Merge pull request #807 from blorente/macventure-clean

MACVENTURE: Add MacVenture engine.
This commit is contained in:
Eugene Sandulenko 2016-09-03 10:41:31 +02:00 committed by GitHub
commit 9d4d4f6803
47 changed files with 8706 additions and 0 deletions

View File

@ -285,6 +285,9 @@ endif
ifdef ENABLE_WINTERMUTE
DIST_FILES_ENGINEDATA+=wintermute.zip
endif
ifdef ENABLE_MACVENTURE
DIST_FILES_ENGINEDATA+=macventure.dat
endif
DIST_FILES_ENGINEDATA:=$(addprefix $(srcdir)/dists/engine-data/,$(DIST_FILES_ENGINEDATA))
# pred.dic is currently only used for the AGI engine

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

@ -0,0 +1,8 @@
printf "Creating border file...\n"
zip -r macventure.zip *.bmp
mv macventure.zip macventure.dat
echo done
ls -l macventure.dat

View File

@ -0,0 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
add_engine macventure "MacVenture" no

View File

@ -0,0 +1,187 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "macventure/container.h"
namespace MacVenture {
Container::Container(Common::String filename) {
_filename = filename;
if (!_file.open(_filename)) {
error("CONTAINER: Could not open %s", _filename.c_str());
}
_res = _file.readStream(_file.size());
_header = _res->readUint32BE();
_simplified = false;
for (uint i = 0; i < 16; ++i) {
_huff.push_back(0);
}
for (uint i = 0; i < 16; ++i) {
_lens.push_back(0);
}
if (!(_header & 0x80000000)) {
// Is simplified container
_simplified = true;
int dataLen = _res->size() - sizeof(_header);
_lenObjs = _header;
_numObjs = dataLen / _lenObjs;
} else {
_header &= 0x7fffffff;
_res->seek(_header, SEEK_SET);
_numObjs = _res->readUint16BE();
for (uint i = 0; i < 15; ++i) {
_huff[i] = _res->readUint16BE();
}
for (uint i = 0; i < 16; ++i) {
_lens[i] = _res->readByte();
}
// Read groups
uint numGroups = _numObjs / 64;
if ((_numObjs % 64) > 0) {
numGroups++;
}
for (uint i = 0; i < numGroups; ++i) {
ItemGroup group;
// Place myself in the correct position to read group
_res->seek(_header + (i * 6) + 0x30, SEEK_SET);
byte b1, b2, b3;
b1 = _res->readByte();
b2 = _res->readByte();
b3 = _res->readByte();
group.bitOffset = (b1 << 16) + (b2 << 8) + (b3 << 0);
b1 = _res->readByte();
b2 = _res->readByte();
b3 = _res->readByte();
group.offset = (b1 << 16) + (b2 << 8) + (b3 << 0);
// Place the bit reader in the correct position
// group.bitOffset indicates the offset from the start of the subHeader
_res->seek(_header + (group.bitOffset >> 3), SEEK_SET);
uint32 bits = group.bitOffset & 7;
for (uint j = 0; j < 64; ++j) {
uint32 length = 0;
uint32 mask = 0;
mask = _res->readUint32BE();
mask >>= (16 - bits);
mask &= 0xFFFF;
debugC(4, kMVDebugContainer, "Load mask of object &%d:%d is %x", i, j, mask);
_res->seek(-4, SEEK_CUR);
// Look in the Huffman table
int x = 0;
for (x = 0; x < 16; x++) {
if (_huff[x] > mask) {
break;
}
}
// I will opt to copy the code from webventure,
// But according to the docs, this call should suffice:
// length = bitStream.getBits(_lens[x]);
// The problem is that _lens[] usually contains values larger
// Than 32, so we have to read them with the method below
//This code below, taken from the implementation, seems to give the same results.
uint32 bitSize = _lens[x];
bits += bitSize & 0xF;
if (bits & 0x10) {
bits &= 0xF;
_res->seek(2, SEEK_CUR);
}
bitSize >>= 4;
if (bitSize) {
length = _res->readUint32BE();
_res->seek(-4, SEEK_CUR);
bitSize--;
if (bitSize == 0) {
length = 0;
} else {
length >>= (32 - bitSize) - bits;
}
length &= (1 << bitSize) - 1;
length |= 1 << bitSize;
bits += bitSize;
if (bits & 0x10) {
bits &= 0xF;
_res->seek(2, SEEK_CUR);
}
}
group.lengths[j] = length;
debugC(4, kMVDebugContainer, "Load legth of object %d:%d is %d", i, j, length);
}
_groups.push_back(group);
}
}
}
Container::~Container() {
if (_file.isOpen())
_file.close();
if (_res)
delete _res;
}
uint32 Container::getItemByteSize(uint32 id) {
if (_simplified) {
return _lenObjs;
} else {
uint32 groupID = (id >> 6);
uint32 objectIndex = id & 0x3f; // Index within the group
return _groups[groupID].lengths[objectIndex];
}
}
Common::SeekableReadStream *Container::getItem(uint32 id) {
if (_simplified) {
_res->seek((id * _lenObjs) + sizeof(_header), SEEK_SET);
} else {
uint32 groupID = (id >> 6);
uint32 objectIndex = id & 0x3f; // Index within the group
uint32 offset = 0;
for (uint i = 0; i < objectIndex; i++) {
offset += _groups[groupID].lengths[i];
}
_res->seek(_groups[groupID].offset + offset + sizeof(_header), SEEK_SET);
}
// HACK Should Limit the size of the stream returned
Common::SeekableReadStream *res = _res->readStream(_res->size() - _res->pos() + 1);
return res;
}
} // End of namespace MacVenture

View File

@ -0,0 +1,81 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef MACVENTURE_CONTAINER_H
#define MACVENTURE_CONTAINER_H
#include "macventure/macventure.h"
#include "common/file.h"
#include "common/fs.h"
#include "common/bitstream.h"
namespace MacVenture {
struct ItemGroup {
uint32 bitOffset; //It's really uint24
uint32 offset; //It's really uint24
uint32 lengths[64];
};
typedef uint32 ContainerHeader;
class Container {
public:
Container(Common::String filename);
~Container();
public:
/**
* Must be called before retrieving an object.
*/
uint32 getItemByteSize(uint32 id);
/**
* getItemByteSize should be called before this one
*/
Common::SeekableReadStream *getItem(uint32 id);
protected:
bool _simplified;
uint _lenObjs; // In the case of simple container, lenght of an object
uint _numObjs;
ContainerHeader _header;
Common::Array<uint16> _huff; // huffman masks
Common::Array<uint8> _lens; // huffman lengths
Common::Array<ItemGroup> _groups;
Common::String _filename;
Common::File _file;
Common::SeekableReadStream *_res;
};
} // End of namespace MacVenture
#endif

View File

@ -0,0 +1,77 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "macventure/gui.h"
namespace MacVenture {
CommandButton::CommandButton() {
_gui = NULL;
}
CommandButton::CommandButton(ControlData data, Gui *g) {
_data = data;
_gui = g;
_selected = false;
}
void CommandButton::draw(Graphics::ManagedSurface &surface) const {
uint colorFill = _selected ? kColorBlack : kColorWhite;
uint colorText = _selected ? kColorWhite : kColorBlack;
surface.fillRect(_data.bounds, colorFill);
surface.frameRect(_data.bounds, kColorBlack);
if (_data.titleLength > 0) {
const Graphics::Font &font = _gui->getCurrentFont();
Common::String title(_data.title);
font.drawString(
&surface,
title,
_data.bounds.left,
_data.bounds.top,
_data.bounds.right - _data.bounds.left,
colorText,
Graphics::kTextAlignCenter);
}
}
bool CommandButton::isInsideBounds(const Common::Point point) const {
return _data.bounds.contains(point);
}
const ControlData &CommandButton::getData() const {
return _data;
}
void CommandButton::select() {
_selected = true;
}
void CommandButton::unselect() {
_selected = false;
}
bool CommandButton::isSelected() {
return _selected;
}
}

View File

@ -0,0 +1,106 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef MACVENTURE_CONTROLS_H
#define MACVENTURE_CONTROLS_H
namespace MacVenture {
class Gui;
enum ControlType { // HACK, should correspond exactly with the types of controls (sliders etc)
kControlExitBox = 0,
kControlExamine = 1,
kControlOpen = 2,
kControlClose = 3,
kControlSpeak = 4,
kControlOperate = 5,
kControlGo = 6,
kControlHit = 7,
kControlConsume = 8,
kControlClickToContinue = 9
};
enum ControlAction {
kNoCommand = 0,
kStartOrResume = 1,
kClose = 2,
kTick = 3,
kActivateObject = 4,
kMoveObject = 5,
kConsume = 6,
kExamine = 7,
kGo = 8,
kHit = 9,
kOpen = 10,
kOperate = 11,
kSpeak = 12,
kBabble = 13,
kTargetName = 14,
kDebugObject = 15,
kClickToContinue = 16
};
struct ControlData {
Common::Rect bounds;
uint16 scrollValue;
uint8 visible;
uint16 scrollMax;
uint16 scrollMin;
uint16 cdef;
ControlAction refcon;
ControlType type;
uint8 titleLength;
Common::String title;
uint16 border;
};
class CommandButton {
enum {
kCommandsLeftPadding = 0,
kCommandsTopPadding = 0
};
public:
CommandButton();
CommandButton(ControlData data, Gui *g);
~CommandButton() {}
void draw(Graphics::ManagedSurface &surface) const;
bool isInsideBounds(const Common::Point point) const;
const ControlData &getData() const;
void select();
void unselect();
bool isSelected();
private:
bool _selected;
ControlData _data;
Gui *_gui;
};
} // End of namespace MacVenture
#endif

View File

@ -0,0 +1,128 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "macventure/gui.h"
namespace MacVenture {
static void cursorTimerHandler(void *refCon);
static const ClickState _transitionTable[kCursorStateCount][kCursorInputCount] = {
/* Button down, Button Up, Tick */
/* Idle */ {kCursorSCStart, kCursorIdle, kCursorIdle },
/* SC Start */ {kCursorSCStart, kCursorDCStart, kCursorSCDrag},
/* SC Do */ {kCursorSCDrag, kCursorIdle, kCursorSCDrag},
/* DC Start */ {kCursorDCDo, kCursorDCStart, kCursorSCSink},
/* DC Do */ {kCursorDCDo, kCursorIdle, kCursorDCDo },
/* SC Sink */ {kCursorIdle, kCursorIdle, kCursorIdle }
};
Cursor::Cursor(Gui *gui) {
_gui = gui;
_state = kCursorIdle;
}
Cursor::~Cursor() {}
void Cursor::tick() {
changeState(kTickCol);
}
bool Cursor::processEvent(const Common::Event &event) {
if (event.type == Common::EVENT_MOUSEMOVE) {
_pos = event.mouse;
return true;
}
if (event.type == Common::EVENT_LBUTTONDOWN) {
changeState(kButtonDownCol);
return true;
}
if (event.type == Common::EVENT_LBUTTONUP) {
changeState(kButtonUpCol);
return true;
}
return false;
}
Common::Point Cursor::getPos() {
return _pos;
}
bool Cursor::canSelectDraggable() {
return _state == kCursorSCDrag;
}
void Cursor::changeState(CursorInput input) {
debugC(3, kMVDebugGUI, "Change cursor state: [%d] -> [%d]", _state, _transitionTable[_state][input]);
if (_state != _transitionTable[_state][input]) {
executeStateOut();
_state = _transitionTable[_state][input];
executeStateIn();
}
}
void Cursor::executeStateIn() {
switch (_state) {
case kCursorSCStart:
g_system->getTimerManager()->installTimerProc(&cursorTimerHandler, 300000, this, "macVentureCursor");
_gui->selectForDrag(_pos);
break;
case kCursorDCStart:
g_system->getTimerManager()->installTimerProc(&cursorTimerHandler, 300000, this, "macVentureCursor");
break;
case kCursorSCSink:
_gui->handleSingleClick();
changeState(kTickCol);
break;
default:
break;
}
}
void Cursor::executeStateOut() {
switch (_state) {
case kCursorIdle:
break;
case kCursorSCStart:
g_system->getTimerManager()->removeTimerProc(&cursorTimerHandler);
break;
case kCursorSCDrag:
_gui->handleSingleClick();
break;
case kCursorDCStart:
g_system->getTimerManager()->removeTimerProc(&cursorTimerHandler);
break;
case kCursorDCDo:
_gui->handleDoubleClick();
break;
default:
break;
}
}
static void cursorTimerHandler(void *refCon) {
Cursor *cursor = (Cursor *)refCon;
cursor->tick();
}
} // End of namespace MacVenture

View File

@ -0,0 +1,88 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef MACVENTURE_DATAFILES_H
#define MACVENTURE_DATAFILES_H
#include "macventure/macventure.h"
#include "macventure/windows.h"
#include "common/unzip.h"
namespace MacVenture {
#define MACVENTURE_DATA_BUNDLE Common::String("macventure.dat")
struct BorderName {
MVWindowType type;
const char *name;
};
static const BorderName g_borderNames[] = {
{kDocument, "Document"},
{kDBox, "DBox"},
{kPlainDBox, "PlainDBox"},
{kAltBox, "AltBox"},
{kNoGrowDoc, "NoGrowDoc"},
{kMovableDBox, "MovableDBox"},
{kZoomDoc, "ZoomDoc"},
{kZoomNoGrow, "ZoomNoGrow"},
{kInvWindow, "InvWindow"},
{kRDoc16, "RDoc16"},
{kRDoc4, "RDoc4"},
{kRDoc6, "RDoc6"},
{kRDoc10, "RDoc10"},
{kNoType, "No type"}
};
Common::String windowTypeName(MVWindowType windowType) {
int i = 0;
while (g_borderNames[i].type != kNoType) {
i++;
if (g_borderNames[i].type == windowType) {
return g_borderNames[i].name;
}
}
return "";
}
void MacVentureEngine::loadDataBundle() {
_dataBundle = Common::makeZipArchive(MACVENTURE_DATA_BUNDLE);
if (!_dataBundle) {
error("ENGINE: Couldn't load data bundle '%s'.", MACVENTURE_DATA_BUNDLE.c_str());
}
}
Common::SeekableReadStream *MacVentureEngine::getBorderFile(MVWindowType windowType, bool isActive) {
Common::String filename = windowTypeName(windowType);
filename += (isActive ? "_act.bmp" : "_inac.bmp");
if (!_dataBundle->hasFile(filename)) {
warning("Missing border file '%s' in data bundle", filename.c_str());
return NULL;
}
return _dataBundle->createReadStreamForMember(filename);
}
} // End of namespace MacVenture
#endif

View File

@ -0,0 +1,38 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef MACVENTURE_DEBUG_H
#define MACVENTURE_DEBUG_H
namespace MacVenture {
enum MacVentureDebugChannel {
kMVDebugMain = 1 << 0,
kMVDebugGUI = 1 << 1,
kMVDebugImage = 1 << 2,
kMVDebugText = 1 << 3,
kMVDebugScript = 1 << 4,
kMVDebugSound = 1 << 5,
kMVDebugContainer = 1 << 6
};
} // End namespace MacVenture
#endif

View File

