From e29ec6e79c325bcea2c95ecbfeb3a64c80a30630 Mon Sep 17 00:00:00 2001 From: Paweł Kołodziejski Date: Wed, 5 May 2004 07:25:32 +0000 Subject: adding initial code for Another World engine svn-id: r13783 --- awe/awe.cpp | 130 ++++++++++++++ awe/awe.h | 57 ++++++ awe/bank.cpp | 140 +++++++++++++++ awe/bank.h | 56 ++++++ awe/engine.cpp | 145 +++++++++++++++ awe/engine.h | 60 +++++++ awe/file.cpp | 190 ++++++++++++++++++++ awe/file.h | 53 ++++++ awe/intern.h | 67 +++++++ awe/logic.cpp | 512 ++++++++++++++++++++++++++++++++++++++++++++++++++++ awe/logic.h | 114 ++++++++++++ awe/module.mk | 25 +++ awe/resource.cpp | 277 ++++++++++++++++++++++++++++ awe/resource.h | 92 ++++++++++ awe/sdlstub.cpp | 324 +++++++++++++++++++++++++++++++++ awe/serializer.cpp | 127 +++++++++++++ awe/serializer.h | 88 +++++++++ awe/staticres.cpp | 403 +++++++++++++++++++++++++++++++++++++++++ awe/systemstub.h | 68 +++++++ awe/util.cpp | 58 ++++++ awe/util.h | 47 +++++ awe/video.cpp | 516 +++++++++++++++++++++++++++++++++++++++++++++++++++++ awe/video.h | 102 +++++++++++ 23 files changed, 3651 insertions(+) create mode 100644 awe/awe.cpp create mode 100644 awe/awe.h create mode 100644 awe/bank.cpp create mode 100644 awe/bank.h create mode 100644 awe/engine.cpp create mode 100644 awe/engine.h create mode 100644 awe/file.cpp create mode 100644 awe/file.h create mode 100644 awe/intern.h create mode 100644 awe/logic.cpp create mode 100644 awe/logic.h create mode 100644 awe/module.mk create mode 100644 awe/resource.cpp create mode 100644 awe/resource.h create mode 100644 awe/sdlstub.cpp create mode 100644 awe/serializer.cpp create mode 100644 awe/serializer.h create mode 100644 awe/staticres.cpp create mode 100644 awe/systemstub.h create mode 100644 awe/util.cpp create mode 100644 awe/util.h create mode 100644 awe/video.cpp create mode 100644 awe/video.h (limited to 'awe') diff --git a/awe/awe.cpp b/awe/awe.cpp new file mode 100644 index 0000000000..df1f7c59d4 --- /dev/null +++ b/awe/awe.cpp @@ -0,0 +1,130 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "common/stdafx.h" + +#include "base/gameDetector.h" +#include "base/plugins.h" +#include "backends/fs/fs.h" + +#include "sound/mixer.h" +#include "common/file.h" +#include "common/config-manager.h" + +#include "awe/awe.h" +#include "awe/engine.h" +#include "awe/systemstub.h" +#include "awe/util.h" + + +struct AWEGameSettings { + const char *name; + const char *description; + byte id; + uint32 features; + const char *detectname; + GameSettings toGameSettings() const { + GameSettings dummy = { name, description, features }; + return dummy; + } +}; + +static const AWEGameSettings awe_settings[] = { + /* Another World - Out of this World - Europe DOS version */ + { "worlde", "Another World - Out of this World - (Europe, DOS)", Awe::GID_WORLDE, MDT_ADLIB, "bank01" }, + { NULL, NULL, 0, 0, NULL } +}; + +GameList Engine_AWE_gameList() { + const AWEGameSettings *g = awe_settings; + GameList games; + while (g->name) { + games.push_back(g->toGameSettings()); + g++; + } + return games; +} + +DetectedGameList Engine_AWE_detectGames(const FSList &fslist) { + DetectedGameList detectedGames; + const AWEGameSettings *g; + + for (g = awe_settings; g->name; ++g) { + // Iterate over all files in the given directory + for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) { + const char *gameName = file->displayName().c_str(); + + if (0 == scumm_stricmp(g->detectname, gameName)) { + // Match found, add to list of candidates, then abort inner loop. + detectedGames.push_back(g->toGameSettings()); + break; + } + } + } + return detectedGames; +} + +Engine *Engine_AWE_create(GameDetector *detector, OSystem *syst) { + return new Awe::AweEngine(detector, syst); +} + +REGISTER_PLUGIN("AWE Engine", Engine_AWE_gameList, Engine_AWE_create, Engine_AWE_detectGames) + +namespace Awe { + +AweEngine::AweEngine(GameDetector *detector, OSystem *syst) + : Engine(syst) { + + // Setup mixer + if (!_mixer->isReady()) { + ::warning("Sound initialization failed."); + } + + _mixer->setVolume(ConfMan.getInt("sfx_volume") * ConfMan.getInt("master_volume") / 255); + + _dataPath = getGameDataPath(); + _savePath = getSavePath(); + + // Initialize backend + syst->initSize(320, 200); +} + +AweEngine::~AweEngine() { + +} + +void AweEngine::errorString(const char *buf1, char *buf2) { + strcpy(buf2, buf1); +} + +void AweEngine::go() { + g_debugMask = DBG_INFO; + SystemStub *stub = SystemStub_SDL_create(); + debug(0, "%s %s", _dataPath, _savePath); + Awe::Engine *e = new Awe::Engine(stub, _dataPath, _savePath); + e->run(); + delete e; + delete stub; +} + +void AweEngine::shutdown() { + _system->quit(); +} + +} diff --git a/awe/awe.h b/awe/awe.h new file mode 100644 index 0000000000..4091874137 --- /dev/null +++ b/awe/awe.h @@ -0,0 +1,57 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef AWE_H +#define AWE_H + +#include "common/stdafx.h" +#include "common/scummsys.h" +#include "base/engine.h" +#include "base/gameDetector.h" +#include "common/util.h" + +namespace Awe { + +#define BYPASS_PROTECTION + +enum AWEGameId { + GID_WORLDE +}; + +class AweEngine : public ::Engine { + + void errorString( const char *buf_input, char *buf_output); + +protected: + void go(); + void shutdown(); + + const char *_dataPath; + const char *_savePath; + +public: + + AweEngine(GameDetector *detector, OSystem *syst); + virtual ~AweEngine(); + +}; + +} + +#endif diff --git a/awe/bank.cpp b/awe/bank.cpp new file mode 100644 index 0000000000..65934dd339 --- /dev/null +++ b/awe/bank.cpp @@ -0,0 +1,140 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "common/stdafx.h" + +#include "awe/awe.h" +#include "awe/bank.h" +#include "awe/file.h" +#include "awe/resource.h" + +namespace Awe { + +Bank::Bank(const char *dataDir) + : _dataDir(dataDir) { +} + +bool Bank::read(const MemEntry *me, uint8 *buf) { + bool ret = false; + char bankName[10]; + sprintf(bankName, "bank%02x", me->bankNum); + File f; + if (f.open(bankName, _dataDir)) { + f.seek(me->bankPos); + if (me->packedSize == me->unpackedSize) { + f.read(buf, me->packedSize); + ret = true; + } else { + f.read(buf, me->packedSize); + _startBuf = buf; + _iBuf = buf + me->packedSize - 4; + ret = unpack(); + } + } else { + ::error("Bank::read() unable to open '%s'", bankName); + } + return ret; +} + +void Bank::decUnk1(uint8 numChunks, uint8 addCount) { + uint16 count = getCode(numChunks) + addCount + 1; + debug(DBG_BANK, "Bank::decUnk1(%d, %d) count=%d", numChunks, addCount, count); + _unpCtx.datasize -= count; + while (count--) { + assert(_oBuf >= _iBuf && _oBuf >= _startBuf); + *_oBuf = (uint8)getCode(8); + --_oBuf; + } +} + +void Bank::decUnk2(uint8 numChunks) { + uint16 i = getCode(numChunks); + uint16 count = _unpCtx.size + 1; + debug(DBG_BANK, "Bank::decUnk2(%d) i=%d count=%d", numChunks, i, count); + _unpCtx.datasize -= count; + while (count--) { + assert(_oBuf >= _iBuf && _oBuf >= _startBuf); + *_oBuf = *(_oBuf + i); + --_oBuf; + } +} + +bool Bank::unpack() { + _unpCtx.size = 0; + _unpCtx.datasize = READ_BE_UINT32(_iBuf); _iBuf -= 4; + _oBuf = _startBuf + _unpCtx.datasize - 1; + _unpCtx.crc = READ_BE_UINT32(_iBuf); _iBuf -= 4; + _unpCtx.chk = READ_BE_UINT32(_iBuf); _iBuf -= 4; + _unpCtx.crc ^= _unpCtx.chk; + do { + if (!nextChunk()) { + _unpCtx.size = 1; + if (!nextChunk()) { + decUnk1(3, 0); + } else { + decUnk2(8); + } + } else { + uint16 c = getCode(2); + if (c == 3) { + decUnk1(8, 8); + } else { + if (c < 2) { + _unpCtx.size = c + 2; + decUnk2(c + 9); + } else { + _unpCtx.size = getCode(8); + decUnk2(12); + } + } + } + } while (_unpCtx.datasize > 0); + return (_unpCtx.crc == 0); +} + +uint16 Bank::getCode(uint8 numChunks) { + uint16 c = 0; + while (numChunks--) { + c <<= 1; + if (nextChunk()) { + c |= 1; + } + } + return c; +} + +bool Bank::nextChunk() { + bool CF = rcr(false); + if (_unpCtx.chk == 0) { + assert(_iBuf >= _startBuf); + _unpCtx.chk = READ_BE_UINT32(_iBuf); _iBuf -= 4; + _unpCtx.crc ^= _unpCtx.chk; + CF = rcr(true); + } + return CF; +} + +bool Bank::rcr(bool CF) { + bool rCF = (_unpCtx.chk & 1); + _unpCtx.chk >>= 1; + if (CF) _unpCtx.chk |= 0x80000000; + return rCF; +} + +} diff --git a/awe/bank.h b/awe/bank.h new file mode 100644 index 0000000000..a5c14b13f9 --- /dev/null +++ b/awe/bank.h @@ -0,0 +1,56 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __BANK_H__ +#define __BANK_H__ + +#include "stdafx.h" + +#include "intern.h" + +namespace Awe { + +struct MemEntry; + +struct UnpackContext { + uint16 size; + uint32 crc; + uint32 chk; + int32 datasize; +}; + +struct Bank { + UnpackContext _unpCtx; + const char *_dataDir; + uint8 *_iBuf, *_oBuf, *_startBuf; + + Bank(const char *dataDir); + + bool read(const MemEntry *me, uint8 *buf); + void decUnk1(uint8 numChunks, uint8 addCount); + void decUnk2(uint8 numChunks); + bool unpack(); + uint16 getCode(uint8 numChunks); + bool nextChunk(); + bool rcr(bool CF); +}; + +} + +#endif diff --git a/awe/engine.cpp b/awe/engine.cpp new file mode 100644 index 0000000000..ab8b60dea4 --- /dev/null +++ b/awe/engine.cpp @@ -0,0 +1,145 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "stdafx.h" + +#include "awe.h" +#include "engine.h" +#include "file.h" +#include "serializer.h" +#include "systemstub.h" + +namespace Awe { + +Engine::Engine(SystemStub *stub, const char *dataDir, const char *saveDir) + : _stub(stub), _log(&_res, &_vid, stub), _res(&_vid, dataDir), _vid(&_res, stub), + _dataDir(dataDir), _saveDir(saveDir), _stateSlot(0) { +} + +void Engine::run() { + _stub->init("Out Of This World"); + setup(); + // XXX + _log.restartAt(0x3E80); // demo starts at 0x3E81 + while (!_stub->_pi.quit) { + _log.setupScripts(); + _log.inp_updatePlayer(); + processInput(); + _log.runScripts(); + } + finish(); + _stub->destroy(); +} + +void Engine::setup() { + _vid.init(); + _res.allocMemBlock(); + _res.readEntries(); + _log.init(); +} + +void Engine::finish() { + // XXX + _res.freeMemBlock(); +} + +void Engine::processInput() { + if (_stub->_pi.load) { + loadGameState(_stateSlot); + _stub->_pi.load = false; + } + if (_stub->_pi.save) { + saveGameState(_stateSlot, "quicksave"); + _stub->_pi.save = false; + } + if (_stub->_pi.fastMode) { + _log._fastMode = !_log._fastMode; + _stub->_pi.fastMode = false; + } + if (_stub->_pi.stateSlot != 0) { + int8 slot = _stateSlot + _stub->_pi.stateSlot; + if (slot >= 0 && slot < MAX_SAVE_SLOTS) { + _stateSlot = slot; + debug(DBG_INFO, "Current game state slot is %d", _stateSlot); + } + _stub->_pi.stateSlot = 0; + } +} + +void Engine::makeGameStateName(uint8 slot, char *buf) { + sprintf(buf, "raw.s%02d", slot); +} + +void Engine::saveGameState(uint8 slot, const char *desc) { + char stateFile[20]; + makeGameStateName(slot, stateFile); + File f(true); + if (!f.open(stateFile, _saveDir, "wb")) { + ::warning("Unable to save state file '%s'", stateFile); + } else { + // header + f.writeUint32BE('AWSV'); + f.writeUint16BE(Serializer::CUR_VER); + f.writeUint16BE(0); + char hdrdesc[32]; + strncpy(hdrdesc, desc, sizeof(hdrdesc) - 1); + f.write(hdrdesc, sizeof(hdrdesc)); + // contents + Serializer s(&f, Serializer::SM_SAVE, _res._memPtrStart); + _log.saveOrLoad(s); + _res.saveOrLoad(s); + _vid.saveOrLoad(s); + if (f.ioErr()) { + ::warning("I/O error when saving game state"); + } else { + debug(DBG_INFO, "Saved state to slot %d", _stateSlot); + } + } +} + +void Engine::loadGameState(uint8 slot) { + char stateFile[20]; + makeGameStateName(slot, stateFile); + File f(true); + if (!f.open(stateFile, _saveDir, "rb")) { + ::warning("Unable to open state file '%s'", stateFile); + } else { + uint32 id = f.readUint32BE(); + if (id != 'AWSV') { + ::warning("Bad savegame format"); + } else { + uint16 ver = f.readUint16BE(); + f.readUint16BE(); + char hdrdesc[32]; + f.read(hdrdesc, sizeof(hdrdesc)); + // contents + Serializer s(&f, Serializer::SM_LOAD, _res._memPtrStart, ver); + _log.saveOrLoad(s); + _res.saveOrLoad(s); + _vid.saveOrLoad(s); + } + if (f.ioErr()) { + ::warning("I/O error when loading game state"); + } else { + debug(DBG_INFO, "Loaded state from slot %d", _stateSlot); + } + } +} + +} diff --git a/awe/engine.h b/awe/engine.h new file mode 100644 index 0000000000..4a8a7ca19b --- /dev/null +++ b/awe/engine.h @@ -0,0 +1,60 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ENGINE_H__ +#define __ENGINE_H__ + +#include "stdafx.h" + +#include "intern.h" +#include "logic.h" +#include "resource.h" +#include "video.h" + +namespace Awe { + +struct SystemStub; + +struct Engine { + enum { + MAX_SAVE_SLOTS = 100 + }; + + SystemStub *_stub; + Logic _log; + Resource _res; + Video _vid; + const char *_dataDir, *_saveDir; + uint8 _stateSlot; + + Engine(SystemStub *stub, const char *dataDir, const char *saveDir); + + void run(); + void setup(); + void finish(); + void processInput(); + + void makeGameStateName(uint8 slot, char *buf); + void saveGameState(uint8 slot, const char *desc); + void loadGameState(uint8 slot); +}; + +} + +#endif diff --git a/awe/file.cpp b/awe/file.cpp new file mode 100644 index 0000000000..15dead158e --- /dev/null +++ b/awe/file.cpp @@ -0,0 +1,190 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "stdafx.h" + +#include "zlib.h" +#include "file.h" + +namespace Awe { + +struct File_impl { + bool _ioErr; + File_impl() : _ioErr(false) {} + virtual bool open(const char *path, const char *mode) = 0; + virtual void close() = 0; + virtual void seek(int32 off) = 0; + virtual void read(void *ptr, uint32 size) = 0; + virtual void write(void *ptr, uint32 size) = 0; +}; + +struct stdFile : File_impl { + FILE *_fp; + stdFile() : _fp(0) {} + bool open(const char *path, const char *mode) { + _ioErr = false; + _fp = fopen(path, mode); + return (_fp != NULL); + } + void close() { + if (_fp) { + fclose(_fp); + _fp = 0; + } + } + void seek(int32 off) { + if (_fp) { + fseek(_fp, off, SEEK_SET); + } + } + void read(void *ptr, uint32 size) { + if (_fp) { + uint32 r = fread(ptr, 1, size, _fp); + if (r != size) { + _ioErr = true; + } + } + } + void write(void *ptr, uint32 size) { + if (_fp) { + uint32 r = fwrite(ptr, 1, size, _fp); + if (r != size) { + _ioErr = true; + } + } + } +}; + +struct zlibFile : File_impl { + gzFile _fp; + zlibFile() : _fp(0) {} + bool open(const char *path, const char *mode) { + _ioErr = false; + _fp = gzopen(path, mode); + return (_fp != NULL); + } + void close() { + if (_fp) { + gzclose(_fp); + _fp = 0; + } + } + void seek(int32 off) { + if (_fp) { + gzseek(_fp, off, SEEK_SET); + } + } + void read(void *ptr, uint32 size) { + if (_fp) { + uint32 r = gzread(_fp, ptr, size); + if (r != size) { + _ioErr = true; + } + } + } + void write(void *ptr, uint32 size) { + if (_fp) { + uint32 r = gzwrite(_fp, ptr, size); + if (r != size) { + _ioErr = true; + } + } + } +}; + +File::File(bool gzipped) { + if (gzipped) { + _impl = new zlibFile; + } else { + _impl = new stdFile; + } +} + +File::~File() { + _impl->close(); + delete _impl; +} + +bool File::open(const char *filename, const char *directory, const char *mode) { + _impl->close(); + char buf[512]; + sprintf(buf, "%s/%s", directory, filename); + char *p = buf + strlen(directory) + 1; + string_lower(p); + bool opened = _impl->open(buf, mode); + if (!opened) { // let's try uppercase + string_upper(p); + opened = _impl->open(buf, mode); + } + return opened; +} + +void File::close() { + _impl->close(); +} + +bool File::ioErr() const { + return _impl->_ioErr; +} + +void File::seek(int32 off) { + _impl->seek(off); +} + +void File::read(void *ptr, uint32 size) { + _impl->read(ptr, size); +} + +uint8 File::readByte() { + uint8 b; + read(&b, 1); + return b; +} + +uint16 File::readUint16BE() { + uint8 hi = readByte(); + uint8 lo = readByte(); + return (hi << 8) | lo; +} + +uint32 File::readUint32BE() { + uint16 hi = readUint16BE(); + uint16 lo = readUint16BE(); + return (hi << 16) | lo; +} + +void File::write(void *ptr, uint32 size) { + _impl->write(ptr, size); +} + +void File::writeByte(uint8 b) { + write(&b, 1); +} + +void File::writeUint16BE(uint16 n) { + writeByte(n >> 8); + writeByte(n & 0xFF); +} + +void File::writeUint32BE(uint32 n) { + writeUint16BE(n >> 16); + writeUint16BE(n & 0xFFFF); +} + +} diff --git a/awe/file.h b/awe/file.h new file mode 100644 index 0000000000..c1efc33ec1 --- /dev/null +++ b/awe/file.h @@ -0,0 +1,53 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __FILE_H__ +#define __FILE_H__ + +#include "stdafx.h" + +#include "intern.h" + +namespace Awe { + +struct File_impl; + +struct File { + File_impl *_impl; + + File(bool gzipped = false); + ~File(); + + bool open(const char *filename, const char *directory, const char *mode="rb"); + void close(); + bool ioErr() const; + void seek(int32 off); + void read(void *ptr, uint32 size); + uint8 readByte(); + uint16 readUint16BE(); + uint32 readUint32BE(); + void write(void *ptr, uint32 size); + void writeByte(uint8 b); + void writeUint16BE(uint16 n); + void writeUint32BE(uint32 n); +}; + +} + +#endif diff --git a/awe/intern.h b/awe/intern.h new file mode 100644 index 0000000000..81b632de87 --- /dev/null +++ b/awe/intern.h @@ -0,0 +1,67 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __INTERN_H__ +#define __INTERN_H__ + +#include +#include +#include +#include + +#include "stdafx.h" + +#include "common/scummsys.h" + +#include "util.h" + +namespace Awe { + +template +inline void SWAP(T &a, T &b) { + T tmp = a; + a = b; + b = tmp; +} + +struct Ptr { + uint8 *pc; + + uint8 fetchByte() { + return *pc++; + } + + uint16 fetchWord() { + uint16 i = READ_BE_UINT16(pc); + pc += 2; + return i; + } +}; + +struct Point { + int16 x, y; + + Point() : x(0), y(0) {} + Point(int16 xx, int16 yy) : x(xx), y(yy) {} + Point(const Point &p) : x(p.x), y(p.y) {} +}; + +} + +#endif diff --git a/awe/logic.cpp b/awe/logic.cpp new file mode 100644 index 0000000000..64733e67f3 --- /dev/null +++ b/awe/logic.cpp @@ -0,0 +1,512 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include + +#include "stdafx.h" + +#include "awe.h" +#include "logic.h" +#include "resource.h" +#include "video.h" +#include "serializer.h" +#include "systemstub.h" + +namespace Awe { + +Logic::Logic(Resource *res, Video *vid, SystemStub *stub) + : _res(res), _vid(vid), _stub(stub) { +} + +void Logic::init() { + memset(_scriptVars, 0, sizeof(_scriptVars)); + _scriptVars[0x54] = 0x81; + _scriptVars[VAR_RANDOM_SEED] = time(0); + _fastMode = false; +} + +void Logic::op_movConst() { + uint8 i = _scriptPtr.fetchByte(); + int16 n = _scriptPtr.fetchWord(); + debug(DBG_LOGIC, "Logic::op_movConst(0x%02X, %d)", i, n); + _scriptVars[i] = n; +} + +void Logic::op_mov() { + uint8 i = _scriptPtr.fetchByte(); + uint8 j = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_mov(0x%02X, 0x%02X)", i, j); + _scriptVars[i] = _scriptVars[j]; +} + +void Logic::op_add() { + uint8 i = _scriptPtr.fetchByte(); + uint8 j = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_add(0x%02X, 0x%02X)", i, j); + _scriptVars[i] += _scriptVars[j]; +} + +void Logic::op_addConst() { + uint8 i = _scriptPtr.fetchByte(); + int16 n = _scriptPtr.fetchWord(); + debug(DBG_LOGIC, "Logic::op_addConst(0x%02X, %d)", i, n); + _scriptVars[i] += n; +} + +void Logic::op_call() { + uint16 off = _scriptPtr.fetchWord(); + uint8 sp = _stackPtr; + debug(DBG_LOGIC, "Logic::op_call(0x%X)", off); + _scriptStackCalls[sp] = _scriptPtr.pc - _res->_segCode; + ++_stackPtr; + _scriptPtr.pc = _res->_segCode + off; +} + +void Logic::op_ret() { + debug(DBG_LOGIC, "Logic::op_ret()"); + --_stackPtr; + uint8 sp = _stackPtr; + _scriptPtr.pc = _res->_segCode + _scriptStackCalls[sp]; +} + +void Logic::op_break() { + debug(DBG_LOGIC, "Logic::op_break()"); + _scriptHalted = true; +} + +void Logic::op_jmp() { + uint16 off = _scriptPtr.fetchWord(); + debug(DBG_LOGIC, "Logic::op_jmp(0x%02X)", off); + _scriptPtr.pc = _res->_segCode + off; +} + +void Logic::op_setScriptPos() { + uint8 i = _scriptPtr.fetchByte(); + uint16 n = _scriptPtr.fetchWord(); + debug(DBG_LOGIC, "Logic::op_setScriptPos(0x%X, 0x%X)", i, n); + _scriptPos[1][i] = n; +} + +void Logic::op_jnz() { + uint8 i = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_jnz(0x%02X)", i); + --_scriptVars[i]; + if (_scriptVars[i] != 0) { + op_jmp(); + } else { + _scriptPtr.fetchWord(); + } +} + +void Logic::op_condJmp() { +#ifdef BYPASS_PROTECTION + if (_res->_curPtrsId == 0x3E80 && _scriptPtr.pc == _res->_segCode + 0xCB9) { + // (0x0CB8) condJmp(0x80, VAR(41), VAR(30), 0xCD3) + *(_scriptPtr.pc + 0x00) = 0x81; + *(_scriptPtr.pc + 0x03) = 0x0D; + *(_scriptPtr.pc + 0x04) = 0x24; + // (0x0D4E) condJmp(0x4, VAR(50), 6, 0xDBC) + *(_scriptPtr.pc + 0x99) = 0x0D; + *(_scriptPtr.pc + 0x9A) = 0x5A; + ::warning("Logic::op_condJmp() bypassing protection"); + } +#endif + uint8 op = _scriptPtr.fetchByte(); + int16 b = _scriptVars[_scriptPtr.fetchByte()]; + int16 a = _scriptPtr.fetchByte(); + if (op & 0x80) { + a = _scriptVars[a]; + } else { + if (op & 0x40) { + a = (a << 8) | _scriptPtr.fetchByte(); + } + } + debug(DBG_LOGIC, "Logic::op_condJmp(%d, 0x%02X, 0x%02X)", op, b, a); + bool expr = false; + switch (op & 7) { + case 0: // jz + expr = (b == a); + break; + case 1: // jnz + expr = (b != a); + break; + case 2: // jg + expr = (b > a); + break; + case 3: // jge + expr = (b >= a); + break; + case 4: // jl + expr = (b < a); + break; + case 5: // jle + expr = (b <= a); + break; + default: + ::warning("Logic::op_condJmp() invalid condition %d", (op & 7)); + break; + } + if (expr) { + op_jmp(); + } else { + _scriptPtr.fetchWord(); + } +} + +void Logic::op_setPalette() { + uint16 i = _scriptPtr.fetchWord(); + debug(DBG_LOGIC, "Logic::op_changePalette(%d)", i); + _vid->_newPal = i >> 8; +} + +void Logic::op_resetScript() { + uint8 j = _scriptPtr.fetchByte(); + uint8 i = _scriptPtr.fetchByte(); + int8 n = (i & 0x3F) - j; + if (n < 0) { + ::warning("Logic::op_resetScript() ec=0x%X (n < 0)", 0x880); + return; + } + ++n; + uint8 _al = _scriptPtr.fetchByte(); + + debug(DBG_LOGIC, "Logic::op_resetScript(%d, %d, %d)", j, i, _al); + + if (_al == 2) { + uint16 *_si = &_scriptPos[1][j]; + while (n--) { + *_si = 0xFFFE; + ++_si; + } + } else if (_al < 2) { + uint8 *_si = &_scriptPaused[1][j]; + while (n--) { + *_si = _al; + ++_si; + } + } +} + +void Logic::op_selectPage() { + uint8 i = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_selectPage(%d)", i); + _vid->changePagePtr1(i); +} + +void Logic::op_fillPage() { + uint8 screen = _scriptPtr.fetchByte(); + uint8 color = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_fillPage(%d, %d)", screen, color); + _vid->fillPage(screen, color); +} + +void Logic::op_copyPage() { + uint8 i = _scriptPtr.fetchByte(); + uint8 j = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_copyPage(%d, %d)", i, j); + _vid->copyPage(i, j, _scriptVars[VAR_SCROLL_Y]); +} + +void Logic::op_updateDisplay() { + uint8 page = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_updateDisplay(%d)", page); + inp_handleSpecialKeys(); + if (_res->_curPtrsId == 0x3E80 && _scriptVars[0x67] == 1) { + _scriptVar_0xBF = _scriptVars[0xBF]; + _scriptVars[0xDC] = 0x21; + } + + static uint32 tstamp = 0; + if (!_fastMode) { + // XXX experimental + int32 delay = _stub->getTimeStamp() - tstamp; + int32 pause = _scriptVars[VAR_PAUSE_SLICES] * 20 - delay; + if (pause > 0) { + _stub->sleep(pause); + } + } + _scriptVars[0xF7] = 0; + + _vid->updateDisplay(page); + tstamp = _stub->getTimeStamp(); +} + +void Logic::op_halt() { + debug(DBG_LOGIC, "Logic::op_halt()"); + _scriptPtr.pc = _res->_segCode + 0xFFFF; + _scriptHalted = true; +} + +void Logic::op_drawString() { + uint16 strId = _scriptPtr.fetchWord(); + uint16 x = _scriptPtr.fetchByte(); + uint16 y = _scriptPtr.fetchByte(); + uint16 col = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_drawString(0x%03X, %d, %d, %d)", strId, x, y, col); + _vid->drawString(col, x, y, strId); +} + +void Logic::op_sub() { + uint8 i = _scriptPtr.fetchByte(); + uint8 j = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_sub(0x%02X, 0x%02X)", i, j); + _scriptVars[i] -= _scriptVars[j]; +} + +void Logic::op_and() { + uint8 i = _scriptPtr.fetchByte(); + uint16 n = _scriptPtr.fetchWord(); + debug(DBG_LOGIC, "Logic::op_and(0x%02X, %d)", i, n); + _scriptVars[i] = (uint16)_scriptVars[i] & n; +} + +void Logic::op_or() { + uint8 i = _scriptPtr.fetchByte(); + uint16 n = _scriptPtr.fetchWord(); + debug(DBG_LOGIC, "Logic::op_or(0x%02X, %d)", i, n); + _scriptVars[i] = (uint16)_scriptVars[i] | n; +} + +void Logic::op_shl() { + uint8 i = _scriptPtr.fetchByte(); + uint16 n = _scriptPtr.fetchWord(); + debug(DBG_LOGIC, "Logic::op_shl(0x%02X, %d)", i, n); + _scriptVars[i] = (uint16)_scriptVars[i] << n; +} + +void Logic::op_shr() { + uint8 i = _scriptPtr.fetchByte(); + uint16 n = _scriptPtr.fetchWord(); + debug(DBG_LOGIC, "Logic::op_shr(0x%02X, %d)", i, n); + _scriptVars[i] = (uint16)_scriptVars[i] >> n; +} + +void Logic::op_soundUnk1() { + uint16 b = _scriptPtr.fetchWord(); + uint16 c = _scriptPtr.fetchWord(); + uint8 a = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_soundUnk1(0x%X, 0x%X, %d)", b, c, a); + // XXX +} + +void Logic::op_updateMemList() { + uint16 num = _scriptPtr.fetchWord(); + debug(DBG_LOGIC, "Logic::op_updateMemList(%d)", num); + _res->update(num); +} + +void Logic::op_soundUnk2() { + uint16 b = _scriptPtr.fetchWord(); + uint16 c = _scriptPtr.fetchWord(); + uint8 a = _scriptPtr.fetchByte(); + debug(DBG_LOGIC, "Logic::op_soundUnk2(0x%X, 0x%X, %d)", b, c, a); + // XXX +} + +void Logic::restartAt(uint16 ptrId) { + // XXX + _scriptVars[0xE4] = 0x14; + _res->setupPtrs(ptrId); + memset((uint8 *)_scriptPos, 0xFF, sizeof(_scriptPos)); + memset((uint8 *)_scriptPaused, 0, sizeof(_scriptPaused)); + _scriptPos[0][0] = 0; +} + +void Logic::setupScripts() { + if (_res->_newPtrsId != 0) { + restartAt(_res->_newPtrsId); + _res->_newPtrsId = 0; + } + for (int i = 0; i < 0x40; ++i) { + _scriptPaused[0][i] = _scriptPaused[1][i]; + uint16 n = _scriptPos[1][i]; + if (n != 0xFFFF) { + _scriptPos[0][i] = (n == 0xFFFE) ? 0xFFFF : n; + _scriptPos[1][i] = 0xFFFF; + } + } +} + +void Logic::runScripts() { + for (int i = 0; i < 0x40; ++i) { + if (_scriptPaused[0][i] == 0) { + uint16 n = _scriptPos[0][i]; + if (n != 0xFFFF) { + _scriptPtr.pc = _res->_segCode + n; + _stackPtr = 0; + _scriptHalted = false; + debug(DBG_LOGIC, "Logic::runScripts() i=0x%02X n=0x%02X *p=0x%02X", i, n, *_scriptPtr.pc); + executeScript(); + _scriptPos[0][i] = _scriptPtr.pc - _res->_segCode; + debug(DBG_LOGIC, "Logic::runScripts() i=0x%02X pos=0x%X", i, _scriptPos[0][i]); + if (_stub->_pi.quit) { + break; + } + } + } + } +} + +void Logic::executeScript() { + while (!_scriptHalted) { + uint8 opcode = _scriptPtr.fetchByte(); + if (opcode & 0x80) { + uint16 off = ((opcode << 8) | _scriptPtr.fetchByte()) * 2; + _res->_useSegVideo2 = false; + int16 x = _scriptPtr.fetchByte(); + int16 y = _scriptPtr.fetchByte(); + int16 h = y - 199; + if (h > 0) { + y = 199; + x += h; + } + debug(DBG_VIDEO, "vid_opcd_0x80 : opcode=0x%X off=0x%X x=%d y=%d", opcode, off, x, y); + _vid->setDataBuffer(_res->_segVideo1, off); + _vid->drawShape(0xFF, 0x40, Point(x,y)); + } else if (opcode & 0x40) { + int16 x, y; + uint16 off = _scriptPtr.fetchWord() * 2; + x = _scriptPtr.fetchByte(); + _res->_useSegVideo2 = false; + if (!(opcode & 0x20)) { + if (!(opcode & 0x10)) { + x = (x << 8) | _scriptPtr.fetchByte(); + } else { + x = _scriptVars[x]; + } + } else { + if (opcode & 0x10) { + x += 0x100; + } + } + y = _scriptPtr.fetchByte(); + if (!(opcode & 8)) { + if (!(opcode & 4)) { + y = (y << 8) | _scriptPtr.fetchByte(); + } else { + y = _scriptVars[y]; + } + } + uint16 zoom = _scriptPtr.fetchByte(); + if (!(opcode & 2)) { + if (!(opcode & 1)) { + --_scriptPtr.pc; + zoom = 0x40; + } else { + zoom = _scriptVars[zoom]; + } + } else { + if (opcode & 1) { + _res->_useSegVideo2 = true; + --_scriptPtr.pc; + zoom = 0x40; + } + } + debug(DBG_VIDEO, "vid_opcd_0x40 : off=0x%X x=%d y=%d", off, x, y); + _vid->setDataBuffer(_res->_useSegVideo2 ? _res->_segVideo2 : _res->_segVideo1, off); + _vid->drawShape(0xFF, zoom, Point(x, y)); + } else { + if (opcode > 0x1A) { + ::error("Logic::executeScript() ec=0x%X invalid opcode=0x%X", 0xFFF, opcode); + } else { + (this->*_opTable[opcode])(); + } + } + } +} + +void Logic::inp_updatePlayer() { + _stub->processEvents(); + if (_res->_curPtrsId == 0x3E89) { + char c = _stub->_pi.lastChar; + if (c == 8 || /*c == 0xD ||*/ c == 0 || (c >= 'a' && c <= 'z')) { + _scriptVars[VAR_LAST_KEYCHAR] = c & ~0x20; + _stub->_pi.lastChar = 0; + } + } + int16 lr = 0; + int16 m = 0; + int16 ud = 0; + if (_stub->_pi.dirMask & PlayerInput::DIR_RIGHT) { + lr = 1; + m |= 1; + } + if (_stub->_pi.dirMask & PlayerInput::DIR_LEFT) { + lr = -1; + m |= 2; + } + if (_stub->_pi.dirMask & PlayerInput::DIR_DOWN) { + ud = 1; + m |= 4; + } + _scriptVars[VAR_HERO_POS_UP_DOWN] = ud; + if (_stub->_pi.dirMask & PlayerInput::DIR_UP) { + _scriptVars[VAR_HERO_POS_UP_DOWN] = -1; + } + if (_stub->_pi.dirMask & PlayerInput::DIR_UP) { // inpJump + ud = -1; + m |= 8; + } + _scriptVars[VAR_HERO_POS_JUMP_DOWN] = ud; + _scriptVars[VAR_HERO_POS_LEFT_RIGHT] = lr; + _scriptVars[VAR_HERO_POS_MASK] = m; + int16 button = 0; + if (_stub->_pi.button) { // inpButton + button = 1; + m |= 0x80; + } + _scriptVars[VAR_HERO_ACTION] = button; + _scriptVars[VAR_HERO_ACTION_POS_MASK] = m; +} + +void Logic::inp_handleSpecialKeys() { + if (_stub->_pi.pause) { + if (_res->_curPtrsId != 0x3E80 && _res->_curPtrsId != 0x3E81) { + _stub->_pi.pause = false; + while (!_stub->_pi.pause) { + _stub->processEvents(); + _stub->sleep(200); + } + } + _stub->_pi.pause = false; + } + if (_stub->_pi.code) { + _stub->_pi.code = false; + if (_res->_curPtrsId != 0x3E89 && _res->_curPtrsId != 0x3E80) { + _res->_newPtrsId = 0x3E89; + } + } + // XXX + if (_scriptVars[0xC9] == 1) { + ::warning("Logic::inp_handleSpecialKeys() unhandled case (_scriptVars[0xC9] == 1)"); + } +} + +void Logic::saveOrLoad(Serializer &ser) { + Serializer::Entry entries[] = { + SE_ARRAY(_scriptVars, 0x100, Serializer::SES_INT16, VER(1)), + SE_ARRAY(_scriptStackCalls, 0x100, Serializer::SES_INT16, VER(1)), + SE_ARRAY(_scriptPos, 0x40 * 2, Serializer::SES_INT16, VER(1)), + SE_ARRAY(_scriptPaused, 0x40 * 2, Serializer::SES_INT8, VER(1)), + SE_END() + }; + ser.saveOrLoadEntries(entries); +} + +} diff --git a/awe/logic.h b/awe/logic.h new file mode 100644 index 0000000000..7763c5204d --- /dev/null +++ b/awe/logic.h @@ -0,0 +1,114 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __LOGIC_H__ +#define __LOGIC_H__ + +#include "stdafx.h" + +#include "intern.h" + +namespace Awe { + +struct Resource; +struct Serializer; +struct SystemStub; +struct Video; + +struct Logic { + typedef void (Logic::*OpcodeStub)(); + + enum ScriptVars { + VAR_RANDOM_SEED = 0x3C, + + VAR_LAST_KEYCHAR = 0xDA, + + VAR_HERO_POS_UP_DOWN = 0xE5, + + VAR_SCROLL_Y = 0xF9, + VAR_HERO_ACTION = 0xFA, + VAR_HERO_POS_JUMP_DOWN = 0xFB, + VAR_HERO_POS_LEFT_RIGHT = 0xFC, + VAR_HERO_POS_MASK = 0xFD, + VAR_HERO_ACTION_POS_MASK = 0xFE, + VAR_PAUSE_SLICES = 0xFF + }; + + static const OpcodeStub _opTable[]; + + Resource *_res; + Video *_vid; + SystemStub *_stub; + + int16 _scriptVar_0xBF; + int16 _scriptVars[0x100]; + uint16 _scriptStackCalls[0x40]; + uint16 _scriptPos[2][0x40]; + uint8 _scriptPaused[2][0x40]; + Ptr _scriptPtr; + uint8 _stackPtr; + bool _scriptHalted; + bool _fastMode; + + Logic(Resource *res, Video *vid, SystemStub *stub); + void init(); + + void op_movConst(); + void op_mov(); + void op_add(); + void op_addConst(); + void op_call(); + void op_ret(); + void op_break(); + void op_jmp(); + void op_setScriptPos(); + void op_jnz(); + void op_condJmp(); + void op_setPalette(); + void op_resetScript(); + void op_selectPage(); + void op_fillPage(); + void op_copyPage(); + void op_updateDisplay(); + void op_halt(); + void op_drawString(); + void op_sub(); + void op_and(); + void op_or(); + void op_shl(); + void op_shr(); + void op_soundUnk1(); + void op_updateMemList(); + void op_soundUnk2(); + + void restartAt(uint16 ptrId); + void setupPtrs(uint16 ptrId); + void setupScripts(); + void runScripts(); + void executeScript(); + + void inp_updatePlayer(); + void inp_handleSpecialKeys(); + + void saveOrLoad(Serializer &ser); +}; + +} + +#endif diff --git a/awe/module.mk b/awe/module.mk new file mode 100644 index 0000000000..c1ef6bdb4e --- /dev/null +++ b/awe/module.mk @@ -0,0 +1,25 @@ +MODULE := awe + +MODULE_OBJS = \ + awe/awe.o \ + awe/bank.o \ + awe/engine.o \ + awe/file.o \ + awe/logic.o \ + awe/resource.o \ + awe/sdlstub.o \ + awe/serializer.o \ + awe/staticres.o \ + awe/util.o \ + awe/video.o + +MODULE_DIRS += \ + awe + +# This module can be built as a plugin +ifdef BUILD_PLUGINS +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/common.rules diff --git a/awe/resource.cpp b/awe/resource.cpp new file mode 100644 index 0000000000..b5c621fcc6 --- /dev/null +++ b/awe/resource.cpp @@ -0,0 +1,277 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "stdafx.h" + +#include "awe.h" +#include "resource.h" +#include "bank.h" +#include "file.h" +#include "serializer.h" +#include "video.h" + +namespace Awe { + +Resource::Resource(Video *vid, const char *dataDir) + : _vid(vid), _dataDir(dataDir) { +} + +void Resource::readBank(const MemEntry *me, uint8 *dstBuf) { + uint16 n = me - _memList; + debug(DBG_BANK, "Resource::readBank(%d)", n); +#ifdef USE_UNPACKED + char bankEntryName[64]; + sprintf(bankEntryName, "ootw-%02X-%d.dump", n, me->type); + File f; + if (!f.open(bankEntryName, _dataDir)) { + ::error("Resource::readBank() unable to open '%s' file\n", bankEntryName); + } + f.read(dstBuf, me->unpackedSize); +#else + Bank bk(_dataDir); + if (!bk.read(me, dstBuf)) { + ::error("Resource::readBank() unable to unpack entry %d\n", n); + } +#endif +} + +void Resource::readEntries() { + File f; + if (!f.open("memlist.bin", _dataDir)) { + ::error("Resource::readEntries() unable to open 'memlist.bin' file\n"); + } + _numMemList = 0; + MemEntry *me = _memList; + while (1) { + assert(_numMemList < ARRAYSIZE(_memList)); + me->valid = f.readByte(); + me->type = f.readByte(); + me->bufPtr = 0; f.readUint16BE(); + me->unk4 = f.readUint16BE(); + me->rankNum = f.readByte(); + me->bankNum = f.readByte(); + me->bankPos = f.readUint32BE(); + me->unkC = f.readUint16BE(); + me->packedSize = f.readUint16BE(); + me->unk10 = f.readUint16BE(); + me->unpackedSize = f.readUint16BE(); + if (me->valid == 0xFF) { + break; + } + ++_numMemList; + ++me; + } +} + +void Resource::load() { + while (1) { + MemEntry *it = _memList; + MemEntry *me = 0; + + // get resource with max rankNum + uint8 maxNum = 0; + uint16 i = _numMemList; + while (i--) { + if (it->valid == 2 && maxNum <= it->rankNum) { + maxNum = it->rankNum; + me = it; + } + ++it; + } + if (me == 0) { + break; // no entry found + } + + uint8 *memPtr = 0; + // XXX if (_audio_no_sound != 0 && _audio_use_roland != 0 && me->type < 2) { + // XXX me->valid = 0; + // XXX continue; + // XXX } + if (me->type == 2) { + memPtr = _vidCurPtr; + } else { + memPtr = _scriptCurPtr; + if (me->unpackedSize > _vidBakPtr - _scriptCurPtr) { + ::warning("Resource::load() not enough memory"); + me->valid = 0; + continue; + } + } + if (me->bankNum == 0) { + ::warning("Resource::load() ec=0x%X (me->bankNum == 0)", 0xF00); + me->valid = 0; + } else { + debug(DBG_BANK, "Resource::load() bufPos=%X size=%X type=%X pos=%X bankNum=%X", memPtr - _memPtrStart, me->packedSize, me->type, me->bankPos, me->bankNum); + readBank(me, memPtr); + if(me->type == 2) { + _vid->copyPagePtr(_vidCurPtr); + me->valid = 0; + } else { + me->bufPtr = memPtr; + me->valid = 1; + _scriptCurPtr += me->unpackedSize; + } + } + } +} + +void Resource::invalidateRes() { + // XXX call ds:sound_stub_1_ptr + MemEntry *me = _memList; + uint16 i = _numMemList; + while (i--) { + if (me->type <= 2 || me->type > 6) { + me->valid = 0; + } + ++me; + } + _scriptCurPtr = _scriptBakPtr; +} + +void Resource::invalidateAll() { + MemEntry *me = _memList; + uint16 i = _numMemList; + while (i--) { + me->valid = 0; + ++me; + } + _scriptCurPtr = _memPtrStart; +} + +void Resource::update(uint16 num) { + if (num == 0) { + invalidateRes(); + } else { + if (num > _numMemList) { + _newPtrsId = num; + } else { + if (false) { // XXX (_audio_use_pro_or_adlib == 1 || _audio_use_spk == 1) { + for (const uint16 *ml = _memListAudio; *ml != 0xFFFF; ++ml) { + if (*ml == num) + return; + } + } + MemEntry *me = &_memList[num]; + if (me->valid == 0) { + me->valid = 2; + load(); + } + } + } +} + +void Resource::setupPtrs(uint16 ptrId) { + if (ptrId != _curPtrsId) { + uint8 ipal = 0; + uint8 icod = 0; + uint8 ivd1 = 0; + uint8 ivd2 = 0; + if (ptrId >= 0x3E80 && ptrId <= 0x3E89) { + uint16 part = ptrId - 0x3E80; + ipal = _memListParts[part][0]; + icod = _memListParts[part][1]; + ivd1 = _memListParts[part][2]; + ivd2 = _memListParts[part][3]; + } else { + ::error("Resource::setupPtrs() ec=0x%X invalid ptrId", 0xF07); + } + invalidateAll(); + _memList[ipal].valid = 2; + _memList[icod].valid = 2; + _memList[ivd1].valid = 2; + if (ivd2 != 0) { + _memList[ivd2].valid = 2; + } + load(); + _segVideoPal = _memList[ipal].bufPtr; + _segCode = _memList[icod].bufPtr; + _segVideo1 = _memList[ivd1].bufPtr; + if (ivd2 != 0) { + _segVideo2 = _memList[ivd2].bufPtr; + } + _curPtrsId = ptrId; + } + _scriptBakPtr = _scriptCurPtr; +} + +void Resource::allocMemBlock() { + _memPtrStart = (uint8 *)malloc(MEM_BLOCK_SIZE); + _scriptBakPtr = _scriptCurPtr = _memPtrStart; + _vidBakPtr = _vidCurPtr = _memPtrStart + MEM_BLOCK_SIZE - 0x800 * 16; + _useSegVideo2 = false; +} + +void Resource::freeMemBlock() { + free(_memPtrStart); +} + +void Resource::saveOrLoad(Serializer &ser) { + uint8 loadedList[64]; + if (ser._mode == Serializer::SM_SAVE) { + memset(loadedList, 0, sizeof(loadedList)); + uint8 *p = loadedList; + uint8 *q = _memPtrStart; + while (1) { + MemEntry *it = _memList; + MemEntry *me = 0; + uint16 num = _numMemList; + while (num--) { + if (it->valid == 1 && it->bufPtr == q) { + me = it; + } + ++it; + } + if (me == 0) { + break; + } else { + assert(p < loadedList + 64); + *p++ = me - _memList; + q += me->unpackedSize; + } + } + } + Serializer::Entry entries[] = { + SE_ARRAY(loadedList, 64, Serializer::SES_INT8, VER(1)), + SE_INT(&_curPtrsId, Serializer::SES_INT16, VER(1)), + SE_PTR(&_scriptBakPtr, VER(1)), + SE_PTR(&_scriptCurPtr, VER(1)), + SE_PTR(&_vidBakPtr, VER(1)), + SE_PTR(&_vidCurPtr, VER(1)), + SE_INT(&_useSegVideo2, Serializer::SES_INT8, VER(1)), + SE_PTR(&_segVideoPal, VER(1)), + SE_PTR(&_segCode, VER(1)), + SE_PTR(&_segVideo1, VER(1)), + SE_PTR(&_segVideo2, VER(1)), + SE_END() + }; + ser.saveOrLoadEntries(entries); + if (ser._mode == Serializer::SM_LOAD) { + uint8 *p = loadedList; + uint8 *q = _memPtrStart; + while (*p) { + MemEntry *me = &_memList[*p++]; + readBank(me, q); + me->bufPtr = q; + me->valid = 1; + q += me->unpackedSize; + } + } +} + +} diff --git a/awe/resource.h b/awe/resource.h new file mode 100644 index 0000000000..3b6f60a2d6 --- /dev/null +++ b/awe/resource.h @@ -0,0 +1,92 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __RESOURCE_H__ +#define __RESOURCE_H__ + +#include "stdafx.h" + +#include "intern.h" + +namespace Awe { + +struct MemEntry { + uint8 valid; // 0x0 + uint8 type; // 0x1, Resource::ResType + uint8 *bufPtr; // 0x2 + uint16 unk4; // 0x4, unused ? + uint8 rankNum; // 0x6 + uint8 bankNum; // 0x7 + uint32 bankPos; // 0x8 0xA + uint16 unkC; // 0xC, unused ? + uint16 packedSize; // 0xE + uint16 unk10; // 0x10, unused ? + uint16 unpackedSize; // 0x12 +}; + +struct Serializer; +struct Video; + +struct Resource { + enum ResType { + RT_SOUND = 0, + RT_MUSIC = 1, + RT_VIDBUF = 2, // full screen video buffer, size=0x7D00 + RT_PAL = 3, // palette (1024=vga + 1024=ega), size=2048 + RT_SCRIPT = 4, + RT_VBMP = 5 + }; + + enum { + MEM_BLOCK_SIZE = 600 * 1024 + }; + + static const uint16 _memListAudio[]; + static const uint16 _memListParts[][4]; + + Video *_vid; + const char *_dataDir; + MemEntry _memList[150]; + uint16 _numMemList; + uint16 _curPtrsId, _newPtrsId; + uint8 *_memPtrStart, *_scriptBakPtr, *_scriptCurPtr, *_vidBakPtr, *_vidCurPtr; + bool _useSegVideo2; + uint8 *_segVideoPal; + uint8 *_segCode; + uint8 *_segVideo1; + uint8 *_segVideo2; + + Resource(Video *vid, const char *dataDir); + + void readBank(const MemEntry *me, uint8 *dstBuf); + void readEntries(); + void load(); + void invalidateAll(); + void invalidateRes(); + void update(uint16 num); + void setupPtrs(uint16 ptrId); + void allocMemBlock(); + void freeMemBlock(); + + void saveOrLoad(Serializer &ser); +}; + +} + +#endif diff --git a/awe/sdlstub.cpp b/awe/sdlstub.cpp new file mode 100644 index 0000000000..79e468b1a9 --- /dev/null +++ b/awe/sdlstub.cpp @@ -0,0 +1,324 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "stdafx.h" +#include "common/util.h" + +#include + +#include "awe.h" +#include "systemstub.h" +#include "util.h" + +namespace Awe { + +struct SDLStub : SystemStub { + typedef void (SDLStub::*ScaleProc)(uint16 *dst, uint16 dstPitch, const uint16 *src, uint16 srcPitch, uint16 w, uint16 h); + + enum { + SCREEN_W = 320, + SCREEN_H = 200 + }; + + struct Scaler { + const char *name; + ScaleProc proc; + uint8 factor; + }; + + static const Scaler _scalers[]; + + uint8 *_offscreen; + SDL_Surface *_screen; + SDL_Surface *_sclscreen; + bool _fullscreen; + uint8 _scaler; + uint16 _pal[16]; + + virtual ~SDLStub() {} + virtual void init(const char *title); + virtual void destroy(); + virtual void setPalette(uint8 s, uint8 n, const uint8 *buf); + virtual void copyRect(uint16 x, uint16 y, uint16 w, uint16 h, const uint8 *buf, uint32 pitch); + virtual void processEvents(); + virtual void sleep(uint32 duration); + virtual uint32 getTimeStamp(); + + void prepareGfxMode(); + void cleanupGfxMode(); + void switchGfxMode(bool fullscreen, uint8 scaler); + + void point1x(uint16 *dst, uint16 dstPitch, const uint16 *src, uint16 srcPitch, uint16 w, uint16 h); + void point2x(uint16 *dst, uint16 dstPitch, const uint16 *src, uint16 srcPitch, uint16 w, uint16 h); + void point3x(uint16 *dst, uint16 dstPitch, const uint16 *src, uint16 srcPitch, uint16 w, uint16 h); +}; + +const SDLStub::Scaler SDLStub::_scalers[] = { + { "Point1x", &SDLStub::point1x, 1 }, + { "Point2x", &SDLStub::point2x, 2 }, + { "Point3x", &SDLStub::point3x, 3 } +}; + +SystemStub *SystemStub_SDL_create() { + return new SDLStub(); +} + +void SDLStub::init(const char *title) { + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER); + SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); + SDL_ShowCursor(SDL_DISABLE); + SDL_WM_SetCaption(title, NULL); + memset(&_pi, 0, sizeof(_pi)); + _offscreen = (uint8 *)malloc(SCREEN_W * SCREEN_H * 2); + if (!_offscreen) { + ::error("Unable to allocate offscreen buffer"); + } + _fullscreen = false; + _scaler = 1; + prepareGfxMode(); +} + +void SDLStub::destroy() { + cleanupGfxMode(); +} + +void SDLStub::setPalette(uint8 s, uint8 n, const uint8 *buf) { + assert(s + n <= 16); + for (int i = s; i < s + n; ++i) { + uint8 c[3]; + for (int j = 0; j < 3; ++j) { + uint8 col = buf[i * 3 + j]; + c[j] = (col << 2) | (col & 3); + } + _pal[i] = SDL_MapRGB(_screen->format, c[0], c[1], c[2]); + } +} + +void SDLStub::copyRect(uint16 x, uint16 y, uint16 w, uint16 h, const uint8 *buf, uint32 pitch) { + buf += y * pitch + x; + uint16 *p = (uint16 *)_offscreen; + while (h--) { + for (int i = 0; i < w / 2; ++i) { + uint8 p1 = *(buf + i) >> 4; + uint8 p2 = *(buf + i) & 0xF; + *(p + i * 2 + 0) = _pal[p1]; + *(p + i * 2 + 1) = _pal[p2]; + } + p += SCREEN_W; + buf += pitch; + } + SDL_LockSurface(_sclscreen); + (this->*_scalers[_scaler].proc)((uint16 *)_sclscreen->pixels, _sclscreen->pitch, (uint16 *)_offscreen, SCREEN_W, SCREEN_W, SCREEN_H); + SDL_UnlockSurface(_sclscreen); + SDL_BlitSurface(_sclscreen, NULL, _screen, NULL); + SDL_UpdateRect(_screen, 0, 0, 0, 0); +} + +void SDLStub::processEvents() { + SDL_Event ev; + while(SDL_PollEvent(&ev)) { + switch (ev.type) { + case SDL_QUIT: + exit(0); + break; + case SDL_KEYUP: + switch(ev.key.keysym.sym) { + case SDLK_LEFT: + _pi.dirMask &= ~PlayerInput::DIR_LEFT; + break; + case SDLK_RIGHT: + _pi.dirMask &= ~PlayerInput::DIR_RIGHT; + break; + case SDLK_UP: + _pi.dirMask &= ~PlayerInput::DIR_UP; + break; + case SDLK_DOWN: + _pi.dirMask &= ~PlayerInput::DIR_DOWN; + break; + case SDLK_SPACE: + case SDLK_RETURN: + _pi.button = false; + break; + default: + break; + } + break; + case SDL_KEYDOWN: + if (ev.key.keysym.mod & KMOD_ALT) { + if (ev.key.keysym.sym == SDLK_RETURN) { + switchGfxMode(!_fullscreen, _scaler); + } else if (ev.key.keysym.sym == SDLK_KP_PLUS) { + uint8 s = _scaler + 1; + if (s < ARRAYSIZE(_scalers)) { + switchGfxMode(_fullscreen, s); + } + } else if (ev.key.keysym.sym == SDLK_KP_MINUS) { + int8 s = _scaler - 1; + if (_scaler > 0) { + switchGfxMode(_fullscreen, s); + } + } else if (ev.key.keysym.sym == SDLK_x) { + _pi.quit = true; + } + break; + } else if (ev.key.keysym.mod & KMOD_CTRL) { + if (ev.key.keysym.sym == SDLK_s) { + _pi.save = true; + } else if (ev.key.keysym.sym == SDLK_l) { + _pi.load = true; + } else if (ev.key.keysym.sym == SDLK_f) { + _pi.fastMode = true; + } else if (ev.key.keysym.sym == SDLK_KP_PLUS) { + _pi.stateSlot = 1; + } else if (ev.key.keysym.sym == SDLK_KP_MINUS) { + _pi.stateSlot = -1; + } + break; + } + _pi.lastChar = ev.key.keysym.sym; + switch(ev.key.keysym.sym) { + case SDLK_LEFT: + _pi.dirMask |= PlayerInput::DIR_LEFT; + break; + case SDLK_RIGHT: + _pi.dirMask |= PlayerInput::DIR_RIGHT; + break; + case SDLK_UP: + _pi.dirMask |= PlayerInput::DIR_UP; + break; + case SDLK_DOWN: + _pi.dirMask |= PlayerInput::DIR_DOWN; + break; + case SDLK_SPACE: + case SDLK_RETURN: + _pi.button = true; + break; + case SDLK_c: + _pi.code = true; + break; + case SDLK_p: + _pi.pause = true; + break; + default: + break; + } + break; + default: + break; + } + } +} + +void SDLStub::sleep(uint32 duration) { + SDL_Delay(duration); +} + +uint32 SDLStub::getTimeStamp() { + return SDL_GetTicks(); +} + +void SDLStub::prepareGfxMode() { + int w = SCREEN_W * _scalers[_scaler].factor; + int h = SCREEN_H * _scalers[_scaler].factor; + _screen = SDL_SetVideoMode(w, h, 16, _fullscreen ? (SDL_FULLSCREEN | SDL_HWSURFACE) : SDL_HWSURFACE); + if (!_screen) { + ::error("SDLStub::prepareGfxMode() unable to allocate _screen buffer"); + } + _sclscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 16, + _screen->format->Rmask, + _screen->format->Gmask, + _screen->format->Bmask, + _screen->format->Amask); + if (!_sclscreen) { + ::error("SDLStub::prepareGfxMode() unable to allocate _sclscreen buffer"); + } +} + +void SDLStub::cleanupGfxMode() { + if (_offscreen) { + free(_offscreen); + _offscreen = 0; + } + if (_sclscreen) { + SDL_FreeSurface(_sclscreen); + _sclscreen = 0; + } + if (_screen) { + SDL_FreeSurface(_screen); + _screen = 0; + } +} + +void SDLStub::switchGfxMode(bool fullscreen, uint8 scaler) { + SDL_Surface *prev_sclscreen = _sclscreen; + SDL_FreeSurface(_screen); + _fullscreen = fullscreen; + _scaler = scaler; + prepareGfxMode(); + SDL_BlitSurface(prev_sclscreen, NULL, _sclscreen, NULL); + SDL_FreeSurface(prev_sclscreen); +} + +void SDLStub::point1x(uint16 *dst, uint16 dstPitch, const uint16 *src, uint16 srcPitch, uint16 w, uint16 h) { + dstPitch >>= 1; + while (h--) { + memcpy(dst, src, w * 2); + dst += dstPitch; + src += dstPitch; + } +} + +void SDLStub::point2x(uint16 *dst, uint16 dstPitch, const uint16 *src, uint16 srcPitch, uint16 w, uint16 h) { + dstPitch >>= 1; + while (h--) { + uint16 *p = dst; + for (int i = 0; i < w; ++i, p += 2) { + uint16 c = *(src + i); + *(p + 0) = c; + *(p + 1) = c; + *(p + 0 + dstPitch) = c; + *(p + 1 + dstPitch) = c; + } + dst += dstPitch * 2; + src += srcPitch; + } +} + +void SDLStub::point3x(uint16 *dst, uint16 dstPitch, const uint16 *src, uint16 srcPitch, uint16 w, uint16 h) { + dstPitch >>= 1; + while (h--) { + uint16 *p = dst; + for (int i = 0; i < w; ++i, p += 3) { + uint16 c = *(src + i); + *(p + 0) = c; + *(p + 1) = c; + *(p + 2) = c; + *(p + 0 + dstPitch) = c; + *(p + 1 + dstPitch) = c; + *(p + 2 + dstPitch) = c; + *(p + 0 + dstPitch * 2) = c; + *(p + 1 + dstPitch * 2) = c; + *(p + 2 + dstPitch * 2) = c; + } + dst += dstPitch * 3; + src += srcPitch; + } +} + +} diff --git a/awe/serializer.cpp b/awe/serializer.cpp new file mode 100644 index 0000000000..aec79d6995 --- /dev/null +++ b/awe/serializer.cpp @@ -0,0 +1,127 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "stdafx.h" + +#include "serializer.h" +#include "file.h" +#include "util.h" + +namespace Awe { + +Serializer::Serializer(File *stream, Mode mode, uint8 *ptrBlock, uint16 saveVer) + : _stream(stream), _mode(mode), _ptrBlock(ptrBlock), _saveVer(saveVer) { +} + +void Serializer::saveOrLoadEntries(Entry *entry) { + switch (_mode) { + case SM_SAVE: + saveEntries(entry); + break; + case SM_LOAD: + loadEntries(entry); + break; + } +} + +void Serializer::saveEntries(Entry *entry) { + for (; entry->type != SET_END; ++entry) { + if (entry->maxVer == CUR_VER) { + switch (entry->type) { + case SET_INT: + saveInt(entry->size, entry->data); + break; + case SET_ARRAY: + if (entry->size == Serializer::SES_INT8) { + _stream->write(entry->data, entry->n); + } else { + uint8 *p = (uint8 *)entry->data; + for (int i = 0; i < entry->n; ++i) { + saveInt(entry->size, p); + p += entry->size; + } + } + break; + case SET_PTR: + _stream->writeUint32BE(*(uint8 **)(entry->data) - _ptrBlock); + break; + case SET_END: + break; + } + } + } +} + +void Serializer::loadEntries(Entry *entry) { + for (; entry->type != SET_END; ++entry) { + if (_saveVer >= entry->minVer && _saveVer <= entry->maxVer) { + switch (entry->type) { + case SET_INT: + loadInt(entry->size, entry->data); + break; + case SET_ARRAY: + if (entry->size == Serializer::SES_INT8) { + _stream->read(entry->data, entry->n); + } else { + uint8 *p = (uint8 *)entry->data; + for (int i = 0; i < entry->n; ++i) { + loadInt(entry->size, p); + p += entry->size; + } + } + break; + case SET_PTR: + *(uint8 **)(entry->data) = _ptrBlock + _stream->readUint32BE(); + break; + case SET_END: + break; + } + } + } +} + +void Serializer::saveInt(uint8 es, void *p) { + switch (es) { + case SES_INT8: + _stream->writeByte(*(uint8 *)p); + break; + case SES_INT16: + _stream->writeUint16BE(*(uint16 *)p); + break; + case SES_INT32: + _stream->writeUint32BE(*(uint32 *)p); + break; + } +} + +void Serializer::loadInt(uint8 es, void *p) { + switch (es) { + case SES_INT8: + *(uint8 *)p = _stream->readByte(); + break; + case SES_INT16: + *(uint16 *)p = _stream->readUint16BE(); + break; + case SES_INT32: + *(uint32 *)p = _stream->readUint32BE(); + break; + } +} + +} diff --git a/awe/serializer.h b/awe/serializer.h new file mode 100644 index 0000000000..9547c3b099 --- /dev/null +++ b/awe/serializer.h @@ -0,0 +1,88 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __SERIALIZER_H__ +#define __SERIALIZER_H__ + +#include "stdafx.h" + +#include "intern.h" + +namespace Awe { + +#define VER(x) x + +#define SE_INT(i,sz,ver) { Serializer::SET_INT, sz, 1, i, ver, Serializer::CUR_VER } +#define SE_ARRAY(a,n,sz,ver) { Serializer::SET_ARRAY, sz, n, a, ver, Serializer::CUR_VER } +#define SE_PTR(p,ver) { Serializer::SET_PTR, 0, 0, p, ver, Serializer::CUR_VER } +#define SE_END() { Serializer::SET_END, 0, 0, 0, 0, 0 } + +struct File; + +struct Serializer { + enum { + CUR_VER = 1 + }; + + enum EntryType { + SET_INT, + SET_ARRAY, + SET_PTR, + SET_END + }; + + enum { + SES_INT8 = 1, + SES_INT16 = 2, + SES_INT32 = 4 + }; + + enum Mode { + SM_SAVE, + SM_LOAD + }; + + struct Entry { + EntryType type; + uint8 size; + uint16 n; + void *data; + uint16 minVer; + uint16 maxVer; + }; + + File *_stream; + Mode _mode; + uint8 *_ptrBlock; + uint16 _saveVer; + + Serializer(File *stream, Mode mode, uint8 *ptrBlock, uint16 saveVer = CUR_VER); + + void saveOrLoadEntries(Entry *entry); + + void saveEntries(Entry *entry); + void loadEntries(Entry *entry); + + void saveInt(uint8 es, void *p); + void loadInt(uint8 es, void *p); +}; + +} + +#endif diff --git a/awe/staticres.cpp b/awe/staticres.cpp new file mode 100644 index 0000000000..686da2ebd6 --- /dev/null +++ b/awe/staticres.cpp @@ -0,0 +1,403 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "stdafx.h" + +#include "logic.h" +#include "resource.h" +#include "video.h" + +namespace Awe { + +const Logic::OpcodeStub Logic::_opTable[] = { + /* 0x00 */ + &Logic::op_movConst, + &Logic::op_mov, + &Logic::op_add, + &Logic::op_addConst, + /* 0x04 */ + &Logic::op_call, + &Logic::op_ret, + &Logic::op_break, + &Logic::op_jmp, + /* 0x08 */ + &Logic::op_setScriptPos, + &Logic::op_jnz, + &Logic::op_condJmp, + &Logic::op_setPalette, + /* 0x0C */ + &Logic::op_resetScript, + &Logic::op_selectPage, + &Logic::op_fillPage, + &Logic::op_copyPage, + /* 0x10 */ + &Logic::op_updateDisplay, + &Logic::op_halt, + &Logic::op_drawString, + &Logic::op_sub, + /* 0x14 */ + &Logic::op_and, + &Logic::op_or, + &Logic::op_shl, + &Logic::op_shr, + /* 0x18 */ + &Logic::op_soundUnk1, + &Logic::op_updateMemList, + &Logic::op_soundUnk2 +}; + +const uint16 Resource::_memListAudio[] = { + 8, 0x10, 0x61, 0x66, 0xFFFF +}; + +const uint16 Resource::_memListParts[][4] = { + { 0x14, 0x15, 0x16, 0x00 }, // protection screens + { 0x17, 0x18, 0x19, 0x00 }, // introduction + { 0x1A, 0x1B, 0x1C, 0x11 }, + { 0x1D, 0x1E, 0x1F, 0x11 }, + { 0x20, 0x21, 0x22, 0x11 }, + { 0x23, 0x24, 0x25, 0x00 }, + { 0x26, 0x27, 0x28, 0x11 }, + { 0x29, 0x2A, 0x2B, 0x11 }, + { 0x7D, 0x7E, 0x7F, 0x00 }, + { 0x7D, 0x7E, 0x7F, 0x00 } // password screen +}; + +const uint8 Video::_font[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, + 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x7E, 0x24, 0x24, 0x7E, 0x24, 0x00, + 0x08, 0x3E, 0x48, 0x3C, 0x12, 0x7C, 0x10, 0x00, 0x42, 0xA4, 0x48, 0x10, 0x24, 0x4A, 0x84, 0x00, + 0x60, 0x90, 0x90, 0x70, 0x8A, 0x84, 0x7A, 0x00, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x08, 0x10, 0x10, 0x10, 0x08, 0x06, 0x00, 0xC0, 0x20, 0x10, 0x10, 0x10, 0x20, 0xC0, 0x00, + 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0x10, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, + 0x78, 0x84, 0x8C, 0x94, 0xA4, 0xC4, 0x78, 0x00, 0x10, 0x30, 0x50, 0x10, 0x10, 0x10, 0x7C, 0x00, + 0x78, 0x84, 0x04, 0x08, 0x30, 0x40, 0xFC, 0x00, 0x78, 0x84, 0x04, 0x38, 0x04, 0x84, 0x78, 0x00, + 0x08, 0x18, 0x28, 0x48, 0xFC, 0x08, 0x08, 0x00, 0xFC, 0x80, 0xF8, 0x04, 0x04, 0x84, 0x78, 0x00, + 0x38, 0x40, 0x80, 0xF8, 0x84, 0x84, 0x78, 0x00, 0xFC, 0x04, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, + 0x78, 0x84, 0x84, 0x78, 0x84, 0x84, 0x78, 0x00, 0x78, 0x84, 0x84, 0x7C, 0x04, 0x08, 0x70, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x10, 0x10, 0x60, + 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, + 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, 0x7C, 0x82, 0x02, 0x0C, 0x10, 0x00, 0x10, 0x00, + 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x78, 0x84, 0x84, 0xFC, 0x84, 0x84, 0x84, 0x00, + 0xF8, 0x84, 0x84, 0xF8, 0x84, 0x84, 0xF8, 0x00, 0x78, 0x84, 0x80, 0x80, 0x80, 0x84, 0x78, 0x00, + 0xF8, 0x84, 0x84, 0x84, 0x84, 0x84, 0xF8, 0x00, 0x7C, 0x40, 0x40, 0x78, 0x40, 0x40, 0x7C, 0x00, + 0xFC, 0x80, 0x80, 0xF0, 0x80, 0x80, 0x80, 0x00, 0x7C, 0x80, 0x80, 0x8C, 0x84, 0x84, 0x7C, 0x00, + 0x84, 0x84, 0x84, 0xFC, 0x84, 0x84, 0x84, 0x00, 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7C, 0x00, + 0x04, 0x04, 0x04, 0x04, 0x84, 0x84, 0x78, 0x00, 0x8C, 0x90, 0xA0, 0xE0, 0x90, 0x88, 0x84, 0x00, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xFC, 0x00, 0x82, 0xC6, 0xAA, 0x92, 0x82, 0x82, 0x82, 0x00, + 0x84, 0xC4, 0xA4, 0x94, 0x8C, 0x84, 0x84, 0x00, 0x78, 0x84, 0x84, 0x84, 0x84, 0x84, 0x78, 0x00, + 0xF8, 0x84, 0x84, 0xF8, 0x80, 0x80, 0x80, 0x00, 0x78, 0x84, 0x84, 0x84, 0x84, 0x8C, 0x7C, 0x03, + 0xF8, 0x84, 0x84, 0xF8, 0x90, 0x88, 0x84, 0x00, 0x78, 0x84, 0x80, 0x78, 0x04, 0x84, 0x78, 0x00, + 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x78, 0x00, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x48, 0x30, 0x00, 0x82, 0x82, 0x82, 0x82, 0x92, 0xAA, 0xC6, 0x00, + 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x00, 0x82, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x00, + 0xFC, 0x04, 0x08, 0x10, 0x20, 0x40, 0xFC, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, + 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, + 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, + 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00, + 0x40, 0x40, 0x78, 0x44, 0x44, 0x44, 0x78, 0x00, 0x00, 0x00, 0x3C, 0x40, 0x40, 0x40, 0x3C, 0x00, + 0x04, 0x04, 0x3C, 0x44, 0x44, 0x44, 0x3C, 0x00, 0x00, 0x00, 0x38, 0x44, 0x7C, 0x40, 0x3C, 0x00, + 0x38, 0x44, 0x40, 0x60, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x3C, 0x44, 0x44, 0x3C, 0x04, 0x78, + 0x40, 0x40, 0x58, 0x64, 0x44, 0x44, 0x44, 0x00, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, + 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x42, 0x3C, 0x40, 0x40, 0x46, 0x48, 0x70, 0x48, 0x46, 0x00, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0xEC, 0x92, 0x92, 0x92, 0x92, 0x00, + 0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, + 0x00, 0x00, 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x00, 0x00, 0x3C, 0x44, 0x44, 0x3C, 0x04, 0x04, + 0x00, 0x00, 0x4C, 0x70, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x3C, 0x40, 0x38, 0x04, 0x78, 0x00, + 0x10, 0x10, 0x3C, 0x10, 0x10, 0x10, 0x0C, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x78, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, 0x00, 0x00, 0x82, 0x82, 0x92, 0xAA, 0xC6, 0x00, + 0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x42, 0x22, 0x24, 0x18, 0x08, 0x30, + 0x00, 0x00, 0x7C, 0x08, 0x10, 0x20, 0x7C, 0x00, 0x60, 0x90, 0x20, 0x40, 0xF0, 0x00, 0x00, 0x00, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x38, 0x44, 0xBA, 0xA2, 0xBA, 0x44, 0x38, 0x00, + 0x38, 0x44, 0x82, 0x82, 0x44, 0x28, 0xEE, 0x00, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA +}; + +const StrEntry Video::_stringsTableEng[] = { + { 0x001, "P E A N U T 3000" }, + { 0x002, "Copyright } 1990 Peanut Computer, Inc.\nAll rights reserved.\n\nCDOS Version 5.01" }, + { 0x003, "2" }, + { 0x004, "3" }, + { 0x005, "." }, + { 0x006, "A" }, + { 0x007, "@" }, + { 0x008, "PEANUT 3000" }, + { 0x00A, "R" }, + { 0x00B, "U" }, + { 0x00C, "N" }, + { 0x00D, "P" }, + { 0x00E, "R" }, + { 0x00F, "O" }, + { 0x010, "J" }, + { 0x011, "E" }, + { 0x012, "C" }, + { 0x013, "T" }, + { 0x014, "Shield 9A.5f Ok" }, + { 0x015, "Flux % 5.0177 Ok" }, + { 0x016, "CDI Vector ok" }, + { 0x017, " %%%ddd ok" }, + { 0x018, "Race-Track ok" }, + { 0x019, "SYNCHROTRON" }, + { 0x01A, "E: 23%\ng: .005\n\nRK: 77.2L\n\nopt: g+\n\n Shield:\n1: OFF\n2: ON\n3: ON\n\nP~: 1\n" }, + { 0x01B, "ON" }, + { 0x01C, "-" }, + { 0x021, "|" }, + { 0x022, "--- Theoretical study ---" }, + { 0x023, " THE EXPERIMENT WILL BEGIN IN SECONDS" }, + { 0x024, " 20" }, + { 0x025, " 19" }, + { 0x026, " 18" }, + { 0x027, " 4" }, + { 0x028, " 3" }, + { 0x029, " 2" }, + { 0x02A, " 1" }, + { 0x02B, " 0" }, + { 0x02C, "L E T ' S G O" }, + { 0x031, "- Phase 0:\nINJECTION of particles\ninto synchrotron" }, + { 0x032, "- Phase 1:\nParticle ACCELERATION." }, + { 0x033, "- Phase 2:\nEJECTION of particles\non the shield." }, + { 0x034, "A N A L Y S I S" }, + { 0x035, "- RESULT:\nProbability of creating:\n ANTIMATTER: 91.V %\n NEUTRINO 27: 0.04 %\n NEUTRINO 424: 18 %\n" }, + { 0x036, " Practical verification Y/N ?" }, + { 0x037, "SURE ?" }, + { 0x038, "MODIFICATION OF PARAMETERS\nRELATING TO PARTICLE\nACCELERATOR (SYNCHROTRON)." }, + { 0x039, " RUN EXPERIMENT ?" }, + { 0x03C, "t---t" }, + { 0x03D, "000 ~" }, + { 0x03E, ".20x14dd" }, + { 0x03F, "gj5r5r" }, + { 0x040, "tilgor 25%" }, + { 0x041, "12% 33% checked" }, + { 0x042, "D=4.2158005584" }, + { 0x043, "d=10.00001" }, + { 0x044, "+" }, + { 0x045, "*" }, + { 0x046, "% 304" }, + { 0x047, "gurgle 21" }, + { 0x048, "{{{{" }, + { 0x049, "Delphine Software" }, + { 0x04A, "By Eric Chahi" }, + { 0x04B, " 5" }, + { 0x04C, " 17" }, + { 0x12C, "0" }, + { 0x12D, "1" }, + { 0x12E, "2" }, + { 0x12F, "3" }, + { 0x130, "4" }, + { 0x131, "5" }, + { 0x132, "6" }, + { 0x133, "7" }, + { 0x134, "8" }, + { 0x135, "9" }, + { 0x136, "A" }, + { 0x137, "B" }, + { 0x138, "C" }, + { 0x139, "D" }, + { 0x13A, "E" }, + { 0x13B, "F" }, + { 0x13C, " ACCESS CODE:" }, + { 0x13D, "PRESS BUTTON OR RETURN TO CONTINUE" }, + { 0x13E, " ENTER ACCESS CODE" }, + { 0x13F, " INVALID PASSWORD !" }, + { 0x140, "ANNULER" }, + { 0x141, " INSERT DISK ?\n\n\n\n\n\n\n\n\nPRESS ANY KEY TO CONTINUE" }, + { 0x142, " SELECT SYMBOLS CORRESPONDING TO\n THE POSITION\n ON THE CODE WHEEL" }, + { 0x143, " LOADING..." }, + { 0x144, " ERROR" }, + { 0x15E, "LDKD" }, + { 0x15F, "HTDC" }, + { 0x160, "CLLD" }, + { 0x161, "FXLC" }, + { 0x162, "KRFK" }, + { 0x163, "XDDJ" }, + { 0x164, "LBKG" }, + { 0x165, "KLFB" }, + { 0x166, "TTCT" }, + { 0x167, "DDRX" }, + { 0x168, "TBHK" }, + { 0x169, "BRTD" }, + { 0x16A, "CKJL" }, + { 0x16B, "LFCK" }, + { 0x16C, "BFLX" }, + { 0x16D, "XJRT" }, + { 0x16E, "HRTB" }, + { 0x16F, "HBHK" }, + { 0x170, "JCGB" }, + { 0x171, "HHFL" }, + { 0x172, "TFBB" }, + { 0x173, "TXHF" }, + { 0x174, "JHJL" }, + { 0x181, " BY" }, + { 0x182, "ERIC CHAHI" }, + { 0x183, " MUSIC AND SOUND EFFECTS" }, + { 0x184, " " }, + { 0x185, "JEAN-FRANCOIS FREITAS" }, + { 0x186, "IBM PC VERSION" }, + { 0x187, " BY" }, + { 0x188, " DANIEL MORAIS" }, + { 0x18B, " THEN PRESS FIRE" }, + { 0x18C, " PUT THE PADDLE ON THE UPPER LEFT CORNER" }, + { 0x18D, "PUT THE PADDLE IN CENTRAL POSITION" }, + { 0x18E, "PUT THE PADDLE ON THE LOWER RIGHT CORNER" }, + { 0x258, " Designed by ..... Eric Chahi" }, + { 0x259, " Programmed by...... Eric Chahi" }, + { 0x25A, " Artwork ......... Eric Chahi" }, + { 0x25B, "Music by ........ Jean-francois Freitas" }, + { 0x25C, " Sound effects" }, + { 0x25D, " Jean-Francois Freitas\n Eric Chahi" }, + { 0x263, " Thanks To" }, + { 0x264, " Jesus Martinez\n\n Daniel Morais\n\n Frederic Savoir\n\n Cecile Chahi\n\n Philippe Delamarre\n\n Philippe Ulrich\n\nSebastien Berthet\n\nPierre Gousseau" }, + { 0x265, "Now Go Out Of This World" }, + { 0x190, "Good evening professor." }, + { 0x191, "I see you have driven here in your\nFerrari." }, + { 0x192, "IDENTIFICATION" }, + { 0x193, "Monsieur est en parfaite sante." }, + { 0x194, "Y\n" }, + { 0x193, "AU BOULOT !!!\n" }, + { 0xFFFF, "" } +}; + +const StrEntry Video::_stringsTableDemo[] = { + { 0x001, "P E A N U T 3000" }, + { 0x002, "Copyright } 1990 Peanut Computer, Inc.\nAll rights reserved.\n\nCDOS Version 5.01" }, + { 0x003, "2" }, + { 0x004, "3" }, + { 0x005, "." }, + { 0x006, "A" }, + { 0x007, "@" }, + { 0x008, "PEANUT 3000" }, + { 0x00A, "R" }, + { 0x00B, "U" }, + { 0x00C, "N" }, + { 0x00D, "P" }, + { 0x00E, "R" }, + { 0x00F, "O" }, + { 0x010, "J" }, + { 0x011, "E" }, + { 0x012, "C" }, + { 0x013, "T" }, + { 0x014, "Shield 9A.5f Ok" }, + { 0x015, "Flux % 5.0177 Ok" }, + { 0x016, "CDI Vector ok" }, + { 0x017, " %%%ddd ok" }, + { 0x018, "Race-Track ok" }, + { 0x019, "SYNCHROTRON" }, + { 0x01A, "E: 23%\ng: .005\n\nRK: 77.2L\n\nopt: g+\n\n Shield:\n1: OFF\n2: ON\n3: ON\n\nP~: 1\n" }, + { 0x01B, "ON" }, + { 0x01C, "-" }, + { 0x021, "|" }, + { 0x022, "--- Theoretical study ---" }, + { 0x023, " THE EXPERIMENT WILL BEGIN IN SECONDS" }, + { 0x024, " 20" }, + { 0x025, " 19" }, + { 0x026, " 18" }, + { 0x027, " 4" }, + { 0x028, " 3" }, + { 0x029, " 2" }, + { 0x02A, " 1" }, + { 0x02B, " 0" }, + { 0x02C, "L E T ' S G O" }, + { 0x031, "- Phase 0:\nINJECTION of particles\ninto synchrotron" }, + { 0x032, "- Phase 1:\nParticle ACCELERATION." }, + { 0x033, "- Phase 2:\nEJECTION of particles\non the shield." }, + { 0x034, "A N A L Y S I S" }, + { 0x035, "- RESULT:\nProbability of creating:\n ANTIMATTER: 91.V %\n NEUTRINO 27: 0.04 %\n NEUTRINO 424: 18 %\n" }, + { 0x036, " Practical verification Y/N ?" }, + { 0x037, "SURE ?" }, + { 0x038, "MODIFICATION OF PARAMETERS\nRELATING TO PARTICLE\nACCELERATOR (SYNCHROTRON)." }, + { 0x039, " RUN EXPERIMENT ?" }, + { 0x03C, "t---t" }, + { 0x03D, "000 ~" }, + { 0x03E, ".20x14dd" }, + { 0x03F, "gj5r5r" }, + { 0x040, "tilgor 25%" }, + { 0x041, "12% 33% checked" }, + { 0x042, "D=4.2158005584" }, + { 0x043, "d=10.00001" }, + { 0x044, "+" }, + { 0x045, "*" }, + { 0x046, "% 304" }, + { 0x047, "gurgle 21" }, + { 0x048, "{{{{" }, + { 0x049, "Delphine Software" }, + { 0x04A, "By Eric Chahi" }, + { 0x04B, " 5" }, + { 0x04C, " 17" }, + { 0x12C, "0" }, + { 0x12D, "1" }, + { 0x12E, "2" }, + { 0x12F, "3" }, + { 0x130, "4" }, + { 0x131, "5" }, + { 0x132, "6" }, + { 0x133, "7" }, + { 0x134, "8" }, + { 0x135, "9" }, + { 0x136, "A" }, + { 0x137, "B" }, + { 0x138, "C" }, + { 0x139, "D" }, + { 0x13A, "E" }, + { 0x13B, "F" }, + { 0x13D, "PRESS BUTTON OR RETURN TO CONTINUE" }, + { 0x13E, " ENTER ACCESS CODE" }, + { 0x13F, " INVALID PASSWORD !" }, + { 0x140, "ANNULER" }, + { 0x141, " INSERT DISK ?" }, + { 0x142, " SELECT SYMBOLS CORRESPONDING TO\n THE POSITION\n ON THE CODE WHEEL" }, + { 0x143, " LOADING..." }, + { 0x144, " ERROR" }, + { 0x181, " BY" }, + { 0x182, "ERIC CHAHI" }, + { 0x183, " MUSIC AND SOUND EFFECTS" }, + { 0x184, " " }, + { 0x185, "JEAN-FRANCOIS FREITAS" }, + { 0x186, "IBM PC VERSION" }, + { 0x187, " BY" }, + { 0x188, " DANIEL MORAIS" }, + { 0x18B, " THEN PRESS FIRE" }, + { 0x18C, " PUT THE PADDLE ON THE UPPER LEFT CORNER" }, + { 0x18D, "PUT THE PADDLE IN CENTRAL POSITION" }, + { 0x18E, "PUT THE PADDLE ON THE LOWER RIGHT CORNER" }, + { 0x1F4, "Over Two Years in the Making" }, + { 0x1F5, " A New, State\nof the Art, Polygon\n Graphics System" }, + { 0x1F6, " Comes to the\nComputer With Full\n Screen Graphics" }, + { 0x1F7, "While conducting a nuclear fission\nexperiment at your local\nparticle accelerator ..." }, + { 0x1F8, "Nature decides to put a little\n extra spin on the ball" }, + { 0x1F9, "And sends you ..." }, + { 0x1FA, " Out of this World\nA Cinematic Action Adventure\n Coming soon to a computer\n screen near you\n from Interplay Productions\n coming soon to the IBM" }, + { 0x258, " Designed by ..... Eric Chahi" }, + { 0x259, " Programmed by...... Eric Chahi" }, + { 0x25A, " Artwork ......... Eric Chahi" }, + { 0x25B, "Music by ........ Jean-francois Freitas" }, + { 0x25C, " Sound effects" }, + { 0x25D, " Jean-Francois Freitas\n Eric Chahi" }, + { 0x263, " Thanks To" }, + { 0x264, " Jesus Martinez\n\n Daniel Morais\n\n Frederic Savoir\n\n Cecile Chahi\n\n Philippe Delamarre\n\n Philippe Ulrich\n\nSebastien Berthet\n\nPierre Gousseau" }, + { 0x265, "Now Go Out Of This World" }, + { 0x190, "Good evening professor." }, + { 0x191, "I see you have driven here in your\nFerrari." }, + { 0x192, "IDENTIFICATION" }, + { 0x193, "Monsieur est en parfaite sante." }, + { 0x194, "Y\n" }, + { 0x193, "AU BOULOT !!!\n" }, +}; + +} diff --git a/awe/systemstub.h b/awe/systemstub.h new file mode 100644 index 0000000000..f86c7aaa68 --- /dev/null +++ b/awe/systemstub.h @@ -0,0 +1,68 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __SYSTEMSTUB_H__ +#define __SYSTEMSTUB_H__ + +#include "stdafx.h" + +#include "intern.h" + +namespace Awe { + +struct PlayerInput { + enum { + DIR_LEFT = 1 << 0, + DIR_RIGHT = 1 << 1, + DIR_UP = 1 << 2, + DIR_DOWN = 1 << 3 + }; + + uint8 dirMask; + bool button; + bool code; + bool pause; + bool quit; + char lastChar; + bool save, load; + bool fastMode; + int8 stateSlot; +}; + +struct SystemStub { + PlayerInput _pi; + + virtual ~SystemStub() {} + + virtual void init(const char *title) = 0; + virtual void destroy() = 0; + + virtual void setPalette(uint8 s, uint8 n, const uint8 *buf) = 0; + virtual void copyRect(uint16 x, uint16 y, uint16 w, uint16 h, const uint8 *buf, uint32 pitch) = 0; + + virtual void processEvents() = 0; + virtual void sleep(uint32 duration) = 0; + virtual uint32 getTimeStamp() = 0; +}; + +extern SystemStub *SystemStub_SDL_create(); + +} + +#endif diff --git a/awe/util.cpp b/awe/util.cpp new file mode 100644 index 0000000000..5de89f6eb2 --- /dev/null +++ b/awe/util.cpp @@ -0,0 +1,58 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include + +#include "stdafx.h" + +#include "util.h" + +namespace Awe { + +uint16 g_debugMask; + +void debug(uint16 cm, const char *msg, ...) { + char buf[1024]; + if (cm & g_debugMask) { + va_list va; + va_start(va, msg); + vsprintf(buf, msg, va); + va_end(va); + printf("%s\n", buf); + fflush(stdout); + } +} + +void string_lower(char *p) { + for (; *p; ++p) { + if (*p >= 'A' && *p <= 'Z') { + *p += 'a' - 'A'; + } + } +} + +void string_upper(char *p) { + for (; *p; ++p) { + if (*p >= 'a' && *p <= 'z') { + *p += 'A' - 'a'; + } + } +} + +} diff --git a/awe/util.h b/awe/util.h new file mode 100644 index 0000000000..64cf47603a --- /dev/null +++ b/awe/util.h @@ -0,0 +1,47 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __UTIL_H__ +#define __UTIL_H__ + +#include "stdafx.h" + +#include "intern.h" + +namespace Awe { + +enum { + DBG_LOGIC = 1 << 0, + DBG_BANK = 1 << 1, + DBG_VIDEO = 1 << 2, + DBG_INFO = 1 << 3 +}; + +extern uint16 g_debugMask; + +extern void debug(uint16 cm, const char *msg, ...); +extern void error(const char *msg, ...); +extern void warning(const char *msg, ...); + +extern void string_lower(char *p); +extern void string_upper(char *p); + +} + +#endif diff --git a/awe/video.cpp b/awe/video.cpp new file mode 100644 index 0000000000..52df154d05 --- /dev/null +++ b/awe/video.cpp @@ -0,0 +1,516 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "stdafx.h" + +#include "awe.h" +#include "video.h" +#include "resource.h" +#include "serializer.h" +#include "systemstub.h" + +namespace Awe { + +void Polygon::init(const uint8 *p, uint16 zoom) { + bbw = (*p++) * zoom / 64; + bbh = (*p++) * zoom / 64; + numPoints = *p++; + assert((numPoints & 1) == 0 && numPoints < MAX_POINTS); + for (int i = 0; i < numPoints; ++i) { + Point *pt = &points[i]; + pt->x = (*p++) * zoom / 64; + pt->y = (*p++) * zoom / 64; + } +} + +Video::Video(Resource *res, SystemStub *stub) + : _res(res), _stub(stub) { +} + +void Video::init() { + _newPal = 0xFF; + for (int i = 0; i < 4; ++i) { + _pagePtrs[i] = allocPage(); + } + _curPagePtr3 = getPagePtr(1); + _curPagePtr2 = getPagePtr(2); + changePagePtr1(0xFE); + _interpTable[0] = 0x4000; + for (int i = 1; i < 0x400; ++i) { + _interpTable[i] = 0x4000 / i; + } +} + +void Video::setDataBuffer(uint8 *dataBuf, uint16 offset) { + _dataBuf = dataBuf; + _pData.pc = dataBuf + offset; +} + +void Video::drawShape(uint8 color, uint16 zoom, const Point &pt) { + uint8 i = _pData.fetchByte(); + if (i >= 0xC0) { + if (color & 0x80) { + color = i & 0x3F; + } + _pg.init(_pData.pc, zoom); + fillPolygon(color, zoom, pt); + } else { + i &= 0x3F; + if (i == 1) { + ::warning("Video::drawShape() ec=0x%X (i != 2)", 0xF80); + } else if (i == 2) { + drawShapeParts(zoom, pt); + } else { + ::warning("Video::drawShape() ec=0x%X (i != 2)", 0xFBB); + } + } +} + +void Video::fillPolygon(uint16 color, uint16 zoom, const Point &pt) { + if (_pg.bbw == 0 && _pg.bbh == 1 && _pg.numPoints == 4) { + drawPoint(color, pt.x, pt.y); + return; + } + + int16 x1 = pt.x - _pg.bbw / 2; + int16 x2 = pt.x + _pg.bbw / 2; + int16 y1 = pt.y - _pg.bbh / 2; + int16 y2 = pt.y + _pg.bbh / 2; + + if (x1 > 319 || x2 < 0 || y1 > 199 || y2 < 0) + return; + + _hliney = y1; + + uint16 i, j; + i = 0; + j = _pg.numPoints - 1; + + x2 = _pg.points[i].x + x1; + x1 = _pg.points[j].x + x1; + + ++i; + --j; + + drawLine pdl; + if (color < 0x10) { + pdl = &Video::drawLineN; + } else if (color > 0x10) { + pdl = &Video::drawLineP; + } else { + pdl = &Video::drawLineT; + } + + uint32 cpt1 = x1 << 16; + uint32 cpt2 = x2 << 16; + + while (1) { + _pg.numPoints -= 2; + if (_pg.numPoints == 0) { + return; + } + uint16 h; + int32 step1 = calcStep(_pg.points[j + 1], _pg.points[j], h); + int32 step2 = calcStep(_pg.points[i - 1], _pg.points[i], h); + + ++i; + --j; + + cpt1 = (cpt1 & 0xFFFF0000) | 0x7FFF; + cpt2 = (cpt2 & 0xFFFF0000) | 0x8000; + + if (h == 0) { + cpt1 += step1; + cpt2 += step2; + } else { + for (; h != 0; --h) { + if (_hliney >= 0) { + x1 = cpt1 >> 16; + x2 = cpt2 >> 16; + if (x1 <= 319 && x2 >= 0) { + if (x1 < 0) x1 = 0; + if (x2 > 319) x2 = 319; + (this->*pdl)(x1, x2, color); + } + } + cpt1 += step1; + cpt2 += step2; + ++_hliney; + if (_hliney > 199) return; + } + } + } +} + +void Video::drawShapeParts(uint16 zoom, const Point &pgc) { + Point pt(pgc); + pt.x -= _pData.fetchByte() * zoom / 64; + pt.y -= _pData.fetchByte() * zoom / 64; + int16 n = _pData.fetchByte(); + debug(DBG_VIDEO, "Video::drawShapeParts n=%d", n); + for ( ; n >= 0; --n) { + uint16 off = _pData.fetchWord(); + Point po(pt); + po.x += _pData.fetchByte() * zoom / 64; + po.y += _pData.fetchByte() * zoom / 64; + uint16 color = 0xFF; + uint16 _bp = off; + off &= 0x7FFF; + if (_bp & 0x8000) { + color = *_pData.pc & 0x7F; + _pData.pc += 2; + } + uint8 *bak = _pData.pc; + _pData.pc = _dataBuf + off * 2; + drawShape(color, zoom, po); + _pData.pc = bak; + } +} + +int32 Video::calcStep(const Point &p1, const Point &p2, uint16 &dy) { + dy = p2.y - p1.y; + return (p2.x - p1.x) * _interpTable[dy] * 4; +} + +void Video::drawString(uint8 color, uint16 x, uint16 y, uint16 strId) { + const StrEntry *se = _stringsTableEng; + while (se->id != 0xFFFF && se->id != strId) ++se; + debug(DBG_VIDEO, "drawString(%d, %d, %d, '%s')", color, x, y, se->str); + uint16 xx = x; + int len = strlen(se->str); + for (int i = 0; i < len; ++i) { + if (se->str[i] == '\n') { + y += 8; + x = xx; + } else { + drawChar(se->str[i], x, y, color, _curPagePtr1); + ++x; + } + } +} + +void Video::drawChar(uint8 c, uint16 x, uint16 y, uint8 color, uint8 *buf) { + if (x <= 39 && y <= 192) { + const uint8 *ft = _font + (c - 0x20) * 8; + uint8 *p = buf + x * 4 + y * 160; + for (int j = 0; j < 8; ++j) { + uint8 ch = *(ft + j); + for (int i = 0; i < 4; ++i) { + uint8 b = *(p + i); + uint8 cmask = 0xFF; + uint8 colb = 0; + if (ch & 0x80) { + colb |= color << 4; + cmask &= 0x0F; + } + ch <<= 1; + if (ch & 0x80) { + colb |= color; + cmask &= 0xF0; + } + ch <<= 1; + *(p + i) = (b & cmask) | colb; + } + p += 160; + } + } +} + +void Video::drawPoint(uint8 color, int16 x, int16 y) { + debug(DBG_VIDEO, "drawPoint(%d, %d, %d)", color, x, y); + if (x >= 0 && x <= 319 && y >= 0 && y <= 199) { + uint16 off = y * 160 + x / 2; + + uint8 cmasko, cmaskn; + if (x & 1) { + cmaskn = 0x0F; + cmasko = 0xF0; + } else { + cmaskn = 0xF0; + cmasko = 0x0F; + } + + uint8 colb = (color << 4) | color; + if (color == 0x10) { + cmaskn &= 0x88; + cmasko = ~cmaskn; + colb = 0x88; + } else if (color == 0x11) { + colb = *(_pagePtrs[0] + off); + } + uint8 b = *(_curPagePtr1 + off); + *(_curPagePtr1 + off) = (b & cmasko) | (colb & cmaskn); + } +} + +void Video::drawLineT(int16 x1, int16 x2, uint8 color) { + debug(DBG_VIDEO, "drawLineT(%d, %d, %d)", x1, x2, color); + int16 xmax = MAX(x1, x2); + int16 xmin = MIN(x1, x2); + uint8 *p = _curPagePtr1 + _hliney * 160 + xmin / 2; + + uint16 w = xmax / 2 - xmin / 2 + 1; + uint8 cmaske = 0; + uint8 cmasks = 0; + if (xmin & 1) { + --w; + cmasks = 0xF7; + } + if (!(xmax & 1)) { + --w; + cmaske = 0x7F; + } + + if (cmasks != 0) { + *p = (*p & cmasks) | 0x08; + ++p; + } + while (w--) { + *p = (*p & 0x77) | 0x88; + ++p; + } + if (cmaske != 0) { + *p = (*p & cmaske) | 0x80; + ++p; + } +} + +void Video::drawLineN(int16 x1, int16 x2, uint8 color) { + debug(DBG_VIDEO, "drawLineN(%d, %d, %d)", x1, x2, color); + int16 xmax = MAX(x1, x2); + int16 xmin = MIN(x1, x2); + uint8 *p = _curPagePtr1 + _hliney * 160 + xmin / 2; + + uint16 w = xmax / 2 - xmin / 2 + 1; + uint8 cmaske = 0; + uint8 cmasks = 0; + if (xmin & 1) { + --w; + cmasks = 0xF0; + } + if (!(xmax & 1)) { + --w; + cmaske = 0x0F; + } + + uint8 colb = ((color & 0xF) << 4) | (color & 0xF); + if (cmasks != 0) { + *p = (*p & cmasks) | (colb & 0x0F); + ++p; + } + while (w--) { + *p++ = colb; + } + if (cmaske != 0) { + *p = (*p & cmaske) | (colb & 0xF0); + ++p; + } +} + +void Video::drawLineP(int16 x1, int16 x2, uint8 color) { + debug(DBG_VIDEO, "drawLineP(%d, %d, %d)", x1, x2, color); + int16 xmax = MAX(x1, x2); + int16 xmin = MIN(x1, x2); + uint16 off = _hliney * 160 + xmin / 2; + uint8 *p = _curPagePtr1 + off; + uint8 *q = _pagePtrs[0] + off; + + uint8 w = xmax / 2 - xmin / 2 + 1; + uint8 cmaske = 0; + uint8 cmasks = 0; + if (xmin & 1) { + --w; + cmasks = 0xF0; + } + if (!(xmax & 1)) { + --w; + cmaske = 0x0F; + } + + if (cmasks != 0) { + *p = (*p & cmasks) | (*q & 0x0F); + ++p; + ++q; + } + while (w--) { + *p++ = *q++; + } + if (cmaske != 0) { + *p = (*p & cmaske) | (*q & 0xF0); + ++p; + ++q; + } +} + +uint8 *Video::getPagePtr(uint8 page) { + uint8 *p; + if (page <= 3) { + p = _pagePtrs[page]; + } else { + switch (page) { + case 0xFF: + p = _curPagePtr3; + break; + case 0xFE: + p = _curPagePtr2; + break; + default: + p = _pagePtrs[0]; // XXX check + ::warning("Video::getPagePtr() p != [0,1,2,3,0xFF,0xFE] == 0x%X", page); + break; + } + } + return p; +} + +void Video::changePagePtr1(uint8 page) { + debug(DBG_VIDEO, "Video::changePagePtr1(%d)", page); + _curPagePtr1 = getPagePtr(page); +} + +void Video::fillPage(uint8 page, uint8 color) { + debug(DBG_VIDEO, "Video::fillPage(%d, %d)", page, color); + uint8 *p = getPagePtr(page); + uint8 c = (color << 4) | color; + memset(p, c, VID_PAGE_SIZE); +} + +void Video::copyPage(uint8 src, uint8 dst, int16 vscroll) { + debug(DBG_VIDEO, "Video::copyPage(%d, %d)", src, dst); + if (src >= 0xFE || !((src &= 0xBF) & 0x80)) { + uint8 *p = getPagePtr(src); + uint8 *q = getPagePtr(dst); + if (p != q) { + memcpy(q, p, VID_PAGE_SIZE); + } + } else { + uint8 *p = getPagePtr(src & 3); + uint8 *q = getPagePtr(dst); + if (p != q && vscroll >= -199 && vscroll <= 199) { + uint16 h = 200; + if (vscroll < 0) { + h += vscroll; + p += -vscroll * 160; + } else { + h -= vscroll; + q += vscroll * 160; + } + memcpy(q, p, h * 160); + } + } +} + +void Video::copyPagePtr(const uint8 *src) { + debug(DBG_VIDEO, "Video::copyPagePtr()"); + uint8 *dst = _pagePtrs[0]; + int h = 200; + while (h--) { + int w = 40; + while (w--) { + uint8 p[] = { + *(src + 8000 * 3), + *(src + 8000 * 2), + *(src + 8000 * 1), + *(src + 8000 * 0) + }; + for(int j = 0; j < 4; ++j) { + uint8 acc = 0; + for (int i = 0; i < 8; ++i) { + acc <<= 1; + acc |= (p[i & 3] & 0x80) ? 1 : 0; + p[i & 3] <<= 1; + } + *dst++ = acc; + } + ++src; + } + } +} + +uint8 *Video::allocPage() { + uint8 *buf = (uint8 *)malloc(VID_PAGE_SIZE); + memset(buf, 0, VID_PAGE_SIZE); + return buf; +} + +void Video::changePal(uint8 palNum) { + if (palNum < 32) { + uint8 *p = _res->_segVideoPal + palNum * 32; + uint8 pal[16 * 3]; + for (int i = 0; i < 16; ++i) { + uint8 c1 = *(p + 0); + uint8 c2 = *(p + 1); + p += 2; + pal[i * 3 + 0] = ((c1 & 0x0F) << 2) | ((c1 & 0x0F) >> 2); // r + pal[i * 3 + 1] = ((c2 & 0xF0) >> 2) | ((c2 & 0xF0) >> 6); // g + pal[i * 3 + 2] = ((c2 & 0x0F) >> 2) | ((c2 & 0x0F) << 2); // b + } + _stub->setPalette(0, 16, pal); + _curPal = palNum; + } +} + +void Video::updateDisplay(uint8 page) { + debug(DBG_VIDEO, "Video::updateDisplay(%d)", page); + if (page != 0xFE) { + if (page == 0xFF) { + SWAP(_curPagePtr2, _curPagePtr3); + } else { + _curPagePtr2 = getPagePtr(page); + } + } + if (_newPal != 0xFF) { + changePal(_newPal); + _newPal = 0xFF; + } + _stub->copyRect(0, 0, 320, 200, _curPagePtr2, 160); +} + +void Video::saveOrLoad(Serializer &ser) { + uint8 mask = 0; + if (ser._mode == Serializer::SM_SAVE) { + for (int i = 0; i < 4; ++i) { + if (_pagePtrs[i] == _curPagePtr1) + mask |= i << 4; + if (_pagePtrs[i] == _curPagePtr2) + mask |= i << 2; + if (_pagePtrs[i] == _curPagePtr3) + mask |= i << 0; + } + } + Serializer::Entry entries[] = { + SE_INT(&_curPal, Serializer::SES_INT8, VER(1)), + SE_INT(&_newPal, Serializer::SES_INT8, VER(1)), + SE_INT(&mask, Serializer::SES_INT8, VER(1)), + SE_ARRAY(_pagePtrs[0], Video::VID_PAGE_SIZE, Serializer::SES_INT8, VER(1)), + SE_ARRAY(_pagePtrs[1], Video::VID_PAGE_SIZE, Serializer::SES_INT8, VER(1)), + SE_ARRAY(_pagePtrs[2], Video::VID_PAGE_SIZE, Serializer::SES_INT8, VER(1)), + SE_ARRAY(_pagePtrs[3], Video::VID_PAGE_SIZE, Serializer::SES_INT8, VER(1)), + SE_END() + }; + ser.saveOrLoadEntries(entries); + if (ser._mode == Serializer::SM_LOAD) { + _curPagePtr1 = _pagePtrs[(mask >> 4) & 0x3]; + _curPagePtr2 = _pagePtrs[(mask >> 2) & 0x3]; + _curPagePtr3 = _pagePtrs[(mask >> 0) & 0x3]; + changePal(_curPal); + } +} + +} diff --git a/awe/video.h b/awe/video.h new file mode 100644 index 0000000000..e6a5d5ea9f --- /dev/null +++ b/awe/video.h @@ -0,0 +1,102 @@ +/* AWE - Another World Engine + * Copyright (C) 2004 Gregory Montoir + * Copyright (C) 2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __VIDEO_H__ +#define __VIDEO_H__ + +#include "stdafx.h" + +#include "intern.h" + +namespace Awe { + +struct StrEntry { + uint16 id; + const char *str; +}; + +struct Polygon { + enum { + MAX_POINTS = 50 + }; + + uint16 bbw, bbh; + uint8 numPoints; + Point points[MAX_POINTS]; + + void init(const uint8 *p, uint16 zoom); +}; + +struct Resource; +struct Serializer; +struct SystemStub; + +struct Video { + typedef void (Video::*drawLine)(int16 x1, int16 x2, uint8 col); + + enum { + VID_PAGE_SIZE = 320 * 200 / 2 + }; + + static const uint8 _font[]; + static const StrEntry _stringsTableEng[]; + static const StrEntry _stringsTableDemo[]; + + Resource *_res; + SystemStub *_stub; + + uint8 _newPal, _curPal; + uint8 *_pagePtrs[4]; + uint8 *_curPagePtr1, *_curPagePtr2, *_curPagePtr3; + Polygon _pg; + int16 _hliney; + uint16 _interpTable[0x400]; + Ptr _pData; + uint8 *_dataBuf; + + Video(Resource *res, SystemStub *stub); + void init(); + + void setDataBuffer(uint8 *dataBuf, uint16 offset); + void drawShape(uint8 color, uint16 zoom, const Point &pt); + void fillPolygon(uint16 color, uint16 zoom, const Point &pt); + void drawShapeParts(uint16 zoom, const Point &pt); + int32 calcStep(const Point &p1, const Point &p2, uint16 &dy); + + void drawString(uint8 color, uint16 x, uint16 y, uint16 strId); + void drawChar(uint8 c, uint16 x, uint16 y, uint8 color, uint8 *buf); + void drawPoint(uint8 color, int16 x, int16 y); + void drawLineT(int16 x1, int16 x2, uint8 color); + void drawLineN(int16 x1, int16 x2, uint8 color); + void drawLineP(int16 x1, int16 x2, uint8 color); + uint8 *getPagePtr(uint8 page); + void changePagePtr1(uint8 page); + void fillPage(uint8 page, uint8 color); + void copyPage(uint8 src, uint8 dst, int16 vscroll); + void copyPagePtr(const uint8 *src); + uint8 *allocPage(); + void changePal(uint8 pal); + void updateDisplay(uint8 page); + + void saveOrLoad(Serializer &ser); +}; + +} + +#endif -- cgit v1.2.3