scummvm/engines/macventure/macventure.cpp

1194 lines
30 KiB
C++
Raw Normal View History

2016-06-03 21:58:25 +02:00
/* 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.
*
2016-06-03 21:58:25 +02:00
* 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.
*
2016-06-03 21:58:25 +02:00
* 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.
*
*/
/*
* Based on
* WebVenture (c) 2010, Sean Kasun
* https://github.com/mrkite/webventure, http://seancode.com/webventure/
*
* Used with explicit permission from the author
*/
2016-06-05 20:55:29 +02:00
#include "common/system.h"
2016-06-05 20:45:14 +02:00
#include "common/debug-channels.h"
#include "common/debug.h"
#include "common/error.h"
2016-08-02 13:58:16 +02:00
#include "common/config-manager.h"
2016-06-05 20:45:14 +02:00
#include "engines/util.h"
#include "macventure/macventure.h"
2016-06-08 16:07:53 +02:00
// To move
#include "common/file.h"
namespace MacVenture {
2016-07-28 12:50:37 +02:00
// HACK, see below
void toASCII(Common::String &str) {
2016-08-16 12:14:20 +02:00
debugC(3, kMVDebugMain, "toASCII: %s", str.c_str());
2016-07-28 12:50:37 +02:00
Common::String::iterator it = str.begin();
for (; it != str.end(); it++) {
if (*it == '\216') {
str.replace(it, it + 1, "e");
}
if (*it == '\210') {
str.replace(it, it + 1, "a");
}
2016-07-28 12:50:37 +02:00
}
}
2016-06-08 16:07:53 +02:00
enum {
kMaxMenuTitleLength = 30
};
MacVentureEngine::MacVentureEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst) {
_gameDescription = gameDesc;
2016-06-05 20:45:14 +02:00
_rnd = new Common::RandomSource("macventure");
2016-08-07 17:15:01 +02:00
initDebugChannels();
2016-06-24 21:00:06 +02:00
_debugger = NULL;
2016-08-13 16:57:42 +02:00
_resourceManager = NULL;
_globalSettings = NULL;
_gui = NULL;
2016-08-13 16:57:42 +02:00
_world = NULL;
_scriptEngine = NULL;
_filenames = NULL;
_decodingDirectArticles = NULL;
_decodingNamingArticles = NULL;
_decodingIndirectArticles = NULL;
_textHuffman = NULL;
2016-06-05 20:45:14 +02:00
_soundManager = NULL;
_dataBundle = NULL;
2016-08-07 17:15:01 +02:00
2016-06-05 20:45:14 +02:00
debug("MacVenture::MacVentureEngine()");
}
MacVentureEngine::~MacVentureEngine() {
2016-06-05 20:45:14 +02:00
debug("MacVenture::~MacVentureEngine()");
DebugMan.clearAllDebugChannels();
if (_rnd)
delete _rnd;
if (_debugger)
delete _debugger;
2016-08-13 16:57:42 +02:00
if (_resourceManager)
delete _resourceManager;
if (_globalSettings)
delete _globalSettings;
if (_gui)
delete _gui;
2016-08-13 16:57:42 +02:00
if (_world)
delete _world;
if (_scriptEngine)
delete _scriptEngine;
2016-06-16 18:17:45 +02:00
2016-06-16 23:04:10 +02:00
if (_filenames)
2016-06-16 18:17:45 +02:00
delete _filenames;
2016-06-16 23:04:10 +02:00
2016-06-25 17:38:15 +02:00
if (_decodingDirectArticles)
delete _decodingDirectArticles;
if (_decodingNamingArticles)
delete _decodingNamingArticles;
if (_decodingIndirectArticles)
delete _decodingIndirectArticles;
2016-06-17 20:46:22 +02:00
2016-06-16 19:02:14 +02:00
if (_textHuffman)
delete _textHuffman;
if (_soundManager)
delete _soundManager;
if (_dataBundle)
delete _dataBundle;
}
2016-08-07 17:15:01 +02:00
void MacVentureEngine::initDebugChannels() {
DebugMan.addDebugChannel(kMVDebugMain, "main", "Engine state");
DebugMan.addDebugChannel(kMVDebugGUI, "gui", "Gui");
DebugMan.addDebugChannel(kMVDebugText, "text", "Text decoders and printers");
DebugMan.addDebugChannel(kMVDebugImage, "image", "Image decoders and renderers");
DebugMan.addDebugChannel(kMVDebugScript, "script", "Script engine");
DebugMan.addDebugChannel(kMVDebugSound, "sound", "Sound decoders");
DebugMan.addDebugChannel(kMVDebugContainer, "container", "Containers");
}
Common::Error MacVentureEngine::run() {
2016-06-05 20:45:14 +02:00
debug("MacVenture::MacVentureEngine::init()");
initGraphics(kScreenWidth, kScreenHeight);
2016-06-05 20:45:14 +02:00
_debugger = new Console(this);
// Additional setup.
2016-06-08 17:13:02 +02:00
debug("MacVentureEngine::init");
2016-06-05 20:55:29 +02:00
2016-06-08 11:17:56 +02:00
_resourceManager = new Common::MacResManager();
if (!_resourceManager->open(getGameFileName()))
error("ENGINE: Could not open %s as a resource fork", getGameFileName());
2016-06-08 11:17:56 +02:00
2016-06-16 19:02:14 +02:00
// Engine-wide loading
2016-06-12 23:08:24 +02:00
if (!loadGlobalSettings())
error("ENGINE: Could not load the engine settings");
2016-06-12 23:08:24 +02:00
2016-06-16 19:02:14 +02:00
_oldTextEncoding = !loadTextHuffman();
2016-06-16 23:04:10 +02:00
2016-06-16 18:17:45 +02:00
_filenames = new StringTable(this, _resourceManager, kFilenamesStringTableID);
2016-06-25 17:38:15 +02:00
_decodingDirectArticles = new StringTable(this, _resourceManager, kCommonArticlesStringTableID);
_decodingNamingArticles = new StringTable(this, _resourceManager, kNamingArticlesStringTableID);
2016-06-25 22:21:26 +02:00
_decodingIndirectArticles = new StringTable(this, _resourceManager, kIndirectArticlesStringTableID);
2016-06-16 23:04:10 +02:00
loadDataBundle();
2016-06-16 18:17:45 +02:00
// Big class instantiation
2016-06-08 17:13:02 +02:00
_gui = new Gui(this, _resourceManager);
2016-06-13 20:29:08 +02:00
_world = new World(this, _resourceManager);
_scriptEngine = new ScriptEngine(this, _world);
2016-06-08 16:07:53 +02:00
2016-08-01 17:19:29 +02:00
_soundManager = new SoundManager(this, _mixer);
setInitialFlags();
2016-06-17 21:47:40 +02:00
2016-08-02 13:58:16 +02:00
int directSaveSlotLoading = ConfMan.getInt("save_slot");
if (directSaveSlotLoading >= 0) {
if (loadGameState(directSaveSlotLoading).getCode() != Common::kNoError) {
error("ENGINE: Could not load game from slot '%d'", directSaveSlotLoading);
2016-08-02 13:58:16 +02:00
}
} else {
setNewGameState();
2016-08-02 13:58:16 +02:00
}
selectControl(kStartOrResume);
2016-06-17 21:47:40 +02:00
_gui->addChild(kSelfWindow, 1);
_gui->updateWindow(kSelfWindow, false);
2016-06-24 21:00:06 +02:00
while (_gameState != kGameStateQuitting) {
2016-06-05 20:55:29 +02:00
processEvents();
2016-06-16 23:04:10 +02:00
2016-08-10 16:40:24 +02:00
if (_gameState != kGameStateQuitting && !_gui->isDialogOpen()) {
2016-08-10 16:40:24 +02:00
if (_prepared) {
_prepared = false;
if (!_halted)
updateState(false);
if (_cmdReady || _halted) {
_halted = false;
if (runScriptEngine()) {
_halted = true;
_paused = true;
} else {
_paused = false;
updateState(true);
updateControls();
updateExits();
}
}
if (_gameState == kGameStateWinnig || _gameState == kGameStateLosing) {
endGame();
2016-06-16 23:04:10 +02:00
}
}
}
refreshScreen();
2016-06-05 20:55:29 +02:00
}
2016-06-05 20:45:14 +02:00
return Common::kNoError;
}
void MacVentureEngine::refreshScreen() {
_gui->draw();
g_system->updateScreen();
g_system->delayMillis(50);
}
2016-08-10 16:40:24 +02:00
void MacVentureEngine::newGame() {
_world->startNewGame();
reset();
setInitialFlags();
setNewGameState();
}
void MacVentureEngine::setInitialFlags() {
_paused = false;
_halted = false;
_cmdReady = false;
_haltedAtEnd = false;
_haltedInSelection = false;
_clickToContinue = true;
_gameState = kGameStateInit;
_destObject = 0;
_prepared = true;
}
void MacVentureEngine::setNewGameState() {
_cmdReady = true;
ObjID playerParent = _world->getObjAttr(1, kAttrParentObject);
_currentSelection.push_back(playerParent);// Push the parent of the player
_world->setObjAttr(playerParent, kAttrContainerOpen, 1);
2016-08-10 16:40:24 +02:00
}
void MacVentureEngine::reset() {
resetInternals();
resetGui();
}
void MacVentureEngine::resetInternals() {
_scriptEngine->reset();
_currentSelection.clear();
_objQueue.clear();
_textQueue.clear();
}
void MacVentureEngine::resetGui() {
2016-08-12 12:42:24 +02:00
_gui->reloadInternals();
_gui->updateWindowInfo(kMainGameWindow, getParent(1), _world->getChildren(getParent(1), true));
// HACK! should update all inventories
2016-08-02 13:58:16 +02:00
_gui->ensureInventoryOpen(kInventoryStart, 1);
_gui->updateWindowInfo(kInventoryStart, 1, _world->getChildren(1, true));
updateControls();
updateExits();
refreshScreen();
}
void MacVentureEngine::requestQuit() {
2016-06-16 23:04:10 +02:00
// TODO: Display save game dialog and such
_gameState = kGameStateQuitting;
}
void MacVentureEngine::requestUnpause() {
_paused = false;
2016-06-16 23:04:10 +02:00
_gameState = kGameStatePlaying;
}
2016-07-04 11:45:47 +02:00
void MacVentureEngine::selectControl(ControlAction id) {
2016-08-07 17:15:01 +02:00
debugC(2, kMVDebugMain, "Select control %x", id);
2016-07-05 13:06:51 +02:00
if (id == kClickToContinue) {
_clickToContinue = false;
_paused = true;
return;
2016-07-09 12:54:26 +02:00
}
2016-08-12 10:02:24 +02:00
_selectedControl = id;
refreshReady();
2016-06-17 12:44:52 +02:00
}
void MacVentureEngine::refreshReady() {
switch (getInvolvedObjects()) {
case 0: // No selected object
_cmdReady = true;
break;
case 1: // We have some selected object
_cmdReady = _currentSelection.size() != 0;
break;
case 2:
if (_destObject > 0) // We have a destination seleted
_cmdReady = true;
break;
}
}
void MacVentureEngine::preparedToRun() {
_prepared = true;
}
2016-06-17 21:47:40 +02:00
void MacVentureEngine::gameChanged() {
_gameChanged = true;
}
void MacVentureEngine::winGame() {
2016-08-09 19:55:43 +02:00
_gui->showPrebuiltDialog(kWinGameDialog);
_gameState = kGameStateWinnig;
}
void MacVentureEngine::loseGame() {
2016-08-10 17:28:55 +02:00
_gui->showPrebuiltDialog(kLoseGameDialog);
2016-08-09 19:55:43 +02:00
_paused = true;
//_gameState = kGameStateLosing;
}
void MacVentureEngine::clickToContinue() {
_clickToContinue = true;
}
void MacVentureEngine::enqueueObject(ObjectQueueID type, ObjID objID, ObjID target) {
2016-06-16 23:04:10 +02:00
QueuedObject obj;
obj.id = type;
if (type == kUpdateObject && isObjEnqueued(objID)) {
return;
}
2016-08-11 18:20:26 +02:00
if (type == kUpdateWindow) {
obj.target = target;
}
2016-06-24 21:00:06 +02:00
if (type != kHightlightExits) {
obj.object = objID;
obj.parent = _world->getObjAttr(objID, kAttrParentObject);
obj.x = _world->getObjAttr(objID, kAttrPosX);
obj.y = _world->getObjAttr(objID, kAttrPosY);
obj.exitx = _world->getObjAttr(objID, kAttrExitX);
obj.exity = _world->getObjAttr(objID, kAttrExitY);
obj.hidden = _world->getObjAttr(objID, kAttrHiddenExit);
obj.offscreen = _world->getObjAttr(objID, kAttrInvisible);
obj.invisible = _world->getObjAttr(objID, kAttrUnclickable);
}
2016-06-16 23:04:10 +02:00
_objQueue.push_back(obj);
}
void MacVentureEngine::enqueueText(TextQueueID type, ObjID target, ObjID source, ObjID text) {
2016-06-20 09:09:10 +02:00
QueuedText newText;
newText.id = type;
newText.destination = target;
newText.source = source;
newText.asset = text;
_textQueue.push_back(newText);
}
void MacVentureEngine::enqueueSound(SoundQueueID type, ObjID target) {
QueuedSound newSound;
newSound.id = type;
newSound.reference = target;
_soundQueue.push_back(newSound);
}
2016-07-02 17:11:42 +02:00
void MacVentureEngine::handleObjectSelect(ObjID objID, WindowReference win, bool shiftPressed, bool isDoubleClick) {
2016-06-24 21:00:06 +02:00
if (win == kExitsWindow) {
win = kMainGameWindow;
}
2016-06-24 21:00:06 +02:00
const WindowData &windata = _gui->getWindowData(win);
2016-07-02 17:11:42 +02:00
if (shiftPressed) {
// TODO: Implement shift functionality.
2016-06-25 22:53:11 +02:00
} else {
2016-06-24 21:00:06 +02:00
if (_selectedControl && _currentSelection.size() > 0 && getInvolvedObjects() > 1) {
2016-08-17 14:35:25 +02:00
if (objID == 0) {
2016-06-24 21:00:06 +02:00
selectPrimaryObject(windata.objRef);
2016-08-17 14:35:25 +02:00
} else {
2016-06-24 21:00:06 +02:00
selectPrimaryObject(objID);
2016-08-17 14:35:25 +02:00
}
2016-06-24 21:00:06 +02:00
preparedToRun();
2016-06-25 22:53:11 +02:00
} else {
2016-06-24 21:00:06 +02:00
if (objID == 0) {
unselectAll();
2016-08-15 11:28:30 +02:00
objID = win;
2016-06-24 21:00:06 +02:00
}
if (objID > 0) {
2016-08-11 18:20:26 +02:00
int currentObjectIndex = findObjectInArray(objID, _currentSelection);
if (currentObjectIndex >= 0)
unselectAll();
2016-06-24 21:00:06 +02:00
2016-07-04 11:45:47 +02:00
if (isDoubleClick) {
2016-07-02 17:11:42 +02:00
selectObject(objID);
2016-07-05 13:06:51 +02:00
_destObject = objID;
2016-08-11 18:20:26 +02:00
setDeltaPoint(Common::Point(0, 0));
2016-07-09 12:54:26 +02:00
if (!_cmdReady) {
2016-07-04 11:45:47 +02:00
selectControl(kActivateObject);
2016-07-09 12:54:26 +02:00
_cmdReady = true;
2016-07-02 17:11:42 +02:00
}
} else {
selectObject(objID);
if (getInvolvedObjects() == 1)
_cmdReady = true;
}
2016-08-11 18:20:26 +02:00
preparedToRun();
2016-06-24 21:00:06 +02:00
}
}
}
}
2016-07-02 17:11:42 +02:00
void MacVentureEngine::handleObjectDrop(ObjID objID, Common::Point delta, ObjID newParent) {
_destObject = newParent;
2016-08-11 18:20:26 +02:00
setDeltaPoint(delta);
selectControl(kMoveObject);
2016-07-02 17:11:42 +02:00
refreshReady();
preparedToRun();
}
2016-08-11 18:20:26 +02:00
void MacVentureEngine::setDeltaPoint(Common::Point newPos) {
2016-08-07 17:15:01 +02:00
debugC(4, kMVDebugMain, "Update delta: Old(%d, %d), New(%d, %d)",
_deltaPoint.x, _deltaPoint.y,
newPos.x, newPos.y);
_deltaPoint = newPos;
}
void MacVentureEngine::focusObjWin(ObjID objID) {
_gui->bringToFront(getObjWindow(objID));
}
void MacVentureEngine::updateWindow(WindowReference winID) {
_gui->updateWindow(winID, true);
}
2016-07-14 00:18:08 +02:00
bool MacVentureEngine::showTextEntry(ObjID text, ObjID srcObj, ObjID destObj) {
2016-08-07 17:15:01 +02:00
debugC(3, kMVDebugMain, "Showing speech dialog, asset %d from %d to %d", text, srcObj, destObj);
2016-07-15 23:02:37 +02:00
_gui->getTextFromUser();
_prepared = false;
warning("Show text entry: not fully tested");
2016-07-14 00:18:08 +02:00
return true;
}
2016-07-15 23:02:37 +02:00
void MacVentureEngine::setTextInput(Common::String content) {
_prepared = true;
_userInput = content;
_clickToContinue = false;
}
Common::String MacVentureEngine::getUserInput() {
return _userInput;
}
Common::String MacVentureEngine::getStartGameFileName() {
Common::SeekableReadStream *res;
res = _resourceManager->getResource(MKTAG('S', 'T', 'R', ' '), kStartGameFilenameID);
if (!res)
return "";
byte length = res->readByte();
char *fileName = new char[length + 1];
res->read(fileName, length);
fileName[length] = '\0';
2016-07-28 12:50:37 +02:00
Common::String result = Common::String(fileName, length);
// HACK, see definition of toASCII
toASCII(result);
2016-08-13 16:57:42 +02:00
delete[] fileName;
delete res;
2016-08-11 18:20:26 +02:00
return result;
}
2016-06-16 23:04:10 +02:00
const GlobalSettings& MacVentureEngine::getGlobalSettings() const {
return *_globalSettings;
}
2016-06-16 23:04:10 +02:00
// Private engine methods
void MacVentureEngine::processEvents() {
Common::Event event;
while (_eventMan->pollEvent(event)) {
if (_gui->processEvent(event))
continue;
switch (event.type) {
2016-06-16 23:04:10 +02:00
case Common::EVENT_QUIT:
_gameState = kGameStateQuitting;
break;
default:
break;
}
}
}
2016-06-16 23:04:10 +02:00
bool MacVenture::MacVentureEngine::runScriptEngine() {
2016-08-16 12:14:20 +02:00
debugC(3, kMVDebugMain, "Running script engine");
2016-06-16 23:04:10 +02:00
if (_haltedAtEnd) {
_haltedAtEnd = false;
2016-06-18 00:27:35 +02:00
if (_scriptEngine->resume(false)) {
2016-06-16 23:04:10 +02:00
_haltedAtEnd = true;
return true;
}
return false;
}
if (_haltedInSelection) {
_haltedInSelection = false;
2016-06-18 00:27:35 +02:00
if (_scriptEngine->resume(false)) {
2016-06-16 23:04:10 +02:00
_haltedInSelection = true;
return true;
}
updateState(true);
2016-06-16 23:04:10 +02:00
}
while (!_currentSelection.empty()) {
ObjID obj = _currentSelection.front();
_currentSelection.remove_at(0);
2016-08-11 18:20:26 +02:00
if (isGameRunning() && _world->isObjActive(obj)) {
2016-06-16 23:04:10 +02:00
if (_scriptEngine->runControl(_selectedControl, obj, _destObject, _deltaPoint)) {
_haltedInSelection = true;
return true;
}
updateState(true);
2016-06-16 23:04:10 +02:00
}
}
2016-08-15 11:28:30 +02:00
if (_selectedControl == 1) {
2016-06-16 23:04:10 +02:00
_gameChanged = false;
2016-08-15 11:28:30 +02:00
} else if (isGameRunning()) {
2016-06-16 23:04:10 +02:00
if (_scriptEngine->runControl(kTick, _selectedControl, _destObject, _deltaPoint)) {
_haltedAtEnd = true;
return true;
}
}
return false;
}
void MacVentureEngine::endGame() {
requestQuit();
}
void MacVentureEngine::updateState(bool pause) {
2016-08-09 13:06:42 +02:00
_prepared = false;
2016-06-16 23:04:10 +02:00
runObjQueue();
printTexts();
playSounds(pause);
2016-06-16 23:04:10 +02:00
}
void MacVentureEngine::revert() {
_gui->invertWindowColors(kMainGameWindow);
preparedToRun();
}
2016-06-16 23:04:10 +02:00
void MacVentureEngine::runObjQueue() {
while (!_objQueue.empty()) {
uint32 biggest = 0;
uint32 index = 0;
uint32 temp;
for (uint i = 0; i < _objQueue.size(); i++) {
temp = _objQueue[i].id;
if (temp > biggest) {
biggest = temp;
index = i;
}
}
QueuedObject obj = _objQueue[index];
_objQueue.remove_at(index);
switch (obj.id) {
case 0x2:
focusObjectWindow(obj.object);
break;
case 0x3:
openObject(obj.object);
break;
case 0x4:
closeObject(obj.object);
break;
case 0x7:
checkObject(obj);
break;
case 0x8:
reflectSwap(obj.object, obj.target);
break;
case 0xc:
_world->setObjAttr(_gui->getWindowData(kMainGameWindow).refcon, kAttrContainerOpen, 0);
_world->setObjAttr(_world->getObjAttr(1, kAttrParentObject), kAttrContainerOpen, 1);
break;
case 0xd:
toggleExits();
break;
case 0xe:
zoomObject(obj.object);
break;
}
}
2016-06-16 23:04:10 +02:00
}
void MacVentureEngine::printTexts() {
for (uint i = 0; i < _textQueue.size(); i++) {
QueuedText text = _textQueue.front();
_textQueue.remove_at(0);
switch (text.id) {
case kTextNumber:
_gui->printText(Common::String(text.asset));
gameChanged();
break;
case kTextNewLine:
_gui->printText(Common::String(""));
gameChanged();
break;
case kTextPlain:
_gui->printText(_world->getText(text.asset, text.source, text.destination));
gameChanged();
break;
}
}
}
void MacVentureEngine::playSounds(bool pause) {
2016-08-17 14:35:25 +02:00
int delay = 0;
while (!_soundQueue.empty()) {
QueuedSound item = _soundQueue.front();
_soundQueue.remove_at(0);
switch (item.id) {
case kSoundPlay:
_soundManager->playSound(item.reference);
break;
case kSoundPlayAndWait:
delay = _soundManager->playSound(item.reference);
break;
case kSoundWait:
// Empty in the original.
break;
}
}
if (pause && delay > 0) {
2016-08-09 15:36:21 +02:00
warning("Sound pausing not yet tested. Pausing for %d", delay);
g_system->delayMillis(delay);
preparedToRun();
}
}
2016-06-16 23:04:10 +02:00
void MacVentureEngine::updateControls() {
selectControl(kNoCommand);
_gui->clearControls();
2016-06-24 21:00:06 +02:00
toggleExits();
resetVars();
2016-06-16 23:04:10 +02:00
}
void MacVentureEngine::resetVars() {
2016-08-12 10:02:24 +02:00
selectControl(kNoCommand);
2016-06-16 23:04:10 +02:00
_currentSelection.clear();
_destObject = 0;
2016-08-11 18:20:26 +02:00
setDeltaPoint(Common::Point(0, 0));
2016-06-16 23:04:10 +02:00
_cmdReady = false;
}
2016-06-24 21:00:06 +02:00
void MacVentureEngine::unselectAll() {
while (!_currentSelection.empty()) {
unselectObject(_currentSelection.front());
}
}
void MacVentureEngine::selectObject(ObjID objID) {
if (!_currentSelection.empty()) {
2016-08-14 12:21:04 +02:00
if (findParentWindow(objID) != findParentWindow(_currentSelection[0])) {
// TODO: Needs further testing, but it doesn't seem necessary.
2016-08-14 12:21:04 +02:00
//unselectAll();
}
2016-06-24 21:00:06 +02:00
}
if (findObjectInArray(objID, _currentSelection) == -1) {
2016-06-24 21:00:06 +02:00
_currentSelection.push_back(objID);
highlightExit(objID);
}
}
void MacVentureEngine::unselectObject(ObjID objID) {
int idxCur = findObjectInArray(objID, _currentSelection);
if (idxCur != -1) {
_currentSelection.remove_at(idxCur);
2016-06-24 21:00:06 +02:00
highlightExit(objID);
}
}
2016-06-30 08:41:25 +02:00
void MacVentureEngine::updateExits() {
2016-07-09 19:46:10 +02:00
_gui->clearExits();
2016-07-09 12:54:26 +02:00
_gui->unselectExits();
2016-06-30 08:41:25 +02:00
Common::Array<ObjID> exits = _world->getChildren(_world->getObjAttr(1, kAttrParentObject), true);
for (uint i = 0; i < exits.size(); i++)
_gui->updateExit(exits[i]);
}
2016-06-24 21:00:06 +02:00
int MacVentureEngine::findObjectInArray(ObjID objID, const Common::Array<ObjID> &list) {
// Find the object in the current selection
bool found = false;
uint i = 0;
while (i < list.size() && !found) {
if (list[i] == objID) {
found = true;
} else {
i++;
}
2016-06-24 21:00:06 +02:00
}
// HACK, should use iterator
2018-07-21 13:24:17 +02:00
return found ? (int)i : -1;
2016-06-24 21:00:06 +02:00
}
2016-06-25 17:38:15 +02:00
uint MacVentureEngine::getPrefixNdx(ObjID obj) {
return _world->getObjAttr(obj, kAttrPrefixes);
}
Common::String MacVentureEngine::getPrefixString(uint flag, ObjID obj) {
uint ndx = getPrefixNdx(obj);
2016-06-25 17:38:15 +02:00
ndx = ((ndx) >> flag) & 3;
return _decodingNamingArticles->getString(ndx);
2016-06-25 17:38:15 +02:00
}
Common::String MacVentureEngine::getNoun(ObjID ndx) {
return _decodingIndirectArticles->getString(ndx);
2016-06-25 17:38:15 +02:00
}
2016-06-24 21:00:06 +02:00
void MacVentureEngine::highlightExit(ObjID objID) {
// TODO: It seems unnecessary since the GUI checks whether an object
// is selected, which includes exits.
warning("STUB: highlightExit");
2016-06-24 21:00:06 +02:00
}
void MacVentureEngine::selectPrimaryObject(ObjID objID) {
if (objID == _destObject) {
return;
}
2016-06-24 21:00:06 +02:00
int idx;
2016-08-16 12:14:20 +02:00
debugC(4, kMVDebugMain, "Select primary object (%d)", objID);
2016-06-24 21:00:06 +02:00
if (_destObject > 0 &&
(idx = findObjectInArray(_destObject, _currentSelection)) != -1) {
2016-08-11 19:41:12 +02:00
unselectAll();
2016-06-24 21:00:06 +02:00
}
_destObject = objID;
if (findObjectInArray(_destObject, _currentSelection) == -1) {
2016-08-11 19:41:12 +02:00
selectObject(_destObject);
2016-06-24 21:00:06 +02:00
}
2016-08-11 19:41:12 +02:00
2016-06-24 21:00:06 +02:00
_cmdReady = true;
}
void MacVentureEngine::focusObjectWindow(ObjID objID) {
if (objID) {
WindowReference win = getObjWindow(objID);
if (win)
_gui->bringToFront(win);
}
}
void MacVentureEngine::openObject(ObjID objID) {
2016-08-16 12:14:20 +02:00
debugC(3, kMVDebugMain, "Open Object[%d] parent[%d] x[%d] y[%d]",
objID,
_world->getObjAttr(objID, kAttrParentObject),
_world->getObjAttr(objID, kAttrPosX),
_world->getObjAttr(objID, kAttrPosY));
if (getObjWindow(objID)) {
return;
}
if (objID == _world->getObjAttr(1, kAttrParentObject)) {
_gui->updateWindowInfo(kMainGameWindow, objID, _world->getChildren(objID, true));
_gui->updateWindow(kMainGameWindow, _world->getObjAttr(objID, kAttrContainerOpen));
2016-06-30 08:41:25 +02:00
updateExits();
2016-06-25 17:38:15 +02:00
_gui->setWindowTitle(kMainGameWindow, _world->getText(objID, objID, objID)); // it ignores source and target in the original
} else { // Open inventory window
Common::Point p(_world->getObjAttr(objID, kAttrPosX), _world->getObjAttr(objID, kAttrPosY));
2016-06-24 21:00:06 +02:00
WindowReference invID = _gui->createInventoryWindow(objID);
2016-06-25 17:38:15 +02:00
_gui->setWindowTitle(invID, _world->getText(objID, objID, objID));
_gui->updateWindowInfo(invID, objID, _world->getChildren(objID, true));
_gui->updateWindow(invID, _world->getObjAttr(objID, kAttrContainerOpen));
}
}
void MacVentureEngine::closeObject(ObjID objID) {
warning("closeObject: not fully implemented");
2016-08-15 12:45:21 +02:00
_gui->tryCloseWindow(getObjWindow(objID));
return;
}
void MacVentureEngine::checkObject(QueuedObject old) {
bool hasChanged = false;
2016-08-16 12:14:20 +02:00
debugC(3, kMVDebugMain, "Check Object[%d] parent[%d] x[%d] y[%d]",
old.object,
old.parent,
old.x,
old.y);
ObjID id = old.object;
if (id == 1) {
if (old.parent != _world->getObjAttr(id, kAttrParentObject)) {
enqueueObject(kSetToPlayerParent, id);
}
if (old.offscreen != _world->getObjAttr(id, kAttrInvisible) ||
old.invisible != _world->getObjAttr(id, kAttrUnclickable)) {
updateWindow(findParentWindow(id));
}
} else if (old.parent != _world->getObjAttr(id, kAttrParentObject) ||
old.x != _world->getObjAttr(id, kAttrPosX) ||
old.y != _world->getObjAttr(id, kAttrPosY)) {
WindowReference oldWin = getObjWindow(old.parent);
if (oldWin) {
_gui->removeChild(oldWin, id);
hasChanged = true;
}
WindowReference newWin = findParentWindow(id);
if (newWin) {
_gui->addChild(newWin, id);
hasChanged = true;
}
} else if (old.offscreen != _world->getObjAttr(id, kAttrInvisible) ||
old.invisible != _world->getObjAttr(id, kAttrUnclickable)) {
updateWindow(findParentWindow(id));
}
if (_world->getObjAttr(id, kAttrIsExit)) {
if (hasChanged ||
old.hidden != _world->getObjAttr(id, kAttrHiddenExit) ||
old.exitx != _world->getObjAttr(id, kAttrExitX) ||
old.exity != _world->getObjAttr(id, kAttrExitY))
2016-06-30 08:41:25 +02:00
_gui->updateExit(id);
}
WindowReference win = getObjWindow(id);
ObjID cur = id;
ObjID root = _world->getObjAttr(1, kAttrParentObject);
while (cur != root) {
if (cur == 0 || !_world->getObjAttr(cur, kAttrContainerOpen)) {
break;
}
cur = _world->getObjAttr(cur, kAttrParentObject);
}
if (cur == root) {
if (win) {
return;
}
enqueueObject(kOpenWindow, id); //open
} else {
if (!win) {
return;
}
enqueueObject(kCloseWindow, id); //close
}
// Update children
Common::Array<ObjID> children = _world->getChildren(id, true);
for (uint i = 0; i < children.size(); i++) {
enqueueObject(kUpdateObject, children[i]);
}
}
void MacVentureEngine::reflectSwap(ObjID fromID, ObjID toID) {
WindowReference from = getObjWindow(fromID);
WindowReference to = getObjWindow(toID);
WindowReference tmp = to;
2016-08-16 12:14:20 +02:00
debugC(3, kMVDebugMain, "Swap Object[%d] to Object[%d], from win[%d] to win[%d] ",
fromID, toID, from, to);
if (!to) {
tmp = from;
}
if (tmp) {
2016-06-25 17:38:15 +02:00
Common::String newTitle = _world->getText(toID, 0, 0); // Ignores src and targ in the original
_gui->setWindowTitle(tmp, newTitle);
_gui->updateWindowInfo(tmp, toID, _world->getChildren(toID, true));
updateWindow(tmp);
}
}
void MacVentureEngine::toggleExits() {
Common::Array<ObjID> exits = _currentSelection;
while (!exits.empty()) {
ObjID obj = exits.front();
exits.remove_at(0);
2016-06-24 21:00:06 +02:00
highlightExit(obj);
updateWindow(findParentWindow(obj));
2016-06-25 17:38:15 +02:00
}
}
void MacVentureEngine::zoomObject(ObjID objID) {
warning("zoomObject: unimplemented");
}
2016-08-11 18:20:26 +02:00
bool MacVentureEngine::isObjEnqueued(ObjID objID) {
Common::Array<QueuedObject>::const_iterator it;
for (it = _objQueue.begin(); it != _objQueue.end(); it++) {
if ((*it).object == objID) {
return true;
}
2016-08-11 18:20:26 +02:00
}
return false;
}
bool MacVentureEngine::isGameRunning() {
return (_gameState == kGameStateInit || _gameState == kGameStatePlaying);
}
2016-07-04 11:45:47 +02:00
ControlAction MacVenture::MacVentureEngine::referenceToAction(ControlType id) {
2016-06-17 12:44:52 +02:00
switch (id) {
case MacVenture::kControlExitBox:
return kActivateObject;//?? Like this in the original
2016-06-17 12:44:52 +02:00
case MacVenture::kControlExamine:
return kExamine;
case MacVenture::kControlOpen:
return kOpen;
case MacVenture::kControlClose:
return kClose;
case MacVenture::kControlSpeak:
return kSpeak;
case MacVenture::kControlOperate:
return kOperate;
case MacVenture::kControlGo:
return kGo;
case MacVenture::kControlHit:
return kHit;
case MacVenture::kControlConsume:
return kConsume;
default:
return kNoCommand;
}
}
2016-06-16 23:04:10 +02:00
// Data retrieval
bool MacVentureEngine::isPaused() {
return _paused;
}
bool MacVentureEngine::needsClickToContinue() {
return _clickToContinue;
}
2016-06-16 23:04:10 +02:00
Common::String MacVentureEngine::getCommandsPausedString() const {
return Common::String("Click to continue");
}
2016-06-16 18:17:45 +02:00
Common::String MacVentureEngine::getFilePath(FilePathID id) const {
if (id <= 3) { // We don't want a file in the subdirectory
return _filenames->getString(id);
2016-06-16 18:17:45 +02:00
} else { // We want a game file
return _filenames->getString(3) + "/" + _filenames->getString(id);
2016-06-16 18:17:45 +02:00
}
}
bool MacVentureEngine::isOldText() const {
return _oldTextEncoding;
}
2016-08-17 14:35:25 +02:00
const HuffmanLists *MacVentureEngine::getDecodingHuffman() const {
return _textHuffman;
}
uint32 MacVentureEngine::randBetween(uint32 min, uint32 max) {
return _rnd->getRandomNumber(max - min) + min;
}
uint32 MacVentureEngine::getInvolvedObjects() {
// If there is no valid control selected, we return a number too big
// to be useful. There is no control that uses that many objects.
return (_selectedControl ? getGlobalSettings()._cmdArgCnts[_selectedControl - 1] : 3000);
}
Common::Point MacVentureEngine::getObjPosition(ObjID objID) {
return Common::Point(_world->getObjAttr(objID, kAttrPosX), _world->getObjAttr(objID, kAttrPosY));
}
bool MacVentureEngine::isObjVisible(ObjID objID) {
return _world->getObjAttr(objID, kAttrInvisible) == 0;
}
bool MacVentureEngine::isObjClickable(ObjID objID) {
return _world->getObjAttr(objID, kAttrUnclickable) == 0;
}
bool MacVentureEngine::isObjSelected(ObjID objID) {
2016-06-24 21:00:06 +02:00
int idx = findObjectInArray(objID, _currentSelection);
return idx != -1;
}
2016-06-25 22:21:26 +02:00
bool MacVentureEngine::isObjExit(ObjID objID) {
return _world->getObjAttr(objID, kAttrIsExit);
}
2016-06-30 08:41:25 +02:00
bool MacVentureEngine::isHiddenExit(ObjID objID) {
return _world->getObjAttr(objID, kAttrHiddenExit);
}
2016-06-25 22:21:26 +02:00
Common::Point MacVentureEngine::getObjExitPosition(ObjID objID) {
uint x = _world->getObjAttr(objID, kAttrExitX);
uint y = _world->getObjAttr(objID, kAttrExitY);
return Common::Point(x, y);
}
2016-06-30 08:41:25 +02:00
ObjID MacVentureEngine::getParent(ObjID objID) {
return _world->getObjAttr(objID, kAttrParentObject);
}
2016-06-24 21:00:06 +02:00
Common::Rect MacVentureEngine::getObjBounds(ObjID objID) {
Common::Point pos = getObjPosition(objID);
2016-08-15 11:28:30 +02:00
WindowReference win = findParentWindow(objID);
if (win != kNoWindow) { // If it's not in a window YET, we don't really care about the border
BorderBounds bounds = borderBounds(_gui->getWindowData(win).type); // HACK
pos.x += bounds.leftOffset;
pos.y += bounds.topOffset;
}
2016-07-12 11:49:05 +02:00
Common::Point measures = _gui->getObjMeasures(objID);
uint w = measures.x;
uint h = measures.y;
2016-06-24 21:00:06 +02:00
return Common::Rect(pos.x, pos.y, pos.x + w, pos.y + h);
}
uint MacVentureEngine::getOverlapPercent(ObjID one, ObjID other) {
// If it's not the same parent, there's 0 overlap
2016-06-24 21:00:06 +02:00
if (_world->getObjAttr(one, kAttrParentObject) !=
2016-06-25 17:38:15 +02:00
_world->getObjAttr(other, kAttrParentObject))
2016-06-24 21:00:06 +02:00
return 0;
Common::Rect oneBounds = getObjBounds(one);
Common::Rect otherBounds = getObjBounds(other);
if (otherBounds.intersects(oneBounds) ||
2016-08-15 11:28:30 +02:00
oneBounds.intersects(otherBounds)) {
2016-06-24 21:00:06 +02:00
uint areaOne = oneBounds.width() * oneBounds.height();
uint areaOther = otherBounds.width() * otherBounds.height();
return (areaOne != 0) ? (areaOther * 100 / areaOne) : 0;
}
2016-06-24 21:00:06 +02:00
return 0;
}
WindowReference MacVentureEngine::getObjWindow(ObjID objID) {
return _gui->getObjWindow(objID);
}
WindowReference MacVentureEngine::findParentWindow(ObjID objID) {
if (objID == 1) {
return kSelfWindow;
}
ObjID parent = _world->getObjAttr(objID, kAttrParentObject);
if (parent == 0) {
return kNoWindow;
}
return getObjWindow(parent);
}
Common::Point MacVentureEngine::getDeltaPoint() {
return _deltaPoint;
}
ObjID MacVentureEngine::getDestObject() {
return _destObject;
}
ControlAction MacVentureEngine::getSelectedControl() {
return _selectedControl;
}
// Data loading
2016-06-12 23:08:24 +02:00
bool MacVentureEngine::loadGlobalSettings() {
Common::MacResIDArray resArray;
if ((resArray = _resourceManager->getResIDArray(MKTAG('G', 'N', 'R', 'L'))).size() == 0)
return false;
2016-08-13 16:57:42 +02:00
Common::SeekableReadStream *res;
2016-06-12 23:08:24 +02:00
res = _resourceManager->getResource(MKTAG('G', 'N', 'R', 'L'), kGlobalSettingsID);
if (res) {
_globalSettings = new GlobalSettings();
_globalSettings->loadSettings(res);
2016-08-13 16:57:42 +02:00
delete res;
2016-06-12 23:08:24 +02:00
return true;
}
return false;
}
2016-06-16 19:02:14 +02:00
bool MacVentureEngine::loadTextHuffman() {
Common::MacResIDArray resArray;
Common::SeekableReadStream *res;
if ((resArray = _resourceManager->getResIDArray(MKTAG('G', 'N', 'R', 'L'))).size() == 0)
return false;
res = _resourceManager->getResource(MKTAG('G', 'N', 'R', 'L'), kTextHuffmanTableID);
if (res) {
uint32 numEntries = res->readUint16BE();
res->readUint16BE(); // Skip
uint32 *masks = new uint32[numEntries];
2016-08-17 14:35:25 +02:00
for (uint i = 0; i < numEntries - 1; i++) {
2016-06-16 19:02:14 +02:00
// For some reason there are one lass mask than entries
masks[i] = res->readUint16BE();
2016-08-17 14:35:25 +02:00
}
2016-06-16 19:02:14 +02:00
uint32 *lengths = new uint32[numEntries];
2016-08-17 14:35:25 +02:00
for (uint i = 0; i < numEntries; i++) {
2016-06-16 19:02:14 +02:00
lengths[i] = res->readByte();
2016-08-17 14:35:25 +02:00
}
2016-06-16 19:02:14 +02:00
uint32 *values = new uint32[numEntries];
2016-08-17 14:35:25 +02:00
for (uint i = 0; i < numEntries; i++) {
2016-06-16 19:02:14 +02:00
values[i] = res->readByte();
2016-08-17 14:35:25 +02:00
}
2016-06-16 19:02:14 +02:00
_textHuffman = new HuffmanLists(numEntries, lengths, masks, values);
2016-08-07 17:15:01 +02:00
debugC(4, kMVDebugMain, "Text is huffman-encoded");
2016-08-13 16:57:42 +02:00
delete res;
delete[] masks;
delete[] lengths;
delete[] values;
2016-06-16 19:02:14 +02:00
return true;
2016-06-16 23:04:10 +02:00
}
return false;
2016-06-16 19:02:14 +02:00
}
2016-06-08 11:17:56 +02:00
// Global Settings
GlobalSettings::GlobalSettings() {
}
GlobalSettings::~GlobalSettings() {
}
void GlobalSettings::loadSettings(Common::SeekableReadStream *dataStream) {
_numObjects = dataStream->readUint16BE();
_numGlobals = dataStream->readUint16BE();
_numCommands = dataStream->readUint16BE();
_numAttributes = dataStream->readUint16BE();
_numGroups = dataStream->readUint16BE();
dataStream->readUint16BE(); // unknown
_invTop = dataStream->readUint16BE();
_invLeft = dataStream->readUint16BE();
_invWidth = dataStream->readUint16BE();
_invHeight = dataStream->readUint16BE();
_invOffsetY = dataStream->readUint16BE();
_invOffsetX = dataStream->readSint16BE();
_defaultFont = dataStream->readUint16BE();
_defaultSize = dataStream->readUint16BE();
uint8 *attrIndices = new uint8[_numAttributes];
dataStream->read(attrIndices, _numAttributes);
_attrIndices = Common::Array<uint8>(attrIndices, _numAttributes);
delete[] attrIndices;
2016-08-17 14:35:25 +02:00
for (int i = 0; i < _numAttributes; i++) {
_attrMasks.push_back(dataStream->readUint16BE());
2016-08-17 14:35:25 +02:00
}
uint8 *attrShifts = new uint8[_numAttributes];
dataStream->read(attrShifts, _numAttributes);
_attrShifts = Common::Array<uint8>(attrShifts, _numAttributes);
delete[] attrShifts;
uint8 *cmdArgCnts = new uint8[_numCommands];
dataStream->read(cmdArgCnts, _numCommands);
_cmdArgCnts = Common::Array<uint8>(cmdArgCnts, _numCommands);
delete[] cmdArgCnts;
uint8 *commands = new uint8[_numCommands];
dataStream->read(commands, _numCommands);
_commands = Common::Array<uint8>(commands, _numCommands);
delete[] commands;
}
} // End of namespace MacVenture