@ -0,0 +1,179 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "base/plugins.h"
#include "engines/advancedDetector.h"
#include "common/system.h"
#include "macventure/macventure.h"
namespace MacVenture {
#define ADGF_DEFAULT (ADGF_DROPLANGUAGE|ADGF_DROPPLATFORM|ADGF_MACRESFORK)
#define BASEGAME(n, v, f, md5, s) {n, v, AD_ENTRY1s(f, md5, s), Common::EN_ANY, Common::kPlatformMacintosh, ADGF_DEFAULT, GUIO0()}
static const ADGameDescription gameDescriptions[] = {
BASEGAME("shadowgate", "Zojoi Rerelease", "Shadowgate.bin", "ebbfbcbf93938bd2900cb0c0213b19ad", 68974), // Zojoi Rerelease
BASEGAME("deja_vu", "Zojoi Rerelease", "Deja Vu.bin", "5e9f5a8e3c8eb29ed02b34ae5937354f", 69034), // Zojoi Rerelease
BASEGAME("deja_vu2", "Zojoi Rerelease", "Lost in Las Vegas.bin", "8f8e1d8d41f577ee0fbc03847969af0d", 66520), // Zojoi Rerelease
AD_TABLE_END_MARKER
};
const char *MacVentureEngine::getGameFileName() const {
return _gameDescription->filesDescriptions[0].fileName;
}
} // End of namespace MacVenture
static const PlainGameDescriptor macventureGames[] = {
{ "shadowgate", "Shadowgate" },
{ "deja_vu", "Deja Vu"},
{ "deja_vu2", "Deja Vu II"},
{ 0, 0 }
};
namespace MacVenture {
SaveStateDescriptor loadMetaData(Common::SeekableReadStream *s, int slot);
class MacVentureMetaEngine : public AdvancedMetaEngine {
public:
MacVentureMetaEngine() : AdvancedMetaEngine(MacVenture::gameDescriptions, sizeof(ADGameDescription), macventureGames) {
_guiOptions = GUIO0();
_md5Bytes = 5000000; // TODO: Upper limit, adjust it once all games are added
}
virtual const char *getName() const override {
return "MacVenture";
}
virtual const char *getOriginalCopyright() const override {
return "(C) ICOM Simulations";
}
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
virtual bool hasFeature(MetaEngineFeature f) const;
virtual SaveStateList listSaves(const char *target) const;
virtual int getMaximumSaveSlot() const;
virtual void removeSaveState(const char *target, int slot) const;
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
};
bool MacVentureMetaEngine::hasFeature(MetaEngineFeature f) const {
return
(f == kSupportsListSaves) ||
(f == kSupportsLoadingDuringStartup) ||
(f == kSupportsDeleteSave) ||
(f == kSavesSupportMetaInfo) ||
(f == kSavesSupportThumbnail) ||
(f == kSavesSupportCreationDate) ||
(f == kSavesSupportPlayTime);
}
bool MacVentureEngine::hasFeature(EngineFeature f) const {
return
(f == kSupportsRTL) ||
(f == kSupportsLoadingDuringRuntime) ||
(f == kSupportsSavingDuringRuntime);
}
SaveStateList MacVentureMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::StringArray filenames;
Common::String pattern = target;
pattern += ".###";
filenames = saveFileMan->listSavefiles(pattern);
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
int slotNum = atoi(file->c_str() + file->size() - 3);
SaveStateDescriptor desc;
// Do not allow save slot 0 (used for auto-saving) to be deleted or
// overwritten.
desc.setDeletableFlag(slotNum != 0);
desc.setWriteProtectedFlag(slotNum == 0);
if (slotNum >= 0 && slotNum <= getMaximumSaveSlot()) {
Common::InSaveFile *in = saveFileMan->openForLoading(*file);
if (in) {
desc = loadMetaData(in, slotNum);
if (desc.getSaveSlot() != slotNum) {
// invalid
delete in;
continue;
}
saveList.push_back(desc);
delete in;
}
}
}
// Sort saves based on slot number.
Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
int MacVentureMetaEngine::getMaximumSaveSlot() const { return 999; }
bool MacVentureMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *game) const {
if (game) {
*engine = new MacVenture::MacVentureEngine(syst, game);
}
return game != 0;
}
void MacVentureMetaEngine::removeSaveState(const char *target, int slot) const {
g_system->getSavefileManager()->removeSavefile(Common::String::format("%s.%03d", target, slot));
}
SaveStateDescriptor MacVentureMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
SaveStateDescriptor desc;
Common::String saveFileName;
Common::String pattern = target;
pattern += ".###";
Common::StringArray filenames = saveFileMan->listSavefiles(pattern);
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
int slotNum = atoi(file->c_str() + file->size() - 3);
if (slotNum == slot) {
saveFileName = *file;
}
}
Common::InSaveFile *in = saveFileMan->openForLoading(saveFileName);
if (in) {
desc = loadMetaData(in, slot);
delete in;
return desc;
}
return SaveStateDescriptor(-1, "");
}
} // End of namespace MacVenture
#if PLUGIN_ENABLED_DYNAMIC(MACVENTURE)
REGISTER_PLUGIN_DYNAMIC(MACVENTURE, PLUGIN_TYPE_ENGINE, MacVenture::MacVentureMetaEngine);
#else
REGISTER_PLUGIN_STATIC(MACVENTURE, PLUGIN_TYPE_ENGINE, MacVenture::MacVentureMetaEngine);
#endif

View File

@ -0,0 +1,253 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "common/system.h"
#include "macventure/dialog.h"
namespace MacVenture {
Dialog::Dialog(Gui *gui, Common::Point pos, uint width, uint height) :
_gui(gui), _bounds(Common::Rect(pos.x, pos.y, pos.x + width, pos.y + height)) {}
Dialog::Dialog(Gui *gui, PrebuiltDialogs prebuilt) {
_gui = gui;
const PrebuiltDialog &dialog = g_prebuiltDialogs[prebuilt];
calculateBoundsFromPrebuilt(dialog.bounds);
for (int i = 0; dialog.elements[i].type != kDEEnd; i++) {
addPrebuiltElement(dialog.elements[i]);
}
}
Dialog::~Dialog() {
for (Common::Array<DialogElement*>::iterator it = _elements.begin(); it != _elements.end(); it++) {
delete *it;
}
}
void Dialog::handleDialogAction(DialogElement *trigger, DialogAction action) {
switch(action) {
case kDACloseDialog:
_gui->closeDialog();
break;
case kDASubmit:
_gui->setTextInput(_userInput);
_gui->closeDialog();
break;
case kDASaveAs:
_gui->saveGame();
_gui->closeDialog();
break;
case kDALoadGame:
_gui->loadGame();
_gui->closeDialog();
break;
case kDANewGame:
_gui->newGame();
_gui->closeDialog();
break;
case kDAQuit:
_gui->quitGame();
_gui->closeDialog();
break;
default:
break;
}
}
const Graphics::Font &Dialog::getFont() {
return _gui->getCurrentFont();
}
bool Dialog::processEvent(Common::Event event) {
for (Common::Array<DialogElement*>::iterator it = _elements.begin(); it != _elements.end(); it++) {
if ((*it)->processEvent(this, event)) {
return true;
}
}
return false;
}
void Dialog::addButton(Common::String title, MacVenture::DialogAction action, Common::Point position, uint width, uint height) {
_elements.push_back(new DialogButton(this, title, action, position, width, height));
}
void Dialog::addText(Common::String content, Common::Point position) {
_elements.push_back(new DialogPlainText(this, content, position));
}
void Dialog::addTextInput(Common::Point position, int width, int height) {
_elements.push_back(new DialogTextInput(this, position, width, height));
}
void Dialog::draw() {
Graphics::ManagedSurface compose;
// Compose the surface
compose.create(_bounds.width(), _bounds.height());
Common::Rect base(0, 0, _bounds.width(), _bounds.height());
compose.fillRect(base, kColorWhite);
compose.frameRect(base, kColorBlack);
for (Common::Array<DialogElement*>::iterator it = _elements.begin(); it != _elements.end(); it++) {
(*it)->draw(this, compose);
}
g_system->copyRectToScreen(compose.getPixels(), compose.pitch,
_bounds.left, _bounds.top, _bounds.width(), _bounds.height());
}
void Dialog::localize(Common::Point &point) {
point.x -= _bounds.left;
point.y -= _bounds.top;
}
void Dialog::setUserInput(Common::String content) {
_userInput = content;
}
void Dialog::addPrebuiltElement(const MacVenture::PrebuiltDialogElement &element) {
Common::Point position(element.left, element.top);
switch(element.type) {
case kDEButton:
addButton(element.title, element.action, position, element.width, element.height);
break;
case kDEPlainText:
addText(element.title, position);
break;
case kDETextInput:
addTextInput(position, element.width, element.height);
break;
default:
break;
}
}
// Dialog Element
DialogElement::DialogElement(Dialog *dialog, Common::String title, DialogAction action, Common::Point position, uint width, uint height) :
_text(title), _action(action) {
if (width == 0) {
width = dialog->getFont().getStringWidth(title);
}
if (height == 0) {
height = dialog->getFont().getFontHeight();
}
_bounds = Common::Rect(position.x, position.y, position.x + width, position.y + height);
}
bool DialogElement::processEvent(MacVenture::Dialog *dialog, Common::Event event) {
return doProcessEvent(dialog, event);
}
void DialogElement::draw(MacVenture::Dialog *dialog, Graphics::ManagedSurface &target) {
doDraw(dialog, target);
}
const Common::String &DialogElement::getText() {
return doGetText();
}
const Common::String &DialogElement::doGetText() {
return _text;
}
// CONCRETE DIALOG ELEMENTS
DialogButton::DialogButton(Dialog *dialog, Common::String title, DialogAction action, Common::Point position, uint width, uint height):
DialogElement(dialog, title, action, position, width, height) {}
bool DialogButton::doProcessEvent(MacVenture::Dialog *dialog, Common::Event event) {
Common::Point mouse = event.mouse;
if (event.type == Common::EVENT_LBUTTONDOWN) {
dialog->localize(mouse);
if (_bounds.contains(mouse)) {
debugC(2, kMVDebugGUI, "Click! Button: %s", _text.c_str());
dialog->handleDialogAction(this, _action);
return true;
}
}
return false;
}
void DialogButton::doDraw(MacVenture::Dialog *dialog, Graphics::ManagedSurface &target) {
target.fillRect(_bounds, kColorWhite);
target.frameRect(_bounds, kColorBlack);
// Draw title
dialog->getFont().drawString(
&target, _text, _bounds.left, _bounds.top, _bounds.width(), kColorBlack, Graphics::kTextAlignCenter);
}
DialogPlainText::DialogPlainText(Dialog *dialog, Common::String content, Common::Point position) :
DialogElement(dialog, content, kDANone, position, 0, 0) { }
DialogPlainText::~DialogPlainText() {}
bool DialogPlainText::doProcessEvent(MacVenture::Dialog *dialog, Common::Event event) {
return false;
}
void DialogPlainText::doDraw(MacVenture::Dialog *dialog, Graphics::ManagedSurface &target) {
// Draw contents
dialog->getFont().drawString(
&target, _text, _bounds.left, _bounds.top, _bounds.width(), kColorBlack, Graphics::kTextAlignCenter);
}
DialogTextInput::DialogTextInput(Dialog *dialog, Common::Point position, uint width, uint height) :
DialogElement(dialog, "", kDANone, position, width, height) {}
DialogTextInput::~DialogTextInput() {}
bool DialogTextInput::doProcessEvent(Dialog *dialog, Common::Event event) {
if (event.type == Common::EVENT_KEYDOWN) {
switch (event.kbd.keycode) {
case Common::KEYCODE_BACKSPACE:
if (!_text.empty()) {
_text.deleteLastChar();
dialog->setUserInput(_text);
return true;
}
break;
default:
if (event.kbd.ascii >= 0x20 && event.kbd.ascii <= 0x7f) {
_text += (char)event.kbd.ascii;
dialog->setUserInput(_text);
return true;
}
break;
}
}
return false;
}
void DialogTextInput::doDraw(MacVenture::Dialog *dialog, Graphics::ManagedSurface &target) {
target.fillRect(_bounds, kColorWhite);
target.frameRect(_bounds, kColorBlack);
dialog->getFont().drawString(&target, _text, _bounds.left, _bounds.top, _bounds.width(), kColorBlack);
}
void Dialog::calculateBoundsFromPrebuilt(const PrebuiltDialogBounds &bounds) {
_bounds = Common::Rect(
bounds.left,
bounds.top,
bounds.right,
bounds.bottom);
}
} // End of namespace MacVenture

123
engines/macventure/dialog.h Normal file
View File

@ -0,0 +1,123 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef MACVENTURE_DIALOG_H
#define MACVENTURE_DIALOG_H
#include "graphics/macgui/macwindowmanager.h"
#include "macventure/macventure.h"
#include "macventure/prebuilt_dialogs.h"
namespace MacVenture {
using namespace Graphics::MacGUIConstants;
class Gui;
class DialogElement;
class Dialog {
public:
Dialog(Gui *gui, Common::Point pos, uint width, uint height);
Dialog(Gui *gui, PrebuiltDialogs prebuilt);
~Dialog();
bool processEvent(Common::Event event);
void draw();
void localize(Common::Point &point);
void handleDialogAction(DialogElement *trigger, DialogAction action);
const Graphics::Font &getFont();
void addButton(Common::String title, DialogAction action, Common::Point position, uint width = 0, uint height = 0);
void addText(Common::String content, Common::Point position);
void addTextInput(Common::Point position, int width, int height);
void setUserInput(Common::String content);
private:
void addPrebuiltElement(const PrebuiltDialogElement &element);
void calculateBoundsFromPrebuilt(const PrebuiltDialogBounds &bounds);
private:
Gui *_gui;
Common::String _userInput;
Common::Array<DialogElement*> _elements;
Common::Rect _bounds;
};
class DialogElement {
public:
DialogElement(Dialog *dialog, Common::String title, DialogAction action, Common::Point position, uint width = 0, uint height = 0);
virtual ~DialogElement() {}
bool processEvent(Dialog *dialog, Common::Event event);
void draw(MacVenture::Dialog *dialog, Graphics::ManagedSurface &target);
const Common::String &getText();
private:
virtual bool doProcessEvent(Dialog *dialog, Common::Event event) = 0;
virtual void doDraw(MacVenture::Dialog *dialog, Graphics::ManagedSurface &target) = 0;
virtual const Common::String &doGetText();
protected:
Common::String _text;
Common::Rect _bounds;
DialogAction _action;
};
// Dialog elements
class DialogButton : public DialogElement {
public:
DialogButton(Dialog *dialog, Common::String title, DialogAction action, Common::Point position, uint width = 0, uint height = 0);
~DialogButton() {}
private:
bool doProcessEvent(Dialog *dialog, Common::Event event);
void doDraw(MacVenture::Dialog *dialog, Graphics::ManagedSurface &target);
};
class DialogPlainText : public DialogElement {
public:
DialogPlainText(Dialog *dialog, Common::String content, Common::Point position);
~DialogPlainText();
private:
bool doProcessEvent(Dialog *dialog, Common::Event event);
void doDraw(MacVenture::Dialog *dialog, Graphics::ManagedSurface &target);
};
class DialogTextInput : public DialogElement {
public:
DialogTextInput(Dialog *dialog, Common::Point position, uint width, uint height);
~DialogTextInput();
private:
bool doProcessEvent(Dialog *dialog, Common::Event event);
void doDraw(MacVenture::Dialog *dialog, Graphics::ManagedSurface &target);
};
} // End of namespace MacVenture
#endif

1464
engines/macventure/gui.cpp Normal file

File diff suppressed because it is too large Load Diff

369
engines/macventure/gui.h Normal file
View File

