From 010315dc0c1862de6778130e416880388b9d0bdf Mon Sep 17 00:00:00 2001 From: Jussi Pitkanen Date: Wed, 25 May 2011 18:40:55 +0300 Subject: AGI: Implement resource loader for the DDP booter game --- engines/agi/agi.h | 17 ++-- engines/agi/loader_v1.cpp | 249 ++++++++++++++++++++++++++++++++++++++++++++++ engines/agi/module.mk | 1 + 3 files changed, 260 insertions(+), 7 deletions(-) create mode 100644 engines/agi/loader_v1.cpp diff --git a/engines/agi/agi.h b/engines/agi/agi.h index 2bc11449b9..bf730fcfb4 100644 --- a/engines/agi/agi.h +++ b/engines/agi/agi.h @@ -652,6 +652,9 @@ private: Common::String _dsk0Name; Common::String _dsk1Name; + int loadDir(AgiDir *agid, int offset, int num); + uint8 *loadVolRes(AgiDir *agid); + public: AgiLoader_v1(AgiEngine *vm, Common::String dsk0, Common::String dsk1) { _vm = vm; @@ -659,13 +662,13 @@ public: _dsk1Name = dsk1; } - virtual int init() { return 0; } - virtual int deinit() { return 0; } - virtual int detectGame() { return 0; } - virtual int loadResource(int, int) { return 0; } - virtual int unloadResource(int, int) { return 0; } - virtual int loadObjects(const char *) { return 0; } - virtual int loadWords(const char *) { return 0; } + virtual int init(); + virtual int deinit(); + virtual int detectGame(); + virtual int loadResource(int, int); + virtual int unloadResource(int, int); + virtual int loadObjects(const char *); + virtual int loadWords(const char *); }; class AgiLoader_v2 : public AgiLoader { diff --git a/engines/agi/loader_v1.cpp b/engines/agi/loader_v1.cpp new file mode 100644 index 0000000000..40f797286f --- /dev/null +++ b/engines/agi/loader_v1.cpp @@ -0,0 +1,249 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "agi/agi.h" + +#define offsetTHS(track,head,sector) (512 * ((((track) * 2 + (head)) * 9) + (sector))) +#define offset(sector) offsetTHS(sector / 18, (sector % 18) / 9, (sector % 18) % 9) + +#define BASE_SECTOR 0x1C2 + +#define LOGDIR_SEC offset(171) + 5 +#define LOGDIR_NUM 43 + +#define PICDIR_SEC offset(180) + 5 +#define PICDIR_NUM 30 + +#define VIEWDIR_SEC offset(189) + 5 +#define VIEWDIR_NUM 171 + +#define SNDDIR_SEC offset(198) + 5 +#define SNDDIR_NUM 64 + +namespace Agi { + +int AgiLoader_v1::detectGame() { + return _vm->setupV2Game(_vm->getVersion()); +} + +int AgiLoader_v1::loadDir(AgiDir *agid, int offset, int num) { + Common::File fp; + + if (!fp.open(_dsk0Name)) + return errBadFileOpen; + + // Cleanup + for (int i = 0; i < MAX_DIRS; i++) { + agid[i].volume = 0xFF; + agid[i].offset = _EMPTY; + } + + fp.seek(offset, SEEK_SET); + for (int i = 0; i < num; i++) { + int b0 = fp.readByte(); + int b1 = fp.readByte(); + int b2 = fp.readByte(); + + if (b0 == 0xFF && b1 == 0xFF && b2 == 0xFF) { + agid[i].volume = 0xFF; + agid[i].offset = _EMPTY; + } else { + int sec = (BASE_SECTOR + (((b0 & 0xF) << 8) | b1)) >> 1; + int off = ((b1 & 0x1) << 8) | b2; + agid[i].volume = 0; + agid[i].offset = (sec << 16) | off; + } + } + + fp.close(); + + return errOK; +} + +int AgiLoader_v1::init() { + int ec = errOK; + + ec = loadDir(_vm->_game.dirLogic, LOGDIR_SEC, LOGDIR_NUM); + if (ec == errOK) + ec = loadDir(_vm->_game.dirPic, PICDIR_SEC, PICDIR_NUM); + if (ec == errOK) + ec = loadDir(_vm->_game.dirView, VIEWDIR_SEC, VIEWDIR_NUM); + if (ec == errOK) + ec = loadDir(_vm->_game.dirSound, SNDDIR_SEC, SNDDIR_NUM); + + return ec; +} + +int AgiLoader_v1::deinit() { + int ec = errOK; + return ec; +} + +uint8 *AgiLoader_v1::loadVolRes(struct AgiDir *agid) { + uint8 *data = NULL; + Common::File fp; + + if (agid->offset == _EMPTY) + return NULL; + + int sec = agid->offset >> 16; + int off = agid->offset & 0xFFFF; + + fp.open(_dsk0Name); + fp.seek(offset(sec) + off, SEEK_SET); + + int signature = fp.readUint16BE(); + if (signature != 0x1234) { + warning("AgiLoader_v1::loadVolRes: bad signature %04x", signature); + return NULL; + } + + fp.readByte(); + agid->len = fp.readUint16LE(); + data = (uint8 *)calloc(1, agid->len + 32); + fp.read(data, agid->len); + + fp.close(); + + return data; +} + +int AgiLoader_v1::loadResource(int t, int n) { + int ec = errOK; + uint8 *data = NULL; + + debugC(3, kDebugLevelResources, "(t = %d, n = %d)", t, n); + if (n > MAX_DIRS) + return errBadResource; + + switch (t) { + case rLOGIC: + if (~_vm->_game.dirLogic[n].flags & RES_LOADED) { + debugC(3, kDebugLevelResources, "loading logic resource %d", n); + unloadResource(rLOGIC, n); + + // load raw resource into data + data = loadVolRes(&_vm->_game.dirLogic[n]); + + _vm->_game.logics[n].data = data; + ec = data ? _vm->decodeLogic(n) : errBadResource; + + _vm->_game.logics[n].sIP = 2; + } + + // if logic was cached, we get here + // reset code pointers incase it was cached + + _vm->_game.logics[n].cIP = _vm->_game.logics[n].sIP; + break; + case rPICTURE: + // if picture is currently NOT loaded *OR* cacheing is off, + // unload the resource (caching == off) and reload it + + debugC(3, kDebugLevelResources, "loading picture resource %d", n); + if (_vm->_game.dirPic[n].flags & RES_LOADED) + break; + + // if loaded but not cached, unload it + // if cached but not loaded, etc + unloadResource(rPICTURE, n); + data = loadVolRes(&_vm->_game.dirPic[n]); + + if (data != NULL) { + _vm->_game.pictures[n].rdata = data; + _vm->_game.dirPic[n].flags |= RES_LOADED; + } else { + ec = errBadResource; + } + break; + case rSOUND: + debugC(3, kDebugLevelResources, "loading sound resource %d", n); + if (_vm->_game.dirSound[n].flags & RES_LOADED) + break; + + data = loadVolRes(&_vm->_game.dirSound[n]); + + if (data != NULL) { + // Freeing of the raw resource from memory is delegated to the createFromRawResource-function + _vm->_game.sounds[n] = AgiSound::createFromRawResource(data, _vm->_game.dirSound[n].len, n, *_vm->_sound, _vm->_soundemu); + _vm->_game.dirSound[n].flags |= RES_LOADED; + } else { + ec = errBadResource; + } + break; + case rVIEW: + // Load a VIEW resource into memory... + // Since VIEWS alter the view table ALL the time + // can we cache the view? or must we reload it all + // the time? + if (_vm->_game.dirView[n].flags & RES_LOADED) + break; + + debugC(3, kDebugLevelResources, "loading view resource %d", n); + unloadResource(rVIEW, n); + data = loadVolRes(&_vm->_game.dirView[n]); + if (data) { + _vm->_game.views[n].rdata = data; + _vm->_game.dirView[n].flags |= RES_LOADED; + ec = _vm->decodeView(n); + } else { + ec = errBadResource; + } + break; + default: + ec = errBadResource; + break; + } + + return ec; +} + +int AgiLoader_v1::unloadResource(int t, int n) { + switch (t) { + case rLOGIC: + _vm->unloadLogic(n); + break; + case rPICTURE: + _vm->_picture->unloadPicture(n); + break; + case rVIEW: + _vm->unloadView(n); + break; + case rSOUND: + _vm->_sound->unloadSound(n); + break; + } + + return errOK; +} + +// TODO: Find the disk image equivalent. +int AgiLoader_v1::loadObjects(const char *fname) { + return _vm->loadObjects(fname); +} + +// TODO: Find the disk image equivalent. +int AgiLoader_v1::loadWords(const char *fname) { + return _vm->loadObjects(fname); +} + +} diff --git a/engines/agi/module.mk b/engines/agi/module.mk index 2339d1019f..3bb4dac20c 100644 --- a/engines/agi/module.mk +++ b/engines/agi/module.mk @@ -11,6 +11,7 @@ MODULE_OBJS := \ id.o \ inv.o \ keyboard.o \ + loader_v1.o \ loader_v2.o \ loader_v3.o \ logic.o \ -- cgit v1.2.3