Initial commit
This commit is contained in:
2
engines/access/POTFILES
Normal file
2
engines/access/POTFILES
Normal file
@@ -0,0 +1,2 @@
|
||||
engines/access/metaengine.cpp
|
||||
engines/access/resources.cpp
|
||||
609
engines/access/access.cpp
Normal file
609
engines/access/access.cpp
Normal file
@@ -0,0 +1,609 @@
|
||||
/* 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 "common/scummsys.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/debug-channels.h"
|
||||
#include "common/events.h"
|
||||
#include "engines/util.h"
|
||||
#include "graphics/scaler.h"
|
||||
#include "graphics/thumbnail.h"
|
||||
#include "access/access.h"
|
||||
#include "access/debugger.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
AccessEngine::AccessEngine(OSystem *syst, const AccessGameDescription *gameDesc)
|
||||
: _gameDescription(gameDesc), Engine(syst), _randomSource("Access"),
|
||||
_useItem(_flags[99]), _startup(_flags[170]), _manScaleOff(_flags[172]), _pictureTaken(_flags[176]) {
|
||||
// Set up debug channels
|
||||
|
||||
_aboutBox = nullptr;
|
||||
_animation = nullptr;
|
||||
_bubbleBox = nullptr;
|
||||
_char = nullptr;
|
||||
_events = nullptr;
|
||||
_files = nullptr;
|
||||
_invBox = nullptr;
|
||||
_inventory = nullptr;
|
||||
_helpBox = nullptr;
|
||||
_midi = nullptr;
|
||||
_player = nullptr;
|
||||
_res = nullptr;
|
||||
_room = nullptr;
|
||||
_screen = nullptr;
|
||||
_scripts = nullptr;
|
||||
_sound = nullptr;
|
||||
_travelBox = nullptr;
|
||||
_video = nullptr;
|
||||
|
||||
_destIn = nullptr;
|
||||
_current = nullptr;
|
||||
_mouseMode = 0;
|
||||
_playerDataCount = 0;
|
||||
_currentMan = 0;
|
||||
_currentManOld = -1;
|
||||
_converseMode = 0;
|
||||
_startup = 0;
|
||||
_currentCharFlag = false;
|
||||
_boxSelect = false;
|
||||
_scale = 0;
|
||||
_scaleH1 = _scaleH2 = 0;
|
||||
_scaleN1 = 0;
|
||||
_scaleT1 = 0;
|
||||
_scaleMaxY = 0;
|
||||
_scaleI = 0;
|
||||
_scrollCol = _scrollRow = 0;
|
||||
_scrollX = _scrollY = 0;
|
||||
_imgUnscaled = false;
|
||||
_canSaveLoad = false;
|
||||
_establish = nullptr;
|
||||
|
||||
_conversation = 0;
|
||||
_newTime = 0;
|
||||
_newDate = 0;
|
||||
Common::fill(&_objectsTable[0], &_objectsTable[100], (SpriteResource *)nullptr);
|
||||
Common::fill(&_establishTable[0], &_establishTable[100], false);
|
||||
Common::fill(&_flags[0], &_flags[256], 0);
|
||||
_establishFlag = false;
|
||||
_establishMode = 0;
|
||||
_establishGroup = 0;
|
||||
_establishCtrlTblOfs = 0;
|
||||
_lastTime = g_system->getMillis();
|
||||
_curTime = 0;
|
||||
_narateFile = 0;
|
||||
_txtPages = 0;
|
||||
_sndSubFile = 0;
|
||||
_loadSaveSlot = -1;
|
||||
_vidX = _vidY = 0;
|
||||
_cheatFl = false;
|
||||
_restartFl = false;
|
||||
_printEnd = 0;
|
||||
ARRAYCLEAR(_objectsTable);
|
||||
_clearSummaryFlag = false;
|
||||
|
||||
ARRAYCLEAR(_travel);
|
||||
_startTravelItem = _startTravelBox = 0;
|
||||
ARRAYCLEAR(_ask);
|
||||
_startAboutItem = _startAboutBox = 0;
|
||||
_byte26CB5 = 0;
|
||||
_bcnt = 0;
|
||||
_boxDataStart = 0;
|
||||
_boxDataEnd = false;
|
||||
_boxSelectY = 0;
|
||||
_boxSelectYOld = -1;
|
||||
_numLines = 0;
|
||||
_pictureTaken = 0;
|
||||
|
||||
_vidEnd = false;
|
||||
|
||||
_icons = nullptr;
|
||||
|
||||
ARRAYCLEAR(_countTbl);
|
||||
}
|
||||
|
||||
AccessEngine::~AccessEngine() {
|
||||
delete _animation;
|
||||
delete _bubbleBox;
|
||||
delete _helpBox;
|
||||
delete _travelBox;
|
||||
delete _invBox;
|
||||
delete _aboutBox;
|
||||
delete _char;
|
||||
delete _events;
|
||||
delete _files;
|
||||
delete _inventory;
|
||||
delete _midi;
|
||||
delete _player;
|
||||
delete _res;
|
||||
delete _room;
|
||||
delete _screen;
|
||||
delete _scripts;
|
||||
delete _sound;
|
||||
delete _video;
|
||||
delete _icons;
|
||||
|
||||
freeCells();
|
||||
delete _establish;
|
||||
}
|
||||
|
||||
void AccessEngine::setVGA() {
|
||||
initGraphics(320, 200);
|
||||
}
|
||||
|
||||
void AccessEngine::initialize() {
|
||||
if (isCD()) {
|
||||
const Common::FSNode gameDataDir(ConfMan.getPath("path"));
|
||||
// The CD version contains two versions of the game.
|
||||
// - The MCGA version, in the CDROM folder
|
||||
// - The VESA version, in the TDROM folder
|
||||
// We use the hires version.
|
||||
|
||||
// Use forward slash for the folders separator, as documented for SearchSet::addSubDirectoryMatching()
|
||||
const Common::String subfolderMatchPrefix = "tdrom/";
|
||||
|
||||
for (int idx = 0; idx < 15; ++idx) {
|
||||
Common::String folder = subfolderMatchPrefix + ((idx == 0) ? "game" : Common::String::format("chap%.2d", idx));
|
||||
SearchMan.addSubDirectoryMatching(gameDataDir, folder);
|
||||
}
|
||||
}
|
||||
|
||||
// Create sub-objects of the engine
|
||||
_animation = new AnimationManager(this);
|
||||
_bubbleBox = new BubbleBox(this, TYPE_2, 64, 32, 130, 122, 0, 0, 0, 0, "");
|
||||
if (getGameID() == kGameMartianMemorandum) {
|
||||
// Note: add 1 more pixel to width and height to get the right box size.
|
||||
_helpBox = new BubbleBox(this, TYPE_1, 64, 24, 147, 123, 1, 32, 2, 76, "HELP");
|
||||
_travelBox = new BubbleBox(this, TYPE_1, 64, 32, 195, 123, 1, 24, 2, 74, "TRAVEL");
|
||||
_invBox = new BubbleBox(this, TYPE_1, 64, 32, 147, 123, 1, 32, 2, 76, "INVENTORY");
|
||||
_aboutBox = new BubbleBox(this, TYPE_1, 64, 32, 195, 123, 1, 32, 2, 76, "ASK ABOUT");
|
||||
} else {
|
||||
_helpBox = nullptr;
|
||||
_travelBox = nullptr;
|
||||
_invBox = nullptr;
|
||||
_aboutBox = nullptr;
|
||||
}
|
||||
_char = new CharManager(this);
|
||||
_events = new EventsManager(this);
|
||||
_files = new FileManager(this);
|
||||
_inventory = new InventoryManager(this);
|
||||
_player = Player::init(this);
|
||||
_screen = new Screen(this);
|
||||
_sound = new SoundManager(this, _mixer);
|
||||
_midi = new MusicManager(this);
|
||||
_video = new VideoPlayer(this);
|
||||
|
||||
syncSoundSettings();
|
||||
|
||||
setDebugger(Debugger::init(this));
|
||||
_buffer1.create(g_system->getWidth() + TILE_WIDTH, g_system->getHeight());
|
||||
_buffer2.create(g_system->getWidth(), g_system->getHeight());
|
||||
_vidBuf.create(160, 101);
|
||||
|
||||
// If requested, load a savegame instead of showing the intro
|
||||
if (ConfMan.hasKey("save_slot")) {
|
||||
int saveSlot = ConfMan.getInt("save_slot");
|
||||
if (saveSlot >= 0 && saveSlot <= 999)
|
||||
_loadSaveSlot = saveSlot;
|
||||
}
|
||||
}
|
||||
|
||||
const SpriteResource *AccessEngine::getIcons() {
|
||||
if (!_icons) {
|
||||
Resource *iconData = _files->loadFile("ICONS.LZ");
|
||||
_icons = new SpriteResource(this, iconData);
|
||||
delete iconData;
|
||||
}
|
||||
return _icons;
|
||||
}
|
||||
|
||||
Common::Error AccessEngine::run() {
|
||||
_res = Resources::init(this);
|
||||
Common::U32String errorMessage;
|
||||
if (!_res->load(errorMessage)) {
|
||||
GUIErrorMessage(errorMessage);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
setVGA();
|
||||
initialize();
|
||||
|
||||
playGame();
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
int AccessEngine::getRandomNumber(int maxNumber) {
|
||||
return _randomSource.getRandomNumber(maxNumber);
|
||||
}
|
||||
|
||||
void AccessEngine::loadCells(const Common::Array<CellIdent> &cells) {
|
||||
for (const auto &cell : cells) {
|
||||
Resource *spriteData = _files->loadFile(cell);
|
||||
assert(_objectsTable[cell._cell] == nullptr); // ensure no leaks
|
||||
_objectsTable[cell._cell] = new SpriteResource(this, spriteData);
|
||||
delete spriteData;
|
||||
}
|
||||
}
|
||||
|
||||
void AccessEngine::freeCells() {
|
||||
for (int i = 0; i < ARRAYSIZE(_objectsTable); ++i) {
|
||||
delete _objectsTable[i];
|
||||
_objectsTable[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void AccessEngine::speakText(BaseSurface *s, const Common::String &msg) {
|
||||
Common::String lines = msg;
|
||||
Common::String line;
|
||||
int curPage = 0;
|
||||
int soundsLeft = 0;
|
||||
|
||||
while (!shouldQuit()) {
|
||||
soundsLeft = _countTbl[curPage];
|
||||
_events->zeroKeysActions();
|
||||
|
||||
int width = 0;
|
||||
bool lastLine = _fonts._font2->getLine(lines, s->_maxChars * 6, line, width);
|
||||
|
||||
// Set font colors
|
||||
Font::_fontColors[0] = 0;
|
||||
Font::_fontColors[1] = 28;
|
||||
Font::_fontColors[2] = 29;
|
||||
Font::_fontColors[3] = 30;
|
||||
|
||||
_fonts._font2->drawString(s, line, s->_printOrg);
|
||||
s->_printOrg = Common::Point(s->_printStart.x, s->_printOrg.y + 9);
|
||||
|
||||
if ((s->_printOrg.y > _printEnd) && (!lastLine)) {
|
||||
_events->clearEvents();
|
||||
while (!shouldQuit()) {
|
||||
_sound->freeSounds();
|
||||
_sound->loadSoundTable(0, _narateFile + 99, _sndSubFile);
|
||||
_sound->playSound(0);
|
||||
|
||||
while(_sound->isSFXPlaying() && !shouldQuit())
|
||||
_events->pollEvents();
|
||||
|
||||
_scripts->cmdFreeSound();
|
||||
|
||||
if (_events->isKeyActionMousePressed()) {
|
||||
_sndSubFile += soundsLeft;
|
||||
break;
|
||||
} else {
|
||||
++_sndSubFile;
|
||||
--soundsLeft;
|
||||
if (soundsLeft == 0)
|
||||
break;
|
||||
_events->clearEvents();
|
||||
}
|
||||
}
|
||||
|
||||
s->copyBuffer(&_buffer2);
|
||||
s->_printOrg.y = s->_printStart.y;
|
||||
++curPage;
|
||||
soundsLeft = _countTbl[curPage];
|
||||
}
|
||||
|
||||
if (lastLine)
|
||||
break;
|
||||
}
|
||||
|
||||
while (soundsLeft) {
|
||||
_sound->freeSounds();
|
||||
Resource *res = _sound->loadSound(_narateFile + 99, _sndSubFile);
|
||||
_sound->_soundTable.push_back(SoundEntry(res, 1));
|
||||
_sound->playSound(0);
|
||||
|
||||
while(_sound->isSFXPlaying() && !shouldQuit())
|
||||
_events->pollEvents();
|
||||
|
||||
_scripts->cmdFreeSound();
|
||||
|
||||
if (_events->_leftButton) {
|
||||
_events->debounceLeft();
|
||||
_sndSubFile += soundsLeft;
|
||||
break;
|
||||
} else if (_events->isKeyActionPending()) {
|
||||
_sndSubFile += soundsLeft;
|
||||
break;
|
||||
} else {
|
||||
++_sndSubFile;
|
||||
--soundsLeft;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AccessEngine::printText(BaseSurface *s, const Common::String &msg) {
|
||||
Common::String lines = msg;
|
||||
Common::String line;
|
||||
int width = 0;
|
||||
|
||||
for (;;) {
|
||||
bool lastLine = _fonts._font2->getLine(lines, s->_maxChars * 6, line, width);
|
||||
|
||||
// Set font colors
|
||||
_fonts._font2->_fontColors[0] = 0;
|
||||
_fonts._font2->_fontColors[1] = 28;
|
||||
_fonts._font2->_fontColors[2] = 29;
|
||||
_fonts._font2->_fontColors[3] = 30;
|
||||
_fonts._font2->drawString(s, line, s->_printOrg);
|
||||
|
||||
s->_printOrg = Common::Point(s->_printStart.x, s->_printOrg.y + 9);
|
||||
|
||||
if (s->_printOrg.y >_printEnd && !lastLine) {
|
||||
_events->waitKeyActionMouse();
|
||||
s->copyBuffer(&_buffer2);
|
||||
s->_printOrg.y = s->_printStart.y;
|
||||
}
|
||||
|
||||
if (lastLine)
|
||||
break;
|
||||
}
|
||||
_events->waitKeyActionMouse();
|
||||
}
|
||||
|
||||
|
||||
void AccessEngine::plotList() {
|
||||
_player->calcPlayer();
|
||||
plotList1();
|
||||
}
|
||||
|
||||
void AccessEngine::plotList1() {
|
||||
for (uint idx = 0; idx < _images.size(); ++idx) {
|
||||
ImageEntry &ie = _images[idx];
|
||||
|
||||
_imgUnscaled = (ie._flags & IMGFLAG_UNSCALED) != 0;
|
||||
Common::Point pt = ie._position - _screen->_bufferStart;
|
||||
const SpriteResource *sprites = ie._spritesPtr;
|
||||
const SpriteFrame *frame = sprites->getFrame(ie._frameNumber);
|
||||
|
||||
Common::Rect bounds(pt.x, pt.y, pt.x + frame->w, pt.y + frame->h);
|
||||
if (!_imgUnscaled) {
|
||||
bounds.setWidth(_screen->_scaleTable1[frame->w]);
|
||||
bounds.setHeight(_screen->_scaleTable1[frame->h]);
|
||||
}
|
||||
|
||||
// Make a copy - some of the drawing methods I've adapted need the full
|
||||
// scaled dimensions on-screen, and handle clipping themselves
|
||||
Common::Rect destBounds = bounds;
|
||||
|
||||
if (_buffer2.clip(bounds)) {
|
||||
ie._flags |= IMGFLAG_CROPPED;
|
||||
} else {
|
||||
ie._flags &= ~IMGFLAG_CROPPED;
|
||||
if (_buffer2._leftSkip != 0 || _buffer2._rightSkip != 0
|
||||
|| _buffer2._topSkip != 0 || _buffer2._bottomSkip != 0)
|
||||
ie._flags |= IMGFLAG_CROPPED;
|
||||
|
||||
_newRects.push_back(bounds);
|
||||
|
||||
if (!_imgUnscaled) {
|
||||
_buffer2._rightSkip /= _scale;
|
||||
bounds.setWidth(bounds.width() / _scale);
|
||||
|
||||
if (ie._flags & IMGFLAG_BACKWARDS) {
|
||||
_buffer2.sPlotB(frame, destBounds);
|
||||
} else {
|
||||
_buffer2.sPlotF(frame, destBounds);
|
||||
}
|
||||
} else {
|
||||
if (ie._flags & IMGFLAG_BACKWARDS) {
|
||||
_buffer2.plotB(frame, Common::Point(destBounds.left, destBounds.top));
|
||||
} else {
|
||||
_buffer2.plotF(frame, Common::Point(destBounds.left, destBounds.top));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ie._flags |= IMGFLAG_DRAWN;
|
||||
}
|
||||
}
|
||||
|
||||
void AccessEngine::copyBlocks() {
|
||||
// Copy the block list from the previous frame
|
||||
for (const auto &rect : _oldRects) {
|
||||
_screen->copyBlock(&_buffer2, rect);
|
||||
}
|
||||
|
||||
copyRects();
|
||||
}
|
||||
|
||||
void AccessEngine::copyRects() {
|
||||
_oldRects.clear();
|
||||
for (const auto &rect : _newRects) {
|
||||
_screen->copyBlock(&_buffer2, rect);
|
||||
_oldRects.push_back(rect);
|
||||
}
|
||||
}
|
||||
|
||||
void AccessEngine::copyBF1BF2() {
|
||||
_buffer2.copyRectToSurface(_buffer1, 0, 0,
|
||||
Common::Rect(_scrollX, _scrollY,
|
||||
_scrollX + _screen->_vWindowBytesWide,
|
||||
_scrollY + _screen->_vWindowLinesTall));
|
||||
}
|
||||
|
||||
void AccessEngine::copyBF2Vid() {
|
||||
_screen->blitFrom(_buffer2,
|
||||
Common::Rect(0, 0, _screen->_vWindowBytesWide, _screen->_vWindowLinesTall),
|
||||
Common::Point(_screen->_windowXAdd, _screen->_windowYAdd));
|
||||
}
|
||||
|
||||
void AccessEngine::playVideo(int videoNum, const Common::Point &pt) {
|
||||
_video->setVideo(_screen, pt, FileIdent(96, videoNum), 10);
|
||||
|
||||
while (!shouldQuit() && !_video->_videoEnd) {
|
||||
_video->playVideo();
|
||||
_events->pollEventsAndWait();
|
||||
}
|
||||
}
|
||||
|
||||
void AccessEngine::freeChar() {
|
||||
_scripts->freeScriptData();
|
||||
_animation->clearTimers();
|
||||
_animation->freeAnimationData();
|
||||
_player->freeSprites();
|
||||
}
|
||||
|
||||
void AccessEngine::syncSoundSettings() {
|
||||
Engine::syncSoundSettings();
|
||||
_midi->syncVolume();
|
||||
_sound->syncVolume();
|
||||
}
|
||||
|
||||
Common::Error AccessEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
|
||||
Common::OutSaveFile *out = g_system->getSavefileManager()->openForSaving(
|
||||
getSaveStateName(slot));
|
||||
if (!out)
|
||||
return Common::kCreatingFileFailed;
|
||||
|
||||
AccessSavegameHeader header;
|
||||
header._saveName = desc;
|
||||
writeSavegameHeader(out, header);
|
||||
|
||||
Common::Serializer s(nullptr, out);
|
||||
synchronize(s);
|
||||
|
||||
out->finalize();
|
||||
delete out;
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
Common::Error AccessEngine::loadGameState(int slot) {
|
||||
Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(
|
||||
getSaveStateName(slot));
|
||||
if (!saveFile)
|
||||
return Common::kReadingFailed;
|
||||
|
||||
Common::Serializer s(saveFile, nullptr);
|
||||
|
||||
// Load the savaegame header
|
||||
AccessSavegameHeader header;
|
||||
if (!readSavegameHeader(saveFile, header))
|
||||
error("Invalid savegame");
|
||||
|
||||
// Load most of the savegame data
|
||||
synchronize(s);
|
||||
delete saveFile;
|
||||
|
||||
// Set extra post-load state
|
||||
_room->_function = FN_CLEAR1;
|
||||
_timers._timersSavedFlag = false;
|
||||
_events->clearEvents();
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
bool AccessEngine::canLoadGameStateCurrently(Common::U32String *msg) {
|
||||
return _canSaveLoad;
|
||||
}
|
||||
|
||||
bool AccessEngine::canSaveGameStateCurrently(Common::U32String *msg) {
|
||||
return _canSaveLoad;
|
||||
}
|
||||
|
||||
void AccessEngine::synchronize(Common::Serializer &s) {
|
||||
s.syncAsUint16LE(_conversation);
|
||||
s.syncAsUint16LE(_currentMan);
|
||||
s.syncAsUint32LE(_newTime);
|
||||
s.syncAsUint32LE(_newDate);
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
s.syncAsUint16LE(_flags[i]);
|
||||
for (int i = 0; i < 100; ++i)
|
||||
s.syncAsByte(_establishTable[i]);
|
||||
|
||||
// Synchronize sub-objects
|
||||
_timers.synchronize(s);
|
||||
_inventory->synchronize(s);
|
||||
_player->synchronize(s);
|
||||
}
|
||||
|
||||
const char *const SAVEGAME_STR = "ACCESS";
|
||||
#define SAVEGAME_STR_SIZE 6
|
||||
|
||||
WARN_UNUSED_RESULT bool AccessEngine::readSavegameHeader(Common::InSaveFile *in, AccessSavegameHeader &header, bool skipThumbnail) {
|
||||
char saveIdentBuffer[SAVEGAME_STR_SIZE + 1];
|
||||
|
||||
// Validate the header Id
|
||||
in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1);
|
||||
if (strncmp(saveIdentBuffer, SAVEGAME_STR, SAVEGAME_STR_SIZE))
|
||||
return false;
|
||||
|
||||
header._version = in->readByte();
|
||||
if (header._version > ACCESS_SAVEGAME_VERSION)
|
||||
return false;
|
||||
|
||||
// Read in the string
|
||||
header._saveName = in->readString();
|
||||
|
||||
// Get the thumbnail
|
||||
if (!Graphics::loadThumbnail(*in, header._thumbnail, skipThumbnail)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read in save date/time
|
||||
header._year = in->readSint16LE();
|
||||
header._month = in->readSint16LE();
|
||||
header._day = in->readSint16LE();
|
||||
header._hour = in->readSint16LE();
|
||||
header._minute = in->readSint16LE();
|
||||
header._totalFrames = in->readUint32LE();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AccessEngine::writeSavegameHeader(Common::OutSaveFile *out, AccessSavegameHeader &header) {
|
||||
// Write out a savegame header
|
||||
out->write(SAVEGAME_STR, SAVEGAME_STR_SIZE + 1);
|
||||
|
||||
out->writeByte(ACCESS_SAVEGAME_VERSION);
|
||||
|
||||
// Write savegame name
|
||||
out->writeString(header._saveName);
|
||||
out->writeByte('\0');
|
||||
|
||||
// Write a thumbnail of the screen
|
||||
uint8 thumbPalette[Graphics::PALETTE_SIZE];
|
||||
_screen->getPalette(thumbPalette);
|
||||
Graphics::Surface saveThumb;
|
||||
::createThumbnail(&saveThumb, (const byte *)_screen->getPixels(),
|
||||
_screen->w, _screen->h, thumbPalette);
|
||||
Graphics::saveThumbnail(*out, saveThumb);
|
||||
saveThumb.free();
|
||||
|
||||
// Write out the save date/time
|
||||
TimeDate td;
|
||||
g_system->getTimeAndDate(td);
|
||||
out->writeSint16LE(td.tm_year + 1900);
|
||||
out->writeSint16LE(td.tm_mon + 1);
|
||||
out->writeSint16LE(td.tm_mday);
|
||||
out->writeSint16LE(td.tm_hour);
|
||||
out->writeSint16LE(td.tm_min);
|
||||
out->writeUint32LE(_events->getFrameCounter());
|
||||
}
|
||||
|
||||
bool AccessEngine::shouldQuitOrRestart() {
|
||||
return shouldQuit() || _restartFl;
|
||||
}
|
||||
} // End of namespace Access
|
||||
369
engines/access/access.h
Normal file
369
engines/access/access.h
Normal file
@@ -0,0 +1,369 @@
|
||||
/* 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 ACCESS_ACCESS_H
|
||||
#define ACCESS_ACCESS_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/system.h"
|
||||
#include "common/error.h"
|
||||
#include "common/random.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/serializer.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include "engines/engine.h"
|
||||
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "access/animation.h"
|
||||
#include "access/bubble_box.h"
|
||||
#include "access/char.h"
|
||||
#include "access/data.h"
|
||||
#include "access/events.h"
|
||||
#include "access/files.h"
|
||||
#include "access/font.h"
|
||||
#include "access/inventory.h"
|
||||
#include "access/player.h"
|
||||
#include "access/resources.h"
|
||||
#include "access/room.h"
|
||||
#include "access/screen.h"
|
||||
#include "access/scripts.h"
|
||||
#include "access/sound.h"
|
||||
#include "access/video.h"
|
||||
#include "access/detection.h"
|
||||
|
||||
/**
|
||||
* This is the namespace of the Access engine.
|
||||
*
|
||||
* Status of this engine: In Development
|
||||
*
|
||||
* Games using this engine:
|
||||
* - Amazon: Guardians of Eden
|
||||
*/
|
||||
namespace Access {
|
||||
|
||||
enum AccessDebugChannels {
|
||||
kDebugPath = 1,
|
||||
kDebugScripts,
|
||||
kDebugGraphics,
|
||||
kDebugSound,
|
||||
};
|
||||
|
||||
/* typed enum to match unsignedness of Common::CustomEventType */
|
||||
enum ACCESSActions : Common::CustomEventType {
|
||||
kActionNone,
|
||||
kActionMoveUp,
|
||||
kActionMoveDown,
|
||||
kActionMoveLeft,
|
||||
kActionMoveRight,
|
||||
kActionMoveUpLeft,
|
||||
kActionMoveUpRight,
|
||||
kActionMoveDownLeft,
|
||||
kActionMoveDownRight,
|
||||
kActionLook,
|
||||
kActionUse,
|
||||
kActionTake,
|
||||
kActionInventory,
|
||||
kActionClimb,
|
||||
kActionTalk,
|
||||
kActionWalk,
|
||||
kActionHelp,
|
||||
kActionOpen,
|
||||
kActionMove,
|
||||
kActionTravel,
|
||||
kActionSkip,
|
||||
kActionSaveLoad,
|
||||
};
|
||||
|
||||
struct AccessActionCode {
|
||||
ACCESSActions _action;
|
||||
int8 _code;
|
||||
};
|
||||
|
||||
static const AccessActionCode AMAZON_ACTION_CODES[] = {
|
||||
{ kActionLook, 1 },
|
||||
{ kActionUse, 2 },
|
||||
{ kActionTake, 3 },
|
||||
{ kActionInventory, 4 },
|
||||
{ kActionClimb, 5 },
|
||||
{ kActionTalk, 6 },
|
||||
{ kActionWalk, 7 },
|
||||
{ kActionHelp, 8 },
|
||||
{ kActionSaveLoad, -2 },
|
||||
{ kActionNone, -1 },
|
||||
};
|
||||
|
||||
static const AccessActionCode MARTIAN_ACTION_CODES[] = {
|
||||
{ kActionLook, 0 },
|
||||
{ kActionOpen, 1 },
|
||||
{ kActionMove, 2 },
|
||||
{ kActionTake, 3 },
|
||||
{ kActionUse, 4 },
|
||||
{ kActionWalk, 5 },
|
||||
{ kActionTalk, 6 },
|
||||
{ kActionTravel, 7 },
|
||||
{ kActionHelp, 8 },
|
||||
{ kActionSaveLoad, -2 },
|
||||
{ kActionNone, -1 },
|
||||
};
|
||||
|
||||
#define ACCESS_SAVEGAME_VERSION 1
|
||||
|
||||
struct AccessSavegameHeader {
|
||||
uint8 _version;
|
||||
Common::String _saveName;
|
||||
Graphics::Surface *_thumbnail;
|
||||
int _year, _month, _day;
|
||||
int _hour, _minute;
|
||||
int _totalFrames;
|
||||
};
|
||||
|
||||
class AccessEngine : public Engine {
|
||||
private:
|
||||
uint32 _lastTime, _curTime;
|
||||
|
||||
/**
|
||||
* A cache for the ICONS.LZ sprite data
|
||||
*/
|
||||
SpriteResource *_icons;
|
||||
|
||||
/**
|
||||
* Handles basic initialization
|
||||
*/
|
||||
void initialize();
|
||||
|
||||
/**
|
||||
* Set VGA mode
|
||||
*/
|
||||
void setVGA();
|
||||
|
||||
protected:
|
||||
const AccessGameDescription *_gameDescription;
|
||||
Common::RandomSource _randomSource;
|
||||
int _loadSaveSlot;
|
||||
|
||||
/**
|
||||
* Main handler for showing game rooms
|
||||
*/
|
||||
void doRoom();
|
||||
|
||||
/**
|
||||
* Play back an entire video
|
||||
*/
|
||||
void playVideo(int videoNum, const Common::Point &pt);
|
||||
|
||||
// Engine APIs
|
||||
Common::Error run() override;
|
||||
bool hasFeature(EngineFeature f) const override;
|
||||
protected:
|
||||
/**
|
||||
* Play the game
|
||||
*/
|
||||
virtual void playGame() = 0;
|
||||
|
||||
/**
|
||||
* Synchronize savegame data
|
||||
*/
|
||||
virtual void synchronize(Common::Serializer &s);
|
||||
public:
|
||||
AnimationManager *_animation;
|
||||
BubbleBox *_bubbleBox;
|
||||
BubbleBox *_helpBox;
|
||||
BubbleBox *_travelBox;
|
||||
BubbleBox *_invBox;
|
||||
BubbleBox *_aboutBox;
|
||||
CharManager *_char;
|
||||
EventsManager *_events;
|
||||
FileManager *_files;
|
||||
InventoryManager *_inventory;
|
||||
Player *_player;
|
||||
Resources *_res;
|
||||
Room *_room;
|
||||
Screen *_screen;
|
||||
Scripts *_scripts;
|
||||
SoundManager *_sound;
|
||||
MusicManager *_midi;
|
||||
VideoPlayer *_video;
|
||||
|
||||
BaseSurface *_destIn;
|
||||
BaseSurface *_current;
|
||||
ASurface _buffer1;
|
||||
ASurface _buffer2;
|
||||
ASurface _vidBuf;
|
||||
int _vidX, _vidY;
|
||||
SpriteResource *_objectsTable[100];
|
||||
bool _establishTable[100];
|
||||
bool _establishFlag;
|
||||
int _establishMode;
|
||||
int _establishGroup;
|
||||
int _establishCtrlTblOfs;
|
||||
TimerList _timers;
|
||||
DeathList _deaths;
|
||||
FontManager _fonts;
|
||||
Common::Array<Common::Rect> _newRects;
|
||||
Common::Array<Common::Rect> _oldRects;
|
||||
Common::Array<ExtraCell> _extraCells;
|
||||
ImageEntryList _images;
|
||||
int _mouseMode;
|
||||
|
||||
uint8 _playerDataCount;
|
||||
int _currentManOld;
|
||||
int _converseMode;
|
||||
bool _currentCharFlag;
|
||||
bool _boxSelect;
|
||||
int _scale;
|
||||
int _scaleH1, _scaleH2;
|
||||
int _scaleN1;
|
||||
int _scaleT1;
|
||||
int _scaleMaxY;
|
||||
int _scaleI;
|
||||
int _scrollX, _scrollY;
|
||||
int _scrollCol, _scrollRow;
|
||||
bool _imgUnscaled;
|
||||
bool _canSaveLoad;
|
||||
|
||||
Resource *_establish;
|
||||
int _printEnd;
|
||||
int _txtPages;
|
||||
int _narateFile;
|
||||
int _sndSubFile;
|
||||
int _countTbl[6];
|
||||
|
||||
// Fields that are included in savegames
|
||||
int _conversation;
|
||||
int _currentMan;
|
||||
uint32 _newTime;
|
||||
uint32 _newDate;
|
||||
int _flags[256];
|
||||
|
||||
// Fields used by MM
|
||||
// TODO: Refactor
|
||||
byte _travel[60];
|
||||
byte _ask[40];
|
||||
int _startTravelItem;
|
||||
int _startTravelBox;
|
||||
int _startAboutItem;
|
||||
int _startAboutBox;
|
||||
int _boxDataStart;
|
||||
bool _boxDataEnd;
|
||||
int _boxSelectY;
|
||||
int _boxSelectYOld;
|
||||
int _numLines;
|
||||
byte _byte26CB5;
|
||||
int _bcnt;
|
||||
|
||||
bool _vidEnd;
|
||||
bool _clearSummaryFlag;
|
||||
bool _cheatFl;
|
||||
bool _restartFl;
|
||||
// Fields mapped into the flags array
|
||||
int &_useItem;
|
||||
int &_startup;
|
||||
int &_manScaleOff;
|
||||
int &_pictureTaken;
|
||||
|
||||
public:
|
||||
AccessEngine(OSystem *syst, const AccessGameDescription *gameDesc);
|
||||
~AccessEngine() override;
|
||||
|
||||
virtual void dead(int deathId) = 0;
|
||||
|
||||
uint32 getFeatures() const;
|
||||
bool isCD() const;
|
||||
bool isDemo() const;
|
||||
Common::Language getLanguage() const;
|
||||
Common::Platform getPlatform() const;
|
||||
uint16 getVersion() const;
|
||||
uint32 getGameID() const;
|
||||
uint32 getGameFeatures() const;
|
||||
bool shouldQuitOrRestart();
|
||||
|
||||
int getRandomNumber(int maxNumber);
|
||||
|
||||
const SpriteResource *getIcons();
|
||||
|
||||
void loadCells(const Common::Array<CellIdent> &cells);
|
||||
|
||||
/**
|
||||
* Free the sprites list
|
||||
*/
|
||||
void freeCells();
|
||||
|
||||
virtual void establish(int esatabIndex, int sub) = 0;
|
||||
|
||||
void plotList();
|
||||
void plotList1();
|
||||
|
||||
void copyBlocks();
|
||||
|
||||
void copyRects();
|
||||
|
||||
void copyBF1BF2();
|
||||
|
||||
void copyBF2Vid();
|
||||
|
||||
void freeChar();
|
||||
|
||||
/**
|
||||
* Draw a string on a given surface and update text positioning
|
||||
*/
|
||||
void printText(BaseSurface *s, const Common::String &msg);
|
||||
void speakText(BaseSurface *s, const Common::String &msg);
|
||||
|
||||
void syncSoundSettings() override;
|
||||
|
||||
/**
|
||||
* Load a savegame
|
||||
*/
|
||||
Common::Error loadGameState(int slot) override;
|
||||
|
||||
/**
|
||||
* Save the game
|
||||
*/
|
||||
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
|
||||
|
||||
/**
|
||||
* Returns true if a savegame can currently be loaded
|
||||
*/
|
||||
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
|
||||
|
||||
/**
|
||||
* Returns true if the game can currently be saved
|
||||
*/
|
||||
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
|
||||
|
||||
/**
|
||||
* Read in a savegame header
|
||||
*/
|
||||
WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, AccessSavegameHeader &header, bool skipThumbnail = true);
|
||||
|
||||
/**
|
||||
* Write out a savegame header
|
||||
*/
|
||||
void writeSavegameHeader(Common::OutSaveFile *out, AccessSavegameHeader &header);
|
||||
|
||||
bool playMovie(const Common::Path &filename, const Common::Point &pos);
|
||||
};
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_ACCESS_H */
|
||||
792
engines/access/amazon/amazon_game.cpp
Normal file
792
engines/access/amazon/amazon_game.cpp
Normal file
@@ -0,0 +1,792 @@
|
||||
/* 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 "access/resources.h"
|
||||
#include "access/amazon/amazon_game.h"
|
||||
#include "access/amazon/amazon_resources.h"
|
||||
#include "access/amazon/amazon_room.h"
|
||||
#include "access/amazon/amazon_scripts.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
namespace Amazon {
|
||||
|
||||
AmazonEngine::AmazonEngine(OSystem *syst, const AccessGameDescription *gameDesc)
|
||||
: AccessEngine(syst, gameDesc), _guardLocation(_flags[122]), _guardFind(_flags[128]),
|
||||
_helpLevel(_flags[167]), _jasMayaFlag(_flags[168]), _moreHelp(_flags[169]),
|
||||
_flashbackFlag(_flags[171]), _riverFlag(_flags[185]), _aniOutFlag(_flags[195]),
|
||||
_badEnd(_flags[218]), _noHints(_flags[219]), _aniFlag(_flags[229]),
|
||||
_allenFlag(_flags[237]), _noSound(_flags[239]) {
|
||||
_ant = nullptr;
|
||||
_cast = nullptr;
|
||||
_guard = nullptr;
|
||||
_jungle = nullptr;
|
||||
_opening = nullptr;
|
||||
_plane = nullptr;
|
||||
_river = nullptr;
|
||||
|
||||
_charSegSwitch = false;
|
||||
|
||||
_oldTitleChapter = _chapter = 0;
|
||||
_updateChapter = -1;
|
||||
_rawInactiveX = 0;
|
||||
_rawInactiveY = 0;
|
||||
_inactiveYOff = 0;
|
||||
_hintLevel = 0;
|
||||
|
||||
Common::fill(&_tileData[0], &_tileData[0] + sizeof(_tileData), 0);
|
||||
Common::fill(&_help1[0], &_help1[0] + sizeof(_help1), 0);
|
||||
Common::fill(&_help2[0], &_help2[0] + sizeof(_help2), 0);
|
||||
Common::fill(&_help3[0], &_help3[0] + sizeof(_help3), 0);
|
||||
_helpTbl[0] = _help1;
|
||||
_helpTbl[1] = _help2;
|
||||
_helpTbl[2] = _help3;
|
||||
|
||||
_chapter = 0;
|
||||
_rawInactiveX = _rawInactiveY = 0;
|
||||
_inactiveYOff = 0;
|
||||
_hintLevel = 0;
|
||||
_updateChapter = 0;
|
||||
_oldTitleChapter = 0;
|
||||
_iqValue = 0;
|
||||
|
||||
_chapterCells.push_back(CellIdent(0, 96, 17));
|
||||
_inactive._spritesPtr = nullptr;
|
||||
_inactive._flags = _inactive._frameNumber = _inactive._offsetY = 0;
|
||||
_inactive._position = Common::Point(0, 0);
|
||||
}
|
||||
|
||||
AmazonEngine::~AmazonEngine() {
|
||||
delete _inactive._altSpritesPtr;
|
||||
|
||||
delete _ant;
|
||||
delete _cast;
|
||||
delete _guard;
|
||||
delete _jungle;
|
||||
delete _opening;
|
||||
delete _plane;
|
||||
delete _river;
|
||||
}
|
||||
|
||||
void AmazonEngine::freeInactivePlayer() {
|
||||
delete _inactive._altSpritesPtr;
|
||||
_inactive._altSpritesPtr = nullptr;
|
||||
}
|
||||
|
||||
void AmazonEngine::configSelect() {
|
||||
// Initialize fields contained in the config file.
|
||||
_hintLevel = 3;
|
||||
}
|
||||
|
||||
void AmazonEngine::initObjects() {
|
||||
_room = new AmazonRoom(this);
|
||||
_scripts = new AmazonScripts(this);
|
||||
|
||||
_ant = new Ant(this);
|
||||
_cast = new Cast(this);
|
||||
_guard = new Guard(this);
|
||||
_jungle = new Jungle(this);
|
||||
_opening = new Opening(this);
|
||||
_plane = new Plane(this);
|
||||
_river = new River(this);
|
||||
}
|
||||
|
||||
void AmazonEngine::playGame() {
|
||||
// Initialize Amazon game-specific objects
|
||||
initObjects();
|
||||
|
||||
// Setup the game
|
||||
setupGame();
|
||||
configSelect();
|
||||
|
||||
if (_loadSaveSlot == -1) {
|
||||
// Do introduction
|
||||
_opening->doIntroduction();
|
||||
if (shouldQuit())
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
_restartFl = false;
|
||||
_screen->clearScreen();
|
||||
_screen->setPanel(0);
|
||||
_screen->forceFadeOut();
|
||||
_events->showCursor();
|
||||
|
||||
initVariables();
|
||||
|
||||
// If there's a pending savegame to load, load it
|
||||
if (_loadSaveSlot != -1) {
|
||||
loadGameState(_loadSaveSlot);
|
||||
_loadSaveSlot = -1;
|
||||
}
|
||||
|
||||
// Execute the room
|
||||
_room->doRoom();
|
||||
} while (_restartFl);
|
||||
}
|
||||
|
||||
void AmazonEngine::setupGame() {
|
||||
Amazon::AmazonResources &res = *((Amazon::AmazonResources *)_res);
|
||||
|
||||
// Load death list
|
||||
_deaths.resize(_res->DEATHS.size());
|
||||
|
||||
for (uint idx = 0; idx < _deaths.size(); ++idx) {
|
||||
_deaths[idx]._screenId = res.DEATHS[idx]._screenId;
|
||||
_deaths[idx]._msg = res.DEATHS[idx]._msg;
|
||||
}
|
||||
|
||||
// Load the deaths cells
|
||||
_deaths._cells.resize(13);
|
||||
for (int i = 0; i < 13; ++i)
|
||||
_deaths._cells[i] = CellIdent(DEATH_CELLS[i][0], DEATH_CELLS[i][1], DEATH_CELLS[i][2]);
|
||||
|
||||
// Miscellaneous
|
||||
_fonts.load(res._font6x6, res._font3x5, nullptr);
|
||||
|
||||
initVariables();
|
||||
}
|
||||
|
||||
void AmazonEngine::initVariables() {
|
||||
_chapter = 1;
|
||||
// Set player room and position
|
||||
if (isDemo())
|
||||
_player->_roomNumber = 33;
|
||||
else
|
||||
_player->_roomNumber = 4;
|
||||
|
||||
_converseMode = 0;
|
||||
_inventory->_startInvItem = 0;
|
||||
_inventory->_startInvBox = 0;
|
||||
Common::fill(&_objectsTable[0], &_objectsTable[100], (SpriteResource *)nullptr);
|
||||
_player->_playerOff = false;
|
||||
|
||||
// Setup timers
|
||||
static const int TIMER_DEFAULTS[] = { 3, 10, 8, 1, 1, 1, 1, 2 };
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
TimerEntry te;
|
||||
te._initTm = te._timer = (i < 8) ? TIMER_DEFAULTS[i] : 1;
|
||||
te._flag = 1;
|
||||
|
||||
_timers.push_back(te);
|
||||
}
|
||||
|
||||
_player->_playerX = _player->_rawPlayer.x = _res->ROOMTBL[_player->_roomNumber]._travelPos.x;
|
||||
_player->_playerY = _player->_rawPlayer.y = _res->ROOMTBL[_player->_roomNumber]._travelPos.y;
|
||||
_room->_selectCommand = -1;
|
||||
_events->setNormalCursor(CURSOR_CROSSHAIRS);
|
||||
_mouseMode = 0;
|
||||
_animation->clearTimers();
|
||||
}
|
||||
|
||||
void AmazonEngine::establish(int screenId, int esatabIndex) {
|
||||
_establishMode = 0;
|
||||
_establishGroup = 0;
|
||||
doEstablish(screenId, esatabIndex);
|
||||
}
|
||||
|
||||
void AmazonEngine::establishCenter(int screenId, int esatabIndex) {
|
||||
_establishMode = 1;
|
||||
doEstablish(screenId, esatabIndex);
|
||||
}
|
||||
|
||||
static const char *const EST_TABLE[] = { "ETEXT0.DAT", "ETEXT1.DAT", "ETEXT2.DAT", "ETEXT3.DAT" };
|
||||
|
||||
void AmazonEngine::loadEstablish(int estabIndex) {
|
||||
if (!_files->existFile("ETEXT.DAT")) {
|
||||
int oldGroup = _establishGroup;
|
||||
_establishGroup = 0;
|
||||
|
||||
_establish = _files->loadFile(EST_TABLE[oldGroup]);
|
||||
_establishCtrlTblOfs = READ_LE_UINT16(_establish->data());
|
||||
|
||||
int ofs = _establishCtrlTblOfs + (estabIndex * 2);
|
||||
int idx = READ_LE_UINT16(_establish->data() + ofs);
|
||||
_narateFile = READ_LE_UINT16(_establish->data() + idx);
|
||||
_txtPages = READ_LE_UINT16(_establish->data() + idx + 2);
|
||||
|
||||
if (!_txtPages)
|
||||
return;
|
||||
|
||||
_sndSubFile = READ_LE_UINT16(_establish->data() + idx + 4);
|
||||
for (int i = 0; i < _txtPages; ++i)
|
||||
_countTbl[i] = READ_LE_UINT16(_establish->data() + idx + 6 + (2 * i));
|
||||
} else {
|
||||
_establishGroup = 0;
|
||||
_narateFile = 0;
|
||||
_txtPages = 0;
|
||||
_sndSubFile = 0;
|
||||
_establish = _files->loadFile("ETEXT.DAT");
|
||||
}
|
||||
}
|
||||
|
||||
void AmazonEngine::doEstablish(int screenId, int estabIndex) {
|
||||
_establishMode = 1;
|
||||
|
||||
_events->clearEvents();
|
||||
_screen->forceFadeOut();
|
||||
_screen->clearScreen();
|
||||
_screen->setPanel(3);
|
||||
|
||||
if (screenId != -1) {
|
||||
_files->loadScreen(95, screenId);
|
||||
_buffer2.copyBuffer(_screen);
|
||||
}
|
||||
|
||||
_screen->setIconPalette();
|
||||
_screen->forceFadeIn();
|
||||
|
||||
_fonts._charSet._lo = 1;
|
||||
_fonts._charSet._hi = 10;
|
||||
_fonts._charFor._lo = 29;
|
||||
_fonts._charFor._hi = 32;
|
||||
_screen->_maxChars = 37;
|
||||
_screen->_printOrg = _screen->_printStart = Common::Point(48, 35);
|
||||
|
||||
loadEstablish(estabIndex);
|
||||
uint16 msgOffset;
|
||||
if (!isCD())
|
||||
msgOffset = READ_LE_UINT16(_establish->data() + (estabIndex * 2));
|
||||
else
|
||||
msgOffset = READ_LE_UINT16(_establish->data() + (estabIndex * 2) + 2);
|
||||
|
||||
_printEnd = 155;
|
||||
Common::String msg((const char *)_establish->data() + msgOffset);
|
||||
|
||||
if ((_txtPages == 0) || !isCD()) {
|
||||
printText(_screen, msg);
|
||||
} else {
|
||||
speakText(_screen, msg);
|
||||
}
|
||||
|
||||
_screen->forceFadeOut();
|
||||
_screen->clearScreen();
|
||||
|
||||
delete _establish;
|
||||
_establish = nullptr;
|
||||
|
||||
if (_establishMode == 0)
|
||||
_room->init4Quads();
|
||||
}
|
||||
|
||||
const char *const _tileFiles[] = {
|
||||
"GRAY.BLK", "RED.BLK", "LTBROWN.BLK", "DKBROWN.BLK", "VIOLET.BLK", "LITEBLUE.BLK",
|
||||
"DARKBLUE.BLK", "CYAN.BLK", "GREEN.BLK", "OLIVE.BLK", "GRAY.BLK", "RED.BLK",
|
||||
"LTBROWN.BLK", "DKBROWN.BLK", "VIOLET.BLK", "OLIVE.BLK"
|
||||
};
|
||||
|
||||
void AmazonEngine::tileScreen() {
|
||||
if (!_screen->_vesaMode)
|
||||
return;
|
||||
|
||||
if (!_clearSummaryFlag && (_oldTitleChapter == _chapter))
|
||||
return;
|
||||
|
||||
_oldTitleChapter = _chapter;
|
||||
int idx = _chapter - 1;
|
||||
|
||||
if (!_files->existFile(_tileFiles[idx]))
|
||||
return;
|
||||
|
||||
Resource *res = _files->loadFile(_tileFiles[idx]);
|
||||
int x = res->_stream->readSint16LE();
|
||||
int y = res->_stream->readSint16LE();
|
||||
int size = ((x + 2) * y) + 10;
|
||||
|
||||
for (int i = 0; i < size; ++i)
|
||||
_tileData[i] = res->_stream->readByte();
|
||||
|
||||
// CHECKME: Depending on the Vesa mode during initialization, 400 or 480
|
||||
Common::Point tilePos;
|
||||
for (tilePos.y = 0; tilePos.y < 480; tilePos.y += y) {
|
||||
for (tilePos.x = 0; tilePos.x < 640; tilePos.x += x)
|
||||
warning("TODO: DRAWOBJECT");
|
||||
}
|
||||
|
||||
delete res;
|
||||
}
|
||||
|
||||
void AmazonEngine::updateSummary(int chap) {
|
||||
if (!_screen->_vesaMode)
|
||||
return;
|
||||
|
||||
int chapter = chap;
|
||||
if (chapter > 16)
|
||||
chapter = 16;
|
||||
|
||||
if (!_clearSummaryFlag && (chapter == _updateChapter))
|
||||
return;
|
||||
|
||||
_clearSummaryFlag = false;
|
||||
int celSubFile = 0;
|
||||
_updateChapter = chapter;
|
||||
Common::Array<CellIdent> summaryCells;
|
||||
loadCells(summaryCells);
|
||||
|
||||
for (int i = celSubFile; i < 16; ++i) {
|
||||
if (i > 7)
|
||||
warning("TODO: DRAWOBJECT (i > 7)");
|
||||
else
|
||||
warning("TODO: DRAWOBJECT (i <= 7)");
|
||||
}
|
||||
|
||||
delete _objectsTable[93];
|
||||
_objectsTable[93] = nullptr;
|
||||
|
||||
for (int i = 1; i <= _updateChapter; ++i) {
|
||||
celSubFile = i;
|
||||
loadCells(summaryCells);
|
||||
if (i > 8)
|
||||
warning("TODO: DRAWOBJECT (i > 8)");
|
||||
else
|
||||
warning("TODO: DRAWOBJECT (i <= 8)");
|
||||
|
||||
delete _objectsTable[93];
|
||||
_objectsTable[93] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void AmazonEngine::calcIQ() {
|
||||
int tmpIQ = 170;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
if (_help1[i] == 1)
|
||||
tmpIQ -= 3;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
if (_help2[i] == 1)
|
||||
tmpIQ -= 5;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
if (_help3[i] == 1)
|
||||
tmpIQ -= 10;
|
||||
}
|
||||
|
||||
if (tmpIQ < 0)
|
||||
tmpIQ = 0;
|
||||
|
||||
_iqValue = tmpIQ;
|
||||
|
||||
if (_iqValue <= 100)
|
||||
_badEnd = 1;
|
||||
|
||||
if (_iqValue <= 0)
|
||||
_noHints = 1;
|
||||
}
|
||||
|
||||
void AmazonEngine::helpTitle() {
|
||||
AmazonResources &res = *(AmazonResources *)_res;
|
||||
int width = _fonts._font2->stringWidth(_bubbleBox->_bubbleTitle);
|
||||
int posX = 160 - (width / 2);
|
||||
_fonts._font2->_fontColors[0] = 0;
|
||||
_fonts._font2->_fontColors[1] = 33;
|
||||
_fonts._font2->_fontColors[2] = 34;
|
||||
_fonts._font2->_fontColors[3] = 35;
|
||||
_fonts._font2->drawString(_screen, _bubbleBox->_bubbleTitle, Common::Point(posX, 24));
|
||||
|
||||
width = _fonts._font2->stringWidth(res.HELPLVLTXT[_helpLevel]);
|
||||
posX = 160 - (width / 2);
|
||||
_fonts._font2->_fontColors[0] = 0;
|
||||
_fonts._font2->_fontColors[1] = 10;
|
||||
_fonts._font2->_fontColors[2] = 11;
|
||||
_fonts._font2->_fontColors[3] = 12;
|
||||
_fonts._font2->drawString(_screen, res.HELPLVLTXT[_helpLevel], Common::Point(posX, 36));
|
||||
|
||||
Common::String iqText = "IQ: ";
|
||||
calcIQ();
|
||||
Common::String scoreIQ = Common::String::format("%d", _iqValue);
|
||||
while (scoreIQ.size() < 4)
|
||||
scoreIQ = " " + scoreIQ;
|
||||
|
||||
iqText += scoreIQ;
|
||||
int index = _iqValue;
|
||||
if (index == 170)
|
||||
index = 169;
|
||||
|
||||
index /= 20;
|
||||
|
||||
iqText += " ";
|
||||
iqText += res.IQLABELS[index];
|
||||
|
||||
width = _fonts._font2->stringWidth(iqText);
|
||||
posX = 160 - (width / 2);
|
||||
_fonts._font2->_fontColors[0] = 0;
|
||||
_fonts._font2->_fontColors[1] = 10;
|
||||
_fonts._font2->_fontColors[2] = 11;
|
||||
_fonts._font2->_fontColors[3] = 12;
|
||||
_fonts._font2->drawString(_screen, iqText, Common::Point(posX, 44));
|
||||
}
|
||||
|
||||
void AmazonEngine::drawHelpText(const Common::String &msg) {
|
||||
_screen->_maxChars = 39;
|
||||
_screen->_printOrg = Common::Point(26, 58);
|
||||
_screen->_printStart = Common::Point(26, 58);
|
||||
|
||||
Common::String lines = msg;
|
||||
Common::String line;
|
||||
int width = 0;
|
||||
bool lastLine = false;
|
||||
do {
|
||||
lastLine = _fonts._font2->getLine(lines, _screen->_maxChars * 6, line, width);
|
||||
|
||||
// Set font colors
|
||||
_fonts._font2->_fontColors[0] = 0;
|
||||
_fonts._font2->_fontColors[1] = 27;
|
||||
_fonts._font2->_fontColors[2] = 28;
|
||||
_fonts._font2->_fontColors[3] = 29;
|
||||
|
||||
_fonts._font2->drawString(_screen, line, _screen->_printOrg);
|
||||
_screen->_printOrg = Common::Point(_screen->_printStart.x, _screen->_printOrg.y + 8);
|
||||
} while (!lastLine);
|
||||
|
||||
_events->showCursor();
|
||||
}
|
||||
|
||||
void AmazonEngine::drawHelp(const Common::String &str) {
|
||||
_events->hideCursor();
|
||||
if (_useItem == 0) {
|
||||
_buffer2.copyBuffer(_screen);
|
||||
if (_screen->_vesaMode) {
|
||||
_screen->setPanel(2);
|
||||
_screen->saveScreen();
|
||||
}
|
||||
_screen->savePalette();
|
||||
_screen->fadeOut();
|
||||
_screen->clearBuffer();
|
||||
if (_moreHelp == 1) {
|
||||
// Set cells
|
||||
Common::Array<CellIdent> cells;
|
||||
cells.push_back(CellIdent(95, 95, 3));
|
||||
loadCells(cells);
|
||||
}
|
||||
}
|
||||
|
||||
_files->loadScreen(95, 2);
|
||||
if (_moreHelp == 1) {
|
||||
BaseSurface *oldDest = _destIn;
|
||||
_destIn = _screen;
|
||||
int oldClip = _screen->_clipHeight;
|
||||
_screen->_clipHeight = 200;
|
||||
_screen->plotImage(_objectsTable[95], 0, Common::Point(76, 168));
|
||||
_destIn = oldDest;
|
||||
_screen->_clipHeight = oldClip;
|
||||
}
|
||||
|
||||
if ((_useItem == 0) && (_screen->_vesaMode == 0))
|
||||
_screen->fadeIn();
|
||||
|
||||
helpTitle();
|
||||
drawHelpText(str);
|
||||
}
|
||||
|
||||
void AmazonEngine::startChapter(int chapter) {
|
||||
_chapter = chapter;
|
||||
assert(_chapter <= 14);
|
||||
|
||||
if (chapter != 1) {
|
||||
_room->clearRoom();
|
||||
freeChar();
|
||||
|
||||
_midi->newMusic(32, 0);
|
||||
playVideo(0, Common::Point());
|
||||
if (shouldQuit())
|
||||
return;
|
||||
|
||||
_events->debounceLeft();
|
||||
_events->zeroKeysActions();
|
||||
playVideo(_chapter, Common::Point(4, 113));
|
||||
if (shouldQuit())
|
||||
return;
|
||||
|
||||
_timers[20]._timer = 500;
|
||||
_timers[20]._initTm = 500;
|
||||
_timers[20]._flag++;
|
||||
_sound->freeSounds();
|
||||
|
||||
if (isCD()) {
|
||||
_sound->loadSoundTable(0, 115, 0);
|
||||
_sound->loadSoundTable(1, 115, 1);
|
||||
_sound->playSound(0);
|
||||
_sound->playSound(1);
|
||||
|
||||
_sound->freeSounds();
|
||||
}
|
||||
|
||||
// Wait loop
|
||||
while (!shouldQuit() && !_events->isKeyActionMousePressed() && _timers[20]._flag) {
|
||||
_events->pollEventsAndWait();
|
||||
}
|
||||
}
|
||||
|
||||
_screen->forceFadeOut();
|
||||
_events->debounceLeft();
|
||||
_events->zeroKeysActions();
|
||||
_screen->clearScreen();
|
||||
|
||||
_screen->setPanel(3);
|
||||
|
||||
// Set up cells for the chapter display
|
||||
Common::Array<CellIdent> chapterCells;
|
||||
chapterCells.push_back(CellIdent(0, 96, 17));
|
||||
const int *chapCell = &CHAPTER_CELLS[_chapter - 1][0];
|
||||
chapterCells.push_back(CellIdent(chapCell[0], chapCell[1], chapCell[2]));
|
||||
loadCells(chapterCells);
|
||||
|
||||
// Show chapter screen
|
||||
_files->loadScreen(96, 15);
|
||||
_buffer2.blitFrom(*_screen);
|
||||
|
||||
const int *chapImg = &CHAPTER_TABLE[_chapter - 1][0];
|
||||
_screen->plotImage(_objectsTable[0], _chapter - 1,
|
||||
Common::Point(chapImg[1], chapImg[2]));
|
||||
_screen->plotImage(_objectsTable[_chapter], 0,
|
||||
Common::Point(chapImg[3], chapImg[4]));
|
||||
if (chapter == 14)
|
||||
_screen->plotImage(_objectsTable[_chapter], 1, Common::Point(169, 76));
|
||||
|
||||
_midi->newMusic(chapImg[4], 1);
|
||||
_midi->newMusic(33, 0);
|
||||
_screen->forceFadeIn();
|
||||
|
||||
_timers[20]._timer = 950;
|
||||
_timers[20]._initTm = 950;
|
||||
_timers[20]._flag++;
|
||||
|
||||
// Wait loop
|
||||
while (!shouldQuit() && !_events->isKeyActionMousePressed() && _timers[20]._flag) {
|
||||
_events->pollEventsAndWait();
|
||||
}
|
||||
if (shouldQuit())
|
||||
return;
|
||||
|
||||
_screen->forceFadeOut();
|
||||
_events->debounceLeft();
|
||||
_events->zeroKeysActions();
|
||||
|
||||
_screen->clearBuffer();
|
||||
_files->loadScreen(96, 16);
|
||||
_buffer2.blitFrom(*_screen);
|
||||
_screen->plotImage(_objectsTable[0], chapImg[0], Common::Point(90, 7));
|
||||
|
||||
_midi->newMusic(7, 1);
|
||||
_midi->newMusic(34, 0);
|
||||
|
||||
_screen->forceFadeIn();
|
||||
_buffer2.blitFrom(*_screen);
|
||||
|
||||
_fonts._charSet._lo = 1;
|
||||
_fonts._charSet._hi = 10;
|
||||
_fonts._charFor._lo = 55;
|
||||
_fonts._charFor._hi = 0xFF;
|
||||
_screen->_maxChars = 43;
|
||||
_screen->_printOrg = Common::Point(31, 77);
|
||||
_screen->_printStart = Common::Point(31, 77);
|
||||
|
||||
_establishGroup = 1;
|
||||
loadEstablish(0x40 + _chapter);
|
||||
|
||||
const byte *entryOffset = _establish->data() + ((0x40 + _chapter) * 2);
|
||||
if (isCD())
|
||||
entryOffset += 2;
|
||||
|
||||
uint16 msgOffset = READ_LE_UINT16(entryOffset);
|
||||
_printEnd = 170;
|
||||
|
||||
Common::String msg((const char *)_establish->data() + msgOffset);
|
||||
|
||||
if ((_txtPages == 0) || !isCD()) {
|
||||
printText(_screen, msg);
|
||||
} else {
|
||||
speakText(_screen, msg);
|
||||
}
|
||||
if (shouldQuit())
|
||||
return;
|
||||
|
||||
_screen->forceFadeOut();
|
||||
_screen->clearBuffer();
|
||||
freeCells();
|
||||
|
||||
_midi->newMusic(_chapter * 2, 1);
|
||||
|
||||
if (chapter != 1 && chapter != 14) {
|
||||
_room->init4Quads();
|
||||
}
|
||||
|
||||
if (isCD()) {
|
||||
if (chapter == 14) {
|
||||
_conversation = 31;
|
||||
_char->loadChar(_conversation);
|
||||
_events->setCursor(CURSOR_ARROW);
|
||||
|
||||
_images.clear();
|
||||
_oldRects.clear();
|
||||
_scripts->_sequence = 0;
|
||||
_scripts->searchForSequence();
|
||||
|
||||
if (_screen->_vesaMode) {
|
||||
_converseMode = 1;
|
||||
}
|
||||
} else if (chapter != 1) {
|
||||
_player->_roomNumber = CHAPTER_JUMP[_chapter - 1];
|
||||
_room->_function = FN_CLEAR1;
|
||||
_converseMode = 0;
|
||||
|
||||
_scripts->cmdRetPos();
|
||||
}
|
||||
}
|
||||
|
||||
delete _establish;
|
||||
_establish = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void AmazonEngine::dead(int deathId) {
|
||||
_events->hideCursor();
|
||||
_screen->forceFadeOut();
|
||||
_scripts->cmdFreeSound();
|
||||
_events->debounceLeft();
|
||||
_events->zeroKeysActions();
|
||||
|
||||
_sound->_soundTable.push_back(SoundEntry(_files->loadFile(98, 44), 1));
|
||||
|
||||
_screen->clearScreen();
|
||||
_screen->setPanel(3);
|
||||
|
||||
if ((deathId == 10) && !isDemo()) {
|
||||
quitGame();
|
||||
_events->pollEvents();
|
||||
return;
|
||||
} else {
|
||||
if (!isDemo())
|
||||
_midi->newMusic(62, 0);
|
||||
_files->_setPaletteFlag = false;
|
||||
_files->loadScreen(94, 0);
|
||||
_files->_setPaletteFlag = true;
|
||||
_buffer2.blitFrom(*_screen);
|
||||
|
||||
if (!isDemo() || deathId != 10) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
_sound->playSound(0);
|
||||
_screen->forceFadeIn();
|
||||
_sound->playSound(0);
|
||||
_screen->forceFadeOut();
|
||||
|
||||
_events->pollEvents();
|
||||
if (shouldQuit())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isDemo()) {
|
||||
freeCells();
|
||||
|
||||
// Load the cell list for the death screen
|
||||
DeathEntry &de = _deaths[deathId];
|
||||
Common::Array<CellIdent> cells;
|
||||
cells.push_back(_deaths._cells[de._screenId]);
|
||||
loadCells(cells);
|
||||
|
||||
_screen->setDisplayScan();
|
||||
_files->_setPaletteFlag = false;
|
||||
_files->loadScreen(&_buffer2, 94, 1);
|
||||
_screen->setIconPalette();
|
||||
|
||||
_buffer2.plotImage(_objectsTable[0], 0, Common::Point(105, 25));
|
||||
_buffer2.copyTo(_screen);
|
||||
_screen->forceFadeIn();
|
||||
|
||||
_fonts._charSet._hi = 10;
|
||||
_fonts._charSet._lo = 1;
|
||||
_fonts._charFor._lo = 55;
|
||||
_fonts._charFor._hi = 255;
|
||||
_screen->_maxChars = 46;
|
||||
_screen->_printOrg = Common::Point(20, 155);
|
||||
_screen->_printStart = Common::Point(20, 155);
|
||||
|
||||
const Common::String &msg = de._msg;
|
||||
_printEnd = 180;
|
||||
|
||||
printText(_screen, msg);
|
||||
_screen->forceFadeOut();
|
||||
|
||||
_midi->newMusic(0, 1);
|
||||
_events->showCursor();
|
||||
_room->clearRoom();
|
||||
freeChar();
|
||||
|
||||
_currentManOld = 1;
|
||||
_player->removeSprite1();
|
||||
|
||||
} else {
|
||||
_files->loadScreen(_screen, 94, _deaths[deathId]._screenId);
|
||||
_screen->forceFadeIn();
|
||||
|
||||
_fonts._charSet._hi = 10;
|
||||
_fonts._charSet._lo = 1;
|
||||
_fonts._charFor._lo = 55;
|
||||
_fonts._charFor._hi = 255;
|
||||
_screen->_maxChars = 49;
|
||||
_screen->_printOrg = Common::Point(15, 165);
|
||||
_screen->_printStart = Common::Point(15, 165);
|
||||
|
||||
const Common::String &msg = _deaths[deathId]._msg;
|
||||
_printEnd = 200;
|
||||
|
||||
printText(_screen, msg);
|
||||
_screen->fadeOut();
|
||||
|
||||
_events->showCursor();
|
||||
_room->clearRoom();
|
||||
freeChar();
|
||||
|
||||
_currentManOld = 1;
|
||||
_player->removeSprite1();
|
||||
}
|
||||
|
||||
// The original was jumping to the restart label in main
|
||||
_restartFl = true;
|
||||
_events->pollEvents();
|
||||
}
|
||||
}
|
||||
|
||||
void AmazonEngine::synchronize(Common::Serializer &s) {
|
||||
AccessEngine::synchronize(s);
|
||||
|
||||
s.syncAsSint16LE(_chapter);
|
||||
s.syncAsSint16LE(_rawInactiveX);
|
||||
s.syncAsSint16LE(_rawInactiveY);
|
||||
s.syncAsSint16LE(_inactiveYOff);
|
||||
|
||||
for (int i = 0; i < 366; ++i) {
|
||||
s.syncAsByte(_help1[i]);
|
||||
s.syncAsByte(_help2[i]);
|
||||
s.syncAsByte(_help3[i]);
|
||||
}
|
||||
|
||||
_river->synchronize(s);
|
||||
_ant->synchronize(s);
|
||||
}
|
||||
|
||||
} // End of namespace Amazon
|
||||
|
||||
} // End of namespace Access
|
||||
138
engines/access/amazon/amazon_game.h
Normal file
138
engines/access/amazon/amazon_game.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/* 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 ACCESS_AMAZON_GAME_H
|
||||
#define ACCESS_AMAZON_GAME_H
|
||||
|
||||
#include "access/access.h"
|
||||
#include "access/amazon/amazon_logic.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
namespace Amazon {
|
||||
|
||||
class AmazonEngine;
|
||||
|
||||
class AmazonEngine : public AccessEngine {
|
||||
private:
|
||||
byte _tileData[1455];
|
||||
Common::Array<CellIdent> _chapterCells;
|
||||
|
||||
/**
|
||||
* Setup variables for the game
|
||||
*/
|
||||
void setupGame();
|
||||
|
||||
/**
|
||||
* Initialize variables found in the config file
|
||||
*/
|
||||
void configSelect();
|
||||
|
||||
void initVariables();
|
||||
void initObjects();
|
||||
void calcIQ();
|
||||
void helpTitle();
|
||||
void drawHelpText(const Common::String &msg);
|
||||
void loadEstablish(int estabIndex);
|
||||
void doEstablish(int screenId, int estabIndex);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Play the game
|
||||
*/
|
||||
void playGame() override;
|
||||
|
||||
/**
|
||||
* Synchronize savegame data
|
||||
*/
|
||||
void synchronize(Common::Serializer &s) override;
|
||||
public:
|
||||
InactivePlayer _inactive;
|
||||
bool _charSegSwitch;
|
||||
byte _help1[366];
|
||||
byte _help2[366];
|
||||
byte _help3[366];
|
||||
byte *_helpTbl[3];
|
||||
|
||||
// Fields that are mapped to flags
|
||||
int &_guardLocation;
|
||||
int &_guardFind;
|
||||
int &_helpLevel;
|
||||
int &_jasMayaFlag;
|
||||
int &_moreHelp;
|
||||
int &_flashbackFlag;
|
||||
int &_riverFlag;
|
||||
int &_aniOutFlag;
|
||||
int &_badEnd;
|
||||
int &_noHints;
|
||||
int &_aniFlag;
|
||||
int &_allenFlag;
|
||||
int &_noSound;
|
||||
|
||||
// Saved fields
|
||||
int _chapter;
|
||||
int _rawInactiveX;
|
||||
int _rawInactiveY;
|
||||
int _inactiveYOff;
|
||||
|
||||
// Other game specific fields
|
||||
Ant *_ant;
|
||||
Cast *_cast;
|
||||
Guard *_guard;
|
||||
Jungle *_jungle;
|
||||
Opening *_opening;
|
||||
Plane *_plane;
|
||||
River *_river;
|
||||
int _hintLevel;
|
||||
int _updateChapter;
|
||||
int _oldTitleChapter;
|
||||
int _iqValue;
|
||||
public:
|
||||
AmazonEngine(OSystem *syst, const AccessGameDescription *gameDesc);
|
||||
|
||||
~AmazonEngine() override;
|
||||
|
||||
void dead(int deathId) override;
|
||||
|
||||
/**
|
||||
* Free the inactive player data
|
||||
*/
|
||||
void freeInactivePlayer();
|
||||
|
||||
void drawHelp(const Common::String &str);
|
||||
|
||||
void establish(int esatabIndex, int sub) override;
|
||||
|
||||
void tileScreen();
|
||||
void updateSummary(int chap);
|
||||
void establishCenter(int screenId, int esatabIndex);
|
||||
|
||||
/**
|
||||
* Show the start of a chapter
|
||||
*/
|
||||
void startChapter(int chapter);
|
||||
};
|
||||
|
||||
} // End of namespace Amazon
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_ACCESS_H */
|
||||
2226
engines/access/amazon/amazon_logic.cpp
Normal file
2226
engines/access/amazon/amazon_logic.cpp
Normal file
File diff suppressed because it is too large
Load Diff
252
engines/access/amazon/amazon_logic.h
Normal file
252
engines/access/amazon/amazon_logic.h
Normal file
@@ -0,0 +1,252 @@
|
||||
/* 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 ACCESS_AMAZON_LOGIC_H
|
||||
#define ACCESS_AMAZON_LOGIC_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "access/scripts.h"
|
||||
#include "access/asurface.h"
|
||||
#include "access/amazon/amazon_resources.h"
|
||||
|
||||
namespace Access {
|
||||
namespace Amazon {
|
||||
|
||||
class AmazonEngine;
|
||||
|
||||
#define PAN_SIZE 32
|
||||
|
||||
class AmazonManager {
|
||||
protected:
|
||||
AmazonEngine *_vm;
|
||||
public:
|
||||
AmazonManager(AmazonEngine *vm) : _vm(vm) {}
|
||||
};
|
||||
|
||||
class PannedScene : public AmazonManager {
|
||||
struct PanEntry {
|
||||
SpriteResource *_pObject;
|
||||
int _pImgNum;
|
||||
int _pObjX;
|
||||
int _pObjY;
|
||||
int _pObjZ;
|
||||
int _pObjXl;
|
||||
int _pObjYl;
|
||||
};
|
||||
protected:
|
||||
int _xCount;
|
||||
int _xTrack;
|
||||
int _yTrack;
|
||||
int _zTrack;
|
||||
int _xCam;
|
||||
int _yCam;
|
||||
int _zCam;
|
||||
int _pNumObj;
|
||||
|
||||
PanEntry _pan[PAN_SIZE];
|
||||
public:
|
||||
PannedScene(AmazonEngine *vm);
|
||||
|
||||
void pan();
|
||||
};
|
||||
|
||||
class CampScene : public PannedScene {
|
||||
protected:
|
||||
bool _skipStart;
|
||||
public:
|
||||
CampScene(AmazonEngine *vm);
|
||||
|
||||
void mWhileDoOpen();
|
||||
};
|
||||
|
||||
class Opening : public CampScene {
|
||||
private:
|
||||
int _pCount;
|
||||
|
||||
void doTitle();
|
||||
void doCredit();
|
||||
void doCreditDemo();
|
||||
void scrollTitle();
|
||||
void doTent();
|
||||
public:
|
||||
Opening(AmazonEngine *vm);
|
||||
|
||||
void doIntroduction();
|
||||
};
|
||||
|
||||
class Plane : public PannedScene {
|
||||
public:
|
||||
int _pCount;
|
||||
Common::Point _position;
|
||||
int _planeCount;
|
||||
int _propCount;
|
||||
|
||||
void doFlyCell();
|
||||
void doFallCell();
|
||||
void scrollFly();
|
||||
void scrollFall();
|
||||
void mWhileFly();
|
||||
void mWhileFall();
|
||||
public:
|
||||
Plane(AmazonEngine *vm);
|
||||
};
|
||||
|
||||
#define JUNGLE_SIZE 3
|
||||
class Jungle : public CampScene {
|
||||
private:
|
||||
void initJWalk2();
|
||||
void jungleMove();
|
||||
void scrollJWalk();
|
||||
|
||||
int _jCnt[JUNGLE_SIZE];
|
||||
int _jungleX[JUNGLE_SIZE];
|
||||
public:
|
||||
Jungle(AmazonEngine *vm);
|
||||
|
||||
void mWhileJWalk();
|
||||
void mWhileJWalk2();
|
||||
};
|
||||
|
||||
class Guard : public PannedScene {
|
||||
private:
|
||||
int _guardCel;
|
||||
Common::Point _position;
|
||||
int _gCode1;
|
||||
int _gCode2;
|
||||
Common::Point _topLeft;
|
||||
Common::Point _bottomRight;
|
||||
int _xMid, _yMid;
|
||||
|
||||
void chkVLine();
|
||||
void chkHLine();
|
||||
void setVerticalCode();
|
||||
void setHorizontalCode();
|
||||
void guardSee();
|
||||
void setGuardFrame();
|
||||
public:
|
||||
Guard(AmazonEngine *vm);
|
||||
|
||||
void doGuard();
|
||||
|
||||
void setPosition(const Common::Point &pt);
|
||||
};
|
||||
|
||||
class Cast : public PannedScene {
|
||||
public:
|
||||
Cast(AmazonEngine *vm);
|
||||
|
||||
void doCast(int param1);
|
||||
};
|
||||
|
||||
class River : public PannedScene {
|
||||
private:
|
||||
bool _chickenOutFl;
|
||||
const byte *_mapPtr;
|
||||
int _canoeVXPos;
|
||||
int _canoeMoveCount;
|
||||
int _canoeFrame;
|
||||
RiverStruct *_topList;
|
||||
RiverStruct *_botList;
|
||||
int _canoeDir;
|
||||
bool _saveRiver;
|
||||
bool _deathFlag;
|
||||
int _deathCount;
|
||||
int _deathType;
|
||||
int _maxHits;
|
||||
|
||||
// Saved fields
|
||||
int _canoeLane;
|
||||
int _canoeYPos;
|
||||
int _hitCount;
|
||||
int _riverIndex;
|
||||
int _hitSafe;
|
||||
int _rScrollRow;
|
||||
int _rScrollCol;
|
||||
int _rScrollX;
|
||||
int _rScrollY;
|
||||
int _mapOffset;
|
||||
int _screenVertX;
|
||||
int _oldScrollCol;
|
||||
|
||||
void initRiver();
|
||||
void resetPositions();
|
||||
void checkRiverPan();
|
||||
bool riverJumpTest();
|
||||
void riverSound();
|
||||
void moveCanoe();
|
||||
void moveCanoe2();
|
||||
void updateObstacles();
|
||||
void riverSetPhysX();
|
||||
bool checkRiverCollide();
|
||||
void plotRiver();
|
||||
void scrollRiver();
|
||||
void scrollRiver1();
|
||||
void setRiverPan();
|
||||
public:
|
||||
River(AmazonEngine *vm);
|
||||
|
||||
void doRiver();
|
||||
void mWhileDownRiver();
|
||||
|
||||
void synchronize(Common::Serializer &s);
|
||||
};
|
||||
|
||||
enum AntDirection { ANT_RIGHT = 0, ANT_LEFT = 1 };
|
||||
|
||||
class Ant : public AmazonManager {
|
||||
private:
|
||||
AntDirection _antDirection;
|
||||
AntDirection _pitDirection;
|
||||
int _antCel;
|
||||
int _torchCel;
|
||||
int _pitCel;
|
||||
int _stabCel;
|
||||
Common::Point _antPos;
|
||||
bool _antDieFl;
|
||||
bool _antEatFl;
|
||||
bool _stabFl;
|
||||
Common::Point _pitPos;
|
||||
|
||||
void plotTorchSpear(int indx, const int *&buf);
|
||||
void plotPit(int indx, const int *&buf);
|
||||
int antHandleRight(int indx, const int *&buf);
|
||||
int antHandleLeft(int indx, const int *&buf);
|
||||
int antHandleStab(int indx, const int *&buf);
|
||||
public:
|
||||
Ant(AmazonEngine *vm);
|
||||
|
||||
void doAnt();
|
||||
|
||||
void synchronize(Common::Serializer &s);
|
||||
};
|
||||
|
||||
class InactivePlayer : public ImageEntry {
|
||||
public:
|
||||
SpriteResource *_altSpritesPtr;
|
||||
|
||||
InactivePlayer() { _altSpritesPtr = nullptr; }
|
||||
};
|
||||
|
||||
} // End of namespace Amazon
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_AMAZON_LOGIC_H */
|
||||
101
engines/access/amazon/amazon_player.cpp
Normal file
101
engines/access/amazon/amazon_player.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/* 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 "common/scummsys.h"
|
||||
#include "access/access.h"
|
||||
#include "access/room.h"
|
||||
#include "access/amazon/amazon_game.h"
|
||||
#include "access/amazon/amazon_player.h"
|
||||
#include "access/amazon/amazon_resources.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
namespace Amazon {
|
||||
|
||||
AmazonPlayer::AmazonPlayer(AccessEngine *vm) : Player(vm) {
|
||||
_game = (AmazonEngine *)vm;
|
||||
}
|
||||
|
||||
void AmazonPlayer::load() {
|
||||
Player::load();
|
||||
|
||||
// Special scene setup for the top-down view when on the Slaver ship
|
||||
if (_vm->_room->_roomFlag == 3) {
|
||||
_playerOffset.x = _vm->_screen->_scaleTable1[8];
|
||||
_playerOffset.y = _vm->_screen->_scaleTable1[11];
|
||||
_leftDelta = 0;
|
||||
_rightDelta = 8;
|
||||
_upDelta = 2;
|
||||
_downDelta = -2;
|
||||
_scrollConst = 2;
|
||||
|
||||
for (uint8 i = 0; i < _vm->_playerDataCount; ++i) {
|
||||
_walkOffRight[i] = OVEROFFR[i];
|
||||
_walkOffLeft[i] = OVEROFFL[i];
|
||||
_walkOffUp[i] = OVEROFFU[i];
|
||||
_walkOffDown[i] = OVEROFFD[i];
|
||||
_walkOffUR[i].x = OVEROFFURX[i];
|
||||
_walkOffUR[i].y = OVEROFFURY[i];
|
||||
_walkOffDR[i].x = OVEROFFDRX[i];
|
||||
_walkOffDR[i].y = OVEROFFDRY[i];
|
||||
_walkOffUL[i].x = OVEROFFULX[i];
|
||||
_walkOffUL[i].y = OVEROFFULY[i];
|
||||
_walkOffDL[i].x = OVEROFFDLX[i];
|
||||
_walkOffDL[i].y = OVEROFFDLY[i];
|
||||
}
|
||||
|
||||
_vm->_timers[8]._initTm = 7;
|
||||
_vm->_timers[8]._timer = 7;
|
||||
++_vm->_timers[8]._flag;
|
||||
|
||||
_sideWalkMin = 0;
|
||||
_sideWalkMax = 5;
|
||||
_upWalkMin = 12;
|
||||
_upWalkMax = 17;
|
||||
_downWalkMin = 6;
|
||||
_downWalkMax = 11;
|
||||
_diagUpWalkMin = 0;
|
||||
_diagUpWalkMax = 5;
|
||||
_diagDownWalkMin = 0;
|
||||
_diagDownWalkMax = 5;
|
||||
_game->_guard->setPosition(Common::Point(56, 190));
|
||||
} else {
|
||||
for (uint8 i = 0; i < _vm->_playerDataCount; ++i) {
|
||||
_walkOffRight[i] = SIDEOFFR[i];
|
||||
_walkOffLeft[i] = SIDEOFFL[i];
|
||||
_walkOffUp[i] = SIDEOFFU[i];
|
||||
_walkOffDown[i] = SIDEOFFD[i];
|
||||
|
||||
_walkOffUR[i].x = DIAGOFFURX[i];
|
||||
_walkOffUR[i].y = DIAGOFFURY[i];
|
||||
_walkOffDR[i].x = DIAGOFFDRX[i];
|
||||
_walkOffDR[i].y = DIAGOFFDRY[i];
|
||||
_walkOffUL[i].x = DIAGOFFULX[i];
|
||||
_walkOffUL[i].y = DIAGOFFULY[i];
|
||||
_walkOffDL[i].x = DIAGOFFDLX[i];
|
||||
_walkOffDL[i].y = DIAGOFFDLY[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Amazon
|
||||
|
||||
} // End of namespace Access
|
||||
47
engines/access/amazon/amazon_player.h
Normal file
47
engines/access/amazon/amazon_player.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* 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 ACCESS_AMAZON_PLAYER_H
|
||||
#define ACCESS_AMAZON_PLAYER_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "access/player.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
namespace Amazon {
|
||||
|
||||
class AmazonEngine;
|
||||
|
||||
class AmazonPlayer : public Player {
|
||||
private:
|
||||
AmazonEngine *_game;
|
||||
public:
|
||||
AmazonPlayer(AccessEngine *vm);
|
||||
|
||||
void load() override;
|
||||
};
|
||||
|
||||
} // End of namespace Amazon
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_AMAZON_PLAYER_H */
|
||||
548
engines/access/amazon/amazon_resources.cpp
Normal file
548
engines/access/amazon/amazon_resources.cpp
Normal file
@@ -0,0 +1,548 @@
|
||||
/* 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 "access/amazon/amazon_resources.h"
|
||||
#include "access/access.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
namespace Amazon {
|
||||
|
||||
static const int BTN_RANGES[6][2] = {
|
||||
{ 0, 76 }, { 77, 154 }, { 155, 232 }, { 233, 276 }, { 0, 0 }, { 277, 319 }
|
||||
};
|
||||
|
||||
static const int RMOUSE[10][2] = {
|
||||
{ 0, 35 }, { 0, 0 }, { 36, 70 }, { 71, 106 }, { 107, 141 },
|
||||
{ 142, 177 }, { 178, 212 }, { 213, 248 }, { 249, 283 }, { 284, 318 }
|
||||
};
|
||||
|
||||
AmazonResources::~AmazonResources() {
|
||||
delete _font3x5;
|
||||
delete _font6x6;
|
||||
}
|
||||
|
||||
void AmazonResources::load(Common::SeekableReadStream &s) {
|
||||
Resources::load(s);
|
||||
uint count;
|
||||
|
||||
// Load the version specific data
|
||||
NO_HELP_MESSAGE = s.readString();
|
||||
NO_HINTS_MESSAGE = s.readString();
|
||||
RIVER_HIT1 = s.readString();
|
||||
RIVER_HIT2 = s.readString();
|
||||
BAR_MESSAGE = s.readString();
|
||||
|
||||
for (int idx = 0; idx < 3; ++idx)
|
||||
HELPLVLTXT[idx] = s.readString();
|
||||
for (int idx = 0; idx < 9; ++idx)
|
||||
IQLABELS[idx] = s.readString();
|
||||
|
||||
CANT_GET_THERE = s.readString();
|
||||
|
||||
// Get the offset of the general shared data for the game
|
||||
uint entryOffset = findEntry(_vm->getGameID(), 2, 0, (Common::Language)0);
|
||||
s.seek(entryOffset);
|
||||
|
||||
// Read in the cursor list
|
||||
count = s.readUint16LE();
|
||||
CURSORS.resize(count);
|
||||
for (uint idx = 0; idx < count; ++idx) {
|
||||
uint count2 = s.readUint16LE();
|
||||
CURSORS[idx].resize(count2);
|
||||
s.read(&CURSORS[idx][0], count2);
|
||||
}
|
||||
|
||||
// Load font data
|
||||
count = s.readUint16LE();
|
||||
Common::Array<int> index;
|
||||
Common::Array<byte> data;
|
||||
|
||||
index.resize(count);
|
||||
for (uint idx = 0; idx < count; ++idx)
|
||||
index[idx] = s.readSint16LE();
|
||||
|
||||
count = s.readUint16LE();
|
||||
data.resize(count);
|
||||
for (uint idx = 0; idx < count; ++idx)
|
||||
data[idx] = s.readByte();
|
||||
_font3x5 = new AmazonFont(&index[0], &data[0]);
|
||||
|
||||
count = s.readUint16LE();
|
||||
index.resize(count);
|
||||
for (uint idx = 0; idx < count; ++idx)
|
||||
index[idx] = s.readSint16LE();
|
||||
|
||||
count = s.readUint16LE();
|
||||
data.resize(count);
|
||||
for (uint idx = 0; idx < count; ++idx)
|
||||
data[idx] = s.readByte();
|
||||
_font6x6 = new AmazonFont(&index[0], &data[0]);
|
||||
}
|
||||
|
||||
const byte *AmazonResources::getCursor(int num) const {
|
||||
return CURSORS[num].data();
|
||||
}
|
||||
|
||||
int AmazonResources::getRMouse(int i, int j) const {
|
||||
return RMOUSE[i][j];
|
||||
}
|
||||
|
||||
int AmazonResources::inButtonXRange(int x) const {
|
||||
for (int i = 0; i < ARRAYSIZE(BTN_RANGES); i++) {
|
||||
if ((x >= BTN_RANGES[i][0]) && (x < BTN_RANGES[i][1]))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
const int SIDEOFFR[] = { 5, 5, 5, 5, 5, 5, 5, 5, 0 };
|
||||
const int SIDEOFFL[] = { 5, 5, 5, 5, 5, 5, 5, 5, 0 };
|
||||
const int SIDEOFFU[] = { 2, 2, 2, 2, 2, 2, 2, 2, 0 };
|
||||
const int SIDEOFFD[] = { 2, 2, 2, 2, 2, 2, 2, 2, 0 };
|
||||
const int DIAGOFFURX[] = { 4, 5, 2, 2, 3, 4, 2, 2, 0 };
|
||||
const int DIAGOFFURY[] = { 2, 3, 2, 2, 2, 3, 1, 1, 0 };
|
||||
const int DIAGOFFDRX[] = { 4, 5, 4, 3, 5, 4, 5, 1, 0 };
|
||||
const int DIAGOFFDRY[] = { 3, 2, 1, 2, 2, 1, 2, 1, 0 };
|
||||
const int DIAGOFFULX[] = { 4, 5, 4, 3, 3, 2, 2, 2, 0 };
|
||||
const int DIAGOFFULY[] = { 3, 3, 1, 2, 2, 1, 1, 1, 0 };
|
||||
const int DIAGOFFDLX[] = { 4, 5, 3, 3, 5, 4, 6, 1, 0 };
|
||||
const int DIAGOFFDLY[] = { 2, 2, 1, 2, 3, 1, 2, 1, 0 };
|
||||
|
||||
const int OVEROFFR[] = { 2, 2, 1, 2, 2, 1, 0, 0, 0 };
|
||||
const int OVEROFFL[] = { 2, 2, 1, 2, 2, 1, 0, 0, 0 };
|
||||
const int OVEROFFU[] = { 1, 1, 1, 1, 1, 1, 0, 0, 0 };
|
||||
const int OVEROFFD[] = { 1, 1, 1, 1, 1, 1, 0, 0, 0 };
|
||||
const int OVEROFFURX[] = { 3, 1, 1, 2, 2, 1, 0, 0, 0 };
|
||||
const int OVEROFFURY[] = { 1, 0, 0, 1, 1, 0, 0, 0, 0 };
|
||||
const int OVEROFFDRX[] = { 1, 2, 1, 1, 2, 1, 0, 0, 0 };
|
||||
const int OVEROFFDRY[] = { 0, 1, 0, 0, 1, 1, 0, 0, 0 };
|
||||
const int OVEROFFULX[] = { 2, 1, 1, 1, 2, 1, 0, 0, 0 };
|
||||
const int OVEROFFULY[] = { 1, 0, 0, 2, 1, 0, 0, 0, 0 };
|
||||
const int OVEROFFDLX[] = { 1, 2, 1, 1, 2, 1, 0, 0, 0 };
|
||||
const int OVEROFFDLY[] = { 0, 1, 0, 0, 1, 1, 0, 0, 0 };
|
||||
|
||||
const int DEATH_CELLS[13][3] = {
|
||||
{ 0, 94, 2 },
|
||||
{ 0, 94, 3 },
|
||||
{ 0, 94, 4 },
|
||||
{ 0, 94, 5 },
|
||||
{ 0, 94, 6 },
|
||||
{ 0, 94, 7 },
|
||||
{ 0, 94, 8 },
|
||||
{ 0, 94, 9 },
|
||||
{ 0, 94, 10 },
|
||||
{ 0, 94, 11 },
|
||||
{ 0, 94, 12 },
|
||||
{ 0, 94, 13 },
|
||||
{ 0, 94, 14 }
|
||||
};
|
||||
|
||||
const int CHAPTER_CELLS[17][3] = {
|
||||
{ 1, 96, 18 },
|
||||
{ 2, 96, 19 },
|
||||
{ 3, 96, 20 },
|
||||
{ 4, 96, 21 },
|
||||
{ 5, 96, 22 },
|
||||
{ 6, 96, 23 },
|
||||
{ 7, 96, 24 },
|
||||
{ 8, 96, 25 },
|
||||
{ 9, 96, 26 },
|
||||
{ 10, 96, 27 },
|
||||
{ 11, 96, 28 },
|
||||
{ 12, 96, 29 },
|
||||
{ 13, 96, 30 },
|
||||
{ 14, 96, 31 }
|
||||
};
|
||||
|
||||
const int CHAPTER_TABLE[14][5] = {
|
||||
{ 18, 136, 27, 76, 49 },
|
||||
{ 16, 134, 27, 53, 74 },
|
||||
{ 16, 136, 27, 52, 56 },
|
||||
{ 16, 135, 26, 46, 75 },
|
||||
{ 16, 135, 27, 54, 66 },
|
||||
{ 16, 137, 27, 67, 79 },
|
||||
{ 14, 136, 27, 82, 52 },
|
||||
{ 15, 136, 26, 65, 73 },
|
||||
{ 15, 137, 26, 48, 75 },
|
||||
{ 17, 135, 27, 52, 66 },
|
||||
{ 15, 135, 27, 62, 65 },
|
||||
{ 16, 135, 28, 45, 66 },
|
||||
{ 16, 135, 28, 36, 67 },
|
||||
{ 15, 135, 27, 34, 63 }
|
||||
};
|
||||
|
||||
const int CHAPTER_JUMP[14] = {
|
||||
0, 12, 10, 15, 19, 25, 31, 36, 45, 46, 29, 55, 61, 0
|
||||
};
|
||||
|
||||
const int ANTWALK[24] = {
|
||||
0, 3, 0,
|
||||
1, 5, 0,
|
||||
2, 4, 0,
|
||||
3, 2, 0,
|
||||
4, 4, 0,
|
||||
5, 3, 0,
|
||||
6, 4, 0,
|
||||
-1, -1, -1
|
||||
};
|
||||
|
||||
const int ANTEAT[33] = {
|
||||
7, 0, -1,
|
||||
8, 0, -5,
|
||||
9, 0, -11,
|
||||
10, 0, 7,
|
||||
11, 0, -3,
|
||||
12, 0, 3,
|
||||
13, 0, -1,
|
||||
9, 0, -6,
|
||||
8, 0, 11,
|
||||
7, 0, 6,
|
||||
-1, -1, -1
|
||||
};
|
||||
|
||||
const int ANTDIE[21] = {
|
||||
14, 4, 8,
|
||||
15, 7, 6,
|
||||
16, 6, 7,
|
||||
17, 8, 2,
|
||||
18, 0, 0,
|
||||
19, 0, 0,
|
||||
-1, -1, -1
|
||||
};
|
||||
|
||||
const int PITWALK[27] = {
|
||||
18, 0, -1,
|
||||
19, -2, 1,
|
||||
20, -2, 1,
|
||||
21, -2, 1,
|
||||
22, -2, 0,
|
||||
23, -3, 0,
|
||||
24, -3, -1,
|
||||
25, -2, -1,
|
||||
-1, -1, -1
|
||||
};
|
||||
|
||||
const int PITSTAB[21] = {
|
||||
14, -2, 0,
|
||||
15, -4, 0,
|
||||
16, 3, -13,
|
||||
16, 0, 0,
|
||||
15, -3, 13,
|
||||
14, 4, 0,
|
||||
-1, -1, -1
|
||||
};
|
||||
|
||||
const int TORCH[12] = {
|
||||
26, -11, -7,
|
||||
27, -12, -2,
|
||||
28, -15, -4,
|
||||
-1, -1, -1
|
||||
};
|
||||
|
||||
const int SPEAR[3] = {30, -13, 1};
|
||||
|
||||
const int OPENING_OBJS[10][4] = {
|
||||
{8, -80, 120, 30},
|
||||
{13, 229, 0, 50},
|
||||
{12, 78, 0, 50},
|
||||
{11, 10, 0, 50},
|
||||
{10, 178, 97, 50},
|
||||
{9, 92, 192, 50},
|
||||
{14, 38, 0, 100},
|
||||
{15, 132, 76, 100},
|
||||
{16, 142, 0, 100},
|
||||
{4, -280, 40, 120},
|
||||
};
|
||||
|
||||
const byte MAP0[26] = {
|
||||
0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 4, 0,
|
||||
0, 0, 1, 0, 2, 0, 0, 1, 1, 3, 0, 0,
|
||||
0, 0xFF
|
||||
};
|
||||
|
||||
const byte MAP1[27] = {
|
||||
0, 0, 1, 0, 3, 0, 0, 1, 1, 2, 0, 0,
|
||||
0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 4, 0,
|
||||
0, 0, 0xFF
|
||||
};
|
||||
|
||||
const byte MAP2[32] = {
|
||||
0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 1, 0,
|
||||
3, 0, 0, 1, 0, 4, 0, 0, 1, 1, 2, 0,
|
||||
0, 1, 0, 1, 0, 0, 0, 0xFF
|
||||
};
|
||||
|
||||
const byte *const MAPTBL[3] = {MAP0, MAP1, MAP2};
|
||||
|
||||
const int DOWNRIVEROBJ[14][4] = {
|
||||
{ 3, 77, 0, 40 },
|
||||
{ 2, 30, 0, 30 },
|
||||
{ 2, 290, 0, 50 },
|
||||
{ 1, 210, 0, 70 },
|
||||
{ 2, 350, 0, 30 },
|
||||
{ 1, 370, 0, 20 },
|
||||
{ 2, 480, 0, 60 },
|
||||
{ 3, 395, 0, 10 },
|
||||
{ 1, 550, 0, 30 },
|
||||
{ 2, 620, 0, 50 },
|
||||
{ 1, 690, 0, 10 },
|
||||
{ 2, 715, 0, 40 },
|
||||
{ 1, 770, 0, 30 },
|
||||
{ 3, 700, 0, 20 }
|
||||
};
|
||||
|
||||
RiverStruct RIVER0OBJECTS[46] = {
|
||||
{16, 31, 6400, 0, 4, 12},
|
||||
{16, 31, 6200, 0, 2, 12},
|
||||
{17, 30, 6100, 0, 3, 15},
|
||||
{16, 31, 5970, 0, 7, 12},
|
||||
{17, 30, 5910, 0, 5, 15},
|
||||
{17, 30, 5730, 0, 3, 15},
|
||||
{16, 31, 5700, 0, 7, 12},
|
||||
{-1, 314, 5392, 0, 4, 0},
|
||||
{17, 30, 5155, 0, 1, 15},
|
||||
{16, 31, 5150, 0, 5, 12},
|
||||
{16, 31, 5056, 0, 7, 12},
|
||||
{17, 30, 4900, 0, 2, 15},
|
||||
{17, 30, 4785, 0, 7, 15},
|
||||
{16, 31, 4690, 0, 4, 12},
|
||||
{16, 31, 4660, 0, 1, 12},
|
||||
{17, 30, 4560, 0, 5, 15},
|
||||
{16, 31, 4465, 0, 2, 12},
|
||||
{-1, 314, 4112, 0, 4, 0},
|
||||
{17, 30, 4005, 0, 3, 15},
|
||||
{16, 31, 3865, 0, 6, 12},
|
||||
{17, 30, 3605, 0, 4, 15},
|
||||
{16, 31, 3360, 0, 1, 12},
|
||||
{17, 30, 3105, 0, 0, 15},
|
||||
{16, 31, 3080, 0, 7, 12},
|
||||
{17, 30, 3014, 0, 4, 15},
|
||||
{16, 31, 2992, 0, 3, 12},
|
||||
{16, 31, 2976, 0, 2, 12},
|
||||
{17, 30, 2880, 0, 7, 15},
|
||||
{17, 30, 2860, 0, 0, 15},
|
||||
{-1, 314, 2512, 0, 4, 0},
|
||||
{17, 30, 2270, 0, 4, 15},
|
||||
{16, 31, 2195, 0, 6, 12},
|
||||
{17, 30, 1824, 0, 1, 15},
|
||||
{16, 31, 1776, 0, 4, 12},
|
||||
{17, 30, 1650, 0, 3, 15},
|
||||
{16, 31, 1616, 0, 7, 12},
|
||||
{17, 30, 1585, 0, 2, 15},
|
||||
{-1, 314, 1232, 0, 4, 0},
|
||||
{17, 30, 1190, 0, 2, 15},
|
||||
{16, 31, 1120, 0, 4, 12},
|
||||
{17, 30, 970, 0, 7, 15},
|
||||
{16, 31, 910, 0, 5, 12},
|
||||
{17, 30, 705, 0, 0, 15},
|
||||
{16, 31, 550, 0, 4, 12},
|
||||
{17, 30, 305, 0, 2, 15},
|
||||
{16, 31, 260, 0, 7, 12}
|
||||
};
|
||||
|
||||
RiverStruct RIVER1OBJECTS[50] = {
|
||||
{16, 31, 6920, 0, 1, 12},
|
||||
{16, 31, 6740, 0, 4, 12},
|
||||
{17, 30, 6699, 0, 1, 15},
|
||||
{16, 31, 6610, 0, 2, 12},
|
||||
{17, 30, 6495, 0, 6, 15},
|
||||
{17, 30, 6385, 0, 4, 15},
|
||||
{16, 31, 6350, 0, 1, 12},
|
||||
{17, 30, 6180, 0, 0, 15},
|
||||
{-1, 314, 6032, 0, 4, 0},
|
||||
{16, 31, 5800, 0, 3, 12},
|
||||
{17, 30, 5790, 0, 6, 15},
|
||||
{16, 31, 5530, 0, 4, 12},
|
||||
{16, 31, 5500, 0, 7, 12},
|
||||
{17, 30, 5495, 0, 1, 15},
|
||||
{17, 30, 5376, 0, 0, 15},
|
||||
{16, 31, 5328, 0, 7, 12},
|
||||
{17, 30, 5248, 0, 2, 15},
|
||||
{16, 31, 5248, 0, 6, 12},
|
||||
{-1, 314, 4752, 0, 4, 0},
|
||||
{17, 30, 4432, 0, 2, 15},
|
||||
{16, 31, 4432, 0, 7, 12},
|
||||
{16, 31, 4384, 0, 2, 12},
|
||||
{17, 30, 4368, 0, 5, 15},
|
||||
{16, 31, 4336, 0, 4, 12},
|
||||
{17, 30, 4185, 0, 1, 15},
|
||||
{16, 31, 4125, 0, 3, 12},
|
||||
{17, 30, 3817, 0, 7, 15},
|
||||
{16, 31, 3612, 0, 4, 12},
|
||||
{16, 31, 3360, 0, 5, 12},
|
||||
{16, 31, 3265, 0, 7, 12},
|
||||
{17, 30, 3200, 0, 1, 15},
|
||||
{17, 30, 3056, 0, 6, 15},
|
||||
{-1, 314, 2832, 0, 4, 0},
|
||||
{16, 31, 2740, 0, 3, 12},
|
||||
{17, 30, 2694, 0, 6, 15},
|
||||
{16, 31, 2455, 0, 0, 12},
|
||||
{17, 30, 2285, 0, 5, 15},
|
||||
{16, 31, 2260, 0, 2, 12},
|
||||
{16, 31, 1904, 0, 5, 12},
|
||||
{17, 30, 1808, 0, 1, 15},
|
||||
{16, 31, 1744, 0, 7, 12},
|
||||
{17, 30, 1696, 0, 4, 15},
|
||||
{16, 31, 1568, 0, 2, 12},
|
||||
{-1, 314, 1232, 0, 4, 0},
|
||||
{17, 30, 970, 0, 4, 15},
|
||||
{16, 31, 910, 0, 7, 12},
|
||||
{17, 30, 705, 0, 0, 15},
|
||||
{16, 31, 550, 0, 6, 12},
|
||||
{17, 30, 305, 0, 3, 15},
|
||||
{ 16, 31, 260, 0, 1, 12 }
|
||||
};
|
||||
|
||||
RiverStruct RIVER2OBJECTS[54] = {
|
||||
{16, 31, 8230, 0, 6, 12},
|
||||
{16, 31, 8115, 0, 7, 12},
|
||||
{17, 30, 7955, 0, 4, 15},
|
||||
{16, 31, 7890, 0, 0, 12},
|
||||
{16, 31, 7616, 0, 2, 12},
|
||||
{17, 30, 7472, 0, 5, 15},
|
||||
{16, 31, 7425, 0, 4, 12},
|
||||
{17, 30, 7360, 0, 1, 15},
|
||||
{16, 31, 7328, 0, 6, 12},
|
||||
{-1, 314, 6992, 0, 4, 0},
|
||||
{16, 31, 6720, 0, 3, 12},
|
||||
{17, 30, 6700, 0, 6, 15},
|
||||
{16, 31, 6518, 0, 2, 12},
|
||||
{17, 30, 6225, 0, 5, 15},
|
||||
{16, 31, 6200, 0, 2, 12},
|
||||
{17, 30, 5990, 0, 1, 15},
|
||||
{16, 31, 5960, 0, 7, 12},
|
||||
{16, 31, 5700, 0, 2, 12},
|
||||
{17, 30, 5650, 0, 4, 15},
|
||||
{16, 31, 5568, 0, 5, 12},
|
||||
{17, 30, 5488, 0, 6, 15},
|
||||
{-1, 314, 5072, 0, 4, 0},
|
||||
{17, 30, 4825, 0, 4, 15},
|
||||
{16, 31, 4782, 0, 2, 12},
|
||||
{17, 30, 4660, 0, 5, 15},
|
||||
{16, 31, 4510, 0, 7, 12},
|
||||
{16, 31, 4495, 0, 1, 12},
|
||||
{17, 30, 4250, 0, 2, 15},
|
||||
{16, 31, 4195, 0, 4, 12},
|
||||
{-1, 314, 3792, 0, 4, 0},
|
||||
{17, 30, 3600, 0, 3, 15},
|
||||
{16, 31, 3470, 0, 5, 12},
|
||||
{16, 31, 3422, 0, 2, 12},
|
||||
{17, 30, 3170, 0, 6, 15},
|
||||
{16, 31, 2960, 0, 4, 12},
|
||||
{17, 30, 2955, 0, 7, 15},
|
||||
{-1, 314, 2512, 0, 4, 0},
|
||||
{17, 30, 2415, 0, 1, 15},
|
||||
{16, 31, 2318, 0, 0, 12},
|
||||
{17, 30, 2275, 0, 2, 15},
|
||||
{16, 31, 2270, 0, 6, 12},
|
||||
{17, 30, 2026, 0, 3, 15},
|
||||
{16, 31, 2000, 0, 0, 12},
|
||||
{16, 31, 1840, 0, 3, 12},
|
||||
{17, 30, 1795, 0, 7, 15},
|
||||
{16, 31, 1634, 0, 5, 12},
|
||||
{17, 30, 1630, 0, 1, 15},
|
||||
{-1, 314, 1232, 0, 4, 0},
|
||||
{17, 30, 970, 0, 2, 15},
|
||||
{16, 31, 910, 0, 5, 12},
|
||||
{17, 30, 705, 0, 0, 15},
|
||||
{16, 31, 550, 0, 4, 12},
|
||||
{17, 30, 305, 0, 3, 15},
|
||||
{16, 31, 260, 0, 6, 12}
|
||||
};
|
||||
|
||||
RiverStruct *RIVER_OBJECTS[3][2] = {
|
||||
{ RIVER0OBJECTS, RIVER0OBJECTS + 46 - 1},
|
||||
{ RIVER1OBJECTS, RIVER1OBJECTS + 50 - 1 },
|
||||
{ RIVER2OBJECTS, RIVER2OBJECTS + 54 - 1 }
|
||||
};
|
||||
|
||||
const int HELP1COORDS[2][4] = {
|
||||
{ 76, 129, 168, 183 }, { 187, 240, 168, 183 }
|
||||
};
|
||||
|
||||
const int RIVER1OBJ[23][4] = {
|
||||
{ 18, -77, 0, 30 },
|
||||
{ 18, -325, 0, 20 },
|
||||
{ 18, -450, 0, 15 },
|
||||
{ 18, -1250, 0, 25 },
|
||||
{ 19, -130, 0, 20 },
|
||||
{ 19, -410, 0, 15 },
|
||||
{ 19, -710, 0, 25 },
|
||||
{ 19, -1510, 0, 20 },
|
||||
{ 20, -350, 0, 30 },
|
||||
{ 20, -695, 0, 25 },
|
||||
{ 20, -990, 0, 20 },
|
||||
{ 20, -1300, 0, 25 },
|
||||
{ 20, -1600, 0, 30 },
|
||||
{ 21, -370, 0, 20 },
|
||||
{ 21, -650, 0, 30 },
|
||||
{ 21, -1215, 0, 40 },
|
||||
{ 21, -1815, 0, 35 },
|
||||
{ 22, -380, 0, 25 },
|
||||
{ 22, -720, 0, 35 },
|
||||
{ 22, -1020, 0, 30 },
|
||||
{ 22, -1170, 0, 25 },
|
||||
{ 22, -1770, 0, 35 },
|
||||
{ 23, -500, 63, 20 }
|
||||
};
|
||||
|
||||
const int CAST_END_OBJ[26][4] = {
|
||||
{ 0, 118, 210, 10 },
|
||||
{ 1, 38, 250, 10 },
|
||||
{ 2, 38, 280, 10 },
|
||||
{ 3, 38, 310, 10 },
|
||||
{ 4, 38, 340, 10 },
|
||||
{ 5, 38, 370, 10 },
|
||||
{ 6, 38, 400, 10 },
|
||||
{ 7, 38, 430, 10 },
|
||||
{ 8, 38, 460, 10 },
|
||||
{ 9, 38, 490, 10 },
|
||||
{ 10, 38, 520, 10 },
|
||||
{ 11, 38, 550, 10 },
|
||||
{ 12, 38, 580, 10 },
|
||||
{ 13, 38, 610, 10 },
|
||||
{ 14, 38, 640, 10 },
|
||||
{ 15, 38, 670, 10 },
|
||||
{ 16, 38, 700, 10 },
|
||||
{ 17, 38, 730, 10 },
|
||||
{ 18, 38, 760, 10 },
|
||||
{ 19, 38, 790, 10 },
|
||||
{ 20, 95, 820, 10 },
|
||||
{ 21, 94, 850, 10 },
|
||||
{ 22, 96, 880, 10 },
|
||||
{ 23, 114, 910, 10 },
|
||||
{ 24, 114, 940, 10 },
|
||||
{ 25, 110, 970, 10 }
|
||||
};
|
||||
|
||||
const int CAST_END_OBJ1[4][4] = {
|
||||
{ 0, 40, 1100, 10 },
|
||||
{ 2, 11, 1180, 10 },
|
||||
{ 1, 154, 1180, 10 },
|
||||
{ 3, 103, 1300, 10 }
|
||||
};
|
||||
|
||||
|
||||
} // End of namespace Amazon
|
||||
} // End of namespace Access
|
||||
156
engines/access/amazon/amazon_resources.h
Normal file
156
engines/access/amazon/amazon_resources.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/* 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 ACCESS_AMAZON_RESOURCES_H
|
||||
#define ACCESS_AMAZON_RESOURCES_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/array.h"
|
||||
#include "access/resources.h"
|
||||
#include "access/font.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
namespace Amazon {
|
||||
|
||||
enum InventoryEnum {
|
||||
INV_BAITED_POLE = 67, INV_TORCH = 76, INV_KNIFE_SPEAR = 78
|
||||
};
|
||||
|
||||
struct RiverStruct {
|
||||
int _id;
|
||||
int _width;
|
||||
int _riverX;
|
||||
int _xp;
|
||||
int _lane;
|
||||
int _offsetY;
|
||||
};
|
||||
|
||||
extern const int SIDEOFFR[];
|
||||
extern const int SIDEOFFL[];
|
||||
extern const int SIDEOFFU[];
|
||||
extern const int SIDEOFFD[];
|
||||
extern const int DIAGOFFURX[];
|
||||
extern const int DIAGOFFURY[];
|
||||
extern const int DIAGOFFDRX[];
|
||||
extern const int DIAGOFFDRY[];
|
||||
extern const int DIAGOFFULX[];
|
||||
extern const int DIAGOFFULY[];
|
||||
extern const int DIAGOFFDLX[];
|
||||
extern const int DIAGOFFDLY[];
|
||||
|
||||
extern const int _travelPos[][2];
|
||||
|
||||
extern const int OVEROFFR[];
|
||||
extern const int OVEROFFL[];
|
||||
extern const int OVEROFFU[];
|
||||
extern const int OVEROFFD[];
|
||||
extern const int OVEROFFURX[];
|
||||
extern const int OVEROFFURY[];
|
||||
extern const int OVEROFFDRX[];
|
||||
extern const int OVEROFFDRY[];
|
||||
extern const int OVEROFFULX[];
|
||||
extern const int OVEROFFULY[];
|
||||
extern const int OVEROFFDLX[];
|
||||
extern const int OVEROFFDLY[];
|
||||
|
||||
extern const int DEATH_CELLS[13][3];
|
||||
|
||||
extern const int CHAPTER_CELLS[17][3];
|
||||
|
||||
extern const int CHAPTER_TABLE[14][5];
|
||||
|
||||
extern const int CHAPTER_JUMP[14];
|
||||
|
||||
extern const int COMBO_TABLE[85][4];
|
||||
|
||||
extern const int ANTWALK[24];
|
||||
|
||||
extern const int ANTEAT[33];
|
||||
|
||||
extern const int ANTDIE[21];
|
||||
|
||||
extern const int PITWALK[27];
|
||||
|
||||
extern const int PITSTAB[21];
|
||||
|
||||
extern const int TORCH[12];
|
||||
|
||||
extern const int SPEAR[3];
|
||||
|
||||
extern const int OPENING_OBJS[10][4];
|
||||
|
||||
extern const byte MAP0[26];
|
||||
extern const byte MAP1[27];
|
||||
extern const byte MAP2[32];
|
||||
|
||||
extern const byte *const MAPTBL[3];
|
||||
|
||||
extern const int DOWNRIVEROBJ[14][4];
|
||||
|
||||
extern RiverStruct RIVER0OBJECTS[46];
|
||||
extern RiverStruct RIVER1OBJECTS[50];
|
||||
extern RiverStruct RIVER2OBJECTS[54];
|
||||
extern RiverStruct *RIVER_OBJECTS[3][2];
|
||||
enum { RIVER_START = 0, RIVER_END = 1 };
|
||||
|
||||
extern const int HELP1COORDS[2][4];
|
||||
|
||||
extern const int RIVER1OBJ[23][4];
|
||||
|
||||
extern const int CAST_END_OBJ[26][4];
|
||||
extern const int CAST_END_OBJ1[4][4];
|
||||
|
||||
class AmazonResources: public Resources {
|
||||
protected:
|
||||
/**
|
||||
* Load data from the access.dat file
|
||||
*/
|
||||
void load(Common::SeekableReadStream &s) override;
|
||||
public:
|
||||
AmazonFont *_font3x5, *_font6x6;
|
||||
Common::String NO_HELP_MESSAGE;
|
||||
Common::String NO_HINTS_MESSAGE;
|
||||
Common::String RIVER_HIT1;
|
||||
Common::String RIVER_HIT2;
|
||||
Common::String BAR_MESSAGE;
|
||||
Common::String HELPLVLTXT[3];
|
||||
Common::String IQLABELS[9];
|
||||
|
||||
private:
|
||||
Common::Array< Common::Array<byte> > CURSORS;
|
||||
|
||||
public:
|
||||
AmazonResources(AccessEngine *vm) : Resources(vm), _font3x5(nullptr), _font6x6(nullptr) {}
|
||||
~AmazonResources() override;
|
||||
|
||||
const byte *getCursor(int num) const override;
|
||||
const char *getEgoName() const override { return "JASON"; }
|
||||
int getRMouse(int i, int j) const override;
|
||||
int inButtonXRange(int x) const override;
|
||||
};
|
||||
|
||||
#define AMRES (*((Amazon::AmazonResources *)_vm->_res))
|
||||
|
||||
} // End of namespace Amazon
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_AMAZON_RESOURCES_H */
|
||||
227
engines/access/amazon/amazon_room.cpp
Normal file
227
engines/access/amazon/amazon_room.cpp
Normal file
@@ -0,0 +1,227 @@
|
||||
/* 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 "common/scummsys.h"
|
||||
#include "access/access.h"
|
||||
#include "access/resources.h"
|
||||
#include "access/amazon/amazon_game.h"
|
||||
#include "access/amazon/amazon_resources.h"
|
||||
#include "access/amazon/amazon_room.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
namespace Amazon {
|
||||
|
||||
AmazonRoom::AmazonRoom(AccessEngine *vm) : Room(vm) {
|
||||
_game = (AmazonEngine *)vm;
|
||||
_antOutFlag = false;
|
||||
_icon = nullptr;
|
||||
}
|
||||
|
||||
AmazonRoom::~AmazonRoom() {
|
||||
}
|
||||
|
||||
void AmazonRoom::loadRoom(int roomNumber) {
|
||||
loadRoomData(&AMRES.ROOMTBL[roomNumber]._data[0]);
|
||||
}
|
||||
|
||||
void AmazonRoom::reloadRoom() {
|
||||
loadRoom(_vm->_player->_roomNumber);
|
||||
|
||||
if (_roomFlag != 1) {
|
||||
_vm->_currentMan = _roomFlag;
|
||||
_vm->_currentManOld = _roomFlag;
|
||||
_vm->_manScaleOff = 0;
|
||||
|
||||
switch (_vm->_currentMan) {
|
||||
case 0:
|
||||
_vm->_player->loadSprites("MAN.LZ");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
_vm->_player->loadSprites("JMAN.LZ");
|
||||
break;
|
||||
|
||||
case 3:
|
||||
_vm->_player->loadSprites("OVERHEAD.LZ");
|
||||
_vm->_manScaleOff = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
reloadRoom1();
|
||||
}
|
||||
|
||||
void AmazonRoom::reloadRoom1() {
|
||||
if (_vm->_player->_roomNumber == 29 || _vm->_player->_roomNumber == 31
|
||||
|| _vm->_player->_roomNumber == 42 || _vm->_player->_roomNumber == 44) {
|
||||
Resource *spriteData = _vm->_files->loadFile("MAYA.LZ");
|
||||
_game->_inactive._altSpritesPtr = new SpriteResource(_vm, spriteData);
|
||||
delete spriteData;
|
||||
_vm->_currentCharFlag = false;
|
||||
}
|
||||
|
||||
_selectCommand = -1;
|
||||
_vm->_events->setNormalCursor(CURSOR_CROSSHAIRS);
|
||||
_vm->_mouseMode = 0;
|
||||
_vm->_boxSelect = true;
|
||||
_vm->_player->_playerOff = false;
|
||||
|
||||
_vm->_screen->fadeOut();
|
||||
_vm->_screen->clearScreen();
|
||||
roomInit();
|
||||
|
||||
if (_roomFlag != 1 && (_vm->_player->_roomNumber != 61 || !_antOutFlag)) {
|
||||
_vm->_player->load();
|
||||
_vm->_player->calcManScale();
|
||||
}
|
||||
|
||||
if (_vm->_player->_roomNumber != 20 && _vm->_player->_roomNumber != 24
|
||||
&& _vm->_player->_roomNumber != 33 && _vm->_player->_roomNumber != 45) {
|
||||
roomMenu();
|
||||
}
|
||||
|
||||
_vm->_screen->setBufferScan();
|
||||
setupRoom();
|
||||
setWallCodes();
|
||||
buildScreen();
|
||||
|
||||
if (!_vm->_screen->_vesaMode) {
|
||||
_vm->copyBF2Vid();
|
||||
} else if (_vm->_player->_roomNumber != 20 && _vm->_player->_roomNumber != 24
|
||||
&& _vm->_player->_roomNumber != 33) {
|
||||
_vm->_screen->setPalette();
|
||||
_vm->copyBF2Vid();
|
||||
}
|
||||
|
||||
// Stop player moving
|
||||
_vm->_player->_playerMove = false;
|
||||
_vm->_player->_frame = 0;
|
||||
|
||||
// Clear any dirty rects from the old scene
|
||||
_vm->_oldRects.clear();
|
||||
_vm->_newRects.clear();
|
||||
}
|
||||
|
||||
void AmazonRoom::setupRoom() {
|
||||
Room::setupRoom();
|
||||
|
||||
// WORKAROUND: The original engine doesn't handle vertical scrolling rooms
|
||||
Screen &screen = *_vm->_screen;
|
||||
if (screen._vWindowHeight == (_playFieldHeight - 1)) {
|
||||
_vm->_scrollRow = 1;
|
||||
_vm->_scrollY = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void AmazonRoom::roomMenu() {
|
||||
const SpriteResource *icons = _vm->getIcons();
|
||||
|
||||
Screen &screen = *_vm->_screen;
|
||||
screen.saveScreen();
|
||||
screen.setDisplayScan();
|
||||
_vm->_destIn = &screen; // TODO: Redundant
|
||||
screen.plotImage(icons, 0, Common::Point(0, 177));
|
||||
screen.plotImage(icons, 1, Common::Point(143, 177));
|
||||
|
||||
screen.restoreScreen();
|
||||
}
|
||||
|
||||
void AmazonRoom::mainAreaClick() {
|
||||
Common::Point &mousePos = _vm->_events->_mousePos;
|
||||
Common::Point pt = _vm->_events->calcRawMouse();
|
||||
Screen &screen = *_vm->_screen;
|
||||
Player &player = *_vm->_player;
|
||||
|
||||
if (_selectCommand == -1) {
|
||||
if (player._roomNumber == 42 || player._roomNumber == 44 ||
|
||||
player._roomNumber == 31 || player._roomNumber == 29) {
|
||||
switch (checkBoxes1(pt)) {
|
||||
case 0:
|
||||
// Make Jason the active player
|
||||
_game->_jasMayaFlag = 0;
|
||||
return;
|
||||
case 1:
|
||||
// Make Maya the active player
|
||||
_game->_jasMayaFlag = 1;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// WORKAROUND: In Amazon room 9, you can't leave the screen to the south due
|
||||
// to not being able to click a Y position that's high enough
|
||||
if (_vm->_scrollRow == 0 && pt.y > 178)
|
||||
pt.y = 200;
|
||||
|
||||
player._moveTo = pt;
|
||||
player._playerMove = true;
|
||||
} else if (mousePos.x >= screen._windowXAdd &&
|
||||
mousePos.x <= (screen._windowXAdd + screen._vWindowBytesWide) &&
|
||||
mousePos.y >= screen._windowYAdd &&
|
||||
mousePos.y <= (screen._windowYAdd + screen._vWindowLinesTall)) {
|
||||
if (checkBoxes1(pt) >= 0) {
|
||||
checkBoxes3();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AmazonRoom::walkCursor() {
|
||||
// WORKAROUND: For scene 29, which is a normal walkable scene, but yet can be
|
||||
// 'exited'. This workaround ensures the scene will only be left if you click
|
||||
// the Exit icon when the cursor is already a walk cursor
|
||||
EventsManager &events = *_vm->_events;
|
||||
|
||||
if (_vm->_events->_middleButton || (_vm->_player->_roomNumber == 29 &&
|
||||
events._normalMouse != CURSOR_CROSSHAIRS)) {
|
||||
events.forceSetCursor(CURSOR_CROSSHAIRS);
|
||||
_selectCommand = -1;
|
||||
_vm->_boxSelect = true;
|
||||
} else {
|
||||
Room::walkCursor();
|
||||
}
|
||||
}
|
||||
|
||||
void AmazonRoom::init4Quads() {
|
||||
if (!_vm->_screen->_vesaMode)
|
||||
return;
|
||||
|
||||
// CHECKME: in the original, this call of tileScreen uses an useless parameter, "TILES.BLK"
|
||||
_game->tileScreen();
|
||||
_vm->_inventory->refreshInventory();
|
||||
_game->updateSummary(_game->_chapter);
|
||||
|
||||
_vm->_screen->setPanel(0);
|
||||
_vm->_screen->clearScreen();
|
||||
}
|
||||
|
||||
void AmazonRoom::clearRoom() {
|
||||
_game->freeInactivePlayer();
|
||||
Room::clearRoom();
|
||||
}
|
||||
|
||||
} // End of namespace Amazon
|
||||
|
||||
} // End of namespace Access
|
||||
70
engines/access/amazon/amazon_room.h
Normal file
70
engines/access/amazon/amazon_room.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/* 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 ACCESS_AMAZON_ROOM_H
|
||||
#define ACCESS_AMAZON_ROOM_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "access/room.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
class AccessEngine;
|
||||
|
||||
namespace Amazon {
|
||||
|
||||
class AmazonEngine;
|
||||
|
||||
class AmazonRoom : public Room {
|
||||
private:
|
||||
AmazonEngine *_game;
|
||||
bool _antOutFlag;
|
||||
const byte *_icon;
|
||||
|
||||
protected:
|
||||
void loadRoom(int roomNumber) override;
|
||||
|
||||
void reloadRoom() override;
|
||||
|
||||
void reloadRoom1() override;
|
||||
|
||||
void setupRoom() override;
|
||||
|
||||
void mainAreaClick() override;
|
||||
|
||||
void clearRoom() override;
|
||||
|
||||
void walkCursor() override;
|
||||
public:
|
||||
AmazonRoom(AccessEngine *vm);
|
||||
|
||||
~AmazonRoom() override;
|
||||
|
||||
void init4Quads() override;
|
||||
|
||||
void roomMenu() override;
|
||||
};
|
||||
|
||||
} // End of namespace Amazon
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_AMAZON_ROOM_H */
|
||||
535
engines/access/amazon/amazon_scripts.cpp
Normal file
535
engines/access/amazon/amazon_scripts.cpp
Normal file
@@ -0,0 +1,535 @@
|
||||
/* 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 "common/scummsys.h"
|
||||
#include "access/access.h"
|
||||
#include "access/resources.h"
|
||||
#include "access/amazon/amazon_game.h"
|
||||
#include "access/amazon/amazon_resources.h"
|
||||
#include "access/amazon/amazon_scripts.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
namespace Amazon {
|
||||
|
||||
AmazonScripts::AmazonScripts(AccessEngine *vm) : Scripts(vm) {
|
||||
_game = (AmazonEngine *)_vm;
|
||||
|
||||
setOpcodes_v2();
|
||||
}
|
||||
|
||||
void AmazonScripts::cLoop() {
|
||||
searchForSequence();
|
||||
_vm->_images.clear();
|
||||
_vm->_buffer2.blitFrom(_vm->_buffer1);
|
||||
_vm->_oldRects.clear();
|
||||
_vm->_scripts->executeScript();
|
||||
_vm->plotList1();
|
||||
_vm->copyBlocks();
|
||||
}
|
||||
|
||||
void AmazonScripts::mWhile1() {
|
||||
_vm->_screen->setDisplayScan();
|
||||
_vm->_screen->fadeOut();
|
||||
_vm->_events->hideCursor();
|
||||
|
||||
_vm->_files->loadScreen(14, 0);
|
||||
_vm->_buffer2.blitFrom(*_vm->_screen);
|
||||
_vm->_buffer1.blitFrom(*_vm->_screen);
|
||||
_vm->_events->showCursor();
|
||||
|
||||
_vm->_screen->setIconPalette();
|
||||
_vm->_screen->forceFadeIn();
|
||||
|
||||
Resource *spriteData = _vm->_files->loadFile(14, 6);
|
||||
_vm->_objectsTable[0] = new SpriteResource(_vm, spriteData);
|
||||
delete spriteData;
|
||||
|
||||
_vm->_images.clear();
|
||||
_vm->_oldRects.clear();
|
||||
_sequence = 2100;
|
||||
|
||||
do {
|
||||
cLoop();
|
||||
_sequence = 2100;
|
||||
} while (_vm->_flags[52] == 1);
|
||||
|
||||
_vm->_buffer1.copyTo(_vm->_screen);
|
||||
_vm->_buffer2.copyTo(&_vm->_buffer1);
|
||||
|
||||
_game->establish(-1, 14);
|
||||
|
||||
spriteData = _vm->_files->loadFile(14, 7);
|
||||
_vm->_objectsTable[1] = new SpriteResource(_vm, spriteData);
|
||||
delete spriteData;
|
||||
|
||||
_vm->_sound->playSound(0);
|
||||
_vm->_screen->setDisplayScan();
|
||||
_vm->_events->hideCursor();
|
||||
|
||||
_vm->_files->loadScreen(14, 1);
|
||||
_vm->_screen->setPalette();
|
||||
_vm->_buffer2.blitFrom(*_vm->_screen);
|
||||
_vm->_buffer1.blitFrom(*_vm->_screen);
|
||||
_vm->_events->showCursor();
|
||||
|
||||
_vm->_screen->setIconPalette();
|
||||
_vm->_images.clear();
|
||||
_vm->_oldRects.clear();
|
||||
_sequence = 2200;
|
||||
|
||||
_vm->_sound->loadSoundTable(0, 14, 15);
|
||||
|
||||
do {
|
||||
cLoop();
|
||||
_sequence = 2200;
|
||||
} while (_vm->_flags[52] == 2);
|
||||
|
||||
_vm->_screen->setDisplayScan();
|
||||
_vm->_events->hideCursor();
|
||||
|
||||
_vm->_files->loadScreen(14, 2);
|
||||
_vm->_screen->setPalette();
|
||||
_vm->_buffer2.blitFrom(*_vm->_screen);
|
||||
_vm->_buffer1.blitFrom(*_vm->_screen);
|
||||
_vm->_events->showCursor();
|
||||
|
||||
_vm->_screen->setIconPalette();
|
||||
_vm->freeCells();
|
||||
|
||||
spriteData = _vm->_files->loadFile(14, 8);
|
||||
_vm->_objectsTable[2] = new SpriteResource(_vm, spriteData);
|
||||
delete spriteData;
|
||||
|
||||
_vm->_images.clear();
|
||||
_vm->_oldRects.clear();
|
||||
_sequence = 2300;
|
||||
_vm->_sound->playSound(0);
|
||||
|
||||
do {
|
||||
cLoop();
|
||||
_sequence = 2300;
|
||||
} while (_vm->_flags[52] == 3);
|
||||
|
||||
_vm->freeCells();
|
||||
spriteData = _vm->_files->loadFile(14, 9);
|
||||
_vm->_objectsTable[3] = new SpriteResource(_vm, spriteData);
|
||||
delete spriteData;
|
||||
|
||||
_vm->_screen->setDisplayScan();
|
||||
_vm->_events->hideCursor();
|
||||
|
||||
_vm->_files->loadScreen(14, 3);
|
||||
_vm->_screen->setPalette();
|
||||
_vm->_buffer2.blitFrom(*_vm->_screen);
|
||||
_vm->_buffer1.blitFrom(*_vm->_screen);
|
||||
_vm->_events->showCursor();
|
||||
|
||||
_vm->_screen->setIconPalette();
|
||||
_vm->_images.clear();
|
||||
_vm->_oldRects.clear();
|
||||
_sequence = 2400;
|
||||
|
||||
do {
|
||||
cLoop();
|
||||
_sequence = 2400;
|
||||
} while (_vm->_flags[52] == 4);
|
||||
}
|
||||
|
||||
void AmazonScripts::mWhile2() {
|
||||
_vm->_screen->setDisplayScan();
|
||||
_vm->_screen->fadeOut();
|
||||
_vm->_events->hideCursor();
|
||||
|
||||
_vm->_files->loadScreen(14, 0);
|
||||
_vm->_buffer2.blitFrom(*_vm->_screen);
|
||||
_vm->_buffer1.blitFrom(*_vm->_screen);
|
||||
_vm->_events->showCursor();
|
||||
|
||||
_vm->_screen->setIconPalette();
|
||||
_vm->_screen->forceFadeIn();
|
||||
|
||||
Resource *spriteData = _vm->_files->loadFile(14, 6);
|
||||
_vm->_objectsTable[0] = new SpriteResource(_vm, spriteData);
|
||||
delete spriteData;
|
||||
|
||||
_vm->_images.clear();
|
||||
_vm->_oldRects.clear();
|
||||
_sequence = 2100;
|
||||
|
||||
do {
|
||||
cLoop();
|
||||
_sequence = 2100;
|
||||
} while (_vm->_flags[52] == 1);
|
||||
|
||||
_vm->_screen->fadeOut();
|
||||
_vm->freeCells();
|
||||
spriteData = _vm->_files->loadFile(14, 9);
|
||||
_vm->_objectsTable[3] = new SpriteResource(_vm, spriteData);
|
||||
delete spriteData;
|
||||
|
||||
_vm->_screen->setDisplayScan();
|
||||
_vm->_events->hideCursor();
|
||||
|
||||
_vm->_files->loadScreen(14, 3);
|
||||
_vm->_screen->setPalette();
|
||||
_vm->_buffer2.blitFrom(*_vm->_screen);
|
||||
_vm->_buffer1.blitFrom(*_vm->_screen);
|
||||
_vm->_events->showCursor();
|
||||
|
||||
_vm->_screen->setIconPalette();
|
||||
_vm->_images.clear();
|
||||
_vm->_oldRects.clear();
|
||||
_sequence = 2400;
|
||||
|
||||
do {
|
||||
cLoop();
|
||||
_sequence = 2400;
|
||||
} while (_vm->_flags[52] == 4);
|
||||
}
|
||||
|
||||
void AmazonScripts::mWhile(int param1) {
|
||||
switch(param1) {
|
||||
case 1:
|
||||
mWhile1();
|
||||
break;
|
||||
case 2:
|
||||
_game->_plane->mWhileFly();
|
||||
break;
|
||||
case 3:
|
||||
_game->_plane->mWhileFall();
|
||||
break;
|
||||
case 4:
|
||||
_game->_jungle->mWhileJWalk();
|
||||
break;
|
||||
case 5:
|
||||
_game->_jungle->mWhileDoOpen();
|
||||
break;
|
||||
case 6:
|
||||
_game->_river->mWhileDownRiver();
|
||||
break;
|
||||
case 7:
|
||||
mWhile2();
|
||||
break;
|
||||
case 8:
|
||||
_game->_jungle->mWhileJWalk2();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AmazonScripts::loadBackground(int param1, int param2) {
|
||||
_vm->_files->_setPaletteFlag = false;
|
||||
_vm->_files->loadScreen(param1, param2);
|
||||
|
||||
_vm->_buffer2.blitFrom(*_vm->_screen);
|
||||
_vm->_buffer1.blitFrom(*_vm->_screen);
|
||||
|
||||
_vm->_screen->forceFadeIn();
|
||||
}
|
||||
|
||||
void AmazonScripts::loadNSound(int param1, int param2) {
|
||||
Resource *sound = _vm->_files->loadFile(param1, param2);
|
||||
_vm->_sound->_soundTable.push_back(SoundEntry(sound, 1));
|
||||
}
|
||||
|
||||
void AmazonScripts::setInactive() {
|
||||
_game->_rawInactiveX = _vm->_player->_rawPlayer.x;
|
||||
_game->_rawInactiveY = _vm->_player->_rawPlayer.y;
|
||||
_game->_charSegSwitch = false;
|
||||
|
||||
mWhile(_game->_rawInactiveY);
|
||||
}
|
||||
|
||||
void AmazonScripts::boatWalls(int param1, int param2) {
|
||||
if (param1 == 1)
|
||||
_vm->_room->_plotter._walls[42] = Common::Rect(96, 27, 96 + 87, 27 + 42);
|
||||
else {
|
||||
_vm->_room->_plotter._walls[39].bottom = _vm->_room->_plotter._walls[41].bottom = 106;
|
||||
_vm->_room->_plotter._walls[40].left = 94;
|
||||
}
|
||||
}
|
||||
|
||||
void AmazonScripts::plotInactive() {
|
||||
Player &player = *_vm->_player;
|
||||
InactivePlayer &inactive = _game->_inactive;
|
||||
|
||||
if (_game->_charSegSwitch) {
|
||||
_game->_currentCharFlag = true;
|
||||
SWAP(inactive._altSpritesPtr, player._playerSprites);
|
||||
_game->_charSegSwitch = false;
|
||||
} else if (_game->_jasMayaFlag != (_game->_currentCharFlag ? 1 : 0)) {
|
||||
if (player._playerOff) {
|
||||
_game->_jasMayaFlag = (_game->_currentCharFlag ? 1 : 0);
|
||||
} else {
|
||||
_game->_currentCharFlag = (_game->_jasMayaFlag == 1);
|
||||
int tmpX = _game->_rawInactiveX;
|
||||
int tmpY = _game->_rawInactiveY;
|
||||
_game->_rawInactiveX = player._rawPlayer.x;
|
||||
_game->_rawInactiveY = player._rawPlayer.y;
|
||||
player._rawPlayer.x = tmpX;
|
||||
player._rawPlayer.y = tmpY;
|
||||
_game->_inactiveYOff = player._playerOffset.y;
|
||||
player.calcManScale();
|
||||
|
||||
SWAP(inactive._altSpritesPtr, player._playerSprites);
|
||||
_vm->_room->setWallCodes();
|
||||
}
|
||||
}
|
||||
|
||||
_game->_flags[155] = 0;
|
||||
if (_game->_rawInactiveX >= 152 && _game->_rawInactiveX <= 167 &&
|
||||
_game->_rawInactiveY >= 158 && _game->_rawInactiveY <= 173) {
|
||||
_game->_flags[155] = 1;
|
||||
} else {
|
||||
_game->_flags[160] = 0;
|
||||
if (!_game->_jasMayaFlag && _game->_rawInactiveX >= 266 && _game->_rawInactiveX <= 290
|
||||
&& _game->_rawInactiveY >= 70 && _game->_rawInactiveY <= 87) {
|
||||
_game->_flags[160] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
inactive._flags &= ~IMGFLAG_UNSCALED;
|
||||
inactive._flags &= ~IMGFLAG_BACKWARDS;
|
||||
inactive._position.x = _game->_rawInactiveX;
|
||||
inactive._position.y = _game->_rawInactiveY - _game->_inactiveYOff;
|
||||
inactive._offsetY = _game->_inactiveYOff;
|
||||
inactive._spritesPtr = inactive._altSpritesPtr;
|
||||
|
||||
_vm->_images.addToList(_game->_inactive);
|
||||
}
|
||||
|
||||
void AmazonScripts::executeSpecial(int commandIndex, int param1, int param2) {
|
||||
switch (commandIndex) {
|
||||
case 0:
|
||||
warning("TODO: DEMO - RESETAN");
|
||||
break;
|
||||
case 1:
|
||||
_vm->establish(param1, param2);
|
||||
break;
|
||||
case 2:
|
||||
loadBackground(param1, param2);
|
||||
break;
|
||||
case 3:
|
||||
if (_vm->isDemo())
|
||||
warning("TODO: DEMO - LOADCELLSET");
|
||||
else
|
||||
_game->_cast->doCast(param1);
|
||||
break;
|
||||
case 4:
|
||||
if (_vm->isDemo())
|
||||
loadNSound(param1, param2);
|
||||
else
|
||||
setInactive();
|
||||
break;
|
||||
case 5:
|
||||
warning("TODO: DEMO - UNLOADCELLSET");
|
||||
break;
|
||||
case 6:
|
||||
mWhile(param1);
|
||||
break;
|
||||
case 7:
|
||||
warning("TODO: DEMO - ADDMONEY");
|
||||
break;
|
||||
case 8:
|
||||
warning("TODO: DEMO - CHKMONEY");
|
||||
break;
|
||||
case 9:
|
||||
_game->_guard->doGuard();
|
||||
break;
|
||||
case 10:
|
||||
_vm->_midi->newMusic(param1, param2);
|
||||
break;
|
||||
case 11:
|
||||
plotInactive();
|
||||
break;
|
||||
case 13:
|
||||
_game->_river->doRiver();
|
||||
break;
|
||||
case 14:
|
||||
_game->_ant->doAnt();
|
||||
break;
|
||||
case 15:
|
||||
boatWalls(param1, param2);
|
||||
break;
|
||||
default:
|
||||
warning("Unexpected Special code %d - Skipped", commandIndex);
|
||||
}
|
||||
}
|
||||
|
||||
typedef void(AmazonScripts::*AmazonScriptMethodPtr)();
|
||||
|
||||
void AmazonScripts::executeCommand(int commandIndex) {
|
||||
static const AmazonScriptMethodPtr AMAZON_COMMAND_LIST[] = {
|
||||
&AmazonScripts::cmdHelp_v2, &AmazonScripts::cmdCycleBack,
|
||||
&AmazonScripts::cmdChapter, &AmazonScripts::cmdSetHelp,
|
||||
&AmazonScripts::cmdCenterPanel, &AmazonScripts::cmdMainPanel,
|
||||
&AmazonScripts::CMDRETFLASH
|
||||
};
|
||||
|
||||
if (commandIndex >= 73)
|
||||
(this->*AMAZON_COMMAND_LIST[commandIndex - 73])();
|
||||
else
|
||||
Scripts::executeCommand(commandIndex);
|
||||
}
|
||||
|
||||
void AmazonScripts::cmdHelp_v2() {
|
||||
Common::String helpMessage = _data->readString();
|
||||
|
||||
if (_game->_helpLevel == 0) {
|
||||
_game->_timers.saveTimers();
|
||||
_game->_useItem = 0;
|
||||
|
||||
if (_game->_noHints) {
|
||||
printString(AMRES.NO_HELP_MESSAGE);
|
||||
return;
|
||||
} else if (_game->_hintLevel == 0) {
|
||||
printString(AMRES.NO_HINTS_MESSAGE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int level = _game->_hintLevel - 1;
|
||||
if (level < _game->_helpLevel)
|
||||
_game->_moreHelp = 0;
|
||||
|
||||
_game->drawHelp(helpMessage);
|
||||
|
||||
const Common::Rect butn1 = Common::Rect(HELP1COORDS[0][0], HELP1COORDS[0][2], HELP1COORDS[0][1], HELP1COORDS[0][3]);
|
||||
const Common::Rect butn2 = Common::Rect(HELP1COORDS[1][0], HELP1COORDS[1][2], HELP1COORDS[1][1], HELP1COORDS[1][3]);
|
||||
|
||||
while (!_vm->shouldQuit()) {
|
||||
while (!_vm->shouldQuit() && !_vm->_events->_leftButton)
|
||||
_vm->_events->pollEventsAndWait();
|
||||
|
||||
_vm->_events->debounceLeft();
|
||||
|
||||
const Common::Point pt = _vm->_events->_mousePos;
|
||||
|
||||
int choice = -1;
|
||||
if (butn1.contains(pt))
|
||||
choice = 0;
|
||||
else if (butn2.contains(pt))
|
||||
choice = 1;
|
||||
|
||||
if (choice < 0)
|
||||
continue;
|
||||
|
||||
if (choice == 1) {
|
||||
// Done button selected
|
||||
_game->_helpLevel = 0;
|
||||
_game->_moreHelp = 1;
|
||||
_game->_useItem = 0;
|
||||
_vm->_events->hideCursor();
|
||||
if (_vm->_screen->_vesaMode) {
|
||||
_vm->_screen->restoreScreen();
|
||||
_vm->_screen->setPanel(0);
|
||||
} else {
|
||||
_vm->_screen->fadeOut();
|
||||
_vm->_screen->clearBuffer();
|
||||
}
|
||||
|
||||
_vm->_buffer2.copyTo(_vm->_screen);
|
||||
_vm->_screen->restorePalette();
|
||||
_vm->_screen->setPalette();
|
||||
_vm->_events->showCursor();
|
||||
|
||||
delete _vm->_objectsTable[45];
|
||||
_vm->_objectsTable[45] = nullptr;
|
||||
_vm->_timers.restoreTimers();
|
||||
break;
|
||||
} else {
|
||||
// More button selected
|
||||
if (_game->_moreHelp == 0)
|
||||
continue;
|
||||
++_game->_helpLevel;
|
||||
_game->_useItem = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
findNull();
|
||||
}
|
||||
|
||||
void AmazonScripts::cmdCycleBack() {
|
||||
if (_vm->_startup == -1)
|
||||
_vm->_screen->cyclePaletteBackwards();
|
||||
}
|
||||
|
||||
void AmazonScripts::cmdChapter() {
|
||||
Resource *activeScript = nullptr;
|
||||
|
||||
if (_vm->isDemo()) {
|
||||
cmdSetHelp();
|
||||
} else {
|
||||
int chapter = _data->readByte();
|
||||
|
||||
if (!_vm->isCD()) {
|
||||
// For floppy version, the current script remains active even
|
||||
// after the end of the chapter start, so we need to save it
|
||||
activeScript = _resource;
|
||||
_resource = nullptr;
|
||||
_data = nullptr;
|
||||
}
|
||||
|
||||
_game->startChapter(chapter);
|
||||
|
||||
if (!_vm->isCD()) {
|
||||
assert(!_resource);
|
||||
setScript(activeScript, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AmazonScripts::cmdSetHelp() {
|
||||
int arrayId = (_data->readUint16LE() & 0xFF) - 1;
|
||||
int helpId = _data->readUint16LE() & 0xFF;
|
||||
|
||||
byte *help = _game->_helpTbl[arrayId];
|
||||
help[helpId] = 1;
|
||||
|
||||
if (_vm->_useItem == 0) {
|
||||
_sequence = 11000;
|
||||
searchForSequence();
|
||||
}
|
||||
}
|
||||
|
||||
void AmazonScripts::cmdCenterPanel() {
|
||||
if (_vm->_screen->_vesaMode) {
|
||||
_vm->_screen->clearScreen();
|
||||
_vm->_screen->setPanel(3);
|
||||
}
|
||||
}
|
||||
|
||||
void AmazonScripts::cmdMainPanel() {
|
||||
if (_vm->_screen->_vesaMode) {
|
||||
_vm->_room->init4Quads();
|
||||
_vm->_screen->setPanel(0);
|
||||
}
|
||||
}
|
||||
|
||||
void AmazonScripts::CMDRETFLASH() {
|
||||
error("TODO CMDRETFLASH");
|
||||
}
|
||||
|
||||
} // End of namespace Amazon
|
||||
|
||||
} // End of namespace Access
|
||||
66
engines/access/amazon/amazon_scripts.h
Normal file
66
engines/access/amazon/amazon_scripts.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/* 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 ACCESS_AMAZON_SCRIPTS_H
|
||||
#define ACCESS_AMAZON_SCRIPTS_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "access/scripts.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
namespace Amazon {
|
||||
|
||||
class AmazonEngine;
|
||||
|
||||
class AmazonScripts : public Scripts {
|
||||
private:
|
||||
AmazonEngine *_game;
|
||||
protected:
|
||||
void executeSpecial(int commandIndex, int param1, int param2) override;
|
||||
void executeCommand(int commandIndex) override;
|
||||
|
||||
void cLoop();
|
||||
void mWhile1();
|
||||
void mWhile2();
|
||||
void mWhile(int param1);
|
||||
void loadBackground(int param1, int param2);
|
||||
void plotInactive();
|
||||
void loadNSound(int param1, int param2);
|
||||
void setInactive();
|
||||
void boatWalls(int param1, int param2);
|
||||
|
||||
void cmdHelp_v2();
|
||||
void cmdCycleBack();
|
||||
void cmdChapter();
|
||||
void cmdSetHelp();
|
||||
void cmdCenterPanel();
|
||||
void cmdMainPanel();
|
||||
void CMDRETFLASH();
|
||||
public:
|
||||
AmazonScripts(AccessEngine *vm);
|
||||
};
|
||||
|
||||
} // End of namespace Amazon
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_AMAZON_SCRIPTS_H */
|
||||
348
engines/access/animation.cpp
Normal file
348
engines/access/animation.cpp
Normal file
@@ -0,0 +1,348 @@
|
||||
/* 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 "common/endian.h"
|
||||
#include "common/memstream.h"
|
||||
#include "access/access.h"
|
||||
#include "access/animation.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
AnimationResource::AnimationResource(AccessEngine *vm, Resource *res) {
|
||||
int count = res->_stream->readUint16LE();
|
||||
|
||||
Common::Array<int> offsets;
|
||||
for (int i = 0; i < count; ++i)
|
||||
offsets.push_back(res->_stream->readUint32LE());
|
||||
|
||||
_animations.reserve(count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
res->_stream->seek(offsets[i]);
|
||||
Animation *anim = new Animation(vm, res->_stream);
|
||||
_animations.push_back(anim);
|
||||
}
|
||||
}
|
||||
|
||||
AnimationResource::~AnimationResource() {
|
||||
for (auto *animation : _animations)
|
||||
delete animation;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
Animation::Animation(AccessEngine *vm, Common::SeekableReadStream *stream) : Manager(vm) {
|
||||
uint32 startOfs = stream->pos();
|
||||
|
||||
_type = stream->readByte();
|
||||
|
||||
// WORKAROUND: In Amazon floppy English, there's an animation associated with
|
||||
// the librarian that isn't used, and has junk data. Luckily, it's animation
|
||||
// type is also invalid, so if the _type isn't in range, exit immediately
|
||||
if (_type > 7) {
|
||||
_scaling = -1;
|
||||
_frameNumber = -1;
|
||||
_initialTicks = _countdownTicks = 0;
|
||||
_loopCount = _currentLoopCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
_scaling = stream->readSByte();
|
||||
stream->readByte(); // unk
|
||||
_frameNumber = stream->readByte();
|
||||
_initialTicks = stream->readUint16LE();
|
||||
stream->readUint16LE(); // unk
|
||||
stream->readUint16LE(); // unk
|
||||
_loopCount = stream->readSint16LE();
|
||||
_countdownTicks = stream->readUint16LE();
|
||||
_currentLoopCount = stream->readSint16LE();
|
||||
stream->readUint16LE(); // unk
|
||||
|
||||
Common::Array<uint16> frameOffsets;
|
||||
uint16 ofs;
|
||||
while ((ofs = stream->readUint16LE()) != 0)
|
||||
frameOffsets.push_back(ofs);
|
||||
|
||||
for (uint16 frameOffset : frameOffsets) {
|
||||
stream->seek(startOfs + frameOffset);
|
||||
|
||||
AnimationFrame *frame = new AnimationFrame(stream, startOfs);
|
||||
_frames.push_back(frame);
|
||||
}
|
||||
}
|
||||
|
||||
Animation::~Animation() {
|
||||
for (auto *frame : _frames)
|
||||
delete frame;
|
||||
}
|
||||
|
||||
typedef void(Animation::*AnimationMethodPtr)();
|
||||
|
||||
void Animation::animate() {
|
||||
static const AnimationMethodPtr METHODS[8] = {
|
||||
&Animation::anim0, &Animation::anim1, &Animation::anim2, &Animation::anim3,
|
||||
&Animation::anim4, &Animation::animNone, &Animation::animNone, &Animation::anim7
|
||||
};
|
||||
|
||||
(this->*METHODS[_type])();
|
||||
}
|
||||
|
||||
void Animation::anim0() {
|
||||
if (_currentLoopCount != -1) {
|
||||
if (_countdownTicks != 0) {
|
||||
setFrame1(calcFrame());
|
||||
} else {
|
||||
_countdownTicks = _initialTicks;
|
||||
++_frameNumber;
|
||||
const AnimationFrame *frame = calcFrame();
|
||||
|
||||
if (frame == nullptr) {
|
||||
_frameNumber = 0;
|
||||
_currentLoopCount = -1;
|
||||
frame = calcFrame();
|
||||
}
|
||||
|
||||
setFrame(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::anim1() {
|
||||
if (_currentLoopCount == -1 || _countdownTicks != 0) {
|
||||
setFrame1(calcFrame());
|
||||
} else {
|
||||
_countdownTicks = _initialTicks;
|
||||
++_frameNumber;
|
||||
const AnimationFrame *frame = calcFrame();
|
||||
|
||||
if (frame == nullptr) {
|
||||
--_frameNumber;
|
||||
_currentLoopCount = -1;
|
||||
frame = calcFrame();
|
||||
}
|
||||
|
||||
setFrame(frame);
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::anim2() {
|
||||
if (_countdownTicks != 0) {
|
||||
setFrame1(calcFrame());
|
||||
} else {
|
||||
_countdownTicks = _initialTicks;
|
||||
++_frameNumber;
|
||||
const AnimationFrame *frame = calcFrame();
|
||||
|
||||
if (frame == nullptr) {
|
||||
_frameNumber = 0;
|
||||
frame = calcFrame();
|
||||
}
|
||||
|
||||
setFrame(frame);
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::anim3() {
|
||||
if (_currentLoopCount != -1) {
|
||||
if (_countdownTicks != 0) {
|
||||
setFrame1(calcFrame());
|
||||
} else {
|
||||
_countdownTicks = _initialTicks;
|
||||
++_frameNumber;
|
||||
const AnimationFrame *frame = calcFrame();
|
||||
|
||||
if (frame == nullptr) {
|
||||
--_currentLoopCount;
|
||||
_frameNumber = 0;
|
||||
frame = calcFrame();
|
||||
}
|
||||
|
||||
setFrame(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::anim4() {
|
||||
if (_currentLoopCount == -1 || _countdownTicks != 0) {
|
||||
setFrame1(calcFrame());
|
||||
} else {
|
||||
_countdownTicks = _initialTicks;
|
||||
++_frameNumber;
|
||||
const AnimationFrame *frame = calcFrame();
|
||||
|
||||
if (frame == nullptr) {
|
||||
if (--_currentLoopCount == -1) {
|
||||
setFrame1(calcFrame());
|
||||
return;
|
||||
} else {
|
||||
_frameNumber = 0;
|
||||
frame = calcFrame();
|
||||
}
|
||||
}
|
||||
|
||||
setFrame(frame);
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::animNone() {
|
||||
// Empty implementation
|
||||
}
|
||||
|
||||
void Animation::anim7() {
|
||||
setFrame(calcFrame1());
|
||||
}
|
||||
|
||||
const AnimationFrame *Animation::calcFrame() {
|
||||
return (_frameNumber < (int)_frames.size()) ? _frames[_frameNumber] : nullptr;
|
||||
}
|
||||
|
||||
const AnimationFrame *Animation::calcFrame1() {
|
||||
return _frames[0];
|
||||
}
|
||||
|
||||
void Animation::setFrame(const AnimationFrame *frame) {
|
||||
assert(frame);
|
||||
_countdownTicks += frame->_frameDelay;
|
||||
setFrame1(frame);
|
||||
}
|
||||
|
||||
void Animation::setFrame1(const AnimationFrame *frame) {
|
||||
_vm->_animation->_base.x = frame->_baseX;
|
||||
_vm->_animation->_base.y = frame->_baseY;
|
||||
|
||||
// Loop to add image draw requests for the parts of the frame
|
||||
for (const AnimationFramePart &part: frame->_parts) {
|
||||
ImageEntry ie;
|
||||
|
||||
// Set the flags
|
||||
ie._flags = part._flags & ~IMGFLAG_UNSCALED;
|
||||
if (_vm->_animation->_frameScale == -1)
|
||||
ie._flags |= IMGFLAG_UNSCALED;
|
||||
|
||||
// Set the other fields
|
||||
ie._spritesPtr = _vm->_objectsTable[part._spritesIndex];
|
||||
ie._frameNumber = part._frameIndex;
|
||||
ie._position = part._position + _vm->_animation->_base;
|
||||
ie._offsetY = part._offsetY - ie._position.y;
|
||||
|
||||
_vm->_images.addToList(ie);
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
AnimationFrame::AnimationFrame(Common::SeekableReadStream *stream, int startOffset) {
|
||||
uint16 nextOffset;
|
||||
|
||||
stream->readByte(); // unk
|
||||
_baseX = stream->readUint16LE();
|
||||
_baseY = stream->readUint16LE();
|
||||
_frameDelay = stream->readUint16LE();
|
||||
nextOffset = stream->readUint16LE();
|
||||
|
||||
while (nextOffset != 0) {
|
||||
stream->seek(startOffset + nextOffset);
|
||||
|
||||
AnimationFramePart framePart(stream);
|
||||
_parts.push_back(framePart);
|
||||
|
||||
nextOffset = stream->readUint16LE();
|
||||
}
|
||||
}
|
||||
|
||||
AnimationFrame::~AnimationFrame() {
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
AnimationFramePart::AnimationFramePart(Common::SeekableReadStream *stream) {
|
||||
_flags = stream->readByte();
|
||||
_spritesIndex = stream->readByte();
|
||||
_frameIndex = stream->readByte();
|
||||
_position.x = stream->readUint16LE();
|
||||
_position.y = stream->readUint16LE();
|
||||
_offsetY = stream->readUint16LE();
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
AnimationManager::AnimationManager(AccessEngine *vm) : Manager(vm) {
|
||||
_animation = nullptr;
|
||||
_animStart = nullptr;
|
||||
_frameScale = 0;
|
||||
}
|
||||
|
||||
AnimationManager::~AnimationManager() {
|
||||
delete _animation;
|
||||
}
|
||||
|
||||
void AnimationManager::freeAnimationData() {
|
||||
delete _animation;
|
||||
_animation = nullptr;
|
||||
_animStart = nullptr;
|
||||
}
|
||||
|
||||
void AnimationManager::clearTimers() {
|
||||
_animationTimers.clear();
|
||||
}
|
||||
|
||||
void AnimationManager::loadAnimations(Resource *res) {
|
||||
_animationTimers.clear();
|
||||
delete _animation;
|
||||
_animation = new AnimationResource(_vm, res);
|
||||
}
|
||||
|
||||
|
||||
Animation *AnimationManager::setAnimation(int animId) {
|
||||
Animation *anim = findAnimation(animId);
|
||||
if (!anim)
|
||||
return nullptr;
|
||||
|
||||
anim->_countdownTicks = anim->_initialTicks;
|
||||
anim->_frameNumber = 0;
|
||||
|
||||
anim->_currentLoopCount = (anim->_type != 3 && anim->_type != 4) ? 0 : anim->_loopCount;
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
void AnimationManager::setAnimTimer(Animation *anim) {
|
||||
_animationTimers.push_back(anim);
|
||||
}
|
||||
|
||||
Animation *AnimationManager::findAnimation(int animId) {
|
||||
_animStart = (_animation == nullptr) ? nullptr : _animation->getAnimation(animId);
|
||||
return _animStart;
|
||||
}
|
||||
|
||||
void AnimationManager::animate(int animId) {
|
||||
Animation *anim = findAnimation(animId);
|
||||
_frameScale = anim->_scaling;
|
||||
anim->animate();
|
||||
}
|
||||
|
||||
void AnimationManager::updateTimers() {
|
||||
for (auto *timer : _animationTimers) {
|
||||
if (timer->_countdownTicks > 0)
|
||||
timer->_countdownTicks--;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Access
|
||||
143
engines/access/animation.h
Normal file
143
engines/access/animation.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/* 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 ACCESS_ANIMATION_H
|
||||
#define ACCESS_ANIMATION_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/array.h"
|
||||
#include "common/memstream.h"
|
||||
#include "access/data.h"
|
||||
#include "access/files.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
class AnimationResource;
|
||||
class Animation;
|
||||
class AnimationFrame;
|
||||
class AnimationFramePart;
|
||||
|
||||
class AnimationManager : public Manager {
|
||||
private:
|
||||
Common::Array<Animation *> _animationTimers;
|
||||
AnimationResource *_animation;
|
||||
public:
|
||||
Animation *_animStart;
|
||||
Common::Point _base;
|
||||
int _frameScale;
|
||||
public:
|
||||
AnimationManager(AccessEngine *vm);
|
||||
~AnimationManager();
|
||||
void freeAnimationData();
|
||||
void loadAnimations(Resource *res);
|
||||
|
||||
Animation *findAnimation(int animId);
|
||||
Animation *setAnimation(int animId);
|
||||
|
||||
void animate(int animId);
|
||||
|
||||
/**
|
||||
* Clear the list of currently active animations
|
||||
*/
|
||||
void clearTimers();
|
||||
|
||||
/**
|
||||
* Add an animation to the list of currently animating ones
|
||||
*/
|
||||
void setAnimTimer(Animation *anim);
|
||||
|
||||
/**
|
||||
* Update the timing of all currently active animation
|
||||
*/
|
||||
void updateTimers();
|
||||
|
||||
/**
|
||||
* Remove the last animation timer
|
||||
*/
|
||||
void popBackTimer() { _animationTimers.pop_back(); }
|
||||
};
|
||||
|
||||
class AnimationResource {
|
||||
private:
|
||||
Common::Array<Animation *> _animations;
|
||||
public:
|
||||
AnimationResource(AccessEngine *vm, Resource *res);
|
||||
~AnimationResource();
|
||||
|
||||
int getCount() const { return _animations.size(); }
|
||||
Animation *getAnimation(int idx) { return _animations[idx]; }
|
||||
};
|
||||
|
||||
class Animation : public Manager {
|
||||
private:
|
||||
Common::Array<AnimationFrame *> _frames;
|
||||
|
||||
void anim0();
|
||||
void anim1();
|
||||
void anim2();
|
||||
void anim3();
|
||||
void anim4();
|
||||
void animNone();
|
||||
void anim7();
|
||||
|
||||
const AnimationFrame *calcFrame();
|
||||
const AnimationFrame *calcFrame1();
|
||||
void setFrame(const AnimationFrame *frame);
|
||||
void setFrame1(const AnimationFrame *frame);
|
||||
public:
|
||||
int _type;
|
||||
int _scaling;
|
||||
int _frameNumber;
|
||||
int _initialTicks;
|
||||
int _loopCount;
|
||||
int _countdownTicks;
|
||||
int _currentLoopCount;
|
||||
public:
|
||||
Animation(AccessEngine *vm, Common::SeekableReadStream *stream);
|
||||
~Animation();
|
||||
|
||||
void animate();
|
||||
};
|
||||
|
||||
class AnimationFrame {
|
||||
public:
|
||||
int _baseX, _baseY;
|
||||
int _frameDelay;
|
||||
Common::Array<AnimationFramePart> _parts;
|
||||
public:
|
||||
AnimationFrame(Common::SeekableReadStream *stream, int startOffset);
|
||||
~AnimationFrame();
|
||||
};
|
||||
|
||||
class AnimationFramePart {
|
||||
public:
|
||||
byte _flags;
|
||||
int _spritesIndex;
|
||||
int _frameIndex;
|
||||
Common::Point _position;
|
||||
int _offsetY;
|
||||
public:
|
||||
AnimationFramePart(Common::SeekableReadStream *stream);
|
||||
};
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_ANIMATION_H */
|
||||
295
engines/access/asurface.cpp
Normal file
295
engines/access/asurface.cpp
Normal file
@@ -0,0 +1,295 @@
|
||||
/* 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 "common/algorithm.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/memstream.h"
|
||||
#include "access/access.h"
|
||||
#include "access/asurface.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
const int TRANSPARENCY = 0;
|
||||
|
||||
SpriteResource::SpriteResource(const AccessEngine *vm, Resource *res) {
|
||||
Common::Array<uint32> offsets;
|
||||
int count = res->_stream->readUint16LE();
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
offsets.push_back(res->_stream->readUint32LE());
|
||||
offsets.push_back(res->_size); // For easier calculations of Noctropolis sizes
|
||||
|
||||
// Build up the frames
|
||||
for (int i = 0; i < count; ++i) {
|
||||
res->_stream->seek(offsets[i]);
|
||||
int frameSize = offsets[i + 1] - offsets[i];
|
||||
|
||||
SpriteFrame *frame = new SpriteFrame(vm, res->_stream, frameSize);
|
||||
_frames.push_back(frame);
|
||||
}
|
||||
}
|
||||
|
||||
SpriteResource::~SpriteResource() {
|
||||
for (auto *frame : _frames)
|
||||
delete frame;
|
||||
}
|
||||
|
||||
SpriteFrame::SpriteFrame(const AccessEngine *vm, Common::SeekableReadStream *stream, int frameSize) {
|
||||
int xSize = stream->readUint16LE();
|
||||
int ySize = stream->readUint16LE();
|
||||
|
||||
if (vm->getGameID() == kGameMartianMemorandum) {
|
||||
int size = stream->readUint16LE();
|
||||
if (size != frameSize)
|
||||
warning("Unexpected file difference: framesize %d - size %d %d - unknown %d", frameSize, xSize, ySize, size);
|
||||
}
|
||||
Graphics::Screen::create(xSize, ySize);
|
||||
|
||||
// Empty surface
|
||||
byte *data = (byte *)getPixels();
|
||||
Common::fill(data, data + w * h, TRANSPARENCY);
|
||||
|
||||
// Decode the data
|
||||
for (int y = 0; y < h; ++y) {
|
||||
int offset = stream->readByte();
|
||||
int len = stream->readByte();
|
||||
assert((offset + len) <= w);
|
||||
|
||||
byte *destP = (byte *)getBasePtr(offset, y);
|
||||
stream->read(destP, len);
|
||||
}
|
||||
}
|
||||
|
||||
SpriteFrame::~SpriteFrame() {
|
||||
Graphics::Screen::free();
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
ImageEntry::ImageEntry() : _frameNumber(0), _spritesPtr(nullptr), _offsetY(0), _flags(0) {
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
static bool sortImagesY(const ImageEntry &ie1, const ImageEntry &ie2) {
|
||||
int v = (ie1._position.y + ie1._offsetY) - (ie2._position.y + ie2._offsetY);
|
||||
return (v < 0) || (v == 0 && ie1._position.y <= ie2._position.y);
|
||||
}
|
||||
|
||||
void ImageEntryList::addToList(ImageEntry &ie) {
|
||||
assert(size() < 35);
|
||||
push_back(ie);
|
||||
Common::sort(begin(), end(), sortImagesY);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
int BaseSurface::_clipWidth;
|
||||
int BaseSurface::_clipHeight;
|
||||
|
||||
int BaseSurface::_lastBoundsX;
|
||||
int BaseSurface::_lastBoundsY;
|
||||
int BaseSurface::_lastBoundsW;
|
||||
int BaseSurface::_lastBoundsH;
|
||||
|
||||
BaseSurface::BaseSurface(): Graphics::Screen(0, 0) {
|
||||
Graphics::Screen::free(); // Free the 0x0 surface allocated by Graphics::Screen
|
||||
_leftSkip = _rightSkip = 0;
|
||||
_topSkip = _bottomSkip = 0;
|
||||
_orgX1 = _orgY1 = 0;
|
||||
_orgX2 = _orgY2 = 0;
|
||||
_lColor = 0;
|
||||
_maxChars = 0;
|
||||
}
|
||||
|
||||
BaseSurface::~BaseSurface() {
|
||||
_savedBlock.free();
|
||||
}
|
||||
|
||||
void BaseSurface::clearBuffer() {
|
||||
byte *pSrc = (byte *)getPixels();
|
||||
Common::fill(pSrc, pSrc + w * h, 0);
|
||||
}
|
||||
|
||||
void BaseSurface::plotImage(const SpriteResource *sprite, int frameNum, const Common::Point &pt) {
|
||||
const SpriteFrame *frame = sprite->getFrame(frameNum);
|
||||
Common::Rect r(pt.x, pt.y, pt.x + frame->w, pt.y + frame->h);
|
||||
|
||||
if (!clip(r)) {
|
||||
_lastBoundsX = r.left;
|
||||
_lastBoundsY = r.top;
|
||||
_lastBoundsW = r.width();
|
||||
_lastBoundsH = r.height();
|
||||
|
||||
plotF(frame, pt);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseSurface::copyBuffer(Graphics::ManagedSurface *src) {
|
||||
blitFrom(*src);
|
||||
}
|
||||
|
||||
void BaseSurface::plotF(const SpriteFrame *frame, const Common::Point &pt) {
|
||||
sPlotF(frame, Common::Rect(pt.x, pt.y, pt.x + frame->w, pt.y + frame->h));
|
||||
}
|
||||
|
||||
void BaseSurface::plotB(const SpriteFrame *frame, const Common::Point &pt) {
|
||||
sPlotB(frame, Common::Rect(pt.x, pt.y, pt.x + frame->w, pt.y + frame->h));
|
||||
}
|
||||
|
||||
void BaseSurface::sPlotF(const SpriteFrame *frame, const Common::Rect &bounds) {
|
||||
transBlitFrom(*frame, Common::Rect(0, 0, frame->w, frame->h), bounds, TRANSPARENCY, false);
|
||||
}
|
||||
|
||||
void BaseSurface::sPlotB(const SpriteFrame *frame, const Common::Rect &bounds) {
|
||||
transBlitFrom(*frame, Common::Rect(0, 0, frame->w, frame->h), bounds, TRANSPARENCY, true);
|
||||
}
|
||||
|
||||
void BaseSurface::copyBlock(const BaseSurface *src, const Common::Rect &bounds) {
|
||||
copyRectToSurface(*src, bounds.left, bounds.top, bounds);
|
||||
}
|
||||
|
||||
void BaseSurface::copyTo(BaseSurface *dest) {
|
||||
if (dest->empty())
|
||||
dest->create(this->w, this->h);
|
||||
|
||||
dest->blitFrom(*this);
|
||||
}
|
||||
|
||||
void BaseSurface::saveBlock(const Common::Rect &bounds) {
|
||||
_savedBounds = bounds;
|
||||
_savedBounds.clip(Common::Rect(0, 0, this->w, this->h));
|
||||
|
||||
_savedBlock.free();
|
||||
_savedBlock.create(bounds.width(), bounds.height(),
|
||||
Graphics::PixelFormat::createFormatCLUT8());
|
||||
_savedBlock.copyRectToSurface(*this, 0, 0, _savedBounds);
|
||||
}
|
||||
|
||||
void BaseSurface::restoreBlock() {
|
||||
if (!_savedBounds.isEmpty()) {
|
||||
copyRectToSurface(_savedBlock, _savedBounds.left, _savedBounds.top,
|
||||
Common::Rect(0, 0, _savedBlock.w, _savedBlock.h));
|
||||
|
||||
_savedBlock.free();
|
||||
_savedBounds = Common::Rect(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseSurface::drawRect() {
|
||||
Graphics::ManagedSurface::fillRect(Common::Rect(_orgX1, _orgY1, _orgX2, _orgY2), _lColor);
|
||||
}
|
||||
|
||||
void BaseSurface::drawLine(int x1, int y1, int x2, int y2, int col) {
|
||||
Graphics::ManagedSurface::drawLine(x1, y1, x2, y2, col);
|
||||
}
|
||||
|
||||
void BaseSurface::drawLine() {
|
||||
Graphics::ManagedSurface::drawLine(_orgX1, _orgY1, _orgX2, _orgY1, _lColor);
|
||||
}
|
||||
|
||||
void BaseSurface::drawBox() {
|
||||
Graphics::ManagedSurface::hLine(_orgX1, _orgY1, _orgX2, _lColor);
|
||||
Graphics::ManagedSurface::hLine(_orgX1, _orgY2, _orgX2, _lColor);
|
||||
Graphics::ManagedSurface::vLine(_orgX1, _orgY1, _orgY2, _lColor);
|
||||
Graphics::ManagedSurface::vLine(_orgX2, _orgY1, _orgY2, _lColor);
|
||||
}
|
||||
|
||||
void BaseSurface::flipHorizontal(BaseSurface &dest) {
|
||||
dest.create(this->w, this->h);
|
||||
for (int y = 0; y < h; ++y) {
|
||||
const byte *pSrc = (const byte *)getBasePtr(this->w - 1, y);
|
||||
byte *pDest = (byte *)dest.getBasePtr(0, y);
|
||||
|
||||
for (int x = 0; x < w; ++x, --pSrc, ++pDest)
|
||||
*pDest = *pSrc;
|
||||
}
|
||||
}
|
||||
|
||||
void BaseSurface::moveBufferLeft() {
|
||||
byte *p = (byte *)getPixels();
|
||||
Common::copy(p + TILE_WIDTH, p + (w * h), p);
|
||||
}
|
||||
|
||||
void BaseSurface::moveBufferRight() {
|
||||
byte *p = (byte *)getPixels();
|
||||
Common::copy_backward(p, p + (pitch * h) - TILE_WIDTH, p + (pitch * h));
|
||||
}
|
||||
|
||||
void BaseSurface::moveBufferUp() {
|
||||
byte *p = (byte *)getPixels();
|
||||
Common::copy(p + (pitch * TILE_HEIGHT), p + (pitch * h), p);
|
||||
}
|
||||
|
||||
void BaseSurface::moveBufferDown() {
|
||||
byte *p = (byte *)getPixels();
|
||||
Common::copy_backward(p, p + (pitch * (h - TILE_HEIGHT)), p + (pitch * h));
|
||||
}
|
||||
|
||||
/* For compatibility with the original logic, true return means the
|
||||
rect is *outside* the clip region. */
|
||||
bool BaseSurface::clip(Common::Rect &r) {
|
||||
int skip;
|
||||
_leftSkip = _rightSkip = 0;
|
||||
_topSkip = _bottomSkip = 0;
|
||||
|
||||
if (r.left > _clipWidth || r.left < 0) {
|
||||
if (r.left >= 0)
|
||||
return true;
|
||||
|
||||
skip = -r.left;
|
||||
r.setWidth(r.width() - skip);
|
||||
_leftSkip = skip;
|
||||
r.moveTo(0, r.top);
|
||||
}
|
||||
|
||||
int right = r.right - 1;
|
||||
if (right < 0)
|
||||
return true;
|
||||
else if (right > _clipWidth) {
|
||||
skip = right - _clipWidth;
|
||||
r.setWidth(r.width() - skip);
|
||||
_rightSkip = skip;
|
||||
}
|
||||
|
||||
if (r.top > _clipHeight || r.top < 0) {
|
||||
if (r.top >= 0)
|
||||
return true;
|
||||
|
||||
skip = -r.top;
|
||||
r.setHeight(r.height() - skip);
|
||||
_topSkip = skip;
|
||||
r.moveTo(r.left, 0);
|
||||
}
|
||||
|
||||
int bottom = r.bottom - 1;
|
||||
if (bottom < 0)
|
||||
return true;
|
||||
else if (bottom > _clipHeight) {
|
||||
skip = bottom - _clipHeight;
|
||||
_bottomSkip = skip;
|
||||
r.setHeight(r.height() - skip);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Access
|
||||
177
engines/access/asurface.h
Normal file
177
engines/access/asurface.h
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ACCESS_ASURFACE_H
|
||||
#define ACCESS_ASURFACE_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/array.h"
|
||||
#include "common/memstream.h"
|
||||
#include "common/rect.h"
|
||||
#include "graphics/screen.h"
|
||||
#include "access/data.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
class SpriteResource;
|
||||
class SpriteFrame;
|
||||
|
||||
/**
|
||||
* Base Access surface class. This derivces from Graphics::Screen
|
||||
* because it has logic we'll need for our own Screen class that
|
||||
* derives from this one
|
||||
*/
|
||||
class BaseSurface : virtual public Graphics::Screen {
|
||||
private:
|
||||
Graphics::Surface _savedBlock;
|
||||
|
||||
void flipHorizontal(BaseSurface &dest);
|
||||
protected:
|
||||
Common::Rect _savedBounds;
|
||||
public:
|
||||
int _leftSkip, _rightSkip;
|
||||
int _topSkip, _bottomSkip;
|
||||
int _orgX1, _orgY1;
|
||||
int _orgX2, _orgY2;
|
||||
int _lColor;
|
||||
|
||||
Common::Point _printOrg;
|
||||
Common::Point _printStart;
|
||||
int _maxChars;
|
||||
public:
|
||||
// These values need to be shared between the buffers
|
||||
static int _lastBoundsX, _lastBoundsY;
|
||||
static int _lastBoundsW, _lastBoundsH;
|
||||
static int _clipWidth, _clipHeight;
|
||||
public:
|
||||
BaseSurface();
|
||||
|
||||
~BaseSurface() override;
|
||||
|
||||
void clearBuffer();
|
||||
|
||||
void plotImage(const SpriteResource *sprite, int frameNum, const Common::Point &pt);
|
||||
|
||||
/**
|
||||
* Scaled draw frame in forward orientation
|
||||
*/
|
||||
void sPlotF(const SpriteFrame *frame, const Common::Rect &bounds);
|
||||
|
||||
/**
|
||||
* Scaled draw frame in backwards orientation
|
||||
*/
|
||||
void sPlotB(const SpriteFrame *frame, const Common::Rect &bounds);
|
||||
|
||||
/**
|
||||
* Draw an image full-size in forward orientation
|
||||
*/
|
||||
void plotF(const SpriteFrame *frame, const Common::Point &pt);
|
||||
|
||||
/**
|
||||
* Draw an image full-size in backwards orientation
|
||||
*/
|
||||
void plotB(const SpriteFrame *frame, const Common::Point &pt);
|
||||
|
||||
virtual void copyBlock(const BaseSurface *src, const Common::Rect &bounds);
|
||||
|
||||
virtual void restoreBlock();
|
||||
|
||||
virtual void drawRect();
|
||||
|
||||
virtual void drawLine(int x1, int y1, int x2, int y2, int col);
|
||||
|
||||
virtual void drawLine();
|
||||
|
||||
virtual void drawBox();
|
||||
|
||||
virtual void copyBuffer(Graphics::ManagedSurface *src);
|
||||
|
||||
void copyTo(BaseSurface *dest);
|
||||
|
||||
void saveBlock(const Common::Rect &bounds);
|
||||
|
||||
void moveBufferLeft();
|
||||
|
||||
void moveBufferRight();
|
||||
|
||||
void moveBufferUp();
|
||||
|
||||
void moveBufferDown();
|
||||
|
||||
bool clip(Common::Rect &r);
|
||||
};
|
||||
|
||||
class ASurface : public BaseSurface {
|
||||
protected:
|
||||
/**
|
||||
* Override the addDirtyRect from Graphics::Screen, since for standard
|
||||
* surfaces we don't need dirty rects to be tracked
|
||||
*/
|
||||
void addDirtyRect(const Common::Rect &r) override {}
|
||||
public:
|
||||
ASurface() : BaseSurface() {}
|
||||
};
|
||||
|
||||
class SpriteFrame : public ASurface {
|
||||
public:
|
||||
SpriteFrame(const AccessEngine *vm, Common::SeekableReadStream *stream, int frameSize);
|
||||
~SpriteFrame() override;
|
||||
};
|
||||
|
||||
class SpriteResource {
|
||||
public:
|
||||
Common::Array<SpriteFrame *> _frames;
|
||||
public:
|
||||
SpriteResource(const AccessEngine *vm, Resource *res);
|
||||
~SpriteResource();
|
||||
|
||||
int getCount() { return _frames.size(); }
|
||||
|
||||
const SpriteFrame *getFrame(int idx) const { return _frames[idx]; }
|
||||
};
|
||||
|
||||
enum ImageFlag {
|
||||
IMGFLAG_NONE = 0,
|
||||
IMGFLAG_CROPPED = 1,
|
||||
IMGFLAG_BACKWARDS = 2,
|
||||
IMGFLAG_DRAWN = 4,
|
||||
IMGFLAG_UNSCALED = 8
|
||||
};
|
||||
|
||||
class ImageEntry {
|
||||
public:
|
||||
int _frameNumber;
|
||||
SpriteResource *_spritesPtr;
|
||||
int _offsetY;
|
||||
Common::Point _position;
|
||||
int _flags;
|
||||
public:
|
||||
ImageEntry();
|
||||
};
|
||||
|
||||
class ImageEntryList : public Common::Array<ImageEntry> {
|
||||
public:
|
||||
void addToList(ImageEntry &ie);
|
||||
};
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_ASURFACE_H */
|
||||
800
engines/access/bubble_box.cpp
Normal file
800
engines/access/bubble_box.cpp
Normal file
@@ -0,0 +1,800 @@
|
||||
/* 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 "common/algorithm.h"
|
||||
#include "access/bubble_box.h"
|
||||
#include "access/access.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
BubbleBox::BubbleBox(AccessEngine *vm, Access::BoxType type, int x, int y, int w, int h, int val1, int val2, int val3, int val4, const char *title) : Manager(vm) {
|
||||
_type = type;
|
||||
_bounds = Common::Rect(x, y, x + w, y + h);
|
||||
_bubbleDisplStr = title;
|
||||
_btnId1 = val1;
|
||||
_btnX1 = val2;
|
||||
_btnId2 = val3;
|
||||
_btnX2 = val4;
|
||||
_btnId3 = _btnX3 = 0; // Unused in MM and Amazon?
|
||||
_boxStartX = _boxStartY = 0;
|
||||
_bIconStartX = _bIconStartY = 0;
|
||||
_boxEndX = _boxEndY = 0;
|
||||
_boxPStartX = _boxPStartY = 0;
|
||||
// Unused in AGoE
|
||||
for (int i = 0; i < ARRAYSIZE(_tempList); i++) {
|
||||
_tempList[i].clear();
|
||||
_tempListIdx[i] = 0;
|
||||
}
|
||||
_btnUpPos = Common::Rect(0, 0, 0, 0);
|
||||
_btnDownPos = Common::Rect(0, 0, 0, 0);
|
||||
_startItem = _startBox = 0;
|
||||
_charCol = 0;
|
||||
_rowOff = 0;
|
||||
}
|
||||
|
||||
void BubbleBox::load(Common::SeekableReadStream *stream) {
|
||||
_bubbleTitle = stream->readString();
|
||||
_bubbleDisplStr = _bubbleTitle;
|
||||
}
|
||||
|
||||
void BubbleBox::clearBubbles() {
|
||||
// Loop through the bubble list to restore the screen areas
|
||||
for (Common::Rect r: _bubbles) {
|
||||
_vm->_screen->_screenYOff = 0;
|
||||
r.left -= 2;
|
||||
r.right = MIN(r.right, (int16)_vm->_screen->w);
|
||||
|
||||
_vm->_screen->copyBlock(&_vm->_buffer1, r);
|
||||
}
|
||||
|
||||
// Clear the list
|
||||
_bubbles.clear();
|
||||
}
|
||||
|
||||
void BubbleBox::placeBubble(const Common::String &msg) {
|
||||
_vm->_screen->_maxChars = (_vm->getGameID() == kGameMartianMemorandum) ? 30 : 27;
|
||||
placeBubble1(msg);
|
||||
}
|
||||
|
||||
void BubbleBox::placeBubble1(const Common::String &msg) {
|
||||
_bubbles.clear();
|
||||
_vm->_fonts._charSet._lo = 1;
|
||||
_vm->_fonts._charSet._hi = 8;
|
||||
_vm->_fonts._charFor._lo = (_vm->getGameID() == kGameMartianMemorandum) ? 247 : 29;
|
||||
_vm->_fonts._charFor._hi = (_vm->getGameID() == kGameMartianMemorandum) ? 255 : 32;
|
||||
|
||||
calcBubble(msg);
|
||||
|
||||
Common::Rect r = _bubbles[0];
|
||||
r.translate(-2, 0);
|
||||
_vm->_screen->saveBlock(r);
|
||||
printBubble(msg);
|
||||
}
|
||||
|
||||
void BubbleBox::calcBubble(const Common::String &msg) {
|
||||
// Save points
|
||||
Screen &screen = *_vm->_screen;
|
||||
Common::Point printOrg = screen._printOrg;
|
||||
Common::Point printStart = screen._printStart;
|
||||
|
||||
// Figure out maximum width allowed
|
||||
if (_type == kBoxTypeFileDialog) {
|
||||
_vm->_fonts._printMaxX = 110;
|
||||
} else {
|
||||
_vm->_fonts._printMaxX = _vm->_fonts._font2->stringWidth(_bubbleDisplStr);
|
||||
}
|
||||
|
||||
// Start of with a rect with the given starting x and y
|
||||
Common::Rect bounds(printOrg.x - 2, printOrg.y - 10, printOrg.x - 2, printOrg.y - 10);
|
||||
|
||||
// Loop through getting lines
|
||||
Common::String s = msg;
|
||||
Common::String line;
|
||||
int width = 0;
|
||||
bool lastLine;
|
||||
do {
|
||||
if (_vm->getGameID() == kGameMartianMemorandum) {
|
||||
lastLine = _vm->_fonts._font1->getLine(s, screen._maxChars, line, width, Font::kWidthInChars);
|
||||
width = _vm->_fonts._font1->stringWidth(line);
|
||||
} else {
|
||||
lastLine = _vm->_fonts._font2->getLine(s, screen._maxChars * 6, line, width);
|
||||
}
|
||||
|
||||
_vm->_fonts._printMaxX = MAX(width, _vm->_fonts._printMaxX);
|
||||
|
||||
screen._printOrg.y += 6;
|
||||
screen._printOrg.x = screen._printStart.x;
|
||||
} while (!lastLine);
|
||||
|
||||
if (_vm->getGameID() == kGameMartianMemorandum) {
|
||||
bounds.setWidth((_vm->_fonts._printMaxX / 16 + 2) * 16 + 2 + 1);
|
||||
bounds.bottom = screen._printOrg.y + 4 + 1;
|
||||
} else {
|
||||
// TODO: Check this maths if we implement original file boxes.
|
||||
if (_type == kBoxTypeFileDialog)
|
||||
screen._printOrg.y += 6;
|
||||
|
||||
// Determine the width for the area
|
||||
width = (((_vm->_fonts._printMaxX >> 4) + 1) << 4) + 5;
|
||||
if (width >= 24)
|
||||
width += 20 - ((width - 24) % 20);
|
||||
bounds.setWidth(width);
|
||||
|
||||
// Determine the height for area
|
||||
int y = screen._printOrg.y + 6;
|
||||
if (_type == kBoxTypeFileDialog)
|
||||
y += 6;
|
||||
int height = y - bounds.top;
|
||||
bounds.setHeight(height);
|
||||
|
||||
height -= (_type == kBoxTypeFileDialog) ? 30 : 24;
|
||||
if (height >= 0)
|
||||
bounds.setHeight(bounds.height() + 13 - (height % 13));
|
||||
}
|
||||
|
||||
if (bounds.bottom > screen.h)
|
||||
bounds.translate(0, screen.h - bounds.bottom);
|
||||
|
||||
// Add the new bounds to the bubbles list
|
||||
_bubbles.push_back(bounds);
|
||||
|
||||
// Restore points
|
||||
_vm->_screen->_printOrg = printOrg;
|
||||
_vm->_screen->_printStart = printStart;
|
||||
}
|
||||
|
||||
void BubbleBox::printBubble(const Common::String &msg) {
|
||||
if (_vm->getGameID() == kGameMartianMemorandum)
|
||||
printBubble_v1(msg);
|
||||
else
|
||||
printBubble_v2(msg);
|
||||
}
|
||||
|
||||
void BubbleBox::printBubble_v1(const Common::String &msg) {
|
||||
Font::_fontColors[1] = 255;
|
||||
|
||||
drawBubble(_bubbles.size() - 1);
|
||||
|
||||
Font::_fontColors[3] = 247;
|
||||
|
||||
// Loop through drawing the lines
|
||||
Common::String s = msg;
|
||||
Common::String line;
|
||||
int width = 0;
|
||||
bool lastLine;
|
||||
do {
|
||||
// Get next line
|
||||
Font &font1 = *_vm->_fonts._font1;
|
||||
lastLine = font1.getLine(s, _vm->_screen->_maxChars, line, width, Font::kWidthInChars);
|
||||
// Draw the text
|
||||
printString(line);
|
||||
|
||||
// Move print position
|
||||
_vm->_screen->_printOrg.y += 6;
|
||||
_vm->_screen->_printOrg.x = _vm->_screen->_printStart.x;
|
||||
} while (!lastLine);
|
||||
|
||||
}
|
||||
|
||||
void BubbleBox::printBubble_v2(const Common::String &msg) {
|
||||
drawBubble(_bubbles.size() - 1);
|
||||
|
||||
// Loop through drawing the lines
|
||||
Common::String s = msg;
|
||||
Common::String line;
|
||||
int width = 0;
|
||||
bool lastLine;
|
||||
do {
|
||||
// Get next line
|
||||
Font &font2 = *_vm->_fonts._font2;
|
||||
lastLine = font2.getLine(s, _vm->_screen->_maxChars * 6, line, width);
|
||||
|
||||
// Set font colors
|
||||
font2._fontColors[0] = 0;
|
||||
font2._fontColors[1] = 27;
|
||||
font2._fontColors[2] = 28;
|
||||
font2._fontColors[3] = 29;
|
||||
|
||||
int xp = _vm->_screen->_printOrg.x;
|
||||
if (_type == kBoxTypeFileDialog)
|
||||
xp = (_bounds.width() - width) / 2 + _bounds.left - 4;
|
||||
|
||||
// Draw the text
|
||||
font2.drawString(_vm->_screen, line, Common::Point(xp, _vm->_screen->_printOrg.y));
|
||||
|
||||
// Move print position
|
||||
_vm->_screen->_printOrg.y += 6;
|
||||
_vm->_screen->_printOrg.x = _vm->_screen->_printStart.x;
|
||||
} while (!lastLine);
|
||||
}
|
||||
|
||||
void BubbleBox::drawBubble(int index) {
|
||||
_bounds = _bubbles[index];
|
||||
if (_vm->getGameID() == kGameMartianMemorandum) {
|
||||
int btnSelected = 0;
|
||||
doBox_v1(0, 0, btnSelected);
|
||||
} else
|
||||
doBox(0, 0);
|
||||
}
|
||||
|
||||
void BubbleBox::doBox(int item, int box) {
|
||||
FontManager &fonts = _vm->_fonts;
|
||||
Screen &screen = *_vm->_screen;
|
||||
|
||||
_startItem = item;
|
||||
_startBox = box;
|
||||
|
||||
// Save state information
|
||||
FontVal charSet = fonts._charSet;
|
||||
FontVal charFor = fonts._charFor;
|
||||
Common::Point printOrg = screen._printOrg;
|
||||
Common::Point printStart = screen._printStart;
|
||||
int charCol = _charCol;
|
||||
int rowOff = _rowOff;
|
||||
|
||||
_vm->_screen->saveScreen();
|
||||
_vm->_screen->setDisplayScan();
|
||||
fonts._charFor._hi = 0xff;
|
||||
fonts._charSet._lo = 1;
|
||||
fonts._charSet._hi = 0;
|
||||
|
||||
if (_type == kBoxTypeFileDialog) {
|
||||
fonts._charFor._lo = 0xFF;
|
||||
error("TODO: filename listing");
|
||||
return;
|
||||
}
|
||||
|
||||
const SpriteResource *icons = _vm->getIcons();
|
||||
|
||||
// Set the up boundaries and color to use for the box background
|
||||
_vm->_screen->_orgX1 = _bounds.left - 2;
|
||||
_vm->_screen->_orgY1 = _bounds.top;
|
||||
_vm->_screen->_orgX2 = _bounds.right - 2;
|
||||
_vm->_screen->_orgY2 = _bounds.bottom;
|
||||
_vm->_screen->_lColor = 1;
|
||||
|
||||
int h = _bounds.height() - (_type == kBoxTypeFileDialog ? 30 : 24);
|
||||
int ySize = (h < 0) ? 0 : (h + 12) / 13;
|
||||
int w = _bounds.width() - 24;
|
||||
int xSize = (w < 0) ? 0 : (w + 19) / 20;
|
||||
|
||||
// Draw a background for the entire area
|
||||
screen.drawRect();
|
||||
|
||||
// Draw images to form the top border
|
||||
int xp, yp;
|
||||
screen.plotImage(icons, 20, Common::Point(screen._orgX1, screen._orgY1));
|
||||
xp = screen._orgX1 + 12;
|
||||
for (int x = 0; x < xSize; ++x, xp += 20)
|
||||
screen.plotImage(icons, 24 + x, Common::Point(xp, screen._orgY1));
|
||||
screen.plotImage(icons, 21, Common::Point(xp, screen._orgY1));
|
||||
|
||||
// Draw images to form the bottom border
|
||||
yp = screen._orgY2 - (_type == kBoxTypeFileDialog ? 18 : 12);
|
||||
screen.plotImage(icons, (_type == kBoxTypeFileDialog) ? 72 : 22,
|
||||
Common::Point(screen._orgX1, yp));
|
||||
xp = screen._orgX1 + 12;
|
||||
yp += (_type == kBoxTypeFileDialog) ? 4 : 8;
|
||||
|
||||
for (int x = 0; x < xSize; ++x, xp += 20) {
|
||||
screen.plotImage(icons, (_type == kBoxTypeFileDialog ? 62 : 34) + x,
|
||||
Common::Point(xp, yp));
|
||||
}
|
||||
|
||||
yp = screen._orgY2 - (_type == kBoxTypeFileDialog ? 18 : 12);
|
||||
screen.plotImage(icons, (_type == kBoxTypeFileDialog) ? 73 : 23, Common::Point(xp, yp));
|
||||
|
||||
if (_type == kBoxTypeFileDialog) {
|
||||
// Further stuff for filename dialog
|
||||
error("TODO: Box type 4");
|
||||
}
|
||||
|
||||
// Draw images to form the sides
|
||||
yp = screen._orgY1 + 12;
|
||||
for (int y = 0; y < ySize; ++y, yp += 13) {
|
||||
screen.plotImage(icons, 44 + y, Common::Point(screen._orgX1, yp));
|
||||
screen.plotImage(icons, 53 + y, Common::Point(screen._orgX2 - 4, yp));
|
||||
}
|
||||
|
||||
// Handle drawing title
|
||||
int titleWidth = _vm->_fonts._font2->stringWidth(_bubbleDisplStr);
|
||||
Font &font2 = *_vm->_fonts._font2;
|
||||
font2._fontColors[0] = 0;
|
||||
font2._fontColors[1] = 3;
|
||||
font2._fontColors[2] = 2;
|
||||
font2._fontColors[3] = 1;
|
||||
font2.drawString(_vm->_screen, _bubbleDisplStr, Common::Point(
|
||||
_bounds.left + (_bounds.width() / 2) - (titleWidth / 2), _bounds.top + 1));
|
||||
|
||||
// Restore positional state
|
||||
fonts._charSet = charSet;
|
||||
fonts._charFor = charFor;
|
||||
screen._printOrg = printOrg;
|
||||
screen._printStart = printStart;
|
||||
_charCol = charCol;
|
||||
_rowOff = rowOff;
|
||||
_vm->_screen->restoreScreen();
|
||||
}
|
||||
|
||||
void BubbleBox::setCursorPos(int posX, int posY) {
|
||||
Common::Point newPt = Common::Point(posX * 8, posY * 8 + _rowOff);
|
||||
_vm->_screen->_printStart = _vm->_screen->_printOrg = newPt;
|
||||
}
|
||||
|
||||
void BubbleBox::printString(Common::String msg) {
|
||||
|
||||
if (_vm->_fonts._charSet._hi & 2) {
|
||||
// Draw a shadow for the text
|
||||
Common::Point shadowPt = _vm->_screen->_printOrg + Common::Point(1, 1);
|
||||
byte oldcol = Font::_fontColors[3];
|
||||
Font::_fontColors[3] = 0;
|
||||
_vm->_fonts._font1->drawString(_vm->_screen, msg, shadowPt);
|
||||
Font::_fontColors[3] = oldcol;
|
||||
}
|
||||
|
||||
_vm->_fonts._font1->drawString(_vm->_screen, msg, _vm->_screen->_printOrg);
|
||||
}
|
||||
|
||||
void BubbleBox::displayBoxData() {
|
||||
_vm->_boxDataEnd = false;
|
||||
_rowOff = 2;
|
||||
_vm->_fonts._charFor._lo = 0xF7;
|
||||
_vm->_fonts._charFor._hi = 0xFF;
|
||||
Font::_fontColors[3] = 247;
|
||||
|
||||
if (_tempList[0].size() == 0)
|
||||
return;
|
||||
|
||||
int idx = 0;
|
||||
if ((_type == TYPE_1) || (_type == TYPE_3)) {
|
||||
_vm->_bcnt = 0;
|
||||
|
||||
if (_tempList[idx].size() == 0) {
|
||||
_vm->_boxDataEnd = true;
|
||||
return;
|
||||
}
|
||||
|
||||
_vm->_events->hideCursor();
|
||||
|
||||
_vm->_screen->_orgX1 = _boxStartX;
|
||||
_vm->_screen->_orgX2 = _boxEndX + 1;
|
||||
_vm->_screen->_orgY1 = _boxStartY;
|
||||
_vm->_screen->_orgY2 = _boxEndY;
|
||||
_vm->_screen->_lColor = 0xFA;
|
||||
_vm->_screen->drawRect();
|
||||
_vm->_events->showCursor();
|
||||
}
|
||||
|
||||
_vm->_events->hideCursor();
|
||||
int oldPStartY = _boxPStartY;
|
||||
++_boxPStartY;
|
||||
|
||||
idx += _vm->_boxDataStart;
|
||||
|
||||
while (true) {
|
||||
setCursorPos(_boxPStartX, _boxPStartY);
|
||||
printString(_tempList[idx]);
|
||||
|
||||
++idx;
|
||||
++_boxPStartY;
|
||||
++_vm->_bcnt;
|
||||
if (_tempList[idx].size() == 0) {
|
||||
_boxPStartY = oldPStartY;
|
||||
_vm->_events->showCursor();
|
||||
_vm->_boxDataEnd = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_vm->_bcnt == _vm->_numLines) {
|
||||
_boxPStartY = oldPStartY;
|
||||
_vm->_events->showCursor();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BubbleBox::drawSelectBox() {
|
||||
if (_tempList[0].size() == 0)
|
||||
return;
|
||||
|
||||
if (((_type != TYPE_1) && (_type != TYPE_3)) || !_vm->_bcnt)
|
||||
return;
|
||||
|
||||
if (_vm->_boxSelectYOld != -1) {
|
||||
_vm->_events->hideCursor();
|
||||
_vm->_screen->_lColor = 0xFA;
|
||||
|
||||
int val = _vm->_boxSelectYOld + _boxPStartY + 1;
|
||||
_vm->_screen->_orgY1 = (val << 3) + 2;
|
||||
_vm->_screen->_orgY2 = _vm->_screen->_orgY1 + 7;
|
||||
_vm->_screen->_orgX1 = _boxStartX;
|
||||
_vm->_screen->_orgX2 = _boxEndX;
|
||||
_vm->_screen->drawBox();
|
||||
_vm->_events->showCursor();
|
||||
}
|
||||
|
||||
_vm->_events->hideCursor();
|
||||
_vm->_boxSelectYOld = _vm->_boxSelectY;
|
||||
int val = _boxPStartY + _vm->_boxSelectY + 1;
|
||||
_vm->_screen->_orgY1 = (val << 3) + 2;
|
||||
_vm->_screen->_orgY2 = _vm->_screen->_orgY1 + 7;
|
||||
_vm->_screen->_orgX1 = _boxStartX;
|
||||
_vm->_screen->_orgX2 = _boxEndX;
|
||||
_vm->_screen->_lColor = 0xFE;
|
||||
_vm->_screen->drawBox();
|
||||
_vm->_events->showCursor();
|
||||
|
||||
if (_type == TYPE_3)
|
||||
warning("TODO: List filenames");
|
||||
}
|
||||
|
||||
int BubbleBox::doBox_v1(int item, int box, int &btnSelected) {
|
||||
static const int ICONW[] = { 0, 11, 28, 19, 19, 15 };
|
||||
|
||||
FontManager &fonts = _vm->_fonts;
|
||||
int retval_ = -1;
|
||||
|
||||
_startItem = item;
|
||||
_startBox = box;
|
||||
|
||||
Common::Point origPrintStart = _vm->_screen->_printStart;
|
||||
Common::Point origPrintOrg = _vm->_screen->_printOrg;
|
||||
|
||||
_vm->_events->hideCursor();
|
||||
|
||||
// Save state information
|
||||
_vm->_screen->saveScreen();
|
||||
_vm->_screen->setDisplayScan();
|
||||
|
||||
fonts._charFor._hi = 0xff;
|
||||
fonts._charSet._lo = 1;
|
||||
fonts._charSet._hi = 0;
|
||||
|
||||
_vm->_destIn = _vm->_screen; // TODO: Redundant
|
||||
|
||||
if (_type != TYPE_2) {
|
||||
Common::Rect r = _bounds;
|
||||
r.left -= 2;
|
||||
_vm->_screen->saveBlock(r);
|
||||
}
|
||||
|
||||
// Set the up boundaries and color to use for the box background
|
||||
_vm->_screen->_orgX1 = _bounds.left - 2;
|
||||
_vm->_screen->_orgY1 = _bounds.top;
|
||||
_vm->_screen->_orgX2 = _bounds.right - 2;
|
||||
_vm->_screen->_orgY2 = _bounds.bottom;
|
||||
_vm->_screen->_lColor = 0xFB;
|
||||
|
||||
// Draw a background for the entire area
|
||||
_vm->_screen->drawRect();
|
||||
|
||||
// Draw the inner box;
|
||||
++_vm->_screen->_orgX1;
|
||||
++_vm->_screen->_orgY1;
|
||||
_vm->_screen->_orgX2 -= 2;
|
||||
_vm->_screen->_orgY2 -= 2;
|
||||
_vm->_screen->_lColor = 0xF9;
|
||||
|
||||
// Draw the inner border
|
||||
_vm->_screen->drawBox();
|
||||
|
||||
const SpriteResource *icons = _vm->getIcons();
|
||||
|
||||
// Draw upper border
|
||||
_vm->_bcnt = (_vm->_screen->_orgX2 - _vm->_screen->_orgX1) >> 4;
|
||||
int oldX = _vm->_screen->_orgX1;
|
||||
for ( ;_vm->_bcnt > 0; --_vm->_bcnt) {
|
||||
_vm->_screen->plotImage(icons, 16, Common::Point(_vm->_screen->_orgX1, _vm->_screen->_orgY1));
|
||||
_vm->_screen->_orgX1 += 16;
|
||||
}
|
||||
|
||||
_vm->_screen->_orgX1 = oldX;
|
||||
int oldY = _vm->_screen->_orgY2;
|
||||
_vm->_screen->_orgY2 = _vm->_screen->_orgY1 + 8;
|
||||
_vm->_screen->_lColor = 0xF9;
|
||||
|
||||
_boxStartY = _vm->_screen->_orgY2 + 1;
|
||||
_vm->_screen->_orgY2 = oldY;
|
||||
|
||||
int tmpX = 0;
|
||||
int tmpY = 0;
|
||||
if (_type != TYPE_2) {
|
||||
// Draw the button background at the bottom
|
||||
oldY = _vm->_screen->_orgY1;
|
||||
// Original does this here, but we need bottom/right offset by 1.
|
||||
//--_vm->_screen->_orgY2;
|
||||
_vm->_screen->_orgY1 = _vm->_screen->_orgY2 - 8;
|
||||
if (_type == TYPE_3)
|
||||
_vm->_screen->_orgY1 -= 8;
|
||||
_vm->_screen->drawRect();
|
||||
tmpX = _bIconStartX = _vm->_screen->_orgX1;
|
||||
|
||||
_boxStartX = tmpX + 1;
|
||||
tmpY = _boxEndY = _vm->_screen->_orgY1;
|
||||
|
||||
if (_type == TYPE_3)
|
||||
_bIconStartY = tmpY + 9;
|
||||
else
|
||||
_bIconStartY = tmpY + 1;
|
||||
|
||||
if (_type == TYPE_3) {
|
||||
_fileStart = Common::Point((tmpX + 2) >> 3, (tmpY + 2) >> 3);
|
||||
int rowOff = tmpY - (_fileStart.y << 3) + 1;
|
||||
if (rowOff == 8) {
|
||||
rowOff = 0;
|
||||
++_fileStart.y;
|
||||
}
|
||||
_fileOff.y = _rowOff = rowOff;
|
||||
setCursorPos(_fileStart.x, _fileStart.y);
|
||||
_vm->_fonts._charFor._lo = 0xF7;
|
||||
_vm->_fonts._charFor._hi = 0;
|
||||
printString("FILE: ");
|
||||
_vm->_fonts._charFor._hi = 0xFF;
|
||||
}
|
||||
_vm->_screen->_orgY1 = oldY;
|
||||
}
|
||||
|
||||
if ((_type != TYPE_0) && (_type != TYPE_2)) {
|
||||
_vm->_screen->_orgY1 += 8;
|
||||
if (_type == TYPE_3)
|
||||
_vm->_screen->_orgY2 -= 8;
|
||||
|
||||
_vm->_screen->_orgY2 -= 8;
|
||||
_btnUpPos.right = _btnDownPos.right = _vm->_screen->_orgX2;
|
||||
_btnUpPos.left = _btnDownPos.left = _vm->_screen->_orgX1 = _vm->_screen->_orgX2 - 8;
|
||||
_boxEndX = _vm->_screen->_orgX1 - 1;
|
||||
_vm->_screen->drawBox();
|
||||
|
||||
_vm->_screen->_orgY1 += 6;
|
||||
_vm->_screen->_orgY2 -= 6;
|
||||
_vm->_screen->drawBox();
|
||||
|
||||
_btnUpPos.bottom = _vm->_screen->_orgY1 + 1;
|
||||
_btnUpPos.top = _btnUpPos.bottom - 5;
|
||||
_btnDownPos.top = _vm->_screen->_orgY2 + 1;
|
||||
_btnDownPos.bottom = _btnDownPos.top + 6;
|
||||
|
||||
_vm->_screen->_orgX1 += 4;
|
||||
_vm->_screen->_orgX2 = _vm->_screen->_orgX1;
|
||||
_vm->_screen->_orgY1 -= 4;
|
||||
_vm->_screen->_orgY2 += 2;
|
||||
_vm->_screen->drawLine();
|
||||
|
||||
++_vm->_screen->_orgY1;
|
||||
--_vm->_screen->_orgX1;
|
||||
++_vm->_screen->_orgX2;
|
||||
_vm->_screen->drawLine();
|
||||
|
||||
++_vm->_screen->_orgY1;
|
||||
--_vm->_screen->_orgX1;
|
||||
++_vm->_screen->_orgX2;
|
||||
_vm->_screen->drawLine();
|
||||
|
||||
_vm->_screen->_orgY1 = _vm->_screen->_orgY2;
|
||||
_vm->_screen->drawLine();
|
||||
|
||||
++_vm->_screen->_orgX1;
|
||||
--_vm->_screen->_orgX2;
|
||||
++_vm->_screen->_orgY1;
|
||||
_vm->_screen->drawLine();
|
||||
|
||||
++_vm->_screen->_orgX1;
|
||||
--_vm->_screen->_orgX2;
|
||||
++_vm->_screen->_orgY1;
|
||||
_vm->_screen->drawLine();
|
||||
}
|
||||
|
||||
// Draw the box title
|
||||
int displStrLen = _bubbleDisplStr.size();
|
||||
|
||||
_boxPStartX = _bounds.left / 8;
|
||||
int newX = _boxPStartX + (_bounds.width() / 8 - displStrLen) / 2;
|
||||
|
||||
_boxPStartY = _bounds.top / 8;
|
||||
_rowOff = 1 - (_boxPStartY * 8 - _bounds.top);
|
||||
if (_rowOff == 8) {
|
||||
_rowOff = 0;
|
||||
++_boxPStartY;
|
||||
}
|
||||
|
||||
retval_ = _rowOff;
|
||||
|
||||
setCursorPos(newX, _boxPStartY);
|
||||
|
||||
Font::_fontColors[1] = _vm->_fonts._charFor._lo = 0xFF;
|
||||
_vm->_fonts._bitFont->drawString(_vm->_screen, _bubbleDisplStr, _vm->_screen->_printOrg);
|
||||
|
||||
if (_type == TYPE_2) {
|
||||
_vm->_events->showCursor();
|
||||
_vm->_screen->_printStart = origPrintStart;
|
||||
_vm->_screen->_printOrg = origPrintOrg;
|
||||
_vm->_screen->restoreScreen();
|
||||
return retval_;
|
||||
}
|
||||
|
||||
_vm->_destIn = _vm->_screen;
|
||||
|
||||
// Draw buttons
|
||||
int ICON1T = 0;
|
||||
int ICON1X = 0;
|
||||
int ICON1Y = 0;
|
||||
int ICON2T = 0;
|
||||
int ICON2X = 0;
|
||||
int ICON3T = 0;
|
||||
int ICON3X = 0;
|
||||
if (_btnId1) {
|
||||
ICON1T = _btnId1;
|
||||
ICON1X = _bIconStartX + _btnX1;
|
||||
ICON1Y = _bIconStartY;
|
||||
_vm->_screen->plotImage(icons, ICON1T + 10, Common::Point(ICON1X, ICON1Y));
|
||||
|
||||
if (_btnId2) {
|
||||
ICON2T = _btnId2;
|
||||
ICON2X = _bIconStartX + _btnX2;
|
||||
_vm->_screen->plotImage(icons, ICON2T + 10, Common::Point(ICON2X, _bIconStartY));
|
||||
|
||||
if (_btnId3) {
|
||||
ICON3T = _btnId3;
|
||||
ICON3X = _bIconStartX + _btnX3;
|
||||
_vm->_screen->plotImage(icons, ICON3T + 10, Common::Point(ICON3X, _bIconStartY));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_vm->_screen->restoreScreen();
|
||||
_vm->_boxDataStart = _startItem;
|
||||
_vm->_boxSelectYOld = -1;
|
||||
_vm->_boxSelectY = _startBox;
|
||||
|
||||
_vm->_numLines = (_bounds.height() / 8) - 2;
|
||||
if (_type == TYPE_3)
|
||||
--_vm->_numLines;
|
||||
|
||||
_vm->_events->showCursor();
|
||||
displayBoxData();
|
||||
drawSelectBox();
|
||||
|
||||
while (!_vm->shouldQuit()) {
|
||||
_vm->_events->pollEvents();
|
||||
if (!_vm->_events->_leftButton && !_vm->_events->_wheelDown && !_vm->_events->_wheelUp && !_vm->_events->isKeyActionPending())
|
||||
continue;
|
||||
|
||||
//
|
||||
// Slight enhancement from original - we also allow mouse wheel and
|
||||
// keyboard events to scroll up/down.
|
||||
//
|
||||
if (((_type == TYPE_1) || (_type == TYPE_3)) && (_vm->_timers[2]._flag == 0)) {
|
||||
++_vm->_timers[2]._flag;
|
||||
|
||||
Common::CustomEventType action = kActionNone;
|
||||
_vm->_events->getAction(action);
|
||||
if (_btnUpPos.contains(_vm->_events->_mousePos) || _vm->_events->_wheelUp || action == kActionMoveUp) {
|
||||
if (_vm->_bcnt) {
|
||||
if (_vm->_boxSelectY != 0) {
|
||||
--_vm->_boxSelectY;
|
||||
drawSelectBox();
|
||||
} else if (_vm->_boxDataStart != 0) {
|
||||
--_vm->_boxDataStart;
|
||||
displayBoxData();
|
||||
drawSelectBox();
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} else if (_btnDownPos.contains(_vm->_events->_mousePos) || _vm->_events->_wheelDown || action == kActionMoveDown) {
|
||||
if (_vm->_bcnt) {
|
||||
if (_vm->_bcnt == _vm->_numLines) {
|
||||
if (_vm->_bcnt != _vm->_boxSelectY + 1) {
|
||||
++_vm->_boxSelectY;
|
||||
drawSelectBox();
|
||||
} else if (!_vm->_boxDataEnd) {
|
||||
++_vm->_boxDataStart;
|
||||
displayBoxData();
|
||||
drawSelectBox();
|
||||
}
|
||||
} else if (_vm->_bcnt != _vm->_boxSelectY + 1) {
|
||||
++_vm->_boxSelectY;
|
||||
drawSelectBox();
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_vm->_events->_leftButton)
|
||||
continue;
|
||||
|
||||
if ((_vm->_events->_mousePos.x >= _boxStartX) && (_vm->_events->_mousePos.x <= _boxEndX)
|
||||
&& (_vm->_events->_mousePos.y >= _boxStartY) && (_vm->_events->_mousePos.y <= _boxEndY)) {
|
||||
int val = (_vm->_events->_mousePos.y >> 3) - _boxPStartY;
|
||||
if (val > _vm->_bcnt)
|
||||
continue;
|
||||
--val;
|
||||
if (_type == TYPE_3)
|
||||
_vm->_boxSelect = val;
|
||||
else {
|
||||
btnSelected = 1;
|
||||
if (_vm->_boxSelectY == val)
|
||||
break;
|
||||
_vm->_boxSelectY = val;
|
||||
_vm->_events->debounceLeft();
|
||||
drawSelectBox();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ((_vm->_events->_mousePos.y >= ICON1Y) && (_vm->_events->_mousePos.y <= ICON1Y + 8)
|
||||
&& (_vm->_events->_mousePos.x >= ICON1X)) {
|
||||
btnSelected = 1;
|
||||
if (_vm->_events->_mousePos.x < ICON1X + ICONW[ICON1T])
|
||||
break;
|
||||
|
||||
if ((_vm->_events->_mousePos.x >= ICON2X) && (_vm->_events->_mousePos.x < ICON2X + ICONW[ICON2T])) {
|
||||
btnSelected = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((_vm->_events->_mousePos.x >= ICON3X) && (_vm->_events->_mousePos.x < ICON3X + ICONW[ICON3T])) {
|
||||
btnSelected = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_type != TYPE_3)
|
||||
continue;
|
||||
|
||||
if ((_vm->_events->_mousePos.x < tmpX) || (_vm->_events->_mousePos.x > tmpX + 144))
|
||||
continue;
|
||||
|
||||
if ((_vm->_events->_mousePos.y < tmpY) || (_vm->_events->_mousePos.y > tmpY + 8))
|
||||
continue;
|
||||
|
||||
warning("TODO: sub175B5 - List of files");
|
||||
}
|
||||
}
|
||||
|
||||
_vm->_events->hideCursor();
|
||||
_vm->_screen->restoreBlock();
|
||||
_vm->_events->showCursor();
|
||||
_vm->_events->debounceLeft();
|
||||
if (_vm->_bcnt == 0)
|
||||
retval_ = -1;
|
||||
else
|
||||
retval_ = _vm->_boxDataStart + _vm->_boxSelectY;
|
||||
|
||||
_vm->_screen->_printStart = origPrintStart;
|
||||
_vm->_screen->_printOrg = origPrintOrg;
|
||||
|
||||
return retval_;
|
||||
}
|
||||
|
||||
void BubbleBox::getList(const char *const data[], const byte *flags) {
|
||||
int srcIdx = 0;
|
||||
int destIdx = 0;
|
||||
while (data[srcIdx]) {
|
||||
if (flags[srcIdx]) {
|
||||
_tempList[destIdx] = data[srcIdx];
|
||||
_tempListIdx[destIdx] = srcIdx;
|
||||
++destIdx;
|
||||
}
|
||||
srcIdx++;
|
||||
}
|
||||
_tempList[destIdx] = "";
|
||||
}
|
||||
} // End of namespace Access
|
||||
112
engines/access/bubble_box.h
Normal file
112
engines/access/bubble_box.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/* 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 ACCESS_BUBBLE_BOX_H
|
||||
#define ACCESS_BUBBLE_BOX_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/array.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/str-array.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/types.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "access/data.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
class AccessEngine;
|
||||
|
||||
enum BoxType { TYPE_0 = 0, TYPE_1 = 1, TYPE_2 = 2, TYPE_3 = 3, kBoxTypeFileDialog = 4 };
|
||||
|
||||
class BubbleBox : public Manager {
|
||||
private:
|
||||
int _startItem, _startBox;
|
||||
int _charCol, _rowOff;
|
||||
Common::Point _fileStart;
|
||||
Common::Point _fileOff;
|
||||
int _boxStartX, _boxStartY;
|
||||
int _boxEndX, _boxEndY;
|
||||
int _bIconStartX, _bIconStartY;
|
||||
int _boxPStartX, _boxPStartY;
|
||||
|
||||
void displayBoxData();
|
||||
void drawSelectBox();
|
||||
/**
|
||||
* Prints a text bubble and it's contents
|
||||
*/
|
||||
void printBubble_v1(const Common::String &msg);
|
||||
void printBubble_v2(const Common::String &msg);
|
||||
|
||||
public:
|
||||
BoxType _type;
|
||||
Common::Rect _bounds;
|
||||
Common::StringArray _nameIndex;
|
||||
Common::String _bubbleTitle;
|
||||
Common::String _bubbleDisplStr;
|
||||
Common::String _tempList[60];
|
||||
int _tempListIdx[60];
|
||||
int _btnId1;
|
||||
int _btnX1;
|
||||
int _btnId2;
|
||||
int _btnX2;
|
||||
int _btnId3;
|
||||
int _btnX3;
|
||||
Common::Rect _btnUpPos;
|
||||
Common::Rect _btnDownPos;
|
||||
Common::Array<Common::Rect> _bubbles;
|
||||
public:
|
||||
BubbleBox(AccessEngine *vm, Access::BoxType type, int x, int y, int w, int h, int val1, int val2, int val3, int val4, const char *title);
|
||||
|
||||
void load(Common::SeekableReadStream *stream);
|
||||
|
||||
void clearBubbles();
|
||||
|
||||
void placeBubble(const Common::String &msg);
|
||||
void placeBubble1(const Common::String &msg);
|
||||
|
||||
/**
|
||||
* Calculate the size of a bubble needed to hold a given string
|
||||
*/
|
||||
void calcBubble(const Common::String &msg);
|
||||
|
||||
/**
|
||||
* Prints a text bubble and it's contents
|
||||
*/
|
||||
void printBubble(const Common::String &msg);
|
||||
|
||||
/*
|
||||
* Draws the background for a text bubble
|
||||
* @param index Index of bounds in _bubbles array
|
||||
*/
|
||||
void drawBubble(int index);
|
||||
|
||||
void doBox(int item, int box);
|
||||
|
||||
int doBox_v1(int item, int box, int &btnSelected);
|
||||
void getList(const char *const data[], const byte *flags);
|
||||
void setCursorPos(int posX, int posY);
|
||||
void printString(Common::String msg);
|
||||
};
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_BUBBLE_BOX_H */
|
||||
180
engines/access/char.cpp
Normal file
180
engines/access/char.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
/* 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 "common/memstream.h"
|
||||
#include "access/access.h"
|
||||
#include "access/char.h"
|
||||
#include "access/amazon/amazon_resources.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
CharEntry::CharEntry(const byte *data, AccessEngine *vm) {
|
||||
Common::MemoryReadStream s(data, 999);
|
||||
|
||||
_charFlag = s.readByte();
|
||||
if (vm->getGameID() != kGameAmazon || !vm->isCD()) {
|
||||
_screenFile.load(s);
|
||||
_estabIndex = s.readSint16LE();
|
||||
} else {
|
||||
_estabIndex = s.readSint16LE();
|
||||
_screenFile.load(s);
|
||||
}
|
||||
|
||||
_paletteFile.load(s);
|
||||
_startColor = s.readUint16LE();
|
||||
if (vm->getGameID() == kGameMartianMemorandum) {
|
||||
int lastColor = s.readUint16LE();
|
||||
_numColors = lastColor - _startColor;
|
||||
} else
|
||||
_numColors = s.readUint16LE();
|
||||
|
||||
// Load cells
|
||||
for (byte cell = s.readByte(); cell != 0xff; cell = s.readByte()) {
|
||||
CellIdent ci;
|
||||
ci._cell = cell;
|
||||
ci.load(s);
|
||||
|
||||
_cells.push_back(ci);
|
||||
}
|
||||
|
||||
_animFile.load(s);
|
||||
_scriptFile.load(s);
|
||||
|
||||
for (int16 v = s.readSint16LE(); v != -1; v = s.readSint16LE()) {
|
||||
ExtraCell ec;
|
||||
ec._vid._fileNum = v;
|
||||
ec._vid._subfile = s.readSint16LE();
|
||||
ec._vidSound.load(s);
|
||||
|
||||
_extraCells.push_back(ec);
|
||||
}
|
||||
}
|
||||
|
||||
CharEntry::CharEntry() : _charFlag(0), _estabIndex(0), _startColor(0), _numColors(0) {
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
CharManager::CharManager(AccessEngine *vm) : Manager(vm) {
|
||||
// Setup character list
|
||||
for (const auto &charEntry: _vm->_res->CHARTBL) {
|
||||
if (charEntry.size() == 0)
|
||||
_charTable.push_back(CharEntry());
|
||||
else
|
||||
_charTable.push_back(CharEntry(charEntry.data(), _vm));
|
||||
}
|
||||
|
||||
_charFlag = 0;
|
||||
}
|
||||
|
||||
void CharManager::loadChar(int charId) {
|
||||
const CharEntry &ce = _charTable[charId];
|
||||
_charFlag = ce._charFlag;
|
||||
|
||||
// Amazon calls "establish" before loading the screen, but MM does it after.
|
||||
_vm->_establishFlag = false;
|
||||
if (_vm->getGameID() == kGameAmazon && ce._estabIndex != -1) {
|
||||
_vm->_establishFlag = true;
|
||||
if (!_vm->_establishTable[ce._estabIndex]) {
|
||||
_vm->_establishTable[ce._estabIndex] = true;
|
||||
_vm->establish(0, ce._estabIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (_charFlag != 0 && _charFlag != 3) {
|
||||
if (!_vm->_establishFlag)
|
||||
_vm->_screen->fadeOut();
|
||||
|
||||
_vm->_files->loadScreen(ce._screenFile._fileNum, ce._screenFile._subfile);
|
||||
_vm->_screen->setIconPalette();
|
||||
_vm->_screen->fadeIn();
|
||||
}
|
||||
|
||||
_vm->_buffer1.blitFrom(*_vm->_screen);
|
||||
_vm->_buffer2.blitFrom(*_vm->_screen);
|
||||
_vm->_screen->setDisplayScan();
|
||||
|
||||
if (_vm->getGameID() == kGameMartianMemorandum && ce._estabIndex != -1) {
|
||||
_vm->_establishFlag = true;
|
||||
if (!_vm->_establishTable[ce._estabIndex]) {
|
||||
_vm->_establishTable[ce._estabIndex] = true;
|
||||
_vm->establish(0, ce._estabIndex);
|
||||
_vm->_screen->blitFrom(_vm->_buffer1);
|
||||
}
|
||||
}
|
||||
|
||||
if (_charFlag != 2 && _charFlag != 3) {
|
||||
charMenu();
|
||||
}
|
||||
|
||||
_vm->_screen->_startColor = ce._startColor;
|
||||
_vm->_screen->_numColors = ce._numColors;
|
||||
if (ce._paletteFile._fileNum != -1) {
|
||||
int srcOffset = (_vm->getGameID() == kGameMartianMemorandum ? ce._startColor * 3 : 0);
|
||||
_vm->_screen->loadPalette(ce._paletteFile._fileNum, ce._paletteFile._subfile, srcOffset);
|
||||
}
|
||||
_vm->_screen->setIconPalette();
|
||||
_vm->_screen->setPalette();
|
||||
|
||||
_vm->loadCells(ce._cells);
|
||||
if (ce._animFile._fileNum != -1) {
|
||||
Resource *data = _vm->_files->loadFile(ce._animFile);
|
||||
_vm->_animation->loadAnimations(data);
|
||||
delete data;
|
||||
}
|
||||
|
||||
// Load script data
|
||||
_vm->_scripts->freeScriptData();
|
||||
if (ce._scriptFile._fileNum != -1) {
|
||||
Resource *data = _vm->_files->loadFile(ce._scriptFile);
|
||||
_vm->_scripts->setScript(data);
|
||||
}
|
||||
|
||||
// Load extra cells
|
||||
_vm->_extraCells.clear();
|
||||
for (const auto &extraCell : ce._extraCells)
|
||||
_vm->_extraCells.push_back(extraCell);
|
||||
}
|
||||
|
||||
void CharManager::charMenu() {
|
||||
const SpriteResource *icons = _vm->getIcons();
|
||||
|
||||
Screen &screen = *_vm->_screen;
|
||||
screen.saveScreen();
|
||||
screen.setDisplayScan();
|
||||
|
||||
if (_vm->getGameID() == kGameMartianMemorandum) {
|
||||
screen.plotImage(icons, 17, Common::Point(0, 184));
|
||||
screen.plotImage(icons, 18, Common::Point(193, 184));
|
||||
} else if (_vm->getGameID() == kGameAmazon) {
|
||||
screen.plotImage(icons, 17, Common::Point(0, 176));
|
||||
screen.plotImage(icons, 18, Common::Point(155, 176));
|
||||
} else
|
||||
error("Game not supported");
|
||||
|
||||
// Make a backup copy of the screen including the character buttons,
|
||||
// for restoring when erasing conversation boxes
|
||||
screen.copyTo(&_vm->_buffer1);
|
||||
|
||||
screen.restoreScreen();
|
||||
}
|
||||
|
||||
} // End of namespace Access
|
||||
63
engines/access/char.h
Normal file
63
engines/access/char.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* 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 ACCESS_CHAR_H
|
||||
#define ACCESS_CHAR_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/array.h"
|
||||
#include "access/data.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
class CharEntry {
|
||||
public:
|
||||
int _charFlag;
|
||||
int _estabIndex;
|
||||
FileIdent _screenFile;
|
||||
FileIdent _paletteFile;
|
||||
int _startColor, _numColors;
|
||||
Common::Array<CellIdent> _cells;
|
||||
FileIdent _animFile;
|
||||
FileIdent _scriptFile;
|
||||
Common::Array<ExtraCell> _extraCells;
|
||||
public:
|
||||
CharEntry(const byte *data, AccessEngine *vm);
|
||||
|
||||
CharEntry();
|
||||
};
|
||||
|
||||
class CharManager : public Manager {
|
||||
private:
|
||||
void charMenu();
|
||||
public:
|
||||
Common::Array<CharEntry> _charTable;
|
||||
int _charFlag;
|
||||
|
||||
public:
|
||||
CharManager(AccessEngine *vm);
|
||||
|
||||
void loadChar(int charId);
|
||||
};
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_CHAR_H */
|
||||
3
engines/access/configure.engine
Normal file
3
engines/access/configure.engine
Normal 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 access "Access" yes "" "" "" "midi"
|
||||
5
engines/access/credits.pl
Normal file
5
engines/access/credits.pl
Normal file
@@ -0,0 +1,5 @@
|
||||
begin_section("Access");
|
||||
add_person("Arnaud Boutonné", "Strangerke", "");
|
||||
add_person("Paul Gilbert", "dreammaster", "");
|
||||
add_person("Matthew Duggan", "stauff", "");
|
||||
end_section();
|
||||
74
engines/access/data.cpp
Normal file
74
engines/access/data.cpp
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/algorithm.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/system.h"
|
||||
#include "access/data.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
TimerList::TimerList() : Common::Array<TimerEntry>() {
|
||||
_timersSavedFlag = false;
|
||||
}
|
||||
|
||||
void TimerList::saveTimers() {
|
||||
if (!_timersSavedFlag /* && !_flashbackFlag */) {
|
||||
_savedTimers = *this;
|
||||
_timersSavedFlag = true;
|
||||
}
|
||||
}
|
||||
|
||||
void TimerList::restoreTimers() {
|
||||
if (_timersSavedFlag /* && !_flashbackFlag */) {
|
||||
clear();
|
||||
*static_cast<Common::Array<TimerEntry> *>(this) = _savedTimers;
|
||||
_timersSavedFlag = false;
|
||||
}
|
||||
}
|
||||
|
||||
void TimerList::updateTimers() {
|
||||
for (uint i = 0; i < size(); ++i) {
|
||||
TimerEntry &te = (*this)[i];
|
||||
if (te._flag) {
|
||||
if (!--te._timer) {
|
||||
te._timer = te._initTm;
|
||||
te._flag = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TimerList::synchronize(Common::Serializer &s) {
|
||||
int count = size();
|
||||
s.syncAsUint16LE(count);
|
||||
|
||||
if (!s.isSaving())
|
||||
resize(count);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
s.syncAsUint32LE((*this)[i]._initTm);
|
||||
s.syncAsUint32LE((*this)[i]._timer);
|
||||
s.syncAsByte((*this)[i]._flag);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Access
|
||||
99
engines/access/data.h
Normal file
99
engines/access/data.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/* 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 ACCESS_DATA_H
|
||||
#define ACCESS_DATA_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/array.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/serializer.h"
|
||||
#include "common/types.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "access/files.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
class AccessEngine;
|
||||
|
||||
class Manager {
|
||||
protected:
|
||||
AccessEngine *_vm;
|
||||
public:
|
||||
Manager(AccessEngine *vm) : _vm(vm) {}
|
||||
};
|
||||
|
||||
struct TimerEntry {
|
||||
int _initTm;
|
||||
int _timer;
|
||||
byte _flag;
|
||||
|
||||
TimerEntry() : _flag(0), _initTm(0), _timer(0) { }
|
||||
};
|
||||
|
||||
class TimerList : public Common::Array<TimerEntry> {
|
||||
private:
|
||||
Common::Array<TimerEntry> _savedTimers;
|
||||
public:
|
||||
bool _timersSavedFlag;
|
||||
public:
|
||||
TimerList();
|
||||
|
||||
/**
|
||||
* Save a copy of all current timers
|
||||
*/
|
||||
void saveTimers();
|
||||
|
||||
/**
|
||||
* Resetore the set of previously saved timers
|
||||
*/
|
||||
void restoreTimers();
|
||||
|
||||
/**
|
||||
* Update the timer list
|
||||
*/
|
||||
void updateTimers();
|
||||
|
||||
/**
|
||||
* Synchronize savegame data
|
||||
*/
|
||||
void synchronize(Common::Serializer &s);
|
||||
};
|
||||
|
||||
class ExtraCell {
|
||||
public:
|
||||
FileIdent _vid;
|
||||
FileIdent _vidSound;
|
||||
};
|
||||
|
||||
struct DeathEntry {
|
||||
int _screenId;
|
||||
Common::String _msg;
|
||||
};
|
||||
|
||||
class DeathList : public Common::Array<DeathEntry> {
|
||||
public:
|
||||
Common::Array<CellIdent> _cells;
|
||||
};
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_DATA_H */
|
||||
410
engines/access/debugger.cpp
Normal file
410
engines/access/debugger.cpp
Normal file
@@ -0,0 +1,410 @@
|
||||
/* 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 "common/file.h"
|
||||
#include "access/access.h"
|
||||
#include "access/debugger.h"
|
||||
#include "access/amazon/amazon_game.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
static int strToInt(const char *s) {
|
||||
if (!*s)
|
||||
// No string at all
|
||||
return 0;
|
||||
else if (toupper(s[strlen(s) - 1]) != 'H')
|
||||
// Standard decimal string
|
||||
return atoi(s);
|
||||
|
||||
// Hexadecimal string
|
||||
uint tmp = 0;
|
||||
int read = sscanf(s, "%xh", &tmp);
|
||||
if (read < 1)
|
||||
error("strToInt failed on string \"%s\"", s);
|
||||
return (int)tmp;
|
||||
}
|
||||
|
||||
Debugger *Debugger::init(AccessEngine *vm) {
|
||||
switch (vm->getGameID()) {
|
||||
case kGameAmazon:
|
||||
return new Amazon::AmazonDebugger(vm);
|
||||
default:
|
||||
return new Debugger(vm);
|
||||
}
|
||||
}
|
||||
|
||||
void Debugger::postEnter() {
|
||||
if (!_playMovieFile.empty()) {
|
||||
_vm->playMovie(_playMovieFile, Common::Point(0, 0));
|
||||
|
||||
_playMovieFile.clear();
|
||||
}
|
||||
|
||||
GUI::Debugger::postEnter();
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
Debugger::Debugger(AccessEngine *vm) : GUI::Debugger(), _vm(vm) {
|
||||
registerCmd("continue", WRAP_METHOD(Debugger, cmdExit));
|
||||
registerCmd("scene", WRAP_METHOD(Debugger, Cmd_LoadScene));
|
||||
registerCmd("cheat", WRAP_METHOD(Debugger, Cmd_Cheat));
|
||||
registerCmd("playmovie", WRAP_METHOD(Debugger, Cmd_PlayMovie));
|
||||
registerCmd("dumpscript", WRAP_METHOD(Debugger, Cmd_DumpScript));
|
||||
registerCmd("timers", WRAP_METHOD(Debugger, Cmd_Timers));
|
||||
registerCmd("flag", WRAP_METHOD(Debugger, Cmd_Flag));
|
||||
registerCmd("travel", WRAP_METHOD(Debugger, Cmd_Travel));
|
||||
registerCmd("ask", WRAP_METHOD(Debugger, Cmd_Ask));
|
||||
registerCmd("inventory", WRAP_METHOD(Debugger, Cmd_Inventory));
|
||||
registerCmd("everything", WRAP_METHOD(Debugger, Cmd_Everything));
|
||||
}
|
||||
|
||||
Debugger::~Debugger() {
|
||||
}
|
||||
|
||||
bool Debugger::Cmd_LoadScene(int argc, const char **argv) {
|
||||
switch (argc) {
|
||||
case 1:
|
||||
debugPrintf("Current scene is: %d\n\n", _vm->_player->_roomNumber);
|
||||
|
||||
for (uint i = 0; i < _vm->_res->ROOMTBL.size(); i++)
|
||||
if (!_vm->_res->ROOMTBL[i]._desc.empty())
|
||||
debugPrintf("%d - %s\n", i, _vm->_res->ROOMTBL[i]._desc.c_str());
|
||||
return true;
|
||||
|
||||
case 2: {
|
||||
int newRoom = strToInt(argv[1]);
|
||||
if (newRoom < 0 || newRoom >= (int)_vm->_res->ROOMTBL.size()) {
|
||||
debugPrintf("Invalid Room Number\n");
|
||||
return true;
|
||||
}
|
||||
if (_vm->_res->ROOMTBL[newRoom]._desc.empty()) {
|
||||
debugPrintf("Unused Room Number\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
_vm->_player->_roomNumber = newRoom;
|
||||
|
||||
_vm->_room->_function = FN_CLEAR1;
|
||||
_vm->freeChar();
|
||||
_vm->_converseMode = 0;
|
||||
_vm->_scripts->_endFlag = true;
|
||||
_vm->_scripts->_returnCode = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
debugPrintf("Current scene is: %d\n", _vm->_player->_roomNumber);
|
||||
debugPrintf("Usage: %s <scene number>\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Debugger::Cmd_Cheat(int argc, const char **argv) {
|
||||
if (argc != 1) {
|
||||
debugPrintf("Usage: %s\n", argv[0]);
|
||||
debugPrintf("Switches on/off the cheat mode. Cheat mode:\n");
|
||||
debugPrintf(" - [Amazon] Skips guard on boat\n");
|
||||
debugPrintf(" - [MM] Allows travel to \"can't get there from here\" locations\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
_vm->_cheatFl = !_vm->_cheatFl;
|
||||
debugPrintf("Cheat is now %s\n", _vm->_cheatFl ? "ON" : "OFF");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::Cmd_PlayMovie(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Format: playmovie <movie-file>\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// play gets postponed until debugger is closed
|
||||
Common::String filename = argv[1];
|
||||
_playMovieFile = filename;
|
||||
|
||||
return cmdExit(0, nullptr);
|
||||
}
|
||||
|
||||
bool Debugger::Cmd_DumpScript(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Usage: %s <path>\n", argv[0]);
|
||||
debugPrintf("Dumps the currently loaded script data to the given path\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *data = _vm->_scripts->_data;
|
||||
if (!data) {
|
||||
debugPrintf("No script loaded\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
const Common::Path outpath = Common::Path(argv[1]);
|
||||
|
||||
Common::DumpFile dumpFile;
|
||||
|
||||
dumpFile.open(outpath);
|
||||
if (!dumpFile.isOpen()) {
|
||||
debugPrintf("Couldn't open %s\n", argv[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
int64 oldpos = data->pos();
|
||||
data->seek(0);
|
||||
|
||||
dumpFile.writeStream(data);
|
||||
dumpFile.close();
|
||||
|
||||
data->seek(oldpos);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::Cmd_Flag(int argc, const char **argv) {
|
||||
if (argc != 2 && argc != 3) {
|
||||
debugPrintf("Usage: %s <flag number> [<flag value>]\n", argv[0]);
|
||||
debugPrintf("Prints or sets the value of the given flag\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (argc == 2) {
|
||||
int flagNum = strToInt(argv[1]);
|
||||
if (flagNum < 0 || flagNum >= 256) {
|
||||
debugPrintf("Invalid flag number\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
debugPrintf("Flag %d: %d\n", flagNum, _vm->_flags[flagNum]);
|
||||
return true;
|
||||
}
|
||||
|
||||
int num = strToInt(argv[1]);
|
||||
if (num < 0 || num >= ARRAYSIZE(_vm->_flags)) {
|
||||
debugPrintf("Invalid flag number\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
int val = strToInt(argv[2]);
|
||||
if (val < 0 || val >= 256) {
|
||||
debugPrintf("Invalid flag val, must be byte\n");
|
||||
return true;
|
||||
}
|
||||
_vm->_flags[num] = val;
|
||||
|
||||
debugPrintf("Flag %d set to %d\n", num, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::Cmd_Timers(int argc, const char **argv) {
|
||||
if (argc != 1) {
|
||||
debugPrintf("Usage: %s\n", argv[0]);
|
||||
debugPrintf("Prints the current timers\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
debugPrintf("Timers:\n");
|
||||
for (uint i = 0; i < _vm->_timers.size(); ++i) {
|
||||
const TimerEntry te = _vm->_timers[i];
|
||||
debugPrintf("%d: init: %d timer: %d flag: %d\n", i, te._initTm, te._timer, te._flag);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::Cmd_Travel(int argc, const char **argv) {
|
||||
if (argc != 1 && argc != 3) {
|
||||
debugPrintf("Usage: %s [<travel number> <travel value>]\n", argv[0]);
|
||||
debugPrintf("Dump the travel table, or set a travel table entry to the given value\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (argc == 1) {
|
||||
debugPrintf("Travel table:\n");
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_vm->_travel); ++i) {
|
||||
if (!Martian::TRAVDATA[i])
|
||||
break;
|
||||
debugPrintf("%2d: %d (%s)\n", i, _vm->_travel[i], Martian::TRAVDATA[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int num = strToInt(argv[1]);
|
||||
if (num < 0 || num >= ARRAYSIZE(_vm->_travel)) {
|
||||
debugPrintf("Invalid travel number\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
int val = strToInt(argv[2]);
|
||||
if (val < 0 || val >= 256) {
|
||||
debugPrintf("Invalid travel val, must be byte\n");
|
||||
return true;
|
||||
}
|
||||
_vm->_flags[num] = val;
|
||||
|
||||
debugPrintf("Travel %d set to %d\n", num, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::Cmd_Ask(int argc, const char **argv) {
|
||||
if (argc != 1 && argc != 3) {
|
||||
debugPrintf("Usage: %s [<ask number> <ask value>]\n", argv[0]);
|
||||
debugPrintf("Dump the ask table, or set an ask table entry to the given value\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (argc == 1) {
|
||||
debugPrintf("Ask table:\n");
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_vm->_ask); ++i) {
|
||||
if (!Martian::ASK_TBL[i])
|
||||
break;
|
||||
debugPrintf("%2d: %d (%s)\n", i, _vm->_ask[i], Martian::ASK_TBL[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int num = strToInt(argv[1]);
|
||||
if (num < 0 || num >= ARRAYSIZE(_vm->_ask)) {
|
||||
debugPrintf("Invalid ask number\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
int val = strToInt(argv[2]);
|
||||
if (val < 0 || val >= 256) {
|
||||
debugPrintf("Invalid ask val, must be byte\n");
|
||||
return true;
|
||||
}
|
||||
_vm->_flags[num] = val;
|
||||
|
||||
debugPrintf("Ask %d set to %d\n", num, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::Cmd_Inventory(int argc, const char **argv) {
|
||||
if (argc != 1 && argc != 3) {
|
||||
debugPrintf("Usage: %s [<inv number> <state value>]\n", argv[0]);
|
||||
debugPrintf("Dump the list of inventory items and their state, or set the state of an item\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char* STATE_NAMES[] = {
|
||||
"0 - Not Found",
|
||||
"1 - In Inv ",
|
||||
"2 - Used ",
|
||||
};
|
||||
|
||||
if (argc == 1) {
|
||||
debugPrintf("Inventory items:\n");
|
||||
|
||||
for (int i = 0; i < (int)_vm->_inventory->_inv.size(); ++i) {
|
||||
const InventoryEntry &entry = _vm->_inventory->_inv[i];
|
||||
debugPrintf("%2d: %s %s\n", i, STATE_NAMES[entry._value], entry._name.c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int num = strToInt(argv[1]);
|
||||
if (num < 0 || num >= (int)_vm->_inventory->_inv.size()) {
|
||||
debugPrintf("Invalid inv number\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
int val = strToInt(argv[2]);
|
||||
if (val < 0 || val > 2) {
|
||||
debugPrintf("Invalid inv state val, must be 0/1/2\n");
|
||||
return true;
|
||||
}
|
||||
_vm->_inventory->_inv[num]._value = val;
|
||||
|
||||
debugPrintf("Set item %d to %d\n", num, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::Cmd_Everything(int argc, const char **argv) {
|
||||
if (argc != 2 || strcmp(argv[1], "please") != 0) {
|
||||
debugPrintf("Usage: %s please\n", argv[0]);
|
||||
debugPrintf("Gives you all items, travel locations, and ask subjects.\n");
|
||||
debugPrintf("Cannot be undone and may break your game, so you have to confirm with 'please'.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
for (uint i = 0; i < _vm->_res->INVENTORY.size(); ++i)
|
||||
_vm->_inventory->_inv[i]._value = ITEM_IN_INVENTORY;
|
||||
|
||||
for (uint i = 0; i < ARRAYSIZE(_vm->_travel); ++i)
|
||||
_vm->_travel[i] = 1;
|
||||
|
||||
//
|
||||
// Turn off known-broken/cut locations that exist in the travel table
|
||||
// but you can't go there or going there directly will cause a crash.
|
||||
//
|
||||
const int INVALID_TRAVEL_LOCATIONS[] = {
|
||||
10, // RESTAURANT
|
||||
12, // LOVE SCENE
|
||||
};
|
||||
|
||||
for (uint i = 0; i < ARRAYSIZE(INVALID_TRAVEL_LOCATIONS); ++i)
|
||||
_vm->_travel[INVALID_TRAVEL_LOCATIONS[i]] = 0;
|
||||
|
||||
for (uint i = 0; i < ARRAYSIZE(_vm->_ask); ++i)
|
||||
_vm->_ask[i] = 1;
|
||||
|
||||
debugPrintf("You now have everything, can go anywhere, and can ask anything.\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
namespace Amazon {
|
||||
|
||||
AmazonDebugger::AmazonDebugger(AccessEngine *vm) : Debugger(vm) {
|
||||
registerCmd("chapter", WRAP_METHOD(AmazonDebugger, Cmd_StartChapter));
|
||||
}
|
||||
|
||||
bool AmazonDebugger::Cmd_StartChapter(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Usage: %s <chapter number>\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Build up a simple one line script to start the given chapter
|
||||
byte *chapterScript = (byte *)malloc(5);
|
||||
if (!chapterScript)
|
||||
error("malloc failed");
|
||||
chapterScript[0] = SCRIPT_START_BYTE;
|
||||
chapterScript[1] = ROOM_SCRIPT % 256;
|
||||
chapterScript[2] = ROOM_SCRIPT / 256;
|
||||
chapterScript[3] = 0x80 + 75; // cmdChapter
|
||||
chapterScript[4] = strToInt(argv[1]); // chapter number
|
||||
_vm->_scripts->setScript(new Resource(chapterScript, 5), true);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Amazon
|
||||
|
||||
} // End of namespace Access
|
||||
72
engines/access/debugger.h
Normal file
72
engines/access/debugger.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/* 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 ACCESS_DEBUGGER_H
|
||||
#define ACCESS_DEBUGGER_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "gui/debugger.h"
|
||||
#include "access/amazon/amazon_resources.h"
|
||||
#include "access/martian/martian_resources.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
class AccessEngine;
|
||||
|
||||
class Debugger : public GUI::Debugger {
|
||||
protected:
|
||||
AccessEngine *_vm;
|
||||
Common::Path _playMovieFile;
|
||||
|
||||
bool Cmd_LoadScene(int argc, const char **argv);
|
||||
bool Cmd_Cheat(int argc, const char **argv);
|
||||
bool Cmd_PlayMovie(int argc, const char **argv);
|
||||
bool Cmd_DumpScript(int argc, const char **argv);
|
||||
bool Cmd_Timers(int argc, const char **argv);
|
||||
bool Cmd_Flag(int argc, const char **argv);
|
||||
bool Cmd_Travel(int argc, const char **argv);
|
||||
bool Cmd_Ask(int argc, const char **argv);
|
||||
bool Cmd_Inventory(int argc, const char **argv);
|
||||
bool Cmd_Everything(int argc, const char **argv);
|
||||
|
||||
public:
|
||||
static Debugger *init(AccessEngine *vm);
|
||||
void postEnter() override;
|
||||
public:
|
||||
Debugger(AccessEngine *vm);
|
||||
~Debugger() override;
|
||||
};
|
||||
|
||||
namespace Amazon {
|
||||
|
||||
class AmazonDebugger : public Debugger {
|
||||
protected:
|
||||
bool Cmd_StartChapter(int argc, const char **argv);
|
||||
public:
|
||||
AmazonDebugger(AccessEngine *vm);
|
||||
~AmazonDebugger() override {}
|
||||
};
|
||||
|
||||
} // End of namespace Amazon
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_DEBUGGER_H */
|
||||
149
engines/access/decompress.cpp
Normal file
149
engines/access/decompress.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
/* 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 "common/debug.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include "access/decompress.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
void LzwDecompressor::decompress(const byte *source, byte *dest) {
|
||||
|
||||
_source = source;
|
||||
|
||||
byte litByte = 0;
|
||||
uint16 oldCode = 0;
|
||||
uint16 copyLength, maxCodeValue, code, nextCode, lastCode;
|
||||
|
||||
byte *copyBuf = new byte[8192];
|
||||
|
||||
struct { uint16 code; byte value; } codeTable[8192];
|
||||
memset(codeTable, 0, sizeof(codeTable));
|
||||
|
||||
_codeLength = 9;
|
||||
nextCode = 258;
|
||||
maxCodeValue = 512;
|
||||
|
||||
copyLength = 0;
|
||||
_sourceBitsLeft = 8;
|
||||
|
||||
while (1) {
|
||||
|
||||
code = getCode();
|
||||
|
||||
if (code == 257)
|
||||
break;
|
||||
|
||||
if (code == 256) {
|
||||
_codeLength = 9;
|
||||
nextCode = 258;
|
||||
maxCodeValue = 512;
|
||||
lastCode = getCode();
|
||||
oldCode = lastCode;
|
||||
litByte = lastCode;
|
||||
*dest++ = litByte;
|
||||
} else {
|
||||
lastCode = code;
|
||||
if (code >= nextCode) {
|
||||
lastCode = oldCode;
|
||||
copyBuf[copyLength++] = litByte;
|
||||
}
|
||||
while (lastCode > 255) {
|
||||
copyBuf[copyLength++] = codeTable[lastCode].value;
|
||||
lastCode = codeTable[lastCode].code;
|
||||
}
|
||||
litByte = lastCode;
|
||||
copyBuf[copyLength++] = lastCode;
|
||||
while (copyLength > 0)
|
||||
*dest++ = copyBuf[--copyLength];
|
||||
codeTable[nextCode].value = lastCode;
|
||||
codeTable[nextCode].code = oldCode;
|
||||
nextCode++;
|
||||
oldCode = code;
|
||||
if (nextCode >= maxCodeValue && _codeLength <= 12) {
|
||||
_codeLength++;
|
||||
maxCodeValue <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
delete[] copyBuf;
|
||||
|
||||
}
|
||||
|
||||
uint16 LzwDecompressor::getCode() {
|
||||
const byte bitMasks[9] = {
|
||||
0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0x0FF
|
||||
};
|
||||
|
||||
byte resultBitsLeft = _codeLength;
|
||||
byte resultBitsPos = 0;
|
||||
uint16 result = 0;
|
||||
byte currentByte = *_source;
|
||||
byte currentBits = 0;
|
||||
|
||||
// Get bits of current byte
|
||||
while (resultBitsLeft) {
|
||||
if (resultBitsLeft < _sourceBitsLeft) {
|
||||
// we need less than we have left
|
||||
currentBits = (currentByte >> (8 - _sourceBitsLeft)) & bitMasks[resultBitsLeft];
|
||||
result |= (currentBits << resultBitsPos);
|
||||
_sourceBitsLeft -= resultBitsLeft;
|
||||
resultBitsLeft = 0;
|
||||
|
||||
} else {
|
||||
// we need as much as we have left or more
|
||||
resultBitsLeft -= _sourceBitsLeft;
|
||||
currentBits = currentByte >> (8 - _sourceBitsLeft);
|
||||
result |= (currentBits << resultBitsPos);
|
||||
resultBitsPos += _sourceBitsLeft;
|
||||
|
||||
// Go to next byte
|
||||
_source++;
|
||||
|
||||
_sourceBitsLeft = 8;
|
||||
if (resultBitsLeft) {
|
||||
currentByte = *_source;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32 decompressDBE(const byte *source, byte **dest) {
|
||||
|
||||
uint32 destSize = READ_LE_UINT32(source + 4);
|
||||
*dest = new byte[destSize];
|
||||
|
||||
debug(1, "decompressDBE() destSize = %d", destSize);
|
||||
|
||||
LzwDecompressor dec;
|
||||
dec.decompress(source + 16, *dest);
|
||||
|
||||
debug(1, "decompressDBE() ok");
|
||||
|
||||
return destSize;
|
||||
}
|
||||
|
||||
} // End of namespace Access
|
||||
43
engines/access/decompress.h
Normal file
43
engines/access/decompress.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* 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 ACCESS_DECOMPRESS_H
|
||||
#define ACCESS_DECOMPRESS_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
class LzwDecompressor {
|
||||
public:
|
||||
void decompress(const byte *source, byte *dest);
|
||||
private:
|
||||
const byte *_source;
|
||||
byte _sourceBitsLeft;
|
||||
byte _codeLength;
|
||||
uint16 getCode();
|
||||
};
|
||||
|
||||
uint32 decompressDBE(const byte *source, byte **dest);
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif
|
||||
67
engines/access/detection.cpp
Normal file
67
engines/access/detection.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/* 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 "base/plugins.h"
|
||||
#include "engines/advancedDetector.h"
|
||||
#include "access/detection.h"
|
||||
#include "access/access.h"
|
||||
|
||||
static const PlainGameDescriptor AccessGames[] = {
|
||||
{"amazon", "Amazon: Guardians of Eden"},
|
||||
{"martian", "Martian Memorandum"},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
static const DebugChannelDef debugFlagList[] = {
|
||||
{Access::kDebugPath, "path", "Pathfinding debug level"},
|
||||
{Access::kDebugScripts, "scripts", "Game scripts"},
|
||||
{Access::kDebugGraphics, "graphics", "Graphics handling"},
|
||||
{Access::kDebugSound, "sound", "Sound and Music handling"},
|
||||
DEBUG_CHANNEL_END
|
||||
};
|
||||
|
||||
#include "access/detection_tables.h"
|
||||
|
||||
class AccessMetaEngineDetection : public AdvancedMetaEngineDetection<Access::AccessGameDescription> {
|
||||
public:
|
||||
AccessMetaEngineDetection() : AdvancedMetaEngineDetection(Access::gameDescriptions, AccessGames) {
|
||||
_maxScanDepth = 3;
|
||||
}
|
||||
|
||||
const char *getName() const override {
|
||||
return "access";
|
||||
}
|
||||
|
||||
const char *getEngineName() const override {
|
||||
return "Access";
|
||||
}
|
||||
|
||||
const char *getOriginalCopyright() const override {
|
||||
return "Access Engine (C) 1989-1994 Access Software";
|
||||
}
|
||||
|
||||
const DebugChannelDef *getDebugChannels() const override {
|
||||
return debugFlagList;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
REGISTER_PLUGIN_STATIC(ACCESS_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, AccessMetaEngineDetection);
|
||||
46
engines/access/detection.h
Normal file
46
engines/access/detection.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* 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 ACCESS_DETECTION_H
|
||||
#define ACCESS_DETECTION_H
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
enum AccessGameType {
|
||||
kGameAmazon = 1,
|
||||
kGameMartianMemorandum = 2,
|
||||
kGameNoctropolis = 3
|
||||
};
|
||||
|
||||
struct AccessGameDescription {
|
||||
AD_GAME_DESCRIPTION_HELPERS(desc);
|
||||
|
||||
ADGameDescription desc;
|
||||
|
||||
int gameID;
|
||||
uint32 features;
|
||||
};
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif // ACCESS_DETECTION_H
|
||||
136
engines/access/detection_tables.h
Normal file
136
engines/access/detection_tables.h
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Access {
|
||||
|
||||
static const AccessGameDescription gameDescriptions[] = {
|
||||
{
|
||||
// Amazon Guardians of Eden - Floppy English
|
||||
// 3.5" and 5.25" floppies provided by Strangerke had the same md5
|
||||
// Except the sound file. The executable is also identical
|
||||
{
|
||||
"amazon",
|
||||
0,
|
||||
AD_ENTRY1s("c00.ap", "dcabf69d5a0d911168cb73511ebaead0", 331481),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NONE)
|
||||
},
|
||||
kGameAmazon,
|
||||
0
|
||||
},
|
||||
|
||||
{
|
||||
// Amazon Guardians of Eden - Spanish
|
||||
// Provided by dianiu in bug report #6958
|
||||
{
|
||||
"amazon",
|
||||
0,
|
||||
AD_ENTRY1s("c00.ap", "aeb429ff015596144c0df06886c84825", 303753),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NONE)
|
||||
},
|
||||
kGameAmazon,
|
||||
0
|
||||
},
|
||||
|
||||
// Amazon Guardians of Eden - Demo English
|
||||
{
|
||||
{
|
||||
"amazon",
|
||||
"Demo",
|
||||
AD_ENTRY1s("c25.ap", "5baba0c052d22157499bfa05cb1ed5b7", 65458),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NONE)
|
||||
},
|
||||
kGameAmazon,
|
||||
0
|
||||
},
|
||||
|
||||
{
|
||||
// Amazon: Guardians of Eden - CD English
|
||||
{
|
||||
"amazon",
|
||||
"CD",
|
||||
AD_ENTRY1s("checksum.crc", "bef85478132fec74cb5d9067f3a37d24", 8),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_CD,
|
||||
GUIO1(GUIO_NONE)
|
||||
},
|
||||
kGameAmazon,
|
||||
0
|
||||
},
|
||||
|
||||
{
|
||||
// Martian Memorandum
|
||||
{
|
||||
"martian",
|
||||
nullptr,
|
||||
AD_ENTRY1s("r01.ap", "c081daca9b0cfd710157cf946e343df6", 39352),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NONE)
|
||||
},
|
||||
kGameMartianMemorandum,
|
||||
0
|
||||
},
|
||||
|
||||
{
|
||||
// Martian Memorandum from "Lasersoft Top Tracks Vol 1" CD
|
||||
{
|
||||
"martian",
|
||||
nullptr,
|
||||
AD_ENTRY1s("r01.ap", "1052fc0e5bd979ae2e18b03ed58fda8e", 39349),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NONE)
|
||||
},
|
||||
kGameMartianMemorandum,
|
||||
0
|
||||
},
|
||||
|
||||
{
|
||||
// Martian Memorandum
|
||||
{
|
||||
"martian",
|
||||
"Demo",
|
||||
AD_ENTRY1s("r01.rm", "c2facf9c43047211289044ee39a2322a", 2313),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO | ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NONE)
|
||||
},
|
||||
kGameMartianMemorandum,
|
||||
0
|
||||
},
|
||||
|
||||
{ AD_TABLE_END_MARKER, 0, 0 }
|
||||
};
|
||||
|
||||
} // End of namespace Access
|
||||
384
engines/access/events.cpp
Normal file
384
engines/access/events.cpp
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "graphics/cursorman.h"
|
||||
#include "common/events.h"
|
||||
#include "common/endian.h"
|
||||
#include "engines/util.h"
|
||||
#include "access/access.h"
|
||||
#include "access/events.h"
|
||||
#include "access/player.h"
|
||||
#include "access/amazon/amazon_resources.h"
|
||||
|
||||
#define CURSOR_WIDTH 16
|
||||
#define CURSOR_HEIGHT 16
|
||||
|
||||
namespace Access {
|
||||
|
||||
EventsManager::EventsManager(AccessEngine *vm) : _vm(vm) {
|
||||
_cursorId = CURSOR_NONE;
|
||||
_normalMouse = CURSOR_CROSSHAIRS;
|
||||
_frameCounter = 10;
|
||||
_priorFrameTime = 0;
|
||||
_leftButton = _rightButton = false;
|
||||
_middleButton = false;
|
||||
_wheelUp = _wheelDown = false;
|
||||
_mouseCol = _mouseRow = 0;
|
||||
_cursorExitFlag = false;
|
||||
_vbCount = 0;
|
||||
_keyCode = Common::KEYCODE_INVALID;
|
||||
_priorTimerTime = 0;
|
||||
_action = kActionNone;
|
||||
}
|
||||
|
||||
EventsManager::~EventsManager() {
|
||||
_invCursor.free();
|
||||
}
|
||||
|
||||
void EventsManager::forceSetCursor(CursorType cursorId) {
|
||||
setNormalCursor(cursorId);
|
||||
setCursor(cursorId);
|
||||
}
|
||||
|
||||
void EventsManager::setNormalCursor(CursorType cursorId) {
|
||||
_normalMouse = cursorId;
|
||||
}
|
||||
|
||||
void EventsManager::setCursor(CursorType cursorId) {
|
||||
if (cursorId == _cursorId)
|
||||
return;
|
||||
_cursorId = cursorId;
|
||||
|
||||
if (cursorId == CURSOR_INVENTORY) {
|
||||
// Set the cursor
|
||||
CursorMan.replaceCursor(_invCursor, _invCursor.w / 2, _invCursor.h / 2, 0);
|
||||
} else {
|
||||
// Get a pointer to the mouse data to use, and get the cursor hotspot
|
||||
const byte *srcP = _vm->_res->getCursor(cursorId);
|
||||
int hotspotX = (int16)READ_LE_UINT16(srcP);
|
||||
int hotspotY = (int16)READ_LE_UINT16(srcP + 2);
|
||||
srcP += 4;
|
||||
|
||||
// Create a surface to build up the cursor on
|
||||
Graphics::Surface cursorSurface;
|
||||
cursorSurface.create(CURSOR_WIDTH, CURSOR_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
|
||||
byte *destP = (byte *)cursorSurface.getPixels();
|
||||
Common::fill(destP, destP + CURSOR_WIDTH * CURSOR_HEIGHT, 0);
|
||||
|
||||
// Loop to build up the cursor
|
||||
for (int y = 0; y < CURSOR_HEIGHT; ++y) {
|
||||
destP = (byte *)cursorSurface.getBasePtr(0, y);
|
||||
int width = CURSOR_WIDTH;
|
||||
int skip = *srcP++;
|
||||
int plot = *srcP++;
|
||||
if (skip >= width)
|
||||
break;
|
||||
|
||||
// Skip over pixels
|
||||
destP += skip;
|
||||
width -= skip;
|
||||
|
||||
// Write out the pixels to plot
|
||||
while (plot > 0 && width > 0) {
|
||||
*destP++ = *srcP++;
|
||||
--plot;
|
||||
--width;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the cursor
|
||||
CursorMan.replaceCursor(cursorSurface, hotspotX, hotspotY, 0);
|
||||
|
||||
// Free the cursor surface
|
||||
cursorSurface.free();
|
||||
}
|
||||
}
|
||||
|
||||
void EventsManager::setCursorData(Graphics::ManagedSurface *src, const Common::Rect &r) {
|
||||
_invCursor.create(r.width(), r.height(), Graphics::PixelFormat::createFormatCLUT8());
|
||||
_invCursor.copyRectToSurface(*src, 0, 0, r);
|
||||
}
|
||||
|
||||
void EventsManager::showCursor() {
|
||||
CursorMan.showMouse(true);
|
||||
}
|
||||
|
||||
void EventsManager::hideCursor() {
|
||||
CursorMan.showMouse(false);
|
||||
}
|
||||
|
||||
bool EventsManager::isCursorVisible() {
|
||||
return CursorMan.isVisible();
|
||||
}
|
||||
|
||||
void EventsManager::delayUntilNextFrame() {
|
||||
while (!checkForNextFrameCounter())
|
||||
delay();
|
||||
nextFrame();
|
||||
}
|
||||
|
||||
void EventsManager::pollEvents(bool skipTimers) {
|
||||
if (checkForNextFrameCounter()) {
|
||||
nextFrame();
|
||||
}
|
||||
|
||||
if (checkForNextTimerUpdate() && !skipTimers)
|
||||
nextTimer();
|
||||
|
||||
_vm->_sound->checkSoundQueue();
|
||||
|
||||
_wheelUp = _wheelDown = false;
|
||||
|
||||
Common::Event event;
|
||||
while (g_system->getEventManager()->pollEvent(event)) {
|
||||
switch (event.type) {
|
||||
case Common::EVENT_QUIT:
|
||||
case Common::EVENT_RETURN_TO_LAUNCHER:
|
||||
return;
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
|
||||
actionControl(event.customType, true);
|
||||
return;
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
|
||||
actionControl(event.customType, false);
|
||||
return;
|
||||
case Common::EVENT_KEYDOWN:
|
||||
// Check for debugger
|
||||
keyControl(event.kbd.keycode, true);
|
||||
return;
|
||||
case Common::EVENT_KEYUP:
|
||||
keyControl(event.kbd.keycode, false);
|
||||
return;
|
||||
case Common::EVENT_MOUSEMOVE:
|
||||
_mousePos = event.mouse;
|
||||
_mouseCol = _mousePos.x / 8;
|
||||
_mouseRow = _mousePos.y / 8;
|
||||
break;
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
_leftButton = true;
|
||||
return;
|
||||
case Common::EVENT_LBUTTONUP:
|
||||
_leftButton = false;
|
||||
return;
|
||||
case Common::EVENT_RBUTTONDOWN:
|
||||
_rightButton = true;
|
||||
return;
|
||||
case Common::EVENT_RBUTTONUP:
|
||||
_rightButton = false;
|
||||
return;
|
||||
case Common::EVENT_MBUTTONDOWN:
|
||||
_middleButton = true;
|
||||
return;
|
||||
case Common::EVENT_MBUTTONUP:
|
||||
_middleButton = false;
|
||||
return;
|
||||
case Common::EVENT_WHEELUP:
|
||||
_wheelUp = true;
|
||||
return;
|
||||
case Common::EVENT_WHEELDOWN:
|
||||
_wheelDown = true;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EventsManager::keyControl(Common::KeyCode keycode, bool isKeyDown) {
|
||||
Player &player = *_vm->_player;
|
||||
|
||||
if (!isKeyDown) {
|
||||
if (player._move != NONE) {
|
||||
_keyCode = Common::KEYCODE_INVALID;
|
||||
player._move = NONE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_keyCode = keycode;
|
||||
}
|
||||
|
||||
void EventsManager::actionControl(Common::CustomEventType action, bool isKeyDown) {
|
||||
Player &player = *_vm->_player;
|
||||
|
||||
if (!isKeyDown) {
|
||||
if (player._move != NONE) {
|
||||
_action = kActionNone;
|
||||
player._move = NONE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_action = action;
|
||||
|
||||
switch (action) {
|
||||
case kActionMoveUp:
|
||||
player._move = UP;
|
||||
break;
|
||||
case kActionMoveDown:
|
||||
player._move = DOWN;
|
||||
break;
|
||||
case kActionMoveLeft:
|
||||
player._move = LEFT;
|
||||
break;
|
||||
case kActionMoveRight:
|
||||
player._move = RIGHT;
|
||||
break;
|
||||
case kActionMoveUpLeft:
|
||||
player._move = UPLEFT;
|
||||
break;
|
||||
case kActionMoveUpRight:
|
||||
player._move = UPRIGHT;
|
||||
break;
|
||||
case kActionMoveDownLeft:
|
||||
player._move = DOWNLEFT;
|
||||
break;
|
||||
case kActionMoveDownRight:
|
||||
player._move = DOWNRIGHT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void EventsManager::pollEventsAndWait() {
|
||||
pollEvents();
|
||||
delay();
|
||||
}
|
||||
|
||||
bool EventsManager::checkForNextFrameCounter() {
|
||||
// Check for next game frame
|
||||
uint32 milli = g_system->getMillis();
|
||||
if ((milli - _priorFrameTime) >= GAME_FRAME_TIME) {
|
||||
--_vbCount;
|
||||
++_frameCounter;
|
||||
_priorFrameTime = milli;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EventsManager::checkForNextTimerUpdate() {
|
||||
// Check for next timer update
|
||||
uint32 milli = g_system->getMillis();
|
||||
if ((milli - _priorTimerTime) >= GAME_TIMER_TIME) {
|
||||
_priorTimerTime = milli;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void EventsManager::nextFrame() {
|
||||
_vm->_screen->update();
|
||||
}
|
||||
|
||||
void EventsManager::nextTimer() {
|
||||
_vm->_animation->updateTimers();
|
||||
_vm->_timers.updateTimers();
|
||||
}
|
||||
|
||||
void EventsManager::delay(int time) {
|
||||
g_system->delayMillis(time);
|
||||
}
|
||||
|
||||
void EventsManager::zeroKeysActions() {
|
||||
_keyCode = Common::KEYCODE_INVALID;
|
||||
_action = kActionNone;
|
||||
}
|
||||
|
||||
bool EventsManager::getAction(Common::CustomEventType &action) {
|
||||
if (_action == kActionNone) {
|
||||
return false;
|
||||
} else {
|
||||
action = _action;
|
||||
_action = kActionNone;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool EventsManager::isKeyActionPending() const {
|
||||
return (_keyCode != Common::KEYCODE_INVALID || _action != kActionNone);
|
||||
}
|
||||
|
||||
void EventsManager::debounceLeft() {
|
||||
while (_leftButton && !_vm->shouldQuit()) {
|
||||
pollEventsAndWait();
|
||||
}
|
||||
}
|
||||
|
||||
void EventsManager::clearEvents() {
|
||||
_leftButton = _rightButton = false;
|
||||
zeroKeysActions();
|
||||
}
|
||||
|
||||
void EventsManager::waitKeyActionMouse() {
|
||||
while (!_vm->shouldQuit() && !isKeyActionMousePressed()) {
|
||||
pollEvents(true);
|
||||
delay();
|
||||
}
|
||||
}
|
||||
|
||||
Common::Point EventsManager::calcRawMouse() {
|
||||
Common::Point pt;
|
||||
Screen &screen = *_vm->_screen;
|
||||
pt.x = _mousePos.x - screen._windowXAdd +
|
||||
(_vm->_scrollCol * TILE_WIDTH) + _vm->_scrollX;
|
||||
pt.y = _mousePos.y - screen._screenYOff - screen._windowYAdd +
|
||||
(_vm->_scrollRow * TILE_HEIGHT) + _vm->_scrollY;
|
||||
|
||||
return pt;
|
||||
}
|
||||
|
||||
int EventsManager::checkMouseBox1(const Common::Array<Common::Rect> &rects) {
|
||||
for (uint16 i = 0; i < rects.size(); ++i) {
|
||||
if (rects[i].left == -1)
|
||||
return -1;
|
||||
|
||||
if ((_mousePos.x > rects[i].left) && (_mousePos.x < rects[i].right)
|
||||
&& (_mousePos.y > rects[i].top) && (_mousePos.y < rects[i].bottom))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool EventsManager::isKeyActionMousePressed() {
|
||||
bool result = _leftButton || _rightButton || isKeyActionPending();
|
||||
debounceLeft();
|
||||
zeroKeysActions();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void EventsManager::centerMousePos() {
|
||||
_mousePos = Common::Point(160, 100);
|
||||
}
|
||||
|
||||
void EventsManager::restrictMouse() {
|
||||
// No implementation in ScummVM
|
||||
}
|
||||
|
||||
} // End of namespace Access
|
||||
164
engines/access/events.h
Normal file
164
engines/access/events.h
Normal file
@@ -0,0 +1,164 @@
|
||||
/* 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 ACCESS_EVENTS_H
|
||||
#define ACCESS_EVENTS_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/events.h"
|
||||
#include "common/stack.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
enum CursorType {
|
||||
CURSOR_NONE = -1,
|
||||
CURSOR_ARROW = 0, CURSOR_CROSSHAIRS, CURSOR_2, CURSOR_3, CURSOR_LOOK,
|
||||
CURSOR_USE, CURSOR_TAKE, CURSOR_CLIMB, CURSOR_TALK, CURSOR_HELP,
|
||||
CURSOR_INVENTORY = 99
|
||||
};
|
||||
|
||||
#define GAME_FRAME_RATE 100
|
||||
#define GAME_FRAME_TIME (1000 / GAME_FRAME_RATE)
|
||||
#define GAME_TIMER_TIME 15
|
||||
|
||||
class AccessEngine;
|
||||
|
||||
class EventsManager {
|
||||
private:
|
||||
AccessEngine *_vm;
|
||||
uint32 _frameCounter;
|
||||
uint32 _priorFrameTime;
|
||||
uint32 _priorTimerTime;
|
||||
Common::KeyCode _keyCode;
|
||||
Common::CustomEventType _action;
|
||||
|
||||
Graphics::Surface _invCursor;
|
||||
bool checkForNextFrameCounter();
|
||||
bool checkForNextTimerUpdate();
|
||||
void nextFrame();
|
||||
void nextTimer();
|
||||
void keyControl(Common::KeyCode keycode, bool isKeyDown);
|
||||
void actionControl(Common::CustomEventType action, bool isKeyDown);
|
||||
public:
|
||||
CursorType _cursorId;
|
||||
CursorType _normalMouse;
|
||||
bool _leftButton, _rightButton;
|
||||
bool _middleButton;
|
||||
bool _wheelUp, _wheelDown;
|
||||
Common::Point _mousePos;
|
||||
int _mouseCol, _mouseRow;
|
||||
bool _cursorExitFlag;
|
||||
int _vbCount;
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
EventsManager(AccessEngine *vm);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~EventsManager();
|
||||
|
||||
/**
|
||||
* Return frame counter
|
||||
*/
|
||||
uint32 getFrameCounter() const { return _frameCounter; }
|
||||
|
||||
/**
|
||||
* Sets the cursor and reset the normal cursor
|
||||
*/
|
||||
void forceSetCursor(CursorType cursorId);
|
||||
|
||||
/**
|
||||
* Sets the normal cursor
|
||||
*/
|
||||
void setNormalCursor(CursorType cursorId);
|
||||
|
||||
/**
|
||||
* Sets the cursor
|
||||
*/
|
||||
void setCursor(CursorType cursorId);
|
||||
|
||||
/**
|
||||
* Set the image for the inventory cursor
|
||||
*/
|
||||
void setCursorData(Graphics::ManagedSurface *src, const Common::Rect &r);
|
||||
|
||||
/**
|
||||
* Return the current cursor Id
|
||||
*/
|
||||
CursorType getCursor() const { return _cursorId; }
|
||||
|
||||
/**
|
||||
* Show the mouse cursor
|
||||
*/
|
||||
void showCursor();
|
||||
|
||||
/**
|
||||
* Hide the mouse cursor
|
||||
*/
|
||||
void hideCursor();
|
||||
|
||||
/**
|
||||
* Returns if the mouse cursor is visible
|
||||
*/
|
||||
bool isCursorVisible();
|
||||
|
||||
void pollEvents(bool skipTimers = false);
|
||||
|
||||
void pollEventsAndWait();
|
||||
|
||||
void zeroKeysActions();
|
||||
|
||||
bool getAction(Common::CustomEventType &action);
|
||||
|
||||
Common::CustomEventType peekAction() const { return _action; }
|
||||
|
||||
Common::KeyCode peekKeyCode() const { return _keyCode; }
|
||||
|
||||
bool isKeyActionPending() const;
|
||||
|
||||
void delay(int time = 5);
|
||||
|
||||
void delayUntilNextFrame();
|
||||
|
||||
void debounceLeft();
|
||||
|
||||
void clearEvents();
|
||||
|
||||
void waitKeyActionMouse();
|
||||
|
||||
const Common::Point &getMousePos() const { return _mousePos; }
|
||||
|
||||
Common::Point calcRawMouse();
|
||||
|
||||
int checkMouseBox1(const Common::Array<Common::Rect> &rects);
|
||||
|
||||
bool isKeyActionMousePressed();
|
||||
|
||||
void centerMousePos();
|
||||
void restrictMouse();
|
||||
};
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_EVENTS_H */
|
||||
228
engines/access/files.cpp
Normal file
228
engines/access/files.cpp
Normal file
@@ -0,0 +1,228 @@
|
||||
/* 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 "common/substream.h"
|
||||
#include "access/files.h"
|
||||
#include "access/amazon/amazon_resources.h"
|
||||
#include "access/martian/martian_resources.h"
|
||||
#include "access/access.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
FileIdent::FileIdent() {
|
||||
_fileNum = -1;
|
||||
_subfile = 0;
|
||||
}
|
||||
|
||||
void FileIdent::load(Common::SeekableReadStream &s) {
|
||||
_fileNum = s.readSint16LE();
|
||||
_subfile = s.readUint16LE();
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
CellIdent:: CellIdent() {
|
||||
_cell = 0;
|
||||
}
|
||||
|
||||
CellIdent::CellIdent(int cell, int fileNum, int subfile) {
|
||||
_cell = cell;
|
||||
_fileNum = fileNum;
|
||||
_subfile = subfile;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
Resource::Resource() {
|
||||
_stream = nullptr;
|
||||
_size = 0;
|
||||
_data = nullptr;
|
||||
}
|
||||
|
||||
Resource::~Resource() {
|
||||
delete[] _data;
|
||||
delete _stream;
|
||||
}
|
||||
|
||||
Resource::Resource(byte *p, int size) {
|
||||
_data = p;
|
||||
_size = size;
|
||||
_stream = new Common::MemoryReadStream(p, size);
|
||||
}
|
||||
|
||||
byte *Resource::data() {
|
||||
if (_data == nullptr) {
|
||||
_data = new byte[_size];
|
||||
int pos = _stream->pos();
|
||||
_stream->seek(0);
|
||||
_stream->read(_data, _size);
|
||||
_stream->seek(pos);
|
||||
}
|
||||
|
||||
return _data;
|
||||
}
|
||||
|
||||
const char *Resource::getFileName() const {
|
||||
return _file.getName();
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
FileManager::FileManager(AccessEngine *vm) : _vm(vm) {
|
||||
_fileNumber = -1;
|
||||
_setPaletteFlag = true;
|
||||
}
|
||||
|
||||
FileManager::~FileManager() {
|
||||
}
|
||||
|
||||
Resource *FileManager::loadFile(int fileNum, int subfile) {
|
||||
Resource *res = new Resource();
|
||||
setAppended(res, fileNum);
|
||||
gotoAppended(res, subfile);
|
||||
|
||||
handleFile(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
Resource *FileManager::loadFile(const FileIdent &fileIdent) {
|
||||
return loadFile(fileIdent._fileNum, fileIdent._subfile);
|
||||
}
|
||||
|
||||
Resource *FileManager::loadFile(const Common::Path &filename) {
|
||||
Resource *res = new Resource();
|
||||
|
||||
// Open the file
|
||||
openFile(res, filename);
|
||||
|
||||
// Set up stream for the entire file
|
||||
res->_size = res->_file.size();
|
||||
res->_stream = res->_file.readStream(res->_size);
|
||||
|
||||
handleFile(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool FileManager::existFile(const Common::Path &filename) {
|
||||
return Common::File::exists(filename);
|
||||
}
|
||||
|
||||
void FileManager::openFile(Resource *res, const Common::Path &filename) {
|
||||
// Open up the file
|
||||
_fileNumber = -1;
|
||||
if (!res->_file.open(filename))
|
||||
error("Could not open file - %s", filename.toString().c_str());
|
||||
}
|
||||
|
||||
void FileManager::loadScreen(Graphics::ManagedSurface *dest, int fileNum, int subfile) {
|
||||
Resource *res = loadFile(fileNum, subfile);
|
||||
handleScreen(dest, res);
|
||||
delete res;
|
||||
}
|
||||
|
||||
void FileManager::handleScreen(Graphics::ManagedSurface *dest, Resource *res) {
|
||||
_vm->_screen->loadRawPalette(res->_stream);
|
||||
if (_setPaletteFlag)
|
||||
_vm->_screen->setPalette();
|
||||
_setPaletteFlag = true;
|
||||
|
||||
// The remainder of the file after the palette may be separately compressed,
|
||||
// so call handleFile to handle it if it is
|
||||
res->_size -= res->_stream->pos();
|
||||
handleFile(res);
|
||||
|
||||
Graphics::Surface destSurface = dest->getSubArea(Common::Rect(0, 0,
|
||||
_vm->_screen->w, _vm->_screen->h));
|
||||
|
||||
if (destSurface.w == destSurface.pitch) {
|
||||
res->_stream->read((byte *)destSurface.getPixels(), destSurface.w * destSurface.h);
|
||||
} else {
|
||||
for (int y = 0; y < destSurface.h; ++y) {
|
||||
byte *pDest = (byte *)destSurface.getBasePtr(0, y);
|
||||
res->_stream->read(pDest, destSurface.w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileManager::loadScreen(int fileNum, int subfile) {
|
||||
loadScreen(_vm->_screen, fileNum, subfile);
|
||||
}
|
||||
|
||||
void FileManager::loadScreen(const Common::Path &filename) {
|
||||
Resource *res = loadFile(filename);
|
||||
handleScreen(_vm->_screen, res);
|
||||
delete res;
|
||||
}
|
||||
|
||||
void FileManager::handleFile(Resource *res) {
|
||||
char header[3];
|
||||
res->_stream->read(&header[0], 3);
|
||||
res->_stream->seek(-3, SEEK_CUR);
|
||||
|
||||
bool isCompressed = !strncmp(header, "DBE", 3);
|
||||
|
||||
// If the data is compressed, uncompress it and replace the stream
|
||||
// in the resource with the decompressed one
|
||||
if (isCompressed) {
|
||||
// Read in the entire compressed data
|
||||
byte *src = new byte[res->_size];
|
||||
res->_stream->read(src, res->_size);
|
||||
|
||||
// Decompress the data
|
||||
res->_size = decompressDBE(src, &res->_data);
|
||||
|
||||
// Replace the default resource stream with a stream for the decompressed data
|
||||
delete res->_stream;
|
||||
res->_file.close();
|
||||
res->_stream = new Common::MemoryReadStream(res->_data, res->_size);
|
||||
|
||||
delete[] src;
|
||||
}
|
||||
}
|
||||
|
||||
void FileManager::setAppended(Resource *res, int fileNum) {
|
||||
// Open the file for access
|
||||
if (!res->_file.open(_vm->_res->FILENAMES[fileNum]))
|
||||
error("Could not open file %s", _vm->_res->FILENAMES[fileNum].toString().c_str());
|
||||
|
||||
// If a different file has been opened then previously, load its index
|
||||
if (_fileNumber != fileNum) {
|
||||
_fileNumber = fileNum;
|
||||
|
||||
// Read in the file index
|
||||
int count = res->_file.readUint16LE();
|
||||
assert(count <= 100);
|
||||
_fileIndex.resize(count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
_fileIndex[i] = res->_file.readUint32LE();
|
||||
}
|
||||
}
|
||||
|
||||
void FileManager::gotoAppended(Resource *res, int subfile) {
|
||||
uint32 offset = _fileIndex[subfile];
|
||||
uint32 size = (subfile == (int)_fileIndex.size() - 1) ? res->_file.size() - offset :
|
||||
_fileIndex[subfile + 1] - offset;
|
||||
|
||||
res->_size = size;
|
||||
res->_stream = new Common::SeekableSubReadStream(&res->_file, offset, offset + size);
|
||||
}
|
||||
|
||||
} // End of namespace Access
|
||||
142
engines/access/files.h
Normal file
142
engines/access/files.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/* 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 ACCESS_FILES_H
|
||||
#define ACCESS_FILES_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/array.h"
|
||||
#include "common/file.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
#include "access/decompress.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
class AccessEngine;
|
||||
|
||||
struct FileIdent {
|
||||
int _fileNum;
|
||||
int _subfile;
|
||||
|
||||
FileIdent();
|
||||
FileIdent(int fileNum, int subfile) { _fileNum = fileNum; _subfile = subfile; }
|
||||
|
||||
void load(Common::SeekableReadStream &s);
|
||||
};
|
||||
|
||||
struct CellIdent : FileIdent {
|
||||
byte _cell;
|
||||
|
||||
CellIdent();
|
||||
CellIdent(int cell, int fileNum, int subfile);
|
||||
};
|
||||
|
||||
class FileManager;
|
||||
|
||||
class Resource {
|
||||
friend class FileManager;
|
||||
private:
|
||||
Common::File _file;
|
||||
byte *_data;
|
||||
public:
|
||||
Common::SeekableReadStream *_stream;
|
||||
int _size;
|
||||
|
||||
Resource();
|
||||
Resource(byte *data, int size);
|
||||
~Resource();
|
||||
byte *data();
|
||||
|
||||
const char *getFileName() const;
|
||||
};
|
||||
|
||||
class FileManager {
|
||||
private:
|
||||
AccessEngine *_vm;
|
||||
|
||||
void openFile(Resource *res, const Common::Path &filename);
|
||||
|
||||
/**
|
||||
* Handles setting up the resource with a stream for the located resource
|
||||
*/
|
||||
void handleFile(Resource *res);
|
||||
|
||||
/**
|
||||
* Handles loading a screen surface and palette with decoded resource
|
||||
*/
|
||||
void handleScreen(Graphics::ManagedSurface *dest, Resource *res);
|
||||
|
||||
/**
|
||||
* Open up a sub-file container file
|
||||
*/
|
||||
void setAppended(Resource *file, int fileNum);
|
||||
|
||||
/**
|
||||
* Open up a sub-file resource within an alrady opened container file.
|
||||
*/
|
||||
void gotoAppended(Resource *file, int subfile);
|
||||
public:
|
||||
int _fileNumber;
|
||||
Common::Array<uint32> _fileIndex;
|
||||
bool _setPaletteFlag;
|
||||
public:
|
||||
FileManager(AccessEngine *vm);
|
||||
~FileManager();
|
||||
|
||||
/**
|
||||
* Check the existence of a given file
|
||||
*/
|
||||
bool existFile(const Common::Path &filename);
|
||||
|
||||
/**
|
||||
* Load a given subfile from a container file
|
||||
*/
|
||||
Resource *loadFile(int fileNum, int subfile);
|
||||
|
||||
/**
|
||||
* Loads a resource specified by a file identifier
|
||||
*/
|
||||
Resource *loadFile(const FileIdent &fileIdent);
|
||||
|
||||
/**
|
||||
* Load a given file by name
|
||||
*/
|
||||
Resource *loadFile(const Common::Path &filename);
|
||||
|
||||
/**
|
||||
* Load a given scren from a container file
|
||||
*/
|
||||
void loadScreen(int fileNum, int subfile);
|
||||
|
||||
/**
|
||||
* Load a given screen by name
|
||||
*/
|
||||
void loadScreen(const Common::Path &filename);
|
||||
|
||||
/**
|
||||
* Load a screen resource onto a designated surface
|
||||
*/
|
||||
void loadScreen(Graphics::ManagedSurface *dest, int fileNum, int subfile);
|
||||
};
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_FILES_H */
|
||||
266
engines/access/font.cpp
Normal file
266
engines/access/font.cpp
Normal file
@@ -0,0 +1,266 @@
|
||||
/* 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 "access/font.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
byte Font::_fontColors[4];
|
||||
|
||||
Font::Font(byte firstCharIndex) : _firstCharIndex(firstCharIndex), _bitWidth(0), _height(0) {
|
||||
}
|
||||
|
||||
Font::~Font() {
|
||||
for (auto &fontChar : _chars)
|
||||
fontChar.free();
|
||||
}
|
||||
|
||||
int Font::charWidth(char c) const {
|
||||
if (c < _firstCharIndex)
|
||||
return 0;
|
||||
|
||||
return _chars[c - _firstCharIndex].w;
|
||||
}
|
||||
|
||||
int Font::stringWidth(const Common::String &msg) const {
|
||||
int total = 0;
|
||||
|
||||
for (const char *c = msg.c_str(); *c != '\0'; ++c)
|
||||
total += charWidth(*c);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
bool Font::getLine(Common::String &s, int maxWidth, Common::String &line, int &width,
|
||||
LINE_WIDTH_TYPE widthType) const {
|
||||
assert(maxWidth > 0);
|
||||
width = 0;
|
||||
const char *src = s.c_str();
|
||||
char c;
|
||||
|
||||
while ((c = *src) != '\0') {
|
||||
if (c == '\r') {
|
||||
// End of line, so return calculated line
|
||||
line = Common::String(s.c_str(), src);
|
||||
s = Common::String(src + 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
++src;
|
||||
width += (widthType == kWidthInPixels ? charWidth(c) : 1);
|
||||
if (width < maxWidth)
|
||||
continue;
|
||||
|
||||
// Reached maximum allowed size
|
||||
// If this was the last character of the string, let it go
|
||||
if (*src == '\0') {
|
||||
line = Common::String(s.c_str(), src);
|
||||
s.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Work backwards to find space at the start of the current word
|
||||
// as a point to split the line on
|
||||
while (src >= s.c_str() && *src != ' ') {
|
||||
width -= (widthType == kWidthInPixels ? charWidth(*src) : 1);
|
||||
--src;
|
||||
}
|
||||
if (src < s.c_str())
|
||||
error("Could not fit line");
|
||||
|
||||
// Split the line around the space
|
||||
line = Common::String(s.c_str(), src);
|
||||
s = Common::String(src + 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return entire string
|
||||
line = s;
|
||||
s.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Font::drawString(BaseSurface *s, const Common::String &msg, const Common::Point &pt) const {
|
||||
Common::Point currPt = pt;
|
||||
const char *msgP = msg.c_str();
|
||||
|
||||
while (*msgP) {
|
||||
currPt.x += drawChar(s, *msgP, currPt);
|
||||
++msgP;
|
||||
}
|
||||
}
|
||||
|
||||
int Font::drawChar(BaseSurface *s, char c, Common::Point &pt) const {
|
||||
const Graphics::Surface &ch = _chars[c - _firstCharIndex];
|
||||
Graphics::Surface dest = s->getSubArea(Common::Rect(pt.x, pt.y, pt.x + ch.w, pt.y + ch.h));
|
||||
|
||||
// Loop through the lines of the character
|
||||
for (int y = 0; y < ch.h; ++y) {
|
||||
const byte *pSrc = (const byte *)ch.getBasePtr(0, y);
|
||||
byte *pDest = (byte *)dest.getBasePtr(0, y);
|
||||
|
||||
// Loop through the horizontal pixels of the line
|
||||
for (int x = 0; x < ch.w; ++x, ++pSrc, ++pDest) {
|
||||
if (*pSrc != 0)
|
||||
*pDest = _fontColors[*pSrc];
|
||||
}
|
||||
}
|
||||
|
||||
return ch.w;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void AmazonFont::load(const int *fontIndex, const byte *fontData) {
|
||||
assert(_chars.size() == 0);
|
||||
int count = fontIndex[0];
|
||||
_bitWidth = fontIndex[1];
|
||||
_height = fontIndex[2];
|
||||
|
||||
_chars.resize(count);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const byte *pData = fontData + fontIndex[i + 3];
|
||||
_chars[i].create(*pData++, _height, Graphics::PixelFormat::createFormatCLUT8());
|
||||
|
||||
for (int y = 0; y < _height; ++y) {
|
||||
int bitsLeft = 0;
|
||||
byte srcByte = 0;
|
||||
byte pixel;
|
||||
|
||||
byte *pDest = (byte *)_chars[i].getBasePtr(0, y);
|
||||
for (int x = 0; x < _chars[i].w; ++x, ++pDest) {
|
||||
// Get the pixel
|
||||
pixel = 0;
|
||||
for (int pixelCtr = 0; pixelCtr < _bitWidth; ++pixelCtr, --bitsLeft) {
|
||||
// No bits in current byte left, so get next byte
|
||||
if (bitsLeft == 0) {
|
||||
bitsLeft = 8;
|
||||
srcByte = *pData++;
|
||||
}
|
||||
|
||||
pixel = (pixel << 1) | (srcByte >> 7);
|
||||
srcByte <<= 1;
|
||||
}
|
||||
|
||||
// Write out the pixel
|
||||
*pDest = pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
MartianFont::MartianFont(int height, Common::SeekableReadStream &s) : Font(0) {
|
||||
_height = height;
|
||||
loadFromStream(s);
|
||||
}
|
||||
|
||||
MartianFont::MartianFont(int height, size_t count, const byte *widths, const int *offsets, const byte *data) : Font(0) {
|
||||
_height = height;
|
||||
loadFromData(count, widths, offsets, data);
|
||||
}
|
||||
|
||||
void MartianFont::loadFromStream(Common::SeekableReadStream &s) {
|
||||
// Get the number of characters and the size of the raw font data
|
||||
size_t count = s.readUint16LE();
|
||||
size_t dataSize = s.readUint16LE();
|
||||
assert(count < 256);
|
||||
|
||||
// Get the character widths
|
||||
Common::Array<byte> widths;
|
||||
widths.resize(count);
|
||||
s.read(&widths[0], count);
|
||||
|
||||
// Get the character offsets
|
||||
Common::Array<int> offsets;
|
||||
offsets.resize(count);
|
||||
for (size_t idx = 0; idx < count; ++idx)
|
||||
offsets[idx] = s.readUint16LE();
|
||||
|
||||
// Get the raw character data
|
||||
Common::Array<byte> data;
|
||||
data.resize(dataSize);
|
||||
s.read(&data[0], dataSize);
|
||||
|
||||
loadFromData(count, widths.data(), offsets.data(), data.data());
|
||||
}
|
||||
|
||||
void MartianFont::loadFromData(size_t count, const byte *widths, const int *offsets, const byte *data) {
|
||||
// Iterate through decoding each character
|
||||
_chars.resize(count);
|
||||
for (size_t idx = 0; idx < count; ++idx) {
|
||||
Graphics::Surface &surface = _chars[idx];
|
||||
surface.create(widths[idx], _height, Graphics::PixelFormat::createFormatCLUT8());
|
||||
const byte *srcP = &data[offsets[idx]];
|
||||
int x1, y1, x2, y2;
|
||||
|
||||
// Write horizontal lines
|
||||
while ((x1 = *srcP++) != 0xff) {
|
||||
x2 = *srcP++;
|
||||
y1 = *srcP++;
|
||||
surface.hLine(x1, y1, x2, 3);
|
||||
}
|
||||
|
||||
// Write vertical lines
|
||||
while ((x1 = *srcP++) != 0xff) {
|
||||
y1 = *srcP++;
|
||||
y2 = *srcP++;
|
||||
surface.vLine(x1, y1, y2, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
MartianBitFont::MartianBitFont(size_t count, const byte *data) : Font(0x20) {
|
||||
_height = 8;
|
||||
_chars.resize(count);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
Graphics::Surface &surface = _chars[i];
|
||||
surface.create(8, _height, Graphics::PixelFormat::createFormatCLUT8());
|
||||
for (int y = 0; y < _height; y++) {
|
||||
byte src = data[i * 8 + y];
|
||||
byte *dst = static_cast<byte *>(surface.getBasePtr(0, y));
|
||||
for (int x = 7; x >= 0; x--) {
|
||||
dst[x] = (src & 1);
|
||||
src >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
FontManager::FontManager() : _font1(nullptr), _font2(nullptr), _bitFont(nullptr) {
|
||||
_printMaxX = 0;
|
||||
Common::fill(&Font::_fontColors[0], &Font::_fontColors[4], 0);
|
||||
}
|
||||
|
||||
void FontManager::load(Font *font1, Font *font2, Font *bitFont) {
|
||||
_font1 = font1;
|
||||
_font2 = font2;
|
||||
_bitFont = bitFont;
|
||||
}
|
||||
|
||||
|
||||
} // End of namespace Access
|
||||
166
engines/access/font.h
Normal file
166
engines/access/font.h
Normal file
@@ -0,0 +1,166 @@
|
||||
/* 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 ACCESS_FONT_H
|
||||
#define ACCESS_FONT_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/array.h"
|
||||
#include "common/rect.h"
|
||||
#include "access/asurface.h"
|
||||
#include "access/data.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
struct FontVal {
|
||||
public:
|
||||
int _lo, _hi;
|
||||
|
||||
FontVal() { _lo = _hi = 0; }
|
||||
};
|
||||
|
||||
class Font {
|
||||
protected:
|
||||
byte _firstCharIndex;
|
||||
int _bitWidth;
|
||||
int _height;
|
||||
Common::Array<Graphics::Surface> _chars;
|
||||
protected:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Font(byte firstCharIndex);
|
||||
public:
|
||||
static byte _fontColors[4];
|
||||
public:
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~Font();
|
||||
|
||||
/**
|
||||
* Get the width of a given character
|
||||
*/
|
||||
int charWidth(char c) const;
|
||||
|
||||
/**
|
||||
* Get the width of a given string
|
||||
*/
|
||||
int stringWidth(const Common::String &msg) const;
|
||||
|
||||
/**
|
||||
* Type of line wrapping - Martian wraps based on chars, Amazon based on px.
|
||||
*
|
||||
* Since the fonts are variable width we need to support both types to
|
||||
* exactly wrap like the originals.
|
||||
*/
|
||||
enum LINE_WIDTH_TYPE {
|
||||
kWidthInPixels,
|
||||
kWidthInChars
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a partial string that will fit in a given width
|
||||
* @param s Source string. Modified to remove line
|
||||
* @param maxWidth Maximum width allowed in px or chars (see widthType)
|
||||
* @param line Output line
|
||||
* @param width Actual width of returned line in selected units
|
||||
* @param widthType Select the type of width constraint - px or chars
|
||||
* @returns True if last line
|
||||
*/
|
||||
bool getLine(Common::String &s, int maxWidth, Common::String &line, int &width,
|
||||
LINE_WIDTH_TYPE widthType = kWidthInPixels) const;
|
||||
|
||||
/**
|
||||
* Draw a string on a given surface
|
||||
*/
|
||||
void drawString(BaseSurface *s, const Common::String &msg, const Common::Point &pt) const;
|
||||
|
||||
/**
|
||||
* Draw a character on a given surface
|
||||
*/
|
||||
int drawChar(BaseSurface *s, char c, Common::Point &pt) const;
|
||||
|
||||
};
|
||||
|
||||
class AmazonFont : public Font {
|
||||
private:
|
||||
/**
|
||||
* Load the given font data
|
||||
*/
|
||||
void load(const int *fontIndex, const byte *fontData);
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
AmazonFont(const int *fontIndex, const byte *fontData) : Font(32) {
|
||||
load(fontIndex, fontData);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class MartianFont : public Font {
|
||||
private:
|
||||
/**
|
||||
* Load the given font data
|
||||
*/
|
||||
void loadFromStream(Common::SeekableReadStream &s);
|
||||
void loadFromData(size_t count, const byte *widths, const int *offsets, const byte *data);
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
MartianFont(int height, Common::SeekableReadStream &s);
|
||||
MartianFont(int height, size_t count, const byte *widths, const int *offsets, const byte *data);
|
||||
};
|
||||
|
||||
class MartianBitFont : public Font {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
MartianBitFont(size_t count, const byte *data);
|
||||
};
|
||||
|
||||
|
||||
class FontManager {
|
||||
public:
|
||||
FontVal _charSet;
|
||||
FontVal _charFor;
|
||||
int _printMaxX;
|
||||
Font *_font1;
|
||||
Font *_font2;
|
||||
Font *_bitFont;
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
FontManager();
|
||||
|
||||
/**
|
||||
* Set the fonts
|
||||
*/
|
||||
void load(Font *font1, Font *font2, Font *bitFont);
|
||||
};
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_FONT_H */
|
||||
572
engines/access/inventory.cpp
Normal file
572
engines/access/inventory.cpp
Normal file
@@ -0,0 +1,572 @@
|
||||
/* 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 "access/inventory.h"
|
||||
#include "access/access.h"
|
||||
#include "access/resources.h"
|
||||
#include "access/amazon/amazon_resources.h"
|
||||
#include "access/martian/martian_resources.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
void InventoryEntry::load(const Common::String &name, const int *data) {
|
||||
_value = ITEM_NOT_FOUND;
|
||||
_name = name;
|
||||
if (data) {
|
||||
_otherItem1 = *data++;
|
||||
_newItem1 = *data++;
|
||||
_otherItem2 = *data++;
|
||||
_newItem2 = *data;
|
||||
} else {
|
||||
_otherItem1 = -1;
|
||||
_newItem1 = -1;
|
||||
_otherItem2 = -1;
|
||||
_newItem2 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int InventoryEntry::checkItem(int itemId) const {
|
||||
if (_otherItem1 == itemId)
|
||||
return _newItem1;
|
||||
else if (_otherItem2 == itemId)
|
||||
return _newItem2;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
InventoryManager::SavedFields::SavedFields() {
|
||||
_vWindowHeight = _vWindowLinesTall = _vWindowWidth = _vWindowBytesWide = 0;
|
||||
_playFieldHeight = _playFieldWidth = 0;
|
||||
_windowXAdd = _windowYAdd = 0;
|
||||
_screenYOff = 0;
|
||||
_scrollX = _scrollY = 0;
|
||||
_clipWidth = _clipHeight = 0;
|
||||
_scrollCol = _scrollRow = 0;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
InventoryManager::InventoryManager(AccessEngine *vm) : Manager(vm) {
|
||||
_startInvItem = 0;
|
||||
_startInvBox = 0;
|
||||
_invChangeFlag = true;
|
||||
_invRefreshFlag = false;
|
||||
_invModeFlag = false;
|
||||
_startAboutItem = 0;
|
||||
_startTravelItem = 0;
|
||||
_iconDisplayFlag = true;
|
||||
_boxNum = 0;
|
||||
|
||||
_inv.resize(_vm->_res->INVENTORY.size());
|
||||
for (uint idx = 0; idx < _inv.size(); ++idx)
|
||||
_inv[idx].load(_vm->_res->INVENTORY[idx]._desc, _vm->_res->INVENTORY[idx]._combo);
|
||||
|
||||
for (uint i = 0; i < 26; ++i) {
|
||||
const int *r = INVCOORDS[i];
|
||||
_invCoords.push_back(Common::Rect(r[0], r[2], r[1], r[3]));
|
||||
}
|
||||
}
|
||||
|
||||
int &InventoryManager::operator[](int idx) {
|
||||
// WORKAROUND: At least in Amazon, some game scripts accidentally do reads
|
||||
// beyond the length of the inventory array
|
||||
static int invalid = 0;
|
||||
return (idx >= (int)_inv.size()) ? invalid : _inv[idx]._value;
|
||||
}
|
||||
|
||||
int InventoryManager::useItem() {
|
||||
return _vm->_useItem;
|
||||
}
|
||||
|
||||
void InventoryManager::setUseItem(int itemId) {
|
||||
_vm->_useItem = itemId;
|
||||
}
|
||||
|
||||
void InventoryManager::refreshInventory() {
|
||||
// The original version was using pre-rendering for the inventory to spare some time.
|
||||
// This is not needed on modern hardware, and it breaks a couple of things.
|
||||
// Therefore it was removed in order to keep the same logic than for the CD version
|
||||
// if (_vm->_screen->_vesaMode) {
|
||||
// _invRefreshFlag = true;
|
||||
// newDisplayInv();
|
||||
// }
|
||||
}
|
||||
|
||||
int InventoryManager::newDisplayInv() {
|
||||
Screen &screen = *_vm->_screen;
|
||||
EventsManager &events = *_vm->_events;
|
||||
Room &room = *_vm->_room;
|
||||
FileManager &files = *_vm->_files;
|
||||
|
||||
_invModeFlag = true;
|
||||
_vm->_timers.saveTimers();
|
||||
|
||||
if (!room._tile && !_invRefreshFlag) {
|
||||
saveScreens();
|
||||
}
|
||||
|
||||
savedFields();
|
||||
screen.setPanel(1);
|
||||
events._cursorExitFlag = false;
|
||||
getList();
|
||||
initFields();
|
||||
|
||||
files._setPaletteFlag = false;
|
||||
files.loadScreen(&_vm->_buffer1, 99, 0);
|
||||
_vm->_buffer1.copyTo(&_vm->_buffer2);
|
||||
_vm->copyBF2Vid();
|
||||
|
||||
// Set cells
|
||||
Common::Array<CellIdent> cells;
|
||||
cells.push_back(CellIdent(99, 99, 1));
|
||||
_vm->loadCells(cells);
|
||||
|
||||
showAllItems();
|
||||
|
||||
if (!_invRefreshFlag) {
|
||||
chooseItem();
|
||||
if (_vm->_useItem != -1) {
|
||||
int savedScale = _vm->_scale;
|
||||
_vm->_scale = 153;
|
||||
_vm->_screen->setScaleTable(_vm->_scale);
|
||||
_vm->_buffer1.clearBuffer();
|
||||
|
||||
SpriteResource *spr = _vm->_objectsTable[99];
|
||||
const SpriteFrame *frame = spr->getFrame(_vm->_useItem);
|
||||
|
||||
int w = screen._scaleTable1[46];
|
||||
int h = screen._scaleTable1[35];
|
||||
_vm->_buffer1.sPlotF(frame, Common::Rect(0, 0, w, h));
|
||||
events.setCursorData(&_vm->_buffer1, Common::Rect(0, 0, w, h));
|
||||
|
||||
_vm->_scale = savedScale;
|
||||
screen.setScaleTable(_vm->_scale);
|
||||
}
|
||||
}
|
||||
|
||||
freeInvCells();
|
||||
screen.setPanel(0);
|
||||
events.debounceLeft();
|
||||
|
||||
restoreFields();
|
||||
screen.restorePalette();
|
||||
// The original was testing the vesa mode too.
|
||||
// We removed this check as we don't use pre-rendering
|
||||
if (!_invRefreshFlag) {
|
||||
screen.clearScreen();
|
||||
screen.setPalette();
|
||||
}
|
||||
|
||||
if (!room._tile && !_invRefreshFlag) {
|
||||
restoreScreens();
|
||||
} else {
|
||||
screen.setBufferScan();
|
||||
room.buildScreen();
|
||||
|
||||
// The original was doing a check on the vesa mode at this point.
|
||||
// We don't need it as we don't do inventory pre-rendering
|
||||
screen.fadeOut();
|
||||
_vm->copyBF2Vid();
|
||||
}
|
||||
|
||||
events._cursorExitFlag = false;
|
||||
screen._screenChangeFlag = false;
|
||||
_invModeFlag = false;
|
||||
events.debounceLeft();
|
||||
_vm->_timers.restoreTimers();
|
||||
_vm->_startup = 1;
|
||||
|
||||
int result = 0;
|
||||
if (!_invRefreshFlag) {
|
||||
if (_vm->_useItem == -1) {
|
||||
result = 2;
|
||||
events.forceSetCursor(CURSOR_CROSSHAIRS);
|
||||
} else
|
||||
events.forceSetCursor(CURSOR_INVENTORY);
|
||||
}
|
||||
|
||||
_invRefreshFlag = false;
|
||||
_invChangeFlag = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
int InventoryManager::displayInv() {
|
||||
size_t invSize = _vm->_res->INVENTORY.size();
|
||||
|
||||
Common::Array<byte> invFlags(invSize + 1);
|
||||
Common::Array<const char *> invNames(invSize + 1);
|
||||
|
||||
// Only show items that are in the inventory, skip "used".
|
||||
for (size_t i = 0; i < invSize; i++) {
|
||||
byte flag = (_inv[i]._value == ITEM_IN_INVENTORY) ? 1 : 0;
|
||||
invFlags[i] = flag;
|
||||
invNames[i] = _inv[i]._name.c_str();
|
||||
}
|
||||
_vm->_events->forceSetCursor(CURSOR_CROSSHAIRS);
|
||||
_vm->_invBox->getList(invNames.data(), invFlags.data());
|
||||
|
||||
int btnSelected = 0;
|
||||
int boxX = _vm->_invBox->doBox_v1(_startInvItem, _startInvBox, btnSelected);
|
||||
_startInvItem = _vm->_boxDataStart;
|
||||
_startInvBox = _vm->_boxSelectY;
|
||||
|
||||
if (boxX == -1)
|
||||
btnSelected = 2;
|
||||
|
||||
if (btnSelected != 2)
|
||||
_vm->_useItem = _vm->_invBox->_tempListIdx[boxX];
|
||||
else
|
||||
_vm->_useItem = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void InventoryManager::savedFields() {
|
||||
Screen &screen = *_vm->_screen;
|
||||
Room &room = *_vm->_room;
|
||||
|
||||
_fields._vWindowHeight = screen._vWindowHeight;
|
||||
_fields._vWindowLinesTall = screen._vWindowLinesTall;
|
||||
_fields._vWindowWidth = screen._vWindowWidth;
|
||||
_fields._vWindowBytesWide = screen._vWindowBytesWide;
|
||||
_fields._playFieldHeight = room._playFieldHeight;
|
||||
_fields._playFieldWidth = room._playFieldWidth;
|
||||
_fields._windowXAdd = screen._windowXAdd;
|
||||
_fields._windowYAdd = screen._windowYAdd;
|
||||
_fields._screenYOff = screen._screenYOff;
|
||||
_fields._scrollX = _vm->_scrollX;
|
||||
_fields._scrollY = _vm->_scrollY;
|
||||
_fields._clipWidth = screen._clipWidth;
|
||||
_fields._clipHeight = screen._clipHeight;
|
||||
_fields._bufferStart = screen._bufferStart;
|
||||
_fields._scrollCol = _vm->_scrollCol;
|
||||
_fields._scrollRow = _vm->_scrollRow;
|
||||
}
|
||||
|
||||
void InventoryManager::restoreFields() {
|
||||
Screen &screen = *_vm->_screen;
|
||||
Room &room = *_vm->_room;
|
||||
|
||||
screen._vWindowHeight = _fields._vWindowHeight;
|
||||
screen._vWindowLinesTall = _fields._vWindowLinesTall;
|
||||
screen._vWindowWidth = _fields._vWindowWidth;
|
||||
screen._vWindowBytesWide = _fields._vWindowBytesWide;
|
||||
room._playFieldHeight = _fields._playFieldHeight;
|
||||
room._playFieldWidth = _fields._playFieldWidth;
|
||||
screen._windowXAdd = _fields._windowXAdd;
|
||||
screen._windowYAdd = _fields._windowYAdd;
|
||||
screen._screenYOff = _fields._screenYOff;
|
||||
_vm->_scrollX = _fields._scrollX;
|
||||
_vm->_scrollY = _fields._scrollY;
|
||||
screen._clipWidth = _fields._clipWidth;
|
||||
screen._clipHeight = _fields._clipHeight;
|
||||
screen._bufferStart = _fields._bufferStart;
|
||||
_vm->_scrollCol = _fields._scrollCol;
|
||||
_vm->_scrollRow = _fields._scrollRow;
|
||||
}
|
||||
|
||||
void InventoryManager::initFields() {
|
||||
Screen &screen = *_vm->_screen;
|
||||
Room &room = *_vm->_room;
|
||||
|
||||
screen._vWindowHeight = screen.h;
|
||||
room._playFieldHeight = screen.h;
|
||||
screen._vWindowLinesTall = screen.h;
|
||||
screen._clipHeight = screen.h;
|
||||
room._playFieldWidth = screen.w;
|
||||
screen._vWindowWidth = screen.w;
|
||||
screen._vWindowBytesWide = screen.w;
|
||||
screen._clipWidth = screen.w;
|
||||
|
||||
screen._windowXAdd = 0;
|
||||
screen._windowYAdd = 0;
|
||||
screen._screenYOff = 0;
|
||||
screen._bufferStart.x = 0;
|
||||
screen._bufferStart.y = 0;
|
||||
_vm->_scrollX = _vm->_scrollY = 0;
|
||||
|
||||
_vm->_buffer1.clearBuffer();
|
||||
_vm->_buffer2.clearBuffer();
|
||||
// The original was doing at this point a check on vesa mode
|
||||
// We don't need it as we don't do inventory pre-rendering
|
||||
if (!_invRefreshFlag)
|
||||
screen.clearBuffer();
|
||||
|
||||
screen.savePalette();
|
||||
}
|
||||
|
||||
void InventoryManager::getList() {
|
||||
_items.clear();
|
||||
_tempLOff.clear();
|
||||
|
||||
for (uint i = 0; i < _inv.size(); ++i) {
|
||||
if (_inv[i]._value == ITEM_IN_INVENTORY) {
|
||||
_items.push_back(i);
|
||||
_tempLOff.push_back(_inv[i]._name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InventoryManager::showAllItems() {
|
||||
_iconDisplayFlag = true;
|
||||
|
||||
for (uint i = 0; i < _items.size(); ++i)
|
||||
putInvIcon(i, _items[i]);
|
||||
}
|
||||
|
||||
void InventoryManager::putInvIcon(int itemIndex, int itemId) {
|
||||
SpriteResource *spr = _vm->_objectsTable[99];
|
||||
assert(spr);
|
||||
Common::Point pt((itemIndex % 6) * 46 + 23, (itemIndex / 6) * 35 + 15);
|
||||
_vm->_buffer2.plotImage(spr, itemId, pt);
|
||||
|
||||
if (_iconDisplayFlag) {
|
||||
_vm->_screen->copyBlock(&_vm->_buffer2, Common::Rect(pt.x, pt.y, pt.x + 46, pt.y + 35));
|
||||
}
|
||||
}
|
||||
|
||||
void InventoryManager::chooseItem() {
|
||||
EventsManager &events = *_vm->_events;
|
||||
_vm->_useItem = -1;
|
||||
|
||||
while (!_vm->shouldQuit()) {
|
||||
// Check for events
|
||||
events.pollEventsAndWait();
|
||||
|
||||
int selIndex;
|
||||
// Poll events and wait for a click on a known area
|
||||
if (!events._leftButton || ((selIndex = coordIndexOf()) == -1))
|
||||
continue;
|
||||
|
||||
if (selIndex > 23) {
|
||||
if (selIndex == 25)
|
||||
_vm->_useItem = -1;
|
||||
break;
|
||||
} else if (selIndex < (int)_items.size() && _items[selIndex] != -1) {
|
||||
_boxNum = selIndex;
|
||||
_vm->copyBF2Vid();
|
||||
combineItems();
|
||||
_vm->copyBF2Vid();
|
||||
outlineIcon(_boxNum);
|
||||
_vm->_useItem = _items[_boxNum];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InventoryManager::freeInvCells() {
|
||||
delete _vm->_objectsTable[99];
|
||||
_vm->_objectsTable[99] = nullptr;
|
||||
}
|
||||
|
||||
int InventoryManager::coordIndexOf() const {
|
||||
const Common::Point pt = _vm->_events->_mousePos;
|
||||
|
||||
for (int i = 0; i < (int)_invCoords.size(); ++i) {
|
||||
if (_invCoords[i].contains(pt))
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void InventoryManager::saveScreens() {
|
||||
_vm->_buffer1.copyTo(&_savedBuffer1);
|
||||
_vm->_screen->copyTo(&_savedScreen);
|
||||
_vm->_newRects.push_back(Common::Rect(0, 0, _savedScreen.w, _savedScreen.h));
|
||||
|
||||
}
|
||||
|
||||
void InventoryManager::restoreScreens() {
|
||||
_vm->_buffer1.w = _vm->_buffer1.pitch;
|
||||
_savedBuffer1.copyTo(&_vm->_buffer1);
|
||||
_savedScreen.copyTo(_vm->_screen);
|
||||
|
||||
_savedBuffer1.free();
|
||||
_savedScreen.free();
|
||||
}
|
||||
|
||||
void InventoryManager::outlineIcon(int itemIndex) {
|
||||
Screen &screen = *_vm->_screen;
|
||||
screen.frameRect(_invCoords[itemIndex], 7);
|
||||
|
||||
Common::String s = _tempLOff[itemIndex];
|
||||
Font &font = *_vm->_fonts._font2;
|
||||
int strWidth = font.stringWidth(s);
|
||||
|
||||
font._fontColors[0] = 0;
|
||||
font._fontColors[1] = 10;
|
||||
font._fontColors[2] = 11;
|
||||
font._fontColors[3] = 12;
|
||||
font.drawString(&screen, s, Common::Point((screen.w - strWidth) / 2, 184));
|
||||
}
|
||||
|
||||
void InventoryManager::combineItems() {
|
||||
Screen &screen = *_vm->_screen;
|
||||
EventsManager &events = *_vm->_events;
|
||||
screen._leftSkip = screen._rightSkip = 0;
|
||||
screen._topSkip = screen._bottomSkip = 0;
|
||||
screen._screenYOff = 0;
|
||||
|
||||
const Common::Rect screenBounds = screen.getBounds();
|
||||
const int screenW = screenBounds.width();
|
||||
const int screenH = screenBounds.height();
|
||||
|
||||
Common::Point tempMouse = events._mousePos;
|
||||
Common::Point lastMouse = events._mousePos;
|
||||
|
||||
Common::Rect &inv = _invCoords[_boxNum];
|
||||
Common::Rect r(inv.left, inv.top, inv.left + 46, inv.top + 35);
|
||||
Common::Point tempBox(inv.left, inv.top);
|
||||
Common::Point lastBox(inv.left, inv.top);
|
||||
|
||||
_vm->_buffer2.copyBlock(&_vm->_buffer1, r);
|
||||
SpriteResource *sprites = _vm->_objectsTable[99];
|
||||
int invItem = _items[_boxNum];
|
||||
events.pollEvents();
|
||||
|
||||
// Item drag handling loop if left button is held down
|
||||
while (!_vm->shouldQuit() && events._leftButton) {
|
||||
// Poll for events
|
||||
events.pollEventsAndWait();
|
||||
|
||||
// Check positioning
|
||||
if (lastMouse == events._mousePos)
|
||||
continue;
|
||||
|
||||
lastMouse = events._mousePos;
|
||||
Common::Rect lastRect(lastBox.x, lastBox.y, MIN(lastBox.x + 46, screenW), MIN(lastBox.y + 35, screenH));
|
||||
screen.copyBlock(&_vm->_buffer2, lastRect);
|
||||
|
||||
Common::Point newPt;
|
||||
newPt.x = MAX(events._mousePos.x - tempMouse.x + tempBox.x, 0);
|
||||
newPt.y = MAX(events._mousePos.y - tempMouse.y + tempBox.y, 0);
|
||||
|
||||
screen.plotImage(sprites, invItem, newPt);
|
||||
lastBox = newPt;
|
||||
}
|
||||
|
||||
int destBox = events.checkMouseBox1(_invCoords);
|
||||
if (destBox >= 0 && destBox != _boxNum && destBox < (int)_items.size()
|
||||
&& _items[destBox] != -1) {
|
||||
int itemA = invItem;
|
||||
int itemB = _items[destBox];
|
||||
|
||||
// Check whether the items can be combined
|
||||
int combinedItem = _inv[itemA].checkItem(itemB);
|
||||
if (combinedItem != -1) {
|
||||
_inv[combinedItem]._value = 1;
|
||||
_inv[itemA]._value = 2;
|
||||
_inv[itemB]._value = 2;
|
||||
_items[_boxNum] = -1;
|
||||
_items[destBox] = combinedItem;
|
||||
_tempLOff[destBox] = _inv[combinedItem]._name;
|
||||
events.hideCursor();
|
||||
|
||||
// Shrink down the first item on top of the second item
|
||||
zoomIcon(itemA, itemB, destBox, true);
|
||||
|
||||
// Shrink down the second item
|
||||
Common::Rect destRect(_invCoords[destBox].left, _invCoords[destBox].top,
|
||||
_invCoords[destBox].left + 46, _invCoords[destBox].top + 35);
|
||||
_vm->_buffer2.copyBlock(&_vm->_buffer1, destRect);
|
||||
screen._screenYOff = 0;
|
||||
zoomIcon(itemB, -1, destBox, true);
|
||||
|
||||
// Exand up the new combined item from nothing to full size
|
||||
zoomIcon(combinedItem, -1, destBox, false);
|
||||
|
||||
_boxNum = destBox;
|
||||
events.showCursor();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_iconDisplayFlag = true;
|
||||
putInvIcon(_boxNum, invItem);
|
||||
}
|
||||
|
||||
void InventoryManager::zoomIcon(int zoomItem, int backItem, int zoomBox, bool shrink) {
|
||||
Screen &screen = *_vm->_screen;
|
||||
screen._screenYOff = 0;
|
||||
SpriteResource *sprites = _vm->_objectsTable[99];
|
||||
|
||||
int oldScale = _vm->_scale;
|
||||
int zoomScale = shrink ? 255 : 1;
|
||||
int zoomInc = shrink ? -1 : 1;
|
||||
Common::Rect boxRect(_invCoords[zoomBox].left, _invCoords[zoomBox].top,
|
||||
_invCoords[zoomBox].left + 46, _invCoords[zoomBox].top + 35);
|
||||
|
||||
while (!_vm->shouldQuit() && zoomScale != 0 && zoomScale != 256) {
|
||||
_vm->_events->pollEventsAndWait();
|
||||
|
||||
_vm->_buffer2.copyBlock(&_vm->_buffer1, boxRect);
|
||||
if (backItem != -1) {
|
||||
_iconDisplayFlag = false;
|
||||
putInvIcon(zoomBox, backItem);
|
||||
}
|
||||
|
||||
_vm->_scale = zoomScale;
|
||||
screen.setScaleTable(zoomScale);
|
||||
|
||||
int xv = screen._scaleTable1[boxRect.width() + 1];
|
||||
if (xv) {
|
||||
int yv = screen._scaleTable1[boxRect.height() + 1];
|
||||
if (yv) {
|
||||
// The zoomed size is positive in both directions, so show zoomed item
|
||||
Common::Rect scaledBox(xv, yv);
|
||||
scaledBox.moveTo(boxRect.left + (boxRect.width() - xv + 1) / 2,
|
||||
boxRect.top + (boxRect.height() - yv + 1) / 2);
|
||||
|
||||
_vm->_buffer2.sPlotF(sprites->getFrame(zoomItem), scaledBox);
|
||||
}
|
||||
}
|
||||
|
||||
screen.copyBlock(&_vm->_buffer2, boxRect);
|
||||
|
||||
zoomScale += zoomInc;
|
||||
}
|
||||
|
||||
if (!shrink) {
|
||||
// Handle the final full-size version
|
||||
_vm->_buffer2.copyBlock(&_vm->_buffer1, boxRect);
|
||||
_vm->_buffer2.plotImage(sprites, zoomItem,
|
||||
Common::Point(boxRect.left, boxRect.top));
|
||||
screen.copyBlock(&_vm->_buffer2, boxRect);
|
||||
}
|
||||
|
||||
_vm->_scale = oldScale;
|
||||
screen.setScaleTable(oldScale);
|
||||
}
|
||||
|
||||
void InventoryManager::synchronize(Common::Serializer &s) {
|
||||
int count = _inv.size();
|
||||
s.syncAsUint16LE(count);
|
||||
|
||||
if (!s.isSaving())
|
||||
_inv.resize(count);
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
s.syncAsUint16LE(_inv[i]._value);
|
||||
}
|
||||
|
||||
} // End of namespace Access
|
||||
142
engines/access/inventory.h
Normal file
142
engines/access/inventory.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/* 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 ACCESS_INVENTORY_H
|
||||
#define ACCESS_INVENTORY_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/array.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/str-array.h"
|
||||
#include "access/data.h"
|
||||
#include "access/asurface.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
enum ItemState {
|
||||
ITEM_NOT_FOUND = 0, ITEM_IN_INVENTORY = 1, ITEM_USED = 2
|
||||
};
|
||||
|
||||
class InventoryEntry {
|
||||
public:
|
||||
Common::String _name;
|
||||
int _value;
|
||||
|
||||
int _otherItem1;
|
||||
int _newItem1;
|
||||
int _otherItem2;
|
||||
int _newItem2;
|
||||
|
||||
void load(const Common::String &name, const int *data);
|
||||
|
||||
int checkItem(int itemId) const;
|
||||
};
|
||||
|
||||
class InventoryManager : public Manager {
|
||||
struct SavedFields {
|
||||
int _vWindowHeight;
|
||||
int _vWindowLinesTall;
|
||||
int _vWindowWidth;
|
||||
int _vWindowBytesWide;
|
||||
int _playFieldHeight;
|
||||
int _playFieldWidth;
|
||||
int _windowXAdd;
|
||||
int _windowYAdd;
|
||||
int _screenYOff;
|
||||
int _scrollX;
|
||||
int _scrollY;
|
||||
int _clipWidth;
|
||||
int _clipHeight;
|
||||
Common::Point _bufferStart;
|
||||
int _scrollCol;
|
||||
int _scrollRow;
|
||||
|
||||
SavedFields();
|
||||
};
|
||||
private:
|
||||
Common::Array<int> _items;
|
||||
Common::Array<Common::Rect> _invCoords;
|
||||
ASurface _savedBuffer1;
|
||||
ASurface _savedScreen;
|
||||
SavedFields _fields;
|
||||
bool _iconDisplayFlag;
|
||||
Common::Array<int> _tempLPtr;
|
||||
Common::StringArray _tempLOff;
|
||||
int _boxNum;
|
||||
|
||||
void savedFields();
|
||||
|
||||
void restoreFields();
|
||||
|
||||
void initFields();
|
||||
|
||||
void getList();
|
||||
|
||||
void showAllItems();
|
||||
|
||||
void putInvIcon(int itemIndex, int itemId);
|
||||
|
||||
void chooseItem();
|
||||
|
||||
void freeInvCells();
|
||||
|
||||
int coordIndexOf() const;
|
||||
|
||||
void saveScreens();
|
||||
|
||||
void restoreScreens();
|
||||
|
||||
void outlineIcon(int itemIndex);
|
||||
|
||||
void combineItems();
|
||||
|
||||
void zoomIcon(int zoomItem, int backItem, int zoomBox, bool shrink);
|
||||
public:
|
||||
Common::Array<InventoryEntry> _inv;
|
||||
int _startInvItem;
|
||||
int _startInvBox;
|
||||
bool _invChangeFlag;
|
||||
bool _invRefreshFlag;
|
||||
bool _invModeFlag;
|
||||
int _startAboutItem;
|
||||
int _startTravelItem;
|
||||
public:
|
||||
InventoryManager(AccessEngine *vm);
|
||||
|
||||
int &operator[](int idx);
|
||||
|
||||
int useItem();
|
||||
void setUseItem(int itemId);
|
||||
|
||||
void refreshInventory();
|
||||
|
||||
int newDisplayInv();
|
||||
int displayInv();
|
||||
|
||||
/**
|
||||
* Synchronize savegame data
|
||||
*/
|
||||
void synchronize(Common::Serializer &s);
|
||||
};
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_INVENTORY_H */
|
||||
1285
engines/access/martian/martian_duct.cpp
Normal file
1285
engines/access/martian/martian_duct.cpp
Normal file
File diff suppressed because it is too large
Load Diff
172
engines/access/martian/martian_duct.h
Normal file
172
engines/access/martian/martian_duct.h
Normal file
@@ -0,0 +1,172 @@
|
||||
/* 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 ACCESS_MARTIAN_MARTIAN_DUCT_H
|
||||
#define ACCESS_MARTIAN_MARTIAN_DUCT_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/array.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/events.h"
|
||||
|
||||
#include "access/martian/martian_resources.h" // For Point3 .. move it?
|
||||
|
||||
namespace Access {
|
||||
|
||||
namespace Martian {
|
||||
|
||||
enum MoveIntent {
|
||||
kMoveIntentNone,
|
||||
kMoveIntentUp,
|
||||
kMoveIntentLeft,
|
||||
kMoveIntentDown,
|
||||
kMoveIntentRight,
|
||||
};
|
||||
|
||||
// Move angles - in the original these are indexes into sin/cos lookup tables.
|
||||
// Add Invalid to ensure at least 2-byte length.
|
||||
enum MoveAngle {
|
||||
kMoveAngleNorth = 0,
|
||||
kMoveAngleEast = 0x40,
|
||||
kMoveAngleSouth = 0x80,
|
||||
kMoveAngleWest = 0xC0,
|
||||
kMoveAngleInvalid = 0xffff,
|
||||
};
|
||||
|
||||
enum DuctFlags {
|
||||
kDuctFlagNone = 0,
|
||||
kDuctFlagZLessThanX = 1,
|
||||
kDuctFlagXLessThanNegZ = 2,
|
||||
kDuctFlagYLessThanNegZ = 4,
|
||||
kDuctFlagZLessThanY = 8,
|
||||
kDuctFlagZLessThan2 = 16,
|
||||
};
|
||||
|
||||
struct RenderShape {
|
||||
byte _col;
|
||||
Common::Array<uint16> _pointIdxs;
|
||||
};
|
||||
|
||||
class MartianEngine;
|
||||
|
||||
class MartianDuct {
|
||||
public:
|
||||
MartianDuct(MartianEngine *vm);
|
||||
~MartianDuct();
|
||||
|
||||
void duct2();
|
||||
void duct4();
|
||||
|
||||
private:
|
||||
void doDuct();
|
||||
void drawArrowSprites();
|
||||
void drawArrowSprites2();
|
||||
void clearWorkScreenArea();
|
||||
void copyBufBlockToScreen();
|
||||
void waitForMoveUpdate();
|
||||
void storeLastValsToPrimArray(const Point3 &pt1, const Point3 &pt2);
|
||||
void updatePlayerPos();
|
||||
void updateMatrix();
|
||||
void applyMatrixToMapData();
|
||||
void updatePrimsAndDraw();
|
||||
bool updateMapLocation();
|
||||
void checkFinished();
|
||||
void doMatrixMulAndAddPoint(int16 x, int16 y, int16 z);
|
||||
bool doPrimArrayUpdates(int &tempIdx);
|
||||
void doDraw(int counter);
|
||||
|
||||
void getPointValuesFromArray(int offset, Point3 &pt1, Point3 &pt2) const;
|
||||
Common::Rect calcFinalLineSegment(const Point3 &pt1, const Point3 &pt2) const;
|
||||
|
||||
bool checkAndUpdatePrimArray1(int &offset);
|
||||
bool checkAndUpdatePrimArray2(int &offset);
|
||||
bool checkAndUpdatePrimArray3(int &offset);
|
||||
bool checkAndUpdatePrimArray4(int &offset);
|
||||
bool checkAndUpdatePrimArray5(int &offset);
|
||||
bool checkAndUpdatePrimArrayForFlag(int &offset, DuctFlags flag, int divmulNum);
|
||||
|
||||
static Point3 divmul1(const Point3 &pt1, const Point3 &pt2);
|
||||
static Point3 divmul2(const Point3 &pt1, const Point3 &pt2);
|
||||
static Point3 divmul3(const Point3 &pt1, const Point3 &pt2);
|
||||
static Point3 divmul4(const Point3 &pt1, const Point3 &pt2);
|
||||
static Point3 divmul5(const Point3 &pt1, const Point3 &pt2);
|
||||
|
||||
bool checkMove0();
|
||||
bool checkMove1();
|
||||
bool checkMove2();
|
||||
bool checkMove3();
|
||||
bool checkMove4();
|
||||
bool checkMove5();
|
||||
bool checkMove6();
|
||||
bool checkMove7();
|
||||
bool checkMove8();
|
||||
bool checkMove9();
|
||||
bool checkMove10();
|
||||
bool checkMove11();
|
||||
bool checkMove12();
|
||||
bool checkMove13_14();
|
||||
|
||||
void getXYandRBFlags(DuctFlags &xyflags, DuctFlags &rbflags, const Point3 &pt1, const Point3 &pt2);
|
||||
int addPointsToMainPrimArray(int tempCount);
|
||||
static DuctFlags getComparisonFlags(int16 x, int16 y, int16 z);
|
||||
|
||||
MartianEngine *_vm;
|
||||
int16 _playerX;
|
||||
int16 _preYOffset;
|
||||
int16 _playerY;
|
||||
|
||||
int16 _nextPlayerX;
|
||||
int16 _nextPlayerY;
|
||||
int16 _xOffset;
|
||||
int16 _yOffset;
|
||||
int16 _xScale;
|
||||
int16 _yScale;
|
||||
uint16 _mapLoc;
|
||||
MoveAngle _moveAngle;
|
||||
int16 _crawlFrame;
|
||||
bool _stopMoveLoop;
|
||||
int16 _threshold1;
|
||||
int16 _drawDistX;
|
||||
int16 _drawDistY;
|
||||
MoveIntent _moveIntent;
|
||||
|
||||
// NOTE: Original uses fixed point sin/cos with a lookup table.
|
||||
float _matrix[3][3];
|
||||
|
||||
int16 _primArrayIdx;
|
||||
|
||||
Common::Array<Point3> _renderPoints;
|
||||
Common::Array<RenderShape> _renderShapes;
|
||||
|
||||
Common::Array<int16> _primX1Array;
|
||||
Common::Array<int16> _primY1Array;
|
||||
Common::Array<int16> _primZ1Array;
|
||||
Common::Array<int16> _primX2Array;
|
||||
Common::Array<int16> _primY2Array;
|
||||
Common::Array<int16> _primZ2Array;
|
||||
Point3 _tempPoints[32];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
} // end namespace Access
|
||||
|
||||
#endif // ACCESS_MARTIAN_MARTIAN_DUCT_H
|
||||
427
engines/access/martian/martian_game.cpp
Normal file
427
engines/access/martian/martian_game.cpp
Normal file
@@ -0,0 +1,427 @@
|
||||
/* 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 "access/resources.h"
|
||||
#include "access/martian/martian_game.h"
|
||||
#include "access/martian/martian_resources.h"
|
||||
#include "access/martian/martian_room.h"
|
||||
#include "access/martian/martian_scripts.h"
|
||||
#include "access/amazon/amazon_resources.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
namespace Martian {
|
||||
|
||||
MartianEngine::MartianEngine(OSystem *syst, const AccessGameDescription *gameDesc) :
|
||||
AccessEngine(syst, gameDesc), _skipStart(false),
|
||||
_creditsStream(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
MartianEngine::~MartianEngine() {
|
||||
_skipStart = false;
|
||||
_creditsStream = nullptr;
|
||||
}
|
||||
|
||||
void MartianEngine::initObjects() {
|
||||
_room = new MartianRoom(this);
|
||||
_scripts = new MartianScripts(this);
|
||||
}
|
||||
|
||||
void MartianEngine::configSelect() {
|
||||
// No implementation required in MM
|
||||
}
|
||||
|
||||
void MartianEngine::initVariables() {
|
||||
// Set player room and position
|
||||
_player->_roomNumber = 7;
|
||||
|
||||
_inventory->_startInvItem = 0;
|
||||
_inventory->_startInvBox = 0;
|
||||
Common::fill(&_objectsTable[0], &_objectsTable[100], (SpriteResource *)nullptr);
|
||||
_player->_playerOff = false;
|
||||
|
||||
setupTimers();
|
||||
|
||||
_player->_playerX = _player->_rawPlayer.x = _res->ROOMTBL[_player->_roomNumber]._travelPos.x;
|
||||
_player->_playerY = _player->_rawPlayer.y = _res->ROOMTBL[_player->_roomNumber]._travelPos.y;
|
||||
_room->_selectCommand = -1;
|
||||
_events->setNormalCursor(CURSOR_CROSSHAIRS);
|
||||
_mouseMode = 0;
|
||||
_animation->clearTimers();
|
||||
|
||||
ARRAYCLEAR(_travel);
|
||||
_travel[7] = 1;
|
||||
|
||||
ARRAYCLEAR(_ask);
|
||||
_ask[33] = 1;
|
||||
|
||||
ARRAYCLEAR(_flags);
|
||||
|
||||
}
|
||||
|
||||
void MartianEngine::setNoteParams() {
|
||||
_events->hideCursor();
|
||||
|
||||
_screen->_orgX1 = 58;
|
||||
_screen->_orgY1 = 124;
|
||||
_screen->_orgX2 = 297;
|
||||
_screen->_orgY2 = 199;
|
||||
_screen->_lColor = 51;
|
||||
_screen->drawRect();
|
||||
|
||||
_events->showCursor();
|
||||
}
|
||||
|
||||
void MartianEngine::displayNote(const Common::String &msg) {
|
||||
_fonts._charSet._lo = 1;
|
||||
_fonts._charSet._hi = 8;
|
||||
_fonts._charFor._lo = 0;
|
||||
_fonts._charFor._hi = 255;
|
||||
Font::_fontColors[3] = 0;
|
||||
|
||||
_screen->_maxChars = 40;
|
||||
_screen->_printOrg = _screen->_printStart = Common::Point(59, 124);
|
||||
|
||||
setNoteParams();
|
||||
|
||||
Common::String lines = msg;
|
||||
Common::String line;
|
||||
int width = 0;
|
||||
bool lastLine = false;
|
||||
do {
|
||||
lastLine = _fonts._font1->getLine(lines, _screen->_maxChars, line, width, Font::kWidthInChars);
|
||||
_bubbleBox->printString(line);
|
||||
_screen->_printOrg = Common::Point(_screen->_printStart.x, _screen->_printOrg.y + 6);
|
||||
|
||||
if (_screen->_printOrg.y == 196) {
|
||||
_events->waitKeyActionMouse();
|
||||
setNoteParams();
|
||||
_screen->_printOrg = _screen->_printStart;
|
||||
}
|
||||
} while (!lastLine);
|
||||
_events->waitKeyActionMouse();
|
||||
}
|
||||
|
||||
void MartianEngine::doSpecial5(int param1) {
|
||||
// Seems redundant to store the song as this is
|
||||
// only ever called from restart or load?
|
||||
debug("TODO: Push midi song?");
|
||||
_midi->stopSong();
|
||||
_midi->setLoop(false);
|
||||
_midi->loadMusic(47, 4);
|
||||
_midi->midiPlay();
|
||||
_screen->setDisplayScan();
|
||||
_events->clearEvents();
|
||||
_screen->forceFadeOut();
|
||||
_events->hideCursor();
|
||||
_files->loadScreen("DATA.SC");
|
||||
_events->showCursor();
|
||||
_screen->setIconPalette();
|
||||
_screen->forceFadeIn();
|
||||
|
||||
Resource *cellsRes = _files->loadFile("CELLS00.LZ");
|
||||
_objectsTable[0] = new SpriteResource(this, cellsRes);
|
||||
delete cellsRes;
|
||||
|
||||
_timers[20]._timer = _timers[20]._initTm = 30;
|
||||
Resource *notesRes = _files->loadFile("NOTES.DAT");
|
||||
notesRes->_stream->skip(param1 * 2);
|
||||
int pos = notesRes->_stream->readUint16LE();
|
||||
notesRes->_stream->seek(pos);
|
||||
Common::String msg = notesRes->_stream->readString();
|
||||
delete notesRes;
|
||||
displayNote(msg);
|
||||
|
||||
_midi->stopSong();
|
||||
_midi->freeMusic();
|
||||
|
||||
_midi->setLoop(true);
|
||||
}
|
||||
|
||||
void MartianEngine::playGame() {
|
||||
// Initialize Martian Memorandum game-specific objects
|
||||
initObjects();
|
||||
|
||||
// Setup the game
|
||||
setupGame();
|
||||
configSelect();
|
||||
|
||||
if (_loadSaveSlot == -1) {
|
||||
// Do introduction
|
||||
doCredits();
|
||||
if (shouldQuit())
|
||||
return;
|
||||
|
||||
// Display Notes screen
|
||||
doSpecial5(4);
|
||||
if (shouldQuit())
|
||||
return;
|
||||
_screen->forceFadeOut();
|
||||
}
|
||||
|
||||
do {
|
||||
_restartFl = false;
|
||||
_screen->clearScreen();
|
||||
_screen->setPanel(0);
|
||||
_screen->forceFadeOut();
|
||||
_events->showCursor();
|
||||
|
||||
initVariables();
|
||||
|
||||
// If there's a pending savegame to load, load it
|
||||
if (_loadSaveSlot != -1) {
|
||||
loadGameState(_loadSaveSlot);
|
||||
_loadSaveSlot = -1;
|
||||
}
|
||||
|
||||
// Execute the room
|
||||
_room->doRoom();
|
||||
} while (_restartFl);
|
||||
}
|
||||
|
||||
bool MartianEngine::showCredits() {
|
||||
_events->hideCursor();
|
||||
_screen->clearScreen();
|
||||
_destIn = _screen;
|
||||
|
||||
int posX = _creditsStream->readSint16LE();
|
||||
int posY = 0;
|
||||
|
||||
while (posX != -1) {
|
||||
posY = _creditsStream->readSint16LE();
|
||||
int frameNum = _creditsStream->readSint16LE();
|
||||
_screen->plotImage(_objectsTable[41], frameNum, Common::Point(posX, posY));
|
||||
|
||||
posX = _creditsStream->readSint16LE();
|
||||
}
|
||||
|
||||
posY = _creditsStream->readSint16LE();
|
||||
if (posY == -1) {
|
||||
_events->showCursor();
|
||||
_screen->forceFadeOut();
|
||||
return true;
|
||||
}
|
||||
|
||||
_screen->forceFadeIn();
|
||||
_timers[3]._timer = _timers[3]._initTm = posY;
|
||||
|
||||
while (!shouldQuit() && !_events->isKeyActionMousePressed() && _timers[3]._timer) {
|
||||
_events->pollEventsAndWait();
|
||||
}
|
||||
|
||||
_events->showCursor();
|
||||
_screen->forceFadeOut();
|
||||
|
||||
if (_events->_rightButton)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void MartianEngine::doCredits() {
|
||||
_midi->setLoop(false);
|
||||
_midi->loadMusic(47, 3);
|
||||
_midi->midiPlay();
|
||||
_screen->setDisplayScan();
|
||||
_events->hideCursor();
|
||||
_screen->forceFadeOut();
|
||||
Resource *data = _files->loadFile(41, 1);
|
||||
_objectsTable[41] = new SpriteResource(this, data);
|
||||
delete data;
|
||||
|
||||
_files->loadScreen(41, 0);
|
||||
_buffer2.copyFrom(*_screen);
|
||||
_buffer1.copyFrom(*_screen);
|
||||
_events->showCursor();
|
||||
_creditsStream = new Common::MemoryReadStream(CREDIT_DATA, 180);
|
||||
|
||||
if (!showCredits()) {
|
||||
_screen->copyFrom(_buffer2);
|
||||
_screen->forceFadeIn();
|
||||
|
||||
_events->_vbCount = 550;
|
||||
while (!shouldQuit() && !_events->isKeyActionMousePressed() && _events->_vbCount > 0)
|
||||
_events->pollEventsAndWait();
|
||||
|
||||
_screen->forceFadeOut();
|
||||
while (!shouldQuit() && !_events->isKeyActionMousePressed()&& !showCredits())
|
||||
_events->pollEventsAndWait();
|
||||
|
||||
delete _objectsTable[41];
|
||||
_objectsTable[41] = nullptr;
|
||||
_midi->freeMusic();
|
||||
}
|
||||
_midi->setLoop(true);
|
||||
}
|
||||
|
||||
void MartianEngine::setupTimers() {
|
||||
_timers.clear();
|
||||
const int TIMER_DEFAULTS[] = { 4, 10, 8, 1, 1, 1, 1, 2 };
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
TimerEntry te;
|
||||
te._initTm = te._timer = (i < 8) ? TIMER_DEFAULTS[i] : 1;
|
||||
te._flag = 1;
|
||||
|
||||
_timers.push_back(te);
|
||||
}
|
||||
}
|
||||
|
||||
void MartianEngine::setupGame() {
|
||||
// Load death list
|
||||
_deaths.resize(_res->DEATHS.size());
|
||||
for (uint idx = 0; idx < _deaths.size(); ++idx) {
|
||||
_deaths[idx]._screenId = _res->DEATHS[idx]._screenId;
|
||||
_deaths[idx]._msg = _res->DEATHS[idx]._msg;
|
||||
}
|
||||
|
||||
setupTimers();
|
||||
|
||||
// Miscellaneous
|
||||
Martian::MartianResources &res = *((Martian::MartianResources *)_res);
|
||||
_fonts.load(res._font1, res._font2, res._bitFont);
|
||||
|
||||
// Set player room and position
|
||||
_player->_roomNumber = 7;
|
||||
_player->_playerX = _player->_rawPlayer.x = _res->ROOMTBL[_player->_roomNumber]._travelPos.x;
|
||||
_player->_playerY = _player->_rawPlayer.y = _res->ROOMTBL[_player->_roomNumber]._travelPos.y;
|
||||
}
|
||||
|
||||
void MartianEngine::showExpositionText(Common::String msg) {
|
||||
Common::String line = "";
|
||||
int width = 0;
|
||||
bool lastLine;
|
||||
do {
|
||||
lastLine = _fonts._font2->getLine(msg, _screen->_maxChars, line, width, Font::kWidthInChars);
|
||||
// Draw the text
|
||||
_bubbleBox->printString(line);
|
||||
|
||||
_screen->_printOrg.y += 6;
|
||||
_screen->_printOrg.x = _screen->_printStart.x;
|
||||
|
||||
if (_screen->_printOrg.y == 180) {
|
||||
_events->waitKeyActionMouse();
|
||||
_screen->copyBuffer(&_buffer2);
|
||||
_screen->_printOrg.y = _screen->_printStart.y;
|
||||
}
|
||||
} while (!lastLine);
|
||||
// Avoid re-using double-click
|
||||
_events->clearEvents();
|
||||
_events->waitKeyActionMouse();
|
||||
}
|
||||
|
||||
void MartianEngine::dead(int deathId) {
|
||||
// Load and display death screen
|
||||
_events->hideCursor();
|
||||
_screen->forceFadeOut();
|
||||
_files->loadScreen(48, _deaths[deathId]._screenId - 1);
|
||||
_screen->setIconPalette();
|
||||
_buffer2.copyBuffer(_screen);
|
||||
_screen->forceFadeIn();
|
||||
_events->showCursor();
|
||||
|
||||
// Setup fonts
|
||||
_fonts._charSet._hi = 10;
|
||||
_fonts._charSet._lo = 1;
|
||||
_fonts._charFor._lo = 247;
|
||||
_fonts._charFor._hi = 255;
|
||||
Font::_fontColors[3] = 247;
|
||||
_screen->_maxChars = 50;
|
||||
_screen->_printOrg = Common::Point(24, 18);
|
||||
_screen->_printStart = Common::Point(24, 18);
|
||||
|
||||
// Display death message
|
||||
showExpositionText(_deaths[deathId]._msg);
|
||||
|
||||
_screen->forceFadeOut();
|
||||
_room->clearRoom();
|
||||
freeChar();
|
||||
|
||||
// The original was jumping to the restart label in main
|
||||
_restartFl = true;
|
||||
_events->pollEvents();
|
||||
}
|
||||
|
||||
void MartianEngine::establish(int estabIndex, int sub) {
|
||||
_fonts._charSet._hi = 10;
|
||||
Font::_fontColors[0] = 0xff;
|
||||
Font::_fontColors[1] = 0xf7;
|
||||
Font::_fontColors[2] = 0xff;
|
||||
Font::_fontColors[3] = 0xf7;
|
||||
|
||||
_screen->_maxChars = 50;
|
||||
_screen->_printOrg = _screen->_printStart = Common::Point(24, 18);
|
||||
|
||||
// TODO: Original has a small delay here.
|
||||
|
||||
Resource *notesRes = _files->loadFile("ETEXT.DAT");
|
||||
notesRes->_stream->seek(2 * sub);
|
||||
uint16 msgOffset = notesRes->_stream->readUint16LE();
|
||||
if (msgOffset == 0 || msgOffset >= notesRes->_stream->size()) {
|
||||
error("MartianEngine::establish: Invalid message offset %d for msg %d", msgOffset, sub);
|
||||
}
|
||||
|
||||
notesRes->_stream->seek(msgOffset);
|
||||
|
||||
Common::String msg = notesRes->_stream->readString();
|
||||
showExpositionText(msg);
|
||||
|
||||
_events->hideCursor();
|
||||
if (sub != 0x3f) {
|
||||
_screen->forceFadeOut();
|
||||
_screen->clearScreen();
|
||||
}
|
||||
|
||||
_events->showCursor();
|
||||
}
|
||||
|
||||
void MartianEngine::synchronize(Common::Serializer &s) {
|
||||
AccessEngine::synchronize(s);
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_travel); i++) {
|
||||
s.syncAsByte(_travel[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(_ask); i++) {
|
||||
s.syncAsByte(_ask[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: Do any of these need to be synchronized here?
|
||||
Mostly involved in modal dialogs.
|
||||
_startTravelItem
|
||||
_startTravelBox
|
||||
_startAboutItem
|
||||
_startAboutBox
|
||||
_byte26CB5
|
||||
_bcnt
|
||||
_boxDataStart
|
||||
_boxDataEnd
|
||||
_boxSelectY
|
||||
_boxSelectYOld
|
||||
_numLines
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
} // End of namespace Martian
|
||||
|
||||
} // End of namespace Access
|
||||
80
engines/access/martian/martian_game.h
Normal file
80
engines/access/martian/martian_game.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/* 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 ACCESS_MARTIAN_GAME_H
|
||||
#define ACCESS_MARTIAN_GAME_H
|
||||
|
||||
#include "access/access.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
namespace Martian {
|
||||
|
||||
class MartianEngine : public AccessEngine {
|
||||
private:
|
||||
bool _skipStart;
|
||||
Common::MemoryReadStream *_creditsStream;
|
||||
|
||||
/**
|
||||
* Do the game introduction
|
||||
*/
|
||||
void doCredits();
|
||||
|
||||
bool showCredits();
|
||||
|
||||
/**
|
||||
* Setup variables for the game
|
||||
*/
|
||||
void setupGame();
|
||||
|
||||
void initObjects();
|
||||
void configSelect();
|
||||
void initVariables();
|
||||
void setupTimers();
|
||||
protected:
|
||||
/**
|
||||
* Play the game
|
||||
*/
|
||||
void playGame() override;
|
||||
|
||||
void dead(int deathId) override;
|
||||
|
||||
void setNoteParams();
|
||||
void displayNote(const Common::String &msg);
|
||||
public:
|
||||
MartianEngine(OSystem *syst, const AccessGameDescription *gameDesc);
|
||||
~MartianEngine() override;
|
||||
|
||||
void doSpecial5(int param1);
|
||||
void showExpositionText(Common::String msg);
|
||||
void establish(int estabIndex, int sub) override;
|
||||
|
||||
/**
|
||||
* Synchronize savegame data
|
||||
*/
|
||||
void synchronize(Common::Serializer &s) override;
|
||||
};
|
||||
|
||||
} // End of namespace Martian
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_MARTIAN_GAME_H */
|
||||
68
engines/access/martian/martian_player.cpp
Normal file
68
engines/access/martian/martian_player.cpp
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "access/access.h"
|
||||
#include "access/room.h"
|
||||
#include "access/martian/martian_game.h"
|
||||
#include "access/martian/martian_player.h"
|
||||
#include "access/martian/martian_resources.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
namespace Martian {
|
||||
|
||||
MartianPlayer::MartianPlayer(AccessEngine *vm) : Player(vm) {
|
||||
_game = (MartianEngine *)vm;
|
||||
}
|
||||
|
||||
void MartianPlayer::load() {
|
||||
Player::load();
|
||||
|
||||
// Overwrite game-specific values
|
||||
_playerOffset.x = _vm->_screen->_scaleTable1[20];
|
||||
_playerOffset.y = _vm->_screen->_scaleTable1[62];
|
||||
_leftDelta = -9;
|
||||
_rightDelta = 33;
|
||||
_upDelta = 5;
|
||||
_downDelta = -5;
|
||||
_scrollConst = 5;
|
||||
|
||||
for (uint8 i = 0; i < _vm->_playerDataCount; ++i) {
|
||||
_walkOffRight[i] = SIDEOFFR[i];
|
||||
_walkOffLeft[i] = SIDEOFFL[i];
|
||||
_walkOffUp[i] = SIDEOFFU[i];
|
||||
_walkOffDown[i] = SIDEOFFD[i];
|
||||
}
|
||||
|
||||
_sideWalkMin = 0;
|
||||
_sideWalkMax = 7;
|
||||
_upWalkMin = 8;
|
||||
_upWalkMax = 14;
|
||||
_downWalkMin = 15;
|
||||
_downWalkMax = 23;
|
||||
|
||||
// playerPalette is configured in Player::load.
|
||||
}
|
||||
|
||||
} // End of namespace Martian
|
||||
|
||||
} // End of namespace Access
|
||||
46
engines/access/martian/martian_player.h
Normal file
46
engines/access/martian/martian_player.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* 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 ACCESS_MARTIAN_PLAYER_H
|
||||
#define ACCESS_MARTIAN_PLAYER_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "access/player.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
namespace Martian {
|
||||
|
||||
class MartianEngine;
|
||||
|
||||
class MartianPlayer : public Player {
|
||||
private:
|
||||
MartianEngine *_game;
|
||||
public:
|
||||
MartianPlayer(AccessEngine *vm);
|
||||
void load() override;
|
||||
};
|
||||
|
||||
} // End of namespace Martian
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_MARTIAN_PLAYER_H */
|
||||
919
engines/access/martian/martian_resources.cpp
Normal file
919
engines/access/martian/martian_resources.cpp
Normal file
File diff suppressed because one or more lines are too long
106
engines/access/martian/martian_resources.h
Normal file
106
engines/access/martian/martian_resources.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/* 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 ACCESS_MARTIAN_RESOURCES_H
|
||||
#define ACCESS_MARTIAN_RESOURCES_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "access/resources.h"
|
||||
#include "access/font.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
namespace Martian {
|
||||
|
||||
extern const int SIDEOFFR[];
|
||||
extern const int SIDEOFFL[];
|
||||
extern const int SIDEOFFU[];
|
||||
extern const int SIDEOFFD[];
|
||||
|
||||
extern const int SIDEOFFR[];
|
||||
extern const int SIDEOFFL[];
|
||||
extern const int SIDEOFFU[];
|
||||
extern const int SIDEOFFD[];
|
||||
|
||||
extern const byte CREDIT_DATA[];
|
||||
extern const byte ICON_PALETTE[];
|
||||
|
||||
extern byte HELP[];
|
||||
extern const char *const ASK_TBL[];
|
||||
extern const char *const TRAVDATA[];
|
||||
|
||||
extern const char *const SPEC7MESSAGE;
|
||||
|
||||
extern const byte CAN_TRAVEL_MATRIX[];
|
||||
extern const int16 PICTURE_RANGE[][2];
|
||||
extern const int16 DUCT_ARROW_BUTTON_RANGE[][2];
|
||||
|
||||
struct DuctMapPoint {
|
||||
int16 ptType;
|
||||
int16 shapeType;
|
||||
int16 x;
|
||||
int16 y;
|
||||
};
|
||||
|
||||
extern const DuctMapPoint DUCT_MAP_DATA[];
|
||||
|
||||
|
||||
struct Point3 {
|
||||
int16 x;
|
||||
int16 y;
|
||||
int16 z;
|
||||
};
|
||||
|
||||
struct DuctShape {
|
||||
int16 numPts;
|
||||
int16 array2Len;
|
||||
const Point3 *points;
|
||||
const uint16 *data;
|
||||
};
|
||||
|
||||
extern const DuctShape *DUCT_SHAPE_DATA[];
|
||||
|
||||
class MartianResources : public Resources {
|
||||
protected:
|
||||
/**
|
||||
* Load data from the access.dat file
|
||||
*/
|
||||
void load(Common::SeekableReadStream &s) override;
|
||||
public:
|
||||
MartianFont *_font1;
|
||||
MartianFont *_font2;
|
||||
MartianBitFont *_bitFont;
|
||||
public:
|
||||
MartianResources(AccessEngine *vm) : Resources(vm), _font1(nullptr), _font2(nullptr), _bitFont(nullptr) {}
|
||||
~MartianResources() override;
|
||||
|
||||
const byte *getCursor(int num) const override;
|
||||
const char *getEgoName() const override { return "TEX"; }
|
||||
int getRMouse(int i, int j) const override;
|
||||
int inButtonXRange(int x) const override;
|
||||
};
|
||||
|
||||
#define MMRES (*((Martian::MartianResources *)_vm->_res))
|
||||
|
||||
} // End of namespace Martian
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_MARTIAN_RESOURCES_H */
|
||||
136
engines/access/martian/martian_room.cpp
Normal file
136
engines/access/martian/martian_room.cpp
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "access/access.h"
|
||||
#include "access/resources.h"
|
||||
#include "access/martian/martian_game.h"
|
||||
#include "access/martian/martian_resources.h"
|
||||
#include "access/martian/martian_room.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
namespace Martian {
|
||||
|
||||
MartianRoom::MartianRoom(AccessEngine *vm) : Room(vm) {
|
||||
_game = (MartianEngine *)vm;
|
||||
|
||||
for (int i = 0; i < 30; i++)
|
||||
_vm->_flags[200 + i] = 0;
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
_vm->_flags[178 + i] = 0;
|
||||
}
|
||||
|
||||
MartianRoom::~MartianRoom() {
|
||||
}
|
||||
|
||||
void MartianRoom::loadRoom(int roomNumber) {
|
||||
loadRoomData(&MMRES.ROOMTBL[roomNumber]._data[0]);
|
||||
}
|
||||
|
||||
void MartianRoom::reloadRoom() {
|
||||
// _vm->_currentMan = _roomFlag;
|
||||
// _vm->_currentManOld = _roomFlag;
|
||||
// _vm->_manScaleOff = 0;
|
||||
|
||||
_vm->_player->loadTexPalette();
|
||||
_vm->_player->loadSprites("TEX.LZ");
|
||||
|
||||
loadRoom(_vm->_player->_roomNumber);
|
||||
|
||||
reloadRoom1();
|
||||
}
|
||||
|
||||
void MartianRoom::reloadRoom1() {
|
||||
_selectCommand = -1;
|
||||
_vm->_boxSelect = false; //-1
|
||||
_vm->_player->_playerOff = false;
|
||||
|
||||
_vm->_screen->forceFadeOut();
|
||||
_vm->_events->hideCursor();
|
||||
_vm->_screen->clearScreen();
|
||||
_vm->_events->showCursor();
|
||||
roomInit();
|
||||
_vm->_player->load();
|
||||
|
||||
if (_vm->_player->_roomNumber != 47)
|
||||
_vm->_player->calcManScale();
|
||||
|
||||
_vm->_events->hideCursor();
|
||||
roomMenu();
|
||||
_vm->_screen->setBufferScan();
|
||||
setupRoom();
|
||||
setWallCodes();
|
||||
buildScreen();
|
||||
_vm->copyBF2Vid();
|
||||
|
||||
_vm->_screen->setManPalette();
|
||||
_vm->_events->showCursor();
|
||||
_vm->_player->_frame = 0;
|
||||
_vm->_oldRects.clear();
|
||||
_vm->_newRects.clear();
|
||||
_vm->_events->clearEvents();
|
||||
}
|
||||
|
||||
void MartianRoom::roomInit() {
|
||||
Room::roomInit();
|
||||
|
||||
for (int i = 0; i < 30; i++)
|
||||
_vm->_flags[200 + i] = 0;
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
_vm->_flags[178 + i] = 0;
|
||||
}
|
||||
|
||||
void MartianRoom::roomMenu() {
|
||||
const SpriteResource *icons = _vm->getIcons();
|
||||
|
||||
_vm->_screen->saveScreen();
|
||||
_vm->_screen->setDisplayScan();
|
||||
_vm->_destIn = _vm->_screen; // TODO: Redundant
|
||||
_vm->_screen->plotImage(icons, 0, Common::Point(5, 184));
|
||||
_vm->_screen->plotImage(icons, 1, Common::Point(155, 184));
|
||||
|
||||
_vm->_screen->restoreScreen();
|
||||
}
|
||||
|
||||
void MartianRoom::mainAreaClick() {
|
||||
Common::Point &mousePos = _vm->_events->_mousePos;
|
||||
Common::Point pt = _vm->_events->calcRawMouse();
|
||||
Screen &screen = *_vm->_screen;
|
||||
Player &player = *_vm->_player;
|
||||
|
||||
if (_selectCommand == -1) {
|
||||
player._moveTo = pt;
|
||||
player._playerMove = true;
|
||||
} else if (mousePos.x >= screen._windowXAdd &&
|
||||
mousePos.x <= (screen._windowXAdd + screen._vWindowBytesWide) &&
|
||||
mousePos.y >= screen._windowYAdd &&
|
||||
mousePos.y <= (screen._windowYAdd + screen._vWindowLinesTall)) {
|
||||
if (checkBoxes1(pt) >= 0) {
|
||||
checkBoxes3();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Martian
|
||||
} // End of namespace Access
|
||||
64
engines/access/martian/martian_room.h
Normal file
64
engines/access/martian/martian_room.h
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ACCESS_MARTIAN_ROOM_H
|
||||
#define ACCESS_MARTIAN_ROOM_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "access/room.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
class AccessEngine;
|
||||
|
||||
namespace Martian {
|
||||
|
||||
class MartianEngine;
|
||||
|
||||
class MartianRoom : public Room {
|
||||
private:
|
||||
MartianEngine *_game;
|
||||
|
||||
protected:
|
||||
void loadRoom(int roomNumber) override;
|
||||
|
||||
void roomInit() override;
|
||||
|
||||
void reloadRoom() override;
|
||||
|
||||
void reloadRoom1() override;
|
||||
|
||||
void mainAreaClick() override;
|
||||
public:
|
||||
MartianRoom(AccessEngine *vm);
|
||||
|
||||
~MartianRoom() override;
|
||||
|
||||
void init4Quads() override { }
|
||||
|
||||
void roomMenu() override;
|
||||
};
|
||||
|
||||
} // End of namespace Martian
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_AMAZON_ROOM_H */
|
||||
383
engines/access/martian/martian_scripts.cpp
Normal file
383
engines/access/martian/martian_scripts.cpp
Normal file
@@ -0,0 +1,383 @@
|
||||
/* 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 "common/scummsys.h"
|
||||
#include "access/access.h"
|
||||
#include "access/martian/martian_game.h"
|
||||
#include "access/martian/martian_resources.h"
|
||||
#include "access/martian/martian_duct.h"
|
||||
#include "access/martian/martian_scripts.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
namespace Martian {
|
||||
|
||||
MartianScripts::MartianScripts(AccessEngine *vm) : Scripts(vm) {
|
||||
_game = (MartianEngine *)_vm;
|
||||
_duct = new MartianDuct(_game);
|
||||
}
|
||||
|
||||
MartianScripts::~MartianScripts() {
|
||||
delete _duct;
|
||||
}
|
||||
|
||||
void MartianScripts::cmdSpecial0() {
|
||||
// Abduction scene
|
||||
_vm->_sound->stopSound();
|
||||
_vm->_midi->stopSong();
|
||||
|
||||
_vm->_midi->loadMusic(47, 1);
|
||||
_vm->_midi->midiPlay();
|
||||
_vm->_midi->setLoop(true);
|
||||
|
||||
_vm->_screen->forceFadeOut();
|
||||
_vm->_files->loadScreen("HOUSE.SC");
|
||||
|
||||
_vm->_video->setVideo(_vm->_screen, Common::Point(46, 30), "HVID.VID", 20);
|
||||
|
||||
_vm->_events->hideCursor();
|
||||
_vm->_events->_vbCount = 300;
|
||||
while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0)
|
||||
_vm->_events->pollEventsAndWait();
|
||||
|
||||
do {
|
||||
_vm->_video->playVideo();
|
||||
_vm->_events->pollEvents();
|
||||
if (_vm->_video->_videoFrame == 4) {
|
||||
_vm->_screen->flashPalette(16);
|
||||
_vm->_sound->playSound(4);
|
||||
do {
|
||||
_vm->_events->pollEvents();
|
||||
} while (!_vm->shouldQuit() && _vm->_sound->isSFXPlaying());
|
||||
//
|
||||
// TODO:
|
||||
//
|
||||
// The original sets these, probably to hold the video until the sound finishes?
|
||||
// But, if we do that they never get past frame 4, because in the next iteration
|
||||
// of the loop the timer is still "counting down", so we stay on frame 4 forever.
|
||||
//
|
||||
// Need to double-check the exact flow of the original here.
|
||||
//
|
||||
//_vm->_timers[31]._timer = _vm->_timers[31]._initTm = 40;
|
||||
}
|
||||
} while (!_vm->_video->_videoEnd && !_vm->shouldQuit());
|
||||
|
||||
if (_vm->shouldQuit())
|
||||
return;
|
||||
|
||||
_vm->_screen->flashPalette(12);
|
||||
_vm->_sound->playSound(4);
|
||||
do {
|
||||
_vm->_events->pollEvents();
|
||||
} while (!_vm->shouldQuit() && _vm->_sound->isSFXPlaying());
|
||||
|
||||
_vm->_events->showCursor();
|
||||
_vm->_midi->stopSong();
|
||||
_vm->_midi->freeMusic();
|
||||
}
|
||||
|
||||
void MartianScripts::cmdSpecial1(int param1, int param2) {
|
||||
//
|
||||
// Special 1 is a scene transition with some explanatory text
|
||||
//
|
||||
_vm->_events->hideCursor();
|
||||
|
||||
if ((byte)param1 != (byte)-1) {
|
||||
_vm->_files->loadScreen(49, param1);
|
||||
_vm->_buffer2.copyBuffer(_vm->_screen);
|
||||
}
|
||||
|
||||
_vm->_screen->setIconPalette();
|
||||
_vm->_screen->forceFadeIn();
|
||||
_vm->_events->showCursor();
|
||||
|
||||
_vm->establish(0, param2);
|
||||
}
|
||||
|
||||
void MartianScripts::cmdSpecial2() {
|
||||
_duct->duct2();
|
||||
}
|
||||
|
||||
void MartianScripts::cmdSpecial3() {
|
||||
_vm->_screen->forceFadeOut();
|
||||
_vm->_events->hideCursor();
|
||||
_vm->_files->loadScreen(57, 3);
|
||||
_vm->_buffer2.copyFrom(*_vm->_screen);
|
||||
|
||||
_vm->_screen->setIconPalette();
|
||||
_vm->_events->showCursor();
|
||||
_vm->_screen->forceFadeIn();
|
||||
}
|
||||
|
||||
void MartianScripts::cmdSpecial4() {
|
||||
_duct->duct4();
|
||||
}
|
||||
|
||||
void MartianScripts::doIntro(int param1) {
|
||||
_game->doSpecial5(param1);
|
||||
}
|
||||
|
||||
void MartianScripts::cmdSpecial6() {
|
||||
// A special transition screen after the jetpack in the outpost.
|
||||
debug("cmdSpecial6: TODO: Store current music?");
|
||||
_vm->_midi->stopSong();
|
||||
_vm->_screen->setDisplayScan();
|
||||
_vm->_events->clearEvents();
|
||||
_vm->_screen->forceFadeOut();
|
||||
_vm->_events->hideCursor();
|
||||
_vm->_files->loadScreen(49, 9);
|
||||
_vm->_events->showCursor();
|
||||
_vm->_screen->setIconPalette();
|
||||
_vm->_screen->forceFadeIn();
|
||||
|
||||
Resource *cellsRes = _vm->_files->loadFile("CELLS00.LZ");
|
||||
_vm->_objectsTable[0] = new SpriteResource(_vm, cellsRes);
|
||||
delete cellsRes;
|
||||
|
||||
_vm->_timers[20]._timer = _vm->_timers[20]._initTm = 30;
|
||||
_vm->_fonts._charSet._lo = 1;
|
||||
_vm->_fonts._charSet._hi = 10;
|
||||
_vm->_fonts._charFor._lo = 1;
|
||||
_vm->_fonts._charFor._hi = 255;
|
||||
|
||||
_vm->_screen->_maxChars = 50;
|
||||
_vm->_screen->_printOrg = _vm->_screen->_printStart = Common::Point(24, 18);
|
||||
|
||||
Resource *notesRes = _vm->_files->loadFile("ETEXT.DAT");
|
||||
notesRes->_stream->seek(72);
|
||||
uint16 offset = notesRes->_stream->readUint16LE();
|
||||
notesRes->_stream->seek(offset);
|
||||
|
||||
// Read the message
|
||||
Common::String msg = notesRes->_stream->readString();
|
||||
|
||||
//display the message
|
||||
_game->showExpositionText(msg);
|
||||
|
||||
delete notesRes;
|
||||
delete _vm->_objectsTable[0];
|
||||
_vm->_objectsTable[0] = nullptr;
|
||||
_vm->_midi->stopSong();
|
||||
|
||||
// WORKAROUND: Reset Tex's scale flag after jetpack.
|
||||
// (bug also present in original game)
|
||||
_vm->_player->_flags &= ~IMGFLAG_UNSCALED;
|
||||
|
||||
// We always go straight to another scene so this seems
|
||||
// redundant..
|
||||
debug("cmdSpecial6: TODO: Restore original music?");
|
||||
}
|
||||
|
||||
void MartianScripts::cmdSpecial7() {
|
||||
_vm->_room->clearRoom();
|
||||
_vm->_midi->loadMusic(47, 8);
|
||||
|
||||
_vm->_sound->freeSounds();
|
||||
Resource *sound = _vm->_sound->loadSound(46, 14);
|
||||
_vm->_sound->_soundTable.push_back(SoundEntry(sound, 1));
|
||||
|
||||
_vm->_screen->setDisplayScan();
|
||||
_vm->_screen->forceFadeOut();
|
||||
_vm->_events->hideCursor();
|
||||
|
||||
_vm->_files->loadScreen(40, 3);
|
||||
_vm->_buffer1.copyBuffer(_vm->_screen);
|
||||
_vm->_buffer2.copyBuffer(_vm->_screen);
|
||||
|
||||
_vm->_events->showCursor();
|
||||
_vm->_screen->setIconPalette();
|
||||
_vm->_screen->forceFadeIn();
|
||||
|
||||
// Load objects specific to this special scene
|
||||
Resource *data = _vm->_files->loadFile(40, 2);
|
||||
_game->_objectsTable[40] = new SpriteResource(_vm, data);
|
||||
delete data;
|
||||
|
||||
// Load animation data
|
||||
_vm->_animation->freeAnimationData();
|
||||
Resource *animResource = _vm->_files->loadFile(40, 1);
|
||||
_vm->_animation->loadAnimations(animResource);
|
||||
delete animResource;
|
||||
|
||||
// Load script
|
||||
Resource *newScript = _vm->_files->loadFile(40, 0);
|
||||
setScript(newScript);
|
||||
|
||||
_vm->_images.clear();
|
||||
_vm->_oldRects.clear();
|
||||
_sequence = 0;
|
||||
searchForSequence();
|
||||
executeScript();
|
||||
_vm->_sound->playSound(0);
|
||||
|
||||
do {
|
||||
charLoop();
|
||||
_vm->_events->pollEvents();
|
||||
} while (_vm->_flags[134] != 1);
|
||||
|
||||
do {
|
||||
_vm->_events->pollEvents();
|
||||
} while (!_vm->shouldQuit() && _vm->_sound->isSFXPlaying());
|
||||
|
||||
_vm->_animation->clearTimers();
|
||||
_vm->_animation->freeAnimationData();
|
||||
_vm->_scripts->freeScriptData();
|
||||
_vm->_sound->freeSounds();
|
||||
|
||||
_vm->_screen->forceFadeOut();
|
||||
_vm->_midi->midiPlay();
|
||||
_vm->_midi->setLoop(true);
|
||||
_vm->_events->hideCursor();
|
||||
|
||||
_vm->_files->loadScreen(40, 4);
|
||||
_vm->_buffer1.copyBuffer(_vm->_screen);
|
||||
_vm->_buffer2.copyBuffer(_vm->_screen);
|
||||
|
||||
_vm->_events->showCursor();
|
||||
_vm->_screen->setIconPalette();
|
||||
_vm->_screen->forceFadeIn();
|
||||
|
||||
// Setup fonts
|
||||
_vm->_fonts._charSet._hi = 10;
|
||||
_vm->_fonts._charSet._lo = 1;
|
||||
_vm->_fonts._charFor._lo = 247;
|
||||
_vm->_fonts._charFor._hi = 255;
|
||||
_vm->_screen->_maxChars = 50;
|
||||
_vm->_screen->_printOrg = Common::Point(24, 18);
|
||||
_vm->_screen->_printStart = Common::Point(24, 18);
|
||||
|
||||
_game->showExpositionText(Common::String(SPEC7MESSAGE));
|
||||
|
||||
_vm->_events->showCursor();
|
||||
_vm->_screen->copyBuffer(&_vm->_buffer1);
|
||||
_vm->_events->hideCursor();
|
||||
|
||||
_vm->_video->setVideo(_vm->_screen, Common::Point(120, 16), FileIdent(40, 5), 10);
|
||||
|
||||
while (!_vm->shouldQuit() && !_vm->_video->_videoEnd) {
|
||||
_vm->_video->playVideo();
|
||||
_vm->_events->pollEventsAndWait();
|
||||
}
|
||||
|
||||
_vm->_sound->freeSounds();
|
||||
sound = _vm->_sound->loadSound(40, 8);
|
||||
_vm->_sound->_soundTable.push_back(SoundEntry(sound, 1));
|
||||
sound = _vm->_sound->loadSound(40, 9);
|
||||
_vm->_sound->_soundTable.push_back(SoundEntry(sound, 1));
|
||||
sound = _vm->_sound->loadSound(40, 10);
|
||||
_vm->_sound->_soundTable.push_back(SoundEntry(sound, 1));
|
||||
|
||||
_vm->_screen->forceFadeOut();
|
||||
_vm->_files->loadScreen(40, 7);
|
||||
_vm->_destIn = _vm->_screen;
|
||||
|
||||
_vm->_screen->plotImage(_game->_objectsTable[40], 8, Common::Point(176, 104));
|
||||
_vm->_screen->plotImage(_game->_objectsTable[40], 7, Common::Point(160, 102));
|
||||
_vm->_events->showCursor();
|
||||
_vm->_screen->forceFadeIn();
|
||||
|
||||
_vm->_events->_vbCount = 100;
|
||||
while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0)
|
||||
_vm->_events->pollEventsAndWait();
|
||||
|
||||
_vm->_sound->playSound(0);
|
||||
do {
|
||||
_vm->_events->pollEvents();
|
||||
} while (!_vm->shouldQuit() && _vm->_sound->isSFXPlaying());
|
||||
|
||||
_vm->_events->_vbCount = 80;
|
||||
while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0)
|
||||
_vm->_events->pollEventsAndWait();
|
||||
|
||||
_vm->_sound->playSound(1);
|
||||
do {
|
||||
_vm->_events->pollEvents();
|
||||
} while (!_vm->shouldQuit() && _vm->_sound->isSFXPlaying());
|
||||
|
||||
_vm->_events->_vbCount = 80;
|
||||
while (!_vm->shouldQuit() && _vm->_events->_vbCount > 0)
|
||||
_vm->_events->pollEventsAndWait();
|
||||
|
||||
_vm->_sound->playSound(2);
|
||||
do {
|
||||
_vm->_events->pollEvents();
|
||||
} while (!_vm->shouldQuit() && _vm->_sound->isSFXPlaying());
|
||||
|
||||
_vm->_sound->freeSounds();
|
||||
|
||||
delete _game->_objectsTable[40];
|
||||
_game->_objectsTable[40] = nullptr;
|
||||
|
||||
_vm->_events->hideCursor();
|
||||
_vm->_screen->forceFadeOut();
|
||||
_vm->_files->loadScreen(40, 6);
|
||||
_vm->_events->showCursor();
|
||||
_vm->_screen->forceFadeIn();
|
||||
|
||||
_vm->_events->waitKeyActionMouse();
|
||||
_vm->_midi->stopSong();
|
||||
_vm->_midi->freeMusic();
|
||||
|
||||
// The original was jumping to the restart label in main
|
||||
_vm->_restartFl = true;
|
||||
_vm->_events->pollEvents();
|
||||
}
|
||||
|
||||
void MartianScripts::executeSpecial(int commandIndex, int param1, int param2) {
|
||||
switch (commandIndex) {
|
||||
case 0:
|
||||
cmdSpecial0();
|
||||
break;
|
||||
case 1:
|
||||
cmdSpecial1(param1, param2);
|
||||
break;
|
||||
case 2:
|
||||
cmdSpecial2();
|
||||
break;
|
||||
case 3:
|
||||
cmdSpecial3();
|
||||
break;
|
||||
case 4:
|
||||
cmdSpecial4();
|
||||
break;
|
||||
case 5:
|
||||
doIntro(param1);
|
||||
break;
|
||||
case 6:
|
||||
cmdSpecial6();
|
||||
break;
|
||||
case 7:
|
||||
cmdSpecial7();
|
||||
break;
|
||||
default:
|
||||
warning("Unexpected Special code %d - Skipped", commandIndex);
|
||||
}
|
||||
}
|
||||
|
||||
typedef void(MartianScripts::*MartianScriptMethodPtr)();
|
||||
|
||||
void MartianScripts::executeCommand(int commandIndex) {
|
||||
Scripts::executeCommand(commandIndex);
|
||||
}
|
||||
|
||||
} // End of namespace Martian
|
||||
|
||||
} // End of namespace Access
|
||||
62
engines/access/martian/martian_scripts.h
Normal file
62
engines/access/martian/martian_scripts.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/* 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 ACCESS_MARTIAN_SCRIPTS_H
|
||||
#define ACCESS_MARTIAN_SCRIPTS_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "access/scripts.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
namespace Martian {
|
||||
|
||||
class MartianEngine;
|
||||
class MartianDuct;
|
||||
|
||||
class MartianScripts : public Scripts {
|
||||
private:
|
||||
MartianEngine *_game;
|
||||
MartianDuct *_duct;
|
||||
|
||||
void cmdSpecial0();
|
||||
void cmdSpecial1(int param1, int param2);
|
||||
void cmdSpecial2();
|
||||
void cmdSpecial3();
|
||||
void cmdSpecial4();
|
||||
void doIntro(int param1);
|
||||
void cmdSpecial6();
|
||||
void cmdSpecial7();
|
||||
|
||||
protected:
|
||||
void executeSpecial(int commandIndex, int param1, int param2) override;
|
||||
void executeCommand(int commandIndex) override;
|
||||
|
||||
public:
|
||||
MartianScripts(AccessEngine *vm);
|
||||
~MartianScripts();
|
||||
};
|
||||
|
||||
} // End of namespace Martian
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_MARTIAN_SCRIPTS_H */
|
||||
207
engines/access/martian/midiparser_bemd.cpp
Normal file
207
engines/access/martian/midiparser_bemd.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
/* 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 "access/martian/midiparser_bemd.h"
|
||||
|
||||
#include "audio/mididrv.h"
|
||||
#include "audio/midiparser.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/util.h"
|
||||
#include "common/file.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
MidiParser_BEmd::MidiParser_BEmd(): _tickData(nullptr), _tickDataEnd(nullptr), _trackDataEnd(nullptr) {
|
||||
}
|
||||
|
||||
bool MidiParser_BEmd::loadMusic(const byte *data, uint32 size) {
|
||||
unloadMusic();
|
||||
const byte *pos = data;
|
||||
|
||||
//
|
||||
// 'BEmd' MIDI format from Martian Memorandum.
|
||||
//
|
||||
// A simple single-track format that splits note and timing data.
|
||||
//
|
||||
// Header is:
|
||||
// 'BEmd' (magic number)
|
||||
// 0xC0 0x00 (unknown, always 0xC0?
|
||||
// 16-bit offset to timing data block
|
||||
// 16-bit size of timing data block
|
||||
// 6 bytes unk (normally 0)
|
||||
// Header is followed by the track data block, then timing delta data
|
||||
// block.
|
||||
//
|
||||
// Track data mostly follows other MIDI formats with a few differences:
|
||||
// * Fixed length arguments
|
||||
// * 0xFF 0x51 (tempo meta event) is followed by a uint16 which is fed
|
||||
// directly to the PIT as a delay
|
||||
// * Deltas are assumed to be 0. On 0xF8, a 16 bit int is read from
|
||||
// the timing block and sent to the PIT as a timing delay.
|
||||
//
|
||||
if (!memcmp(pos, "BEmd", 4)) {
|
||||
pos += 4;
|
||||
if (size <= 16)
|
||||
error("Wrong BEmd music resource size");
|
||||
|
||||
/*uint16 unk1 = */ READ_LE_UINT16(pos); // Normally 0xC0?
|
||||
uint16 secondBlockOffset = READ_LE_UINT16(pos + 2);
|
||||
if (secondBlockOffset < 16 || secondBlockOffset >= size)
|
||||
error("Bad second block offset in BEmd file");
|
||||
uint16 secondBlockSize = READ_LE_UINT16(pos + 4);
|
||||
if (static_cast<uint32>(secondBlockOffset + secondBlockSize) != size)
|
||||
error("Bad second block offset+size in BEmd file");
|
||||
|
||||
_trackDataEnd = data + secondBlockOffset;
|
||||
_tickData = _trackDataEnd;
|
||||
_tickDataEnd = data + size;
|
||||
|
||||
// Only one track
|
||||
_numTracks = 1;
|
||||
_numSubtracks[0] = 1;
|
||||
_autoLoop = false;
|
||||
_ppqn = 1;
|
||||
_tracks[0][0] = data + 16;
|
||||
|
||||
resetTracking();
|
||||
setTempo(16667);
|
||||
setTrack(0);
|
||||
return true;
|
||||
} else {
|
||||
warning("Expected BEmd header but found '%c%c%c%c' instead", pos[0], pos[1], pos[2], pos[3]);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void MidiParser_BEmd::parseNextEvent(EventInfo &info) {
|
||||
uint8 subtrack = info.subtrack;
|
||||
const byte *playPos = _position._subtracks[subtrack]._playPos;
|
||||
info.start = playPos;
|
||||
|
||||
info.delta = 0;
|
||||
|
||||
// Process the next info.
|
||||
if ((playPos[0] & 0xF0) >= 0x80)
|
||||
info.event = *(playPos++);
|
||||
else
|
||||
info.event = _position._subtracks[subtrack]._runningStatus;
|
||||
if (info.event < 0x80) {
|
||||
_position._subtracks[subtrack]._playPos = playPos;
|
||||
return;
|
||||
}
|
||||
|
||||
_position._subtracks[subtrack]._runningStatus = info.event;
|
||||
switch (info.command()) {
|
||||
case 0x9: // Note On
|
||||
info.basic.param1 = *(playPos++);
|
||||
info.basic.param2 = *(playPos++);
|
||||
if (info.basic.param2 == 0)
|
||||
info.event = info.channel() | 0x80;
|
||||
info.length = 0;
|
||||
break;
|
||||
|
||||
case 0xC:
|
||||
case 0xD:
|
||||
info.basic.param1 = *(playPos++);
|
||||
info.basic.param2 = 0;
|
||||
break;
|
||||
|
||||
case 0x8:
|
||||
case 0xA:
|
||||
case 0xB:
|
||||
case 0xE:
|
||||
info.basic.param1 = *(playPos++);
|
||||
info.basic.param2 = *(playPos++);
|
||||
info.length = 0;
|
||||
break;
|
||||
|
||||
case 0xF:
|
||||
switch (info.event & 0x0F) {
|
||||
case 0x2: // Song Position Pointer
|
||||
info.basic.param1 = *(playPos++);
|
||||
info.basic.param2 = *(playPos++);
|
||||
break;
|
||||
|
||||
case 0x3: // Song Select
|
||||
info.basic.param1 = *(playPos++);
|
||||
info.basic.param2 = 0;
|
||||
break;
|
||||
|
||||
case 0x8: // Timing data
|
||||
// Tick data is stored separately.
|
||||
info.delta = READ_LE_UINT16(_tickData);
|
||||
_tickData += 2;
|
||||
// FALL THROUGH
|
||||
case 0x6:
|
||||
case 0xA:
|
||||
case 0xB:
|
||||
case 0xC:
|
||||
case 0xE:
|
||||
info.basic.param1 = info.basic.param2 = 0;
|
||||
break;
|
||||
|
||||
case 0x0: // SysEx
|
||||
error("MidiParser_BEmd::parseNextEvent: Unexpected SysEx event");
|
||||
break;
|
||||
|
||||
case 0xF: // META event
|
||||
info.ext.type = *(playPos++);
|
||||
if (info.ext.type == 0x51) {
|
||||
// Set Tempo - 2 bytes and interpreted as direct input for the PIT
|
||||
// as ticks to next note (0.8381uS/tick)
|
||||
setTempo(READ_LE_UINT16(playPos) * 0.8381);
|
||||
}
|
||||
info.length = (info.ext.type == 0x2f ? 0 : 2);
|
||||
info.ext.data = playPos;
|
||||
playPos += info.length;
|
||||
break;
|
||||
|
||||
default:
|
||||
error("MidiParser_BEmd::parseNextEvent: Unsupported event code %x", info.event);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
_position._subtracks[subtrack]._playPos = playPos;
|
||||
|
||||
assert(playPos < _trackDataEnd);
|
||||
assert(_tickData < _tickDataEnd);
|
||||
}
|
||||
|
||||
bool MidiParser_BEmd::processEvent(const EventInfo &info, bool fireEvents) {
|
||||
// Ignore timer events we handled already.
|
||||
if ((info.event == 0xF8) || (info.event == 0xFF && info.ext.type == 0x51))
|
||||
return true;
|
||||
return MidiParser::processEvent(info, fireEvents);
|
||||
}
|
||||
|
||||
void MidiParser_BEmd::resetTracking() {
|
||||
_tickData = _trackDataEnd;
|
||||
MidiParser::resetTracking();
|
||||
}
|
||||
|
||||
} // end namespace Access
|
||||
49
engines/access/martian/midiparser_bemd.h
Normal file
49
engines/access/martian/midiparser_bemd.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/* 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 ACCESS_MARTIAN_MIDI_PARSER_BEMD_H
|
||||
#define ACCESS_MARTIAN_MIDI_PARSER_BEMD_H
|
||||
|
||||
#include "audio/midiparser.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
class MidiParser_BEmd : public MidiParser {
|
||||
public:
|
||||
MidiParser_BEmd();
|
||||
|
||||
bool loadMusic(const byte *data, uint32 size) override;
|
||||
|
||||
protected:
|
||||
void parseNextEvent(EventInfo &info) override;
|
||||
bool processEvent(const EventInfo &info, bool fireEvents) override;
|
||||
void resetTracking() override;
|
||||
|
||||
private:
|
||||
const byte *_trackDataEnd;
|
||||
const byte *_tickData;
|
||||
const byte *_tickDataEnd;
|
||||
|
||||
};
|
||||
|
||||
} // end namespace Access
|
||||
|
||||
#endif // ACCESS_MARTIAN_MIDI_PARSER_BEMD_H
|
||||
360
engines/access/metaengine.cpp
Normal file
360
engines/access/metaengine.cpp
Normal file
@@ -0,0 +1,360 @@
|
||||
/* 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 "common/savefile.h"
|
||||
#include "common/system.h"
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "access/access.h"
|
||||
#include "access/amazon/amazon_game.h"
|
||||
#include "access/martian/martian_game.h"
|
||||
|
||||
#include "access/detection.h"
|
||||
|
||||
#include "backends/keymapper/action.h"
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
#include "backends/keymapper/standard-actions.h"
|
||||
|
||||
#include "common/translation.h"
|
||||
|
||||
#define MAX_SAVES 99
|
||||
|
||||
namespace Access {
|
||||
|
||||
uint32 AccessEngine::getGameID() const {
|
||||
return _gameDescription->gameID;
|
||||
}
|
||||
|
||||
uint32 AccessEngine::getGameFeatures() const {
|
||||
return _gameDescription->features;
|
||||
}
|
||||
|
||||
uint32 AccessEngine::getFeatures() const {
|
||||
return _gameDescription->desc.flags;
|
||||
}
|
||||
|
||||
bool AccessEngine::isCD() const {
|
||||
return (bool)(_gameDescription->desc.flags & ADGF_CD);
|
||||
}
|
||||
|
||||
bool AccessEngine::isDemo() const {
|
||||
return (bool)(_gameDescription->desc.flags & ADGF_DEMO);
|
||||
}
|
||||
|
||||
Common::Language AccessEngine::getLanguage() const {
|
||||
return _gameDescription->desc.language;
|
||||
}
|
||||
|
||||
Common::Platform AccessEngine::getPlatform() const {
|
||||
return _gameDescription->desc.platform;
|
||||
}
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
class AccessMetaEngine : public AdvancedMetaEngine<Access::AccessGameDescription> {
|
||||
public:
|
||||
const char *getName() const override {
|
||||
return "access";
|
||||
}
|
||||
|
||||
bool hasFeature(MetaEngineFeature f) const override;
|
||||
|
||||
Common::Error createInstance(OSystem *syst, Engine **engine, const Access::AccessGameDescription *desc) const override;
|
||||
|
||||
SaveStateList listSaves(const char *target) const override;
|
||||
int getMaximumSaveSlot() const override;
|
||||
bool removeSaveState(const char *target, int slot) const override;
|
||||
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override;
|
||||
Common::KeymapArray initKeymaps(const char *target) const override;
|
||||
};
|
||||
|
||||
bool AccessMetaEngine::hasFeature(MetaEngineFeature f) const {
|
||||
return
|
||||
(f == kSupportsListSaves) ||
|
||||
(f == kSupportsLoadingDuringStartup) ||
|
||||
(f == kSupportsDeleteSave) ||
|
||||
(f == kSavesSupportMetaInfo) ||
|
||||
(f == kSavesSupportThumbnail) ||
|
||||
(f == kSimpleSavesNames);
|
||||
}
|
||||
|
||||
bool Access::AccessEngine::hasFeature(EngineFeature f) const {
|
||||
return
|
||||
(f == kSupportsReturnToLauncher) ||
|
||||
(f == kSupportsLoadingDuringRuntime) ||
|
||||
(f == kSupportsSavingDuringRuntime);
|
||||
}
|
||||
|
||||
Common::Error AccessMetaEngine::createInstance(OSystem *syst, Engine **engine, const Access::AccessGameDescription *gd) const {
|
||||
switch (gd->gameID) {
|
||||
case Access::kGameAmazon:
|
||||
*engine = new Access::Amazon::AmazonEngine(syst, gd);
|
||||
break;
|
||||
case Access::kGameMartianMemorandum:
|
||||
*engine = new Access::Martian::MartianEngine(syst, gd);
|
||||
break;
|
||||
default:
|
||||
return Common::kUnsupportedGameidError;
|
||||
}
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
SaveStateList AccessMetaEngine::listSaves(const char *target) const {
|
||||
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
|
||||
Common::String saveDesc;
|
||||
Common::String pattern = Common::String::format("%s.0##", target);
|
||||
Common::StringArray filenames = saveFileMan->listSavefiles(pattern);
|
||||
Access::AccessSavegameHeader header;
|
||||
SaveStateList saveList;
|
||||
|
||||
for (const auto &filename : filenames) {
|
||||
const char *ext = strrchr(filename.c_str(), '.');
|
||||
int slot = ext ? atoi(ext + 1) : -1;
|
||||
|
||||
if (slot >= 0 && slot < MAX_SAVES) {
|
||||
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename);
|
||||
|
||||
if (in) {
|
||||
if (Access::AccessEngine::readSavegameHeader(in, header))
|
||||
saveList.push_back(SaveStateDescriptor(this, slot, header._saveName));
|
||||
|
||||
delete in;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort saves based on slot number.
|
||||
Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
|
||||
return saveList;
|
||||
}
|
||||
|
||||
int AccessMetaEngine::getMaximumSaveSlot() const {
|
||||
return MAX_SAVES;
|
||||
}
|
||||
|
||||
bool AccessMetaEngine::removeSaveState(const char *target, int slot) const {
|
||||
Common::String filename = Common::String::format("%s.%03d", target, slot);
|
||||
return g_system->getSavefileManager()->removeSavefile(filename);
|
||||
}
|
||||
|
||||
SaveStateDescriptor AccessMetaEngine::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) {
|
||||
Access::AccessSavegameHeader header;
|
||||
if (!Access::AccessEngine::readSavegameHeader(f, header, false)) {
|
||||
delete f;
|
||||
return SaveStateDescriptor();
|
||||
}
|
||||
|
||||
delete f;
|
||||
|
||||
// Create the return descriptor
|
||||
SaveStateDescriptor desc(this, slot, header._saveName);
|
||||
desc.setThumbnail(header._thumbnail);
|
||||
desc.setSaveDate(header._year, header._month, header._day);
|
||||
desc.setSaveTime(header._hour, header._minute);
|
||||
desc.setPlayTime(header._totalFrames * GAME_FRAME_TIME);
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
return SaveStateDescriptor();
|
||||
}
|
||||
|
||||
Common::KeymapArray AccessMetaEngine::initKeymaps(const char *target) const {
|
||||
using namespace Common;
|
||||
using namespace Access;
|
||||
|
||||
// Get the game ID for the target
|
||||
const Common::String currDomain = ConfMan.getActiveDomainName();
|
||||
ConfMan.setActiveDomain(target);
|
||||
const Common::String gameId = ConfMan.get("gameid");
|
||||
ConfMan.setActiveDomain(currDomain);
|
||||
|
||||
Keymap *engineKeyMap = new Keymap(Keymap::kKeymapTypeGame, "access-default", _("Default keymappings"));
|
||||
|
||||
Action *act;
|
||||
|
||||
act = new Action(kStandardActionLeftClick, _("Move / Interact / Skip"));
|
||||
act->setLeftClickEvent();
|
||||
act->addDefaultInputMapping("MOUSE_LEFT");
|
||||
act->addDefaultInputMapping("JOY_A");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action(kStandardActionRightClick, _("Skip"));
|
||||
act->setRightClickEvent();
|
||||
act->addDefaultInputMapping("MOUSE_RIGHT");
|
||||
act->addDefaultInputMapping("JOY_B");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("SKIP", _("Skip movie"));
|
||||
act->setCustomEngineActionEvent(kActionSkip);
|
||||
act->addDefaultInputMapping("ESCAPE");
|
||||
act->addDefaultInputMapping("JOY_X");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("UP", _("Move up"));
|
||||
act->setCustomEngineActionEvent(kActionMoveUp);
|
||||
act->addDefaultInputMapping("UP");
|
||||
act->addDefaultInputMapping("KP8");
|
||||
act->addDefaultInputMapping("JOY_UP");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("DOWN", _("Move down"));
|
||||
act->setCustomEngineActionEvent(kActionMoveDown);
|
||||
act->addDefaultInputMapping("DOWN");
|
||||
act->addDefaultInputMapping("KP2");
|
||||
act->addDefaultInputMapping("JOY_DOWN");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("LEFT", _("Move left"));
|
||||
act->setCustomEngineActionEvent(kActionMoveLeft);
|
||||
act->addDefaultInputMapping("LEFT");
|
||||
act->addDefaultInputMapping("KP4");
|
||||
act->addDefaultInputMapping("JOY_LEFT");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("RIGHT", _("Move right"));
|
||||
act->setCustomEngineActionEvent(kActionMoveRight);
|
||||
act->addDefaultInputMapping("RIGHT");
|
||||
act->addDefaultInputMapping("KP6");
|
||||
act->addDefaultInputMapping("JOY_RIGHT");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("UPLEFT", _("Move up-left"));
|
||||
act->setCustomEngineActionEvent(kActionMoveUpLeft);
|
||||
act->addDefaultInputMapping("KP7");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("UPRIGHT", _("Move up-right"));
|
||||
act->setCustomEngineActionEvent(kActionMoveUpRight);
|
||||
act->addDefaultInputMapping("KP9");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("DOWNLEFT", _("Move down-left"));
|
||||
act->setCustomEngineActionEvent(kActionMoveDownLeft);
|
||||
act->addDefaultInputMapping("KP1");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("DOWNRIGHT", _("Move down-right"));
|
||||
act->setCustomEngineActionEvent(kActionMoveDownRight);
|
||||
act->addDefaultInputMapping("KP3");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("LOOK", _("Look"));
|
||||
act->setCustomEngineActionEvent(kActionLook);
|
||||
act->addDefaultInputMapping("F1");
|
||||
if (strcmp(target, "amazon") == 0)
|
||||
act->addDefaultInputMapping("F2");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
if (gameId.equals("martian")) {
|
||||
act = new Action("OPEN", _("Open"));
|
||||
act->setCustomEngineActionEvent(kActionOpen);
|
||||
act->addDefaultInputMapping("F2");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("MOVE", _("Move"));
|
||||
act->setCustomEngineActionEvent(kActionMove);
|
||||
act->addDefaultInputMapping("F3");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("GET", _("Get"));
|
||||
act->setCustomEngineActionEvent(kActionTake);
|
||||
act->addDefaultInputMapping("F4");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("USE", _("Use"));
|
||||
act->setCustomEngineActionEvent(kActionUse);
|
||||
act->addDefaultInputMapping("F5");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("GOTO", _("Goto"));
|
||||
act->setCustomEngineActionEvent(kActionWalk);
|
||||
act->addDefaultInputMapping("F6");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("TALK", _("Talk"));
|
||||
act->setCustomEngineActionEvent(kActionTalk);
|
||||
act->addDefaultInputMapping("F7");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("TRAVEL", _("Travel"));
|
||||
act->setCustomEngineActionEvent(kActionTravel);
|
||||
act->addDefaultInputMapping("F8");
|
||||
engineKeyMap->addAction(act);
|
||||
} else {
|
||||
// Amazon keymaps
|
||||
act = new Action("USE", _("Use"));
|
||||
act->setCustomEngineActionEvent(kActionUse);
|
||||
act->addDefaultInputMapping("F3");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("TAKE", _("Take"));
|
||||
act->setCustomEngineActionEvent(kActionTake);
|
||||
act->addDefaultInputMapping("F4");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("INVENTORY", _("Inventory"));
|
||||
act->setCustomEngineActionEvent(kActionInventory);
|
||||
act->addDefaultInputMapping("F5");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("CLIMB", _("Climb"));
|
||||
act->setCustomEngineActionEvent(kActionClimb);
|
||||
act->addDefaultInputMapping("F6");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("TALK", _("Talk"));
|
||||
act->setCustomEngineActionEvent(kActionTalk);
|
||||
act->addDefaultInputMapping("F7");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("WALK", _("Walk"));
|
||||
act->setCustomEngineActionEvent(kActionWalk);
|
||||
act->addDefaultInputMapping("F8");
|
||||
engineKeyMap->addAction(act);
|
||||
}
|
||||
|
||||
act = new Action("HELP", _("Help"));
|
||||
act->setCustomEngineActionEvent(kActionHelp);
|
||||
act->addDefaultInputMapping("F9");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("SAVELOAD", _("Open save/load menu"));
|
||||
act->setCustomEngineActionEvent(kActionSaveLoad);
|
||||
act->addDefaultInputMapping("F10");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
return Keymap::arrayOf(engineKeyMap);
|
||||
}
|
||||
|
||||
#if PLUGIN_ENABLED_DYNAMIC(ACCESS)
|
||||
REGISTER_PLUGIN_DYNAMIC(ACCESS, PLUGIN_TYPE_ENGINE, AccessMetaEngine);
|
||||
#else
|
||||
REGISTER_PLUGIN_STATIC(ACCESS, PLUGIN_TYPE_ENGINE, AccessMetaEngine);
|
||||
#endif
|
||||
48
engines/access/module.mk
Normal file
48
engines/access/module.mk
Normal file
@@ -0,0 +1,48 @@
|
||||
MODULE := engines/access
|
||||
|
||||
MODULE_OBJS := \
|
||||
access.o \
|
||||
animation.o \
|
||||
asurface.o \
|
||||
bubble_box.o \
|
||||
char.o \
|
||||
data.o \
|
||||
debugger.o \
|
||||
decompress.o \
|
||||
events.o \
|
||||
files.o \
|
||||
font.o \
|
||||
inventory.o \
|
||||
metaengine.o \
|
||||
player.o \
|
||||
resources.o \
|
||||
room.o \
|
||||
screen.o \
|
||||
scripts.o \
|
||||
sound.o \
|
||||
video.o \
|
||||
amazon/amazon_game.o \
|
||||
amazon/amazon_logic.o \
|
||||
amazon/amazon_player.o \
|
||||
amazon/amazon_resources.o \
|
||||
amazon/amazon_room.o \
|
||||
amazon/amazon_scripts.o \
|
||||
martian/martian_game.o \
|
||||
martian/martian_player.o \
|
||||
martian/martian_resources.o \
|
||||
martian/martian_duct.o \
|
||||
martian/martian_room.o \
|
||||
martian/martian_scripts.o \
|
||||
martian/midiparser_bemd.o \
|
||||
video/movie_decoder.o
|
||||
|
||||
# This module can be built as a plugin
|
||||
ifeq ($(ENABLE_ACCESS), DYNAMIC_PLUGIN)
|
||||
PLUGIN := 1
|
||||
endif
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/rules.mk
|
||||
|
||||
# Detection objects
|
||||
DETECT_OBJS += $(MODULE)/detection.o
|
||||
944
engines/access/player.cpp
Normal file
944
engines/access/player.cpp
Normal file
@@ -0,0 +1,944 @@
|
||||
/* 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 "common/algorithm.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "access/player.h"
|
||||
#include "access/access.h"
|
||||
#include "access/resources.h"
|
||||
#include "access/amazon/amazon_player.h"
|
||||
#include "access/martian/martian_player.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
Player *Player::init(AccessEngine *vm) {
|
||||
switch (vm->getGameID()) {
|
||||
case kGameAmazon:
|
||||
vm->_playerDataCount = 8;
|
||||
return new Amazon::AmazonPlayer(vm);
|
||||
case kGameMartianMemorandum:
|
||||
vm->_playerDataCount = 10;
|
||||
return new Martian::MartianPlayer(vm);
|
||||
default:
|
||||
vm->_playerDataCount = 8;
|
||||
return new Player(vm);
|
||||
}
|
||||
}
|
||||
|
||||
Player::Player(AccessEngine *vm) : Manager(vm), ImageEntry() {
|
||||
_playerSprites = nullptr;
|
||||
_playerSprites1 = nullptr;
|
||||
_manPal1 = nullptr;
|
||||
_frameNumber = 0;
|
||||
_rawTempL = 0;
|
||||
_rawXTemp = 0;
|
||||
_rawYTempL = 0;
|
||||
_rawYTemp = 0;
|
||||
_playerXLow = 0;
|
||||
_playerX = 0;
|
||||
_playerYLow = 0;
|
||||
_playerY = 0;
|
||||
_frame = 0;
|
||||
_playerOff = false;
|
||||
_playerMove = false;
|
||||
_leftDelta = _rightDelta = 0;
|
||||
_upDelta = _downDelta = 0;
|
||||
_scrollConst = 0;
|
||||
_scrollFlag = false;
|
||||
_scrollThreshold = 0;
|
||||
_scrollAmount = 0;
|
||||
_scrollEnd = 0;
|
||||
_roomNumber = 0;
|
||||
_collideFlag = false;
|
||||
_move = NONE;
|
||||
_playerDirection = NONE;
|
||||
_xFlag = _yFlag = 0;
|
||||
_inactiveYOff = 0;
|
||||
_jetpackFlag = 0;
|
||||
|
||||
_sideWalkMin = _sideWalkMax = 0;
|
||||
_upWalkMin = _upWalkMax = 0;
|
||||
_downWalkMin = _downWalkMax = 0;
|
||||
_diagUpWalkMin = _diagUpWalkMax = 0;
|
||||
_diagDownWalkMin = _diagDownWalkMax = 0;
|
||||
_walkOffRight = _walkOffLeft = nullptr;
|
||||
_walkOffUp = _walkOffDown = nullptr;
|
||||
_walkOffUR = _walkOffDR = nullptr;
|
||||
_walkOffUL = _walkOffDL = nullptr;
|
||||
}
|
||||
|
||||
Player::~Player() {
|
||||
delete _playerSprites;
|
||||
delete[] _manPal1;
|
||||
delete[] _walkOffRight;
|
||||
delete[] _walkOffLeft;
|
||||
delete[] _walkOffUp;
|
||||
delete[] _walkOffDown;
|
||||
delete[] _walkOffUR;
|
||||
delete[] _walkOffDR;
|
||||
delete[] _walkOffUL;
|
||||
delete[] _walkOffDL;
|
||||
}
|
||||
|
||||
void Player::load() {
|
||||
uint8 dataCount = _vm->_playerDataCount;
|
||||
_walkOffRight = new int[dataCount];
|
||||
_walkOffLeft = new int[dataCount];
|
||||
_walkOffUp = new int[dataCount];
|
||||
_walkOffDown = new int[dataCount];
|
||||
_walkOffUR = new Common::Point[dataCount];
|
||||
_walkOffDR = new Common::Point[dataCount];
|
||||
_walkOffUL = new Common::Point[dataCount];
|
||||
_walkOffDL = new Common::Point[dataCount];
|
||||
|
||||
// NOTE: Although the values get set here to Amazon defaults, they are overridden
|
||||
// in both AmazonPlayer and MartianPlayer load() functions.
|
||||
_playerOffset.x = _vm->_screen->_scaleTable1[25];
|
||||
_playerOffset.y = _vm->_screen->_scaleTable1[67];
|
||||
_leftDelta = -3;
|
||||
_rightDelta = 33;
|
||||
_upDelta = 5;
|
||||
_downDelta = -10;
|
||||
_scrollConst = 5;
|
||||
|
||||
_sideWalkMin = 0;
|
||||
_sideWalkMax = 7;
|
||||
_upWalkMin = 16;
|
||||
_upWalkMax = 23;
|
||||
_downWalkMin = 8;
|
||||
_downWalkMax = 15;
|
||||
_diagUpWalkMin = 0;
|
||||
_diagUpWalkMax = 7;
|
||||
_diagDownWalkMin = 0;
|
||||
_diagDownWalkMax = 7;
|
||||
|
||||
_playerSprites = _playerSprites1;
|
||||
if (_manPal1) {
|
||||
// Those values are from MM as Amazon doesn't use it
|
||||
Common::copy(_manPal1 + 0x2A0, _manPal1 + 0x2A0 + 0x42, _vm->_screen->_manPal);
|
||||
} else {
|
||||
Common::fill(_vm->_screen->_manPal, _vm->_screen->_manPal + 0x60, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::loadTexPalette() {
|
||||
Resource *texPal = _vm->_files->loadFile("TEXPAL.COL");
|
||||
int size = texPal->_size;
|
||||
assert(size == 768);
|
||||
_manPal1 = new byte[size];
|
||||
memcpy(_manPal1, texPal->data(), size);
|
||||
}
|
||||
|
||||
void Player::loadSprites(const Common::Path &name) {
|
||||
freeSprites();
|
||||
|
||||
Resource *data = _vm->_files->loadFile(name);
|
||||
|
||||
#if 0
|
||||
Common::DumpFile *outFile = new Common::DumpFile();
|
||||
Common::String outName = name + ".dump";
|
||||
outFile->open(outName);
|
||||
outFile->write(data->data(), data->_size);
|
||||
outFile->finalize();
|
||||
outFile->close();
|
||||
#endif
|
||||
|
||||
_playerSprites1 = new SpriteResource(_vm, data);
|
||||
delete data;
|
||||
}
|
||||
|
||||
void Player::freeSprites() {
|
||||
delete _playerSprites;
|
||||
_playerSprites1 = nullptr;
|
||||
_playerSprites = nullptr;
|
||||
}
|
||||
|
||||
void Player::removeSprite1() {
|
||||
if (_playerSprites1) {
|
||||
delete _playerSprites1;
|
||||
_playerSprites1 = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool Player::isMMHover() const {
|
||||
// Whether or not this is MM and the player is on the hoverboard.
|
||||
return (_vm->getGameID() == kGameMartianMemorandum &&
|
||||
_vm->_flags[174] == 1);
|
||||
}
|
||||
|
||||
void Player::calcManScale() {
|
||||
if (!_vm->_manScaleOff) {
|
||||
_vm->_scale = ((((_rawPlayer.y - _vm->_scaleMaxY + _vm->_scaleN1) *
|
||||
_vm->_scaleT1 + (_vm->_scaleH2 << 8)) & 0xff00) / _vm->_scaleH1 * _vm->_scaleI) >> 8;
|
||||
_vm->_screen->setScaleTable(_vm->_scale);
|
||||
|
||||
_playerOffset.x = _vm->_screen->_scaleTable1[20];
|
||||
_playerOffset.y = _vm->_screen->_scaleTable1[(_vm->getGameID() == kGameMartianMemorandum) ? 62 : 67];
|
||||
_inactiveYOff = _playerOffset.y;
|
||||
}
|
||||
}
|
||||
|
||||
void Player::jetpack() {
|
||||
_playerDirection = UP;
|
||||
ImageFlag flags = IMGFLAG_NONE;
|
||||
if (!_vm->_timers[0]._flag) {
|
||||
_vm->_timers[0]._flag = 1;
|
||||
_jetpackFlag ^= 1;
|
||||
_rawPlayer.y -= 4;
|
||||
if (_move == RIGHT) {
|
||||
_frame = 0;
|
||||
flags = IMGFLAG_CROPPED;
|
||||
if (_rawPlayer.x < 0x101)
|
||||
_rawPlayer.x += 2;
|
||||
else
|
||||
_rawPlayer.x = 256;
|
||||
}
|
||||
if (_move == LEFT) {
|
||||
_frame = 0;
|
||||
flags = IMGFLAG_BACKWARDS;
|
||||
_rawPlayer.x -= 2;
|
||||
if (_rawPlayer.x < 0)
|
||||
_rawPlayer.x = 0;
|
||||
}
|
||||
|
||||
// Leave tex facing whichever direction he was previously
|
||||
// unless moving in some direction
|
||||
if (_move == LEFT || _move == RIGHT)
|
||||
_flags = (_flags & 0xfd) | flags;
|
||||
}
|
||||
|
||||
_flags |= IMGFLAG_UNSCALED;
|
||||
|
||||
_position.x = _rawPlayer.x;
|
||||
_position.y = _rawPlayer.y - _playerOffset.y;
|
||||
_offsetY = _playerOffset.y;
|
||||
_frameNumber = 23 + _jetpackFlag;
|
||||
|
||||
ImageEntry ie = *this;
|
||||
ie._spritesPtr = _vm->_objectsTable[35];
|
||||
_vm->_images.addToList(ie);
|
||||
}
|
||||
|
||||
void Player::walk() {
|
||||
_collideFlag = false;
|
||||
|
||||
if (_vm->getGameID() == kGameMartianMemorandum && _vm->_flags[173] == 1) {
|
||||
// Special case for MM Jetpack
|
||||
jetpack();
|
||||
return;
|
||||
}
|
||||
|
||||
_playerDirection = NONE;
|
||||
|
||||
if (_playerOff)
|
||||
return;
|
||||
else if (_vm->_timers[0]._flag) {
|
||||
plotCom3();
|
||||
return;
|
||||
}
|
||||
|
||||
++_vm->_timers[0]._flag;
|
||||
switch (_move) {
|
||||
case UP:
|
||||
_playerMove = false;
|
||||
walkUp();
|
||||
break;
|
||||
case DOWN:
|
||||
_playerMove = false;
|
||||
walkDown();
|
||||
break;
|
||||
case LEFT:
|
||||
_playerMove = false;
|
||||
walkLeft();
|
||||
break;
|
||||
case RIGHT:
|
||||
_playerMove = false;
|
||||
walkRight();
|
||||
break;
|
||||
case UPLEFT:
|
||||
_playerMove = false;
|
||||
walkUpLeft();
|
||||
break;
|
||||
case DOWNLEFT:
|
||||
_playerMove = false;
|
||||
walkDownLeft();
|
||||
break;
|
||||
case UPRIGHT:
|
||||
_playerMove = false;
|
||||
walkUpRight();
|
||||
break;
|
||||
case DOWNRIGHT:
|
||||
_playerMove = false;
|
||||
walkDownRight();
|
||||
break;
|
||||
default:
|
||||
checkMove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Player::calcPlayer() {
|
||||
Screen &scr = *_vm->_screen;
|
||||
scr._bufferStart.x = (_vm->_scrollCol << 4) + _vm->_scrollX;
|
||||
scr._bufferStart.y = (_vm->_scrollRow << 4) + _vm->_scrollY;
|
||||
_playerX = _rawPlayer.x - scr._bufferStart.x;
|
||||
_playerY = _rawPlayer.y - scr._bufferStart.y;
|
||||
}
|
||||
|
||||
void Player::walkUp() {
|
||||
if (_frame > _upWalkMax || _frame < _upWalkMin)
|
||||
_frame = _upWalkMin;
|
||||
|
||||
_playerDirection = UP;
|
||||
int walkOff = _walkOffUp[_frame - _upWalkMin];
|
||||
int tempL = _rawPlayerLow.y - (isMMHover() ? 2 : _vm->_screen->_scaleTable2[walkOff]);
|
||||
_rawYTempL = (byte)tempL;
|
||||
int yTemp = _rawPlayer.y - (isMMHover() ? 2 : _vm->_screen->_scaleTable1[walkOff]) -
|
||||
(tempL < 0 ? 1 : 0);
|
||||
_rawYTemp = yTemp;
|
||||
_rawXTemp = _rawPlayer.x;
|
||||
|
||||
if (_vm->_room->codeWalls()) {
|
||||
plotCom2();
|
||||
} else {
|
||||
_rawPlayer.y = _rawYTemp;
|
||||
_rawPlayerLow.y = _rawYTempL;
|
||||
|
||||
calcManScale();
|
||||
|
||||
if (_vm->getGameID() == kGameMartianMemorandum && _vm->_flags[174] == 0 && (_frame == 8 || _frame == 12))
|
||||
_vm->_sound->playSound(0);
|
||||
else if (_vm->getGameID() == kGameAmazon && _vm->_currentMan != 3 && (_frame == 17 || _frame == 21))
|
||||
_vm->_sound->playSound(0);
|
||||
|
||||
if (++_frame > _upWalkMax)
|
||||
_frame = _upWalkMin;
|
||||
|
||||
plotCom(0);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::walkDown() {
|
||||
if (_frame > _downWalkMax || _frame < _downWalkMin)
|
||||
_frame = _downWalkMin;
|
||||
|
||||
_playerDirection = DOWN;
|
||||
int walkOff = _walkOffDown[_frame - _downWalkMin];
|
||||
int tempL = (isMMHover() ? 2 : _vm->_screen->_scaleTable2[walkOff]) + _rawPlayerLow.y;
|
||||
_rawYTempL = (byte)tempL;
|
||||
_rawYTemp = (isMMHover() ? 2 : _vm->_screen->_scaleTable1[walkOff]) + _rawPlayer.y + (tempL >= 0x100 ? 1 : 0);
|
||||
_rawXTemp = _rawPlayer.x;
|
||||
|
||||
if (_vm->_room->codeWalls()) {
|
||||
plotCom2();
|
||||
} else {
|
||||
_rawPlayer.y = _rawYTemp;
|
||||
_rawPlayerLow.y = _rawYTempL;
|
||||
|
||||
calcManScale();
|
||||
|
||||
if (_vm->getGameID() == kGameMartianMemorandum && _vm->_flags[174] == 0 && (_frame == 17 || _frame == 21))
|
||||
_vm->_sound->playSound(0);
|
||||
else if (_vm->getGameID() == kGameAmazon && _vm->_currentMan != 3 && (_frame == 10 || _frame == 14))
|
||||
_vm->_sound->playSound(0);
|
||||
|
||||
if (++_frame > _downWalkMax)
|
||||
_frame = _downWalkMin;
|
||||
|
||||
plotCom(0);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::walkLeft() {
|
||||
if (_frame > _sideWalkMax || _frame < _sideWalkMin)
|
||||
_frame = _sideWalkMin;
|
||||
|
||||
_playerDirection = LEFT;
|
||||
|
||||
bool flag = _scrollEnd == 1;
|
||||
if (!flag) {
|
||||
calcPlayer();
|
||||
flag = (_playerX - _vm->_screen->_scaleTable1[_scrollConst] -
|
||||
_vm->_player->_scrollThreshold) > 0;
|
||||
}
|
||||
if (flag) {
|
||||
int walkOffset = _walkOffLeft[_frame - _sideWalkMin];
|
||||
int tempL = _rawPlayerLow.x - (isMMHover() ? 2 : _vm->_screen->_scaleTable2[walkOffset]);
|
||||
_rawTempL = (byte)tempL;
|
||||
_rawXTemp = _rawPlayer.x - (isMMHover() ? 2 : _vm->_screen->_scaleTable1[walkOffset]) -
|
||||
(tempL < 0 ? 1 : 0);
|
||||
} else {
|
||||
_rawXTemp = _rawPlayer.x - _vm->_screen->_scaleTable1[_scrollConst];
|
||||
}
|
||||
_rawYTemp = _rawPlayer.y;
|
||||
|
||||
if (_vm->_room->codeWalls()) {
|
||||
plotCom2();
|
||||
} else {
|
||||
_rawPlayer.x = _rawXTemp;
|
||||
_rawPlayerLow.x = _rawTempL;
|
||||
++_frame;
|
||||
|
||||
if (_vm->getGameID() == kGameMartianMemorandum && _vm->_flags[174] == 0 && (_frame == 7 || _frame == 3))
|
||||
_vm->_sound->playSound(0);
|
||||
else if (_vm->getGameID() == kGameAmazon && _vm->_currentMan != 3 && (_frame == 1 || _frame == 5))
|
||||
_vm->_sound->playSound(0);
|
||||
|
||||
if (_frame > _sideWalkMax)
|
||||
_frame = _sideWalkMin;
|
||||
|
||||
plotCom1();
|
||||
}
|
||||
}
|
||||
|
||||
void Player::walkRight() {
|
||||
if (_frame > _sideWalkMax || _frame < _sideWalkMin)
|
||||
_frame = _sideWalkMin;
|
||||
|
||||
_playerDirection = RIGHT;
|
||||
|
||||
bool flag = _scrollEnd == 2;
|
||||
if (!flag) {
|
||||
calcPlayer();
|
||||
flag = (_vm->_screen->_clipWidth - _playerX - _vm->_screen->_scaleTable1[_scrollConst] -
|
||||
_vm->_player->_scrollThreshold) > 0;
|
||||
}
|
||||
if (flag) {
|
||||
int walkOffset = _walkOffRight[_frame - _sideWalkMin];
|
||||
int tempL = _rawPlayerLow.x + (isMMHover() ? 2 : _vm->_screen->_scaleTable2[walkOffset]);
|
||||
_rawTempL = (byte)tempL;
|
||||
_rawXTemp = _rawPlayer.x + (isMMHover() ? 2 : _vm->_screen->_scaleTable1[walkOffset]) +
|
||||
(tempL >= 0x100 ? 1 : 0);
|
||||
} else {
|
||||
_rawXTemp = _rawPlayer.x + _vm->_screen->_scaleTable1[_scrollConst];
|
||||
}
|
||||
_rawYTemp = _rawPlayer.y;
|
||||
|
||||
if (_vm->_room->codeWalls()) {
|
||||
plotCom2();
|
||||
} else {
|
||||
_rawPlayer.x = _rawXTemp;
|
||||
_rawPlayerLow.x = _rawTempL;
|
||||
++_frame;
|
||||
|
||||
if (_vm->getGameID() == kGameMartianMemorandum && _vm->_flags[174] == 0 && (_frame == 7 || _frame == 3))
|
||||
_vm->_sound->playSound(0);
|
||||
else if (_vm->getGameID() == kGameAmazon && _vm->_currentMan != 3 && (_frame == 1 || _frame == 5))
|
||||
_vm->_sound->playSound(0);
|
||||
|
||||
// Useless check removed
|
||||
if (_frame > _sideWalkMax)
|
||||
_frame = _sideWalkMin;
|
||||
|
||||
plotCom0();
|
||||
}
|
||||
}
|
||||
|
||||
void Player::walkUpLeft() {
|
||||
if (_frame > _diagUpWalkMax || _frame < _diagUpWalkMin)
|
||||
_frame = _diagUpWalkMin;
|
||||
|
||||
_playerDirection = UPLEFT;
|
||||
|
||||
int walkOffset, tempL;
|
||||
bool flag = _scrollEnd == 1;
|
||||
if (!flag) {
|
||||
calcPlayer();
|
||||
flag = (_playerX - _vm->_screen->_scaleTable1[_scrollConst] -
|
||||
_vm->_player->_scrollThreshold) > 0;
|
||||
}
|
||||
if (flag) {
|
||||
walkOffset = _walkOffUL[_frame - _diagUpWalkMin].x;
|
||||
tempL = _rawPlayerLow.x - _vm->_screen->_scaleTable2[walkOffset];
|
||||
_rawTempL = (byte)tempL;
|
||||
_rawXTemp = _rawPlayer.x - _vm->_screen->_scaleTable1[walkOffset] -
|
||||
(tempL < 0 ? 1 : 0);
|
||||
} else {
|
||||
_rawXTemp = _rawPlayer.x - _vm->_screen->_scaleTable1[_scrollConst];
|
||||
}
|
||||
|
||||
walkOffset = _walkOffUL[_frame - _diagUpWalkMin].y;
|
||||
tempL = _rawPlayerLow.y - _vm->_screen->_scaleTable2[walkOffset];
|
||||
_rawYTempL = (byte)tempL;
|
||||
_rawYTemp = _rawPlayer.y - _vm->_screen->_scaleTable1[walkOffset] -
|
||||
(tempL < 0 ? 1 : 0);
|
||||
|
||||
if (_vm->_room->codeWalls()) {
|
||||
plotCom2();
|
||||
} else {
|
||||
_rawPlayer.x = _rawXTemp;
|
||||
_rawPlayer.y = _rawYTemp;
|
||||
_rawPlayerLow.x = _rawTempL;
|
||||
_rawPlayerLow.y = _rawYTempL;
|
||||
|
||||
++_frame;
|
||||
calcManScale();
|
||||
|
||||
if (_vm->_currentMan != 3 && (_frame == 1 || _frame == 5))
|
||||
_vm->_sound->playSound(0);
|
||||
|
||||
if (_frame > _diagUpWalkMax)
|
||||
_frame = _diagUpWalkMin;
|
||||
|
||||
plotCom1();
|
||||
}
|
||||
}
|
||||
|
||||
void Player::walkDownLeft() {
|
||||
if (_frame > _diagDownWalkMax || _frame < _diagDownWalkMin)
|
||||
_frame = _diagDownWalkMin;
|
||||
|
||||
_playerDirection = DOWNLEFT;
|
||||
|
||||
int walkOffset, tempL;
|
||||
bool flag = _scrollEnd == 1;
|
||||
if (!flag) {
|
||||
calcPlayer();
|
||||
flag = (_playerX - _vm->_screen->_scaleTable1[_scrollConst] -
|
||||
_vm->_player->_scrollThreshold) > 0;
|
||||
}
|
||||
if (flag) {
|
||||
walkOffset = _walkOffDL[_frame - _sideWalkMin].x;
|
||||
tempL = _rawPlayerLow.x - _vm->_screen->_scaleTable2[walkOffset];
|
||||
_rawTempL = (byte)tempL;
|
||||
_rawXTemp = _rawPlayer.x - _vm->_screen->_scaleTable1[walkOffset] -
|
||||
(tempL < 0 ? 1 : 0);
|
||||
} else {
|
||||
_rawXTemp = _rawPlayer.x - _vm->_screen->_scaleTable1[_scrollConst];
|
||||
}
|
||||
|
||||
walkOffset = _walkOffDL[_frame - _diagDownWalkMin].y;
|
||||
tempL = _rawPlayerLow.y + _vm->_screen->_scaleTable2[walkOffset];
|
||||
_rawYTempL = (byte)tempL;
|
||||
_rawYTemp = _rawPlayer.y + _vm->_screen->_scaleTable1[walkOffset] +
|
||||
(tempL >= 0x100 ? 1 : 0);
|
||||
|
||||
if (_vm->_room->codeWalls()) {
|
||||
plotCom2();
|
||||
} else {
|
||||
_rawPlayer.x = _rawXTemp;
|
||||
_rawPlayer.y = _rawYTemp;
|
||||
_rawPlayerLow.x = _rawTempL;
|
||||
_rawPlayerLow.y = _rawYTempL;
|
||||
|
||||
++_frame;
|
||||
calcManScale();
|
||||
|
||||
if (_vm->_currentMan != 3 && (_frame == 1 || _frame == 5))
|
||||
_vm->_sound->playSound(0);
|
||||
|
||||
if (_frame > _diagDownWalkMax)
|
||||
_frame = _diagDownWalkMin;
|
||||
|
||||
plotCom1();
|
||||
}
|
||||
}
|
||||
|
||||
void Player::walkUpRight() {
|
||||
if (_frame > _diagUpWalkMax || _frame < _diagUpWalkMin)
|
||||
_frame = _diagUpWalkMin;
|
||||
|
||||
_playerDirection = UPRIGHT;
|
||||
|
||||
int walkOffset, tempL;
|
||||
bool flag = _scrollEnd == 1;
|
||||
if (!flag) {
|
||||
calcPlayer();
|
||||
flag = (_vm->_screen->_clipWidth - _playerX - _vm->_screen->_scaleTable1[_scrollConst] -
|
||||
_vm->_player->_scrollThreshold) > 0;
|
||||
}
|
||||
if (flag) {
|
||||
walkOffset = _walkOffUR[_frame - _diagUpWalkMin].x;
|
||||
tempL = _rawPlayerLow.x + _vm->_screen->_scaleTable2[walkOffset];
|
||||
_rawTempL = (byte)tempL;
|
||||
_rawXTemp = _rawPlayer.x + _vm->_screen->_scaleTable1[walkOffset] +
|
||||
(tempL >= 0x100 ? 1 : 0);
|
||||
} else {
|
||||
_rawXTemp = _rawPlayer.x + _vm->_screen->_scaleTable1[_scrollConst];
|
||||
}
|
||||
|
||||
walkOffset = _walkOffUL[_frame - _diagUpWalkMin].y;
|
||||
tempL = _rawPlayerLow.y - _vm->_screen->_scaleTable2[walkOffset];
|
||||
_rawYTempL = (byte)tempL;
|
||||
_rawYTemp = _rawPlayer.y - _vm->_screen->_scaleTable1[walkOffset] -
|
||||
(tempL < 0 ? 1 : 0);
|
||||
|
||||
if (_vm->_room->codeWalls()) {
|
||||
plotCom2();
|
||||
} else {
|
||||
_rawPlayer.x = _rawXTemp;
|
||||
_rawPlayer.y = _rawYTemp;
|
||||
_rawPlayerLow.x = _rawTempL;
|
||||
_rawPlayerLow.y = _rawYTempL;
|
||||
|
||||
++_frame;
|
||||
calcManScale();
|
||||
|
||||
if (_vm->_currentMan != 3 && (_frame == 1 || _frame == 5))
|
||||
_vm->_sound->playSound(0);
|
||||
|
||||
if (_frame > _diagUpWalkMax)
|
||||
_frame = _diagUpWalkMin;
|
||||
|
||||
plotCom(0);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::walkDownRight() {
|
||||
if (_frame > _diagDownWalkMax || _frame < _diagDownWalkMin)
|
||||
_frame = _diagDownWalkMin;
|
||||
|
||||
_playerDirection = DOWNRIGHT;
|
||||
|
||||
int walkOffset, tempL;
|
||||
bool flag = _scrollEnd == 2;
|
||||
if (!flag) {
|
||||
calcPlayer();
|
||||
flag = (_vm->_screen->_clipWidth - _playerX - _vm->_screen->_scaleTable1[_scrollConst] -
|
||||
_vm->_player->_scrollThreshold) > 0;
|
||||
}
|
||||
if (flag) {
|
||||
walkOffset = _walkOffUR[_frame - _diagDownWalkMin].x;
|
||||
tempL = _rawPlayerLow.x + _vm->_screen->_scaleTable2[walkOffset];
|
||||
_rawTempL = (byte)tempL;
|
||||
_rawXTemp = _rawPlayer.x + _vm->_screen->_scaleTable1[walkOffset] +
|
||||
(tempL >= 0x100 ? 1 : 0);
|
||||
} else {
|
||||
_rawXTemp = _rawPlayer.x + _vm->_screen->_scaleTable1[_scrollConst];
|
||||
}
|
||||
|
||||
walkOffset = _walkOffDR[_frame - _diagDownWalkMin].y;
|
||||
tempL = _rawPlayerLow.y + _vm->_screen->_scaleTable2[walkOffset];
|
||||
_rawYTempL = (byte)tempL;
|
||||
_rawYTemp = _rawPlayer.y + _vm->_screen->_scaleTable1[walkOffset] +
|
||||
(tempL >= 0x100 ? 1 : 0);
|
||||
|
||||
if (_vm->_room->codeWalls()) {
|
||||
plotCom2();
|
||||
} else {
|
||||
_rawPlayer.x = _rawXTemp;
|
||||
_rawPlayer.y = _rawYTemp;
|
||||
_rawPlayerLow.x = _rawTempL;
|
||||
_rawPlayerLow.y = _rawYTempL;
|
||||
|
||||
calcManScale();
|
||||
|
||||
if (_vm->_currentMan != 3 && (_frame == 1 || _frame == 5))
|
||||
_vm->_sound->playSound(0);
|
||||
|
||||
++_frame;
|
||||
if (_frame > _diagDownWalkMax)
|
||||
_frame = _diagDownWalkMin;
|
||||
|
||||
plotCom(0);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::checkMove() {
|
||||
if (_playerMove) {
|
||||
if (_xFlag == 0 && _yFlag == 0) {
|
||||
int xp = (_playerOffset.x / 2) + _rawPlayer.x - _moveTo.x;
|
||||
if (xp < 0)
|
||||
xp = -xp;
|
||||
int yp = _rawPlayer.y - _moveTo.y;
|
||||
if (yp < 0)
|
||||
yp = -yp;
|
||||
|
||||
if (xp >= yp)
|
||||
_xFlag = 1;
|
||||
else
|
||||
_yFlag = 1;
|
||||
}
|
||||
|
||||
if (_yFlag == 1) {
|
||||
int yd = _rawPlayer.y - _moveTo.y;
|
||||
if ((yd >= 0 && yd <= _upDelta) || (yd < 0 && -yd <= _upDelta)) {
|
||||
++_yFlag;
|
||||
if (_xFlag) {
|
||||
_playerMove = false;
|
||||
_xFlag = _yFlag = 0;
|
||||
} else {
|
||||
++_xFlag;
|
||||
}
|
||||
} else {
|
||||
if (yd >= 0)
|
||||
walkUp();
|
||||
else
|
||||
walkDown();
|
||||
|
||||
if (_collideFlag) {
|
||||
_playerMove = false;
|
||||
_xFlag = _yFlag = 0;
|
||||
}
|
||||
}
|
||||
} else if (_xFlag == 1) {
|
||||
int xd = (_playerOffset.x / 2) + _rawPlayer.x - _moveTo.x;
|
||||
if ((xd >= 0 && xd <= -_leftDelta) || (xd < 0 && -xd <= -_leftDelta)) {
|
||||
++_xFlag;
|
||||
|
||||
if (_yFlag) {
|
||||
_playerMove = false;
|
||||
_xFlag = _yFlag = 0;
|
||||
}
|
||||
} else {
|
||||
if (xd >= 0)
|
||||
walkLeft();
|
||||
else
|
||||
walkRight();
|
||||
|
||||
if (_collideFlag) {
|
||||
_playerMove = false;
|
||||
_xFlag = _yFlag = 0;
|
||||
}
|
||||
}
|
||||
} else if (!_yFlag) {
|
||||
++_yFlag;
|
||||
} else {
|
||||
_playerMove = false;
|
||||
_xFlag = _yFlag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
plotCom3();
|
||||
}
|
||||
|
||||
void Player::plotCom(int flags) {
|
||||
_flags &= ~IMGFLAG_BACKWARDS;
|
||||
_flags &= ~IMGFLAG_UNSCALED;
|
||||
_flags |= flags;
|
||||
|
||||
plotCom3();
|
||||
}
|
||||
|
||||
void Player::plotCom0() {
|
||||
plotCom(_vm->getGameID() == kGameAmazon ? 0 : IMGFLAG_BACKWARDS);
|
||||
}
|
||||
|
||||
void Player::plotCom1() {
|
||||
plotCom(_vm->getGameID() == kGameAmazon ? IMGFLAG_BACKWARDS : 0);
|
||||
}
|
||||
|
||||
void Player::plotCom2() {
|
||||
// WORKAROUND: Amazon has at least one cutscene with the player not properly turned off
|
||||
if (!_playerOff && _spritesPtr != nullptr) {
|
||||
ImageEntry ie = *this;
|
||||
if (!isMMHover()) {
|
||||
_vm->_images.addToList(ie);
|
||||
} else if (_vm->_objectsTable[23]) {
|
||||
// MM player on hoverboard
|
||||
ie._spritesPtr = _vm->_objectsTable[23];
|
||||
ie._frameNumber = 13;
|
||||
_vm->_images.addToList(ie);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::plotCom3() {
|
||||
// Update the base ImageEntry fields for the player
|
||||
_position.x = _rawPlayer.x;
|
||||
_position.y = _rawPlayer.y - _playerOffset.y;
|
||||
_offsetY = _playerOffset.y;
|
||||
_spritesPtr = _playerSprites;
|
||||
_frameNumber = _frame;
|
||||
|
||||
plotCom2();
|
||||
}
|
||||
|
||||
void Player::checkScrollUp() {
|
||||
if ((_playerDirection == DOWNRIGHT || _playerDirection == DOWNLEFT ||
|
||||
_playerDirection == DOWN) && (_vm->_screen->_clipHeight -
|
||||
_playerY - _scrollThreshold) <= 0) {
|
||||
// Scroll up
|
||||
if (scrollUp()) {
|
||||
_scrollEnd = 4;
|
||||
_vm->_scrollY &= TILE_HEIGHT;
|
||||
_scrollFlag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::checkScroll() {
|
||||
_scrollFlag = false;
|
||||
if (_playerDirection == NONE)
|
||||
return;
|
||||
|
||||
calcPlayer();
|
||||
|
||||
if ((_playerDirection == UPLEFT || _playerDirection == DOWNLEFT ||
|
||||
_playerDirection == LEFT) && _playerX <= _scrollThreshold) {
|
||||
// Scroll right
|
||||
if (!scrollRight()) {
|
||||
if (_playerDirection == DOWNLEFT)
|
||||
checkScrollUp();
|
||||
|
||||
return;
|
||||
}
|
||||
} else if ((_playerDirection == UPRIGHT || _playerDirection == DOWNRIGHT ||
|
||||
_playerDirection == RIGHT) && (_vm->_screen->_clipWidth -
|
||||
_playerX - _scrollThreshold) <= 0) {
|
||||
// Scroll left
|
||||
if (!scrollLeft()) {
|
||||
if (_playerDirection == DOWNRIGHT)
|
||||
checkScrollUp();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((_playerDirection == UPRIGHT || _playerDirection == UPLEFT ||
|
||||
_playerDirection == UP) && _playerY <= _scrollThreshold) {
|
||||
scrollDown();
|
||||
} else {
|
||||
checkScrollUp();
|
||||
}
|
||||
}
|
||||
|
||||
bool Player::scrollUp(int forcedAmount) {
|
||||
if (forcedAmount == -1)
|
||||
_scrollAmount = -(_vm->_screen->_clipHeight - _playerY - _scrollThreshold);
|
||||
else
|
||||
_scrollAmount = forcedAmount;
|
||||
|
||||
if ((_vm->_scrollRow + _vm->_screen->_vWindowHeight) >=
|
||||
_vm->_room->_playFieldHeight) {
|
||||
return true;
|
||||
}
|
||||
|
||||
_scrollFlag = true;
|
||||
_vm->_scrollY = _vm->_scrollY + _scrollAmount;
|
||||
|
||||
while (_vm->_scrollY >= TILE_HEIGHT && !_vm->shouldQuit()) {
|
||||
_vm->_scrollY -= TILE_HEIGHT;
|
||||
++_vm->_scrollRow;
|
||||
_vm->_buffer1.moveBufferUp();
|
||||
|
||||
_vm->_room->buildRow(_vm->_scrollRow + _vm->_screen->_vWindowHeight,
|
||||
_vm->_screen->_vWindowLinesTall);
|
||||
|
||||
if ((_vm->_scrollRow + _vm->_screen->_vWindowHeight) >=
|
||||
_vm->_room->_playFieldHeight)
|
||||
return true;
|
||||
|
||||
if (_vm->_scrollY <= TILE_HEIGHT)
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Player::scrollDown(int forcedAmount) {
|
||||
if (forcedAmount == -1)
|
||||
_scrollAmount = -(_playerY - _scrollThreshold);
|
||||
else
|
||||
_scrollAmount = forcedAmount;
|
||||
|
||||
_scrollFlag = true;
|
||||
_vm->_scrollY -= _scrollAmount;
|
||||
if (_vm->_scrollY >= 0)
|
||||
return true;
|
||||
|
||||
do {
|
||||
_vm->_scrollY += TILE_HEIGHT;
|
||||
if (--_vm->_scrollRow < 0)
|
||||
break;
|
||||
|
||||
_vm->_buffer1.moveBufferDown();
|
||||
_vm->_room->buildRow(_vm->_scrollRow, 0);
|
||||
|
||||
if (_vm->_scrollY >= 0)
|
||||
return false;
|
||||
} while (!_vm->shouldQuit());
|
||||
|
||||
_scrollEnd = 3;
|
||||
_vm->_scrollY = 0;
|
||||
_vm->_scrollRow = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Player::scrollLeft(int forcedAmount) {
|
||||
Screen &screen = *_vm->_screen;
|
||||
if (forcedAmount == -1)
|
||||
_scrollAmount = -(_vm->_screen->_clipWidth - _playerX - _scrollThreshold);
|
||||
else
|
||||
_scrollAmount = forcedAmount;
|
||||
|
||||
if ((_vm->_scrollCol + screen._vWindowWidth) == _vm->_room->_playFieldWidth) {
|
||||
_scrollEnd = 2;
|
||||
_vm->_scrollX = 0;
|
||||
_scrollFlag = true;
|
||||
return true;
|
||||
} else {
|
||||
_scrollFlag = true;
|
||||
_vm->_scrollX += _scrollAmount;
|
||||
|
||||
do {
|
||||
if (_vm->_scrollX < TILE_WIDTH)
|
||||
return true;
|
||||
|
||||
_vm->_scrollX -= TILE_WIDTH;
|
||||
++_vm->_scrollCol;
|
||||
_vm->_buffer1.moveBufferLeft();
|
||||
_vm->_room->buildColumn(_vm->_scrollCol + screen._vWindowWidth,
|
||||
screen._vWindowBytesWide);
|
||||
} while (!_vm->shouldQuit() && (_vm->_scrollX >= TILE_WIDTH));
|
||||
|
||||
return (_playerDirection == UPRIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
bool Player::scrollRight(int forcedAmount) {
|
||||
if (forcedAmount == -1)
|
||||
_scrollAmount = -(_playerX - _scrollThreshold);
|
||||
else
|
||||
_scrollAmount = forcedAmount;
|
||||
|
||||
_scrollFlag = true;
|
||||
_vm->_scrollX -= _scrollAmount;
|
||||
|
||||
if (_vm->_scrollX < 0) {
|
||||
do {
|
||||
_vm->_scrollX += TILE_WIDTH;
|
||||
if (--_vm->_scrollCol < 0) {
|
||||
_scrollEnd = 1;
|
||||
_vm->_scrollX = 0;
|
||||
_vm->_scrollCol = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
_vm->_buffer1.moveBufferRight();
|
||||
_vm->_room->buildColumn(_vm->_scrollCol, 0);
|
||||
} while (!_vm->shouldQuit() && (_vm->_scrollX < 0));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Player::synchronize(Common::Serializer &s) {
|
||||
s.syncAsUint16LE(_roomNumber);
|
||||
s.syncAsSint16LE(_rawPlayerLow.x);
|
||||
s.syncAsSint16LE(_rawPlayer.x);
|
||||
s.syncAsSint16LE(_rawPlayerLow.y);
|
||||
s.syncAsSint16LE(_rawPlayer.y);
|
||||
}
|
||||
|
||||
} // End of namespace Access
|
||||
159
engines/access/player.h
Normal file
159
engines/access/player.h
Normal file
@@ -0,0 +1,159 @@
|
||||
/* 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 ACCESS_PLAYER_H
|
||||
#define ACCESS_PLAYER_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/serializer.h"
|
||||
#include "access/asurface.h"
|
||||
#include "access/data.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
enum Direction {
|
||||
NONE = 0,
|
||||
UP = 1,
|
||||
DOWN = 2,
|
||||
LEFT = 3,
|
||||
RIGHT = 4,
|
||||
UPRIGHT = 5,
|
||||
DOWNRIGHT = 6,
|
||||
UPLEFT = 7,
|
||||
DOWNLEFT = 8
|
||||
};
|
||||
|
||||
class AccessEngine;
|
||||
|
||||
class Player : public ImageEntry, public Manager {
|
||||
protected:
|
||||
int _leftDelta, _rightDelta;
|
||||
int _upDelta, _downDelta;
|
||||
int _scrollConst;
|
||||
int _sideWalkMin, _sideWalkMax;
|
||||
int _upWalkMin, _upWalkMax;
|
||||
int _downWalkMin, _downWalkMax;
|
||||
int _diagUpWalkMin, _diagUpWalkMax;
|
||||
int _diagDownWalkMin, _diagDownWalkMax;
|
||||
SpriteResource *_playerSprites1;
|
||||
int _scrollEnd;
|
||||
int _inactiveYOff;
|
||||
int _jetpackFlag;
|
||||
|
||||
void plotCom(int v1);
|
||||
void plotCom0();
|
||||
void plotCom1();
|
||||
void plotCom2();
|
||||
void plotCom3();
|
||||
|
||||
void walkUp();
|
||||
void walkDown();
|
||||
void walkLeft();
|
||||
void walkRight();
|
||||
void walkUpLeft();
|
||||
void walkDownLeft();
|
||||
void walkUpRight();
|
||||
void walkDownRight();
|
||||
void checkScrollUp();
|
||||
|
||||
bool isMMHover() const;
|
||||
void jetpack();
|
||||
|
||||
public:
|
||||
Direction _playerDirection;
|
||||
SpriteResource *_playerSprites;
|
||||
// Fields in original Player structure
|
||||
byte *_manPal1;
|
||||
int *_walkOffRight;
|
||||
int *_walkOffLeft;
|
||||
int *_walkOffUp;
|
||||
int *_walkOffDown;
|
||||
Common::Point *_walkOffUR;
|
||||
Common::Point *_walkOffDR;
|
||||
Common::Point *_walkOffUL;
|
||||
Common::Point *_walkOffDL;
|
||||
byte _rawTempL;
|
||||
int _rawXTemp;
|
||||
byte _rawYTempL;
|
||||
int _rawYTemp;
|
||||
Common::Point _playerOffset;
|
||||
int _playerXLow;
|
||||
int _playerX;
|
||||
int _playerYLow;
|
||||
int _playerY;
|
||||
int _frame;
|
||||
int _xFlag, _yFlag;
|
||||
Direction _move;
|
||||
|
||||
// Additional public globals we've added to new Player class
|
||||
bool _playerOff;
|
||||
bool _playerMove;
|
||||
Common::Point _moveTo;
|
||||
bool _collideFlag;
|
||||
bool _scrollFlag;
|
||||
int _scrollThreshold;
|
||||
int _scrollAmount;
|
||||
|
||||
// Additional globals that need to be saved
|
||||
int _roomNumber;
|
||||
Common::Point _rawPlayerLow;
|
||||
Common::Point _rawPlayer;
|
||||
public:
|
||||
Player(AccessEngine *vm);
|
||||
virtual ~Player();
|
||||
static Player *init(AccessEngine *vm);
|
||||
|
||||
virtual void load();
|
||||
|
||||
void loadTexPalette();
|
||||
|
||||
void loadSprites(const Common::Path &name);
|
||||
|
||||
void freeSprites();
|
||||
|
||||
void removeSprite1();
|
||||
|
||||
void calcManScale();
|
||||
|
||||
void extracted();
|
||||
|
||||
void walk();
|
||||
|
||||
void calcPlayer();
|
||||
|
||||
bool scrollUp(int forcedAmount = -1);
|
||||
bool scrollDown(int forcedAmount = -1);
|
||||
bool scrollLeft(int forcedAmount = -1);
|
||||
bool scrollRight(int forcedAmount = -1);
|
||||
void checkScroll();
|
||||
|
||||
void checkMove();
|
||||
|
||||
/**
|
||||
* Synchronize savegame data
|
||||
*/
|
||||
void synchronize(Common::Serializer &s);
|
||||
};
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_PLAYER_H */
|
||||
241
engines/access/resources.cpp
Normal file
241
engines/access/resources.cpp
Normal file
@@ -0,0 +1,241 @@
|
||||
/* 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 "access/resources.h"
|
||||
#include "access/access.h"
|
||||
#include "access/amazon/amazon_resources.h"
|
||||
#include "access/martian/martian_resources.h"
|
||||
#include "common/translation.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
Resources *Resources::init(AccessEngine *vm) {
|
||||
if (vm->getGameID() == kGameAmazon)
|
||||
return new Amazon::AmazonResources(vm);
|
||||
else if (vm->getGameID() == kGameMartianMemorandum)
|
||||
return new Martian::MartianResources(vm);
|
||||
|
||||
error("Unknown game");
|
||||
}
|
||||
|
||||
bool Resources::load(Common::U32String &errorMessage) {
|
||||
Common::File f;
|
||||
Common::String filename = "access.dat";
|
||||
if (!f.open(filename.c_str())) {
|
||||
errorMessage = Common::U32String::format(_("Unable to locate the '%s' engine data file."), filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for the magic identifier
|
||||
char buffer[4];
|
||||
f.read(buffer, 4);
|
||||
if (strncmp(buffer, "SVMA", 4)) {
|
||||
errorMessage = Common::U32String::format(_("The '%s' engine data file is corrupt."), filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate the version number
|
||||
uint expectedVersion = 2;
|
||||
uint version = f.readUint16LE();
|
||||
if (version != expectedVersion) {
|
||||
errorMessage = Common::U32String::format(
|
||||
_("Incorrect version of the '%s' engine data file found. Expected %d.%d but got %d.%d."),
|
||||
filename.c_str(), expectedVersion, 0, version, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load in the index
|
||||
uint count = f.readUint16LE();
|
||||
_datIndex.resize(count);
|
||||
for (auto &datEntry : _datIndex) {
|
||||
datEntry._gameId = f.readByte();
|
||||
datEntry._discType = f.readByte();
|
||||
datEntry._demoType = f.readByte();
|
||||
|
||||
byte language = f.readByte();
|
||||
switch (language) {
|
||||
case 0:
|
||||
datEntry._language = (Common::Language)0;
|
||||
break;
|
||||
case 5:
|
||||
datEntry._language = Common::EN_ANY;
|
||||
break;
|
||||
case 23:
|
||||
datEntry._language = Common::ES_ESP;
|
||||
break;
|
||||
default:
|
||||
error("Unknown language");
|
||||
break;
|
||||
}
|
||||
|
||||
datEntry._fileOffset = f.readUint32LE();
|
||||
}
|
||||
|
||||
// Load in the data for the game
|
||||
load(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Resources::load(Common::SeekableReadStream &s) {
|
||||
uint count;
|
||||
|
||||
// Get the offset of the data for the game
|
||||
uint entryOffset = findEntry(_vm->getGameID(), _vm->isCD() ? 1 : 0,
|
||||
_vm->isDemo() ? 1 : 0, _vm->getLanguage());
|
||||
s.seek(entryOffset);
|
||||
|
||||
// Load filename list
|
||||
count = s.readUint16LE();
|
||||
FILENAMES.resize(count);
|
||||
for (uint idx = 0; idx < count; ++idx)
|
||||
FILENAMES[idx] = s.readString();
|
||||
|
||||
// Load the character data
|
||||
count = s.readUint16LE();
|
||||
CHARTBL.resize(count);
|
||||
for (uint idx = 0; idx < count; ++idx) {
|
||||
uint count2 = s.readUint16LE();
|
||||
CHARTBL[idx].resize(count2);
|
||||
if (count2 > 0)
|
||||
s.read(&CHARTBL[idx][0], count2);
|
||||
}
|
||||
|
||||
// Load the room data
|
||||
count = s.readUint16LE();
|
||||
ROOMTBL.resize(count);
|
||||
for (uint idx = 0; idx < count; ++idx) {
|
||||
ROOMTBL[idx]._desc = s.readString();
|
||||
ROOMTBL[idx]._travelPos.x = s.readSint16LE();
|
||||
ROOMTBL[idx]._travelPos.y = s.readSint16LE();
|
||||
uint count2 = s.readUint16LE();
|
||||
ROOMTBL[idx]._data.resize(count2);
|
||||
if (count2 > 0)
|
||||
s.read(&ROOMTBL[idx]._data[0], count2);
|
||||
}
|
||||
|
||||
// Load the deaths list
|
||||
count = s.readUint16LE();
|
||||
DEATHS.resize(count);
|
||||
for (uint idx = 0; idx < count; ++idx) {
|
||||
DEATHS[idx]._screenId = s.readByte();
|
||||
DEATHS[idx]._msg = s.readString();
|
||||
}
|
||||
|
||||
// Load in the inventory list
|
||||
count = s.readUint16LE();
|
||||
INVENTORY.resize(count);
|
||||
for (uint idx = 0; idx < count; ++idx) {
|
||||
INVENTORY[idx]._desc = s.readString();
|
||||
for (uint idx2 = 0; idx2 < 4; ++idx2)
|
||||
INVENTORY[idx]._combo[idx2] = s.readSint16LE();
|
||||
}
|
||||
}
|
||||
|
||||
uint Resources::findEntry(byte gameId, byte discType, byte demoType, Common::Language language) {
|
||||
for (const DATEntry &de : _datIndex) {
|
||||
if (de._gameId == gameId && de._discType == discType &&
|
||||
de._demoType == demoType && de._language == language)
|
||||
return de._fileOffset;
|
||||
}
|
||||
|
||||
error("Could not locate appropriate access.dat entry");
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
const byte INITIAL_PALETTE[18 * 3] = {
|
||||
0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff,
|
||||
0xf0, 0xf0, 0xf0,
|
||||
0xe0, 0xe0, 0xe0,
|
||||
0xd0, 0xd0, 0xd0,
|
||||
0xc0, 0xc0, 0xc0,
|
||||
0xb0, 0xb0, 0xb0,
|
||||
0xa0, 0xa0, 0xa0,
|
||||
0x90, 0x90, 0x90,
|
||||
0x80, 0x80, 0x80,
|
||||
0x70, 0x70, 0x70,
|
||||
0x60, 0x60, 0x60,
|
||||
0x50, 0x50, 0x50,
|
||||
0x40, 0x40, 0x40,
|
||||
0x30, 0x30, 0x30,
|
||||
0x20, 0x20, 0x20,
|
||||
0x10, 0x10, 0x10,
|
||||
0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
const char *const GENERAL_MESSAGES[] = {
|
||||
"LOOKING THERE REVEALS NOTHING OF INTEREST.", // LOOK_MESSAGE
|
||||
"THAT DOESN'T OPEN.", // OPEN_MESSAGE
|
||||
"THAT WON'T MOVE.", // MOVE_MESSAGE
|
||||
"YOU CAN'T TAKE THAT.", // GET_MESSAGE
|
||||
"THAT DOESN'T SEEM TO WORK.", // USE_MESSAGE
|
||||
"YOU CAN'T CLIMB THAT.", // GO_MESSAGE
|
||||
"THERE SEEMS TO BE NO RESPONSE.", // TALK_MESSAGE
|
||||
"THIS OBJECT REQUIRES NO HINTS", // HELP_MESSAGE
|
||||
"THIS OBJECT REQUIRES NO HINTS", // HELP_MESSAGE
|
||||
"THAT DOESN'T SEEM TO WORK." // USE_MESSAGE
|
||||
};
|
||||
|
||||
const char *const ESP_GENERAL_MESSAGES[] = {
|
||||
"MIRANDO AHI NO ENCONTRARAS NADA DE INTERES.", // LOOK_MESSAGE
|
||||
"NO ESTA ABIERTO.", // OPEN_MESSAGE
|
||||
"NO PUEDES MOVERLO.", // MOVE_MESSAGE
|
||||
"NO PUEDES COGER ESO.", // GET_MESSAGE
|
||||
"NO PARECE QUE FUNCIONE.", // USE_MESSAGE
|
||||
"NO PUEDES SUBIRTE A ESO.", // GO_MESSAGE
|
||||
"PARECE QUE NO TE RESPONDE.", // TALK_MESSAGE
|
||||
"NO HAY AYUDA PARA ESE OBJETO.", // HELP_MESSAGE
|
||||
"NO HAY AYUDA PARA ESE OBJETO.", // HELP_MESSAGE
|
||||
"NO PARECE QUE FUNCIONE." // USE_MESSAGE
|
||||
};
|
||||
|
||||
const int INVCOORDS[][4] = {
|
||||
{ 23, 68, 15, 49 },
|
||||
{ 69, 114, 15, 49 },
|
||||
{ 115, 160, 15, 49 },
|
||||
{ 161, 206, 15, 49 },
|
||||
{ 207, 252, 15, 49 },
|
||||
{ 253, 298, 15, 49 },
|
||||
{ 23, 68, 50, 84 },
|
||||
{ 69, 114, 50, 84 },
|
||||
{ 115, 160, 50, 84 },
|
||||
{ 161, 206, 50, 84 },
|
||||
{ 207, 252, 50, 84 },
|
||||
{ 253, 298, 50, 84 },
|
||||
{ 23, 68, 85, 119 },
|
||||
{ 69, 114, 85, 119 },
|
||||
{ 115, 160, 85, 119 },
|
||||
{ 161, 206, 85, 119 },
|
||||
{ 207, 252, 85, 119 },
|
||||
{ 253, 298, 85, 119 },
|
||||
{ 23, 68, 120, 154 },
|
||||
{ 69, 114, 120, 154 },
|
||||
{ 115, 160, 120, 154 },
|
||||
{ 161, 206, 120, 154 },
|
||||
{ 207, 252, 120, 154 },
|
||||
{ 253, 298, 120, 154 },
|
||||
{ 237, 298, 177, 193 },
|
||||
{ 25, 85, 177, 193 }
|
||||
};
|
||||
|
||||
} // End of namespace Access
|
||||
120
engines/access/resources.h
Normal file
120
engines/access/resources.h
Normal file
@@ -0,0 +1,120 @@
|
||||
/* 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 ACCESS_RESOURCES_H
|
||||
#define ACCESS_RESOURCES_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/array.h"
|
||||
#include "common/language.h"
|
||||
#include "common/path.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/str-array.h"
|
||||
#include "common/stream.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
extern const byte INITIAL_PALETTE[18 * 3];
|
||||
|
||||
extern const char *const GENERAL_MESSAGES[];
|
||||
extern const char *const ESP_GENERAL_MESSAGES[];
|
||||
|
||||
extern const int INVCOORDS[][4];
|
||||
|
||||
class AccessEngine;
|
||||
|
||||
class Resources {
|
||||
struct DATEntry {
|
||||
byte _gameId;
|
||||
byte _discType;
|
||||
byte _demoType;
|
||||
Common::Language _language;
|
||||
uint _fileOffset;
|
||||
};
|
||||
struct DeathEntry {
|
||||
byte _screenId;
|
||||
Common::String _msg;
|
||||
};
|
||||
struct InventoryEntry {
|
||||
Common::String _desc;
|
||||
int _combo[4];
|
||||
};
|
||||
protected:
|
||||
struct RoomEntry {
|
||||
Common::String _desc;
|
||||
Common::Point _travelPos;
|
||||
Common::Array<byte> _data;
|
||||
};
|
||||
|
||||
AccessEngine *_vm;
|
||||
Common::Array<DATEntry> _datIndex;
|
||||
|
||||
/**
|
||||
* Locate a specified entry in the index and return it's file offset
|
||||
*/
|
||||
uint findEntry(byte gameId, byte discType, byte demoType, Common::Language language);
|
||||
|
||||
/**
|
||||
* Load data from the access.dat file
|
||||
*/
|
||||
virtual void load(Common::SeekableReadStream &s);
|
||||
public:
|
||||
Common::Array<Common::Path> FILENAMES;
|
||||
Common::Array< Common::Array<byte> > CHARTBL;
|
||||
Common::Array<RoomEntry> ROOMTBL;
|
||||
Common::Array<DeathEntry> DEATHS;
|
||||
Common::Array<InventoryEntry> INVENTORY;
|
||||
Common::String CANT_GET_THERE;
|
||||
public:
|
||||
Resources(AccessEngine *vm) : _vm(vm) {}
|
||||
virtual ~Resources() {}
|
||||
static Resources *init(AccessEngine *vm);
|
||||
|
||||
/**
|
||||
* Load the access.dat file
|
||||
*/
|
||||
bool load(Common::U32String &errorMessage);
|
||||
|
||||
/**
|
||||
* Get the raw data for the given cursor number
|
||||
*/
|
||||
virtual const byte *getCursor(int num) const = 0;
|
||||
|
||||
/**
|
||||
* Get the name of the lead character
|
||||
*/
|
||||
virtual const char *getEgoName() const = 0;
|
||||
|
||||
/**
|
||||
* Get the room mouse values
|
||||
*/
|
||||
virtual int getRMouse(int i, int j) const = 0;
|
||||
|
||||
/**
|
||||
* Find if the mouse X is inside the range for a button,
|
||||
* or -1 if no button range matches.
|
||||
*/
|
||||
virtual int inButtonXRange(int x) const = 0;
|
||||
};
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_RESOURCES_H */
|
||||
1014
engines/access/room.cpp
Normal file
1014
engines/access/room.cpp
Normal file
File diff suppressed because it is too large
Load Diff
207
engines/access/room.h
Normal file
207
engines/access/room.h
Normal file
@@ -0,0 +1,207 @@
|
||||
/* 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 ACCESS_ROOM_H
|
||||
#define ACCESS_ROOM_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/array.h"
|
||||
#include "common/rect.h"
|
||||
#include "access/data.h"
|
||||
|
||||
#define TILE_WIDTH 16
|
||||
#define TILE_HEIGHT 16
|
||||
|
||||
namespace Access {
|
||||
|
||||
class Plotter {
|
||||
public:
|
||||
Common::Array<Common::Rect> _walls;
|
||||
Common::Array<Common::Rect> _blocks;
|
||||
int _blockIn;
|
||||
int _delta;
|
||||
public:
|
||||
Plotter();
|
||||
|
||||
void load(Common::SeekableReadStream *stream, int wallCount, int blockCount);
|
||||
};
|
||||
|
||||
class JetFrame {
|
||||
public:
|
||||
int _wallCode;
|
||||
int _wallCodeOld;
|
||||
int _wallCode1;
|
||||
int _wallCode1Old;
|
||||
|
||||
JetFrame() {
|
||||
_wallCode = _wallCodeOld = 0;
|
||||
_wallCode1 = _wallCode1Old = 0;
|
||||
}
|
||||
};
|
||||
|
||||
enum Function { FN_NONE = 0, FN_CLEAR1 = 1, FN_CLEAR2 = 2, FN_RELOAD = 3, FN_BREAK = 4 };
|
||||
|
||||
class Room : public Manager {
|
||||
private:
|
||||
void roomLoop();
|
||||
|
||||
void loadPlayField(int fileNum, int subfile);
|
||||
|
||||
void commandOff();
|
||||
|
||||
void swapOrg();
|
||||
int calcLR(int yp);
|
||||
int calcUD(int xp);
|
||||
|
||||
void takePicture();
|
||||
|
||||
/**
|
||||
* Cycles forwards or backwards through the list of commands
|
||||
*/
|
||||
void cycleCommand(int incr);
|
||||
|
||||
bool checkCode(int v1, int v2);
|
||||
protected:
|
||||
void loadRoomData(const byte *roomData);
|
||||
|
||||
/**
|
||||
* Free the playfield data
|
||||
*/
|
||||
void freePlayField();
|
||||
|
||||
/**
|
||||
* Free tile data
|
||||
*/
|
||||
void freeTileData();
|
||||
|
||||
int checkBoxes();
|
||||
int checkBoxes1(const Common::Point &pt);
|
||||
int checkBoxes2(const Common::Point &pt, int start, int count);
|
||||
void checkBoxes3();
|
||||
|
||||
int validateBox(int boxId);
|
||||
|
||||
/**
|
||||
* Inner handler for switching to a given command mode
|
||||
*/
|
||||
void executeCommand(int commandId);
|
||||
|
||||
void clearCamera();
|
||||
|
||||
virtual void roomInit();
|
||||
|
||||
virtual void reloadRoom() = 0;
|
||||
|
||||
virtual void reloadRoom1() = 0;
|
||||
|
||||
virtual void setupRoom();
|
||||
|
||||
virtual void doCommands();
|
||||
|
||||
virtual void mainAreaClick() = 0;
|
||||
|
||||
virtual void walkCursor();
|
||||
public:
|
||||
Plotter _plotter;
|
||||
Common::Array<JetFrame> _jetFrame;
|
||||
Function _function;
|
||||
int _roomFlag;
|
||||
byte *_playField;
|
||||
int _matrixSize;
|
||||
int _playFieldWidth;
|
||||
int _playFieldHeight;
|
||||
byte *_tile;
|
||||
int _selectCommand;
|
||||
bool _conFlag;
|
||||
int _rMouse[10][2];
|
||||
public:
|
||||
Room(AccessEngine *vm);
|
||||
|
||||
virtual ~Room();
|
||||
|
||||
void doRoom();
|
||||
|
||||
virtual void loadRoom(int roomNumber) = 0;
|
||||
|
||||
virtual void roomMenu() = 0;
|
||||
|
||||
/**
|
||||
* Clear all the data used by the room
|
||||
*/
|
||||
virtual void clearRoom();
|
||||
|
||||
/**
|
||||
* Builds up a game screen
|
||||
*/
|
||||
void buildScreen();
|
||||
|
||||
/**
|
||||
* Draw a column of a game scene
|
||||
*/
|
||||
void buildColumn(int playX, int screenX);
|
||||
|
||||
/**
|
||||
* Draw a row of a game scene
|
||||
*/
|
||||
void buildRow(int playY, int screenY);
|
||||
|
||||
virtual void init4Quads() = 0;
|
||||
|
||||
void setWallCodes();
|
||||
|
||||
bool codeWalls();
|
||||
|
||||
/**
|
||||
* Switch to a given command mode
|
||||
*/
|
||||
void handleCommand(int commandId);
|
||||
};
|
||||
|
||||
class RoomInfo {
|
||||
public:
|
||||
struct SoundIdent : FileIdent {
|
||||
int _priority;
|
||||
};
|
||||
public:
|
||||
int _roomFlag;
|
||||
int _estIndex;
|
||||
FileIdent _musicFile;
|
||||
int _scaleH1;
|
||||
int _scaleH2;
|
||||
int _scaleN1;
|
||||
FileIdent _playFieldFile;
|
||||
Common::Array<CellIdent> _cells;
|
||||
FileIdent _scriptFile;
|
||||
FileIdent _animFile;
|
||||
int _scaleI;
|
||||
int _scrollThreshold;
|
||||
FileIdent _paletteFile;
|
||||
int _startColor;
|
||||
int _numColors;
|
||||
Common::Array<ExtraCell> _extraCells;
|
||||
Common::Array<SoundIdent> _sounds;
|
||||
public:
|
||||
RoomInfo(const byte *data, int gameType, bool isCD, bool isDemo);
|
||||
};
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_ROOM_H */
|
||||
378
engines/access/screen.cpp
Normal file
378
engines/access/screen.cpp
Normal file
@@ -0,0 +1,378 @@
|
||||
/* 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 "common/algorithm.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/system.h"
|
||||
#include "graphics/paletteman.h"
|
||||
#include "graphics/palette.h"
|
||||
#include "access/access.h"
|
||||
#include "access/screen.h"
|
||||
#include "access/resources.h"
|
||||
#include "access/martian/martian_resources.h"
|
||||
|
||||
|
||||
// for frame contents debugging
|
||||
//#define DEBUG_FRAME_DUMP 1
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
#include "graphics/paletteman.h"
|
||||
#include "image/png.h"
|
||||
#include "common/path.h"
|
||||
#include "common/file.h"
|
||||
#endif
|
||||
|
||||
namespace Access {
|
||||
|
||||
ScreenSave::ScreenSave() : _clipWidth(0), _clipHeight(0), _windowXAdd(0), _windowYAdd(0), _scrollCol(0), _scrollRow(0), _screenYOff(0) {
|
||||
}
|
||||
|
||||
Screen::Screen(AccessEngine *vm) : _vm(vm) {
|
||||
Graphics::Screen::create(320, 200);
|
||||
Common::fill(&_tempPalette[0], &_tempPalette[Graphics::PALETTE_SIZE], 0);
|
||||
Common::fill(&_manPal[0], &_manPal[0x60], 0);
|
||||
Common::fill(&_scaleTable1[0], &_scaleTable1[256], 0);
|
||||
Common::fill(&_scaleTable2[0], &_scaleTable2[256], 0);
|
||||
_savedPaletteCount = 0;
|
||||
if (_vm->isCD())
|
||||
_vesaMode = 0;
|
||||
else
|
||||
_vesaMode = 1;
|
||||
|
||||
_vesaCurrentWin = 0;
|
||||
_currentPanel = 0;
|
||||
_hideFlag = true;
|
||||
_startColor = _numColors = 0;
|
||||
_windowXAdd = _windowYAdd = 0;
|
||||
_screenYOff = 0;
|
||||
_screenChangeFlag = false;
|
||||
|
||||
_bufferBytesWide = _vWindowBytesWide = this->w;
|
||||
_vWindowLinesTall = this->h;
|
||||
_vWindowWidth = _vWindowHeight = 0;
|
||||
_clipWidth = _vWindowBytesWide - 1;
|
||||
_clipHeight = _vWindowLinesTall - 1;
|
||||
_startCycle = 0;
|
||||
_cycleStart = 0;
|
||||
_endCycle = 0;
|
||||
_fadeIn = false;
|
||||
|
||||
for (int i = 0; i < Graphics::PALETTE_SIZE; ++i) {
|
||||
_rawPalette[i] = 0;
|
||||
_savedPalettes[0][i] = 0;
|
||||
_savedPalettes[1][i] = 0;
|
||||
_tempPalette[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::clearScreen() {
|
||||
clearBuffer();
|
||||
if (_vesaMode)
|
||||
_vm->_clearSummaryFlag = true;
|
||||
}
|
||||
|
||||
void Screen::setDisplayScan() {
|
||||
_clipWidth = this->w - 1;
|
||||
_clipHeight = this->h - 1;
|
||||
_windowXAdd = _windowYAdd = 0;
|
||||
_vm->_scrollX = _vm->_scrollY = 0;
|
||||
_vm->_scrollCol = _vm->_scrollRow = 0;
|
||||
_bufferStart.x = _bufferStart.y = 0;
|
||||
_screenYOff = 0;
|
||||
}
|
||||
|
||||
void Screen::setPanel(int num) {
|
||||
assert(num < 4);
|
||||
_currentPanel = num;
|
||||
_msVirtualOffset = _virtualOffsetsTable[num];
|
||||
}
|
||||
|
||||
void Screen::update() {
|
||||
if (_vm->_startup >= 0) {
|
||||
if (--_vm->_startup == -1)
|
||||
_fadeIn = true;
|
||||
return;
|
||||
}
|
||||
markAllDirty();//****DEBUG****
|
||||
Graphics::Screen::update();
|
||||
}
|
||||
|
||||
void Screen::setInitialPalettte() {
|
||||
Common::copy(&INITIAL_PALETTE[0], &INITIAL_PALETTE[18 * 3], _rawPalette);
|
||||
Common::fill(&_rawPalette[18 * 3], &_rawPalette[Graphics::PALETTE_SIZE], 0);
|
||||
|
||||
g_system->getPaletteManager()->setPalette(INITIAL_PALETTE, 0, 18);
|
||||
}
|
||||
|
||||
void Screen::setManPalette() {
|
||||
// Player palette is colors 224~246
|
||||
for (int i = 0; i < 0x42; i++) {
|
||||
_rawPalette[672 + i] = PALETTE_6BIT_TO_8BIT(_manPal[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::setIconPalette() {
|
||||
// Icon palette is colors 247~255
|
||||
if (_vm->getGameID() == kGameMartianMemorandum) {
|
||||
for (int i = 0; i < 0x1B; i++) {
|
||||
_rawPalette[741 + i] = PALETTE_6BIT_TO_8BIT(Martian::ICON_PALETTE[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::loadPalette(int fileNum, int subfile, int srcOffset) {
|
||||
Resource *res = _vm->_files->loadFile(fileNum, subfile);
|
||||
const byte *palette = res->data() + srcOffset;
|
||||
|
||||
if (_vm->getGameID() == kGameMartianMemorandum) {
|
||||
for (int i = 0; i < _numColors * 3; i++)
|
||||
_rawPalette[_startColor * 3 + i] = PALETTE_6BIT_TO_8BIT(palette[i]);
|
||||
} else {
|
||||
// TODO: is this right for Amazon? Surely it should be converted? Maybe never used..
|
||||
Common::copy(palette, palette + (_numColors * 3), &_rawPalette[_startColor * 3]);
|
||||
}
|
||||
delete res;
|
||||
}
|
||||
|
||||
void Screen::setPalette() {
|
||||
g_system->getPaletteManager()->setPalette(&_rawPalette[0], 0, Graphics::PALETTE_COUNT);
|
||||
}
|
||||
|
||||
void Screen::loadRawPalette(Common::SeekableReadStream *stream) {
|
||||
stream->read(&_rawPalette[0], Graphics::PALETTE_SIZE);
|
||||
for (byte *p = &_rawPalette[0]; p < &_rawPalette[Graphics::PALETTE_SIZE]; ++p)
|
||||
*p = PALETTE_6BIT_TO_8BIT(*p);
|
||||
}
|
||||
|
||||
void Screen::updatePalette() {
|
||||
g_system->getPaletteManager()->setPalette(&_tempPalette[0], 0, Graphics::PALETTE_COUNT);
|
||||
update();
|
||||
}
|
||||
|
||||
void Screen::savePalette() {
|
||||
Common::copy(&_rawPalette[0], &_rawPalette[Graphics::PALETTE_SIZE],
|
||||
&_savedPalettes[_savedPaletteCount][0]);
|
||||
|
||||
if (++_savedPaletteCount == 2)
|
||||
_savedPaletteCount = 1;
|
||||
}
|
||||
|
||||
void Screen::restorePalette() {
|
||||
if (--_savedPaletteCount < 0)
|
||||
_savedPaletteCount = 0;
|
||||
|
||||
Common::copy(&_savedPalettes[_savedPaletteCount][0],
|
||||
&_savedPalettes[_savedPaletteCount][Graphics::PALETTE_SIZE], &_rawPalette[0]);
|
||||
}
|
||||
|
||||
void Screen::getPalette(byte *pal) {
|
||||
g_system->getPaletteManager()->grabPalette(pal, 0, 256);
|
||||
}
|
||||
|
||||
void Screen::forceFadeOut() {
|
||||
const int FADE_AMOUNT = 2;
|
||||
bool repeatFlag;
|
||||
byte *srcP;
|
||||
int count;
|
||||
|
||||
do {
|
||||
repeatFlag = false;
|
||||
for (srcP = &_tempPalette[0], count = 0; count < Graphics::PALETTE_SIZE; ++count, ++srcP) {
|
||||
int v = *srcP;
|
||||
if (v) {
|
||||
repeatFlag = true;
|
||||
*srcP = MAX((int)*srcP - FADE_AMOUNT, 0);
|
||||
}
|
||||
}
|
||||
|
||||
updatePalette();
|
||||
_vm->_events->pollEventsAndWait();
|
||||
} while (repeatFlag && !_vm->shouldQuit());
|
||||
}
|
||||
|
||||
void Screen::forceFadeIn() {
|
||||
Common::fill(&_tempPalette[0], &_tempPalette[Graphics::PALETTE_SIZE], 0);
|
||||
|
||||
const int FADE_AMOUNT = 2;
|
||||
bool repeatFlag;
|
||||
do {
|
||||
repeatFlag = false;
|
||||
const byte *srcP = &_rawPalette[0];
|
||||
byte *destP = &_tempPalette[0];
|
||||
|
||||
for (int idx = 0; idx < Graphics::PALETTE_SIZE; ++idx, ++srcP, ++destP) {
|
||||
if (*destP != *srcP) {
|
||||
repeatFlag = true;
|
||||
*destP = MIN((int)*destP + FADE_AMOUNT, (int)*srcP);
|
||||
}
|
||||
}
|
||||
|
||||
updatePalette();
|
||||
_vm->_events->pollEventsAndWait();
|
||||
} while (repeatFlag);
|
||||
}
|
||||
|
||||
void Screen::copyBuffer(const byte *data) {
|
||||
byte *destP = (byte *)getPixels();
|
||||
Common::copy(data, data + (h * w), destP);
|
||||
g_system->copyRectToScreen(destP, w, 0, 0, w, h);
|
||||
}
|
||||
|
||||
void Screen::setBufferScan() {
|
||||
_clipWidth = _vWindowBytesWide - 1;
|
||||
_windowXAdd = (320 - _clipWidth) >> 1;
|
||||
_clipHeight = _vWindowLinesTall - 1;
|
||||
_windowYAdd = (176 - _clipHeight) >> 1;
|
||||
}
|
||||
|
||||
void Screen::setScaleTable(int scale) {
|
||||
int total = 0;
|
||||
for (int idx = 0; idx < ARRAYSIZE(_scaleTable1); ++idx) {
|
||||
_scaleTable1[idx] = total >> 8;
|
||||
_scaleTable2[idx] = total & 0xff;
|
||||
total += scale;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::saveScreen() {
|
||||
_screenSave._clipWidth = _clipWidth;
|
||||
_screenSave._clipHeight = _clipHeight;
|
||||
_screenSave._windowXAdd = _windowXAdd;
|
||||
_screenSave._windowYAdd = _windowYAdd;
|
||||
_screenSave._scroll.x = _vm->_scrollX;
|
||||
_screenSave._scroll.y = _vm->_scrollY;
|
||||
_screenSave._scrollCol = _vm->_scrollCol;
|
||||
_screenSave._scrollRow = _vm->_scrollRow;
|
||||
_screenSave._bufferStart.x = _bufferStart.x;
|
||||
_screenSave._bufferStart.y = _bufferStart.y;
|
||||
_screenSave._screenYOff = _screenYOff;
|
||||
}
|
||||
|
||||
void Screen::restoreScreen() {
|
||||
_clipWidth = _screenSave._clipWidth;
|
||||
_clipHeight = _screenSave._clipHeight;
|
||||
_windowXAdd = _screenSave._windowXAdd;
|
||||
_windowYAdd = _screenSave._windowYAdd;
|
||||
_vm->_scrollX = _screenSave._scroll.x;
|
||||
_vm->_scrollY = _screenSave._scroll.y;
|
||||
_vm->_scrollCol = _screenSave._scrollCol;
|
||||
_vm->_scrollRow = _screenSave._scrollRow;
|
||||
_bufferStart.x = _screenSave._bufferStart.x;
|
||||
_bufferStart.y = _screenSave._bufferStart.y;
|
||||
_screenYOff = _screenSave._screenYOff;
|
||||
}
|
||||
|
||||
void Screen::copyBlock(const BaseSurface *src, const Common::Rect &bounds) {
|
||||
Common::Rect destBounds = bounds;
|
||||
destBounds.translate(_windowXAdd, _windowYAdd + _screenYOff);
|
||||
|
||||
copyRectToSurface(*src, destBounds.left, destBounds.top, bounds);
|
||||
addDirtyRect(destBounds);
|
||||
}
|
||||
|
||||
void Screen::restoreBlock() {
|
||||
if (!_savedBounds.isEmpty())
|
||||
addDirtyRect(_savedBounds);
|
||||
BaseSurface::restoreBlock();
|
||||
}
|
||||
|
||||
void Screen::drawRect() {
|
||||
addDirtyRect(Common::Rect(_orgX1, _orgY1, _orgX2, _orgY2));
|
||||
BaseSurface::drawRect();
|
||||
}
|
||||
|
||||
void Screen::drawBox() {
|
||||
addDirtyRect(Common::Rect(_orgX1, _orgY1, _orgX2, _orgY2));
|
||||
BaseSurface::drawBox();
|
||||
}
|
||||
|
||||
void Screen::copyBuffer(Graphics::ManagedSurface *src) {
|
||||
addDirtyRect(Common::Rect(0, 0, src->w, src->h));
|
||||
BaseSurface::copyBuffer(src);
|
||||
}
|
||||
|
||||
void Screen::setPaletteCycle(int startCycle, int endCycle, int timer) {
|
||||
_startCycle = _cycleStart = startCycle;
|
||||
_endCycle = endCycle;
|
||||
|
||||
TimerEntry &te = _vm->_timers[6];
|
||||
te._timer = te._initTm = timer;
|
||||
te._flag++;
|
||||
}
|
||||
|
||||
void Screen::cyclePaletteForward() {
|
||||
cyclePaletteBackwards();
|
||||
}
|
||||
|
||||
void Screen::cyclePaletteBackwards() {
|
||||
if (!_vm->_timers[6]._flag) {
|
||||
_vm->_timers[6]._flag++;
|
||||
byte *pStart = &_rawPalette[_cycleStart * 3];
|
||||
byte *pEnd = &_rawPalette[_endCycle * 3];
|
||||
|
||||
for (int idx = _startCycle; idx < _endCycle; ++idx) {
|
||||
g_system->getPaletteManager()->setPalette(pStart, idx, 1);
|
||||
|
||||
pStart += 3;
|
||||
if (pStart == pEnd)
|
||||
pStart = &_rawPalette[_cycleStart * 3];
|
||||
}
|
||||
|
||||
if (--_cycleStart <= _startCycle)
|
||||
_cycleStart = _endCycle - 1;
|
||||
|
||||
g_system->updateScreen();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::flashPalette(int step) {
|
||||
// Note: Original parameter is for 64-level palette
|
||||
step *= 4;
|
||||
|
||||
for (int i = 0; i < Graphics::PALETTE_SIZE; ++i) {
|
||||
_tempPalette[i] = (byte)MIN(_rawPalette[i] + step, 255);
|
||||
}
|
||||
|
||||
updatePalette();
|
||||
_vm->_events->pollEventsAndWait();
|
||||
|
||||
// Ensure at least 1 frame delay at 30FPS before resetting palette
|
||||
// to ensure the effect is perceptible and matches original.
|
||||
_vm->_events->delay(30);
|
||||
setPalette();
|
||||
_vm->_events->pollEventsAndWait();
|
||||
}
|
||||
|
||||
void Screen::dump(const char *fname) const {
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
// For debugging, dump the frame contents.
|
||||
::Common::DumpFile outf;
|
||||
uint32 now = g_system->getMillis();
|
||||
outf.open(::Common::Path(::Common::String::format("/tmp/%07d-%s.png", now, fname)));
|
||||
::Image::writePNG(outf, *this, _rawPalette);
|
||||
outf.close();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // End of namespace Access
|
||||
180
engines/access/screen.h
Normal file
180
engines/access/screen.h
Normal file
@@ -0,0 +1,180 @@
|
||||
/* 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 ACCESS_SCREEN_H
|
||||
#define ACCESS_SCREEN_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/stream.h"
|
||||
#include "graphics/screen.h"
|
||||
#include "access/asurface.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
class AccessEngine;
|
||||
|
||||
struct ScreenSave {
|
||||
int _clipWidth;
|
||||
int _clipHeight;
|
||||
int _windowXAdd;
|
||||
int _windowYAdd;
|
||||
Common::Point _scroll;
|
||||
int _scrollCol;
|
||||
int _scrollRow;
|
||||
Common::Point _bufferStart;
|
||||
int _screenYOff;
|
||||
|
||||
ScreenSave();
|
||||
};
|
||||
|
||||
class Screen : public BaseSurface {
|
||||
private:
|
||||
AccessEngine *_vm;
|
||||
byte _tempPalette[Graphics::PALETTE_SIZE];
|
||||
byte _rawPalette[Graphics::PALETTE_SIZE];
|
||||
byte _savedPalettes[2][Graphics::PALETTE_SIZE];
|
||||
int _savedPaletteCount;
|
||||
int _vesaCurrentWin;
|
||||
int _currentPanel;
|
||||
Common::Point _msVirtualOffset;
|
||||
Common::Point _virtualOffsetsTable[4];
|
||||
bool _hideFlag;
|
||||
ScreenSave _screenSave;
|
||||
int _startCycle;
|
||||
int _cycleStart;
|
||||
int _endCycle;
|
||||
|
||||
void updatePalette();
|
||||
public:
|
||||
int _vesaMode;
|
||||
int _startColor, _numColors;
|
||||
Common::Point _bufferStart;
|
||||
int _windowXAdd, _windowYAdd;
|
||||
int _screenYOff;
|
||||
byte _manPal[0x60];
|
||||
byte _scaleTable1[256];
|
||||
byte _scaleTable2[256];
|
||||
int _vWindowWidth;
|
||||
int _vWindowHeight;
|
||||
int _vWindowBytesWide;
|
||||
int _bufferBytesWide;
|
||||
int _vWindowLinesTall;
|
||||
bool _screenChangeFlag;
|
||||
bool _fadeIn;
|
||||
public:
|
||||
/**
|
||||
* Updates the screen
|
||||
*/
|
||||
void update() override;
|
||||
|
||||
void copyBlock(const BaseSurface *src, const Common::Rect &bounds) override;
|
||||
|
||||
void restoreBlock() override;
|
||||
|
||||
void drawRect() override;
|
||||
|
||||
void drawBox() override;
|
||||
|
||||
void copyBuffer(Graphics::ManagedSurface *src) override;
|
||||
public:
|
||||
Screen(AccessEngine *vm);
|
||||
|
||||
~Screen() override {}
|
||||
|
||||
void setDisplayScan();
|
||||
|
||||
void setPanel(int num);
|
||||
|
||||
/**
|
||||
* Fade out screen
|
||||
*/
|
||||
void forceFadeOut();
|
||||
|
||||
/**
|
||||
* Fade in screen
|
||||
*/
|
||||
void forceFadeIn();
|
||||
|
||||
void fadeOut() { forceFadeOut(); }
|
||||
void fadeIn() { forceFadeIn(); }
|
||||
void clearScreen();
|
||||
|
||||
/**
|
||||
* Set the initial palette
|
||||
*/
|
||||
void setInitialPalettte();
|
||||
|
||||
/**
|
||||
* Set icon palette
|
||||
*/
|
||||
void setIconPalette();
|
||||
|
||||
/**
|
||||
* Set Tex palette (Martian Memorandum)
|
||||
*/
|
||||
void setManPalette();
|
||||
|
||||
void loadPalette(int fileNum, int subfile, int srcOffset = 0);
|
||||
|
||||
void setPalette();
|
||||
|
||||
void loadRawPalette(Common::SeekableReadStream *stream);
|
||||
|
||||
void savePalette();
|
||||
|
||||
void restorePalette();
|
||||
|
||||
void getPalette(byte *pal);
|
||||
|
||||
void flashPalette(int step);
|
||||
|
||||
/**
|
||||
* Copy a buffer to the screen
|
||||
*/
|
||||
void copyBuffer(const byte *data);
|
||||
|
||||
void setBufferScan();
|
||||
|
||||
void setScaleTable(int scale);
|
||||
|
||||
/**
|
||||
* Save all the screen display state variables
|
||||
*/
|
||||
void saveScreen();
|
||||
|
||||
/**
|
||||
* Restores previously saved screen display state variables
|
||||
*/
|
||||
void restoreScreen();
|
||||
|
||||
void setPaletteCycle(int startCycle, int endCycle, int timer);
|
||||
|
||||
void cyclePaletteForward();
|
||||
|
||||
void cyclePaletteBackwards();
|
||||
|
||||
void dump(const char *fname) const;
|
||||
};
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_SCREEN_H */
|
||||
1261
engines/access/scripts.cpp
Normal file
1261
engines/access/scripts.cpp
Normal file
File diff suppressed because it is too large
Load Diff
183
engines/access/scripts.h
Normal file
183
engines/access/scripts.h
Normal file
@@ -0,0 +1,183 @@
|
||||
/* 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 ACCESS_SCRIPTS_H
|
||||
#define ACCESS_SCRIPTS_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/memstream.h"
|
||||
#include "access/data.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
class AccessEngine;
|
||||
class Scripts;
|
||||
|
||||
#define SCRIPT_START_BYTE 0xE0
|
||||
#define ROOM_SCRIPT 2000
|
||||
#define INIT_ROOM_SCRIPT 1000
|
||||
|
||||
typedef void(Scripts::*ScriptMethodPtr)();
|
||||
|
||||
class Scripts : public Manager {
|
||||
friend class Debugger;
|
||||
|
||||
private:
|
||||
int _specialFunction;
|
||||
|
||||
void clearWatch();
|
||||
void printWatch();
|
||||
|
||||
protected:
|
||||
Resource *_resource;
|
||||
Common::SeekableReadStream *_data;
|
||||
ScriptMethodPtr COMMAND_LIST[100];
|
||||
|
||||
virtual void executeSpecial(int commandIndex, int param1, int param2) = 0;
|
||||
virtual void executeCommand(int commandIndex);
|
||||
|
||||
void charLoop();
|
||||
|
||||
void cmdObject();
|
||||
void cmdEndObject();
|
||||
void cmdJumpLook();
|
||||
void cmdJumpOpen();
|
||||
void cmdJumpHelp();
|
||||
void cmdJumpGet();
|
||||
void cmdJumpMove();
|
||||
void cmdJumpUse();
|
||||
void cmdJumpTalk();
|
||||
void cmdNull();
|
||||
void cmdPrint_v1();
|
||||
void cmdPrint_v2();
|
||||
void cmdAnim();
|
||||
void cmdSetFlag();
|
||||
void cmdCheckFlag();
|
||||
|
||||
/**
|
||||
* Jump to another script
|
||||
*/
|
||||
void cmdGoto();
|
||||
|
||||
void cmdAddScore();
|
||||
void cmdSetInventory();
|
||||
void cmdCheckInventory();
|
||||
void cmdSetTex();
|
||||
void cmdNewRoom();
|
||||
void cmdConverse();
|
||||
void cmdCheckFrame();
|
||||
void cmdCheckAnim();
|
||||
void cmdSnd();
|
||||
void cmdRetNeg();
|
||||
void cmdCheckLoc();
|
||||
void cmdSetAnim();
|
||||
void cmdDispInv_v1();
|
||||
void cmdDispInv_v2();
|
||||
void cmdSetAbout();
|
||||
void cmdSetTimer();
|
||||
void cmdCheckTimer();
|
||||
void cmdJumpGoto();
|
||||
void cmdSetTravel();
|
||||
void cmdSetVideo();
|
||||
void cmdPlayVideo();
|
||||
void cmdPlotImage();
|
||||
void cmdSetDisplay();
|
||||
void cmdSetBuffer();
|
||||
void cmdSetScroll();
|
||||
void cmdSaveRect();
|
||||
void cmdVideoEnded();
|
||||
void cmdSetBufVid();
|
||||
void cmdPlayBufVid();
|
||||
void cmdRemoveLast();
|
||||
void cmdDoTravel();
|
||||
void cmdCheckAbout();
|
||||
void cmdSpecial();
|
||||
void cmdSetCycle();
|
||||
void cmdCycle();
|
||||
void cmdCharSpeak();
|
||||
void cmdTexSpeak();
|
||||
void cmdTexChoice();
|
||||
void cmdWait();
|
||||
void cmdSetConPos();
|
||||
void cmdCheckVFrame();
|
||||
void cmdJumpChoice();
|
||||
void cmdReturnChoice();
|
||||
void cmdClearBlock();
|
||||
void cmdLoadSound();
|
||||
void cmdSetVideoSound();
|
||||
void cmdPlayVideoSound();
|
||||
void cmdPrintWatch();
|
||||
void cmdDispAbout();
|
||||
void cmdPushLocation();
|
||||
void cmdPushLocation_v1();
|
||||
void cmdCheckTravel();
|
||||
void cmdBlock();
|
||||
void cmdPlayerOff();
|
||||
void cmdPlayerOn();
|
||||
void cmdDead();
|
||||
void cmdFadeOut();
|
||||
void cmdEndVideo();
|
||||
void cmdHelp_v1();
|
||||
void cmdHelp_v2();
|
||||
void cmdCycleBack();
|
||||
void cmdSetHelp();
|
||||
public:
|
||||
int _sequence;
|
||||
bool _endFlag;
|
||||
int _returnCode;
|
||||
int _scriptCommand;
|
||||
int _choice;
|
||||
int32 _choiceStart;
|
||||
Common::Point _charsOrg, _texsOrg;
|
||||
|
||||
public:
|
||||
Scripts(AccessEngine *vm);
|
||||
|
||||
virtual ~Scripts();
|
||||
|
||||
void setOpcodes();
|
||||
void setOpcodes_v2();
|
||||
|
||||
void setScript(Resource *data, bool restartFlag = false);
|
||||
|
||||
void freeScriptData();
|
||||
|
||||
void searchForSequence();
|
||||
|
||||
int executeScript();
|
||||
|
||||
void findNull();
|
||||
void doCmdPrint_v1(const Common::String &msg);
|
||||
|
||||
/**
|
||||
* Print a given message to the screen in a bubble box
|
||||
*/
|
||||
void printString(const Common::String &msg);
|
||||
|
||||
// Script commands that need to be public
|
||||
void cmdFreeSound();
|
||||
void cmdRetPos();
|
||||
void converse1(int val);
|
||||
};
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_SCRIPTS_H */
|
||||
425
engines/access/sound.cpp
Normal file
425
engines/access/sound.cpp
Normal file
@@ -0,0 +1,425 @@
|
||||
/* 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 "common/config-manager.h"
|
||||
#include "audio/mixer.h"
|
||||
#include "audio/audiostream.h"
|
||||
#include "audio/mididrv.h"
|
||||
#include "audio/midiparser.h"
|
||||
#include "audio/decoders/raw.h"
|
||||
#include "audio/decoders/wave.h"
|
||||
// Miles Audio
|
||||
#include "audio/miles.h"
|
||||
#include "access/access.h"
|
||||
#include "access/sound.h"
|
||||
|
||||
#include "access/martian/midiparser_bemd.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
SoundManager::SoundManager(AccessEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
|
||||
_effectsHandle = new Audio::SoundHandle();
|
||||
}
|
||||
|
||||
SoundManager::~SoundManager() {
|
||||
clearSounds();
|
||||
delete _effectsHandle;
|
||||
}
|
||||
|
||||
void SoundManager::clearSounds() {
|
||||
debugC(1, kDebugSound, "clearSounds()");
|
||||
|
||||
for (auto &sound : _soundTable)
|
||||
delete sound._res;
|
||||
|
||||
_soundTable.clear();
|
||||
|
||||
if (_mixer->isSoundHandleActive(*_effectsHandle))
|
||||
_mixer->stopHandle(*_effectsHandle);
|
||||
|
||||
while (_queue.size()) {
|
||||
delete _queue[0]._stream;
|
||||
_queue.remove_at(0);
|
||||
}
|
||||
}
|
||||
|
||||
bool SoundManager::isSoundQueued(int soundId) const {
|
||||
for (uint idx = 0; idx < _queue.size(); ++idx) {
|
||||
if (_queue[idx]._soundId == soundId)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SoundManager::loadSoundTable(int idx, int fileNum, int subfile, int priority) {
|
||||
debugC(1, kDebugSound, "loadSoundTable(%d, %d, %d)", idx, fileNum, subfile);
|
||||
|
||||
Resource *soundResource;
|
||||
|
||||
if (idx >= (int)_soundTable.size())
|
||||
_soundTable.resize(idx + 1);
|
||||
|
||||
delete _soundTable[idx]._res;
|
||||
soundResource = _vm->_files->loadFile(fileNum, subfile);
|
||||
_soundTable[idx]._res = soundResource;
|
||||
_soundTable[idx]._priority = priority;
|
||||
}
|
||||
|
||||
Resource *SoundManager::loadSound(int fileNum, int subfile) {
|
||||
debugC(1, kDebugSound, "loadSound(%d, %d)", fileNum, subfile);
|
||||
return _vm->_files->loadFile(fileNum, subfile);
|
||||
}
|
||||
|
||||
void SoundManager::playSound(int soundIndex, bool loop) {
|
||||
debugC(1, kDebugSound, "playSound(%d, %d)", soundIndex, loop);
|
||||
if (isSoundQueued(soundIndex))
|
||||
// Prevent duplicate copies of a sound from being queued
|
||||
return;
|
||||
|
||||
int priority = _soundTable[soundIndex]._priority;
|
||||
playSound(_soundTable[soundIndex]._res, priority, loop, soundIndex);
|
||||
}
|
||||
|
||||
void SoundManager::playSound(Resource *res, int priority, bool loop, int soundIndex) {
|
||||
debugC(1, kDebugSound, "playSound");
|
||||
|
||||
const byte *resourceData = res->data();
|
||||
|
||||
assert(res->_size >= 32);
|
||||
|
||||
Audio::RewindableAudioStream *audioStream;
|
||||
|
||||
if (READ_BE_UINT32(resourceData) == MKTAG('R','I','F','F')) {
|
||||
// CD version uses WAVE-files
|
||||
Common::SeekableReadStream *waveStream = new Common::MemoryReadStream(resourceData, res->_size, DisposeAfterUse::NO);
|
||||
audioStream = Audio::makeWAVStream(waveStream, DisposeAfterUse::YES);
|
||||
} else if (READ_BE_UINT32(resourceData) == MKTAG('S', 'T', 'E', 'V')) {
|
||||
// sound files have a fixed header of 32 bytes in total
|
||||
// header content:
|
||||
// "STEVE" - fixed header
|
||||
// byte - sample rate
|
||||
// 01h mapped internally to 3Ch
|
||||
// 02h mapped internally to 78h
|
||||
// 03h mapped internally to B5h
|
||||
// 04h mapped internally to F1h
|
||||
// byte - unknown
|
||||
// word - actual sample size (should be resource-size - 32)
|
||||
byte internalSampleRate = resourceData[5];
|
||||
int sampleSize = READ_LE_UINT16(resourceData + 7);
|
||||
|
||||
assert( (sampleSize + 32) <= res->_size);
|
||||
|
||||
int sampleRate = 0;
|
||||
switch (internalSampleRate) {
|
||||
case 1: // NEG(3Ch) -> C4h time constant
|
||||
sampleRate = 16666;
|
||||
break;
|
||||
|
||||
case 2: // NEG(78h) -> 88h time constant
|
||||
sampleRate = 8334;
|
||||
break;
|
||||
|
||||
case 3: // NEG(B5h) -> 4Bh time constant
|
||||
sampleRate = 5525;
|
||||
break;
|
||||
|
||||
case 4: // NEG(F1h) -> 0Fh time constant
|
||||
sampleRate = 4150;
|
||||
break;
|
||||
|
||||
default:
|
||||
error("Unexpected internal Sample Rate %d", internalSampleRate);
|
||||
return;
|
||||
}
|
||||
|
||||
audioStream = Audio::makeRawStream(resourceData + 32, sampleSize, sampleRate, 0, DisposeAfterUse::NO);
|
||||
} else
|
||||
error("Unknown format");
|
||||
|
||||
if (loop) {
|
||||
_queue.push_back(QueuedSound(new Audio::LoopingAudioStream(audioStream, 0,
|
||||
DisposeAfterUse::NO), soundIndex));
|
||||
} else {
|
||||
_queue.push_back(QueuedSound(audioStream, soundIndex));
|
||||
}
|
||||
|
||||
if (!_mixer->isSoundHandleActive(*_effectsHandle))
|
||||
_mixer->playStream(Audio::Mixer::kSFXSoundType, _effectsHandle,
|
||||
_queue[0]._stream, -1, _mixer->kMaxChannelVolume, 0,
|
||||
DisposeAfterUse::NO);
|
||||
}
|
||||
|
||||
void SoundManager::checkSoundQueue() {
|
||||
debugC(5, kDebugSound, "checkSoundQueue");
|
||||
|
||||
if (_queue.empty() || _mixer->isSoundHandleActive(*_effectsHandle))
|
||||
return;
|
||||
|
||||
delete _queue[0]._stream;
|
||||
_queue.remove_at(0);
|
||||
|
||||
if (_queue.size() && _queue[0]._stream)
|
||||
_mixer->playStream(Audio::Mixer::kSFXSoundType, _effectsHandle,
|
||||
_queue[0]._stream, -1, _mixer->kMaxChannelVolume, 0,
|
||||
DisposeAfterUse::NO);
|
||||
}
|
||||
|
||||
bool SoundManager::isSFXPlaying() {
|
||||
return _mixer->isSoundHandleActive(*_effectsHandle);
|
||||
}
|
||||
|
||||
void SoundManager::syncVolume() {
|
||||
int sfxVol = CLIP(ConfMan.getInt("sfx_volume"), 0, 255);
|
||||
_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, sfxVol);
|
||||
}
|
||||
|
||||
void SoundManager::loadSounds(const Common::Array<RoomInfo::SoundIdent> &sounds) {
|
||||
debugC(1, kDebugSound, "loadSounds");
|
||||
|
||||
clearSounds();
|
||||
|
||||
for (const auto &sound : sounds) {
|
||||
Resource *soundRes = loadSound(sound._fileNum, sound._subfile);
|
||||
_soundTable.push_back(SoundEntry(soundRes, sound._priority));
|
||||
}
|
||||
}
|
||||
|
||||
void SoundManager::stopSound() {
|
||||
debugC(3, kDebugSound, "stopSound");
|
||||
|
||||
_mixer->stopHandle(*_effectsHandle);
|
||||
}
|
||||
|
||||
void SoundManager::freeSounds() {
|
||||
debugC(3, kDebugSound, "freeSounds");
|
||||
|
||||
stopSound();
|
||||
clearSounds();
|
||||
}
|
||||
|
||||
/******************************************************************************************/
|
||||
|
||||
MusicManager::MusicManager(AccessEngine *vm) : _vm(vm) {
|
||||
_music = nullptr;
|
||||
_tempMusic = nullptr;
|
||||
_isLooping = false;
|
||||
_driver = nullptr;
|
||||
|
||||
MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MT32);
|
||||
MusicType musicType = MidiDriver::getMusicType(dev);
|
||||
|
||||
// Amazon Guardians of Eden uses MIDPAK inside MIDIDRV.AP
|
||||
// AdLib patches are inside MIDIDRV.AP too, 2nd resource file
|
||||
//
|
||||
// Amazon Guardians of Eden (demo) seems to use another type of driver, possibly written by Access themselves
|
||||
// Martian Memorandum uses this other type of driver as well, which means it makes sense to reverse engineer it.
|
||||
//
|
||||
switch (musicType) {
|
||||
case MT_ADLIB: {
|
||||
if (_vm->getGameID() == kGameAmazon && !_vm->isDemo()) {
|
||||
Resource *midiDrvResource = _vm->_files->loadFile(92, 1);
|
||||
Common::MemoryReadStream *adLibInstrumentStream = new Common::MemoryReadStream(midiDrvResource->data(), midiDrvResource->_size);
|
||||
|
||||
_driver = Audio::MidiDriver_Miles_AdLib_create("", "", adLibInstrumentStream);
|
||||
|
||||
delete midiDrvResource;
|
||||
delete adLibInstrumentStream;
|
||||
} else {
|
||||
MidiPlayer::createDriver();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MT_MT32:
|
||||
_driver = Audio::MidiDriver_Miles_MT32_create("");
|
||||
_nativeMT32 = true;
|
||||
break;
|
||||
case MT_GM:
|
||||
if (ConfMan.getBool("native_mt32")) {
|
||||
_driver = Audio::MidiDriver_Miles_MT32_create("");
|
||||
_nativeMT32 = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
MidiPlayer::createDriver();
|
||||
MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
|
||||
#endif
|
||||
|
||||
if (_driver) {
|
||||
int retValue = _driver->open();
|
||||
if (retValue == 0) {
|
||||
if (_nativeMT32)
|
||||
_driver->sendMT32Reset();
|
||||
else
|
||||
_driver->sendGMReset();
|
||||
|
||||
_driver->setTimerCallback(this, &timerCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MusicManager::~MusicManager() {
|
||||
delete _music;
|
||||
delete _tempMusic;
|
||||
}
|
||||
|
||||
void MusicManager::send(uint32 b) {
|
||||
// Pass data directly to driver
|
||||
_driver->send(b);
|
||||
#if 0
|
||||
if ((b & 0xF0) == 0xC0 && !_nativeMT32) {
|
||||
b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
|
||||
}
|
||||
|
||||
Audio::MidiPlayer::send(b);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MusicManager::midiPlay() {
|
||||
debugC(1, kDebugSound, "midiPlay");
|
||||
|
||||
if (!_driver)
|
||||
return;
|
||||
|
||||
if (_music->_size < 4) {
|
||||
error("midiPlay() wrong music resource size");
|
||||
}
|
||||
|
||||
stop();
|
||||
|
||||
uint32 magic = READ_BE_UINT32(_music->data());
|
||||
if (magic == MKTAG('B', 'E', 'm', 'd')) {
|
||||
_parser = new MidiParser_BEmd();
|
||||
|
||||
if (!_parser->loadMusic(_music->data(), _music->_size))
|
||||
error("midiPlay() couldn't load music resource");
|
||||
|
||||
_parser->setTrack(0);
|
||||
_parser->setMidiDriver(this);
|
||||
_parser->setTimerRate(_driver->getBaseTempo());
|
||||
_parser->property(MidiParser::mpAutoLoop, _isLooping);
|
||||
syncVolume();
|
||||
_isPlaying = true;
|
||||
} else if (magic == MKTAG('F', 'O', 'R', 'M')) {
|
||||
_parser = MidiParser::createParser_XMIDI();
|
||||
|
||||
if (!_parser->loadMusic(_music->data(), _music->_size))
|
||||
error("midiPlay() wrong music resource");
|
||||
|
||||
_parser->setTrack(0);
|
||||
_parser->setMidiDriver(this);
|
||||
_parser->setTimerRate(_driver->getBaseTempo());
|
||||
_parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
|
||||
_parser->property(MidiParser::mpSendSustainOffOnNotesOff, 1);
|
||||
|
||||
// Handle music looping
|
||||
_parser->property(MidiParser::mpAutoLoop, _isLooping);
|
||||
syncVolume();
|
||||
_isPlaying = true;
|
||||
} else {
|
||||
warning("midiPlay() Unexpected signature 0x%08x, expected 'FORM'", magic);
|
||||
_isPlaying = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool MusicManager::checkMidiDone() {
|
||||
debugC(1, kDebugSound, "checkMidiDone");
|
||||
return (!_isPlaying);
|
||||
}
|
||||
|
||||
void MusicManager::midiRepeat() {
|
||||
debugC(1, kDebugSound, "midiRepeat");
|
||||
|
||||
if (!_driver)
|
||||
return;
|
||||
if (!_parser)
|
||||
return;
|
||||
|
||||
_isLooping = true;
|
||||
_parser->property(MidiParser::mpAutoLoop, _isLooping);
|
||||
if (!_isPlaying)
|
||||
_parser->setTrack(0);
|
||||
}
|
||||
|
||||
void MusicManager::stopSong() {
|
||||
debugC(1, kDebugSound, "stopSong");
|
||||
|
||||
if (!_driver)
|
||||
return;
|
||||
|
||||
stop();
|
||||
}
|
||||
|
||||
void MusicManager::loadMusic(int fileNum, int subfile) {
|
||||
debugC(1, kDebugSound, "loadMusic(%d, %d)", fileNum, subfile);
|
||||
|
||||
_music = _vm->_files->loadFile(fileNum, subfile);
|
||||
}
|
||||
|
||||
void MusicManager::loadMusic(FileIdent file) {
|
||||
debugC(1, kDebugSound, "loadMusic(%d, %d)", file._fileNum, file._subfile);
|
||||
|
||||
_music = _vm->_files->loadFile(file);
|
||||
}
|
||||
|
||||
void MusicManager::newMusic(int musicId, int mode) {
|
||||
debugC(1, kDebugSound, "newMusic(%d, %d)", musicId, mode);
|
||||
|
||||
if (!_driver)
|
||||
return;
|
||||
|
||||
if (mode == 1) {
|
||||
stopSong();
|
||||
freeMusic();
|
||||
_music = _tempMusic;
|
||||
_tempMusic = nullptr;
|
||||
_isLooping = true;
|
||||
} else {
|
||||
_isLooping = (mode == 2);
|
||||
_tempMusic = _music;
|
||||
stopSong();
|
||||
loadMusic(97, musicId);
|
||||
}
|
||||
|
||||
if (_music)
|
||||
midiPlay();
|
||||
}
|
||||
|
||||
void MusicManager::freeMusic() {
|
||||
debugC(3, kDebugSound, "freeMusic");
|
||||
|
||||
delete _music;
|
||||
_music = nullptr;
|
||||
}
|
||||
|
||||
void MusicManager::setLoop(bool loop) {
|
||||
debugC(3, kDebugSound, "setLoop");
|
||||
|
||||
_isLooping = loop;
|
||||
if (_parser)
|
||||
_parser->property(MidiParser::mpAutoLoop, _isLooping);
|
||||
}
|
||||
} // End of namespace Access
|
||||
122
engines/access/sound.h
Normal file
122
engines/access/sound.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/* 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 ACCESS_SOUND_H
|
||||
#define ACCESS_SOUND_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "access/files.h"
|
||||
#include "audio/midiplayer.h"
|
||||
|
||||
#define MAX_SOUNDS 20
|
||||
|
||||
namespace Audio {
|
||||
class AudioStream;
|
||||
class SoundHandle;
|
||||
}
|
||||
|
||||
namespace Access {
|
||||
|
||||
class AccessEngine;
|
||||
|
||||
struct SoundEntry {
|
||||
Resource *_res;
|
||||
int _priority;
|
||||
|
||||
SoundEntry() { _res = nullptr; _priority = 0; }
|
||||
SoundEntry(Resource *res, int priority) { _res = res; _priority = priority; }
|
||||
};
|
||||
|
||||
class SoundManager {
|
||||
struct QueuedSound {
|
||||
Audio::AudioStream *_stream;
|
||||
int _soundId;
|
||||
|
||||
QueuedSound() : _stream(nullptr), _soundId(-1) {}
|
||||
QueuedSound(Audio::AudioStream *stream, int soundId) : _stream(stream), _soundId(soundId) {}
|
||||
};
|
||||
private:
|
||||
AccessEngine *_vm;
|
||||
Audio::Mixer *_mixer;
|
||||
Audio::SoundHandle *_effectsHandle;
|
||||
Common::Array<QueuedSound> _queue;
|
||||
|
||||
void clearSounds();
|
||||
|
||||
void playSound(Resource *res, int priority, bool loop, int soundIndex = -1);
|
||||
|
||||
bool isSoundQueued(int soundId) const;
|
||||
public:
|
||||
Common::Array<SoundEntry> _soundTable;
|
||||
public:
|
||||
SoundManager(AccessEngine *vm, Audio::Mixer *mixer);
|
||||
~SoundManager();
|
||||
|
||||
void loadSoundTable(int idx, int fileNum, int subfile, int priority = 1);
|
||||
|
||||
void playSound(int soundIndex, bool loop = false);
|
||||
void checkSoundQueue();
|
||||
bool isSFXPlaying();
|
||||
|
||||
Resource *loadSound(int fileNum, int subfile);
|
||||
void loadSounds(const Common::Array<RoomInfo::SoundIdent> &sounds);
|
||||
void syncVolume();
|
||||
|
||||
void stopSound();
|
||||
void freeSounds();
|
||||
};
|
||||
|
||||
class MusicManager : public Audio::MidiPlayer {
|
||||
private:
|
||||
AccessEngine *_vm;
|
||||
|
||||
Resource *_tempMusic;
|
||||
|
||||
// MidiDriver_BASE interface implementation
|
||||
void send(uint32 b) override;
|
||||
|
||||
public:
|
||||
Resource *_music;
|
||||
|
||||
public:
|
||||
MusicManager(AccessEngine *vm);
|
||||
~MusicManager() override;
|
||||
|
||||
void midiPlay();
|
||||
|
||||
bool checkMidiDone();
|
||||
|
||||
void midiRepeat();
|
||||
|
||||
void stopSong();
|
||||
|
||||
void newMusic(int musicId, int mode);
|
||||
|
||||
void freeMusic();
|
||||
|
||||
void loadMusic(int fileNum, int subfile);
|
||||
void loadMusic(FileIdent file);
|
||||
|
||||
void setLoop(bool loop);
|
||||
};
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_SOUND_H*/
|
||||
209
engines/access/video.cpp
Normal file
209
engines/access/video.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
/* 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 "access/video.h"
|
||||
#include "access/access.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
VideoPlayer::VideoPlayer(AccessEngine *vm) : Manager(vm) {
|
||||
_vidSurface = nullptr;
|
||||
_videoData = nullptr;
|
||||
_startCoord = nullptr;
|
||||
|
||||
_frameCount = 0;
|
||||
_xCount = 0;
|
||||
_scanCount = 0;
|
||||
_frameSize = 0;
|
||||
_videoFrame = 0;
|
||||
_soundFlag = false;
|
||||
_soundFrame = 0;
|
||||
_videoEnd = false;
|
||||
|
||||
_header._frameCount = 0;
|
||||
_header._width = _header._height = 0;
|
||||
_header._flags = VIDEOFLAG_NONE;
|
||||
}
|
||||
|
||||
VideoPlayer::~VideoPlayer() {
|
||||
closeVideo();
|
||||
}
|
||||
|
||||
void VideoPlayer::setVideo(BaseSurface *vidSurface, const Common::Point &pt, int rate) {
|
||||
_vidSurface = vidSurface;
|
||||
vidSurface->_orgX1 = pt.x;
|
||||
vidSurface->_orgY1 = pt.y;
|
||||
_vm->_timers[31]._timer = rate;
|
||||
_vm->_timers[31]._initTm = rate;
|
||||
|
||||
// Load in header
|
||||
_header._frameCount = _videoData->_stream->readUint16LE();
|
||||
_header._width = _videoData->_stream->readUint16LE();
|
||||
_header._height = _videoData->_stream->readUint16LE();
|
||||
_videoData->_stream->skip(1);
|
||||
_header._flags = (VideoFlags)_videoData->_stream->readByte();
|
||||
|
||||
_startCoord = (byte *)vidSurface->getBasePtr(pt.x, pt.y);
|
||||
_frameCount = _header._frameCount - 2;
|
||||
_xCount = _header._width;
|
||||
_scanCount = _header._height;
|
||||
_videoFrame = 0;
|
||||
_videoBounds = Common::Rect(pt.x, pt.y, pt.x + _header._width, pt.y + _header._height);
|
||||
|
||||
getFrame();
|
||||
|
||||
if (_header._flags == VIDEOFLAG_BG) {
|
||||
// Draw the background
|
||||
for (int y = 0; y < _scanCount; ++y) {
|
||||
byte *pDest = (byte *)vidSurface->getBasePtr(pt.x, pt.y + y);
|
||||
_videoData->_stream->read(pDest, _xCount);
|
||||
}
|
||||
|
||||
if (vidSurface == _vm->_screen) {
|
||||
assert(pt.x >= 0 && pt.y >= 0 && pt.x < 320 && pt.y < 200 &&
|
||||
_xCount > 0 && _xCount <= 320 && _scanCount > 0 && _scanCount <= 200);
|
||||
_vm->_newRects.push_back(Common::Rect(pt.x, pt.y, pt.x + _xCount, pt.y + _scanCount));
|
||||
}
|
||||
|
||||
getFrame();
|
||||
}
|
||||
|
||||
_videoEnd = false;
|
||||
}
|
||||
|
||||
void VideoPlayer::setVideo(BaseSurface *vidSurface, const Common::Point &pt, const Common::Path &filename, int rate) {
|
||||
// Open up video stream
|
||||
_videoData = _vm->_files->loadFile(filename);
|
||||
|
||||
setVideo(vidSurface, pt, rate);
|
||||
}
|
||||
|
||||
void VideoPlayer::setVideo(BaseSurface *vidSurface, const Common::Point &pt, const FileIdent &videoFile, int rate) {
|
||||
// Open up video stream
|
||||
_videoData = _vm->_files->loadFile(videoFile);
|
||||
|
||||
setVideo(vidSurface, pt, rate);
|
||||
}
|
||||
|
||||
void VideoPlayer::closeVideo() {
|
||||
delete _videoData;
|
||||
_videoData = nullptr;
|
||||
}
|
||||
|
||||
void VideoPlayer::getFrame() {
|
||||
_frameSize = _videoData->_stream->readUint16LE();
|
||||
}
|
||||
|
||||
void VideoPlayer::playVideo() {
|
||||
if (_vm->_timers[31]._flag)
|
||||
return;
|
||||
_vm->_timers[31]._flag = 1;
|
||||
|
||||
byte *pDest = _startCoord;
|
||||
byte *pLine = _startCoord;
|
||||
uint32 frameEnd = _videoData->_stream->pos() + _frameSize;
|
||||
|
||||
if (frameEnd > _videoData->_stream->size())
|
||||
error("VideoPlayer::playVideo: Frame end %d > stream size %d", frameEnd, (int)_videoData->_stream->size());
|
||||
|
||||
while ((uint32)_videoData->_stream->pos() < frameEnd) {
|
||||
int count = _videoData->_stream->readByte();
|
||||
|
||||
if (count & 0x80) {
|
||||
count &= 0x7f;
|
||||
|
||||
// Skip count number of pixels
|
||||
// Loop across lines if necessary
|
||||
while (count >= (pLine + _xCount - pDest)) {
|
||||
count -= (pLine + _xCount - pDest);
|
||||
pLine += _vidSurface->pitch;
|
||||
pDest = pLine;
|
||||
}
|
||||
|
||||
// Skip any remaining pixels in the new line
|
||||
pDest += count;
|
||||
} else {
|
||||
// Read count number of pixels
|
||||
|
||||
// Load across lines if necessary
|
||||
while (count >= (pLine + _xCount - pDest)) {
|
||||
int lineCount = (pLine + _xCount - pDest);
|
||||
_videoData->_stream->read(pDest, lineCount);
|
||||
count -= lineCount;
|
||||
pLine += _vidSurface->pitch;
|
||||
pDest = pLine;
|
||||
}
|
||||
|
||||
// Load remainder of pixels on line
|
||||
if (count > 0) {
|
||||
_videoData->_stream->read(pDest, count);
|
||||
pDest += count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the video is playing on the screen surface, add a dirty rect
|
||||
if (_vidSurface == _vm->_screen)
|
||||
_vm->_screen->markAllDirty();
|
||||
|
||||
_vm->_screen->dump("vidframe");
|
||||
|
||||
getFrame();
|
||||
if (++_videoFrame == _frameCount) {
|
||||
closeVideo();
|
||||
_videoEnd = true;
|
||||
}
|
||||
}
|
||||
|
||||
void VideoPlayer::copyVideo() {
|
||||
// aka drawTalkVideoFrame
|
||||
_vm->_player->calcPlayer();
|
||||
|
||||
// Figure out the dirty rect area for the video frame
|
||||
Common::Rect r = Common::Rect(_vm->_vidX - _vm->_screen->_bufferStart.x,
|
||||
_vm->_vidY - _vm->_screen->_bufferStart.y,
|
||||
_vm->_vidX - _vm->_screen->_bufferStart.x + _header._width,
|
||||
_vm->_vidY - _vm->_screen->_bufferStart.y + _header._height);
|
||||
if (_vm->_screen->clip(r))
|
||||
return;
|
||||
assert(r.left >= 0 && r.left < 320 && r.top >= 0 && r.top < 200 &&
|
||||
r.right > 0 && r.right <= 320 && r.bottom > 0 && r.bottom <= 200);
|
||||
_vm->_newRects.push_back(r);
|
||||
|
||||
// Draw the clipped video to the buffer
|
||||
int vh = r.height();
|
||||
int vw = r.width();
|
||||
int destIdx = r.left + r.top * _vm->_buffer2.pitch;
|
||||
int srcIdx = _vm->_screen->_leftSkip + _vm->_screen->_topSkip * _vm->_vidBuf.pitch;
|
||||
|
||||
assert(srcIdx >= 0);
|
||||
assert(destIdx >= 0);
|
||||
|
||||
const byte *srcP = (const byte *)_vm->_vidBuf.getPixels() + srcIdx;
|
||||
byte *destP = (byte *)_vm->_buffer2.getPixels() + destIdx;
|
||||
for (int i = 0; i < vh; i++) {
|
||||
Common::copy(srcP, srcP + vw, destP);
|
||||
srcP += _vm->_vidBuf.pitch;
|
||||
destP += _vm->_buffer2.pitch;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Access
|
||||
83
engines/access/video.h
Normal file
83
engines/access/video.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/* 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 ACCESS_VIDEO_H
|
||||
#define ACCESS_VIDEO_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/memstream.h"
|
||||
#include "access/data.h"
|
||||
#include "access/asurface.h"
|
||||
#include "access/files.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
enum VideoFlags { VIDEOFLAG_NONE = 0, VIDEOFLAG_BG = 1 };
|
||||
|
||||
class VideoPlayer : public Manager {
|
||||
struct VideoHeader {
|
||||
int _frameCount;
|
||||
int _width, _height;
|
||||
VideoFlags _flags;
|
||||
};
|
||||
private:
|
||||
BaseSurface *_vidSurface;
|
||||
Resource *_videoData;
|
||||
VideoHeader _header;
|
||||
byte *_startCoord;
|
||||
int _frameCount;
|
||||
int _xCount;
|
||||
int _scanCount;
|
||||
int _frameSize;
|
||||
Common::Rect _videoBounds;
|
||||
|
||||
void getFrame();
|
||||
void setVideo(BaseSurface *vidSurface, const Common::Point &pt, int rate);
|
||||
public:
|
||||
int _videoFrame;
|
||||
bool _soundFlag;
|
||||
int _soundFrame;
|
||||
bool _videoEnd;
|
||||
public:
|
||||
VideoPlayer(AccessEngine *vm);
|
||||
~VideoPlayer();
|
||||
|
||||
/**
|
||||
* Start up a video
|
||||
*/
|
||||
void setVideo(BaseSurface *vidSurface, const Common::Point &pt, const FileIdent &videoFile, int rate);
|
||||
void setVideo(BaseSurface *vidSurface, const Common::Point &pt, const Common::Path &filename, int rate);
|
||||
|
||||
/**
|
||||
* Decodes a frame of the video
|
||||
*/
|
||||
void playVideo();
|
||||
|
||||
void copyVideo();
|
||||
/**
|
||||
* Frees the data for a previously loaded video
|
||||
*/
|
||||
void closeVideo();
|
||||
};
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif /* ACCESS_VIDEO_H */
|
||||
738
engines/access/video/movie_decoder.cpp
Normal file
738
engines/access/video/movie_decoder.cpp
Normal file
@@ -0,0 +1,738 @@
|
||||
/* 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 "common/scummsys.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
#include "audio/decoders/raw.h"
|
||||
|
||||
#include "access/access.h"
|
||||
#include "access/video/movie_decoder.h"
|
||||
|
||||
// for Test-Code
|
||||
#include "common/system.h"
|
||||
#include "common/events.h"
|
||||
#include "common/keyboard.h"
|
||||
#include "engines/engine.h"
|
||||
#include "engines/util.h"
|
||||
#include "graphics/paletteman.h"
|
||||
#include "graphics/pixelformat.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
namespace Access {
|
||||
|
||||
AccessVIDMovieDecoder::AccessVIDMovieDecoder()
|
||||
: _stream(nullptr), _videoTrack(nullptr), _audioTrack(nullptr) {
|
||||
_streamSeekOffset = 0;
|
||||
_streamVideoIndex = 0;
|
||||
_streamAudioIndex = 0;
|
||||
}
|
||||
|
||||
AccessVIDMovieDecoder::~AccessVIDMovieDecoder() {
|
||||
AccessVIDMovieDecoder::close();
|
||||
}
|
||||
|
||||
bool AccessVIDMovieDecoder::loadStream(Common::SeekableReadStream *stream) {
|
||||
uint32 videoCodecTag = 0;
|
||||
uint32 videoHeight = 0;
|
||||
uint32 videoWidth = 0;
|
||||
uint16 regularDelay = 0;
|
||||
uint32 audioSampleRate = 0;
|
||||
|
||||
close();
|
||||
|
||||
_stream = stream;
|
||||
_streamSeekOffset = 15; // offset of first chunk
|
||||
_streamVideoIndex = 0;
|
||||
_streamAudioIndex = 0;
|
||||
|
||||
// read header
|
||||
// ID [dword] "VID"
|
||||
// ?? [byte]
|
||||
// ?? [word]
|
||||
// width [word]
|
||||
// height [word]
|
||||
// regular delay between frames (60 per second) [word]
|
||||
// ?? [word]
|
||||
|
||||
videoCodecTag = _stream->readUint32BE();
|
||||
if (videoCodecTag != MKTAG('V','I','D',0x00)) {
|
||||
warning("AccessVIDMoviePlay: bad codec tag, not a video file?");
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
_stream->skip(3);
|
||||
videoWidth = _stream->readUint16LE();
|
||||
videoHeight = _stream->readUint16LE();
|
||||
regularDelay = _stream->readUint16LE();
|
||||
_stream->skip(2);
|
||||
|
||||
if (!regularDelay) {
|
||||
warning("AccessVIDMoviePlay: delay between frames is zero?");
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// create video track
|
||||
_videoTrack = new StreamVideoTrack(videoWidth, videoHeight, regularDelay);
|
||||
addTrack(_videoTrack);
|
||||
|
||||
//warning("width %d, height %d", videoWidth, videoHeight);
|
||||
|
||||
// Look through the first few packets
|
||||
static const int maxPacketCheckCount = 10;
|
||||
|
||||
for (int i = 0; i < maxPacketCheckCount; i++) {
|
||||
byte chunkId = _stream->readByte();
|
||||
|
||||
// Bail out if done
|
||||
if (_stream->eos())
|
||||
break;
|
||||
|
||||
// Bail also in case end of file chunk was found
|
||||
if (chunkId == kVIDMovieChunkId_EndOfFile)
|
||||
break;
|
||||
|
||||
uint32 chunkStartOffset = _stream->pos();
|
||||
//warning("data chunk at %x", chunkStartOffset);
|
||||
|
||||
switch (chunkId) {
|
||||
case kVIDMovieChunkId_FullFrame:
|
||||
case kVIDMovieChunkId_FullFrameCompressed:
|
||||
case kVIDMovieChunkId_PartialFrameCompressed:
|
||||
case kVIDMovieChunkId_FullFrameCompressedFill: {
|
||||
if (!_videoTrack->skipOverFrame(_stream, chunkId)) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kVIDMovieChunkId_Palette: {
|
||||
if (!_videoTrack->skipOverPalette(_stream)) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kVIDMovieChunkId_AudioFirstChunk:
|
||||
case kVIDMovieChunkId_Audio: {
|
||||
// sync [word]
|
||||
// sampling rate [byte]
|
||||
// size of audio data [word]
|
||||
// sample data [] (mono, 8-bit, unsigned)
|
||||
//
|
||||
// Only first chunk has sync + sampling rate
|
||||
if (chunkId == kVIDMovieChunkId_AudioFirstChunk) {
|
||||
byte soundblasterRate;
|
||||
|
||||
_stream->skip(2); // skip over sync
|
||||
soundblasterRate = _stream->readByte();
|
||||
audioSampleRate = 1000000 / (256 - soundblasterRate);
|
||||
|
||||
_audioTrack = new StreamAudioTrack(audioSampleRate, getSoundType());
|
||||
addTrack(_audioTrack);
|
||||
|
||||
_stream->seek(chunkStartOffset); // seek back
|
||||
}
|
||||
|
||||
if (!_audioTrack) {
|
||||
warning("AccessVIDMoviePlay: regular audio chunk, before audio chunk w/ header");
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
if (!_audioTrack->skipOverAudio(_stream, chunkId)) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
warning("AccessVIDMoviePlay: Unknown chunk-id '%x' inside VID movie", chunkId);
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remember this chunk inside our cache
|
||||
IndexCacheEntry indexCacheEntry;
|
||||
|
||||
indexCacheEntry.chunkId = chunkId;
|
||||
indexCacheEntry.offset = chunkStartOffset;
|
||||
|
||||
_indexCacheTable.push_back(indexCacheEntry);
|
||||
|
||||
// Got an audio chunk now? -> exit b/c we are done
|
||||
if (audioSampleRate)
|
||||
break;
|
||||
}
|
||||
|
||||
// Remember offset of latest not-indexed-yet chunk
|
||||
_streamSeekOffset = _stream->pos();
|
||||
|
||||
// If sample rate was found, create an audio track
|
||||
if (audioSampleRate) {
|
||||
_audioTrack = new StreamAudioTrack(audioSampleRate, getSoundType());
|
||||
addTrack(_audioTrack);
|
||||
}
|
||||
|
||||
// Rewind back to the beginning right to the first chunk
|
||||
_stream->seek(15);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AccessVIDMovieDecoder::close() {
|
||||
Video::VideoDecoder::close();
|
||||
|
||||
delete _stream; _stream = nullptr;
|
||||
_videoTrack = nullptr;
|
||||
|
||||
_indexCacheTable.clear();
|
||||
}
|
||||
|
||||
// We try to at least decode 1 frame
|
||||
// and also try to get at least 0.5 seconds of audio queued up
|
||||
void AccessVIDMovieDecoder::readNextPacket() {
|
||||
uint32 currentMovieTime = getTime();
|
||||
uint32 wantedAudioQueued = currentMovieTime + 500; // always try to be 0.500 seconds in front of movie time
|
||||
|
||||
uint32 streamIndex = 0;
|
||||
IndexCacheEntry indexEntry;
|
||||
bool currentlySeeking = false;
|
||||
|
||||
bool videoDone = false;
|
||||
bool audioDone = false;
|
||||
|
||||
// Seek to smallest stream offset
|
||||
if ((_streamVideoIndex <= _streamAudioIndex) || (!_audioTrack)) {
|
||||
streamIndex = _streamVideoIndex;
|
||||
} else {
|
||||
streamIndex = _streamAudioIndex;
|
||||
}
|
||||
|
||||
if (_audioTrack) {
|
||||
if (wantedAudioQueued <= _audioTrack->getTotalAudioQueued()) {
|
||||
// already got enough audio queued up
|
||||
audioDone = true;
|
||||
}
|
||||
} else {
|
||||
// no audio track, audio is always done
|
||||
audioDone = true;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
// Check, if stream-index is already cached
|
||||
if (streamIndex < _indexCacheTable.size()) {
|
||||
indexEntry.chunkId = _indexCacheTable[streamIndex].chunkId;
|
||||
indexEntry.offset = _indexCacheTable[streamIndex].offset;
|
||||
currentlySeeking = false;
|
||||
|
||||
} else {
|
||||
// read from file
|
||||
_stream->seek(_streamSeekOffset);
|
||||
indexEntry.chunkId = _stream->readByte();
|
||||
indexEntry.offset = _stream->pos();
|
||||
currentlySeeking = true;
|
||||
|
||||
// and store that as well
|
||||
_indexCacheTable.push_back(indexEntry);
|
||||
}
|
||||
|
||||
// end of stream -> exit
|
||||
if (_stream->eos())
|
||||
break;
|
||||
|
||||
// end of file chunk -> exit
|
||||
if (indexEntry.chunkId == kVIDMovieChunkId_EndOfFile)
|
||||
break;
|
||||
|
||||
// warning("chunk %x", indexEntry.chunkId);
|
||||
|
||||
switch (indexEntry.chunkId) {
|
||||
case kVIDMovieChunkId_FullFrame:
|
||||
case kVIDMovieChunkId_FullFrameCompressed:
|
||||
case kVIDMovieChunkId_PartialFrameCompressed:
|
||||
case kVIDMovieChunkId_FullFrameCompressedFill: {
|
||||
if ((_streamVideoIndex <= streamIndex) && (!videoDone)) {
|
||||
// We are at an index, that is still relevant for video decoding
|
||||
// and we are not done with video yet
|
||||
if (!currentlySeeking) {
|
||||
// seek to stream position in case we used the cache
|
||||
_stream->seek(indexEntry.offset);
|
||||
}
|
||||
//warning("video decode chunk %x at %lx", indexEntry.chunkId, _stream->pos());
|
||||
_videoTrack->decodeFrame(_stream, indexEntry.chunkId);
|
||||
videoDone = true;
|
||||
_streamVideoIndex = streamIndex + 1;
|
||||
} else {
|
||||
if (currentlySeeking) {
|
||||
// currently seeking, so we have to skip the frame bytes manually
|
||||
_videoTrack->skipOverFrame(_stream, indexEntry.chunkId);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kVIDMovieChunkId_Palette: {
|
||||
if ((_streamVideoIndex <= streamIndex) && (!videoDone)) {
|
||||
// We are at an index, that is still relevant for video decoding
|
||||
// and we are not done with video yet
|
||||
if (!currentlySeeking) {
|
||||
// seek to stream position in case we used the cache
|
||||
_stream->seek(indexEntry.offset);
|
||||
}
|
||||
_videoTrack->decodePalette(_stream);
|
||||
_streamVideoIndex = streamIndex + 1;
|
||||
} else {
|
||||
if (currentlySeeking) {
|
||||
// currently seeking, so we have to skip the frame bytes manually
|
||||
_videoTrack->skipOverPalette(_stream);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kVIDMovieChunkId_AudioFirstChunk:
|
||||
case kVIDMovieChunkId_Audio: {
|
||||
if ((_streamAudioIndex <= streamIndex) && (!audioDone)) {
|
||||
// We are at an index that is still relevant for audio decoding
|
||||
if (!currentlySeeking) {
|
||||
// seek to stream position in case we used the cache
|
||||
_stream->seek(indexEntry.offset);
|
||||
}
|
||||
_audioTrack->queueAudio(_stream, indexEntry.chunkId);
|
||||
_streamAudioIndex = streamIndex + 1;
|
||||
|
||||
if (wantedAudioQueued <= _audioTrack->getTotalAudioQueued()) {
|
||||
// Got enough audio
|
||||
audioDone = true;
|
||||
}
|
||||
} else {
|
||||
if (!_audioTrack) {
|
||||
error("AccessVIDMoviePlay: audio chunks found without audio track active");
|
||||
}
|
||||
if (currentlySeeking) {
|
||||
// currently seeking, so we have to skip the audio bytes manually
|
||||
_audioTrack->skipOverAudio(_stream, indexEntry.chunkId);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
error("AccessVIDMoviePlay: Unknown chunk-id '%x' inside VID movie", indexEntry.chunkId);
|
||||
}
|
||||
|
||||
if (currentlySeeking) {
|
||||
// remember currently stream offset in case we are seeking
|
||||
_streamSeekOffset = _stream->pos();
|
||||
}
|
||||
|
||||
// go to next index
|
||||
streamIndex++;
|
||||
|
||||
if ((videoDone) && (audioDone)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!videoDone) {
|
||||
// no more video frames? set end of video track
|
||||
_videoTrack->setEndOfTrack();
|
||||
}
|
||||
}
|
||||
|
||||
AccessVIDMovieDecoder::StreamVideoTrack::StreamVideoTrack(uint32 width, uint32 height, uint16 regularFrameDelay) {
|
||||
_width = width;
|
||||
_height = height;
|
||||
_regularFrameDelay = regularFrameDelay;
|
||||
_curFrame = -1;
|
||||
_nextFrameStartTime = 0;
|
||||
_endOfTrack = false;
|
||||
_dirtyPalette = false;
|
||||
|
||||
memset(&_palette, 0, sizeof(_palette));
|
||||
|
||||
_surface = new Graphics::Surface();
|
||||
_surface->create(_width, _height, Graphics::PixelFormat::createFormatCLUT8());
|
||||
}
|
||||
|
||||
AccessVIDMovieDecoder::StreamVideoTrack::~StreamVideoTrack() {
|
||||
delete _surface;
|
||||
}
|
||||
|
||||
bool AccessVIDMovieDecoder::StreamVideoTrack::endOfTrack() const {
|
||||
return _endOfTrack;
|
||||
}
|
||||
|
||||
Graphics::PixelFormat AccessVIDMovieDecoder::StreamVideoTrack::getPixelFormat() const {
|
||||
return _surface->format;
|
||||
}
|
||||
|
||||
void AccessVIDMovieDecoder::StreamVideoTrack::decodeFrame(Common::SeekableReadStream *stream, byte chunkId) {
|
||||
byte *framePixelsPtr = (byte *)_surface->getPixels();
|
||||
byte *pixelsPtr = framePixelsPtr;
|
||||
byte rleByte = 0;
|
||||
uint16 additionalDelay = 0;
|
||||
int32 expectedPixels = 0;
|
||||
|
||||
switch (chunkId) {
|
||||
case kVIDMovieChunkId_FullFrame: {
|
||||
// Full frame is:
|
||||
// data [width * height]
|
||||
additionalDelay = stream->readUint16LE();
|
||||
stream->read(framePixelsPtr, _width * _height);
|
||||
break;
|
||||
}
|
||||
|
||||
case kVIDMovieChunkId_FullFrameCompressed:
|
||||
case kVIDMovieChunkId_PartialFrameCompressed: {
|
||||
// Skip manually over compressed data
|
||||
// Full frame compressed is:
|
||||
// additional delay [word]
|
||||
// REPEAT:
|
||||
// RLE [byte]
|
||||
// RLE upper bit set: skip over RLE & 0x7F pixels
|
||||
// RLE upper bit not set: draw RLE amount of pixels (those pixels follow right after RLE byte)
|
||||
//
|
||||
// Partial frame compressed is:
|
||||
// sync [word]
|
||||
// horizontal start position [word]
|
||||
// REPEAT:
|
||||
// see full frame compressed
|
||||
uint16 horizontalStartPosition = 0;
|
||||
|
||||
additionalDelay = stream->readUint16LE();
|
||||
|
||||
if (chunkId == kVIDMovieChunkId_PartialFrameCompressed) {
|
||||
horizontalStartPosition = stream->readUint16LE();
|
||||
if (horizontalStartPosition >= _height) {
|
||||
error("AccessVIDMoviePlay: starting position larger than height during partial frame compressed, data corrupt?");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
expectedPixels = _width * (_height - horizontalStartPosition);
|
||||
|
||||
// adjust frame destination pointer
|
||||
pixelsPtr += (horizontalStartPosition * _width);
|
||||
|
||||
while (expectedPixels >= 0) {
|
||||
rleByte = stream->readByte();
|
||||
if (!rleByte) // NUL means end of stream
|
||||
break;
|
||||
|
||||
if (rleByte & 0x80) {
|
||||
rleByte = rleByte & 0x7F;
|
||||
expectedPixels -= rleByte;
|
||||
} else {
|
||||
// skip over pixels
|
||||
expectedPixels -= rleByte;
|
||||
stream->read(pixelsPtr, rleByte); // read pixel data into frame
|
||||
}
|
||||
pixelsPtr += rleByte;
|
||||
}
|
||||
// expectedPixels may be positive here in case stream got terminated with a NUL
|
||||
if (expectedPixels < 0) {
|
||||
error("AccessVIDMoviePlay: pixel count mismatch during full/partial frame compressed, data corrupt?");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kVIDMovieChunkId_FullFrameCompressedFill: {
|
||||
// Full frame compressed fill is:
|
||||
// additional delay [word]
|
||||
// REPEAT:
|
||||
// RLE [byte]
|
||||
// RLE upper bit set: draw RLE amount (& 0x7F) of pixels with specified color (color byte follows after RLE byte)
|
||||
// RLE upper bit not set: draw RLE amount of pixels (those pixels follow right after RLE byte)
|
||||
additionalDelay = stream->readUint16LE();
|
||||
expectedPixels = _width * _height;
|
||||
|
||||
while (expectedPixels > 0) {
|
||||
rleByte = stream->readByte();
|
||||
|
||||
if (rleByte & 0x80) {
|
||||
rleByte = rleByte & 0x7F;
|
||||
expectedPixels -= rleByte;
|
||||
|
||||
byte fillColor = stream->readByte();
|
||||
memset(pixelsPtr, fillColor, rleByte);
|
||||
} else {
|
||||
// skip over pixels
|
||||
expectedPixels -= rleByte;
|
||||
stream->read(pixelsPtr, rleByte); // read pixel data into frame
|
||||
}
|
||||
pixelsPtr += rleByte;
|
||||
}
|
||||
if (expectedPixels < 0) {
|
||||
error("AccessVIDMoviePlay: pixel count mismatch during full frame compressed fill, data corrupt?");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
_curFrame++;
|
||||
|
||||
// TODO: not sure, if additionalDelay is supposed to affect the follow-up frame or the current frame
|
||||
// the videos, that I found, don't have it set
|
||||
uint32 currentFrameStartTime = getNextFrameStartTime();
|
||||
uint32 nextFrameStartTime = (_regularFrameDelay * _curFrame) * 1000 / 60;
|
||||
if (additionalDelay) {
|
||||
nextFrameStartTime += additionalDelay * 1000 / 60;
|
||||
}
|
||||
assert(currentFrameStartTime <= nextFrameStartTime);
|
||||
setNextFrameStartTime(nextFrameStartTime);
|
||||
}
|
||||
|
||||
bool AccessVIDMovieDecoder::StreamVideoTrack::skipOverFrame(Common::SeekableReadStream *stream, byte chunkId) {
|
||||
byte rleByte = 0;
|
||||
int32 expectedPixels = 0;
|
||||
|
||||
switch (chunkId) {
|
||||
case kVIDMovieChunkId_FullFrame: {
|
||||
// Full frame is:
|
||||
// additional delay [word]
|
||||
// data [width * height]
|
||||
stream->skip(2);
|
||||
stream->skip(_width * _height);
|
||||
break;
|
||||
}
|
||||
|
||||
case kVIDMovieChunkId_FullFrameCompressed:
|
||||
case kVIDMovieChunkId_PartialFrameCompressed: {
|
||||
// Skip manually over compressed data
|
||||
// Full frame compressed is:
|
||||
// additional delay [word]
|
||||
// REPEAT:
|
||||
// RLE [byte]
|
||||
// RLE upper bit set: skip over RLE & 0x7F pixels
|
||||
// RLE upper bit not set: draw RLE amount of pixels (those pixels follow right after RLE byte)
|
||||
//
|
||||
// Partial frame compressed is:
|
||||
// sync [word]
|
||||
// horizontal start position [word]
|
||||
// REPEAT:
|
||||
// see full frame compressed
|
||||
uint16 horizontalStartPosition = 0;
|
||||
|
||||
stream->skip(2);
|
||||
|
||||
if (chunkId == kVIDMovieChunkId_PartialFrameCompressed) {
|
||||
horizontalStartPosition = stream->readUint16LE();
|
||||
if (horizontalStartPosition >= _height) {
|
||||
warning("AccessVIDMoviePlay: starting position larger than height during partial frame compressed, data corrupt?");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
expectedPixels = _width * (_height - horizontalStartPosition);
|
||||
|
||||
while (expectedPixels >= 0) {
|
||||
rleByte = stream->readByte();
|
||||
if (!rleByte) // NUL means end of stream
|
||||
break;
|
||||
|
||||
if (rleByte & 0x80) {
|
||||
expectedPixels -= rleByte & 0x7F;
|
||||
} else {
|
||||
// skip over pixels
|
||||
expectedPixels -= rleByte;
|
||||
stream->skip(rleByte); // skip over pixel data
|
||||
}
|
||||
}
|
||||
// expectedPixels may be positive here in case stream got terminated with a NUL
|
||||
if (expectedPixels < 0) {
|
||||
warning("AccessVIDMoviePlay: pixel count mismatch during full/partial frame compressed, data corrupt?");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kVIDMovieChunkId_FullFrameCompressedFill: {
|
||||
// Full frame compressed fill is:
|
||||
// additional delay [word]
|
||||
// REPEAT:
|
||||
// RLE [byte]
|
||||
// RLE upper bit set: draw RLE amount (& 0x7F) of pixels with specified color (color byte follows after RLE byte)
|
||||
// RLE upper bit not set: draw RLE amount of pixels (those pixels follow right after RLE byte)
|
||||
stream->skip(2);
|
||||
expectedPixels = _width * _height;
|
||||
|
||||
while (expectedPixels > 0) {
|
||||
rleByte = stream->readByte();
|
||||
|
||||
if (rleByte & 0x80) {
|
||||
expectedPixels -= rleByte & 0x7F;
|
||||
stream->skip(1);
|
||||
} else {
|
||||
// skip over pixels
|
||||
expectedPixels -= rleByte;
|
||||
stream->skip(rleByte); // skip over pixel data
|
||||
}
|
||||
}
|
||||
if (expectedPixels < 0) {
|
||||
warning("AccessVIDMoviePlay: pixel count mismatch during full frame compressed fill, data corrupt?");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AccessVIDMovieDecoder::StreamVideoTrack::skipOverPalette(Common::SeekableReadStream *stream) {
|
||||
stream->skip(0x300); // 3 bytes per color, 256 colors
|
||||
return true;
|
||||
}
|
||||
|
||||
void AccessVIDMovieDecoder::StreamVideoTrack::decodePalette(Common::SeekableReadStream *stream) {
|
||||
byte red, green, blue;
|
||||
assert(stream);
|
||||
|
||||
// VID files use a 6-bit palette and not a 8-bit one, we change it to 8-bit
|
||||
for (uint16 curColor = 0; curColor < 256; curColor++) {
|
||||
red = stream->readByte() & 0x3F;
|
||||
green = stream->readByte() & 0x3F;
|
||||
blue = stream->readByte() & 0x3F;
|
||||
_palette[curColor * 3] = (red << 2) | (red >> 4);
|
||||
_palette[curColor * 3 + 1] = (green << 2) | (green >> 4);
|
||||
_palette[curColor * 3 + 2] = (blue << 2) | (blue >> 4);
|
||||
}
|
||||
|
||||
_dirtyPalette = true;
|
||||
}
|
||||
|
||||
const byte *AccessVIDMovieDecoder::StreamVideoTrack::getPalette() const {
|
||||
_dirtyPalette = false;
|
||||
return _palette;
|
||||
}
|
||||
|
||||
bool AccessVIDMovieDecoder::StreamVideoTrack::hasDirtyPalette() const {
|
||||
return _dirtyPalette;
|
||||
}
|
||||
|
||||
AccessVIDMovieDecoder::StreamAudioTrack::StreamAudioTrack(uint32 sampleRate, Audio::Mixer::SoundType soundType) :
|
||||
AudioTrack(soundType) {
|
||||
_totalAudioQueued = 0; // currently 0 milliseconds queued
|
||||
|
||||
_sampleRate = sampleRate;
|
||||
_stereo = false; // always mono
|
||||
|
||||
_audioStream = Audio::makeQueuingAudioStream(sampleRate, _stereo);
|
||||
}
|
||||
|
||||
AccessVIDMovieDecoder::StreamAudioTrack::~StreamAudioTrack() {
|
||||
delete _audioStream;
|
||||
}
|
||||
|
||||
void AccessVIDMovieDecoder::StreamAudioTrack::queueAudio(Common::SeekableReadStream *stream, byte chunkId) {
|
||||
Common::SeekableReadStream *rawAudioStream = nullptr;
|
||||
Audio::RewindableAudioStream *audioStream = nullptr;
|
||||
uint32 audioLengthMSecs = 0;
|
||||
|
||||
if (chunkId == kVIDMovieChunkId_AudioFirstChunk) {
|
||||
stream->skip(3); // skip over additional delay + sample rate
|
||||
}
|
||||
|
||||
uint32 audioSize = stream->readUint16LE();
|
||||
|
||||
// Read the specified chunk into memory
|
||||
rawAudioStream = stream->readStream(audioSize);
|
||||
audioLengthMSecs = audioSize * 1000 / _sampleRate; // 1 byte == 1 8-bit sample
|
||||
|
||||
audioStream = Audio::makeRawStream(rawAudioStream, _sampleRate, Audio::FLAG_UNSIGNED | Audio::FLAG_LITTLE_ENDIAN, DisposeAfterUse::YES);
|
||||
if (audioStream) {
|
||||
_totalAudioQueued += audioLengthMSecs;
|
||||
_audioStream->queueAudioStream(audioStream, DisposeAfterUse::YES);
|
||||
} else {
|
||||
// in case there was an error
|
||||
delete rawAudioStream;
|
||||
}
|
||||
}
|
||||
|
||||
bool AccessVIDMovieDecoder::StreamAudioTrack::skipOverAudio(Common::SeekableReadStream *stream, byte chunkId) {
|
||||
if (chunkId == kVIDMovieChunkId_AudioFirstChunk) {
|
||||
stream->skip(3); // skip over additional delay + sample rate
|
||||
}
|
||||
uint32 audioSize = stream->readUint16LE();
|
||||
stream->skip(audioSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
Audio::AudioStream *AccessVIDMovieDecoder::StreamAudioTrack::getAudioStream() const {
|
||||
return _audioStream;
|
||||
}
|
||||
|
||||
bool AccessEngine::playMovie(const Common::Path &filename, const Common::Point &pos) {
|
||||
AccessVIDMovieDecoder videoDecoder;
|
||||
|
||||
Common::Point framePos(pos.x, pos.y);
|
||||
|
||||
if (!videoDecoder.loadFile(filename)) {
|
||||
warning("AccessVIDMoviePlay: could not open '%s'", filename.toString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool skipVideo = false;
|
||||
|
||||
_events->clearEvents();
|
||||
videoDecoder.start();
|
||||
|
||||
while (!shouldQuit() && !videoDecoder.endOfVideo() && !skipVideo) {
|
||||
if (videoDecoder.needsUpdate()) {
|
||||
const Graphics::Surface *frame = videoDecoder.decodeNextFrame();
|
||||
|
||||
if (frame) {
|
||||
_screen->blitFrom(*frame);
|
||||
|
||||
if (videoDecoder.hasDirtyPalette()) {
|
||||
const byte *palette = videoDecoder.getPalette();
|
||||
g_system->getPaletteManager()->setPalette(palette, 0, 256);
|
||||
}
|
||||
|
||||
_screen->update();
|
||||
}
|
||||
}
|
||||
|
||||
_events->pollEventsAndWait();
|
||||
|
||||
Common::CustomEventType action;
|
||||
if (_events->getAction(action)) {
|
||||
if (action == kActionSkip)
|
||||
skipVideo = true;
|
||||
}
|
||||
}
|
||||
|
||||
return !skipVideo;
|
||||
}
|
||||
|
||||
} // End of namespace Access
|
||||
151
engines/access/video/movie_decoder.h
Normal file
151
engines/access/video/movie_decoder.h
Normal file
@@ -0,0 +1,151 @@
|
||||
/* 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 ACCESS_VIDEO_MOVIE_DECODER_H
|
||||
#define ACCESS_VIDEO_MOVIE_DECODER_H
|
||||
|
||||
#include "video/video_decoder.h"
|
||||
#include "audio/audiostream.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace Image {
|
||||
class Codec;
|
||||
}
|
||||
|
||||
namespace Access {
|
||||
|
||||
enum kDebugLevels {
|
||||
kVIDMovieChunkId_FullFrame = 0x00,
|
||||
kVIDMovieChunkId_FullFrameCompressed = 0x01,
|
||||
kVIDMovieChunkId_Palette = 0x02,
|
||||
kVIDMovieChunkId_FullFrameCompressedFill = 0x03,
|
||||
kVIDMovieChunkId_PartialFrameCompressed = 0x04,
|
||||
kVIDMovieChunkId_EndOfFile = 0x14,
|
||||
kVIDMovieChunkId_AudioFirstChunk = 0x7C,
|
||||
kVIDMovieChunkId_Audio = 0x7D
|
||||
};
|
||||
|
||||
// This video format is used in at least the following Access engine games:
|
||||
// - Noctropolis
|
||||
// - Synnergist
|
||||
|
||||
class AccessVIDMovieDecoder : public Video::VideoDecoder {
|
||||
public:
|
||||
AccessVIDMovieDecoder();
|
||||
~AccessVIDMovieDecoder() override;
|
||||
|
||||
bool loadStream(Common::SeekableReadStream *stream) override;
|
||||
void close() override;
|
||||
|
||||
protected:
|
||||
void readNextPacket() override;
|
||||
|
||||
private:
|
||||
bool streamSkipFullFrameCompressedFill();
|
||||
|
||||
private:
|
||||
int32 _streamSeekOffset; /* current stream offset, pointing to not-yet-indexed stream position */
|
||||
uint32 _streamVideoIndex; /* current stream index for video decoding */
|
||||
uint32 _streamAudioIndex; /* current stream index for audio decoding */
|
||||
|
||||
struct IndexCacheEntry {
|
||||
byte chunkId;
|
||||
int32 offset;
|
||||
};
|
||||
|
||||
Common::Array<IndexCacheEntry> _indexCacheTable;
|
||||
|
||||
private:
|
||||
class StreamVideoTrack : public VideoTrack {
|
||||
public:
|
||||
StreamVideoTrack(uint32 width, uint32 height, uint16 regularFrameDelay);
|
||||
~StreamVideoTrack() override;
|
||||
|
||||
bool endOfTrack() const override;
|
||||
|
||||
uint16 getWidth() const override { return _width; }
|
||||
uint16 getHeight() const override { return _height; }
|
||||
Graphics::PixelFormat getPixelFormat() const override;
|
||||
int getCurFrame() const override { return _curFrame; }
|
||||
void setNextFrameStartTime(uint32 nextFrameStartTime) { _nextFrameStartTime = nextFrameStartTime; }
|
||||
uint32 getNextFrameStartTime() const override { return _nextFrameStartTime; }
|
||||
const Graphics::Surface *decodeNextFrame() override { return _surface; }
|
||||
|
||||
const byte *getPalette() const override;
|
||||
bool hasDirtyPalette() const override;
|
||||
|
||||
void decodePalette(Common::SeekableReadStream *stream);
|
||||
void decodeFrame(Common::SeekableReadStream *stream, byte chunkId);
|
||||
bool skipOverFrame(Common::SeekableReadStream *stream, byte chunkId);
|
||||
bool skipOverPalette(Common::SeekableReadStream *stream);
|
||||
|
||||
void setEndOfTrack() { _endOfTrack = true; }
|
||||
|
||||
private:
|
||||
Graphics::Surface *_surface;
|
||||
|
||||
int _curFrame;
|
||||
uint32 _nextFrameStartTime;
|
||||
|
||||
byte _palette[3 * 256];
|
||||
mutable bool _dirtyPalette;
|
||||
uint16 _width, _height;
|
||||
|
||||
uint16 _regularFrameDelay; // delay between frames (1 = 1/60 of a second)
|
||||
bool _endOfTrack;
|
||||
};
|
||||
|
||||
class StreamAudioTrack : public AudioTrack {
|
||||
public:
|
||||
StreamAudioTrack(uint32 sampleRate, Audio::Mixer::SoundType soundType);
|
||||
~StreamAudioTrack() override;
|
||||
|
||||
void queueAudio(Common::SeekableReadStream *stream, byte chunkId);
|
||||
bool skipOverAudio(Common::SeekableReadStream *stream, byte chunkId);
|
||||
|
||||
protected:
|
||||
Audio::AudioStream *getAudioStream() const override;
|
||||
|
||||
private:
|
||||
Audio::QueuingAudioStream *_audioStream;
|
||||
uint32 _totalAudioQueued; /* total amount of milliseconds of audio, that we queued up already */
|
||||
|
||||
public:
|
||||
uint32 getTotalAudioQueued() const { return _totalAudioQueued; }
|
||||
|
||||
private:
|
||||
int16 decodeSample(uint8 dataNibble);
|
||||
|
||||
uint16 _sampleRate;
|
||||
bool _stereo;
|
||||
};
|
||||
|
||||
Common::SeekableReadStream *_stream;
|
||||
StreamVideoTrack *_videoTrack;
|
||||
StreamAudioTrack *_audioTrack;
|
||||
};
|
||||
|
||||
} // End of namespace Access
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user