@ -0,0 +1,369 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef MACVENTURE_GUI_H
#define MACVENTURE_GUI_H
#include "graphics/macgui/macwindowmanager.h"
#include "graphics/macgui/macwindow.h"
#include "graphics/macgui/macmenu.h"
#include "graphics/font.h"
#include "common/timer.h"
#include "macventure/macventure.h"
#include "macventure/container.h"
#include "macventure/image.h"
#include "macventure/prebuilt_dialogs.h"
#include "macventure/dialog.h"
#include "macventure/controls.h"
#include "macventure/windows.h"
namespace MacVenture {
using namespace Graphics::MacGUIConstants;
using namespace Graphics::MacWindowConstants;
class MacVentureEngine;
typedef uint32 ObjID;
class Cursor;
class ConsoleText;
class CommandButton;
class ImageAsset;
class Dialog;
BorderBounds borderBounds(MVWindowType type);
enum MenuAction {
kMenuActionAbout,
kMenuActionNew,
kMenuActionOpen,
kMenuActionSave,
kMenuActionSaveAs,
kMenuActionQuit,
kMenuActionUndo,
kMenuActionCut,
kMenuActionCopy,
kMenuActionPaste,
kMenuActionClear,
kMenuActionCleanUp,
kMenuActionMessUp,
kMenuActionCommand
};
struct DraggedObj {
ObjID id;
Common::Point pos;
Common::Point mouseOffset;
Common::Point startPos;
WindowReference startWin;
bool hasMoved;
};
class Gui {
public:
Gui(MacVentureEngine *engine, Common::MacResManager *resman);
~Gui();
void reloadInternals();
void draw();
void drawMenu();
void drawTitle();
void clearControls();
bool processEvent(Common::Event &event);
void handleMenuAction(MenuAction action);
void updateWindow(WindowReference winID, bool containerOpen);
void invertWindowColors(WindowReference winID);
WindowReference createInventoryWindow(ObjID objRef);
bool tryCloseWindow(WindowReference winID);
Common::Point getObjMeasures(ObjID obj);
WindowReference getObjWindow(ObjID objID);
WindowReference findObjWindow(ObjID objID);
// Event processors
bool processCommandEvents(WindowClick click, Common::Event &event);
bool processMainGameEvents(WindowClick click, Common::Event &event);
bool processOutConsoleEvents(WindowClick click, Common::Event &event);
bool processSelfEvents(WindowClick click, Common::Event &event);
bool processExitsEvents(WindowClick click, Common::Event &event);
bool processDiplomaEvents(WindowClick click, Common::Event &event);
bool processInventoryEvents(WindowClick click, Common::Event &event);
const WindowData& getWindowData(WindowReference reference);
const Graphics::Font& getCurrentFont();
// Clicks
void selectForDrag(Common::Point cursorPosition);
void handleSingleClick();
void handleDoubleClick();
// Modifiers
void bringToFront(WindowReference window);
void setWindowTitle(WindowReference winID, Common::String string);
void updateWindowInfo(WindowReference ref, ObjID objID, const Common::Array<ObjID> &children);
void ensureInventoryOpen(WindowReference reference, ObjID id);
void addChild(WindowReference target, ObjID child);
void removeChild(WindowReference target, ObjID child);
void clearExits();
void unselectExits();
void updateExit(ObjID id);
void printText(const Common::String &text);
//Dialog interactions
void showPrebuiltDialog(PrebuiltDialogs type);
bool isDialogOpen();
void getTextFromUser();
void setTextInput(Common::String str);
void closeDialog();
void loadGame();
void saveGame();
void newGame();
void quitGame();
void createInnerSurface(Graphics::ManagedSurface *innerSurface, Graphics::ManagedSurface *outerSurface, const BorderBounds &borders);
private: // Attributes
MacVentureEngine *_engine;
Common::MacResManager *_resourceManager;
Graphics::ManagedSurface _screen;
Graphics::MacWindowManager _wm;
Common::List<WindowData> *_windowData;
Common::Array<CommandButton> *_controlData;
Common::Array<CommandButton> *_exitsData;
Graphics::MacWindow *_controlsWindow;
Graphics::MacWindow *_mainGameWindow;
Graphics::MacWindow *_outConsoleWindow;
Graphics::MacWindow *_selfWindow;
Graphics::MacWindow *_exitsWindow;
Graphics::MacWindow *_diplomaWindow;
Common::Array<Graphics::MacWindow*> _inventoryWindows;
Graphics::Menu *_menu;
Dialog *_dialog;
Container *_graphics;
Common::HashMap<ObjID, ImageAsset*> _assets;
Graphics::ManagedSurface _draggedSurface;
DraggedObj _draggedObj;
Cursor *_cursor;
ConsoleText *_consoleText;
private: // Methods
// Initializers
void initGUI();
void initWindows();
void assignObjReferences(); // Mainly guesswork
// Loaders
bool loadMenus();
bool loadWindows();
bool loadControls();
void loadBorders(Graphics::MacWindow *target, MVWindowType type);
void loadBorder(Graphics::MacWindow *target, MVWindowType type, bool active);
void loadGraphics();
void clearAssets();
// Drawers
void drawWindows();
void drawCommandsWindow();
void drawMainGameWindow();
void drawSelfWindow();
void drawInventories();
void drawExitsWindow();
void drawConsoleWindow();
void drawDraggedObject();
void drawObjectsInWindow(const WindowData &targetData, Graphics::ManagedSurface *surface);
void drawWindowTitle(WindowReference target, Graphics::ManagedSurface *surface);
void drawDialog();
void moveDraggedObject(Common::Point target);
// Finders
WindowReference findWindowAtPoint(Common::Point point);
Common::Point getGlobalScrolledSurfacePosition(WindowReference reference);
WindowData& findWindowData(WindowReference reference);
Graphics::MacWindow *findWindow(WindowReference reference);
// Utils
void checkSelect(const WindowData &data, Common::Point pos, const Common::Rect &clickRect, WindowReference ref);
bool canBeSelected(ObjID obj, const Common::Rect &clickRect, WindowReference ref);
bool isRectInsideObject(Common::Rect target, ObjID obj);
void selectDraggable(ObjID child, WindowReference origin, Common::Point startPos);
void handleDragRelease(bool shiftPressed, bool isDoubleClick);
Common::Rect calculateClickRect(Common::Point clickPos, Common::Rect windowBounds);
Common::Point localizeTravelledDistance(Common::Point point, WindowReference origin, WindowReference target);
void removeInventoryWindow(WindowReference ref);
void ensureAssetLoaded(ObjID obj);
};
enum ClickState {
kCursorIdle = 0,
kCursorSCStart = 1,
kCursorSCDrag = 2,
kCursorDCStart = 3,
kCursorDCDo = 4,
kCursorSCSink = 5,
kCursorStateCount
};
enum CursorInput { // Columns for the FSM transition table
kButtonDownCol = 0,
kButtonUpCol = 1,
kTickCol = 2,
kCursorInputCount
};
class Cursor {
public:
Cursor(Gui *gui);
~Cursor();
void tick();
bool processEvent(const Common::Event &event);
Common::Point getPos();
bool canSelectDraggable();
private:
void changeState(CursorInput input);
void executeStateIn();
void executeStateOut();
private:
Gui *_gui;
Common::Point _pos;
ClickState _state;
};
enum {
kConsoleLeftOffset = 2
};
class ConsoleText {
public:
ConsoleText(Gui *gui) {
_gui = gui;
_lines.push_back("");
updateScroll();
}
~ConsoleText() {
}
void printLine(const Common::String &str, int maxW) {
Common::StringArray wrappedLines;
int textW = maxW;
const Graphics::Font *font = &_gui->getCurrentFont();
font->wordWrapText(str, textW, wrappedLines);
if (wrappedLines.empty()) // Sometimes we have empty lines
_lines.push_back("");
for (Common::StringArray::const_iterator j = wrappedLines.begin(); j != wrappedLines.end(); ++j) {
_lines.push_back(*j);
}
updateScroll();
}
void renderInto(Graphics::ManagedSurface *target, const BorderBounds borders, int textOffset) {
target->fillRect(target->getBounds(), kColorWhite);
Graphics::ManagedSurface *composeSurface = new Graphics::ManagedSurface();
_gui->createInnerSurface(composeSurface, target, borders);
composeSurface->clear(kColorGreen);
const Graphics::Font *font = &_gui->getCurrentFont();
uint y = target->h - font->getFontHeight();
for (uint i = _scrollPos; i != 0; i--) {
font->drawString(target, _lines[i], textOffset, y, font->getStringWidth(_lines[i]), kColorBlack);
y -= font->getFontHeight();
}
Common::Point composePosition = Common::Point(borders.leftOffset, borders.topOffset);
target->transBlitFrom(*composeSurface, composePosition, kColorGreen);
delete composeSurface;
}
void updateScroll() {
_scrollPos = _lines.size() - 1;
}
void scrollDown() {
if (_scrollPos < (int)(_lines.size() - 1)) {
_scrollPos++;
}
}
void scrollUp() {
if (_scrollPos > 0) {
_scrollPos--;
}
}
private:
Gui *_gui;
Common::StringArray _lines;
int _scrollPos;
};
} // End of namespace MacVenture
#endif

View File

@ -0,0 +1,57 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef MACVENTURE_HUFFLIST_H
#define MACVENTURE_HUFFLIST_H
namespace MacVenture {
// The engine uses a <= comparison instead of ==, so I can't use Common::Huffman
class HuffmanLists {
public:
HuffmanLists() {
_numEntries = 0;
}
HuffmanLists(uint32 num, uint32 *lens, uint32 *masks, uint32 *symbols) {
_numEntries = num;
_lens = Common::Array<uint32>(lens, num);
_masks = Common::Array<uint32>(masks, num);
_symbols = Common::Array<uint32>(symbols, num);
}
~HuffmanLists() {}
uint32 getNumEntries() const { return _numEntries; }
uint32 getLength(uint32 index) const { return _lens[index]; }
uint32 getMask(uint32 index) const { return _masks[index]; }
uint32 getSymbol(uint32 index) const { return _symbols[index]; }
private:
uint32 _numEntries;
Common::Array<uint32> _lens;
Common::Array<uint32> _masks;
Common::Array<uint32> _symbols;
};
} // End of namespace MacVenture
#endif

View File

