Merge pull request #807 from blorente/macventure-clean
MACVENTURE: Add MacVenture engine.
@ -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
|
||||
|
BIN
devtools/create_macventure/AltBox_act.bmp
Normal file
After Width: | Height: | Size: 822 B |
BIN
devtools/create_macventure/AltBox_inac.bmp
Normal file
After Width: | Height: | Size: 822 B |
BIN
devtools/create_macventure/InvWindow_act.bmp
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
devtools/create_macventure/InvWindow_inac.bmp
Normal file
After Width: | Height: | Size: 8.2 KiB |
BIN
devtools/create_macventure/NoGrowDoc_act.bmp
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
devtools/create_macventure/NoGrowDoc_inac.bmp
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
devtools/create_macventure/PlainDBox_act.bmp
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
devtools/create_macventure/PlainDBox_inac.bmp
Normal file
After Width: | Height: | Size: 6.8 KiB |
BIN
devtools/create_macventure/RDoc4_act.bmp
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
devtools/create_macventure/RDoc4_inac.bmp
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
devtools/create_macventure/ZoomDoc_act.bmp
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
devtools/create_macventure/ZoomDoc_inac.bmp
Normal file
After Width: | Height: | Size: 8.4 KiB |
8
devtools/create_macventure/create_macventure.sh
Executable 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
|
3
engines/macventure/configure.engine
Normal file
@ -0,0 +1,3 @@
|
||||
# This file is included from the main "configure" script
|
||||
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
|
||||
add_engine macventure "MacVenture" no
|
187
engines/macventure/container.cpp
Normal 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
|
81
engines/macventure/container.h
Normal 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
|
77
engines/macventure/controls.cpp
Normal 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;
|
||||
}
|
||||
}
|
106
engines/macventure/controls.h
Normal file
@ -0,0 +1,106 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 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
|
128
engines/macventure/cursor.cpp
Normal 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
|
88
engines/macventure/datafiles.cpp
Normal 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
|
38
engines/macventure/debug.h
Normal 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
|
179
engines/macventure/detection.cpp
Normal 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
|
253
engines/macventure/dialog.cpp
Normal 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
@ -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
369
engines/macventure/gui.h
Normal file
@ -0,0 +1,369 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 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
|
57
engines/macventure/hufflists.h
Normal 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
|
553
engines/macventure/image.cpp
Normal 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
@ -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
|
1185
engines/macventure/macventure.cpp
Normal file
369
engines/macventure/macventure.h
Normal file
@ -0,0 +1,369 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 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
|
31
engines/macventure/module.mk
Normal 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
|
76
engines/macventure/prebuilt_dialogs.cpp
Normal 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
|
87
engines/macventure/prebuilt_dialogs.h
Normal 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
|
197
engines/macventure/saveload.cpp
Normal 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
|
1251
engines/macventure/script.cpp
Normal file
285
engines/macventure/script.h
Normal 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
|
282
engines/macventure/sound.cpp
Normal 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
|
95
engines/macventure/sound.h
Normal 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
|
109
engines/macventure/stringtable.h
Normal 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
@ -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
@ -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
|
61
engines/macventure/windows.cpp
Normal 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
|
99
engines/macventure/windows.h
Normal file
@ -0,0 +1,99 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 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
|
350
engines/macventure/world.cpp
Normal 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
@ -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
|