@ -0,0 +1,553 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "macventure/image.h"
namespace MacVenture {
static const PPICHuff PPIC1Huff = {
// Masks
{ 0x0000,0x2000,0x4000,0x5000,0x6000,0x7000,0x8000,0x9000,0xa000,
0xb000,0xc000,0xd000,0xd800,0xe000,0xe800,0xf000,0xf800 },
// Lens
{ 3,3,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5 },
// Symbols
{ 0x00,0x0f,0x03,0x05,0x06,0x07,0x08,0x09,0x0a,0x0c,0xff,0x01,
0x02,0x04,0x0b,0x0d,0xe }
};
static const PPICHuff PPIC2Huff = {
// Masks
{ 0x0000,0x4000,0x8000,0xc000,0xc800,0xd000,0xd800,0xe000,0xe800,
0xf000,0xf400,0xf600,0xf800,0xfa00,0xfc00,0xfe00,0xff00 },
// Lens
{ 2,2,2,5,5,5,5,5,5,6,7,7,7,7,7,8,8 },
// Symbols
{ 0xff,0x00,0x0f,0x01,0x03,0x07,0x0e,0x0c,0x08,0x06,0x02,0x04,
0x09,0x0d,0x0b,0x0a,0x05 }
};
// Used to load the huffman table in PPIC3 decoding
static const byte loadBits[] = {
0x08, 0x0f, 0x02, 0xff, 0x00,
0x04, 0xff, 0x01,
0x07, 0x09, 0x08, 0xff, 0x03,
0x04, 0xff, 0x04,
0x0a, 0x07, 0x0a, 0x0b, 0x06, 0xff, 0x05,
0x06, 0x06, 0x0b, 0xff, 0x07,
0x03, 0xff, 0x09,
0x04, 0x03, 0x0e, 0xff, 0x0c,
0x02, 0xff, 0x0d,
0x01, 0xff, 0x0f,
0xff
};
ImageAsset::ImageAsset(ObjID original, Container *container) {
_id = (original * 2);
_mask = (original * 2) + 1;
uint imgRowBytes = 0;
uint imgBitWidth = 0;
uint imgBitHeight = 0;
uint maskRowBytes = 0;
uint maskBitWidth = 0;
uint maskBitHeight = 0;
_container = container;
decodePPIC(_id, _imgData, imgBitHeight, imgBitWidth, imgRowBytes);
_imgRowBytes = imgRowBytes;
_imgBitWidth = imgBitWidth;
_imgBitHeight = imgBitHeight;
if (_container->getItemByteSize(_mask)) {
decodePPIC(_mask, _maskData, maskBitHeight, maskBitWidth, maskRowBytes);
}
_maskRowBytes = maskRowBytes;
_maskBitWidth = maskBitWidth;
_maskBitHeight = maskBitHeight;
}
ImageAsset::~ImageAsset() {
debugC(3, kMVDebugImage, "~ImageAsset(%d)", _id / 2);
}
void ImageAsset::decodePPIC(ObjID id, Common::Array<byte> &data, uint &bitHeight, uint &bitWidth, uint &rowBytes) {
ObjID realID = id;
uint32 size = _container->getItemByteSize(id);
if (size < 2) {
rowBytes = 0;
bitHeight = 0;
bitWidth = 0;
return;
}
if (size == 2) {
Common::SeekableReadStream *newItemStream = _container->getItem(id);
realID = newItemStream->readUint16BE();
delete newItemStream;
}
Common::SeekableReadStream *baseStream = _container->getItem(realID);
Common::BitStream32BEMSB stream(baseStream);
uint8 mode = stream.getBits(3);
int w, h;
if (stream.getBit()) {
h = stream.getBits(10);
} else {
h = stream.getBits(6);
}
if (stream.getBit()) {
w = stream.getBits(10);
} else {
w = stream.getBits(6);
}
rowBytes = ((w + 0xF) >> 3) & 0xFFFE;
bitWidth = w;
bitHeight = h;
for (uint i = 0; i < rowBytes * h; i++) {
data.push_back(0);
}
switch (mode) {
case MacVenture::kPPIC0:
decodePPIC0(stream, data, bitHeight, bitWidth, rowBytes);
break;
case MacVenture::kPPIC1:
decodePPIC1(stream, data, bitHeight, bitWidth, rowBytes);
break;
case MacVenture::kPPIC2:
decodePPIC2(stream, data, bitHeight, bitWidth, rowBytes);
break;
case MacVenture::kPPIC3:
decodePPIC3(stream, data, bitHeight, bitWidth, rowBytes);
break;
}
delete baseStream;
}
void ImageAsset::decodePPIC0(Common::BitStream &stream, Common::Array<byte> &data, uint bitHeight, uint bitWidth, uint rowBytes) {
uint words = bitWidth >> 4;
uint bytes = bitWidth & 0xF;
uint v = 0;
uint p = 0;
for (uint y = 0; y < bitHeight; y++) {
for (uint x = 0; x < words; x++) {
v = stream.peekBits(32);
stream.skip(16);
v >>= 16 - (stream.pos() % 8);
data[p] = (v >> 8) & 0xff; p++;
data[p] = v & 0xff; p++;
}
if (bytes) {
v = stream.getBits(bytes);
v <<= 16 - bytes;
data[p] = (v >> 8) & 0xff; p++;
data[p] = v & 0xff; p++;
}
}
}
void ImageAsset::decodePPIC1(Common::BitStream &stream, Common::Array<byte> &data, uint bitHeight, uint bitWidth, uint rowBytes) {
decodeHuffGraphic(PPIC1Huff, stream, data, bitHeight, bitWidth, rowBytes);
}
void ImageAsset::decodePPIC2(Common::BitStream &stream, Common::Array<byte> &data, uint bitHeight, uint bitWidth, uint rowBytes) {
decodeHuffGraphic(PPIC2Huff, stream, data, bitHeight, bitWidth, rowBytes);
}
void ImageAsset::decodePPIC3(Common::BitStream &stream, Common::Array<byte> &data, uint bitHeight, uint bitWidth, uint rowBytes) {
// We need to load the huffman from the PPIC itself
PPICHuff huff;
uint16 v, bits;
uint16 load = 0;
while ((bits = loadBits[load++]) != 0xFF) {
v = stream.getBits(bits);
while ((bits = loadBits[load++]) != 0xFF) {
huff.symbols[loadBits[load++]] = v % bits;
v = (bits != 0) ? (v / bits) : 0;
}
huff.symbols[loadBits[load++]] = v;
}
huff.symbols[0x10] = 0;
for (uint i = 0x10; i > 0; i--) {
for (uint j = i; j <= 0x10; j++) {
if (huff.symbols[j] >= huff.symbols[i - 1]) {
huff.symbols[j]++;
}
}
}
for (int i = 0x10; i >= 0; i--) {
if (huff.symbols[i] == 0x10) {
huff.symbols[i] = 0xff;
break;
}
}
bits = stream.getBits(2) + 1;
uint16 mask = 0;
for (uint i = 0; i < 0xf; i++) {
if (i) {
while (!stream.getBit()) {
bits++;
}
}
huff.lens[i] = bits;
huff.masks[i] = mask;
mask += 1 << (16 - bits);
}
huff.masks[0xf] = mask;
while (mask&(1 << (16 - bits))) {
bits++;
}
huff.masks[0x10] = mask | (1 << (16 - bits));
huff.lens[0xf] = bits;
huff.lens[0x10] = bits;
decodeHuffGraphic(huff, stream, data, bitHeight, bitWidth, rowBytes);
}
void ImageAsset::decodeHuffGraphic(const PPICHuff &huff, Common::BitStream &stream, Common::Array<byte> &data, uint bitHeight, uint bitWidth, uint rowBytes) {
byte flags = 0;
_walkRepeat = 0;
_walkLast = 0;
if (bitWidth & 3) {
flags = stream.getBits(5);
} else {
flags = stream.getBits(4) << 1;
}
byte odd = 0;
byte blank = bitWidth & 0xf;
if (blank) {
blank >>= 2;
odd = blank & 1;
blank = 2 - (blank >> 1);
}
uint16 pos = 0;
for (uint y = 0; y < bitHeight; y++) {
uint16 x = 0;
for (; x < bitWidth >> 3; x++) {
byte hi = walkHuff(huff, stream) << 4;
data[pos++] = walkHuff(huff, stream) | hi;
}
if (odd) {
data[pos] = walkHuff(huff, stream) << 4;
}
pos += blank;
}
uint16 edge = bitWidth & 3;
if (edge) {
pos = rowBytes - blank;
uint16 bits = 0;
uint16 val = 0;
uint16 v;
for (uint y = 0; y < bitHeight; y++) {
if (flags & 1) {
if (bits < edge) {
v = walkHuff(huff, stream) << 4;
val |= v >> bits;
bits += 4;
}
bits -= edge;
v = val;
val <<= edge;
val &= 0xFF;
} else {
v = stream.getBits(edge);
v <<= 8 - edge;
}
if (odd)
v >>= 4;
data[pos] |= v & 0xff;
pos += rowBytes;
}
}
if (flags & 8) {
pos = 0;
for (uint y = 0; y < bitHeight; y++) {
uint16 v = 0;
if (flags & 2) {
for (uint x = 0; x < rowBytes; x++) {
data[pos] ^= v;
v = data[pos];
pos++;
}
} else {
for (uint x = 0; x < rowBytes; x++) {
uint16 val = data[pos] ^ v;
val ^= (val >> 4) & 0xf;
data[pos] = val;
pos++;
v = (val << 4) & 0xff;
}
}
}
}
if (flags & 4) {
uint16 delta = rowBytes * 4;
if (flags & 2) {
delta *= 2;
}
pos = 0;
uint q = delta;
for (uint i = 0; i < bitHeight * rowBytes - delta; i++) {
data[q] ^= data[pos];
q++;
pos++;
}
}
}
byte ImageAsset::walkHuff(const PPICHuff &huff, Common::BitStream &stream) {
if (_walkRepeat) {
_walkRepeat--;
_walkLast = ((_walkLast << 8) & 0xFF00) | (_walkLast >> 8);
return _walkLast & 0xFF;
}
uint16 dw = stream.peekBits(16);
uint16 i = 0;
for (;i < 16; i++) {
if (huff.masks[i + 1] > dw) {
break;
}
}
stream.skip(huff.lens[i]);
uint8 val = huff.symbols[i];
if (val == 0xFF) {
if (!stream.getBit()) {
_walkLast &= 0xFF;
_walkLast |= _walkLast << 8;
}
_walkRepeat = stream.getBits(3);
if (_walkRepeat < 3) {
_walkRepeat <<= 4;
_walkRepeat |= stream.getBits(4);
if (_walkRepeat < 8) {
_walkRepeat <<= 8;
_walkRepeat |= stream.getBits(8);
}
}
_walkRepeat -= 2;
_walkLast = ((_walkLast << 8) & 0xFF00) | (_walkLast >> 8);
return _walkLast & 0xFF;
} else {
_walkLast <<= 8;
_walkLast |= val;
_walkLast &= 0xFFFF;
}
return val;
}
void ImageAsset::blitInto(Graphics::ManagedSurface *target, int x, int y, BlitMode mode) {
if (mode == kBlitDirect) {
blitDirect(target, x, y, _imgData, _imgBitHeight, _imgBitWidth, _imgRowBytes);
} else if (mode < kBlitXOR) {
if (_container->getItemByteSize(_mask)) { // Has mask
switch (mode) {
case MacVenture::kBlitBIC:
blitBIC(target, x, y, _maskData, _maskBitHeight, _maskBitWidth, _maskRowBytes);
break;
case MacVenture::kBlitOR:
blitOR(target, x, y, _maskData, _maskBitHeight, _maskBitWidth, _maskRowBytes);
break;
default:
break;
}
} else if (_container->getItemByteSize(_id)) {
switch (mode) {
case MacVenture::kBlitBIC:
target->fillRect(Common::Rect(x, y, x + _imgBitWidth, y + _imgBitHeight), kColorWhite);
break;
case MacVenture::kBlitOR:
target->fillRect(Common::Rect(x, y, x + _imgBitWidth, y + _imgBitHeight), kColorBlack);
break;
default:
break;
}
}
if (_container->getItemByteSize(_id) && mode > 0) {
blitXOR(target, x, y, _imgData, _imgBitHeight, _imgBitWidth, _imgRowBytes);
}
}
}
bool ImageAsset::isPointInside(Common::Point point) {
if (point.x >= _maskBitWidth || point.y >= _maskBitHeight) {
return false;
}
if (_maskData.empty()) {
return false;
}
// We see if the point lands on the mask.
uint pix = _maskData[(point.y * _maskRowBytes) + (point.x >> 3)] & (1 << (7 - (point.x & 7)));
return pix != 0;
}
bool ImageAsset::isRectInside(Common::Rect rect) {
if (_maskData.empty()) {
return (rect.width() > 0 && rect.height() > 0);
}
for (int y = rect.top; y < rect.top + rect.height(); y++) {
uint bmpofs = y * _maskRowBytes;
byte pix;
for (int x = rect.left; x < rect.left + rect.width(); x++) {
pix = _maskData[bmpofs + (x >> 3)] & (1 << (7 - (x & 7)));
if (pix) {
return true;
}
}
}
return false;
}
int ImageAsset::getWidth() {
if (_imgData.size() == 0) {
return 0;
}
return MAX(0, (int)_imgBitWidth);
}
int ImageAsset::getHeight() {
if (_imgData.size() == 0) {
return 0;
}
return MAX(0, (int)_imgBitHeight);
}
void ImageAsset::blitDirect(Graphics::ManagedSurface *target, int ox, int oy, const Common::Array<byte> &data, uint bitHeight, uint bitWidth, uint rowBytes) {
uint sx, sy, w, h;
calculateSectionToDraw(target, ox, oy, bitWidth, bitHeight, sx, sy, w, h);
for (uint y = 0; y < h; y++) {
uint bmpofs = (y + sy) * rowBytes;
byte pix = 0;
for (uint x = 0; x < w; x++) {
assert(ox + x <= target->w);
assert(oy + y <= target->h);
pix = data[bmpofs + ((x + sx) >> 3)] & (1 << (7 - ((x + sx) & 7)));
pix = pix ? kColorBlack : kColorWhite;
*((byte *)target->getBasePtr(ox + x, oy + y)) = pix;
}
}
}
void ImageAsset::blitBIC(Graphics::ManagedSurface *target, int ox, int oy, const Common::Array<byte> &data, uint bitHeight, uint bitWidth, uint rowBytes) {
uint sx, sy, w, h;
calculateSectionToDraw(target, ox, oy, bitWidth, bitHeight, sx, sy, w, h);
for (uint y = 0; y < h; y++) {
uint bmpofs = (y + sy) * rowBytes;
byte pix = 0;
for (uint x = 0; x < w; x++) {
assert(ox + x <= target->w);
assert(oy + y <= target->h);
pix = data[bmpofs + ((x + sx) >> 3)] & (1 << (7 - ((x + sx) & 7)));
if (pix) {
*((byte *)target->getBasePtr(ox + x, oy + y)) = kColorWhite;
}
}
}
}
void ImageAsset::blitOR(Graphics::ManagedSurface *target, int ox, int oy, const Common::Array<byte> &data, uint bitHeight, uint bitWidth, uint rowBytes) {
uint sx, sy, w, h;
calculateSectionToDraw(target, ox, oy, bitWidth, bitHeight, sx, sy, w, h);
for (uint y = 0; y < h; y++) {
uint bmpofs = (y + sy) * rowBytes;
byte pix = 0;
for (uint x = 0; x < w; x++) {
assert(ox + x <= target->w);
assert(oy + y <= target->h);
pix = data[bmpofs + ((x + sx) >> 3)] & (1 << (7 - ((x + sx) & 7)));
if (pix) {
*((byte *)target->getBasePtr(ox + x, oy + y)) = kColorBlack;
}
}
}
}
void ImageAsset::blitXOR(Graphics::ManagedSurface *target, int ox, int oy, const Common::Array<byte> &data, uint bitHeight, uint bitWidth, uint rowBytes) {
uint sx, sy, w, h;
calculateSectionToDraw(target, ox, oy, bitWidth, bitHeight, sx, sy, w, h);
for (uint y = 0; y < h; y++) {
uint bmpofs = (y + sy) * rowBytes;
byte pix = 0;
for (uint x = 0; x < w; x++) {
pix = data[bmpofs + ((x + sx) >> 3)] & (1 << (7 - ((x + sx) & 7)));
if (pix) { // We need to xor
assert(ox + x <= target->w);
assert(oy + y <= target->h);
byte p = *((byte *)target->getBasePtr(ox + x, oy + y));
*((byte *)target->getBasePtr(ox + x, oy + y)) =
(p == kColorWhite) ? kColorBlack : kColorWhite;
}
}
}
}
void ImageAsset::calculateSectionToDraw(Graphics::ManagedSurface *target, int &ox, int &oy, uint bitWidth, uint bitHeight, uint &sx, uint &sy, uint &w, uint &h) {
calculateSectionInDirection(target->w, bitWidth, ox, sx, w);
calculateSectionInDirection(target->h, bitHeight, oy, sy, h);
assert(w <= target->w);
assert((int)w >= 0);
assert(w <= bitWidth);
assert(h <= target->h);
assert((int)h >= 0);
assert(h <= bitHeight);
}
void ImageAsset::calculateSectionInDirection(uint targetWhole, uint originWhole, int &originPosition, uint &startPosition, uint &blittedWhole) {
startPosition = 0;
blittedWhole = originWhole;
if (originPosition < 0) {
if (ABS(originPosition) > (int)blittedWhole) {
blittedWhole = 0;
} else {
blittedWhole -= -originPosition;
}
startPosition = -originPosition;
originPosition = 0;
}
if (originPosition + blittedWhole > targetWhole) {
if (originPosition > (int)targetWhole) {
blittedWhole = 0;
} else {
blittedWhole = targetWhole - originPosition;
}
}
}
} // End of namespace MacVenture

108
engines/macventure/image.h Normal file
View File

@ -0,0 +1,108 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef MACVENTURE_IMAGE_H
#define MACVENTURE_IMAGE_H
#include "macventure/macventure.h"
#include "macventure/container.h"
namespace MacVenture {
typedef uint32 ObjID;
class Container;
enum BlitMode {
kBlitDirect = 0,
kBlitBIC = 1,
kBlitOR = 2,
kBlitXOR = 3
};
enum GraphicsEncoding {
kPPIC0 = 0,
kPPIC1 = 1,
kPPIC2 = 2,
kPPIC3 = 3
};
struct PPICHuff {
uint16 masks[17];
uint16 lens[17];
uint8 symbols[17];
};
class ImageAsset {
public:
ImageAsset(ObjID original, Container *container);
~ImageAsset();
void blitInto(Graphics::ManagedSurface *target, int x, int y, BlitMode mode);
bool isPointInside(Common::Point point);
bool isRectInside(Common::Rect rect);
int getWidth();
int getHeight();
private:
void decodePPIC(ObjID id, Common::Array<byte> &data, uint &bitHeight, uint &bitWidth, uint &rowBytes);
void decodePPIC0(Common::BitStream &stream, Common::Array<byte> &data, uint bitHeight, uint bitWidth, uint rowBytes);
void decodePPIC1(Common::BitStream &stream, Common::Array<byte> &data, uint bitHeight, uint bitWidth, uint rowBytes);
void decodePPIC2(Common::BitStream &stream, Common::Array<byte> &data, uint bitHeight, uint bitWidth, uint rowBytes);
void decodePPIC3(Common::BitStream &stream, Common::Array<byte> &data, uint bitHeight, uint bitWidth, uint rowBytes);
void decodeHuffGraphic(const PPICHuff &huff, Common::BitStream &stream, Common::Array<byte> &data, uint bitHeight, uint bitWidth, uint rowBytes);
byte walkHuff(const PPICHuff &huff, Common::BitStream &stream);
void blitDirect(Graphics::ManagedSurface *target, int ox, int oy, const Common::Array<byte> &data, uint bitHeight, uint bitWidth, uint rowBytes);
void blitBIC(Graphics::ManagedSurface *target, int ox, int oy, const Common::Array<byte> &data, uint bitHeight, uint bitWidth, uint rowBytes);
void blitOR(Graphics::ManagedSurface *target, int ox, int oy, const Common::Array<byte> &data, uint bitHeight, uint bitWidth, uint rowBytes);
void blitXOR(Graphics::ManagedSurface *target, int ox, int oy, const Common::Array<byte> &data, uint bitHeight, uint bitWidth, uint rowBytes);
void calculateSectionToDraw(Graphics::ManagedSurface *target, int &ox, int &oy, uint bitWidth, uint bitHeight, uint &sx, uint &sy, uint &w, uint &h);
void calculateSectionInDirection(uint targetWhole, uint originWhole, int &originPosition, uint &startPosition, uint &blittedWhole);
private:
ObjID _id;
ObjID _mask;
Container *_container;
uint16 _walkRepeat;
uint16 _walkLast;
Common::Array<byte> _imgData;
uint16 _imgRowBytes;
uint16 _imgBitWidth;
uint16 _imgBitHeight;
Common::Array<byte> _maskData;
uint16 _maskRowBytes;
uint16 _maskBitWidth;
uint16 _maskBitHeight;
};
} // End of namespace MacVenture
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,369 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef MACVENTURE_MACVENTURE_H
#define MACVENTURE_MACVENTURE_H
#include "engines/engine.h"
#include "common/scummsys.h"
#include "common/system.h"
#include "common/debug.h"
#include "common/random.h"
#include "common/macresman.h"
#include "common/huffman.h"
#include "common/savefile.h"
#include "gui/debugger.h"
#include "macventure/debug.h"
#include "macventure/gui.h"
#include "macventure/world.h"
#include "macventure/hufflists.h"
#include "macventure/stringtable.h"
#include "macventure/script.h"
#include "macventure/controls.h"
#include "macventure/windows.h"
#include "macventure/sound.h"
struct ADGameDescription;
namespace MacVenture {
class SaveFileManager;
class Console;
class World;
class ScriptEngine;
class SoundManager;
typedef uint32 ObjID;
// HACK, until I find a way to translate correctly
extern void toASCII(Common::String &str);
enum {
kScreenWidth = 512,
kScreenHeight = 342
};
enum {
kGlobalSettingsID = 0x80,
kDiplomaGeometryID = 0x81,
kTextHuffmanTableID = 0x83
};
enum {
kSaveGameStrID = 0x82,
kDiplomaFilenameID = 0x83,
kClickToContinueTextID = 0x84,
kStartGameFilenameID = 0x85
};
enum FilePathID {
kMCVID = 1,
kTitlePathID = 2,
kSubdirPathID = 3,
kObjectPathID = 4,
kFilterPathID = 5,
kTextPathID = 6,
kGraphicPathID = 7,
kSoundPathID = 8
};
class GlobalSettings {
public:
GlobalSettings();
~GlobalSettings();
void loadSettings(Common::SeekableReadStream *dataStream);
// HACK MAybe this should be private, but the class is only here to handle
// memory allocation/deallocation
public:
uint16 _numObjects; // number of game objects defined
uint16 _numGlobals; // number of globals defined
uint16 _numCommands; // number of commands defined
uint16 _numAttributes; // number of attributes
uint16 _numGroups; // number of object groups
uint16 _invTop; // inventory window bounds
uint16 _invLeft;
uint16 _invHeight;
uint16 _invWidth;
uint16 _invOffsetY; // positioning offset for
uint16 _invOffsetX; // new inventory windows
uint16 _defaultFont; // default font
uint16 _defaultSize; // default font size
Common::Array<uint8> _attrIndices; // attribute indices into attribute table
Common::Array<uint16> _attrMasks; // attribute masks
Common::Array<uint8> _attrShifts; // attribute bit shifts
Common::Array<uint8> _cmdArgCnts; // command argument counts
Common::Array<uint8> _commands; // command buttons
};
enum GameState {
kGameStateInit,
kGameStatePlaying,
kGameStateWinnig,
kGameStateLosing,
kGameStateQuitting
};
enum ObjectQueueID {
kFocusWindow = 2,
kOpenWindow = 3,
kCloseWindow = 4,
kUpdateObject = 7,
kUpdateWindow = 8,
kSetToPlayerParent = 12,
kHightlightExits = 13,
kAnimateBack = 14
};
struct QueuedObject {
ObjectQueueID id;
ObjID object;
ObjID parent;
uint x;
uint y;
uint exitx;
uint exity;
bool hidden;
bool offscreen;
bool invisible;
ObjID target; // For swapping
};
enum TextQueueID {
kTextNumber = 1,
kTextNewLine = 2,
kTextPlain = 3
};
struct QueuedText {
TextQueueID id;
ObjID source;
ObjID destination;
ObjID asset;
};
enum SoundQueueID {
kSoundPlay = 1,
kSoundPlayAndWait = 2,
kSoundWait = 3
};
struct QueuedSound {
SoundQueueID id;
ObjID reference;
};
class MacVentureEngine : public Engine {
public:
MacVentureEngine(OSystem *syst, const ADGameDescription *gameDesc);
~MacVentureEngine();
virtual bool hasFeature(EngineFeature f) const;
virtual Common::Error run();
bool scummVMSaveLoadDialog(bool isSave);
bool canLoadGameStateCurrently();
bool canSaveGameStateCurrently();
virtual Common::Error loadGameState(int slot);
virtual Common::Error saveGameState(int slot, const Common::String &desc);
void newGame();
void setInitialFlags();
void setNewGameState();
void initDebugChannels();
void reset();
void resetInternals();
void resetGui();
void refreshScreen();
// datafiles.cpp
void loadDataBundle();
Common::SeekableReadStream *getBorderFile(MVWindowType windowType, bool isActive);
void requestQuit();
void requestUnpause();
void selectControl(ControlAction action);
void refreshReady();
void preparedToRun();
void gameChanged();
void winGame();
void loseGame();
void clickToContinue();
void updateState(bool pause);
void revert();
void enqueueObject(ObjectQueueID type, ObjID objID, ObjID target = 0);
void enqueueText(TextQueueID type, ObjID target, ObjID source, ObjID text);
void enqueueSound(SoundQueueID type, ObjID target);
void runObjQueue();
void printTexts();
void playSounds(bool pause);
void handleObjectSelect(ObjID objID, WindowReference win, bool shiftPressed, bool isDoubleClick);
void handleObjectDrop(ObjID objID, Common::Point delta, ObjID newParent);
void setDeltaPoint(Common::Point newPos);
void focusObjWin(ObjID objID);
void updateWindow(WindowReference winID);
bool showTextEntry(ObjID text, ObjID srcObj, ObjID destObj);
void setTextInput(Common::String content);
Common::String getUserInput();
// Data retrieval
Common::String getStartGameFileName();
bool isPaused();
bool needsClickToContinue();
Common::String getCommandsPausedString() const;
const GlobalSettings &getGlobalSettings() const;
Common::String getFilePath(FilePathID id) const;
bool isOldText() const;
const HuffmanLists *getDecodingHuffman() const;
uint32 randBetween(uint32 min, uint32 max);
uint32 getInvolvedObjects();
int findObjectInArray(ObjID objID, const Common::Array<ObjID> &list);
uint getPrefixNdx(ObjID obj);
Common::String getPrefixString(uint flag, ObjID obj);
Common::String getNoun(ObjID ndx);
// Attributes consult
Common::Point getObjPosition(ObjID objID);
bool isObjVisible(ObjID objID);
bool isObjClickable(ObjID objID);
bool isObjSelected(ObjID objID);
bool isObjExit(ObjID objID);
bool isHiddenExit(ObjID objID);
Common::Point getObjExitPosition(ObjID objID);
ObjID getParent(ObjID objID);
// Utils
ControlAction referenceToAction(ControlType id);
// Encapsulation HACK
Common::Rect getObjBounds(ObjID objID);
uint getOverlapPercent(ObjID one, ObjID other);
WindowReference getObjWindow(ObjID objID);
WindowReference findParentWindow(ObjID objID);
Common::Point getDeltaPoint();
ObjID getDestObject();
ControlAction getSelectedControl();
private:
void processEvents();
bool runScriptEngine();
void endGame();
void updateControls();
void resetVars();
void unselectAll();
void selectObject(ObjID objID);
void unselectObject(ObjID objID);
void highlightExit(ObjID objID);
void selectPrimaryObject(ObjID objID);
void updateExits();
// Object queue methods
void focusObjectWindow(ObjID objID);
void openObject(ObjID objID);
void closeObject(ObjID objID);
void checkObject(QueuedObject objID);
void reflectSwap(ObjID fromID, ObjID toID);
void toggleExits();
void zoomObject(ObjID objID);
bool isObjEnqueued(ObjID obj);
bool isGameRunning();
// Data loading
bool loadGlobalSettings();
bool loadTextHuffman();
const char *getGameFileName() const;
private: // Attributes
const ADGameDescription *_gameDescription;
Common::RandomSource *_rnd;
Common::MacResManager *_resourceManager;
Console *_debugger;
Gui *_gui;
World *_world;
ScriptEngine *_scriptEngine;
// String tables
StringTable *_filenames;
StringTable *_decodingDirectArticles;
StringTable *_decodingNamingArticles;
StringTable *_decodingIndirectArticles;
SoundManager *_soundManager;
Common::Archive *_dataBundle;
// Engine state
GameState _gameState;
GlobalSettings *_globalSettings;
HuffmanLists *_textHuffman;
bool _oldTextEncoding;
bool _paused, _halted, _cmdReady, _prepared;
bool _haltedAtEnd, _haltedInSelection;
bool _gameChanged;
bool _clickToContinue;
Common::Array<QueuedObject> _objQueue;
Common::Array<QueuedObject> _inQueue;
Common::Array<QueuedSound> _soundQueue;
Common::Array<QueuedText> _textQueue;
// Selections
ObjID _destObject;
ControlAction _selectedControl;
Common::Array<ObjID> _currentSelection;
Common::Point _deltaPoint;
Common::String _userInput;
};
class Console : public GUI::Debugger {
public:
Console(MacVentureEngine *vm) {}
virtual ~Console(void) {}
};
} // End of namespace MacVenture
#endif

View File

@ -0,0 +1,31 @@
MODULE := engines/macventure
MODULE_OBJS := \
container.o \
controls.o \
cursor.o \
datafiles.o \
detection.o \
dialog.o \
gui.o \
image.o \
macventure.o \
prebuilt_dialogs.o \
saveload.o \
script.o \
sound.o \
text.o \
windows.o \
world.o
MODULE_DIRS += \
engines/macventure
# This module can be built as a plugin
ifeq ($(ENABLE_MACVENTURE), DYNAMIC_PLUGIN)
PLUGIN := 1
endif
# Include common rules
include $(srcdir)/rules.mk

View File

@ -0,0 +1,76 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "macventure/prebuilt_dialogs.h"
namespace MacVenture {
const PrebuiltDialog g_prebuiltDialogs[kPrebuiltDialogCount] = {
{/* kSaveAsDialog */
{0, 146, 456, 254},
{
{kDEButton, "YES", kDASaveAs, 24, 68, 120, 22},
{kDEButton, "NO", kDACloseDialog, 168, 68, 120, 22},
{kDEButton, "CANCEL", kDACloseDialog, 312, 68, 120, 22},
{kDEPlainText, "Save As...", kDANone, 100, 10, 340, 38},
{kDETextInput, "", kDANone, 100, 30, 340, 20},
{kDEEnd, "", kDANone, 0, 0, 0, 0}
}
},
{ /* kSpeakDialog */
{20, 92, 400, 200},
{
{kDEButton, "OK", kDASubmit, 10, 70, 50, 20},
{kDEButton, "CANCEL", kDACloseDialog, 96, 70, 50, 20},
{kDEPlainText, "What would you like to say?", kDANone, 10, 10, 400, 20},
{kDETextInput, "", kDANone, 10, 25, 350, 40},
{kDEEnd, "", kDANone, 0, 0, 0, 0}
}
},
{ /* kWinGameDialog */
{20, 100, 320, 200},
{
{kDEPlainText, "You Won!", kDANone, 20, 16, 280, 20},
{kDEPlainText, "What do you want to do?", kDANone, 20, 30, 280, 20},
{kDEButton, "New Game", kDANewGame, 20, 60, 70, 20},
{kDEButton, "Load", kDALoadGame, 110, 60, 70, 20},
{kDEButton, "Quit", kDAQuit, 200, 60, 70, 20},
{kDEEnd, "", kDANone, 0, 0, 0, 0}
}
},
{ /* kLoseGameDialog */
{20, 100, 320, 200},
{
{kDEPlainText, "You Died", kDANone, 20, 16, 280, 20},
{kDEPlainText, "What do you want to do?", kDANone, 20, 30, 280, 20},
{kDEButton, "New Game", kDANewGame, 20, 60, 70, 20},
{kDEButton, "Load", kDALoadGame, 110, 60, 70, 20},
{kDEButton, "Quit", kDAQuit, 200, 60, 70, 20},
{kDEEnd, "", kDANone, 0, 0, 0, 0}
}
}
};
} // End of namespace MacVenture

View File

@ -0,0 +1,87 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef MACVENTURE_PREBUIT_DIALOGS_H
#define MACVENTURE_PREBUIT_DIALOGS_H
#include "common/rect.h"
namespace MacVenture {
enum DialogAction {
kDANone,
kDACloseDialog,
kDASubmit,
kDASaveAs,
kDALoadGame,
kDAQuit,
kDANewGame
};
enum PrebuiltDialogs {
kSaveAsDialog = 0, //TODO: Currently unused, we are using ScummVM dialogs instead.
kSpeakDialog = 1,
kWinGameDialog = 2,
kLoseGameDialog = 3,
kPrebuiltDialogCount
};
enum PrebuiltElementType {
kDEPlainText,
kDEButton,
kDETextInput,
kDEEnd
};
struct PrebuiltDialogBounds {
uint left;
uint top;
uint right;
uint bottom;
};
struct PrebuiltDialogElement {
PrebuiltElementType type;
const char *title;
DialogAction action;
uint left;
uint top;
uint width;
uint height;
};
// Prebuilt dialogs
enum {
// HACK
kMaxPrebuiltDialogElements = 10
};
struct PrebuiltDialog {
PrebuiltDialogBounds bounds;
PrebuiltDialogElement elements[kMaxPrebuiltDialogElements];
};
extern const PrebuiltDialog g_prebuiltDialogs[];
} // End of namespace MacVenture
#endif

View File

@ -0,0 +1,197 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "macventure/macventure.h"
#include "common/error.h"
#include "common/savefile.h"
#include "engines/savestate.h"
#include "gui/saveload.h"
#include "graphics/thumbnail.h"
namespace MacVenture {
#define MACVENTURE_SAVE_HEADER MKTAG('M', 'V', 'S', 'S') // (M)ac(V)enture (S)cummVM (S)ave (0x4d565353, uint32)
#define MACVENTURE_SAVE_VERSION 1 //1 BYTE
#define MACVENTURE_DESC_LENGTH 4 //4 BYTE for the metadata length
SaveStateDescriptor loadMetaData(Common::SeekableReadStream *s, int slot) {
// Metadata is stored at the end of the file
// |THUMBNAIL |
// | |
// |DESCSIZE| DESCRIPTION |
// |HEADER |VERSION|DESCLEN|
s->seek(-(5 + MACVENTURE_DESC_LENGTH), SEEK_END);
uint32 sig = s->readUint32BE();
byte version = s->readByte();
SaveStateDescriptor desc(-1, ""); // init to an invalid save slot
if (sig != MACVENTURE_SAVE_HEADER || version > MACVENTURE_SAVE_VERSION)
return desc;
// Save is valid, set its slot number
desc.setSaveSlot(slot);
// Depends on MACVENTURE_DESC_LENGTH
uint32 metaSize = s->readUint32BE();
s->seek(-(5 + MACVENTURE_DESC_LENGTH + metaSize), SEEK_END);
// Load the thumbnail
Graphics::Surface *thumb = Graphics::loadThumbnail(*s);
desc.setThumbnail(thumb);
// Load the description
Common::String name;
uint32 descSize = s->readUint32BE();
for (uint32 i = 0; i < descSize; ++i) {
name += s->readByte();
}
desc.setDescription(name);
// Load date
uint32 saveDate = s->readUint32LE();
int day = (saveDate >> 24) & 0xFF;
int month = (saveDate >> 16) & 0xFF;
int year = saveDate & 0xFFFF;
desc.setSaveDate(year, month, day);
uint16 saveTime = s->readUint16LE();
int hour = (saveTime >> 8) & 0xFF;
int minutes = saveTime & 0xFF;
desc.setSaveTime(hour, minutes);
// Load playtime
uint32 playTime = s->readUint32LE();
desc.setPlayTime(playTime * 1000);
return desc;
}
uint saveCurrentDate(Common::OutSaveFile *file) {
TimeDate curTime;
g_system->getTimeAndDate(curTime);
uint32 saveDate = ((curTime.tm_mday & 0xFF) << 24) | (((curTime.tm_mon + 1) & 0xFF) << 16) | ((curTime.tm_year + 1900) & 0xFFFF);
uint16 saveTime = ((curTime.tm_hour & 0xFF) << 8) | ((curTime.tm_min) & 0xFF);
file->writeUint32LE(saveDate);
file->writeUint16LE(saveTime);
// Return the number of bytes occupied
return 6;
}
uint savePlayTime(Common::OutSaveFile *file) {
uint32 playTime = g_engine->getTotalPlayTime() / 1000;
file->writeUint32LE(playTime);
// Return the number of bytes occupied
return 4;
}
void writeMetaData(Common::OutSaveFile *file, Common::String desc) {
// Write thumbnail
uint thumbSize = file->pos();
Graphics::saveThumbnail(*file);
thumbSize = file->pos() - thumbSize;
// Write description
file->writeUint32BE(desc.size());
file->writeString(desc);
uint dateSize = saveCurrentDate(file);
uint playTimeSize = savePlayTime(file);
file->writeUint32BE(MACVENTURE_SAVE_HEADER);
file->writeByte(MACVENTURE_SAVE_VERSION);
file->writeUint32BE(4 + desc.size() + dateSize + playTimeSize + thumbSize);
}
Common::Error MacVentureEngine::loadGameState(int slot) {
Common::String saveFileName = Common::String::format("%s.%03d", _targetName.c_str(), slot);
Common::InSaveFile *file;
if(!(file = getSaveFileManager()->openForLoading(saveFileName))) {
error("ENGINE: Missing savegame file %s", saveFileName.c_str());
}
_world->loadGameFrom(file);
reset();
return Common::kNoError;
}
Common::Error MacVentureEngine::saveGameState(int slot, const Common::String &desc) {
Common::String saveFileName = Common::String::format("%s.%03d", _targetName.c_str(), slot);
Common::SaveFileManager *manager = getSaveFileManager();
// HACK Get a real name!
Common::OutSaveFile *file = manager->openForSaving(saveFileName);
_world->saveGameInto(file);
writeMetaData(file, desc);
file->finalize();
if (file->err()) {
warning("Could not save '%s' correctly.", saveFileName.c_str());
}
delete file;
return Common::kNoError;
}
bool MacVentureEngine::scummVMSaveLoadDialog(bool isSave) {
if (!isSave) {
// do loading
GUI::SaveLoadChooser dialog = GUI::SaveLoadChooser(Common::String("Load game:"), Common::String("Load"), false);
int slot = dialog.runModalWithCurrentTarget();
if (slot < 0)
return true;
return loadGameState(slot).getCode() == Common::kNoError;
}
// do saving
GUI::SaveLoadChooser dialog = GUI::SaveLoadChooser(Common::String("Save game:"), Common::String("Save"), true);
int slot = dialog.runModalWithCurrentTarget();
Common::String desc = dialog.getResultString();
if (desc.empty()) {
// create our own description for the saved game, the user didnt enter it
desc = dialog.createDefaultSaveDescription(slot);
}
/*
if (desc.size() > (1 << MACVENTURE_DESC_LENGTH * 8) - 1)
desc = Common::String(desc.c_str(), (1 << MACVENTURE_DESC_LENGTH * 8) - 1);
*/
if (slot < 0)
return true;
return saveGameState(slot, desc).getCode() == Common::kNoError;
}
bool MacVentureEngine::canLoadGameStateCurrently() {
return true;
}
bool MacVentureEngine::canSaveGameStateCurrently() {
return true;
}
} // End of namespace MacVenture

File diff suppressed because it is too large Load Diff

285
engines/macventure/script.h Normal file
View File

@ -0,0 +1,285 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef MACVENTURE_SCRIPT_H
#define MACVENTURE_SCRIPT_H
#include "macventure/container.h"
#include "macventure/world.h"
#include "macventure/macventure.h"
#include "macventure/controls.h"
namespace MacVenture {
class Container;
class World;
typedef uint32 ObjID;
class ScriptAsset {
public:
ScriptAsset(ObjID id, Container *container);
~ScriptAsset() {}
void reset();
uint8 fetch();
bool hasNext();
void branch(int16 amount);
ObjID getId();
private:
void loadInstructions();
private:
ObjID _id;
Container *_container;
Common::Array<uint8> _instructions;
uint32 _ip; // Instruction pointer
};
class EngineState {
public:
EngineState() {
clear();
}
void push(int16 data) {
sp--;
stack[sp] = unneg16(data);
}
int16 pop() {
int16 v = stack[sp];
sp++;
return v;
}
int16 peek(int16 off) {
return stack[sp + off];
}
void poke(int16 off, int16 val) {
stack[sp + off] = unneg16(val);
}
void clear() {
sp = 0x80;
for (int i = 0; i < sp; i++) {
stack[i] = 0;
}
}
int16 size() {
return 0x80 - sp;
}
private:
int16 unneg16(int16 data) {
if (data < 0)
data = ((-data) ^ 0xFFFF) + 1;
return data;
}
private:
int16 stack[0x80];
int16 sp;
};
struct FunCall {
int16 func;
int16 rank;
FunCall(int16 f, int16 r) {
func = f;
rank = r;
}
};
struct EngineFrame {
ControlAction action;
ObjID src;
ObjID dest;
int x;
int y;
EngineState state;
Common::List<ScriptAsset> scripts;
Common::Array<FunCall> saves;
uint32 familyIdx;
bool haltedInFirst;
bool haltedInFamily;
bool haltedInSaves;
};
class ScriptEngine {
public:
ScriptEngine(MacVentureEngine *engine, World *world);
~ScriptEngine();
public:
bool runControl(ControlAction action, ObjID source, ObjID destination, Common::Point delta);
bool resume(bool execAll);
void reset();
private:
bool execFrame(bool execAll);
bool loadScript(EngineFrame *frame, uint32 scriptID);
bool resumeFunc(EngineFrame *frame);
bool runFunc(EngineFrame *frame);
private:
// Aux
int16 neg16(int16 val);
int16 neg8(int16 val);
int16 sumChildrenAttr(int16 obj, int16 attr, bool recursive);
void ensureNonzeroDivisor(int16 divisor, byte opcode);
// Opcodes
void op80GATT(EngineState *state, EngineFrame *frame); //get attribute
void op81SATT(EngineState *state, EngineFrame *frame); //set attribute
void op82SUCH(EngineState *state, EngineFrame *frame); //sum children attribute
void op83PUCT(EngineState *state, EngineFrame *frame); //push selected control
void op84PUOB(EngineState *state, EngineFrame *frame); //push selected object
void op85PUTA(EngineState *state, EngineFrame *frame); //push target
void op86PUDX(EngineState *state, EngineFrame *frame); //push deltax
void op87PUDY(EngineState *state, EngineFrame *frame); //push deltay
void op88PUIB(EngineState *state, EngineFrame *frame, ScriptAsset *script);//push immediate.b
void op89PUI(EngineState *state, EngineFrame *frame, ScriptAsset *script);//push immediate
void op8aGGLO(EngineState *state, EngineFrame *frame); //get global
void op8bSGLO(EngineState *state, EngineFrame *frame); //set global
void op8cRAND(EngineState *state, EngineFrame *frame); //random
void op8dCOPY(EngineState *state, EngineFrame *frame); //copy
void op8eCOPYN(EngineState *state, EngineFrame *frame); //copyn
void op8fSWAP(EngineState *state, EngineFrame *frame); //swap
void op90SWAPN(EngineState *state, EngineFrame *frame); //swapn
void op91POP(EngineState *state, EngineFrame *frame); //pop
void op92COPYP(EngineState *state, EngineFrame *frame); //copy+1
void op93COPYPN(EngineState *state, EngineFrame *frame);//copy+n
void op94SHUFF(EngineState *state, EngineFrame *frame); //shuffle
void op95SORT(EngineState *state, EngineFrame *frame); //sort
void op96CLEAR(EngineState *state, EngineFrame *frame); //clear stack
void op97SIZE(EngineState *state, EngineFrame *frame); //get stack size
void op98ADD(EngineState *state, EngineFrame *frame); //add
void op99SUB(EngineState *state, EngineFrame *frame); //subtract
void op9aMUL(EngineState *state, EngineFrame *frame); //multiply
void op9bDIV(EngineState *state, EngineFrame *frame); //divide
void op9cMOD(EngineState *state, EngineFrame *frame); //mod
void op9dDMOD(EngineState *state, EngineFrame *frame); //divmod
void op9eABS(EngineState *state, EngineFrame *frame); //abs
void op9fNEG(EngineState *state, EngineFrame *frame); //neg
void opa0AND(EngineState *state, EngineFrame *frame); //and
void opa1OR(EngineState *state, EngineFrame *frame); //or
void opa2XOR(EngineState *state, EngineFrame *frame); //xor
void opa3NOT(EngineState *state, EngineFrame *frame); //not
void opa4LAND(EngineState *state, EngineFrame *frame); //logical and
void opa5LOR(EngineState *state, EngineFrame *frame); //logical or
void opa6LXOR(EngineState *state, EngineFrame *frame); //logical xor
void opa7LNOT(EngineState *state, EngineFrame *frame); //logical not
void opa8GTU(EngineState *state, EngineFrame *frame); //gt? unsigned
void opa9LTU(EngineState *state, EngineFrame *frame); //lt? unsigned
void opaaGTS(EngineState *state, EngineFrame *frame); //gt? signed
void opabLTS(EngineState *state, EngineFrame *frame); //lt? signed
void opacEQ(EngineState *state, EngineFrame *frame); //eq?
void opadEQS(EngineState *state, EngineFrame *frame); //eq string?
void opaeCONT(EngineState *state, EngineFrame *frame); //contains
void opafCONTW(EngineState *state, EngineFrame *frame); //contains word
void opb0BRA(EngineState *state, EngineFrame *frame, ScriptAsset *script); //bra
void opb1BRAB(EngineState *state, EngineFrame *frame, ScriptAsset *script); //bra.b
void opb2BEQ(EngineState *state, EngineFrame *frame, ScriptAsset *script); //beq
void opb3BEQB(EngineState *state, EngineFrame *frame, ScriptAsset *script); //beq.b
void opb4BNE(EngineState *state, EngineFrame *frame, ScriptAsset *script); //bne
void opb5BNEB(EngineState *state, EngineFrame *frame, ScriptAsset *script); //bne.b
void opb6CLAT(EngineState *state, EngineFrame *frame); //call later
void opb7CCA(EngineState *state, EngineFrame *frame); //cancel call
void opb8CLOW(EngineState *state, EngineFrame *frame); //cancel low priority
void opb9CHI(EngineState *state, EngineFrame *frame); //cancel high priority
void opbaCRAN(EngineState *state, EngineFrame *frame); //cancel priority range
bool opbbFORK(EngineState *state, EngineFrame *frame); //fork
bool opbcCALL(EngineState *state, EngineFrame *frame, ScriptAsset &script); //call
void opbdFOOB(EngineState *state, EngineFrame *frame); //focus object
void opbeSWOB(EngineState *state, EngineFrame *frame); //swap objects
void opbfSNOB(EngineState *state, EngineFrame *frame); //snap object
void opc0TEXI(EngineState *state, EngineFrame *frame); //toggle exits
void opc1PTXT(EngineState *state, EngineFrame *frame); //print text
void opc2PNEW(EngineState *state, EngineFrame *frame); //print newline
void opc3PTNE(EngineState *state, EngineFrame *frame); //print text+nl
void opc4PNTN(EngineState *state, EngineFrame *frame); //print nl+text+nl
void opc5PNUM(EngineState *state, EngineFrame *frame); //print number
void opc6P2(EngineState *state, EngineFrame *frame); //push 2
void opc7PLBG(EngineState *state, EngineFrame *frame); //play sound in background
void opc8PLAW(EngineState *state, EngineFrame *frame); //play sound and wait
void opc9WAIT(EngineState *state, EngineFrame *frame); //wait for sound to finish?
void opcaTIME(EngineState *state, EngineFrame *frame); //get current time
void opcbDAY(EngineState *state, EngineFrame *frame); //get current day
void opccCHLD(EngineState *state, EngineFrame *frame); //get children
void opcdNCHLD(EngineState *state, EngineFrame *frame); //get num children
void opceVERS(EngineState *state, EngineFrame *frame); //get engine version
void opcfPSCE(EngineState *state, EngineFrame *frame); //push scenario number
void opd0P1(EngineState *state, EngineFrame *frame); //push 1
void opd1GOBD(EngineState *state, EngineFrame *frame); //get object dimensions
void opd2GOVP(EngineState *state, EngineFrame *frame); //get overlap percent
void opd3CAPC(EngineState *state, EngineFrame *frame); //capture children
void opd4RELC(EngineState *state, EngineFrame *frame); //release children
void opd5DLOG(EngineState *state, EngineFrame *frame); //show speech dialog
void opd6ACMD(EngineState *state, EngineFrame *frame); //activate command
void opd7LOSE(EngineState *state, EngineFrame *frame); //lose game
void opd8WIN(EngineState *state, EngineFrame *frame); //win game
void opd9SLEEP(EngineState *state, EngineFrame *frame); //sleep
void opdaCLICK(EngineState *state, EngineFrame *frame); //click to continue
void opdbROBQ(EngineState *state, EngineFrame *frame); //run queue
void opdcRSQ(EngineState *state, EngineFrame *frame); //run sound queue
void opddRTQ(EngineState *state, EngineFrame *frame); //run text queue
void opdeUPSC(EngineState *state, EngineFrame *frame); //update screen
void opdfFMAI(EngineState *state, EngineFrame *frame); //flash main window
void ope0CHGR(EngineState *state, EngineFrame *frame); //cache graphic and object
void ope1CHSO(EngineState *state, EngineFrame *frame); //cache sound
void ope2MDIV(EngineState *state, EngineFrame *frame); //muldiv
void ope3UPOB(EngineState *state, EngineFrame *frame); //update object
void ope4PLEV(EngineState *state, EngineFrame *frame); //currently playing event?
void ope5WEV(EngineState *state, EngineFrame *frame); //wait for event to finish
void ope6GFIB(EngineState *state, EngineFrame *frame); //get fibonacci (joke)
void ope7CFIB(EngineState *state, EngineFrame *frame); //calc fibonacci
void op00NOOP(byte op);
private:
MacVentureEngine *_engine;
World *_world;
Common::List<EngineFrame> _frames;
Container *_scripts;
};
} // End of namespace MacVenture
#endif

View File

@ -0,0 +1,282 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "macventure/sound.h"
#include "audio/mixer.h"
#include "audio/audiostream.h"
#include "audio/decoders/raw.h"
namespace MacVenture {
// SoundManager
SoundManager::SoundManager(MacVentureEngine *engine, Audio::Mixer *mixer) {
_container = NULL;
Common::String filename = engine->getFilePath(kSoundPathID);
_container = new Container(filename);
_mixer = mixer;
debugC(1, kMVDebugSound, "Created sound manager with file %s", filename.c_str());
}
SoundManager::~SoundManager() {
if (_container)
delete _container;
Common::HashMap<ObjID, SoundAsset*>::iterator it;
Common::HashMap<ObjID, SoundAsset*>::iterator end = _assets.end();
for (it = _assets.begin(); it != end; it++) {
delete it->_value;
}
}
uint32 SoundManager::playSound(ObjID sound) {
ensureLoaded(sound);
_assets[sound]->play(_mixer, &_handle);
return _assets[sound]->getPlayLength();
}
void SoundManager::ensureLoaded(ObjID sound) {
if (!_assets.contains(sound))
_assets[sound] = new SoundAsset(_container, sound);
}
SoundAsset::SoundAsset(Container *container, ObjID id) :
_container(container), _id(id), _length(0), _frequency(1) {
if (_container->getItemByteSize(_id) == 0)
warning("Trying to load an empty sound asset (%d).", _id);
Common::SeekableReadStream *stream = _container->getItem(_id);
stream->seek(5, SEEK_SET);
SoundType type = (SoundType)stream->readByte();
debugC(2, kMVDebugSound, "Decoding sound of type %x", type);
switch(type) {
case kSound10:
decode10(stream);
break;
case kSound12:
decode12(stream);
break;
case kSound18:
decode18(stream);
break;
case kSound1a:
decode1a(stream);
break;
case kSound44:
decode44(stream);
break;
case kSound78:
decode78(stream);
break;
case kSound7e:
decode7e(stream);
break;
default:
warning("Unrecognized sound type: %x", type);
break;
}
delete stream;
}
SoundAsset::~SoundAsset() {
debugC(3, kMVDebugSound, "~SoundAsset(%d)", _id);
}
void SoundAsset::play(Audio::Mixer *mixer, Audio::SoundHandle *soundHandle) {
if (_data.size() == 0) {
return;
}
Audio::AudioStream *sound = Audio::makeRawStream(&_data.front(), _length, _frequency, Audio::FLAG_UNSIGNED, DisposeAfterUse::NO);
mixer->playStream(Audio::Mixer::kPlainSoundType, soundHandle, sound);
}
uint32 SoundAsset::getPlayLength() {
// Transform to milliseconds
return _length * 1000 / _frequency;
}
void SoundAsset::decode10(Common::SeekableReadStream *stream) {
warning("Decode sound 0x10 untested");
Common::Array<byte> wavtable;
stream->seek(0x198, SEEK_SET);
for (uint i = 0; i < 16; i++) {
wavtable.push_back(stream->readByte());
}
_length = stream->readUint32BE() * 2;
//Unused
stream->readUint16BE();
_frequency = (stream->readUint32BE() * 22100 / 0x10000);
byte ch = 0;
for (uint i = 0; i < _length; i++) {
if (i & 1) {
ch >>= 4;
} else {
ch = stream->readByte();
}
_data.push_back(wavtable[ch & 0xf]);
}
}
void SoundAsset::decode12(Common::SeekableReadStream *stream) {
warning("Decode sound 0x12 untested");
stream->seek(0xc, SEEK_SET);
uint32 repeat = stream->readUint16BE();
stream->seek(0x34, SEEK_SET);
uint32 base = stream->readUint16BE() + 0x34;
stream->seek(base, SEEK_SET);
_length = stream->readUint32BE() - 6;
stream->readUint16BE();
_frequency = (stream->readUint32BE() * 22100 / 0x10000);
stream->seek(0xe2, SEEK_SET);
// TODO: Possible source of bugs, the original just assigns the seek to the scales
uint32 scales = stream->pos() + 0xe2;
for (uint i = 0; i < repeat; i++) {
stream->seek(scales + i * 2, SEEK_SET);
uint32 scale = stream->readUint16BE();
stream->seek(base + 0xa, SEEK_SET);
for (uint j = 0; j < _length; j++) {
byte ch = stream->readByte();
if (ch & 0x80) {
ch -= 0x80;
uint32 env = ch * scale;
ch = (env >> 8) & 0xff;
if (ch & 0x80) {
ch = 0x7f;
}
ch += 0x80;
} else {
ch = (ch ^ 0xff) + 1;
ch -= 0x80;
uint32 env = ch * scale;
ch = (env >> 8) & 0xff;
if (ch & 0x80) {
ch = 0x7f;
}
ch += 0x80;
ch = (ch ^ 0xff) + 1;
}
_data.push_back(ch);
}
}
}
void SoundAsset::decode18(Common::SeekableReadStream *stream) {
warning("Decode sound 0x18 untested");
Common::Array<byte> wavtable;
stream->seek(0x252, SEEK_SET);
for (uint i = 0; i < 16; i++) {
wavtable.push_back(stream->readByte());
}
_length = stream->readUint32BE() * 2;
//Unused
stream->readUint16BE();
// TODO: It had `| 0` at the end of this line, possible source of bugs.
_frequency = (stream->readUint32BE() * 22100 / 0x10000);
byte ch = 0;
for (uint i = 0; i < _length; i++) {
if (i & 1) {
ch >>= 4;
} else {
ch = stream->readByte();
}
_data.push_back(wavtable[ch & 0xf]);
}
}
void SoundAsset::decode1a(Common::SeekableReadStream *stream) {
warning("Decode sound 0x1a untested");
Common::Array<byte> wavtable;
stream->seek(0x220, SEEK_SET);
for (uint i = 0; i < 16; i++) {
wavtable.push_back(stream->readByte());
}
_length = stream->readUint32BE();
//Unused
stream->readUint16BE();
_frequency = (stream->readUint32BE() * 22100 / 0x10000);
byte ch = 0;
for (uint i = 0; i < _length; i++) {
if (i & 1) {
ch >>= 4;
} else {
ch = stream->readByte();
}
_data.push_back(wavtable[ch & 0xf]);
}
}
void SoundAsset::decode44(Common::SeekableReadStream *stream) {
stream->seek(0x5e, SEEK_SET);
_length = stream->readUint32BE();
_frequency = (stream->readUint32BE() * 22100 / 0x10000);
for (uint i = 0; i < _length; i++) {
_data.push_back(stream->readByte());
}
}
void SoundAsset::decode78(Common::SeekableReadStream *stream) {
Common::Array<byte> wavtable;
stream->seek(0xba, SEEK_SET);
for (uint i = 0; i < 16; i++) {
wavtable.push_back(stream->readByte());
}
//Unused
stream->readUint32BE();
_length = stream->readUint32BE();
_frequency = (stream->readUint32BE() * 22100 / 0x10000);
byte ch = 0;
for (uint i = 0; i < _length; i++) {
if (i & 1) {
ch <<= 4;
} else {
ch = stream->readByte();
}
_data.push_back(wavtable[(ch >> 4) & 0xf]);
}
}
void SoundAsset::decode7e(Common::SeekableReadStream *stream) {
Common::Array<byte> wavtable;
stream->seek(0xc2, SEEK_SET);
for (uint i = 0; i < 16; i++) {
wavtable.push_back(stream->readByte());
}
//Unused
stream->readUint32BE();
_length = stream->readUint32BE();
_frequency = (stream->readUint32BE() * 22100 / 0x10000);
uint32 last = 0x80;
byte ch = 0;
for (uint i = 0; i < _length; i++) {
if (i & 1) {
ch <<= 4;
} else {
ch = stream->readByte();
}
last += wavtable[(ch >> 4) & 0xf];
_data.push_back(last & 0xff);
}
}
} //End of namespace MacVenture

View File

@ -0,0 +1,95 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef MACVENTURE_SOUND_H
#define MACVENTURE_SOUND_H
#include "macventure/macventure.h"
#include "macventure/container.h"
#include "common/file.h"
#include "common/hashmap.h"
#include "audio/mixer.h"
namespace MacVenture {
enum SoundType {
kSound10 = 0x10,
kSound12 = 0x12,
kSound18 = 0x18,
kSound1a = 0x1a,
kSound44 = 0x44,
kSound78 = 0x78,
kSound7e = 0x7e
};
class SoundAsset {
public:
SoundAsset(Container *container, ObjID id);
~SoundAsset();
void play(Audio::Mixer *mixer, Audio::SoundHandle *soundHandle);
uint32 getPlayLength();
private:
void decode10(Common::SeekableReadStream *stream);
void decode12(Common::SeekableReadStream *stream);
void decode18(Common::SeekableReadStream *stream);
void decode1a(Common::SeekableReadStream *stream);
void decode44(Common::SeekableReadStream *stream);
void decode78(Common::SeekableReadStream *stream);
void decode7e(Common::SeekableReadStream *stream);
private:
Container *_container;
ObjID _id;
Common::Array<byte> _data;
uint32 _length;
uint32 _frequency;
};
class SoundManager {
public:
SoundManager(MacVentureEngine *engine, Audio::Mixer *mixer);
~SoundManager();
uint32 playSound(ObjID sound);
private:
void ensureLoaded(ObjID sound);
private:
Container *_container;
Common::HashMap<ObjID, SoundAsset*> _assets;
Audio::SoundHandle _handle;
Audio::Mixer *_mixer;
};
} // End of namespace MacVenture
#endif

View File

@ -0,0 +1,109 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef MACVENTURE_STRINGTABLE_H
#define MACVENTURE_STRINGTABLE_H
#include "macventure/macventure.h"
#include "common/file.h"
namespace MacVenture {
extern void toASCII(Common::String &str);
enum StringTableID {
kErrorStringTableID = 0x80,
kFilenamesStringTableID = 0x81,
kCommonArticlesStringTableID = 0x82,
kNamingArticlesStringTableID = 0x83,
kIndirectArticlesStringTableID = 0x84
};
class StringTable {
public:
StringTable(MacVentureEngine *engine, Common::MacResManager *resMan, StringTableID id) {
_engine = engine;
_resourceManager = resMan;
_id = id;
if (!loadStrings())
error("ENGINE: Could not load string table %x", id);
}
~StringTable() {
}
const Common::Array<Common::String> &getStrings() {
return _strings;
}
Common::String getString(uint ndx) {
assert(ndx < _strings.size());
return _strings[ndx];
}
private:
bool loadStrings() {
Common::MacResIDArray resArray;
Common::SeekableReadStream *res;
if ((resArray = _resourceManager->getResIDArray(MKTAG('S', 'T', 'R', '#'))).size() == 0)
return false;
res = _resourceManager->getResource(MKTAG('S', 'T', 'R', '#'), _id);
_strings.push_back("dummy"); // String tables are 1-indexed
uint16 numStrings = res->readUint16BE();
uint8 strLength = 0;
for (uint i = 0; i < numStrings; ++i) {
strLength = res->readByte();
char *str = new char[strLength + 1];
res->read(str, strLength);
str[strLength] = '\0';
// HACK until a proper special char implementation is found, this will have to do.
Common::String result = Common::String(str);
toASCII(result);
debugC(4, kMVDebugText, "Loaded string %s", str);
_strings.push_back(Common::String(result));
delete[] str;
}
delete res;
return true;
}
private:
MacVentureEngine *_engine;
Common::MacResManager *_resourceManager;
StringTableID _id;
Common::Array<Common::String> _strings;
};
} // End of namespace MacVenture
#endif

201
engines/macventure/text.cpp Normal file
View File

@ -0,0 +1,201 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "macventure/text.h"
namespace MacVenture {
TextAsset::TextAsset(MacVentureEngine *engine, ObjID objid, ObjID source, ObjID target, Container *container, bool isOld, const HuffmanLists *huffman) {
_id = objid;
_sourceObj = source;
_targetObj = target;
_container = container;
_huffman = huffman;
_isOld = isOld;
_engine = engine;
if (_isOld) {
decodeOld();
} else {
decodeHuffman();
}
}
void TextAsset::decodeOld() {
Common::SeekableReadStream *res = _container->getItem(_id);
uint16 strLen = res->readUint16BE();
Common::BitStream32BELSB stream(res, true);
char *str = new char[strLen + 1];
bool lowercase = false;
char c;
for (uint16 i = 0; i < strLen; i++) {
char val = stream.getBits(5);
if (val == 0x0) { // Space
c = ' ';
} else if (val >= 0x1 && val <= 0x1A) {
if (lowercase) { // Ascii a-z
c = val + 0x60;
} else { // Ascii A-Z
c = val + 0x40;
}
lowercase = true;
} else if (val == 0x1B) {
if (lowercase) {
c = '.';
} else {
c = ',';
}
lowercase = true;
} else if (val == 0x1C) {
if (lowercase) {
c = '\'';
} else {
c = '"';
}
lowercase = true;
} else if (val == 0x1D) { // Composite
ObjID subval = stream.getBits(16);
Common::String child;
if (subval & 0x8000) {
// Composite object id
subval ^= 0xFFFF;
child = getNoun(subval);
} else {
// Just another id
// HACK, see below in getNoun()
child = *TextAsset(_engine, subval, _sourceObj, _targetObj, _container, _isOld, _huffman).decode();
}
if (child.size() > 0) {
c = '?'; // HACK Will fix later, should append
}
lowercase = true;
} else if (val == 0x1E) {
c = stream.getBits(8);
lowercase = true;
} else if (val == 0x1F) {
lowercase = !lowercase;
} else {
warning("Unrecognized char in old text %d, pos %d", _id, i);
}
str[i] = c;
}
str[strLen] = '\0';
debugC(3, kMVDebugText, "Decoded string [%d] (old encoding): %s", _id, str);
_decoded = Common::String(str);
}
void TextAsset::decodeHuffman() {
_decoded = Common::String("");
Common::SeekableReadStream *res = _container->getItem(_id);
Common::BitStream8MSB stream(res, true);
uint16 strLen = 0;
if (stream.getBit()) {
strLen = stream.getBits(15);
} else {
strLen = stream.getBits(7);
}
uint32 mask = 0;
uint32 symbol = 0;
char c;
for (uint16 i = 0; i < strLen; i++) {
mask = stream.peekBits(16);
uint32 entry;
// Find the length index
for (entry = 0; entry < _huffman->getNumEntries(); entry++) {
if (mask < _huffman->getMask(entry)) {
break;
}
}
stream.skip(_huffman->getLength(entry));
symbol = _huffman->getSymbol(entry);
if (symbol == 1) { // 7-bit ascii
c = stream.getBits(7);
_decoded += c;
} else if (symbol == 2) { // Composite
if (stream.getBit()) { // TextID
ObjID embedId = stream.getBits(15);
uint pos = stream.pos(); // HACK, part 1
TextAsset embedded(_engine, embedId, _sourceObj, _targetObj, _container, _isOld, _huffman);
stream.rewind();// HACK, part 2
stream.skip(pos);
_decoded.replace(_decoded.end(), _decoded.end(), *embedded.decode());
// Another HACK, to get around that EOS char I insert at the end
_decoded.replace(_decoded.end() - 1, _decoded.end(), "");
} else { //Composite obj string
ObjID embedId = stream.getBits(8);
uint pos = stream.pos(); // HACK, part 1
_decoded.replace(_decoded.end(), _decoded.end(), getNoun(embedId));
stream.rewind();// HACK, part 2
stream.skip(pos);
// Another HACK, to get around that EOS char I insert at the end
_decoded.replace(_decoded.end() - 1, _decoded.end(), "");
}
} else { // Plain ascii
c = symbol & 0xFF;
_decoded.replace(_decoded.end(), _decoded.end(), Common::String(c));
}
}
_decoded += '\0';
debugC(3, kMVDebugText, "Decoded string [%d] (new encoding): %s", _id, _decoded.c_str());
}
Common::String TextAsset::getNoun(ObjID subval) {
ObjID obj;
Common::String name;
if (subval & 8) {
obj = _targetObj;
} else {
obj = _sourceObj;
}
if ((subval & 3) == 1) {
uint idx = _engine->getPrefixNdx(obj);
idx = ((idx >> 4) & 3) + 1;
name = _engine->getNoun(idx);
} else {
// HACK, there should be a pool of assets or something like in the GUI
name = *TextAsset(_engine, obj, _sourceObj, _targetObj, _container, _isOld, _huffman).decode();
switch (subval & 3) {
case 2:
name = _engine->getPrefixString(0, obj) + name;
break;
case 3:
name = _engine->getPrefixString(2, obj) + name;
break;
}
}
if (name.size() && (subval & 4)) {
Common::String tmp = name;
name.toUppercase();
name.replace(1, name.size() - 1, tmp, 1, tmp.size() - 1);
}
return name;
}
} // End of namespace MacVenture

64
engines/macventure/text.h Normal file
View File

@ -0,0 +1,64 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef MACVENTURE_TEXT_H
#define MACVENTURE_TEXT_H
#include "macventure/macventure.h"
#include "macventure/hufflists.h"
namespace MacVenture {
typedef uint32 ObjID;
class MacVentureEngine;
class TextAsset {
public:
TextAsset(MacVentureEngine *engine, ObjID objid, ObjID source, ObjID target, Container *container, bool isOld, const HuffmanLists *huffman);
~TextAsset() {}
const Common::String *decode() {
return &_decoded;
}
private:
void decodeOld();
void decodeHuffman();
Common::String getNoun(ObjID id);
private:
MacVentureEngine *_engine;
Container *_container;
ObjID _id;
ObjID _targetObj;
ObjID _sourceObj;
const HuffmanLists *_huffman;
bool _isOld;
Common::String _decoded;
};
} // End of namespace MacVenture
#endif

View File

@ -0,0 +1,61 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "macventure/windows.h"
namespace MacVenture {
BorderBounds borderBounds(MVWindowType type) {
switch (type) {
case MacVenture::kDocument:
break;
case MacVenture::kDBox:
break;
case MacVenture::kPlainDBox:
return BorderBounds(3, 3, 3, 3);
case MacVenture::kAltBox:
return BorderBounds(0, 0, 0, 0); // Hand-tested
case MacVenture::kNoGrowDoc:
return BorderBounds(1, 20, 1, 1);
case MacVenture::kMovableDBox:
break;
case MacVenture::kZoomDoc:
return BorderBounds(1, 20, 17, 1);
case MacVenture::kZoomNoGrow:
break;
case MacVenture::kInvWindow:
return BorderBounds(1, 20, 17, 17);
case MacVenture::kRDoc16:
break;
case MacVenture::kRDoc4:
return BorderBounds(1, 20, 1, 1);
case MacVenture::kRDoc6:
break;
case MacVenture::kRDoc10:
break;
default:
break;
}
return BorderBounds(0, 0, 0, 0);
}
} // End of namespace MacVenture

View File

@ -0,0 +1,99 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef MACVENTURE_WINDOWS_H
#define MACVENTURE_WINDOWS_H
#include "common/rect.h"
#include "common/array.h"
namespace MacVenture {
// massive HACK
typedef uint32 ObjID;
enum WindowReference {
kNoWindow = 0,
kInventoryStart = 1,
kCommandsWindow = 0x80,
kMainGameWindow = 0x81,
kOutConsoleWindow = 0x82,
kSelfWindow = 0x83,
kExitsWindow = 0x84,
kDiplomaWindow = 0x85
};
enum MVWindowType {
kDocument = 0x00,
kDBox = 0x01,
kPlainDBox = 0x02,
kAltBox = 0x03,
kNoGrowDoc = 0x04,
kMovableDBox = 0x05,
kZoomDoc = 0x08,
kZoomNoGrow = 0x0c,
// WebVenture assigns arbitrary kinds post-loading
kInvWindow = 0x0e,
kRDoc16 = 0x10,
kRDoc4 = 0x12,
kRDoc6 = 0x14,
kRDoc10 = 0x16,
kNoType = 0xFF
};
struct DrawableObject {
ObjID obj;
byte mode;
DrawableObject(ObjID id, byte md) {
obj = id;
mode = md;
}
};
enum {
kScrollAmount = 10
};
struct WindowData {
Common::Rect bounds;
MVWindowType type;
ObjID objRef;
uint16 visible;
uint16 hasCloseBox;
WindowReference refcon;
uint8 titleLength;
Common::String title;
Common::Array<DrawableObject> children;
bool updateScroll;
Common::Point scrollPos;
};
struct BorderBounds {
uint16 leftOffset;
uint16 topOffset;
uint16 rightOffset;
uint16 bottomOffset;
BorderBounds(uint16 l, uint16 t, uint16 r, uint16 b) :
leftOffset(l), topOffset(t), rightOffset(r), bottomOffset(b) {}
};
}
#endif

View File

@ -0,0 +1,350 @@
#include "macventure/world.h"
#include "macventure/macventure.h"
#include "common/file.h"
namespace MacVenture {
World::World(MacVentureEngine *engine, Common::MacResManager *resMan) {
_resourceManager = resMan;
_engine = engine;
_saveGame = NULL;
_gameText = NULL;
startNewGame();
_objectConstants = new Container(_engine->getFilePath(kObjectPathID));
calculateObjectRelations();
_gameText = new Container(_engine->getFilePath(kTextPathID));
}
World::~World() {
if (_saveGame)
delete _saveGame;
if (_objectConstants)
delete _objectConstants;
if (_gameText)
delete _gameText;
}
void World::startNewGame() {
if (_saveGame)
delete _saveGame;
if ((_startGameFileName = _engine->getStartGameFileName()) == "")
error("WORLD: Could not load initial game configuration");
Common::File saveGameFile;
if (!saveGameFile.open(_startGameFileName))
error("WORLD: Could not load initial game configuration");
debugC(2, kMVDebugMain, "Loading save game state from %s", _startGameFileName.c_str());
Common::SeekableReadStream *saveGameRes = saveGameFile.readStream(saveGameFile.size());
_saveGame = new SaveGame(_engine, saveGameRes);
calculateObjectRelations();
delete saveGameRes;
saveGameFile.close();
}
uint32 World::getObjAttr(ObjID objID, uint32 attrID) {
uint res;
uint32 index = _engine->getGlobalSettings()._attrIndices[attrID];
// HACK, but if I try to initialize it in the else clause, it goes out of scope and segfaults
Common::SeekableReadStream *objStream = _objectConstants->getItem(objID);
if (!(index & 0x80)) { // It's not a constant
res = _saveGame->getAttr(objID, index);
} else {
index &= 0x7F;
if (objStream->size() == 0) {
return 0;
}
// Look for the right attribute inside the object
objStream->skip(index * 2);
res = objStream->readByte() << 8;
res |= objStream->readByte();
}
res &= _engine->getGlobalSettings()._attrMasks[attrID];
res >>= _engine->getGlobalSettings()._attrShifts[attrID];
if (res & 0x8000)
res = -((res ^ 0xffff) + 1);
debugC(5, kMVDebugMain, "Attribute %x from object %x is %x", attrID, objID, res);
delete objStream;
return res;
}
void World::setObjAttr(ObjID objID, uint32 attrID, Attribute value) {
if (attrID == kAttrPosX || attrID == kAttrPosY) {
// Round to scale
// Intentionally empty, we don't seem to require this functionality
}
if (attrID == kAttrParentObject)
setParent(objID, value);
if (attrID < kAttrOtherDoor)
_engine->enqueueObject(kUpdateObject, objID);
uint32 idx = _engine->getGlobalSettings()._attrIndices[attrID];
value <<= _engine->getGlobalSettings()._attrShifts[attrID];
value &= _engine->getGlobalSettings()._attrMasks[attrID];
Attribute oldVal = _saveGame->getAttr(objID, idx);
oldVal &= ~_engine->getGlobalSettings()._attrMasks[attrID];
_saveGame->setAttr(idx, objID, (value | oldVal));
_engine->gameChanged();
}
bool MacVenture::World::isObjActive(ObjID obj) {
ObjID destObj = _engine->getDestObject();
Common::Point p = _engine->getDeltaPoint();
ControlAction selectedControl = _engine->getSelectedControl();
if (!getAncestor(obj)) {
return false; // If our ancestor is the garbage (obj 0), we're inactive
}
if (_engine->getInvolvedObjects() >= 2 && // If (we need > 1 objs for the command) &&
destObj > 0 && // we have a destination object &&
!getAncestor(destObj)) { // but that destination object is in the garbage
return false;
}
if (selectedControl != kMoveObject) {
return true; // We only need one
}
// Handle move object
if (!isObjDraggable(obj)) {
return false; // We can't move it
}
if (getObjAttr(1, kAttrParentObject) != destObj) {
return true; // if the target is not the player's parent, we can go
}
Common::Rect rect(kScreenWidth, kScreenHeight);
rect.top -= getObjAttr(obj, kAttrPosY) + p.y;
rect.left -= getObjAttr(obj, kAttrPosX) + p.x;
return intersects(obj, rect);
}
ObjID World::getAncestor(ObjID objID) {
ObjID root = getObjAttr(1, kAttrParentObject);
while (objID != 0 && objID != 1 && objID != root) {
objID = getObjAttr(objID, kAttrParentObject);
}
return objID;
}
Common::Array<ObjID> World::getFamily(ObjID objID, bool recursive) {
Common::Array<ObjID> res;
res.push_back(objID);
res.push_back(getChildren(objID, recursive));
return res;
}
Common::Array<ObjID> World::getChildren(ObjID objID, bool recursive) {
Common::Array<ObjID> res;
ObjID child = _relations[objID * 2];
while (child) {
res.push_back(child);
if (!recursive)
res.push_back(getChildren(child, false));
child = _relations[child * 2 + 1];
}
return res;
}
Attribute World::getGlobal(uint32 attrID) {
return _saveGame->getGlobals()[attrID];
}
void World::setGlobal(uint32 attrID, Attribute value) {
_saveGame->setGlobal(attrID, value);
}
void World::updateObj(ObjID objID) {
WindowReference win;
if (getObjAttr(1, kAttrParentObject) == objID) {
win = kMainGameWindow;
} else {
win = _engine->getObjWindow(objID);
}
if (win) {
_engine->focusObjWin(objID);
_engine->runObjQueue();
_engine->updateWindow(win);
}
}
void World::captureChildren(ObjID objID) {
warning("Capture children unimplemented!");
}
void World::releaseChildren(ObjID objID) {
warning("Release children unimplemented!");
}
Common::String World::getText(ObjID objID, ObjID source, ObjID target) {
if (objID & 0x8000) {
return _engine->getUserInput();
}
TextAsset text = TextAsset(_engine, objID, source, target, _gameText, _engine->isOldText(), _engine->getDecodingHuffman());
return *text.decode();
}
bool World::isObjDraggable(ObjID objID) {
return (getObjAttr(objID, kAttrInvisible) == 0 &&
getObjAttr(objID, kAttrUnclickable) == 0 &&
getObjAttr(objID, kAttrUndraggable) == 0);
}
bool World::intersects(ObjID objID, Common::Rect rect) {
return _engine->getObjBounds(objID).intersects(rect);
}
void World::calculateObjectRelations() {
_relations.clear();
ObjID val, next;
uint32 numObjs = _engine->getGlobalSettings()._numObjects;
const AttributeGroup &parents = *_saveGame->getGroup(0);
for (uint i = 0; i < numObjs * 2; i++) {
_relations.push_back(0);
}
for (uint i = numObjs - 1; i > 0; i--) {
val = parents[i];
next = _relations[val * 2];
if (next) {
_relations[i * 2 + 1] = next;
}
_relations[val * 2] = i;
}
}
void World::setParent(ObjID child, ObjID newParent) {
ObjID old = _saveGame->getAttr(child, kAttrParentObject);
if (newParent == child)
return;
ObjID oldNdx = old * 2;
old = _relations[oldNdx];
while (old != child) {
oldNdx = (old * 2) + 1;
old = _relations[oldNdx];
}
_relations[oldNdx] = _relations[(old * 2) + 1];
oldNdx = newParent * 2;
old = _relations[oldNdx];
while (old && old <= child) {
oldNdx = (old * 2) + 1;
old = _relations[oldNdx];
}
_relations[child * 2 + 1] = old;
_relations[oldNdx] = child;
}
void World::loadGameFrom(Common::InSaveFile *file) {
if (_saveGame) {
delete _saveGame;
}
_saveGame = new SaveGame(_engine, file);
calculateObjectRelations();
}
void World::saveGameInto(Common::OutSaveFile *file) {
_saveGame->saveInto(file);
}
// SaveGame
SaveGame::SaveGame(MacVentureEngine *engine, Common::SeekableReadStream *res) {
_groups = Common::Array<AttributeGroup>();
loadGroups(engine, res);
_globals = Common::Array<uint16>();
loadGlobals(engine, res);
_text = Common::String();
loadText(engine, res);
}
SaveGame::~SaveGame() {
}
Attribute SaveGame::getAttr(ObjID objID, uint32 attrID) {
return _groups[attrID][objID];
}
void SaveGame::setAttr(uint32 attrID, ObjID objID, Attribute value) {
_groups[attrID][objID] = value;
}
const Common::Array<AttributeGroup> &MacVenture::SaveGame::getGroups() {
return _groups;
}
const AttributeGroup *SaveGame::getGroup(uint32 groupID) {
assert(groupID < _groups.size());
return &(_groups[groupID]);
}
void SaveGame::setGlobal(uint32 attrID, Attribute value) {
_globals[attrID] = value;
}
const Common::Array<uint16> &SaveGame::getGlobals() {
return _globals;
}
const Common::String &SaveGame::getText() {
return _text;
}
void SaveGame::saveInto(Common::OutSaveFile *file) {
warning("Saving the game not yet tested!");
// Save attibutes
Common::Array<AttributeGroup>::const_iterator itg;
for (itg = _groups.begin(); itg != _groups.end(); itg++) {
Common::Array<Attribute>::const_iterator ita;
for (ita = itg->begin(); ita != itg->end(); ita++) {
file->writeUint16BE((*ita));
}
}
// Save globals
Common::Array<uint16>::const_iterator global;
for (global = _globals.begin(); global != _globals.end(); global++) {
file->writeUint16BE((*global));
}
// Save text
// TODO: Insert text from GUI console
_text = "Hello";
file->write(_text.c_str(), _text.size());
}
void SaveGame::loadGroups(MacVentureEngine *engine, Common::SeekableReadStream *res) {
GlobalSettings settings = engine->getGlobalSettings();
for (int i = 0; i < settings._numGroups; ++i) {
AttributeGroup g;
for (int j = 0; j < settings._numObjects; ++j) {
g.push_back(res->readUint16BE());
}
_groups.push_back(g);
}
}
void SaveGame::loadGlobals(MacVentureEngine *engine, Common::SeekableReadStream *res) {
GlobalSettings settings = engine->getGlobalSettings();
for (int i = 0; i < settings._numGlobals; ++i) {
_globals.push_back(res->readUint16BE());
}
}
void SaveGame::loadText(MacVentureEngine *engine, Common::SeekableReadStream *res) {
// TODO: Load console text. For now, the GUI doesn't even look at this.
_text = "Placeholder Console Text";
}
} // End of namespace MacVenture

139
engines/macventure/world.h Normal file
View File

@ -0,0 +1,139 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef MACVENTURE_WORLD_H
#define MACVENTURE_WORLD_H
#include "macventure/container.h"
#include "macventure/text.h"
namespace MacVenture {
typedef uint32 ObjID;
typedef uint16 Attribute;
typedef Common::Array<Attribute> AttributeGroup;
class TextAsset;
enum ObjectAttributeID {
kAttrParentObject = 0,
kAttrPosX = 1,
kAttrPosY = 2,
kAttrInvisible = 3,
kAttrUnclickable = 4,
kAttrUndraggable = 5,
kAttrContainerOpen = 6,
kAttrPrefixes = 7,
kAttrIsExit = 8,
kAttrExitX = 9,
kAttrExitY = 10,
kAttrHiddenExit = 11,
kAttrOtherDoor = 12,
kAttrIsOpen = 13,
kAttrIsLocked = 14,
kAttrWeight = 16,
kAttrSize = 17,
kAttrHasDescription = 19,
kAttrIsDoor = 20,
kAttrIsContainer = 22,
kAttrIsOperable = 23,
kAttrIsEnterable = 24,
kAttrIsEdible = 25
};
class SaveGame {
public:
SaveGame(MacVentureEngine *engine, Common::SeekableReadStream *res);
~SaveGame();
Attribute getAttr(ObjID objID, uint32 attrID);
void setAttr(uint32 attrID, ObjID objID, Attribute value);
void setGlobal(uint32 attrID, Attribute value);
const Common::Array<uint16> &getGlobals();
const Common::Array<AttributeGroup> &getGroups();
const AttributeGroup *getGroup(uint32 groupID);
const Common::String &getText();
void saveInto(Common::OutSaveFile *file);
private:
void loadGroups(MacVentureEngine *engine, Common::SeekableReadStream *res);
void loadGlobals(MacVentureEngine *engine, Common::SeekableReadStream *res);
void loadText(MacVentureEngine *engine, Common::SeekableReadStream *res);
private:
Common::Array<AttributeGroup> _groups;
Common::Array<uint16> _globals;
Common::String _text;
};
class World {
public:
World(MacVentureEngine *engine, Common::MacResManager *resMan);
~World();
void startNewGame();
void setObjAttr(ObjID objID, uint32 attrID, Attribute value);
void setGlobal(uint32 attrID, Attribute value);
void updateObj(ObjID objID);
void captureChildren(ObjID objID);
void releaseChildren(ObjID objID);
uint32 getObjAttr(ObjID objID, uint32 attrID);
Attribute getGlobal(uint32 attrID);
Common::String getText(ObjID objID, ObjID source, ObjID target);
bool isObjActive(ObjID objID);
ObjID getAncestor(ObjID objID);
Common::Array<ObjID> getFamily(ObjID objID, bool recursive);
Common::Array<ObjID> getChildren(ObjID objID, bool recursive);
void loadGameFrom(Common::InSaveFile *file);
void saveGameInto(Common::OutSaveFile *file);
private:
bool isObjDraggable(ObjID objID);
bool intersects(ObjID objID, Common::Rect rect);
void calculateObjectRelations();
void setParent(ObjID child, ObjID newParent);
private:
MacVentureEngine *_engine;
Common::MacResManager *_resourceManager;
Common::String _startGameFileName;
SaveGame *_saveGame;
Container *_objectConstants;
Container *_gameText;
Common::Array<ObjID> _relations; // Parent-child relations, stored in Williams Heap format
};
} // End of namespace MacVenture
#endif