Initial commit
This commit is contained in:
5
engines/lab/POTFILES
Normal file
5
engines/lab/POTFILES
Normal file
@@ -0,0 +1,5 @@
|
||||
engines/lab/engine.cpp
|
||||
engines/lab/metaengine.cpp
|
||||
engines/lab/processroom.cpp
|
||||
engines/lab/savegame.cpp
|
||||
engines/lab/speciallocks.cpp
|
||||
354
engines/lab/anim.cpp
Normal file
354
engines/lab/anim.cpp
Normal file
@@ -0,0 +1,354 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/file.h"
|
||||
|
||||
#include "lab/lab.h"
|
||||
|
||||
#include "lab/anim.h"
|
||||
#include "lab/dispman.h"
|
||||
#include "lab/eventman.h"
|
||||
#include "lab/music.h"
|
||||
#include "lab/utils.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
Anim::Anim(LabEngine *vm) : _vm(vm) {
|
||||
_lastBlockHeader = 0;
|
||||
_numChunks = 1;
|
||||
_headerdata._width = 0;
|
||||
_headerdata._height = 0;
|
||||
_headerdata._fps = 0;
|
||||
_headerdata._flags = 0;
|
||||
_delayMicros = 0;
|
||||
_continuous = false;
|
||||
_isPlaying = false;
|
||||
_isAnim = false;
|
||||
_isPal = false;
|
||||
_noPalChange = false;
|
||||
_donePal = false;
|
||||
_frameNum = 0;
|
||||
_playOnce = false;
|
||||
_diffFile = nullptr;
|
||||
_diffFileStart = 0;
|
||||
_size = 0;
|
||||
_scrollScreenBuffer = nullptr;
|
||||
_waitForEffect = false;
|
||||
_stopPlayingEnd = false;
|
||||
_sampleSpeed = 0;
|
||||
_doBlack = false;
|
||||
|
||||
for (int i = 0; i < 3 * 256; i++)
|
||||
_diffPalette[i] = 0;
|
||||
|
||||
_outputBuffer = nullptr; // output to screen
|
||||
}
|
||||
|
||||
Anim::~Anim() {
|
||||
delete[] _vm->_anim->_scrollScreenBuffer;
|
||||
_vm->_anim->_scrollScreenBuffer = nullptr;
|
||||
}
|
||||
|
||||
void Anim::setOutputBuffer(byte *memoryBuffer) {
|
||||
_outputBuffer = memoryBuffer;
|
||||
}
|
||||
|
||||
uint16 Anim::getDIFFHeight() {
|
||||
return _headerdata._height;
|
||||
}
|
||||
|
||||
void Anim::diffNextFrame(bool onlyDiffData) {
|
||||
if (_lastBlockHeader == 65535)
|
||||
// Already done.
|
||||
return;
|
||||
|
||||
bool drawOnScreen = false;
|
||||
byte *startOfBuf = _outputBuffer;
|
||||
int bufPitch = _vm->_graphics->_screenWidth;
|
||||
|
||||
if (!startOfBuf) {
|
||||
startOfBuf = _vm->_graphics->getCurrentDrawingBuffer();
|
||||
drawOnScreen = true;
|
||||
}
|
||||
byte *endOfBuf = startOfBuf + (int)_headerdata._width * _headerdata._height;
|
||||
|
||||
int curBit = 0;
|
||||
|
||||
while (1) {
|
||||
byte *buf = startOfBuf + 0x10000 * curBit;
|
||||
|
||||
if (buf >= endOfBuf) {
|
||||
if (!onlyDiffData) {
|
||||
if (_headerdata._fps) {
|
||||
uint32 targetMillis = _vm->_system->getMillis() + _delayMicros;
|
||||
while (_vm->_system->getMillis() < targetMillis)
|
||||
_vm->_system->delayMillis(10);
|
||||
}
|
||||
|
||||
if (_isPal && !_noPalChange) {
|
||||
_vm->_graphics->setPalette(_diffPalette, 256);
|
||||
_isPal = false;
|
||||
}
|
||||
|
||||
_donePal = true;
|
||||
}
|
||||
|
||||
if (_isPal && !_noPalChange && !onlyDiffData && !_donePal) {
|
||||
_vm->_graphics->setPalette(_diffPalette, 256);
|
||||
_isPal = false;
|
||||
}
|
||||
|
||||
_donePal = false;
|
||||
|
||||
_frameNum++;
|
||||
|
||||
if ((_frameNum == 1) && (_continuous || !_playOnce))
|
||||
_diffFileStart = _diffFile->pos();
|
||||
|
||||
_isAnim = (_frameNum >= 3) && (!_playOnce);
|
||||
|
||||
if (drawOnScreen)
|
||||
_vm->_graphics->screenUpdate();
|
||||
|
||||
// done with the next frame.
|
||||
return;
|
||||
}
|
||||
|
||||
_vm->updateEvents();
|
||||
_lastBlockHeader = _diffFile->readUint32LE();
|
||||
_size = _diffFile->readUint32LE();
|
||||
|
||||
uint32 curPos = 0;
|
||||
|
||||
switch (_lastBlockHeader) {
|
||||
case 8:
|
||||
_diffFile->read(_diffPalette, _size);
|
||||
_isPal = true;
|
||||
break;
|
||||
|
||||
case 10:
|
||||
if (onlyDiffData) {
|
||||
if (curBit > 0)
|
||||
error("diffNextFrame: attempt to read screen to non-zero plane (%d)", curBit);
|
||||
delete[] _scrollScreenBuffer;
|
||||
_scrollScreenBuffer = new byte[_headerdata._width * _headerdata._height];
|
||||
_diffFile->read(_scrollScreenBuffer, _size);
|
||||
} else {
|
||||
_diffFile->read(buf, _size);
|
||||
}
|
||||
curBit++;
|
||||
break;
|
||||
|
||||
case 11:
|
||||
curPos = _diffFile->pos();
|
||||
_diffFile->skip(4);
|
||||
_vm->_utils->runLengthDecode(buf, _diffFile);
|
||||
curBit++;
|
||||
_diffFile->seek(curPos + _size, SEEK_SET);
|
||||
break;
|
||||
|
||||
case 12:
|
||||
curPos = _diffFile->pos();
|
||||
_diffFile->skip(4);
|
||||
_vm->_utils->verticalRunLengthDecode(buf, _diffFile, bufPitch);
|
||||
curBit++;
|
||||
_diffFile->seek(curPos + _size, SEEK_SET);
|
||||
break;
|
||||
|
||||
case 20:
|
||||
curPos = _diffFile->pos();
|
||||
_vm->_utils->unDiff(buf, buf, _diffFile, bufPitch, false);
|
||||
curBit++;
|
||||
_diffFile->seek(curPos + _size, SEEK_SET);
|
||||
break;
|
||||
|
||||
case 21:
|
||||
curPos = _diffFile->pos();
|
||||
_vm->_utils->unDiff(buf, buf, _diffFile, bufPitch, true);
|
||||
curBit++;
|
||||
_diffFile->seek(curPos + _size, SEEK_SET);
|
||||
break;
|
||||
|
||||
case 25:
|
||||
case 26:
|
||||
curBit++;
|
||||
break;
|
||||
|
||||
case 30:
|
||||
case 31:
|
||||
if (_waitForEffect) {
|
||||
while (_vm->_music->isSoundEffectActive()) {
|
||||
_vm->updateEvents();
|
||||
_vm->waitTOF();
|
||||
}
|
||||
|
||||
_waitForEffect = false;
|
||||
}
|
||||
|
||||
_size -= 8;
|
||||
|
||||
_diffFile->skip(4);
|
||||
_sampleSpeed = _diffFile->readUint16LE();
|
||||
_diffFile->skip(2);
|
||||
|
||||
// Sound effects embedded in animations are started here. These are
|
||||
// usually animation-specific, like door opening sounds, and are not looped.
|
||||
// The engine should wait for all such sounds to end.
|
||||
_waitForEffect = true;
|
||||
_vm->_music->playSoundEffect(_sampleSpeed, _size, false, _diffFile);
|
||||
break;
|
||||
|
||||
case 65535:
|
||||
if ((_frameNum == 1) || _playOnce || _stopPlayingEnd) {
|
||||
bool didTOF = false;
|
||||
|
||||
if (_waitForEffect) {
|
||||
while (_vm->_music->isSoundEffectActive()) {
|
||||
_vm->updateEvents();
|
||||
_vm->waitTOF();
|
||||
|
||||
if (drawOnScreen)
|
||||
didTOF = true;
|
||||
}
|
||||
|
||||
_waitForEffect = false;
|
||||
}
|
||||
|
||||
_isPlaying = false;
|
||||
|
||||
if (!didTOF)
|
||||
_vm->_graphics->screenUpdate();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Random frame number so it never gets back to 2
|
||||
_frameNum = 4;
|
||||
_diffFile->seek(_diffFileStart, SEEK_SET);
|
||||
break;
|
||||
|
||||
default:
|
||||
_diffFile->skip(_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Anim::stopDiff() {
|
||||
if (_isPlaying && _isAnim)
|
||||
_vm->_graphics->blackScreen();
|
||||
}
|
||||
|
||||
void Anim::stopDiffEnd() {
|
||||
if (!_isPlaying)
|
||||
return;
|
||||
|
||||
_stopPlayingEnd = true;
|
||||
while (_isPlaying) {
|
||||
_vm->updateEvents();
|
||||
diffNextFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void Anim::readDiff(Common::File *diffFile, bool playOnce, bool onlyDiffData) {
|
||||
_playOnce = playOnce;
|
||||
_delayMicros = 0;
|
||||
_frameNum = 0;
|
||||
_numChunks = 1;
|
||||
_donePal = false;
|
||||
_stopPlayingEnd = false;
|
||||
_isPlaying = true;
|
||||
|
||||
if (_doBlack) {
|
||||
_doBlack = false;
|
||||
_vm->_graphics->blackScreen();
|
||||
}
|
||||
|
||||
_diffFile = diffFile;
|
||||
|
||||
_continuous = false;
|
||||
|
||||
if (!_diffFile)
|
||||
return;
|
||||
|
||||
uint32 magicBytes = _diffFile->readUint32LE();
|
||||
if (magicBytes != 1219009121) {
|
||||
_isPlaying = false;
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 signature3 = _diffFile->readUint32LE();
|
||||
_size = _diffFile->readUint32LE();
|
||||
|
||||
if (signature3 != 0)
|
||||
return;
|
||||
|
||||
// sizeof(headerdata) != 18, but the padding might be at the end
|
||||
// 2 bytes, version, unused.
|
||||
_diffFile->skip(2);
|
||||
_headerdata._width = _diffFile->readUint16LE();
|
||||
_headerdata._height = _diffFile->readUint16LE();
|
||||
// 1 byte, depth, unused
|
||||
_diffFile->skip(1);
|
||||
_headerdata._fps = _diffFile->readByte();
|
||||
|
||||
// HACK: The original game defines a 1 second delay when changing screens, which is
|
||||
// very annoying. We first removed the delay, but it looked wrong when changing screens
|
||||
// as it was possible to see that something was displayed, without being able to tell
|
||||
// what it was. A shorter delay (150ms) makes it acceptable during gameplay and
|
||||
// readable. The big question is: do we need that message?
|
||||
_vm->_system->delayMillis(150);
|
||||
|
||||
if (_headerdata._fps == 1)
|
||||
_headerdata._fps = 0;
|
||||
|
||||
// 4 + 2 bytes, buffer size and machine, unused
|
||||
_diffFile->skip(6);
|
||||
_headerdata._flags = _diffFile->readUint32LE();
|
||||
|
||||
_diffFile->skip(_size - 18);
|
||||
|
||||
_continuous = CONTINUOUS & _headerdata._flags;
|
||||
_vm->_utils->setBytesPerRow(_headerdata._width);
|
||||
|
||||
delete[] _scrollScreenBuffer;
|
||||
_scrollScreenBuffer = nullptr;
|
||||
|
||||
if (_headerdata._fps)
|
||||
_delayMicros = 1000 / _headerdata._fps;
|
||||
|
||||
_lastBlockHeader = signature3;
|
||||
if (_playOnce) {
|
||||
while (_lastBlockHeader != 65535)
|
||||
diffNextFrame(onlyDiffData);
|
||||
} else
|
||||
diffNextFrame(onlyDiffData);
|
||||
}
|
||||
|
||||
} // End of namespace Lab
|
||||
102
engines/lab/anim.h
Normal file
102
engines/lab/anim.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LAB_ANIM_H
|
||||
#define LAB_ANIM_H
|
||||
|
||||
namespace Lab {
|
||||
|
||||
class LabEngine;
|
||||
#define CONTINUOUS 0xFFFF
|
||||
|
||||
struct DIFFHeader {
|
||||
uint16 _width;
|
||||
uint16 _height;
|
||||
char _fps;
|
||||
uint32 _flags;
|
||||
};
|
||||
|
||||
class Anim {
|
||||
private:
|
||||
LabEngine *_vm;
|
||||
|
||||
uint32 _lastBlockHeader;
|
||||
uint16 _numChunks;
|
||||
uint32 _delayMicros;
|
||||
bool _continuous;
|
||||
bool _isPlaying;
|
||||
bool _isAnim;
|
||||
bool _isPal;
|
||||
bool _donePal;
|
||||
uint16 _frameNum;
|
||||
bool _playOnce;
|
||||
Common::File *_diffFile;
|
||||
uint32 _diffFileStart;
|
||||
uint32 _size;
|
||||
bool _stopPlayingEnd;
|
||||
uint16 _sampleSpeed;
|
||||
|
||||
byte *_outputBuffer;
|
||||
DIFFHeader _headerdata;
|
||||
|
||||
public:
|
||||
Anim(LabEngine *vm);
|
||||
~Anim();
|
||||
|
||||
char _diffPalette[256 * 3];
|
||||
bool _waitForEffect; // Wait for each sound effect to finish before continuing.
|
||||
bool _doBlack; // Black the screen before new picture
|
||||
bool _noPalChange; // Don't change the palette.
|
||||
byte *_scrollScreenBuffer;
|
||||
|
||||
/**
|
||||
* Reads in a DIFF file.
|
||||
*/
|
||||
void setOutputBuffer(byte *memoryBuffer); // nullptr for output to screen
|
||||
void readDiff(Common::File *diffFile, bool playOnce, bool onlyDiffData);
|
||||
void diffNextFrame(bool onlyDiffData = false);
|
||||
|
||||
/**
|
||||
* Stops an animation from running.
|
||||
*/
|
||||
void stopDiff();
|
||||
|
||||
/**
|
||||
* Stops an animation from running.
|
||||
*/
|
||||
void stopDiffEnd();
|
||||
|
||||
uint16 getDIFFHeight();
|
||||
|
||||
bool isPlaying() const { return _isPlaying; }
|
||||
};
|
||||
|
||||
} // End of namespace Lab
|
||||
|
||||
#endif // LAB_ANIM_H
|
||||
3
engines/lab/configure.engine
Normal file
3
engines/lab/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] [components]
|
||||
add_engine lab "Labyrinth of Time" yes
|
||||
143
engines/lab/console.cpp
Normal file
143
engines/lab/console.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gui/debugger.h"
|
||||
|
||||
#include "lab/lab.h"
|
||||
#include "lab/console.h"
|
||||
#include "lab/dispman.h"
|
||||
#include "lab/eventman.h"
|
||||
#include "lab/music.h"
|
||||
#include "lab/processroom.h"
|
||||
#include "lab/resource.h"
|
||||
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
Console::Console(LabEngine *vm) : GUI::Debugger(), _vm(vm) {
|
||||
registerCmd("scene", WRAP_METHOD(Console, Cmd_Scene));
|
||||
registerCmd("scene_resources", WRAP_METHOD(Console, Cmd_DumpSceneResources));
|
||||
registerCmd("find_action", WRAP_METHOD(Console, Cmd_FindAction));
|
||||
}
|
||||
|
||||
Console::~Console() {
|
||||
}
|
||||
|
||||
bool Console::Cmd_Scene(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
const char *directions[] = { "North", "South", "East", "West" };
|
||||
debugPrintf("Current scene is %d, direction: %s\n", _vm->_roomNum, directions[_vm->getDirection()]);
|
||||
debugPrintf("Use %s <scene number> to change the current scene\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
_vm->_roomNum = atoi(argv[1]);
|
||||
_vm->_music->checkRoomMusic(1, _vm->_roomNum);
|
||||
_vm->_curFileName = " ";
|
||||
_vm->_closeDataPtr = nullptr;
|
||||
_vm->_mainDisplay = true;
|
||||
_vm->_followingCrumbs = false;
|
||||
_vm->_event->simulateEvent();
|
||||
_vm->_graphics->_longWinInFront = false;
|
||||
|
||||
Common::Keymapper *keymapper = _vm->_system->getEventManager()->getKeymapper();
|
||||
keymapper->disableAllGameKeymaps();
|
||||
keymapper->getKeymap("lab-default")->setEnabled(true);
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(true);
|
||||
keymapper->getKeymap("exit")->setEnabled(true);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Console::Cmd_DumpSceneResources(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Usage: %s <scene number> to dump the resources for a scene\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
int scene = atoi(argv[1]);
|
||||
_vm->_resource->readViews(scene);
|
||||
RoomData *roomData = &_vm->_rooms[scene];
|
||||
RuleList &rules = roomData->_rules;
|
||||
const char *transitions[] = { "None", "Wipe", "ScrollWipe", "ScrollBlack", "ScrollBounce", "Transporter", "ReadFirstFrame", "ReadNextFrame" };
|
||||
const char *ruleTypes[] = { "None", "Action", "Operate", "Go forward", "Conditions", "Turn", "Go main view", "Turn from to" };
|
||||
const char *directions[] = { "", "North", "South", "East", "West" };
|
||||
const char *actionTypes[] = {
|
||||
"", "PlaySound", "PlaySoundLooping", "ShowDiff", "ShowDiffLooping", "LoadDiff", "LoadBitmap", "ShowBitmap", "Transition", "NoUpdate", "ForceUpdate",
|
||||
"ShowCurPict", "SetElement", "UnsetElement", "ShowMessage", "ShowMessages", "ChangeRoom", "SetCloseup", "MainView", "SubInv", "AddInv", "ShowDir",
|
||||
"WaitSecs", "StopMusic", "StartMusic", "ChangeMusic", "ResetMusic", "FillMusic", "WaitSound", "ClearSound", "WinMusic", "WinGame", "LostGame",
|
||||
"ResetBuffer", "SpecialCmd", "CShowMessage", "PlaySoundNoWait"
|
||||
};
|
||||
|
||||
debugPrintf("Room message: %s\n", roomData->_roomMsg.c_str());
|
||||
debugPrintf("Transition: %s (%d)\n", transitions[roomData->_transitionType], roomData->_transitionType);
|
||||
|
||||
debugPrintf("Script:\n");
|
||||
|
||||
for (auto &rule : rules) {
|
||||
debugPrintf("Rule type: %s", ruleTypes[rule._ruleType]);
|
||||
if (rule._ruleType == kRuleTypeAction || rule._ruleType == kRuleTypeOperate)
|
||||
debugPrintf(" (item %d, closeup %d)", rule._param1, rule._param2);
|
||||
else if (rule._ruleType == kRuleTypeGoForward)
|
||||
debugPrintf(" (%s)", directions[rule._param1]);
|
||||
else if (rule._ruleType == kRuleTypeTurnFromTo)
|
||||
debugPrintf(" (from %s to %s)", directions[rule._param1], directions[rule._param2]);
|
||||
debugPrintf("\n");
|
||||
|
||||
for (auto &action : rule._actionList) {
|
||||
debugPrintf(" - %s ('%s', %d, %d, %d)\n", actionTypes[action._actionType], action._messages[0].c_str(), action._param1, action._param2, action._param3);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::Cmd_FindAction(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
debugPrintf("Usage: %s <action id> [param 1] [param 2] [param 3]\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
int actionId = atoi(argv[1]);
|
||||
int param1 = (argc > 2) ? atoi(argv[2]) : -1;
|
||||
int param2 = (argc > 3) ? atoi(argv[3]) : -1;
|
||||
int param3 = (argc > 4) ? atoi(argv[4]) : -1;
|
||||
|
||||
for (int i = 1; i <= _vm->_manyRooms; i++) {
|
||||
_vm->_resource->readViews(i);
|
||||
|
||||
for (auto &rule: _vm->_rooms[i]._rules) {
|
||||
for (auto &action : rule._actionList) {
|
||||
if (action._actionType == actionId &&
|
||||
(action._param1 == param1 || param1 == -1) &&
|
||||
(action._param2 == param2 || param2 == -1) &&
|
||||
(action._param3 == param3 || param3 == -1)) {
|
||||
debugPrintf("Found at script %d\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Neverhood
|
||||
45
engines/lab/console.h
Normal file
45
engines/lab/console.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LAB_CONSOLE_H
|
||||
#define LAB_CONSOLE_H
|
||||
|
||||
#include "gui/debugger.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
class LabEngine;
|
||||
|
||||
class Console : public GUI::Debugger {
|
||||
public:
|
||||
Console(LabEngine *vm);
|
||||
~Console(void) override;
|
||||
|
||||
private:
|
||||
LabEngine *_vm;
|
||||
|
||||
bool Cmd_Scene(int argc, const char **argv);
|
||||
bool Cmd_DumpSceneResources(int argc, const char **argv);
|
||||
bool Cmd_FindAction(int argc, const char **argv);
|
||||
};
|
||||
|
||||
} // End of namespace Lab
|
||||
#endif
|
||||
6
engines/lab/credits.pl
Normal file
6
engines/lab/credits.pl
Normal file
@@ -0,0 +1,6 @@
|
||||
begin_section("Lab");
|
||||
add_person("Arnaud Boutonné", "Strangerke", "");
|
||||
add_person("Filippos Karapetis", "bluegr", "");
|
||||
add_person("Willem Jan Palenstijn", "wjp", "");
|
||||
add_person("Eugene Sandulenko", "sev", "");
|
||||
end_section();
|
||||
118
engines/lab/detection.cpp
Normal file
118
engines/lab/detection.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
#include "lab/detection.h"
|
||||
|
||||
static const PlainGameDescriptor lab_setting[] = {
|
||||
{ "lab", "The Labyrinth of Time" },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
static const ADGameDescription labDescriptions[] = {
|
||||
{
|
||||
"lab",
|
||||
"",
|
||||
AD_ENTRY2s("doors", "d77536010e7e5ae17ee066323ceb9585", 2537, // game/doors
|
||||
"noteold.fon", "6c1d90ad55149556e79d3f7bfddb4bd7", 9252), // game/spict/noteold.fon
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"lab",
|
||||
"Lowres",
|
||||
AD_ENTRY2s("doors", "d77536010e7e5ae17ee066323ceb9585", 2537, // game/doors
|
||||
"64b", "3a84d41bcc6a782f22e8e954bce09721", 39916), // game/pict/h2/64b
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
Lab::GF_LOWRES | ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"lab",
|
||||
"Rerelease",
|
||||
{
|
||||
{ "doors", 0, "d77536010e7e5ae17ee066323ceb9585", 2537 }, // game/doors
|
||||
{ "noteold.fon", 0, "6c1d90ad55149556e79d3f7bfddb4bd7", 9252 }, // game/spict/noteold.fon
|
||||
{ "wyrmkeep",0, "97c7064c54c28b952d37c4ebff6efa50", 52286 }, // game/spict/intro
|
||||
{ nullptr, 0, nullptr, 0 }
|
||||
},
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"lab",
|
||||
"",
|
||||
AD_ENTRY1s("doors", "7bf458df6ec30cc8ef4665e4d7c77f59", 2537), // game/doors
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformAmiga,
|
||||
Lab::GF_LOWRES | ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
AD_TABLE_END_MARKER
|
||||
};
|
||||
|
||||
static const char *const directoryGlobs[] = {
|
||||
"game",
|
||||
"pict",
|
||||
"spict",
|
||||
"rooms",
|
||||
"h2",
|
||||
"intro",
|
||||
nullptr
|
||||
};
|
||||
|
||||
|
||||
|
||||
class LabMetaEngineDetection : public AdvancedMetaEngineDetection<ADGameDescription> {
|
||||
public:
|
||||
LabMetaEngineDetection() : AdvancedMetaEngineDetection(labDescriptions, lab_setting) {
|
||||
_maxScanDepth = 4;
|
||||
_directoryGlobs = directoryGlobs;
|
||||
_flags = kADFlagUseExtraAsHint;
|
||||
}
|
||||
|
||||
const char *getName() const override {
|
||||
return "lab";
|
||||
}
|
||||
|
||||
const char *getEngineName() const override {
|
||||
return "Labyrinth of Time";
|
||||
}
|
||||
|
||||
const char *getOriginalCopyright() const override {
|
||||
return "The Labyrinth of Time (C) 2004 The Wyrmkeep Entertainment Co. and Terra Nova Development";
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_PLUGIN_STATIC(LAB_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, LabMetaEngineDetection);
|
||||
34
engines/lab/detection.h
Normal file
34
engines/lab/detection.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LAB_DETECTION_H
|
||||
#define LAB_DETECTION_H
|
||||
|
||||
namespace Lab {
|
||||
|
||||
enum GameFeatures {
|
||||
GF_LOWRES = 1 << 0,
|
||||
GF_WINDOWS_TRIAL = 1 << 1
|
||||
};
|
||||
|
||||
} // End of namespace Lab
|
||||
|
||||
#endif // LAB_DETECTION_H
|
||||
958
engines/lab/dispman.cpp
Normal file
958
engines/lab/dispman.cpp
Normal file
@@ -0,0 +1,958 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/file.h"
|
||||
#include "graphics/paletteman.h"
|
||||
|
||||
#include "lab/lab.h"
|
||||
|
||||
#include "lab/anim.h"
|
||||
#include "lab/dispman.h"
|
||||
#include "lab/eventman.h"
|
||||
#include "lab/music.h"
|
||||
#include "lab/image.h"
|
||||
#include "lab/interface.h"
|
||||
#include "lab/resource.h"
|
||||
#include "lab/utils.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
DisplayMan::DisplayMan(LabEngine *vm) : _vm(vm) {
|
||||
_longWinInFront = false;
|
||||
_lastMessageLong = false;
|
||||
_actionMessageShown = false;
|
||||
|
||||
_screenBytesPerPage = 0;
|
||||
_curBitmap = nullptr;
|
||||
_displayBuffer = nullptr;
|
||||
_currentDisplayBuffer = nullptr;
|
||||
_fadePalette = nullptr;
|
||||
|
||||
_screenWidth = 0;
|
||||
_screenHeight = 0;
|
||||
|
||||
for (int i = 0; i < 256 * 3; i++)
|
||||
_curVgaPal[i] = 0;
|
||||
}
|
||||
|
||||
DisplayMan::~DisplayMan() {
|
||||
freePict();
|
||||
delete[] _displayBuffer;
|
||||
}
|
||||
|
||||
void DisplayMan::loadPict(const Common::String &filename) {
|
||||
freePict();
|
||||
_curBitmap = _vm->_resource->openDataFile(filename, MKTAG('D', 'I', 'F', 'F'));
|
||||
}
|
||||
|
||||
void DisplayMan::loadBackPict(const Common::String &fileName, uint16 *highPal) {
|
||||
_fadePalette = highPal;
|
||||
_vm->_anim->_noPalChange = true;
|
||||
readPict(fileName);
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
highPal[i] = ((_vm->_anim->_diffPalette[i * 3] >> 2) << 8) +
|
||||
((_vm->_anim->_diffPalette[i * 3 + 1] >> 2) << 4) +
|
||||
((_vm->_anim->_diffPalette[i * 3 + 2] >> 2));
|
||||
}
|
||||
|
||||
_vm->_anim->_noPalChange = false;
|
||||
}
|
||||
|
||||
void DisplayMan::readPict(const Common::String &filename, bool playOnce, bool onlyDiffData, byte *memoryBuffer) {
|
||||
_vm->_anim->stopDiff();
|
||||
loadPict(filename);
|
||||
_vm->_anim->setOutputBuffer(memoryBuffer);
|
||||
_vm->_anim->readDiff(_curBitmap, playOnce, onlyDiffData);
|
||||
}
|
||||
|
||||
void DisplayMan::freePict() {
|
||||
delete _curBitmap;
|
||||
_curBitmap = nullptr;
|
||||
}
|
||||
|
||||
Common::String DisplayMan::getWord(const char *mainBuffer) {
|
||||
Common::String result;
|
||||
|
||||
for (int i = 0; mainBuffer[i] && (mainBuffer[i] != ' ') && (mainBuffer[i] != '\n'); i++)
|
||||
result += mainBuffer[i];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Common::String DisplayMan::getLine(TextFont *tf, const char **mainBuffer, uint16 lineWidth) {
|
||||
uint16 curWidth = 0;
|
||||
Common::String result;
|
||||
|
||||
while ((*mainBuffer)[0]) {
|
||||
Common::String wordBuffer = getWord(*mainBuffer);
|
||||
|
||||
if ((curWidth + textLength(tf, wordBuffer)) <= lineWidth) {
|
||||
result += wordBuffer;
|
||||
(*mainBuffer) += wordBuffer.size();
|
||||
|
||||
// end of line
|
||||
if ((*mainBuffer)[0] == '\n') {
|
||||
(*mainBuffer)++;
|
||||
break;
|
||||
}
|
||||
|
||||
// append any space after the word
|
||||
if ((*mainBuffer)[0]) {
|
||||
result += (*mainBuffer)[0];
|
||||
(*mainBuffer)++;
|
||||
}
|
||||
|
||||
curWidth = textLength(tf, result);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int DisplayMan::flowText(TextFont *font, int16 spacing, byte penColor, byte backPen,
|
||||
bool fillBack, bool centerh, bool centerv, bool output, Common::Rect textRect, const char *str, Image *targetImage) {
|
||||
|
||||
byte *saveDisplayBuffer = _currentDisplayBuffer;
|
||||
|
||||
if (targetImage) {
|
||||
_currentDisplayBuffer = targetImage->_imageData;
|
||||
assert(_screenBytesPerPage == (uint32)(targetImage->_width * targetImage->_height));
|
||||
}
|
||||
|
||||
if (fillBack)
|
||||
rectFill(textRect, backPen);
|
||||
|
||||
if (!str)
|
||||
return 0;
|
||||
|
||||
const char *orig = str;
|
||||
|
||||
TextFont *msgFont = font;
|
||||
uint16 fontHeight = textHeight(msgFont) + spacing;
|
||||
uint16 numLines = (textRect.height() + 1) / fontHeight;
|
||||
uint16 width = textRect.width() + 1;
|
||||
uint16 y = textRect.top;
|
||||
|
||||
if (centerv && output) {
|
||||
const char *temp = str;
|
||||
uint16 actlines = 0;
|
||||
|
||||
while (temp[0]) {
|
||||
getLine(msgFont, &temp, width);
|
||||
actlines++;
|
||||
}
|
||||
|
||||
if (actlines <= numLines)
|
||||
y += ((textRect.height() + 1) - (actlines * fontHeight)) / 2;
|
||||
}
|
||||
|
||||
while (numLines && str[0]) {
|
||||
Common::String lineBuffer;
|
||||
lineBuffer = getLine(msgFont, &str, width);
|
||||
|
||||
uint16 x = textRect.left;
|
||||
|
||||
if (centerh)
|
||||
x += (width - textLength(msgFont, lineBuffer)) / 2;
|
||||
|
||||
if (output)
|
||||
drawText(msgFont, x, y, penColor, lineBuffer);
|
||||
|
||||
numLines--;
|
||||
y += fontHeight;
|
||||
}
|
||||
|
||||
_currentDisplayBuffer = saveDisplayBuffer;
|
||||
|
||||
return (str - orig);
|
||||
}
|
||||
|
||||
void DisplayMan::createBox(uint16 y2) {
|
||||
// Message box area
|
||||
rectFillScaled(4, 154, 315, y2 - 2, 7);
|
||||
|
||||
// Box around message area
|
||||
drawHLine(_vm->_utils->vgaScaleX(2), _vm->_utils->vgaScaleY(152), _vm->_utils->vgaScaleX(317), 0);
|
||||
drawVLine(_vm->_utils->vgaScaleX(317), _vm->_utils->vgaScaleY(152), _vm->_utils->vgaScaleY(y2), 0);
|
||||
drawHLine(_vm->_utils->vgaScaleX(2), _vm->_utils->vgaScaleY(y2), _vm->_utils->vgaScaleX(317), 0);
|
||||
drawVLine(_vm->_utils->vgaScaleX(2), _vm->_utils->vgaScaleY(152), _vm->_utils->vgaScaleY(y2), 0);
|
||||
}
|
||||
|
||||
int DisplayMan::longDrawMessage(Common::String str, bool isActionMessage) {
|
||||
if (isActionMessage) {
|
||||
_actionMessageShown = true;
|
||||
} else if (_actionMessageShown) {
|
||||
_actionMessageShown = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (str.empty())
|
||||
return 0;
|
||||
|
||||
_vm->_interface->attachButtonList(nullptr);
|
||||
|
||||
if (!_longWinInFront) {
|
||||
_longWinInFront = true;
|
||||
// Clear Area
|
||||
rectFill(0, _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2), _vm->_utils->vgaScaleX(319), _vm->_utils->vgaScaleY(199), 3);
|
||||
}
|
||||
|
||||
createBox(198);
|
||||
|
||||
return flowText(_vm->_msgFont, 0, 1, 7, false, true, true, true, _vm->_utils->vgaRectScale(6, 155, 313, 195), str.c_str());
|
||||
}
|
||||
|
||||
void DisplayMan::drawMessage(Common::String str, bool isActionMessage) {
|
||||
if (isActionMessage) {
|
||||
_actionMessageShown = true;
|
||||
} else if (_actionMessageShown) {
|
||||
_actionMessageShown = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (str.empty())
|
||||
return;
|
||||
|
||||
if ((textLength(_vm->_msgFont, str) > _vm->_utils->vgaScaleX(306))) {
|
||||
longDrawMessage(str, isActionMessage);
|
||||
_lastMessageLong = true;
|
||||
} else {
|
||||
if (_longWinInFront) {
|
||||
_longWinInFront = false;
|
||||
drawPanel();
|
||||
}
|
||||
|
||||
createBox(168);
|
||||
drawText(_vm->_msgFont, _vm->_utils->vgaScaleX(7), _vm->_utils->vgaScaleY(155) + _vm->_utils->svgaCord(2), 1, str);
|
||||
_lastMessageLong = false;
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayMan::drawPanel() {
|
||||
// Clear Area
|
||||
rectFill(0, _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2), _vm->_utils->vgaScaleX(319), _vm->_utils->vgaScaleY(199), 3);
|
||||
|
||||
// First Line
|
||||
drawHLine(0, _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2), _vm->_utils->vgaScaleX(319), 0);
|
||||
// Second Line
|
||||
drawHLine(0, _vm->_utils->vgaScaleY(149) + 1 + _vm->_utils->svgaCord(2), _vm->_utils->vgaScaleX(319), 5);
|
||||
// Button Separators
|
||||
drawHLine(0, _vm->_utils->vgaScaleY(170), _vm->_utils->vgaScaleX(319), 0);
|
||||
|
||||
if (!_vm->_alternate) {
|
||||
// The horizontal lines under the black one
|
||||
drawHLine(0, _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleX(319), 4);
|
||||
_vm->_interface->drawButtonList(&_vm->_moveButtonList);
|
||||
} else {
|
||||
if (_vm->getPlatform() != Common::kPlatformWindows) {
|
||||
// Vertical Black lines
|
||||
drawVLine(_vm->_utils->vgaScaleX(124), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleY(199), 0);
|
||||
drawVLine(_vm->_utils->vgaScaleX(194), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleY(199), 0);
|
||||
} else {
|
||||
// Vertical Black lines
|
||||
drawVLine(_vm->_utils->vgaScaleX(90), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleY(199), 0);
|
||||
drawVLine(_vm->_utils->vgaScaleX(160), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleY(199), 0);
|
||||
drawVLine(_vm->_utils->vgaScaleX(230), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleY(199), 0);
|
||||
}
|
||||
|
||||
// The horizontal lines under the black one
|
||||
drawHLine(0, _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleX(122), 4);
|
||||
drawHLine(_vm->_utils->vgaScaleX(126), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleX(192), 4);
|
||||
drawHLine(_vm->_utils->vgaScaleX(196), _vm->_utils->vgaScaleY(170) + 1, _vm->_utils->vgaScaleX(319), 4);
|
||||
// The vertical high light lines
|
||||
drawVLine(_vm->_utils->vgaScaleX(1), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198), 4);
|
||||
|
||||
if (_vm->getPlatform() != Common::kPlatformWindows) {
|
||||
drawVLine(_vm->_utils->vgaScaleX(126), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198), 4);
|
||||
drawVLine(_vm->_utils->vgaScaleX(196), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198), 4);
|
||||
} else {
|
||||
drawVLine(_vm->_utils->vgaScaleX(92), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198), 4);
|
||||
drawVLine(_vm->_utils->vgaScaleX(162), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198), 4);
|
||||
drawVLine(_vm->_utils->vgaScaleX(232), _vm->_utils->vgaScaleY(170) + 2, _vm->_utils->vgaScaleY(198), 4);
|
||||
}
|
||||
|
||||
_vm->_interface->drawButtonList(&_vm->_invButtonList);
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayMan::setUpScreens() {
|
||||
Interface *i = _vm->_interface;
|
||||
ButtonList *moveButtonList = &_vm->_moveButtonList;
|
||||
ButtonList *invButtonList = &_vm->_invButtonList;
|
||||
Image **moveImages = _vm->_moveImages;
|
||||
Image **invImages = _vm->_invImages;
|
||||
|
||||
createScreen(_vm->_isHiRes);
|
||||
|
||||
// TODO: The CONTROL file is not present in the Amiga version
|
||||
Common::File *controlFile = _vm->_resource->openDataFile("P:Control");
|
||||
for (int j = 0; j < 20; j++)
|
||||
_vm->_moveImages[j] = new Image(controlFile, _vm);
|
||||
delete controlFile;
|
||||
|
||||
// Creates the buttons for the movement control panel
|
||||
// The key mapping was only set for the Windows version.
|
||||
// It's very convenient to have those shortcut, so I added them
|
||||
// for all versions. (Strangerke)
|
||||
uint16 y = _vm->_utils->vgaScaleY(173) - _vm->_utils->svgaCord(2);
|
||||
moveButtonList->push_back(i->createButton( 1, y, 0, kActionTake, moveImages[0], moveImages[1]));
|
||||
moveButtonList->push_back(i->createButton( 33, y, 1, kActionMove, moveImages[2], moveImages[3]));
|
||||
moveButtonList->push_back(i->createButton( 65, y, 2, kActionOpen, moveImages[4], moveImages[5]));
|
||||
moveButtonList->push_back(i->createButton( 97, y, 3, kActionClose, moveImages[6], moveImages[7]));
|
||||
moveButtonList->push_back(i->createButton(129, y, 4, kActionLook, moveImages[8], moveImages[9]));
|
||||
moveButtonList->push_back(i->createButton(161, y, 5, kActionInv, moveImages[12], moveImages[13]));
|
||||
moveButtonList->push_back(i->createButton(193, y, 6, kActionLeft, moveImages[14], moveImages[15]));
|
||||
moveButtonList->push_back(i->createButton(225, y, 7, kActionForward, moveImages[16], moveImages[17]));
|
||||
moveButtonList->push_back(i->createButton(257, y, 8, kActionRight, moveImages[18], moveImages[19]));
|
||||
moveButtonList->push_back(i->createButton(289, y, 9, kActionMap, moveImages[10], moveImages[11]));
|
||||
|
||||
// TODO: The INV file is not present in the Amiga version
|
||||
Common::File *invFile = _vm->_resource->openDataFile("P:Inv");
|
||||
if (_vm->getPlatform() == Common::kPlatformWindows) {
|
||||
for (int imgIdx = 0; imgIdx < 10; imgIdx++)
|
||||
_vm->_invImages[imgIdx] = new Image(invFile, _vm);
|
||||
} else {
|
||||
for (int imgIdx = 0; imgIdx < 6; imgIdx++)
|
||||
_vm->_invImages[imgIdx] = new Image(invFile, _vm);
|
||||
}
|
||||
|
||||
if (_vm->getPlatform() == Common::kPlatformWindows) {
|
||||
invButtonList->push_back(i->createButton( 24, y, 0, kActionMainDisplay, invImages[0], invImages[1]));
|
||||
invButtonList->push_back(i->createButton( 56, y, 1, kActionSaveLoad, invImages[2], invImages[3]));
|
||||
invButtonList->push_back(i->createButton( 94, y, 2, kActionUse, invImages[4], invImages[5]));
|
||||
invButtonList->push_back(i->createButton(126, y, 3, kActionInvLook, moveImages[8], moveImages[9]));
|
||||
invButtonList->push_back(i->createButton(164, y, 4, kActionPrev, moveImages[14], moveImages[15]));
|
||||
invButtonList->push_back(i->createButton(196, y, 5, kActionNext, moveImages[18], moveImages[19]));
|
||||
// The windows version has 2 extra buttons for breadcrumb trail
|
||||
// CHECKME: the game is really hard to play without those, maybe we could add something to enable that.
|
||||
invButtonList->push_back(i->createButton(234, y, 6, kActionDropBreadcrumb, invImages[6], invImages[7]));
|
||||
invButtonList->push_back(i->createButton(266, y, 7, kActionFollowBreadcrumbs, invImages[8], invImages[9]));
|
||||
} else {
|
||||
invButtonList->push_back(i->createButton( 58, y, 0, kActionMainDisplay, invImages[0], invImages[1]));
|
||||
invButtonList->push_back(i->createButton( 90, y, 1, kActionSaveLoad, invImages[2], invImages[3]));
|
||||
invButtonList->push_back(i->createButton(128, y, 2, kActionUse, invImages[4], invImages[5]));
|
||||
invButtonList->push_back(i->createButton(160, y, 3, kActionInvLook, moveImages[8], moveImages[9]));
|
||||
invButtonList->push_back(i->createButton(198, y, 4, kActionPrev, moveImages[14], moveImages[15]));
|
||||
invButtonList->push_back(i->createButton(230, y, 5, kActionNext, moveImages[18], moveImages[19]));
|
||||
}
|
||||
|
||||
delete invFile;
|
||||
}
|
||||
|
||||
void DisplayMan::rectFill(Common::Rect fillRect, byte color) {
|
||||
int width = fillRect.width() + 1;
|
||||
int height = fillRect.height() + 1;
|
||||
|
||||
if (fillRect.left + width > _screenWidth)
|
||||
width = _screenWidth - fillRect.left;
|
||||
|
||||
if (fillRect.top + height > _screenHeight)
|
||||
height = _screenHeight - fillRect.top;
|
||||
|
||||
if ((width > 0) && (height > 0)) {
|
||||
byte *d = getCurrentDrawingBuffer() + fillRect.top * _screenWidth + fillRect.left;
|
||||
|
||||
while (height-- > 0) {
|
||||
byte *dd = d;
|
||||
int ww = width;
|
||||
|
||||
while (ww-- > 0) {
|
||||
*dd++ = color;
|
||||
}
|
||||
|
||||
d += _screenWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayMan::rectFill(uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte color) {
|
||||
rectFill(Common::Rect(x1, y1, x2, y2), color);
|
||||
}
|
||||
|
||||
void DisplayMan::rectFillScaled(uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte color) {
|
||||
rectFill(_vm->_utils->vgaRectScale(x1, y1, x2, y2), color);
|
||||
}
|
||||
|
||||
void DisplayMan::drawVLine(uint16 x, uint16 y1, uint16 y2, byte color) {
|
||||
rectFill(x, y1, x, y2, color);
|
||||
}
|
||||
|
||||
void DisplayMan::drawHLine(uint16 x1, uint16 y, uint16 x2, byte color) {
|
||||
rectFill(x1, y, x2, y, color);
|
||||
}
|
||||
|
||||
void DisplayMan::screenUpdate() {
|
||||
_vm->_event->processInput();
|
||||
|
||||
_vm->_system->copyRectToScreen(_displayBuffer, _screenWidth, 0, 0, _screenWidth, _screenHeight);
|
||||
_vm->_system->updateScreen();
|
||||
}
|
||||
|
||||
void DisplayMan::createScreen(bool hiRes) {
|
||||
if (hiRes) {
|
||||
_screenWidth = 640;
|
||||
_screenHeight = 480;
|
||||
} else {
|
||||
_screenWidth = 320;
|
||||
_screenHeight = 200;
|
||||
}
|
||||
_screenBytesPerPage = _screenWidth * _screenHeight;
|
||||
|
||||
if (_displayBuffer)
|
||||
delete[] _displayBuffer;
|
||||
_displayBuffer = new byte[_screenBytesPerPage]();
|
||||
}
|
||||
|
||||
void DisplayMan::setAmigaPal(uint16 *pal) {
|
||||
byte vgaPal[16 * 3];
|
||||
uint16 vgaIdx = 0;
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
vgaPal[vgaIdx++] = (byte)(((pal[i] & 0xf00) >> 8) << 2);
|
||||
vgaPal[vgaIdx++] = (byte)(((pal[i] & 0x0f0) >> 4) << 2);
|
||||
vgaPal[vgaIdx++] = (byte)(((pal[i] & 0x00f)) << 2);
|
||||
}
|
||||
|
||||
writeColorRegs(vgaPal, 0, 16);
|
||||
}
|
||||
|
||||
void DisplayMan::writeColorRegs(byte *buf, uint16 first, uint16 numReg) {
|
||||
assert(first + numReg <= 256);
|
||||
byte tmp[256 * 3];
|
||||
|
||||
for (int i = 0; i < numReg * 3; i++)
|
||||
tmp[i] = (buf[i] << 2) | (buf[i] >> 4); // better results than buf[i] * 4
|
||||
|
||||
_vm->_system->getPaletteManager()->setPalette(tmp, first, numReg);
|
||||
memcpy(&(_curVgaPal[first * 3]), buf, numReg * 3);
|
||||
}
|
||||
|
||||
void DisplayMan::setPalette(void *newPal, uint16 numColors) {
|
||||
if (memcmp(newPal, _curVgaPal, numColors * 3) != 0)
|
||||
writeColorRegs((byte *)newPal, 0, numColors);
|
||||
}
|
||||
|
||||
byte *DisplayMan::getCurrentDrawingBuffer() {
|
||||
if (_currentDisplayBuffer)
|
||||
return _currentDisplayBuffer;
|
||||
|
||||
return _displayBuffer;
|
||||
}
|
||||
|
||||
void DisplayMan::checkerBoardEffect(uint16 penColor, uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
|
||||
int w = x2 - x1 + 1;
|
||||
int h = y2 - y1 + 1;
|
||||
|
||||
if (x1 + w > _screenWidth)
|
||||
w = _screenWidth - x1;
|
||||
|
||||
if (y1 + h > _screenHeight)
|
||||
h = _screenHeight - y1;
|
||||
|
||||
if ((w > 0) && (h > 0)) {
|
||||
byte *d = getCurrentDrawingBuffer() + y1 * _screenWidth + x1;
|
||||
|
||||
while (h-- > 0) {
|
||||
byte *dd = d;
|
||||
int ww = w;
|
||||
|
||||
if (y1 & 1) {
|
||||
dd++;
|
||||
ww--;
|
||||
}
|
||||
|
||||
while (ww > 0) {
|
||||
*dd = penColor;
|
||||
dd += 2;
|
||||
ww -= 2;
|
||||
}
|
||||
|
||||
d += _screenWidth;
|
||||
y1++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayMan::freeFont(TextFont **font) {
|
||||
if (*font) {
|
||||
if ((*font)->_data)
|
||||
delete[] (*font)->_data;
|
||||
|
||||
delete *font;
|
||||
*font = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 DisplayMan::textLength(TextFont *font, const Common::String &text) {
|
||||
uint16 length = 0;
|
||||
|
||||
if (font) {
|
||||
int numChars = text.size();
|
||||
for (int i = 0; i < numChars; i++) {
|
||||
length += font->_widths[(byte)text[i]];
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
uint16 DisplayMan::textHeight(TextFont *tf) {
|
||||
return (tf) ? tf->_height : 0;
|
||||
}
|
||||
|
||||
void DisplayMan::drawText(TextFont *tf, uint16 x, uint16 y, uint16 color, const Common::String &text) {
|
||||
byte *vgaTop = getCurrentDrawingBuffer();
|
||||
int numChars = text.size();
|
||||
|
||||
for (int i = 0; i < numChars; i++) {
|
||||
uint32 realOffset = (_screenWidth * y) + x;
|
||||
uint16 curPage = realOffset / _screenBytesPerPage;
|
||||
uint32 segmentOffset = realOffset - (curPage * _screenBytesPerPage);
|
||||
int32 leftInSegment = _screenBytesPerPage - segmentOffset;
|
||||
byte *vgaCur = vgaTop + segmentOffset;
|
||||
|
||||
if (tf->_widths[(byte)text[i]]) {
|
||||
byte *cdata = tf->_data + tf->_offsets[(byte)text[i]];
|
||||
uint16 bwidth = *cdata++;
|
||||
byte *vgaTemp = vgaCur;
|
||||
byte *vgaTempLine = vgaCur;
|
||||
|
||||
for (int rows = 0; rows < tf->_height; rows++) {
|
||||
int32 templeft = leftInSegment;
|
||||
|
||||
vgaTemp = vgaTempLine;
|
||||
|
||||
for (int cols = 0; cols < bwidth; cols++) {
|
||||
uint16 data = *cdata++;
|
||||
|
||||
if (data && (templeft >= 8)) {
|
||||
for (int j = 7; j >= 0; j--) {
|
||||
if ((1 << j) & data)
|
||||
*vgaTemp = color;
|
||||
vgaTemp++;
|
||||
}
|
||||
|
||||
templeft -= 8;
|
||||
} else if (data) {
|
||||
uint16 mask = 0x80;
|
||||
templeft = leftInSegment;
|
||||
|
||||
for (int counterb = 0; counterb < 8; counterb++) {
|
||||
if (templeft <= 0) {
|
||||
curPage++;
|
||||
vgaTemp = vgaTop - templeft;
|
||||
// Set up VGATempLine for next line
|
||||
vgaTempLine -= _screenBytesPerPage;
|
||||
// Set up LeftInSegment for next line
|
||||
leftInSegment += _screenBytesPerPage + templeft;
|
||||
templeft += _screenBytesPerPage;
|
||||
}
|
||||
|
||||
if (mask & data)
|
||||
*vgaTemp = color;
|
||||
|
||||
vgaTemp++;
|
||||
|
||||
mask = mask >> 1;
|
||||
templeft--;
|
||||
}
|
||||
} else {
|
||||
templeft -= 8;
|
||||
vgaTemp += 8;
|
||||
}
|
||||
}
|
||||
|
||||
vgaTempLine += _screenWidth;
|
||||
leftInSegment -= _screenWidth;
|
||||
|
||||
if (leftInSegment <= 0) {
|
||||
curPage++;
|
||||
vgaTempLine -= _screenBytesPerPage;
|
||||
leftInSegment += _screenBytesPerPage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x += tf->_widths[(byte)text[i]];
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayMan::doScrollBlack() {
|
||||
uint16 width = _vm->_utils->vgaScaleX(320);
|
||||
uint16 height = _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2);
|
||||
|
||||
_vm->_event->mouseHide();
|
||||
|
||||
byte *mem = new byte[width * height];
|
||||
int16 by = _vm->_utils->vgaScaleX(4);
|
||||
int16 verticalScroll = height;
|
||||
|
||||
while (verticalScroll > 0) {
|
||||
scrollDisplayY(-by, 0, 0, width - 1, height - 1, mem);
|
||||
verticalScroll -= by;
|
||||
|
||||
_vm->updateEvents();
|
||||
_vm->waitTOF();
|
||||
}
|
||||
|
||||
delete[] mem;
|
||||
|
||||
_vm->_event->mouseShow();
|
||||
}
|
||||
|
||||
void DisplayMan::copyPage(uint16 width, uint16 height, uint16 nheight, uint16 startLine, byte *mem) {
|
||||
byte *baseAddr = getCurrentDrawingBuffer();
|
||||
|
||||
uint32 size = (int32)(height - nheight) * (int32)width;
|
||||
mem += startLine * width;
|
||||
uint16 curPage = ((int32)nheight * (int32)width) / _screenBytesPerPage;
|
||||
uint32 offSet = ((int32)nheight * (int32)width) - (curPage * _screenBytesPerPage);
|
||||
|
||||
while (size) {
|
||||
uint32 copySize;
|
||||
if (size > (_screenBytesPerPage - offSet))
|
||||
copySize = _screenBytesPerPage - offSet;
|
||||
else
|
||||
copySize = size;
|
||||
|
||||
size -= copySize;
|
||||
|
||||
memcpy(baseAddr + (offSet >> 2), mem, copySize);
|
||||
mem += copySize;
|
||||
curPage++;
|
||||
offSet = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayMan::doScrollWipe(const Common::String &filename) {
|
||||
_vm->_event->mouseHide();
|
||||
uint16 width = _vm->_utils->vgaScaleX(320);
|
||||
uint16 height = _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2);
|
||||
|
||||
while (_vm->_music->isSoundEffectActive()) {
|
||||
_vm->updateEvents();
|
||||
_vm->waitTOF();
|
||||
}
|
||||
|
||||
readPict(filename, true, true);
|
||||
setPalette(_vm->_anim->_diffPalette, 256);
|
||||
byte *mem = _vm->_anim->_scrollScreenBuffer;
|
||||
|
||||
_vm->updateEvents();
|
||||
uint16 by = _vm->_utils->vgaScaleX(3);
|
||||
uint16 nheight = height;
|
||||
uint16 startLine = 0, onRow = 0;
|
||||
|
||||
while (onRow < _vm->_anim->getDIFFHeight()) {
|
||||
_vm->updateEvents();
|
||||
|
||||
if ((by > nheight) && nheight)
|
||||
by = nheight;
|
||||
|
||||
if ((startLine + by) > (_vm->_anim->getDIFFHeight() - height - 1))
|
||||
break;
|
||||
|
||||
if (nheight)
|
||||
nheight -= by;
|
||||
|
||||
copyPage(width, height, nheight, startLine, mem);
|
||||
screenUpdate();
|
||||
|
||||
if (!nheight)
|
||||
startLine += by;
|
||||
|
||||
onRow += by;
|
||||
|
||||
if (nheight <= (height / 4))
|
||||
by = _vm->_utils->vgaScaleX(5);
|
||||
else if (nheight <= (height / 3))
|
||||
by = _vm->_utils->vgaScaleX(4);
|
||||
else if (nheight <= (height / 2))
|
||||
by = _vm->_utils->vgaScaleX(3);
|
||||
}
|
||||
|
||||
_vm->_event->mouseShow();
|
||||
}
|
||||
|
||||
void DisplayMan::doScrollBounce() {
|
||||
const uint16 offsets[8] = { 3, 3, 2, 2, 2, 1, 1, 1 };
|
||||
const int multiplier = (_vm->_isHiRes) ? 2 : 1;
|
||||
|
||||
_vm->_event->mouseHide();
|
||||
int width = _vm->_utils->vgaScaleX(320);
|
||||
int height = _vm->_utils->vgaScaleY(149) + _vm->_utils->svgaCord(2);
|
||||
byte *mem = _vm->_anim->_scrollScreenBuffer;
|
||||
|
||||
_vm->updateEvents();
|
||||
int startLine = _vm->_anim->getDIFFHeight() - height - 1;
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
_vm->updateEvents();
|
||||
startLine -= (5 - i) * multiplier;
|
||||
copyPage(width, height, 0, startLine, mem);
|
||||
_vm->waitTOF();
|
||||
}
|
||||
|
||||
for (int i = 8; i > 0; i--) {
|
||||
_vm->updateEvents();
|
||||
startLine += offsets[i - 1] * multiplier;
|
||||
copyPage(width, height, 0, startLine, mem);
|
||||
_vm->waitTOF();
|
||||
}
|
||||
|
||||
_vm->_event->mouseShow();
|
||||
}
|
||||
|
||||
void DisplayMan::doTransWipe(const Common::String &filename) {
|
||||
uint16 lastY, linesLast;
|
||||
|
||||
if (_vm->_isHiRes) {
|
||||
linesLast = 3;
|
||||
lastY = 358;
|
||||
} else {
|
||||
linesLast = 1;
|
||||
lastY = 148;
|
||||
}
|
||||
|
||||
uint16 linesDone = 0;
|
||||
|
||||
for (int j = 0; j < 2; j++) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
uint16 curY = i * 2;
|
||||
|
||||
while (curY < lastY) {
|
||||
if (linesDone >= linesLast) {
|
||||
_vm->updateEvents();
|
||||
_vm->waitTOF();
|
||||
linesDone = 0;
|
||||
}
|
||||
|
||||
if (j == 0)
|
||||
checkerBoardEffect(0, 0, curY, _screenWidth - 1, curY + 1);
|
||||
else
|
||||
rectFill(0, curY, _screenWidth - 1, curY + 1, 0);
|
||||
curY += 4;
|
||||
linesDone++;
|
||||
} // while
|
||||
} // for i
|
||||
} // for j
|
||||
|
||||
if (filename.empty())
|
||||
_vm->_curFileName = _vm->getPictName(true);
|
||||
else if (filename[0] > ' ')
|
||||
_vm->_curFileName = filename;
|
||||
else
|
||||
_vm->_curFileName = _vm->getPictName(true);
|
||||
|
||||
byte *bitMapBuffer = new byte[_screenWidth * (lastY + 5)];
|
||||
readPict(_vm->_curFileName, true, false, bitMapBuffer);
|
||||
|
||||
setPalette(_vm->_anim->_diffPalette, 256);
|
||||
|
||||
Image imgSource(_vm);
|
||||
imgSource._width = _screenWidth;
|
||||
imgSource._height = lastY;
|
||||
imgSource.setData(bitMapBuffer, true);
|
||||
|
||||
Image imgDest(_vm);
|
||||
imgDest._width = _screenWidth;
|
||||
imgDest._height = _screenHeight;
|
||||
imgDest.setData(getCurrentDrawingBuffer(), false);
|
||||
|
||||
for (int j = 0; j < 2; j++) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
uint16 curY = i * 2;
|
||||
|
||||
while (curY < lastY) {
|
||||
if (linesDone >= linesLast) {
|
||||
_vm->updateEvents();
|
||||
_vm->waitTOF();
|
||||
linesDone = 0;
|
||||
}
|
||||
|
||||
imgDest.setData(getCurrentDrawingBuffer(), false);
|
||||
|
||||
if (j == 0) {
|
||||
imgSource.blitBitmap(0, curY, &imgDest, 0, curY, _screenWidth, 2, false);
|
||||
checkerBoardEffect(0, 0, curY, _screenWidth - 1, curY + 1);
|
||||
} else {
|
||||
uint16 bitmapHeight = (curY == lastY) ? 1 : 2;
|
||||
imgSource.blitBitmap(0, curY, &imgDest, 0, curY, _screenWidth, bitmapHeight, false);
|
||||
}
|
||||
curY += 4;
|
||||
linesDone++;
|
||||
} // while
|
||||
} // for i
|
||||
} // for j
|
||||
|
||||
// bitMapBuffer will be deleted by the Image destructor
|
||||
}
|
||||
|
||||
void DisplayMan::doTransition(TransitionType transitionType, const Common::String &filename) {
|
||||
switch (transitionType) {
|
||||
case kTransitionWipe:
|
||||
case kTransitionTransporter:
|
||||
doTransWipe(filename);
|
||||
break;
|
||||
case kTransitionScrollWipe: // only used in scene 7 (street, when teleporting to the surreal maze)
|
||||
doScrollWipe(filename);
|
||||
break;
|
||||
case kTransitionScrollBlack: // only used in scene 7 (street, when teleporting to the surreal maze)
|
||||
doScrollBlack();
|
||||
break;
|
||||
case kTransitionScrollBounce: // only used in scene 7 (street, when teleporting to the surreal maze)
|
||||
doScrollBounce();
|
||||
break;
|
||||
case kTransitionReadFirstFrame: // only used in scene 7 (street, when teleporting to the surreal maze)
|
||||
readPict(filename, false);
|
||||
break;
|
||||
case kTransitionReadNextFrame: // only used in scene 7 (street, when teleporting to the surreal maze)
|
||||
_vm->_anim->diffNextFrame();
|
||||
break;
|
||||
case kTransitionNone:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayMan::blackScreen() {
|
||||
byte pal[256 * 3];
|
||||
memset(pal, 0, 248 * 3);
|
||||
writeColorRegs(pal, 8, 248);
|
||||
|
||||
_vm->_system->delayMillis(32);
|
||||
}
|
||||
|
||||
void DisplayMan::whiteScreen() {
|
||||
byte pal[256 * 3];
|
||||
memset(pal, 255, 248 * 3);
|
||||
writeColorRegs(pal, 8, 248);
|
||||
}
|
||||
|
||||
void DisplayMan::blackAllScreen() {
|
||||
byte pal[256 * 3];
|
||||
memset(pal, 0, 256 * 3);
|
||||
writeColorRegs(pal, 0, 256);
|
||||
|
||||
_vm->_system->delayMillis(32);
|
||||
}
|
||||
|
||||
void DisplayMan::scrollDisplayX(int16 dx, uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte *buffer) {
|
||||
Image img(_vm);
|
||||
img.setData(buffer, false);
|
||||
|
||||
if (x1 > x2)
|
||||
SWAP<uint16>(x1, x2);
|
||||
|
||||
if (y1 > y2)
|
||||
SWAP<uint16>(y1, y2);
|
||||
|
||||
if (dx > 0) {
|
||||
img._width = x2 - x1 + 1 - dx;
|
||||
img._height = y2 - y1 + 1;
|
||||
|
||||
img.readScreenImage(x1, y1);
|
||||
img.drawImage(x1 + dx, y1);
|
||||
|
||||
rectFill(x1, y1, x1 + dx - 1, y2, 0);
|
||||
} else if (dx < 0) {
|
||||
img._width = x2 - x1 + 1 + dx;
|
||||
img._height = y2 - y1 + 1;
|
||||
|
||||
img.readScreenImage(x1 - dx, y1);
|
||||
img.drawImage(x1, y1);
|
||||
|
||||
rectFill(x2 + dx + 1, y1, x2, y2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayMan::scrollDisplayY(int16 dy, uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte *buffer) {
|
||||
Image img(_vm);
|
||||
img.setData(buffer, false);
|
||||
|
||||
if (x1 > x2)
|
||||
SWAP<uint16>(x1, x2);
|
||||
|
||||
if (y1 > y2)
|
||||
SWAP<uint16>(y1, y2);
|
||||
|
||||
if (dy > 0) {
|
||||
img._width = x2 - x1 + 1;
|
||||
img._height = y2 - y1 + 1 - dy;
|
||||
|
||||
img.readScreenImage(x1, y1);
|
||||
img.drawImage(x1, y1 + dy);
|
||||
|
||||
rectFill(x1, y1, x2, y1 + dy - 1, 0);
|
||||
} else if (dy < 0) {
|
||||
img._width = x2 - x1 + 1;
|
||||
img._height = y2 - y1 + 1 + dy;
|
||||
|
||||
img.readScreenImage(x1, y1 - dy);
|
||||
img.drawImage(x1, y1);
|
||||
|
||||
rectFill(x1, y2 + dy + 1, x2, y2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
uint16 DisplayMan::fadeNumIn(uint16 num, uint16 res, uint16 counter) {
|
||||
return (num - ((((int32)(15 - counter)) * ((int32)(num - res))) / 15));
|
||||
}
|
||||
|
||||
uint16 DisplayMan::fadeNumOut(uint16 num, uint16 res, uint16 counter) {
|
||||
return (num - ((((int32) counter) * ((int32)(num - res))) / 15));
|
||||
}
|
||||
|
||||
void DisplayMan::fade(bool fadeIn) {
|
||||
uint16 newPal[16];
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int palIdx = 0; palIdx < 16; palIdx++) {
|
||||
if (fadeIn)
|
||||
newPal[palIdx] =
|
||||
(0x00F & fadeNumIn(0x00F & _fadePalette[palIdx], 0, i)) +
|
||||
(0x0F0 & fadeNumIn(0x0F0 & _fadePalette[palIdx], 0, i)) +
|
||||
(0xF00 & fadeNumIn(0xF00 & _fadePalette[palIdx], 0, i));
|
||||
else
|
||||
newPal[palIdx] =
|
||||
(0x00F & fadeNumOut(0x00F & _fadePalette[palIdx], 0, i)) +
|
||||
(0x0F0 & fadeNumOut(0x0F0 & _fadePalette[palIdx], 0, i)) +
|
||||
(0xF00 & fadeNumOut(0xF00 & _fadePalette[palIdx], 0, i));
|
||||
}
|
||||
|
||||
setAmigaPal(newPal);
|
||||
_vm->updateEvents();
|
||||
_vm->waitTOF();
|
||||
_vm->waitTOF();
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Lab
|
||||
273
engines/lab/dispman.h
Normal file
273
engines/lab/dispman.h
Normal file
@@ -0,0 +1,273 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LAB_DISPMAN_H
|
||||
#define LAB_DISPMAN_H
|
||||
|
||||
namespace Lab {
|
||||
|
||||
class LabEngine;
|
||||
class Image;
|
||||
|
||||
struct TextFont {
|
||||
uint32 _dataLength;
|
||||
uint16 _height;
|
||||
byte _widths[256];
|
||||
uint16 _offsets[256];
|
||||
byte *_data;
|
||||
};
|
||||
|
||||
enum TransitionType {
|
||||
kTransitionNone,
|
||||
kTransitionWipe,
|
||||
kTransitionScrollWipe,
|
||||
kTransitionScrollBlack,
|
||||
kTransitionScrollBounce,
|
||||
kTransitionTransporter,
|
||||
kTransitionReadFirstFrame,
|
||||
kTransitionReadNextFrame
|
||||
};
|
||||
|
||||
class DisplayMan {
|
||||
private:
|
||||
LabEngine *_vm;
|
||||
|
||||
/**
|
||||
* Does the fading of the Palette on the screen.
|
||||
*/
|
||||
uint16 fadeNumIn(uint16 num, uint16 res, uint16 counter);
|
||||
uint16 fadeNumOut(uint16 num, uint16 res, uint16 counter);
|
||||
|
||||
/**
|
||||
* Extracts the first word from a string.
|
||||
*/
|
||||
Common::String getWord(const char *mainBuffer);
|
||||
|
||||
void createBox(uint16 y2);
|
||||
|
||||
/**
|
||||
* Sets up either a low-res or a high-res 256 color screen.
|
||||
*/
|
||||
void createScreen(bool hiRes);
|
||||
|
||||
/**
|
||||
* Scrolls the display to black.
|
||||
*/
|
||||
void doScrollBlack();
|
||||
void copyPage(uint16 width, uint16 height, uint16 nheight, uint16 startline, byte *mem);
|
||||
|
||||
/**
|
||||
* Scrolls the display to a new picture from a black screen.
|
||||
*/
|
||||
void doScrollWipe(const Common::String &filename);
|
||||
|
||||
/**
|
||||
* Does the scroll bounce. Assumes bitmap already in memory.
|
||||
*/
|
||||
void doScrollBounce();
|
||||
|
||||
/**
|
||||
* Does the transporter wipe.
|
||||
*/
|
||||
void doTransWipe(const Common::String &filename);
|
||||
|
||||
/**
|
||||
* Draws a vertical line.
|
||||
*/
|
||||
void drawHLine(uint16 x, uint16 y1, uint16 y2, byte color);
|
||||
|
||||
/**
|
||||
* Draws a horizontal line.
|
||||
*/
|
||||
void drawVLine(uint16 x1, uint16 y, uint16 x2, byte color);
|
||||
|
||||
/**
|
||||
* Draws the text to the screen.
|
||||
*/
|
||||
void drawText(TextFont *tf, uint16 x, uint16 y, uint16 color, const Common::String &text);
|
||||
|
||||
/**
|
||||
* Gets a line of text for flowText; makes sure that its length is less than
|
||||
* or equal to the maximum width.
|
||||
*/
|
||||
Common::String getLine(TextFont *tf, const char **mainBuffer, uint16 lineWidth);
|
||||
|
||||
/**
|
||||
* Returns the length of a text in the specified font.
|
||||
*/
|
||||
uint16 textLength(TextFont *font, const Common::String &text);
|
||||
|
||||
bool _actionMessageShown;
|
||||
Common::File *_curBitmap;
|
||||
byte _curVgaPal[256 * 3];
|
||||
byte *_currentDisplayBuffer;
|
||||
|
||||
public:
|
||||
DisplayMan(LabEngine *lab);
|
||||
virtual ~DisplayMan();
|
||||
|
||||
void loadPict(const Common::String &filename);
|
||||
void loadBackPict(const Common::String &fileName, uint16 *highPal);
|
||||
|
||||
/**
|
||||
* Reads in a picture into the display bitmap.
|
||||
*/
|
||||
void readPict(const Common::String &filename, bool playOnce = true, bool onlyDiffData = false, byte *memoryBuffer = nullptr);
|
||||
void freePict();
|
||||
|
||||
/**
|
||||
* Does a certain number of pre-programmed wipes.
|
||||
*/
|
||||
void doTransition(TransitionType transitionType, const Common::String &filename);
|
||||
|
||||
/**
|
||||
* Changes the front screen to black.
|
||||
*/
|
||||
void blackScreen();
|
||||
|
||||
/**
|
||||
* Changes the front screen to white.
|
||||
*/
|
||||
void whiteScreen();
|
||||
|
||||
/**
|
||||
* Changes the entire screen to black.
|
||||
*/
|
||||
void blackAllScreen();
|
||||
|
||||
/**
|
||||
* Draws the control panel display.
|
||||
*/
|
||||
void drawPanel();
|
||||
|
||||
/**
|
||||
* Sets up the Labyrinth screens, and opens up the initial windows.
|
||||
*/
|
||||
void setUpScreens();
|
||||
|
||||
int longDrawMessage(Common::String str, bool isActionMessage);
|
||||
|
||||
/**
|
||||
* Draws a message to the message box.
|
||||
*/
|
||||
void drawMessage(Common::String str, bool isActionMessage);
|
||||
|
||||
void setActionMessage(bool val) { _actionMessageShown = val; }
|
||||
|
||||
/**
|
||||
* Fills in a rectangle.
|
||||
*/
|
||||
void rectFill(uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte color);
|
||||
void rectFill(Common::Rect fillRect, byte color);
|
||||
void rectFillScaled(uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte color);
|
||||
/**
|
||||
* Dumps a chunk of text to an arbitrary box; flows it within that box and
|
||||
* optionally centers it. Returns the number of characters that were processed.
|
||||
* @note Every individual word MUST be int16 enough to fit on a line, and
|
||||
* each line less than 255 characters.
|
||||
* @param font Pointer on the font used
|
||||
* @param spacing How much vertical spacing between the lines
|
||||
* @param penColor Pen number to use for text
|
||||
* @param backPen Background color
|
||||
* @param fillBack Whether to fill the background
|
||||
* @param centerh Whether to center the text horizontally
|
||||
* @param centerv Whether to center the text vertically
|
||||
* @param output Whether to output any text
|
||||
* @param textRect Coords
|
||||
* @param text The text itself
|
||||
*/
|
||||
int flowText(TextFont *font, int16 spacing, byte penColor, byte backPen, bool fillBack,
|
||||
bool centerh, bool centerv, bool output, Common::Rect textRect, const char *text, Image *targetImage = nullptr);
|
||||
|
||||
void screenUpdate();
|
||||
|
||||
/**
|
||||
* Converts a 16-color Amiga palette to a VGA palette, then sets
|
||||
* the VGA palette.
|
||||
*/
|
||||
void setAmigaPal(uint16 *pal);
|
||||
|
||||
/**
|
||||
* Writes any number of the 256 color registers.
|
||||
* @param buf A char pointer which contains the selected color registers.
|
||||
* Each value representing a color register occupies 3 bytes in the array. The
|
||||
* order is red, green then blue. The first byte in the array is the red component
|
||||
* of the first element selected. The length of the buffer is 3 times the number
|
||||
* of registers selected.
|
||||
* @param first The number of the first color register to write.
|
||||
* @param numReg The number of registers to write.
|
||||
*/
|
||||
void writeColorRegs(byte *buf, uint16 first, uint16 numReg);
|
||||
void setPalette(void *newPal, uint16 numColors);
|
||||
|
||||
/**
|
||||
* Overlays a region on the screen using the desired pen color.
|
||||
*/
|
||||
void checkerBoardEffect(uint16 penColor, uint16 x1, uint16 y1, uint16 x2, uint16 y2);
|
||||
|
||||
/**
|
||||
* Returns the base address of the current VGA display.
|
||||
*/
|
||||
byte *getCurrentDrawingBuffer();
|
||||
|
||||
/**
|
||||
* Scrolls the display in the x direction by blitting.
|
||||
* The _tempScrollData variable must be initialized to some memory, or this
|
||||
* function will fail.
|
||||
*/
|
||||
void scrollDisplayX(int16 dx, uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte *buffer);
|
||||
|
||||
/**
|
||||
* Scrolls the display in the y direction by blitting.
|
||||
*/
|
||||
void scrollDisplayY(int16 dy, uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte *buffer);
|
||||
void fade(bool fadein);
|
||||
|
||||
/**
|
||||
* Closes a font and frees all memory associated with it.
|
||||
*/
|
||||
void freeFont(TextFont **font);
|
||||
|
||||
/**
|
||||
* Returns the height of a specified font.
|
||||
*/
|
||||
uint16 textHeight(TextFont *tf);
|
||||
|
||||
bool _longWinInFront;
|
||||
bool _lastMessageLong;
|
||||
uint32 _screenBytesPerPage;
|
||||
int _screenWidth;
|
||||
int _screenHeight;
|
||||
byte *_displayBuffer;
|
||||
uint16 *_fadePalette;
|
||||
};
|
||||
|
||||
} // End of namespace Lab
|
||||
|
||||
#endif // LAB_DISPMAN_H
|
||||
1217
engines/lab/engine.cpp
Normal file
1217
engines/lab/engine.cpp
Normal file
File diff suppressed because it is too large
Load Diff
191
engines/lab/eventman.cpp
Normal file
191
engines/lab/eventman.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/events.h"
|
||||
|
||||
#include "graphics/cursorman.h"
|
||||
|
||||
#include "lab/lab.h"
|
||||
|
||||
#include "lab/dispman.h"
|
||||
#include "lab/eventman.h"
|
||||
#include "lab/image.h"
|
||||
#include "lab/interface.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
static const byte mouseData[] = {
|
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 7, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 7, 7, 1, 0, 0, 0, 0, 0, 0,
|
||||
1, 7, 7, 7, 1, 0, 0, 0, 0, 0,
|
||||
1, 7, 7, 7, 7, 1, 0, 0, 0, 0,
|
||||
1, 7, 7, 7, 7, 7, 1, 0, 0, 0,
|
||||
1, 7, 7, 7, 7, 7, 7, 1, 0, 0,
|
||||
1, 7, 7, 7, 7, 7, 7, 7, 1, 0,
|
||||
1, 7, 7, 7, 7, 7, 1, 1, 1, 1,
|
||||
1, 7, 7, 1, 7, 7, 1, 0, 0, 0,
|
||||
1, 7, 1, 0, 1, 7, 7, 1, 0, 0,
|
||||
1, 1, 0, 0, 1, 7, 7, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 7, 7, 1, 0,
|
||||
0, 0, 0, 0, 0, 1, 7, 7, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 0, 0
|
||||
};
|
||||
|
||||
#define MOUSE_WIDTH 10
|
||||
#define MOUSE_HEIGHT 15
|
||||
|
||||
EventManager::EventManager(LabEngine *vm) : _vm(vm) {
|
||||
_leftClick = false;
|
||||
_rightClick = false;
|
||||
_buttonHit = false;
|
||||
_mousePos = Common::Point(0, 0);
|
||||
_actionPressed = kActionNone;
|
||||
}
|
||||
|
||||
void EventManager::initMouse() {
|
||||
CursorMan.pushCursor(mouseData, MOUSE_WIDTH, MOUSE_HEIGHT, 0, 0, 0);
|
||||
CursorMan.showMouse(false);
|
||||
|
||||
setMousePos(Common::Point(_vm->_graphics->_screenWidth / 2, _vm->_graphics->_screenHeight / 2));
|
||||
}
|
||||
|
||||
void EventManager::mouseShow() {
|
||||
CursorMan.showMouse(true);
|
||||
}
|
||||
|
||||
void EventManager::mouseHide() {
|
||||
CursorMan.showMouse(false);
|
||||
}
|
||||
|
||||
void EventManager::setMousePos(Common::Point pos) {
|
||||
if (_vm->_isHiRes)
|
||||
_vm->_system->warpMouse(pos.x, pos.y);
|
||||
else
|
||||
_vm->_system->warpMouse(pos.x * 2, pos.y);
|
||||
}
|
||||
|
||||
void EventManager::processInput() {
|
||||
Common::Event event;
|
||||
|
||||
while (_vm->_system->getEventManager()->pollEvent(event)) {
|
||||
switch (event.type) {
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
if (_vm->_interface->checkButtonHit(_mousePos))
|
||||
_buttonHit = true;
|
||||
else
|
||||
_leftClick = true;
|
||||
break;
|
||||
case Common::EVENT_RBUTTONDOWN:
|
||||
_rightClick = true;
|
||||
break;
|
||||
case Common::EVENT_MOUSEMOVE:
|
||||
_mousePos = event.mouse;
|
||||
break;
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
|
||||
switch (event.customType) {
|
||||
case kActionSoundLower:
|
||||
_vm->changeVolume(-1);
|
||||
break;
|
||||
case kActionSoundRaise:
|
||||
_vm->changeVolume(1);
|
||||
break;
|
||||
default:
|
||||
_actionPressed = event.customType;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Common::EVENT_KEYDOWN:
|
||||
_actionPressed = kActionQuitDialogNo; // Used for "Press any key to continue" scenarios as well.
|
||||
break;
|
||||
case Common::EVENT_QUIT:
|
||||
case Common::EVENT_RETURN_TO_LAUNCHER:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IntuiMessage *EventManager::getMsg() {
|
||||
static IntuiMessage message;
|
||||
|
||||
_vm->_interface->handlePressedButton();
|
||||
processInput();
|
||||
|
||||
if (_buttonHit) {
|
||||
Button *lastButtonHit = _vm->_interface->checkButtonHit(_mousePos);
|
||||
_buttonHit = false;
|
||||
if (lastButtonHit) {
|
||||
_vm->_interface->handlePressedButton();
|
||||
message._msgClass = kMessageButtonUp;
|
||||
message._code = lastButtonHit->_buttonId;
|
||||
message._qualifier = 0; // This does not seem to be used anywhere. Since qualifiers can be detected by keymapper anyways, this is set to 0.
|
||||
|
||||
return &message;
|
||||
} else
|
||||
return nullptr;
|
||||
} else if (_leftClick || _rightClick) {
|
||||
message._msgClass = (_leftClick) ? kMessageLeftClick : kMessageRightClick;
|
||||
message._qualifier = 0;
|
||||
message._mouse = _mousePos;
|
||||
_leftClick = _rightClick = false;
|
||||
return &message;
|
||||
} else if (_actionPressed != kActionNone) {
|
||||
Button *curButton = _vm->_interface->checkNumButtonHit(_actionPressed);
|
||||
|
||||
if (curButton) {
|
||||
message._msgClass = kMessageButtonUp;
|
||||
message._code = curButton->_buttonId;
|
||||
} else {
|
||||
message._msgClass = kMessageAction;
|
||||
message._code = _actionPressed;
|
||||
}
|
||||
|
||||
message._qualifier = 0; // This does not seem to be used anywhere. Since qualifiers can be detected by keymapper anyways, this is set to 0.
|
||||
message._mouse = _mousePos;
|
||||
|
||||
_actionPressed = kActionNone;
|
||||
|
||||
return &message;
|
||||
} else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Common::Point EventManager::updateAndGetMousePos() {
|
||||
processInput();
|
||||
|
||||
return _mousePos;
|
||||
}
|
||||
|
||||
void EventManager::simulateEvent() {
|
||||
// Simulate an event by setting an unused action.
|
||||
_actionPressed = kActionDummy;
|
||||
}
|
||||
|
||||
} // End of namespace Lab
|
||||
94
engines/lab/eventman.h
Normal file
94
engines/lab/eventman.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LAB_EVENTMAN_H
|
||||
#define LAB_EVENTMAN_H
|
||||
|
||||
#include "common/events.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
class LabEngine;
|
||||
class Image;
|
||||
|
||||
struct IntuiMessage {
|
||||
MessageClass _msgClass;
|
||||
uint16 _code; // Action or Button Id
|
||||
uint16 _qualifier;
|
||||
Common::Point _mouse;
|
||||
};
|
||||
|
||||
class EventManager {
|
||||
private:
|
||||
LabEngine *_vm;
|
||||
|
||||
bool _leftClick;
|
||||
bool _rightClick;
|
||||
bool _buttonHit;
|
||||
|
||||
Common::Point _mousePos;
|
||||
Common::CustomEventType _actionPressed;
|
||||
|
||||
public:
|
||||
EventManager (LabEngine *vm);
|
||||
|
||||
IntuiMessage *getMsg();
|
||||
|
||||
/**
|
||||
* Initializes the mouse.
|
||||
*/
|
||||
void initMouse();
|
||||
|
||||
/**
|
||||
* Shows the mouse.
|
||||
*/
|
||||
void mouseShow();
|
||||
|
||||
/**
|
||||
* Hides the mouse.
|
||||
*/
|
||||
void mouseHide();
|
||||
void processInput();
|
||||
|
||||
/**
|
||||
* Moves the mouse to new co-ordinates.
|
||||
*/
|
||||
void setMousePos(Common::Point pos);
|
||||
Common::Point updateAndGetMousePos();
|
||||
|
||||
/**
|
||||
* Simulates an event for the game main loop, when a game is
|
||||
* loaded or when the user teleports to a scene
|
||||
*/
|
||||
void simulateEvent();
|
||||
};
|
||||
|
||||
} // End of namespace Lab
|
||||
|
||||
#endif // LAB_EVENTMAN_H
|
||||
135
engines/lab/image.cpp
Normal file
135
engines/lab/image.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/file.h"
|
||||
|
||||
#include "lab/lab.h"
|
||||
|
||||
#include "lab/dispman.h"
|
||||
#include "lab/image.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
Image::Image(Common::File *s, LabEngine *vm) : _vm(vm) {
|
||||
_width = s->readUint16LE();
|
||||
_height = s->readUint16LE();
|
||||
s->skip(4);
|
||||
|
||||
uint32 size = _width * _height;
|
||||
if (size & 1)
|
||||
size++;
|
||||
|
||||
_imageData = new byte[size];
|
||||
s->read(_imageData, size);
|
||||
_autoFree = true;
|
||||
}
|
||||
|
||||
Image::~Image() {
|
||||
if (_autoFree)
|
||||
delete[] _imageData;
|
||||
}
|
||||
|
||||
void Image::setData(byte *d, bool autoFree) {
|
||||
if (_autoFree)
|
||||
delete[] _imageData;
|
||||
_imageData = d;
|
||||
_autoFree = autoFree;
|
||||
}
|
||||
|
||||
void Image::blitBitmap(uint16 srcX, uint16 srcY, Image *imgDest,
|
||||
uint16 destX, uint16 destY, uint16 width, uint16 height, byte masked) {
|
||||
int clipWidth = width;
|
||||
int clipHeight = height;
|
||||
int destWidth = (imgDest) ? imgDest->_width : _vm->_graphics->_screenWidth;
|
||||
int destHeight = (imgDest) ? imgDest->_height : _vm->_graphics->_screenHeight;
|
||||
byte *destBuffer = (imgDest) ? imgDest->_imageData : _vm->_graphics->getCurrentDrawingBuffer();
|
||||
|
||||
if (destX + clipWidth > destWidth)
|
||||
clipWidth = destWidth - destX;
|
||||
|
||||
if (destY + clipHeight > destHeight)
|
||||
clipHeight = destHeight - destY;
|
||||
|
||||
if ((clipWidth > 0) && (clipHeight > 0)) {
|
||||
byte *img = _imageData + srcY * _width + srcX;
|
||||
byte *dest = destBuffer + destY * destWidth + destX;
|
||||
|
||||
if (!masked) {
|
||||
for (int i = 0; i < clipHeight; i++) {
|
||||
memcpy(dest, img, clipWidth);
|
||||
img += _width;
|
||||
dest += destWidth;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < clipHeight; i++) {
|
||||
for (int j = 0; j < clipWidth; j++) {
|
||||
byte c = img[j];
|
||||
|
||||
if (c)
|
||||
dest[j] = c - 1;
|
||||
}
|
||||
|
||||
img += _width;
|
||||
dest += destWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Image::drawImage(uint16 x, uint16 y) {
|
||||
blitBitmap(0, 0, nullptr, x, y, _width, _height, false);
|
||||
}
|
||||
|
||||
void Image::drawMaskImage(uint16 x, uint16 y) {
|
||||
blitBitmap(0, 0, nullptr, x, y, _width, _height, true);
|
||||
}
|
||||
|
||||
void Image::readScreenImage(uint16 x, uint16 y) {
|
||||
int clipWidth = _width;
|
||||
int clipHeight = _height;
|
||||
|
||||
if (x + clipWidth > _vm->_graphics->_screenWidth)
|
||||
clipWidth = _vm->_graphics->_screenWidth - x;
|
||||
|
||||
if (y + clipHeight > _vm->_graphics->_screenHeight)
|
||||
clipHeight = _vm->_graphics->_screenHeight - y;
|
||||
|
||||
if ((clipWidth > 0) && (clipHeight > 0)) {
|
||||
byte *img = _imageData;
|
||||
byte *screen = _vm->_graphics->getCurrentDrawingBuffer() + y * _vm->_graphics->_screenWidth + x;
|
||||
|
||||
while (clipHeight-- > 0) {
|
||||
memcpy(img, screen, clipWidth);
|
||||
img += _width;
|
||||
screen += _vm->_graphics->_screenWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Lab
|
||||
82
engines/lab/image.h
Normal file
82
engines/lab/image.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LAB_IMAGE_H
|
||||
#define LAB_IMAGE_H
|
||||
|
||||
namespace Common {
|
||||
class File;
|
||||
}
|
||||
|
||||
namespace Lab {
|
||||
|
||||
class LabEngine;
|
||||
|
||||
class Image {
|
||||
LabEngine *_vm;
|
||||
|
||||
public:
|
||||
uint16 _width;
|
||||
uint16 _height;
|
||||
byte *_imageData;
|
||||
|
||||
Image(LabEngine *vm) : _width(0), _height(0), _imageData(nullptr), _vm(vm), _autoFree(true) {}
|
||||
Image(int w, int h, byte *d, LabEngine *vm, bool autoFree = true) : _width(w), _height(h), _imageData(d), _vm(vm), _autoFree(autoFree) {}
|
||||
Image(Common::File *s, LabEngine *vm);
|
||||
~Image();
|
||||
|
||||
void setData(byte *d, bool autoFree = true);
|
||||
|
||||
/**
|
||||
* Draws an image to the screen.
|
||||
*/
|
||||
void drawImage(uint16 x, uint16 y);
|
||||
|
||||
/**
|
||||
* Draws an image to the screen with transparency.
|
||||
*/
|
||||
void drawMaskImage(uint16 x, uint16 y);
|
||||
|
||||
/**
|
||||
* Reads an image from the screen.
|
||||
*/
|
||||
void readScreenImage(uint16 x, uint16 y);
|
||||
|
||||
/**
|
||||
* Blits a piece of one image to another.
|
||||
*/
|
||||
void blitBitmap(uint16 srcX, uint16 srcY, Image *imgDest, uint16 destX, uint16 destY, uint16 width, uint16 height, byte masked);
|
||||
|
||||
private:
|
||||
bool _autoFree; ///< Free _imageData in destructor?
|
||||
};
|
||||
|
||||
} // End of namespace Lab
|
||||
|
||||
#endif // LAB_IMAGE_H
|
||||
231
engines/lab/interface.cpp
Normal file
231
engines/lab/interface.cpp
Normal file
@@ -0,0 +1,231 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/events.h"
|
||||
|
||||
#include "lab/lab.h"
|
||||
|
||||
#include "lab/dispman.h"
|
||||
#include "lab/interface.h"
|
||||
#include "lab/image.h"
|
||||
#include "lab/utils.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
#define CRUMBSWIDTH 24
|
||||
#define CRUMBSHEIGHT 24
|
||||
|
||||
Interface::Interface(LabEngine *vm) : _vm(vm) {
|
||||
_screenButtonList = nullptr;
|
||||
_hitButton = nullptr;
|
||||
}
|
||||
|
||||
Button *Interface::createButton(uint16 x, uint16 y, uint16 id, Common::CustomEventType action, Image *image, Image *altImage) {
|
||||
Button *button = new Button();
|
||||
|
||||
if (button) {
|
||||
button->_x = _vm->_utils->vgaScaleX(x);
|
||||
button->_y = y;
|
||||
button->_buttonId = id;
|
||||
button->_actionEquiv = action;
|
||||
button->_image = image;
|
||||
button->_altImage = altImage;
|
||||
button->_isEnabled = true;
|
||||
|
||||
return button;
|
||||
} else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Interface::freeButtonList(ButtonList *buttonList) {
|
||||
for (auto &button : *buttonList) {
|
||||
delete button->_image;
|
||||
delete button->_altImage;
|
||||
delete button;
|
||||
}
|
||||
|
||||
buttonList->clear();
|
||||
}
|
||||
|
||||
void Interface::drawButtonList(ButtonList *buttonList) {
|
||||
for (auto &button : *buttonList) {
|
||||
toggleButton(button, 1, true);
|
||||
|
||||
if (!button->_isEnabled)
|
||||
toggleButton(button, 1, false);
|
||||
}
|
||||
}
|
||||
|
||||
void Interface::toggleButton(Button *button, uint16 disabledPenColor, bool enable) {
|
||||
if (!enable)
|
||||
_vm->_graphics->checkerBoardEffect(disabledPenColor, button->_x, button->_y, button->_x + button->_image->_width - 1, button->_y + button->_image->_height - 1);
|
||||
else
|
||||
button->_image->drawImage(button->_x, button->_y);
|
||||
|
||||
button->_isEnabled = enable;
|
||||
}
|
||||
|
||||
Button *Interface::checkNumButtonHit(Common::CustomEventType action) {
|
||||
if (!_screenButtonList)
|
||||
return nullptr;
|
||||
|
||||
for (auto &button : *_screenButtonList) {
|
||||
if (!button->_isEnabled)
|
||||
continue;
|
||||
|
||||
if ((button->_actionEquiv != kActionNone && action == button->_actionEquiv)) {
|
||||
button->_altImage->drawImage(button->_x, button->_y);
|
||||
_vm->_system->delayMillis(80);
|
||||
button->_image->drawImage(button->_x, button->_y);
|
||||
return button;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Button *Interface::checkButtonHit(Common::Point pos) {
|
||||
if (!_screenButtonList)
|
||||
return nullptr;
|
||||
|
||||
for (auto &button : *_screenButtonList) {
|
||||
Common::Rect buttonRect(button->_x, button->_y, button->_x + button->_image->_width - 1, button->_y + button->_image->_height - 1);
|
||||
|
||||
if (buttonRect.contains(pos) && button->_isEnabled) {
|
||||
_hitButton = button;
|
||||
return button;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Interface::handlePressedButton() {
|
||||
if (!_hitButton)
|
||||
return;
|
||||
|
||||
_hitButton->_altImage->drawImage(_hitButton->_x, _hitButton->_y);
|
||||
for (int i = 0; i < 3; i++)
|
||||
_vm->waitTOF();
|
||||
_hitButton->_image->drawImage(_hitButton->_x, _hitButton->_y);
|
||||
|
||||
_hitButton = nullptr;
|
||||
_vm->_graphics->screenUpdate();
|
||||
}
|
||||
|
||||
void Interface::attachButtonList(ButtonList *buttonList) {
|
||||
_screenButtonList = buttonList;
|
||||
}
|
||||
|
||||
Button *Interface::getButton(uint16 id) {
|
||||
for (auto &button : *_screenButtonList) {
|
||||
if (button->_buttonId == id)
|
||||
return button;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Interface::mayShowCrumbIndicator() {
|
||||
static byte dropCrumbsImageData[CRUMBSWIDTH * CRUMBSHEIGHT] = {
|
||||
0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0,
|
||||
0, 4, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 4, 0,
|
||||
4, 7, 7, 3, 4, 4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 7, 7, 4,
|
||||
4, 7, 4, 4, 0, 0, 3, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 7, 4,
|
||||
4, 7, 4, 0, 0, 0, 3, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 7, 4,
|
||||
4, 7, 4, 0, 0, 3, 2, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0, 3, 2, 3, 0, 4, 7, 4,
|
||||
4, 7, 4, 0, 0, 0, 3, 3, 3, 4, 4, 4, 4, 4, 4, 0, 0, 3, 2, 3, 0, 4, 7, 4,
|
||||
4, 7, 4, 0, 0, 0, 0, 0, 4, 7, 7, 7, 7, 7, 7, 4, 3, 2, 2, 2, 3, 4, 7, 4,
|
||||
4, 7, 4, 0, 0, 0, 0, 4, 7, 7, 4, 4, 4, 4, 7, 7, 4, 3, 3, 3, 0, 4, 7, 4,
|
||||
4, 7, 4, 0, 0, 0, 0, 4, 7, 4, 4, 0, 0, 4, 4, 7, 4, 0, 0, 0, 0, 4, 7, 4,
|
||||
4, 7, 4, 0, 0, 0, 0, 4, 7, 4, 0, 0, 0, 0, 4, 7, 4, 0, 0, 0, 0, 4, 7, 4,
|
||||
4, 7, 4, 0, 0, 0, 0, 4, 4, 4, 3, 0, 0, 0, 4, 7, 4, 0, 0, 0, 0, 4, 7, 4,
|
||||
4, 7, 4, 0, 0, 0, 0, 0, 4, 3, 2, 3, 0, 0, 4, 7, 4, 0, 0, 0, 0, 4, 7, 4,
|
||||
4, 7, 4, 0, 0, 0, 0, 0, 0, 3, 2, 3, 0, 0, 4, 7, 4, 0, 0, 0, 0, 4, 7, 4,
|
||||
4, 7, 4, 0, 0, 0, 0, 0, 3, 2, 2, 2, 3, 4, 4, 7, 4, 0, 0, 0, 0, 4, 7, 4,
|
||||
4, 7, 7, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, 7, 4, 0, 0, 0, 0, 4, 7, 4,
|
||||
0, 4, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 4, 0, 0, 0, 0, 0, 4, 7, 4,
|
||||
0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 0, 0, 0, 0, 0, 4, 7, 4,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 3, 0, 0, 0, 0, 4, 7, 4,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 3, 0, 0, 0, 0, 4, 7, 4,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 2, 2, 3, 0, 0, 4, 4, 7, 4,
|
||||
0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, 7, 4,
|
||||
0, 0, 4, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 4, 0,
|
||||
0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0
|
||||
};
|
||||
|
||||
if (_vm->getPlatform() != Common::kPlatformWindows)
|
||||
return;
|
||||
|
||||
if (_vm->_droppingCrumbs && _vm->isMainDisplay()) {
|
||||
Image dropCrumbsImage(CRUMBSWIDTH, CRUMBSHEIGHT, dropCrumbsImageData, _vm, false);
|
||||
|
||||
dropCrumbsImage.drawMaskImage(612, 4);
|
||||
}
|
||||
}
|
||||
|
||||
void Interface::mayShowCrumbIndicatorOff() {
|
||||
static byte dropCrumbsOffImageData[CRUMBSWIDTH * CRUMBSHEIGHT] = {
|
||||
0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0,
|
||||
0, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 0,
|
||||
4, 8, 8, 3, 4, 4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 8, 8, 4,
|
||||
4, 8, 4, 4, 0, 0, 3, 8, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 8, 4,
|
||||
4, 8, 4, 0, 0, 0, 3, 8, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4, 8, 4,
|
||||
4, 8, 4, 0, 0, 3, 8, 8, 8, 3, 0, 0, 0, 0, 0, 0, 0, 3, 8, 3, 0, 4, 8, 4,
|
||||
4, 8, 4, 0, 0, 0, 3, 3, 3, 4, 4, 4, 4, 4, 4, 0, 0, 3, 8, 3, 0, 4, 8, 4,
|
||||
4, 8, 4, 0, 0, 0, 0, 0, 4, 8, 8, 8, 8, 8, 8, 4, 3, 8, 8, 8, 3, 4, 8, 4,
|
||||
4, 8, 4, 0, 0, 0, 0, 4, 8, 8, 4, 4, 4, 4, 8, 8, 4, 3, 3, 3, 0, 4, 8, 4,
|
||||
4, 8, 4, 0, 0, 0, 0, 4, 8, 4, 4, 0, 0, 4, 4, 8, 4, 0, 0, 0, 0, 4, 8, 4,
|
||||
4, 8, 4, 0, 0, 0, 0, 4, 8, 4, 0, 0, 0, 0, 4, 8, 4, 0, 0, 0, 0, 4, 8, 4,
|
||||
4, 8, 4, 0, 0, 0, 0, 4, 4, 4, 3, 0, 0, 0, 4, 8, 4, 0, 0, 0, 0, 4, 8, 4,
|
||||
4, 8, 4, 0, 0, 0, 0, 0, 4, 3, 8, 3, 0, 0, 4, 8, 4, 0, 0, 0, 0, 4, 8, 4,
|
||||
4, 8, 4, 0, 0, 0, 0, 0, 0, 3, 8, 3, 0, 0, 4, 8, 4, 0, 0, 0, 0, 4, 8, 4,
|
||||
4, 8, 4, 0, 0, 0, 0, 0, 3, 8, 8, 8, 3, 4, 4, 8, 4, 0, 0, 0, 0, 4, 8, 4,
|
||||
4, 8, 8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 4, 0, 0, 0, 0, 4, 8, 4,
|
||||
0, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 0, 0, 0, 0, 0, 4, 8, 4,
|
||||
0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 0, 0, 0, 0, 0, 4, 8, 4,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 8, 3, 0, 0, 0, 0, 4, 8, 4,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 8, 3, 0, 0, 0, 0, 4, 8, 4,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 8, 8, 8, 3, 0, 0, 4, 4, 8, 4,
|
||||
0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 4,
|
||||
0, 0, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 0,
|
||||
0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0
|
||||
};
|
||||
|
||||
if (_vm->getPlatform() != Common::kPlatformWindows)
|
||||
return;
|
||||
|
||||
if (_vm->isMainDisplay()) {
|
||||
Image dropCrumbsOffImage(CRUMBSWIDTH, CRUMBSHEIGHT, dropCrumbsOffImageData, _vm, false);
|
||||
|
||||
dropCrumbsOffImage.drawMaskImage(612, 4);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Lab
|
||||
90
engines/lab/interface.h
Normal file
90
engines/lab/interface.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LAB_INTERFACE_H
|
||||
#define LAB_INTERFACE_H
|
||||
|
||||
#include "common/events.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
class LabEngine;
|
||||
class Image;
|
||||
|
||||
struct Button {
|
||||
uint16 _x, _y, _buttonId;
|
||||
Common::CustomEventType _actionEquiv; // the action which activates this button
|
||||
bool _isEnabled;
|
||||
Image *_image, *_altImage;
|
||||
};
|
||||
|
||||
typedef Common::List<Button *> ButtonList;
|
||||
|
||||
class Interface {
|
||||
private:
|
||||
LabEngine *_vm;
|
||||
|
||||
Button *_hitButton;
|
||||
ButtonList *_screenButtonList;
|
||||
|
||||
public:
|
||||
Interface(LabEngine *vm);
|
||||
|
||||
void attachButtonList(ButtonList *buttonList);
|
||||
Button *createButton(uint16 x, uint16 y, uint16 id, Common::CustomEventType action, Image *image, Image *altImage);
|
||||
void toggleButton(Button *button, uint16 penColor, bool enable);
|
||||
|
||||
/**
|
||||
* Draws a button list to the screen.
|
||||
*/
|
||||
void drawButtonList(ButtonList *buttonList);
|
||||
void freeButtonList(ButtonList *buttonList);
|
||||
Button *getButton(uint16 id);
|
||||
|
||||
/**
|
||||
* Checks whether or not the coords fall within one of the buttons in a list
|
||||
* of buttons.
|
||||
*/
|
||||
Button *checkButtonHit(Common::Point pos);
|
||||
|
||||
/**
|
||||
* Checks whether or not the coords fall within one of the buttons in a list
|
||||
* of buttons.
|
||||
*/
|
||||
Button *checkNumButtonHit(Common::CustomEventType action);
|
||||
|
||||
void handlePressedButton();
|
||||
|
||||
void mayShowCrumbIndicator();
|
||||
void mayShowCrumbIndicatorOff();
|
||||
};
|
||||
|
||||
} // End of namespace Lab
|
||||
|
||||
#endif // LAB_INTERFACE_H
|
||||
416
engines/lab/intro.cpp
Normal file
416
engines/lab/intro.cpp
Normal file
@@ -0,0 +1,416 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/file.h"
|
||||
|
||||
#include "lab/lab.h"
|
||||
|
||||
#include "lab/anim.h"
|
||||
#include "lab/dispman.h"
|
||||
#include "lab/eventman.h"
|
||||
#include "lab/intro.h"
|
||||
#include "lab/music.h"
|
||||
#include "lab/resource.h"
|
||||
#include "lab/utils.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
Intro::Intro(LabEngine *vm) : _vm(vm) {
|
||||
_quitIntro = false;
|
||||
_font = _vm->_resource->getFont("F:Map.fon");
|
||||
}
|
||||
|
||||
Intro::~Intro() {
|
||||
_vm->_graphics->freeFont(&_font);
|
||||
}
|
||||
|
||||
void Intro::introEatMessages() {
|
||||
while (1) {
|
||||
IntuiMessage *msg = _vm->_event->getMsg();
|
||||
|
||||
if (_vm->shouldQuit()) {
|
||||
_quitIntro = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
if ((msg->_msgClass == kMessageRightClick)
|
||||
|| ((msg->_msgClass == kMessageAction) && (msg->_code == kActionSkipIntro)))
|
||||
_quitIntro = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Intro::doPictText(const Common::String &filename, bool isScreen) {
|
||||
Common::String path = Common::String("Lab:rooms/Intro/") + filename;
|
||||
|
||||
uint timeDelay = (isScreen) ? 35 : 7;
|
||||
_vm->updateEvents();
|
||||
|
||||
if (_quitIntro)
|
||||
return;
|
||||
|
||||
uint32 lastMillis = 0;
|
||||
bool drawNextText = true;
|
||||
bool doneFl = false;
|
||||
bool begin = true;
|
||||
|
||||
Common::File *textFile = _vm->_resource->openDataFile(path);
|
||||
char *textBuffer = new char[textFile->size()];
|
||||
textFile->read(textBuffer, textFile->size());
|
||||
delete textFile;
|
||||
const char *curText = textBuffer;
|
||||
|
||||
while (1) {
|
||||
if (drawNextText) {
|
||||
if (begin)
|
||||
begin = false;
|
||||
else if (isScreen)
|
||||
_vm->_graphics->fade(false);
|
||||
|
||||
if (isScreen) {
|
||||
_vm->_graphics->rectFillScaled(10, 10, 310, 190, 7);
|
||||
|
||||
curText += _vm->_graphics->flowText(_font, _vm->_isHiRes ? 0 : -1, 5, 7, false, false, true, true, _vm->_utils->vgaRectScale(14, 11, 306, 189), curText);
|
||||
_vm->_graphics->fade(true);
|
||||
} else
|
||||
curText += _vm->_graphics->longDrawMessage(Common::String(curText), false);
|
||||
|
||||
doneFl = (*curText == 0);
|
||||
|
||||
drawNextText = false;
|
||||
introEatMessages();
|
||||
|
||||
if (_quitIntro) {
|
||||
if (isScreen)
|
||||
_vm->_graphics->fade(false);
|
||||
|
||||
delete[] textBuffer;
|
||||
return;
|
||||
}
|
||||
|
||||
lastMillis = _vm->_system->getMillis();
|
||||
}
|
||||
|
||||
IntuiMessage *msg = _vm->_event->getMsg();
|
||||
if (_vm->shouldQuit()) {
|
||||
_quitIntro = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!msg) {
|
||||
_vm->updateEvents();
|
||||
_vm->_anim->diffNextFrame();
|
||||
|
||||
uint32 elapsedSeconds = (_vm->_system->getMillis() - lastMillis) / 1000;
|
||||
|
||||
if (elapsedSeconds > timeDelay) {
|
||||
if (doneFl) {
|
||||
if (isScreen)
|
||||
_vm->_graphics->fade(false);
|
||||
|
||||
delete[] textBuffer;
|
||||
return;
|
||||
} else {
|
||||
drawNextText = true;
|
||||
}
|
||||
}
|
||||
_vm->waitTOF();
|
||||
} else {
|
||||
uint32 msgClass = msg->_msgClass;
|
||||
uint16 code = msg->_code;
|
||||
|
||||
if ((msgClass == kMessageRightClick) ||
|
||||
((msgClass == kMessageAction) && (code == kActionSkipIntro))) {
|
||||
_quitIntro = true;
|
||||
|
||||
if (isScreen)
|
||||
_vm->_graphics->fade(false);
|
||||
|
||||
delete[] textBuffer;
|
||||
return;
|
||||
} else if ((msgClass == kMessageLeftClick) || (msgClass == kMessageRightClick)) {
|
||||
if (msgClass == kMessageLeftClick) {
|
||||
if (doneFl) {
|
||||
if (isScreen)
|
||||
_vm->_graphics->fade(false);
|
||||
|
||||
delete[] textBuffer;
|
||||
return;
|
||||
} else
|
||||
drawNextText = true;
|
||||
}
|
||||
|
||||
introEatMessages();
|
||||
|
||||
if (_quitIntro) {
|
||||
if (isScreen)
|
||||
_vm->_graphics->fade(false);
|
||||
|
||||
delete[] textBuffer;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (doneFl) {
|
||||
if (isScreen)
|
||||
_vm->_graphics->fade(false);
|
||||
|
||||
delete[] textBuffer;
|
||||
return;
|
||||
} else
|
||||
drawNextText = true;
|
||||
}
|
||||
} // while(1)
|
||||
}
|
||||
|
||||
void Intro::nReadPict(const Common::String &filename, bool playOnce, bool noPalChange, bool doBlack, int wait) {
|
||||
Common::String finalFileName = Common::String("P:Intro/") + filename;
|
||||
|
||||
_vm->updateEvents();
|
||||
introEatMessages();
|
||||
|
||||
if (_quitIntro)
|
||||
return;
|
||||
|
||||
if (noPalChange)
|
||||
_vm->_anim->_noPalChange = true;
|
||||
|
||||
_vm->_anim->_doBlack = doBlack;
|
||||
_vm->_anim->stopDiffEnd();
|
||||
_vm->_graphics->readPict(finalFileName, playOnce);
|
||||
|
||||
if (wait) {
|
||||
for (int i = 0; i < wait / 10; i++) {
|
||||
_vm->updateEvents();
|
||||
introEatMessages();
|
||||
if (_quitIntro)
|
||||
break;
|
||||
_vm->_system->delayMillis(10);
|
||||
}
|
||||
}
|
||||
|
||||
if (noPalChange)
|
||||
_vm->_anim->_noPalChange = false;
|
||||
}
|
||||
|
||||
void Intro::play() {
|
||||
uint16 palette[16] = {
|
||||
0x0000, 0x0855, 0x0FF9, 0x0EE7,
|
||||
0x0ED5, 0x0DB4, 0x0CA2, 0x0C91,
|
||||
0x0B80, 0x0B80, 0x0B91, 0x0CA2,
|
||||
0x0CB3, 0x0DC4, 0x0DD6, 0x0EE7
|
||||
};
|
||||
|
||||
if (_vm->getPlatform() == Common::kPlatformDOS) {
|
||||
nReadPict("EA0");
|
||||
nReadPict("EA1");
|
||||
nReadPict("EA2");
|
||||
nReadPict("EA3");
|
||||
} else if (_vm->getPlatform() == Common::kPlatformWindows) {
|
||||
nReadPict("WYRMKEEP", true, false, false, 4000);
|
||||
}
|
||||
|
||||
_vm->_graphics->blackAllScreen();
|
||||
_vm->_music->resetMusic(false);
|
||||
|
||||
if (_vm->getPlatform() == Common::kPlatformDOS)
|
||||
nReadPict("TNDcycle.pic", true, true);
|
||||
else
|
||||
nReadPict("TNDcycle2.pic", true, true);
|
||||
|
||||
_vm->_graphics->_fadePalette = palette;
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
palette[i] = ((_vm->_anim->_diffPalette[i * 3] >> 2) << 8) +
|
||||
((_vm->_anim->_diffPalette[i * 3 + 1] >> 2) << 4) +
|
||||
(_vm->_anim->_diffPalette[i * 3 + 2] >> 2);
|
||||
}
|
||||
|
||||
_vm->updateEvents();
|
||||
introEatMessages();
|
||||
if (!_quitIntro)
|
||||
_vm->_graphics->fade(true);
|
||||
|
||||
for (int times = 0; times < 150; times++) {
|
||||
_vm->updateEvents();
|
||||
introEatMessages();
|
||||
if (_quitIntro)
|
||||
break;
|
||||
|
||||
uint16 temp = palette[2];
|
||||
|
||||
for (int i = 2; i < 15; i++)
|
||||
palette[i] = palette[i + 1];
|
||||
|
||||
palette[15] = temp;
|
||||
|
||||
_vm->_graphics->setAmigaPal(palette);
|
||||
_vm->waitTOF();
|
||||
_vm->waitTOF();
|
||||
}
|
||||
|
||||
if (!_quitIntro) {
|
||||
_vm->_graphics->fade(false);
|
||||
_vm->_graphics->blackAllScreen();
|
||||
_vm->updateEvents();
|
||||
introEatMessages();
|
||||
}
|
||||
|
||||
nReadPict("Title.A");
|
||||
nReadPict("AB", true, false, false, 1000);
|
||||
nReadPict("BA");
|
||||
nReadPict("AC", true, false, false, 1000);
|
||||
nReadPict("CA");
|
||||
nReadPict("AD", true, false, false, 1000);
|
||||
nReadPict("DA");
|
||||
|
||||
_vm->_graphics->blackAllScreen();
|
||||
_vm->updateEvents();
|
||||
introEatMessages();
|
||||
|
||||
nReadPict("Intro.1", true, true);
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
palette[i] = ((_vm->_anim->_diffPalette[i * 3] >> 2) << 8) +
|
||||
((_vm->_anim->_diffPalette[i * 3 + 1] >> 2) << 4) +
|
||||
(_vm->_anim->_diffPalette[i * 3 + 2] >> 2);
|
||||
}
|
||||
|
||||
doPictText("i.1", true);
|
||||
if (_vm->getPlatform() == Common::kPlatformWindows) {
|
||||
doPictText("i.2A", true);
|
||||
doPictText("i.2B", true);
|
||||
}
|
||||
|
||||
_vm->_graphics->blackAllScreen();
|
||||
_vm->updateEvents();
|
||||
introEatMessages();
|
||||
|
||||
nReadPict("Station1", true, false, true);
|
||||
doPictText("i.3");
|
||||
|
||||
nReadPict("Station2", true, false, true);
|
||||
doPictText("i.4");
|
||||
|
||||
nReadPict("Stiles4", true, false, true);
|
||||
doPictText("i.5");
|
||||
|
||||
nReadPict("Stiles3", true, false, true);
|
||||
doPictText("i.6");
|
||||
|
||||
if (_vm->getPlatform() == Common::kPlatformWindows)
|
||||
nReadPict("Platform2", true, false, true);
|
||||
else
|
||||
nReadPict("Platform", true, false, true);
|
||||
doPictText("i.7");
|
||||
|
||||
nReadPict("Subway.1", true, false, true);
|
||||
doPictText("i.8");
|
||||
|
||||
nReadPict("Subway.2", true, false, true);
|
||||
|
||||
doPictText("i.9");
|
||||
doPictText("i.10");
|
||||
doPictText("i.11");
|
||||
|
||||
for (int i = 0; i < 50; i++) {
|
||||
_vm->updateEvents();
|
||||
introEatMessages();
|
||||
if (_quitIntro)
|
||||
break;
|
||||
|
||||
for (int idx = (8 * 3); idx < (255 * 3); idx++)
|
||||
_vm->_anim->_diffPalette[idx] = 255 - _vm->_anim->_diffPalette[idx];
|
||||
|
||||
_vm->waitTOF();
|
||||
_vm->_graphics->setPalette(_vm->_anim->_diffPalette, 256);
|
||||
_vm->waitTOF();
|
||||
_vm->waitTOF();
|
||||
}
|
||||
|
||||
doPictText("i.12");
|
||||
doPictText("i.13");
|
||||
|
||||
nReadPict("Daed0");
|
||||
doPictText("i.14");
|
||||
|
||||
nReadPict("Daed1");
|
||||
doPictText("i.15");
|
||||
|
||||
nReadPict("Daed2");
|
||||
doPictText("i.16");
|
||||
doPictText("i.17");
|
||||
doPictText("i.18");
|
||||
|
||||
nReadPict("Daed3");
|
||||
doPictText("i.19");
|
||||
doPictText("i.20");
|
||||
|
||||
nReadPict("Daed4");
|
||||
doPictText("i.21");
|
||||
|
||||
nReadPict("Daed5");
|
||||
doPictText("i.22");
|
||||
doPictText("i.23");
|
||||
doPictText("i.24");
|
||||
|
||||
nReadPict("Daed6");
|
||||
doPictText("i.25");
|
||||
doPictText("i.26");
|
||||
|
||||
nReadPict("Daed7", false);
|
||||
doPictText("i.27");
|
||||
doPictText("i.28");
|
||||
|
||||
nReadPict("Daed8");
|
||||
doPictText("i.29");
|
||||
doPictText("i.30");
|
||||
|
||||
nReadPict("Daed9");
|
||||
doPictText("i.31");
|
||||
doPictText("i.32");
|
||||
doPictText("i.33");
|
||||
|
||||
nReadPict("Daed9a");
|
||||
nReadPict("Daed10");
|
||||
doPictText("i.34");
|
||||
doPictText("i.35");
|
||||
doPictText("i.36");
|
||||
|
||||
nReadPict("SubX");
|
||||
|
||||
if (_quitIntro) {
|
||||
_vm->_graphics->rectFill(0, 0, _vm->_graphics->_screenWidth - 1, _vm->_graphics->_screenHeight - 1, 0);
|
||||
_vm->_anim->_doBlack = true;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Lab
|
||||
66
engines/lab/intro.h
Normal file
66
engines/lab/intro.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LAB_INTRO_H
|
||||
#define LAB_INTRO_H
|
||||
|
||||
namespace Lab {
|
||||
|
||||
class Intro {
|
||||
public:
|
||||
Intro(LabEngine *vm);
|
||||
~Intro();
|
||||
|
||||
/**
|
||||
* Does the introduction sequence for Labyrinth.
|
||||
*/
|
||||
void play();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Goes through, and responds to all the intuition messages currently in the
|
||||
* message queue.
|
||||
*/
|
||||
void introEatMessages();
|
||||
|
||||
/**
|
||||
* Reads in a picture.
|
||||
*/
|
||||
void doPictText(const Common::String &filename, bool isScreen = false);
|
||||
|
||||
void nReadPict(const Common::String &filename, bool playOnce = true, bool noPalChange = false, bool doBlack = false, int wait = 0);
|
||||
|
||||
LabEngine *_vm;
|
||||
bool _quitIntro;
|
||||
TextFont *_font;
|
||||
};
|
||||
|
||||
} // End of namespace Lab
|
||||
|
||||
#endif // LAB_INTRO_H
|
||||
224
engines/lab/lab.cpp
Normal file
224
engines/lab/lab.cpp
Normal file
@@ -0,0 +1,224 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/debug-channels.h"
|
||||
#include "common/error.h"
|
||||
#include "common/file.h"
|
||||
|
||||
#include "engines/util.h"
|
||||
|
||||
#include "lab/lab.h"
|
||||
|
||||
#include "lab/anim.h"
|
||||
#include "lab/console.h"
|
||||
#include "lab/dispman.h"
|
||||
#include "lab/eventman.h"
|
||||
#include "lab/image.h"
|
||||
#include "lab/interface.h"
|
||||
#include "lab/music.h"
|
||||
#include "lab/processroom.h"
|
||||
#include "lab/resource.h"
|
||||
#include "lab/speciallocks.h"
|
||||
#include "lab/utils.h"
|
||||
|
||||
namespace Lab {
|
||||
LabEngine::LabEngine(OSystem *syst, const ADGameDescription *gameDesc)
|
||||
: Engine(syst), _gameDescription(gameDesc), _extraGameFeatures(0) {
|
||||
_lastWaitTOFTicks = 0;
|
||||
|
||||
_isHiRes = false;
|
||||
_roomNum = -1;
|
||||
for (int i = 0; i < MAX_CRUMBS; i++) {
|
||||
_breadCrumbs[i]._crumbRoomNum = 0;
|
||||
_breadCrumbs[i]._crumbDirection = kDirectionNorth;
|
||||
}
|
||||
|
||||
_numCrumbs = 0;
|
||||
_droppingCrumbs = false;
|
||||
_followingCrumbs = false;
|
||||
_followCrumbsFast = false;
|
||||
_isCrumbTurning = false;
|
||||
_isCrumbWaiting = false;
|
||||
_noUpdateDiff = false;
|
||||
_quitLab = false;
|
||||
_mainDisplay = true;
|
||||
|
||||
_numInv = 0;
|
||||
_manyRooms = 0;
|
||||
_direction = 0;
|
||||
_highestCondition = 0;
|
||||
_crumbTimestamp = 0;
|
||||
_maxRooms = 0;
|
||||
|
||||
_event = nullptr;
|
||||
_interface = nullptr;
|
||||
_resource = nullptr;
|
||||
_music = nullptr;
|
||||
_anim = nullptr;
|
||||
_closeDataPtr = nullptr;
|
||||
_conditions = nullptr;
|
||||
_graphics = nullptr;
|
||||
_rooms = nullptr;
|
||||
_roomsFound = nullptr;
|
||||
_specialLocks = nullptr;
|
||||
_utils = nullptr;
|
||||
_journalBackImage = nullptr;
|
||||
|
||||
_lastTooLong = false;
|
||||
_alternate = false;
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
_moveImages[i] = nullptr;
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
_invImages[i] = nullptr;
|
||||
|
||||
_curFileName = " ";
|
||||
_msgFont = nullptr;
|
||||
_inventory = nullptr;
|
||||
|
||||
_imgMap = nullptr;
|
||||
_imgRoom = nullptr;
|
||||
_imgUpArrowRoom = nullptr;
|
||||
_imgDownArrowRoom = nullptr;
|
||||
_imgBridge = nullptr;
|
||||
_imgHRoom = nullptr;
|
||||
_imgVRoom = nullptr;
|
||||
_imgMaze = nullptr;
|
||||
_imgHugeMaze = nullptr;
|
||||
_imgPath = nullptr;
|
||||
for (int i = 0; i < 4; i++)
|
||||
_imgMapX[i] = nullptr;
|
||||
_maps = nullptr;
|
||||
|
||||
_blankJournal = nullptr;
|
||||
_journalFont = nullptr;
|
||||
_journalPage = 0;
|
||||
_lastPage = false;
|
||||
_monitorPage = 0;
|
||||
_monitorTextFilename = "";
|
||||
_monitorButton = nullptr;
|
||||
_monitorButtonHeight = 1;
|
||||
for (int i = 0; i < 20; i++)
|
||||
_highPalette[i] = 0;
|
||||
_introPlaying = false;
|
||||
|
||||
const Common::FSNode gameDataDir(ConfMan.getPath("path"));
|
||||
SearchMan.addSubDirectoryMatching(gameDataDir, "game", 0, 4);
|
||||
}
|
||||
|
||||
LabEngine::~LabEngine() {
|
||||
freeMapData();
|
||||
delete[] _rooms;
|
||||
delete[] _inventory;
|
||||
|
||||
delete _conditions;
|
||||
delete _roomsFound;
|
||||
delete _event;
|
||||
delete _interface;
|
||||
delete _resource;
|
||||
delete _music;
|
||||
delete _anim;
|
||||
delete _graphics;
|
||||
delete _specialLocks;
|
||||
delete _utils;
|
||||
delete _journalBackImage;
|
||||
}
|
||||
|
||||
Common::Error LabEngine::run() {
|
||||
if (getFeatures() & GF_LOWRES)
|
||||
initGraphics(320, 200);
|
||||
else
|
||||
initGraphics(640, 480);
|
||||
|
||||
_interface = new Interface(this);
|
||||
_event = new EventManager(this);
|
||||
_resource = new Resource(this);
|
||||
_music = new Music(this);
|
||||
_graphics = new DisplayMan(this);
|
||||
_anim = new Anim(this);
|
||||
_specialLocks = new SpecialLocks(this);
|
||||
_utils = new Utils(this);
|
||||
setDebugger(new Console(this));
|
||||
_journalBackImage = new Image(this);
|
||||
|
||||
go();
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
void LabEngine::drawStaticMessage(byte index) {
|
||||
_graphics->drawMessage(_resource->getStaticText((StaticText)index), false);
|
||||
}
|
||||
|
||||
void LabEngine::changeVolume(int delta) {
|
||||
int sfxPrev = _mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType);
|
||||
int musicPrev = _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType);
|
||||
int sfxNew = (delta > 0) ? MIN<int>(sfxPrev + 10, Audio::Mixer::kMaxMixerVolume) : MAX<int>(sfxPrev - 10, 0);
|
||||
int musicNew = (delta > 0) ? MIN<int>(musicPrev + 10, Audio::Mixer::kMaxMixerVolume) : MAX<int>(musicPrev - 10, 0);
|
||||
_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, sfxNew);
|
||||
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, musicNew);
|
||||
}
|
||||
|
||||
void LabEngine::waitTOF() {
|
||||
_graphics->screenUpdate();
|
||||
|
||||
uint32 now;
|
||||
|
||||
for (now = _system->getMillis(); now - _lastWaitTOFTicks <= 0xF; now = _system->getMillis() )
|
||||
_system->delayMillis(_lastWaitTOFTicks - now + 17);
|
||||
|
||||
_lastWaitTOFTicks = now;
|
||||
}
|
||||
|
||||
void LabEngine::updateEvents() {
|
||||
_event->processInput();
|
||||
_interface->handlePressedButton();
|
||||
}
|
||||
|
||||
Common::Error LabEngine::loadGameState(int slot) {
|
||||
bool result = loadGame(slot);
|
||||
return (result) ? Common::kNoError : Common::kUserCanceled;
|
||||
}
|
||||
|
||||
Common::Error LabEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
|
||||
bool result = saveGame(slot, desc);
|
||||
return (result) ? Common::kNoError : Common::kUserCanceled;
|
||||
}
|
||||
|
||||
bool LabEngine::canLoadGameStateCurrently(Common::U32String *msg) {
|
||||
return !_introPlaying;
|
||||
}
|
||||
|
||||
bool LabEngine::canSaveGameStateCurrently(Common::U32String *msg) {
|
||||
return !_introPlaying;
|
||||
}
|
||||
|
||||
} // End of namespace Lab
|
||||
540
engines/lab/lab.h
Normal file
540
engines/lab/lab.h
Normal file
@@ -0,0 +1,540 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LAB_LAB_H
|
||||
#define LAB_LAB_H
|
||||
|
||||
#include "common/system.h"
|
||||
#include "common/random.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/savefile.h"
|
||||
#include "engines/engine.h"
|
||||
#include "engines/savestate.h"
|
||||
|
||||
#include "lab/console.h"
|
||||
#include "lab/image.h"
|
||||
#include "lab/labsets.h"
|
||||
#include "lab/detection.h"
|
||||
|
||||
struct ADGameDescription;
|
||||
|
||||
namespace Lab {
|
||||
|
||||
struct MapData;
|
||||
struct Action;
|
||||
struct CloseData;
|
||||
struct Button;
|
||||
struct IntuiMessage;
|
||||
struct InventoryData;
|
||||
struct RoomData;
|
||||
struct Rule;
|
||||
struct TextFont;
|
||||
struct ViewData;
|
||||
|
||||
class Anim;
|
||||
class DisplayMan;
|
||||
class EventManager;
|
||||
class Interface;
|
||||
class Image;
|
||||
class Music;
|
||||
class Resource;
|
||||
class SpecialLocks;
|
||||
class Utils;
|
||||
|
||||
struct SaveGameHeader {
|
||||
byte _version;
|
||||
SaveStateDescriptor _descr;
|
||||
uint16 _roomNumber;
|
||||
uint16 _direction;
|
||||
};
|
||||
|
||||
typedef Common::List<Button *> ButtonList;
|
||||
|
||||
struct CrumbData {
|
||||
uint16 _crumbRoomNum;
|
||||
uint16 _crumbDirection;
|
||||
};
|
||||
|
||||
#define MAX_CRUMBS 128
|
||||
|
||||
typedef Common::List<Rule> RuleList;
|
||||
typedef Common::List<Action> ActionList;
|
||||
typedef Common::List<CloseData> CloseDataList;
|
||||
typedef Common::List<ViewData> ViewDataList;
|
||||
|
||||
enum Direction {
|
||||
kDirectionNorth,
|
||||
kDirectionSouth,
|
||||
kDirectionEast,
|
||||
kDirectionWest
|
||||
};
|
||||
|
||||
enum MainButton {
|
||||
kButtonNone = -1,
|
||||
kButtonPickup,
|
||||
kButtonUse,
|
||||
kButtonOpen,
|
||||
kButtonClose,
|
||||
kButtonLook,
|
||||
kButtonInventory,
|
||||
kButtonLeft,
|
||||
kButtonForward,
|
||||
kButtonRight,
|
||||
kButtonMap
|
||||
};
|
||||
|
||||
enum MessageClass {
|
||||
kMessageLeftClick,
|
||||
kMessageRightClick,
|
||||
kMessageButtonUp,
|
||||
kMessageAction
|
||||
};
|
||||
|
||||
enum LABActions {
|
||||
kActionNone,
|
||||
kActionQuit,
|
||||
kActionSkipIntro,
|
||||
kActionSoundRaise,
|
||||
kActionSoundLower,
|
||||
kActionInteract,
|
||||
kActionTake,
|
||||
kActionMove,
|
||||
kActionOpen,
|
||||
kActionClose,
|
||||
kActionLook,
|
||||
kActionInv,
|
||||
kActionForward,
|
||||
kActionLeft,
|
||||
kActionRight,
|
||||
kActionMap,
|
||||
kActionFocusOnNextInteractiveItem,
|
||||
kActionExit,
|
||||
kActionMainDisplay,
|
||||
kActionSaveLoad,
|
||||
kActionUse,
|
||||
kActionInvLook,
|
||||
kActionPrev,
|
||||
kActionNext,
|
||||
kActionDropBreadcrumb,
|
||||
kActionFollowBreadcrumbs,
|
||||
kActionRunWhileFollowingBreadcrumbs,
|
||||
kActionMapExit,
|
||||
kActionUpperFloor,
|
||||
kActionLowerFloor,
|
||||
kActionQuitDialogYes,
|
||||
kActionQuitDialogNo,
|
||||
kActionJournalBack,
|
||||
kActionJournalExit,
|
||||
kActionJournalForward,
|
||||
kActionDummy,
|
||||
};
|
||||
|
||||
class LabEngine : public Engine {
|
||||
friend class Console;
|
||||
|
||||
private:
|
||||
bool _isCrumbWaiting;
|
||||
bool _lastTooLong;
|
||||
bool _lastPage;
|
||||
bool _mainDisplay;
|
||||
bool _noUpdateDiff;
|
||||
bool _quitLab;
|
||||
|
||||
byte *_blankJournal;
|
||||
|
||||
int _lastWaitTOFTicks;
|
||||
|
||||
uint16 _direction;
|
||||
uint16 _highPalette[20];
|
||||
uint16 _journalPage;
|
||||
uint16 _maxRooms;
|
||||
uint16 _monitorPage;
|
||||
uint16 _monitorButtonHeight;
|
||||
|
||||
uint32 _extraGameFeatures;
|
||||
|
||||
Common::String _journalText;
|
||||
Common::String _journalTextTitle;
|
||||
Common::String _nextFileName;
|
||||
Common::String _newFileName;
|
||||
Common::String _monitorTextFilename;
|
||||
|
||||
const CloseData *_closeDataPtr;
|
||||
ButtonList _journalButtonList;
|
||||
ButtonList _mapButtonList;
|
||||
Image *_imgMap, *_imgRoom, *_imgUpArrowRoom, *_imgDownArrowRoom, *_imgBridge;
|
||||
Image *_imgHRoom, *_imgVRoom, *_imgMaze, *_imgHugeMaze, *_imgPath;
|
||||
Image *_imgMapX[4];
|
||||
InventoryData *_inventory;
|
||||
MapData *_maps;
|
||||
Image *_monitorButton;
|
||||
Image *_journalBackImage;
|
||||
TextFont *_journalFont;
|
||||
bool _introPlaying;
|
||||
|
||||
public:
|
||||
bool _alternate;
|
||||
bool _droppingCrumbs;
|
||||
bool _followingCrumbs;
|
||||
bool _followCrumbsFast;
|
||||
bool _isCrumbTurning;
|
||||
bool _isHiRes;
|
||||
|
||||
int _roomNum;
|
||||
|
||||
uint16 _highestCondition;
|
||||
uint16 _manyRooms;
|
||||
uint16 _numCrumbs;
|
||||
uint16 _numInv;
|
||||
|
||||
uint32 _crumbTimestamp;
|
||||
|
||||
Common::String _curFileName;
|
||||
|
||||
Anim *_anim;
|
||||
CrumbData _breadCrumbs[MAX_CRUMBS];
|
||||
DisplayMan *_graphics;
|
||||
EventManager *_event;
|
||||
Interface *_interface;
|
||||
ButtonList _invButtonList;
|
||||
ButtonList _moveButtonList;
|
||||
Image *_invImages[10];
|
||||
Image *_moveImages[20];
|
||||
LargeSet *_conditions, *_roomsFound;
|
||||
Music *_music;
|
||||
Resource *_resource;
|
||||
RoomData *_rooms;
|
||||
TextFont *_msgFont;
|
||||
SpecialLocks *_specialLocks;
|
||||
Utils *_utils;
|
||||
|
||||
public:
|
||||
LabEngine(OSystem *syst, const ADGameDescription *gameDesc);
|
||||
~LabEngine() override;
|
||||
|
||||
Common::Error run() override;
|
||||
void go();
|
||||
|
||||
const ADGameDescription *_gameDescription;
|
||||
Common::Platform getPlatform() const;
|
||||
uint32 getFeatures() const;
|
||||
|
||||
bool hasFeature(EngineFeature f) const override;
|
||||
|
||||
void changeVolume(int delta);
|
||||
uint16 getDirection() { return _direction; }
|
||||
|
||||
/**
|
||||
* Returns the current picture name.
|
||||
*/
|
||||
Common::String getPictName(bool useClose);
|
||||
uint16 getQuarters();
|
||||
void setQuarters(uint16 quarters);
|
||||
void updateEvents();
|
||||
void waitTOF();
|
||||
|
||||
Common::Error loadGameState(int slot) override;
|
||||
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
|
||||
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
|
||||
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
|
||||
|
||||
bool isMainDisplay() const { return _mainDisplay; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Checks whether all the conditions in a condition list are met.
|
||||
*/
|
||||
bool checkConditions(const Common::Array<int16> &cond);
|
||||
|
||||
/**
|
||||
* Decrements the current inventory number.
|
||||
*/
|
||||
void decIncInv(uint16 *CurInv, bool dec);
|
||||
|
||||
/**
|
||||
* Processes the action list.
|
||||
*/
|
||||
void doActions(const ActionList &actionList);
|
||||
|
||||
/**
|
||||
* Goes through the rules if an action is taken.
|
||||
*/
|
||||
bool doActionRule(Common::Point pos, int16 action, int16 roomNum);
|
||||
|
||||
/**
|
||||
* Does the work for doActionRule.
|
||||
*/
|
||||
bool doActionRuleSub(int16 action, int16 roomNum, const CloseData *closePtr, bool allowDefaults);
|
||||
|
||||
/**
|
||||
* Handles monitor closeups
|
||||
*/
|
||||
void handleMonitorCloseup();
|
||||
|
||||
/**
|
||||
* Goes through the rules if the user tries to go forward.
|
||||
*/
|
||||
bool doGoForward();
|
||||
|
||||
/**
|
||||
* Does the journal processing.
|
||||
*/
|
||||
void doJournal();
|
||||
|
||||
/**
|
||||
* Goes through the rules if the user tries to go to the main view
|
||||
*/
|
||||
bool doMainView();
|
||||
|
||||
/**
|
||||
* Does the map processing.
|
||||
*/
|
||||
void doMap();
|
||||
|
||||
/**
|
||||
* Does what's necessary for the monitor.
|
||||
*/
|
||||
void doMonitor(const Common::String &background, const Common::String &textfile, bool isinteractive, Common::Rect textRect);
|
||||
|
||||
/**
|
||||
* Does the things to properly set up the detective notes.
|
||||
*/
|
||||
void doNotes();
|
||||
|
||||
/**
|
||||
* Does the work for doActionRule.
|
||||
*/
|
||||
bool doOperateRuleSub(int16 itemNum, int16 roomNum, const CloseData *closePtr, bool allowDefaults);
|
||||
|
||||
/**
|
||||
* Goes through the rules if the user tries to operate an item on an object.
|
||||
*/
|
||||
bool doOperateRule(Common::Point pos, int16 ItemNum);
|
||||
|
||||
/**
|
||||
* Goes through the rules if the user tries to turn.
|
||||
*/
|
||||
bool doTurn(uint16 from, uint16 to);
|
||||
|
||||
/**
|
||||
* If the user hits the "Use" button; things that can get used on themselves.
|
||||
*/
|
||||
bool doUse(uint16 curInv);
|
||||
|
||||
/**
|
||||
* Does the things to properly set up the old west newspaper. Assumes that
|
||||
* OpenHiRes already called.
|
||||
*/
|
||||
void doWestPaper();
|
||||
|
||||
/**
|
||||
* Draws the current direction to the screen.
|
||||
*/
|
||||
void drawDirection(const CloseData *closePtr);
|
||||
|
||||
/**
|
||||
* Draws the journal from page x.
|
||||
*/
|
||||
void drawJournal(uint16 wipenum, bool needFade);
|
||||
|
||||
/**
|
||||
* Draws the text to the back journal screen to the appropriate Page number
|
||||
*/
|
||||
void drawJournalText();
|
||||
|
||||
/**
|
||||
* Draws the map
|
||||
*/
|
||||
void drawMap(uint16 curRoom, uint16 curMsg, uint16 floorNum, bool fadeIn);
|
||||
|
||||
/**
|
||||
* Draws the text for the monitor.
|
||||
*/
|
||||
void drawMonText(const char *text, TextFont *monitorFont, Common::Rect textRect, bool isinteractive);
|
||||
|
||||
/**
|
||||
* Draws a room map.
|
||||
*/
|
||||
void drawRoomMap(uint16 curRoom, bool drawMarkFl);
|
||||
|
||||
/**
|
||||
* Draws the message for the room.
|
||||
*/
|
||||
void drawRoomMessage(uint16 curInv, const CloseData *closePtr);
|
||||
void drawStaticMessage(byte index);
|
||||
|
||||
/**
|
||||
* Eats all the available messages.
|
||||
*/
|
||||
void eatMessages();
|
||||
|
||||
/**
|
||||
* Goes through the list of closeups to find a match.
|
||||
* @note Known bug here. If there are two objects that have closeups, and
|
||||
* some of the closeups have the same hit boxes, then this returns the first
|
||||
* occurrence of the object with the same hit box.
|
||||
*/
|
||||
const CloseData *findClosePtrMatch(const CloseData *closePtr, const CloseDataList &list);
|
||||
|
||||
/**
|
||||
* Checks if a floor has been visited.
|
||||
*/
|
||||
bool floorVisited(uint16 floorNum);
|
||||
|
||||
/**
|
||||
* New code to allow quick(er) return navigation in game.
|
||||
*/
|
||||
MainButton followCrumbs();
|
||||
void freeMapData();
|
||||
void freeScreens();
|
||||
bool processEvent(MessageClass tmpClass, uint16 code, uint16 qualifier, Common::Point tmpPos,
|
||||
uint16 &curInv, IntuiMessage *curMsg, bool &forceDraw, uint16 buttonId, uint16 &actionMode);
|
||||
|
||||
/**
|
||||
* Gets the current inventory name.
|
||||
*/
|
||||
Common::String getInvName(uint16 curInv);
|
||||
|
||||
/**
|
||||
* Returns the floor to show when the down arrow is pressed
|
||||
* @note The original did not show all the visited floors, but we do
|
||||
*/
|
||||
uint16 getLowerFloor(uint16 floorNum);
|
||||
|
||||
/**
|
||||
* Gets an object, if any, from the user's click on the screen.
|
||||
*/
|
||||
const CloseData *getObject(Common::Point pos, const CloseData *closePtr);
|
||||
|
||||
/**
|
||||
* Returns the floor to show when the up arrow is pressed
|
||||
* @note The original did not show all the visited floors, but we do
|
||||
*/
|
||||
uint16 getUpperFloor(uint16 floorNum);
|
||||
|
||||
/**
|
||||
* Gets the current ViewDataPointer.
|
||||
*/
|
||||
ViewData *getViewData(uint16 roomNum, uint16 direction);
|
||||
|
||||
/**
|
||||
* Turns the interface off.
|
||||
*/
|
||||
void interfaceOff();
|
||||
|
||||
/**
|
||||
* Turns the interface on.
|
||||
*/
|
||||
void interfaceOn();
|
||||
|
||||
/**
|
||||
* Loads in the data for the journal.
|
||||
*/
|
||||
void loadJournalData();
|
||||
|
||||
/**
|
||||
* Loads in the map data.
|
||||
*/
|
||||
void loadMapData();
|
||||
|
||||
/**
|
||||
* The main game loop.
|
||||
*/
|
||||
void mainGameLoop();
|
||||
void showLab2Teaser();
|
||||
|
||||
/**
|
||||
* Permanently flips the imagery of a button.
|
||||
*/
|
||||
void perFlipButton(uint16 buttonId);
|
||||
|
||||
/**
|
||||
* process a arrow button movement.
|
||||
*/
|
||||
uint16 processArrow(uint16 curDirection, uint16 arrow);
|
||||
|
||||
/**
|
||||
* Processes user input.
|
||||
*/
|
||||
void processJournal();
|
||||
|
||||
/**
|
||||
* Processes the map.
|
||||
*/
|
||||
void processMap(uint16 curRoom);
|
||||
|
||||
/**
|
||||
* Processes user input.
|
||||
*/
|
||||
void processMonitor(const Common::String &ntext, TextFont *monitorFont, bool isInteractive, Common::Rect textRect);
|
||||
|
||||
/**
|
||||
* Figures out what a room's coordinates should be.
|
||||
*/
|
||||
Common::Rect roomCoords(uint16 curRoom);
|
||||
bool saveRestoreGame();
|
||||
|
||||
/**
|
||||
* Sets the current close up data.
|
||||
*/
|
||||
void setCurrentClose(Common::Point pos, const CloseData **closePtrList, bool useAbsoluteCoords, bool next=false);
|
||||
|
||||
/**
|
||||
* Takes the currently selected item.
|
||||
*/
|
||||
bool takeItem(Common::Point pos);
|
||||
|
||||
/**
|
||||
* Does the turn page wipe.
|
||||
*/
|
||||
void turnPage(bool fromLeft);
|
||||
bool processKey(IntuiMessage *curMsg, uint32 msgClass, uint16 &qualifier, Common::Point &curPos, uint16 &curInv, bool &forceDraw, uint16 code);
|
||||
void processMainButton(uint16 &curInv, uint16 &lastInv, uint16 &oldDirection, bool &forceDraw, uint16 buttonId, uint16 &actionMode);
|
||||
void processAltButton(uint16 &curInv, uint16 &lastInv, uint16 buttonId, uint16 &actionMode);
|
||||
void performAction(uint16 actionMode, Common::Point curPos, uint16 &curInv);
|
||||
|
||||
/**
|
||||
* Writes the game out to disk.
|
||||
*/
|
||||
bool saveGame(int slot, const Common::String &desc);
|
||||
|
||||
/**
|
||||
* Reads the game from disk.
|
||||
*/
|
||||
bool loadGame(int slot);
|
||||
void writeSaveGameHeader(Common::OutSaveFile *out, const Common::String &saveName);
|
||||
|
||||
void handleTrialWarning();
|
||||
};
|
||||
|
||||
WARN_UNUSED_RESULT bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header, bool skipThumbnail = true);
|
||||
|
||||
} // End of namespace Lab
|
||||
|
||||
#endif // LAB_LAB_H
|
||||
75
engines/lab/labsets.cpp
Normal file
75
engines/lab/labsets.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/file.h"
|
||||
|
||||
#include "lab/lab.h"
|
||||
|
||||
#include "lab/labsets.h"
|
||||
#include "lab/resource.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
LargeSet::LargeSet(uint16 last, LabEngine *vm) : _vm(vm) {
|
||||
last = (((last + 15) >> 4) << 4);
|
||||
|
||||
_array = new uint16[last >> 3]();
|
||||
_lastElement = last;
|
||||
}
|
||||
|
||||
LargeSet::~LargeSet() {
|
||||
delete[] _array;
|
||||
}
|
||||
|
||||
bool LargeSet::in(uint16 element) {
|
||||
return ((1 << ((element - 1) % 16)) & (_array[(element - 1) >> 4])) > 0;
|
||||
}
|
||||
|
||||
void LargeSet::inclElement(uint16 element) {
|
||||
_array[(element - 1) >> 4] |= 1 << ((element - 1) % 16);
|
||||
}
|
||||
|
||||
void LargeSet::exclElement(uint16 element) {
|
||||
_array[(element - 1) >> 4] &= ~(1 << ((element - 1) % 16));
|
||||
}
|
||||
|
||||
bool LargeSet::readInitialConditions(const Common::String &fileName) {
|
||||
Common::File *file = _vm->_resource->openDataFile(fileName, MKTAG('C', 'O', 'N', '0'));
|
||||
|
||||
uint16 conditions = file->readUint16LE();
|
||||
for (int i = 0; i < conditions; i++) {
|
||||
inclElement(file->readUint16LE());
|
||||
}
|
||||
|
||||
delete file;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // End of namespace Lab
|
||||
60
engines/lab/labsets.h
Normal file
60
engines/lab/labsets.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LAB_LABSETS_H
|
||||
#define LAB_LABSETS_H
|
||||
|
||||
namespace Lab {
|
||||
|
||||
//---------------------------
|
||||
//----- From LabSets.c ------
|
||||
//---------------------------
|
||||
|
||||
class LabEngine;
|
||||
|
||||
class LargeSet {
|
||||
public:
|
||||
LargeSet(uint16 last, LabEngine *vm);
|
||||
~LargeSet();
|
||||
bool in(uint16 element);
|
||||
void inclElement(uint16 element);
|
||||
void exclElement(uint16 element);
|
||||
bool readInitialConditions(const Common::String &fileName);
|
||||
|
||||
private:
|
||||
LabEngine *_vm;
|
||||
|
||||
public:
|
||||
uint16 _lastElement;
|
||||
uint16 *_array;
|
||||
};
|
||||
|
||||
} // End of namespace Lab
|
||||
|
||||
#endif // LAB_LABSETS_H
|
||||
558
engines/lab/map.cpp
Normal file
558
engines/lab/map.cpp
Normal file
@@ -0,0 +1,558 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/file.h"
|
||||
|
||||
#include "lab/lab.h"
|
||||
|
||||
#include "lab/dispman.h"
|
||||
#include "lab/eventman.h"
|
||||
#include "lab/image.h"
|
||||
#include "lab/interface.h"
|
||||
#include "lab/labsets.h"
|
||||
#include "lab/music.h"
|
||||
#include "lab/processroom.h"
|
||||
#include "lab/resource.h"
|
||||
#include "lab/utils.h"
|
||||
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/*------------------------------ The Map stuff ------------------------------*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
enum MapFloor {
|
||||
kFloorNone,
|
||||
kFloorLower,
|
||||
kFloorMiddle,
|
||||
kFloorUpper,
|
||||
kFloorMedMaze,
|
||||
kFloorHedgeMaze,
|
||||
kFloorSurMaze,
|
||||
kFloorCarnival
|
||||
};
|
||||
|
||||
void LabEngine::loadMapData() {
|
||||
Common::File *mapImages = _resource->openDataFile("P:MapImage");
|
||||
|
||||
_imgMap = new Image(mapImages, this);
|
||||
_imgRoom = new Image(mapImages, this);
|
||||
_imgUpArrowRoom = new Image(mapImages, this);
|
||||
_imgDownArrowRoom = new Image(mapImages, this);
|
||||
_imgHRoom = new Image(mapImages, this);
|
||||
_imgVRoom = new Image(mapImages, this);
|
||||
_imgMaze = new Image(mapImages, this);
|
||||
_imgHugeMaze = new Image(mapImages, this);
|
||||
|
||||
_imgMapX[kDirectionNorth] = new Image(mapImages, this);
|
||||
_imgMapX[kDirectionEast] = new Image(mapImages, this);
|
||||
_imgMapX[kDirectionSouth] = new Image(mapImages, this);
|
||||
_imgMapX[kDirectionWest] = new Image(mapImages, this);
|
||||
_imgPath = new Image(mapImages, this);
|
||||
_imgBridge = new Image(mapImages, this);
|
||||
|
||||
_mapButtonList.push_back(_interface->createButton( 8, _utils->vgaScaleY(105), 0, kActionMapExit, new Image(mapImages, this), new Image(mapImages, this))); // back
|
||||
_mapButtonList.push_back(_interface->createButton( 55, _utils->vgaScaleY(105), 1, kActionUpperFloor, new Image(mapImages, this), new Image(mapImages, this))); // up
|
||||
_mapButtonList.push_back(_interface->createButton(101, _utils->vgaScaleY(105), 2, kActionLowerFloor, new Image(mapImages, this), new Image(mapImages, this))); // down
|
||||
|
||||
delete mapImages;
|
||||
|
||||
Common::File *mapFile = _resource->openDataFile("Lab:Maps", MKTAG('M', 'A', 'P', '0'));
|
||||
updateEvents();
|
||||
|
||||
_maxRooms = mapFile->readUint16LE();
|
||||
_maps = new MapData[_maxRooms + 1]; // will be freed when the user exits the map
|
||||
for (int i = 0; i <= _maxRooms; i++) {
|
||||
_maps[i]._x = mapFile->readUint16LE();
|
||||
_maps[i]._y = mapFile->readUint16LE();
|
||||
_maps[i]._pageNumber = mapFile->readUint16LE();
|
||||
_maps[i]._specialID = (SpecialRoom) mapFile->readUint16LE();
|
||||
_maps[i]._mapFlags = mapFile->readUint32LE();
|
||||
}
|
||||
|
||||
delete mapFile;
|
||||
}
|
||||
|
||||
void LabEngine::freeMapData() {
|
||||
_interface->freeButtonList(&_mapButtonList);
|
||||
|
||||
delete _imgMap;
|
||||
delete _imgRoom;
|
||||
delete _imgUpArrowRoom;
|
||||
delete _imgDownArrowRoom;
|
||||
delete _imgBridge;
|
||||
delete _imgHRoom;
|
||||
delete _imgVRoom;
|
||||
delete _imgMaze;
|
||||
delete _imgHugeMaze;
|
||||
delete _imgPath;
|
||||
for (int i = 0; i < 4; i++)
|
||||
delete _imgMapX[i];
|
||||
delete[] _maps;
|
||||
|
||||
_imgMap = nullptr;
|
||||
_imgRoom = nullptr;
|
||||
_imgUpArrowRoom = nullptr;
|
||||
_imgDownArrowRoom = nullptr;
|
||||
_imgBridge = nullptr;
|
||||
_imgHRoom = nullptr;
|
||||
_imgVRoom = nullptr;
|
||||
_imgMaze = nullptr;
|
||||
_imgHugeMaze = nullptr;
|
||||
_imgPath = nullptr;
|
||||
for (int i = 0; i < 4; i++)
|
||||
_imgMapX[i] = nullptr;
|
||||
_maps = nullptr;
|
||||
}
|
||||
|
||||
Common::Rect LabEngine::roomCoords(uint16 curRoom) {
|
||||
Image *curRoomImg = nullptr;
|
||||
|
||||
switch (_maps[curRoom]._specialID) {
|
||||
case kNormalRoom:
|
||||
case kUpArrowRoom:
|
||||
case kDownArrowRoom:
|
||||
curRoomImg = _imgRoom;
|
||||
break;
|
||||
case kBridgeRoom:
|
||||
curRoomImg = _imgBridge;
|
||||
break;
|
||||
case kVerticalCorridor:
|
||||
curRoomImg = _imgVRoom;
|
||||
break;
|
||||
case kHorizontalCorridor:
|
||||
curRoomImg = _imgHRoom;
|
||||
break;
|
||||
default:
|
||||
// Some rooms (like the map) do not have an image
|
||||
break;
|
||||
}
|
||||
|
||||
int x1 = _utils->mapScaleX(_maps[curRoom]._x);
|
||||
int y1 = _utils->mapScaleY(_maps[curRoom]._y);
|
||||
int x2 = x1;
|
||||
int y2 = y1;
|
||||
|
||||
if (curRoomImg) {
|
||||
x2 += curRoomImg->_width;
|
||||
y2 += curRoomImg->_height;
|
||||
}
|
||||
|
||||
return Common::Rect(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
void LabEngine::drawRoomMap(uint16 curRoom, bool drawMarkFl) {
|
||||
uint16 drawX, drawY, offset;
|
||||
|
||||
uint16 x = _utils->mapScaleX(_maps[curRoom]._x);
|
||||
uint16 y = _utils->mapScaleY(_maps[curRoom]._y);
|
||||
uint32 flags = _maps[curRoom]._mapFlags;
|
||||
|
||||
switch (_maps[curRoom]._specialID) {
|
||||
case kNormalRoom:
|
||||
case kUpArrowRoom:
|
||||
case kDownArrowRoom:
|
||||
if (_maps[curRoom]._specialID == kNormalRoom)
|
||||
_imgRoom->drawImage(x, y);
|
||||
else if (_maps[curRoom]._specialID == kDownArrowRoom)
|
||||
_imgDownArrowRoom->drawImage(x, y);
|
||||
else
|
||||
_imgUpArrowRoom->drawImage(x, y);
|
||||
|
||||
offset = (_imgRoom->_width - _imgPath->_width) / 2;
|
||||
|
||||
if ((kDoorLeftNorth & flags) && (y >= _imgPath->_height))
|
||||
_imgPath->drawImage(x + offset, y - _imgPath->_height);
|
||||
|
||||
if (kDoorLeftSouth & flags)
|
||||
_imgPath->drawImage(x + offset, y + _imgRoom->_height);
|
||||
|
||||
offset = (_imgRoom->_height - _imgPath->_height) / 2;
|
||||
|
||||
if (kDoorLeftEast & flags)
|
||||
_imgPath->drawImage(x + _imgRoom->_width, y + offset);
|
||||
|
||||
if (kDoorLeftWest & flags)
|
||||
_imgPath->drawImage(x - _imgPath->_width, y + offset);
|
||||
|
||||
drawX = x + (_imgRoom->_width - _imgMapX[_direction]->_width) / 2;
|
||||
drawY = y + (_imgRoom->_height - _imgMapX[_direction]->_height) / 2;
|
||||
|
||||
break;
|
||||
|
||||
case kBridgeRoom:
|
||||
_imgBridge->drawImage(x, y);
|
||||
|
||||
drawX = x + (_imgBridge->_width - _imgMapX[_direction]->_width) / 2;
|
||||
drawY = y + (_imgBridge->_height - _imgMapX[_direction]->_height) / 2;
|
||||
|
||||
break;
|
||||
|
||||
case kVerticalCorridor:
|
||||
_imgVRoom->drawImage(x, y);
|
||||
|
||||
offset = (_imgVRoom->_width - _imgPath->_width) / 2;
|
||||
|
||||
if (kDoorLeftNorth & flags)
|
||||
_imgPath->drawImage(x + offset, y - _imgPath->_height);
|
||||
|
||||
if (kDoorLeftSouth & flags)
|
||||
_imgPath->drawImage(x + offset, y + _imgVRoom->_height);
|
||||
|
||||
offset = (_imgRoom->_height - _imgPath->_height) / 2;
|
||||
|
||||
if (kDoorLeftEast & flags)
|
||||
_imgPath->drawImage(x + _imgVRoom->_width, y + offset);
|
||||
|
||||
if (kDoorLeftWest & flags)
|
||||
_imgPath->drawImage(x - _imgPath->_width, y + offset);
|
||||
|
||||
if (kDoorBottomEast & flags)
|
||||
_imgPath->drawImage(x + _imgVRoom->_width, y - offset - _imgPath->_height + _imgVRoom->_height);
|
||||
|
||||
if (kDoorBottomWest & flags)
|
||||
_imgPath->drawImage(x - _imgPath->_width, y - offset - _imgPath->_height + _imgVRoom->_height);
|
||||
|
||||
offset = (_imgVRoom->_height - _imgPath->_height) / 2;
|
||||
|
||||
if (kDoorMiddleEast & flags)
|
||||
_imgPath->drawImage(x + _imgVRoom->_width, y - offset - _imgPath->_height + _imgVRoom->_height);
|
||||
|
||||
if (kDoorMiddleWest & flags)
|
||||
_imgPath->drawImage(x - _imgPath->_width, y - offset - _imgPath->_height + _imgVRoom->_height);
|
||||
|
||||
drawX = x + (_imgVRoom->_width - _imgMapX[_direction]->_width) / 2;
|
||||
drawY = y + (_imgVRoom->_height - _imgMapX[_direction]->_height) / 2;
|
||||
|
||||
break;
|
||||
|
||||
case kHorizontalCorridor:
|
||||
_imgHRoom->drawImage(x, y);
|
||||
|
||||
offset = (_imgRoom->_width - _imgPath->_width) / 2;
|
||||
|
||||
if (kDoorLeftNorth & flags)
|
||||
_imgPath->drawImage(x + offset, y - _imgPath->_height);
|
||||
|
||||
if (kDoorLeftSouth & flags)
|
||||
_imgPath->drawImage(x + offset, y + _imgRoom->_height);
|
||||
|
||||
if (kDoorRightNorth & flags)
|
||||
_imgPath->drawImage(x - offset - _imgPath->_width + _imgHRoom->_width, y - _imgPath->_height);
|
||||
|
||||
if (kDoorRightSouth & flags)
|
||||
_imgPath->drawImage(x - offset - _imgPath->_width + _imgHRoom->_width, y + _imgRoom->_height);
|
||||
|
||||
offset = (_imgHRoom->_width - _imgPath->_width) / 2;
|
||||
|
||||
if (kDoorMiddleNorth & flags)
|
||||
_imgPath->drawImage(x - offset - _imgPath->_width + _imgHRoom->_width, y - _imgPath->_height);
|
||||
|
||||
if (kDoorMiddleSouth & flags)
|
||||
_imgPath->drawImage(x - offset - _imgPath->_width + _imgHRoom->_width, y + _imgRoom->_height);
|
||||
|
||||
offset = (_imgRoom->_height - _imgPath->_height) / 2;
|
||||
|
||||
if (kDoorLeftEast & flags)
|
||||
_imgPath->drawImage(x + _imgHRoom->_width, y + offset);
|
||||
|
||||
if (kDoorLeftWest & flags)
|
||||
_imgPath->drawImage(x - _imgPath->_width, y + offset);
|
||||
|
||||
drawX = x + (_imgHRoom->_width - _imgMapX[_direction]->_width) / 2;
|
||||
drawY = y + (_imgHRoom->_height - _imgMapX[_direction]->_height) / 2;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (drawMarkFl)
|
||||
_imgMapX[_direction]->drawImage(drawX, drawY);
|
||||
}
|
||||
|
||||
bool LabEngine::floorVisited(uint16 floorNum) {
|
||||
for (int i = 0; i < _maxRooms; i++) {
|
||||
if ((_maps[i]._pageNumber == floorNum) && _roomsFound->in(i) && _maps[i]._x)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16 LabEngine::getUpperFloor(uint16 floorNum) {
|
||||
if ((floorNum == kFloorCarnival) || (floorNum == kFloorNone))
|
||||
return kFloorNone;
|
||||
|
||||
for (int i = floorNum; i < kFloorCarnival; i++)
|
||||
if (floorVisited(i + 1))
|
||||
return i + 1;
|
||||
|
||||
return kFloorNone;
|
||||
}
|
||||
|
||||
uint16 LabEngine::getLowerFloor(uint16 floorNum) {
|
||||
if ((floorNum == kFloorLower) || (floorNum == kFloorNone))
|
||||
return kFloorNone;
|
||||
|
||||
for (int i = floorNum; i > kFloorLower; i--)
|
||||
if (floorVisited(i - 1))
|
||||
return i - 1;
|
||||
|
||||
return kFloorNone;
|
||||
}
|
||||
|
||||
void LabEngine::drawMap(uint16 curRoom, uint16 curMsg, uint16 floorNum, bool fadeIn) {
|
||||
_graphics->rectFill(0, 0, _graphics->_screenWidth - 1, _graphics->_screenHeight - 1, 0);
|
||||
_imgMap->drawImage(0, 0);
|
||||
_interface->drawButtonList(&_mapButtonList);
|
||||
|
||||
for (int i = 1; i <= _maxRooms; i++) {
|
||||
if ((_maps[i]._pageNumber == floorNum) && _roomsFound->in(i) && _maps[i]._x) {
|
||||
drawRoomMap(i, (bool)(i == curRoom));
|
||||
}
|
||||
}
|
||||
|
||||
updateEvents();
|
||||
|
||||
// Makes sure the X is drawn in corridors
|
||||
// NOTE: this here on purpose just in case there's some weird
|
||||
// condition, like the surreal maze where there are no rooms
|
||||
if ((_maps[curRoom]._pageNumber == floorNum) && _roomsFound->in(curRoom) && _maps[curRoom]._x)
|
||||
drawRoomMap(curRoom, true);
|
||||
|
||||
_interface->toggleButton(_interface->getButton(1), 12, (getUpperFloor(floorNum) != kFloorNone)); // up button
|
||||
_interface->toggleButton(_interface->getButton(2), 12, (getLowerFloor(floorNum) != kFloorNone)); // down button
|
||||
|
||||
// Labyrinth specific code
|
||||
if (floorNum == kFloorLower) {
|
||||
if (floorVisited(kFloorSurMaze))
|
||||
_imgMaze->drawImage(_utils->mapScaleX(538), _utils->mapScaleY(277));
|
||||
} else if (floorNum == kFloorMiddle) {
|
||||
if (floorVisited(kFloorCarnival))
|
||||
_imgMaze->drawImage(_utils->mapScaleX(358), _utils->mapScaleY(72));
|
||||
|
||||
if (floorVisited(kFloorMedMaze))
|
||||
_imgMaze->drawImage(_utils->mapScaleX(557), _utils->mapScaleY(325));
|
||||
} else if (floorNum == kFloorUpper) {
|
||||
if (floorVisited(kFloorHedgeMaze))
|
||||
_imgHugeMaze->drawImage(_utils->mapScaleX(524), _utils->mapScaleY(97));
|
||||
} else if (floorNum == kFloorSurMaze) {
|
||||
Common::Rect textRect = Common::Rect(_utils->mapScaleX(360), 0, _utils->mapScaleX(660), _utils->mapScaleY(450));
|
||||
_graphics->flowText(_msgFont, 0, 7, 0, true, true, true, true, textRect, _resource->getStaticText(kTextSurmazeMessage).c_str());
|
||||
}
|
||||
|
||||
if ((floorNum >= kFloorLower) && (floorNum <= kFloorCarnival)) {
|
||||
_graphics->flowText(_msgFont, 0, 5, 3, true, true, true, true, _utils->vgaRectScale(14, 75, 134, 97), _resource->getStaticText(floorNum - 1).c_str());
|
||||
}
|
||||
|
||||
if (!_rooms[curMsg]._roomMsg.empty())
|
||||
_graphics->flowText(_msgFont, 0, 5, 3, true, true, true, true, _utils->vgaRectScale(14, 148, 134, 186), _rooms[curMsg]._roomMsg.c_str());
|
||||
|
||||
if (fadeIn)
|
||||
_graphics->fade(true);
|
||||
}
|
||||
|
||||
void LabEngine::processMap(uint16 curRoom) {
|
||||
byte place = 1;
|
||||
uint16 curMsg = curRoom;
|
||||
uint16 curFloor = _maps[curRoom]._pageNumber;
|
||||
|
||||
while (1) {
|
||||
IntuiMessage *msg = _event->getMsg();
|
||||
if (shouldQuit()) {
|
||||
_quitLab = true;
|
||||
return;
|
||||
}
|
||||
|
||||
updateEvents();
|
||||
_graphics->screenUpdate();
|
||||
_system->delayMillis(10);
|
||||
|
||||
if (!msg) {
|
||||
updateEvents();
|
||||
|
||||
byte newcolor[3];
|
||||
|
||||
if (place <= 14) {
|
||||
newcolor[0] = 14 << 2;
|
||||
newcolor[1] = place << 2;
|
||||
newcolor[2] = newcolor[1];
|
||||
} else {
|
||||
newcolor[0] = 14 << 2;
|
||||
newcolor[1] = (28 - place) << 2;
|
||||
newcolor[2] = newcolor[1];
|
||||
}
|
||||
|
||||
waitTOF();
|
||||
_graphics->writeColorRegs(newcolor, 1, 1);
|
||||
_interface->handlePressedButton();
|
||||
waitTOF();
|
||||
|
||||
place++;
|
||||
|
||||
if (place >= 28)
|
||||
place = 1;
|
||||
|
||||
} else {
|
||||
uint32 msgClass = msg->_msgClass;
|
||||
uint16 msgCode = msg->_code;
|
||||
uint16 mouseX = msg->_mouse.x;
|
||||
uint16 mouseY = msg->_mouse.y;
|
||||
|
||||
if ((msgClass == kMessageRightClick) || ((msgClass == kMessageAction) && (msgCode == kActionExit)))
|
||||
return;
|
||||
|
||||
if (msgClass == kMessageButtonUp) {
|
||||
if (msgCode == 0) {
|
||||
// Quit menu button
|
||||
return;
|
||||
} else if (msgCode == 1) {
|
||||
// Up arrow
|
||||
uint16 upperFloor = getUpperFloor(curFloor);
|
||||
if (upperFloor != kFloorNone) {
|
||||
curFloor = upperFloor;
|
||||
_graphics->fade(false);
|
||||
drawMap(curRoom, curMsg, curFloor, false);
|
||||
_graphics->fade(true);
|
||||
}
|
||||
} else if (msgCode == 2) {
|
||||
// Down arrow
|
||||
uint16 lowerFloor = getLowerFloor(curFloor);
|
||||
if (lowerFloor != kFloorNone) {
|
||||
curFloor = lowerFloor;
|
||||
_graphics->fade(false);
|
||||
drawMap(curRoom, curMsg, curFloor, false);
|
||||
_graphics->fade(true);
|
||||
}
|
||||
}
|
||||
} else if (msgClass == kMessageLeftClick) {
|
||||
if ((curFloor == kFloorLower) && _utils->mapRectScale(538, 277, 633, 352).contains(mouseX, mouseY)
|
||||
&& floorVisited(kFloorSurMaze)) {
|
||||
curFloor = kFloorSurMaze;
|
||||
|
||||
_graphics->fade(false);
|
||||
drawMap(curRoom, curMsg, curFloor, false);
|
||||
_graphics->fade(true);
|
||||
} else if ((curFloor == kFloorMiddle) && _utils->mapRectScale(358, 71, 452, 147).contains(mouseX, mouseY)
|
||||
&& floorVisited(kFloorCarnival)) {
|
||||
curFloor = kFloorCarnival;
|
||||
|
||||
_graphics->fade(false);
|
||||
drawMap(curRoom, curMsg, curFloor, false);
|
||||
_graphics->fade(true);
|
||||
} else if ((curFloor == kFloorMiddle) && _utils->mapRectScale(557, 325, 653, 401).contains(mouseX, mouseY)
|
||||
&& floorVisited(kFloorMedMaze)) {
|
||||
curFloor = kFloorMedMaze;
|
||||
|
||||
_graphics->fade(false);
|
||||
drawMap(curRoom, curMsg, curFloor, false);
|
||||
_graphics->fade(true);
|
||||
} else if ((curFloor == kFloorUpper) && _utils->mapRectScale(524, 97, 645, 207).contains(mouseX, mouseY)
|
||||
&& floorVisited(kFloorHedgeMaze)) {
|
||||
curFloor = kFloorHedgeMaze;
|
||||
|
||||
_graphics->fade(false);
|
||||
drawMap(curRoom, curMsg, curFloor, false);
|
||||
_graphics->fade(true);
|
||||
} else if (mouseX > _utils->mapScaleX(314)) {
|
||||
uint16 oldMsg = curMsg;
|
||||
Common::Rect curCoords;
|
||||
|
||||
for (int i = 1; i <= _maxRooms; i++) {
|
||||
curCoords = roomCoords(i);
|
||||
|
||||
if ((_maps[i]._pageNumber == curFloor)
|
||||
&& _roomsFound->in(i) && curCoords.contains(Common::Point(mouseX, mouseY))) {
|
||||
curMsg = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (oldMsg != curMsg) {
|
||||
if (!_rooms[curMsg]._roomMsg.empty())
|
||||
_resource->readViews(curMsg);
|
||||
|
||||
const char *sptr;
|
||||
if ((sptr = _rooms[curMsg]._roomMsg.c_str())) {
|
||||
_graphics->rectFillScaled(13, 148, 135, 186, 3);
|
||||
_graphics->flowText(_msgFont, 0, 5, 3, true, true, true, true, _utils->vgaRectScale(14, 148, 134, 186), sptr);
|
||||
|
||||
if (_maps[oldMsg]._pageNumber == curFloor)
|
||||
drawRoomMap(oldMsg, (bool)(oldMsg == curRoom));
|
||||
|
||||
curCoords = roomCoords(curMsg);
|
||||
int right = (curCoords.left + curCoords.right) / 2;
|
||||
int left = right - 1;
|
||||
int top, bottom;
|
||||
top = bottom = (curCoords.top + curCoords.bottom) / 2;
|
||||
|
||||
if ((curMsg != curRoom) && (_maps[curMsg]._pageNumber == curFloor))
|
||||
_graphics->rectFill(left, top, right, bottom, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_graphics->screenUpdate();
|
||||
}
|
||||
} // while
|
||||
}
|
||||
|
||||
void LabEngine::doMap() {
|
||||
static uint16 amigaMapPalette[] = {
|
||||
0x0BA8, 0x0C11, 0x0A74, 0x0076,
|
||||
0x0A96, 0x0DCB, 0x0CCA, 0x0222,
|
||||
0x0444, 0x0555, 0x0777, 0x0999,
|
||||
0x0AAA, 0x0ED0, 0x0EEE, 0x0694
|
||||
};
|
||||
|
||||
_graphics->_fadePalette = amigaMapPalette;
|
||||
|
||||
updateEvents();
|
||||
loadMapData();
|
||||
_graphics->blackAllScreen();
|
||||
_interface->attachButtonList(&_mapButtonList);
|
||||
drawMap(_roomNum, _roomNum, _maps[_roomNum]._pageNumber, true);
|
||||
_event->mouseShow();
|
||||
_graphics->screenUpdate();
|
||||
processMap(_roomNum);
|
||||
_event->mouseHide();
|
||||
_interface->attachButtonList(nullptr);
|
||||
_graphics->fade(false);
|
||||
_graphics->blackAllScreen();
|
||||
_graphics->rectFill(0, 0, _graphics->_screenWidth - 1, _graphics->_screenHeight - 1, 0);
|
||||
freeMapData();
|
||||
_event->mouseShow();
|
||||
_graphics->screenUpdate();
|
||||
}
|
||||
|
||||
} // End of namespace Lab
|
||||
432
engines/lab/metaengine.cpp
Normal file
432
engines/lab/metaengine.cpp
Normal file
@@ -0,0 +1,432 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lab/lab.h"
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
#include "common/translation.h"
|
||||
|
||||
#include "backends/keymapper/action.h"
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
#include "backends/keymapper/standard-actions.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
Common::Platform LabEngine::getPlatform() const {
|
||||
return _gameDescription->platform;
|
||||
}
|
||||
|
||||
uint32 LabEngine::getFeatures() const {
|
||||
return _gameDescription->flags | _extraGameFeatures;
|
||||
}
|
||||
|
||||
} // End of namespace Lab
|
||||
|
||||
class LabMetaEngine : public AdvancedMetaEngine<ADGameDescription> {
|
||||
public:
|
||||
const char *getName() const override {
|
||||
return "lab";
|
||||
}
|
||||
|
||||
Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override {
|
||||
*engine = new Lab::LabEngine(syst, desc);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
bool hasFeature(MetaEngineFeature f) const override;
|
||||
SaveStateList listSaves(const char *target) const override;
|
||||
int getMaximumSaveSlot() const override;
|
||||
bool removeSaveState(const char *target, int slot) const override;
|
||||
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override;
|
||||
Common::KeymapArray initKeymaps(const char *target) const override;
|
||||
};
|
||||
|
||||
bool LabMetaEngine::hasFeature(MetaEngineFeature f) const {
|
||||
return
|
||||
(f == kSupportsListSaves) ||
|
||||
(f == kSupportsLoadingDuringStartup) ||
|
||||
(f == kSupportsDeleteSave) ||
|
||||
(f == kSavesSupportMetaInfo) ||
|
||||
(f == kSavesSupportThumbnail) ||
|
||||
(f == kSavesSupportCreationDate) ||
|
||||
(f == kSavesSupportPlayTime) ||
|
||||
(f == kSimpleSavesNames);
|
||||
}
|
||||
|
||||
bool Lab::LabEngine::hasFeature(EngineFeature f) const {
|
||||
return
|
||||
(f == kSupportsReturnToLauncher) ||
|
||||
(f == kSupportsLoadingDuringRuntime) ||
|
||||
(f == kSupportsSavingDuringRuntime);
|
||||
}
|
||||
|
||||
SaveStateList LabMetaEngine::listSaves(const char *target) const {
|
||||
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
|
||||
Lab::SaveGameHeader header;
|
||||
Common::String pattern = target;
|
||||
pattern += ".###";
|
||||
|
||||
Common::StringArray filenames = saveFileMan->listSavefiles(pattern.c_str());
|
||||
SaveStateList saveList;
|
||||
|
||||
for (const auto &filename : filenames) {
|
||||
// Obtain the last 3 digits of the filename, since they correspond to the save slot
|
||||
int slotNum = atoi(filename.c_str() + filename.size() - 3);
|
||||
|
||||
if (slotNum >= 0 && slotNum <= 999) {
|
||||
Common::InSaveFile *in = saveFileMan->openForLoading(filename);
|
||||
if (in) {
|
||||
if (Lab::readSaveGameHeader(in, header))
|
||||
saveList.push_back(SaveStateDescriptor(this, slotNum, header._descr.getDescription()));
|
||||
delete in;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort saves based on slot number.
|
||||
Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
|
||||
return saveList;
|
||||
}
|
||||
|
||||
int LabMetaEngine::getMaximumSaveSlot() const {
|
||||
return 999;
|
||||
}
|
||||
|
||||
bool LabMetaEngine::removeSaveState(const char *target, int slot) const {
|
||||
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
|
||||
return saveFileMan->removeSavefile(Common::String::format("%s.%03u", target, slot));
|
||||
}
|
||||
|
||||
SaveStateDescriptor LabMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
|
||||
Common::String filename = Common::String::format("%s.%03u", target, slot);
|
||||
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename.c_str());
|
||||
|
||||
if (in) {
|
||||
Lab::SaveGameHeader header;
|
||||
|
||||
bool successfulRead = Lab::readSaveGameHeader(in, header, false);
|
||||
delete in;
|
||||
|
||||
if (successfulRead) {
|
||||
SaveStateDescriptor desc(this, slot, header._descr.getDescription());
|
||||
return header._descr;
|
||||
}
|
||||
}
|
||||
|
||||
return SaveStateDescriptor();
|
||||
}
|
||||
|
||||
Common::KeymapArray LabMetaEngine::initKeymaps(const char *target) const {
|
||||
using namespace Common;
|
||||
using namespace Lab;
|
||||
|
||||
Keymap *engineKeymap = new Keymap(Keymap::kKeymapTypeGame, "lab-default", _("Default keymappings"));
|
||||
Keymap *exitKeymap = new Keymap(Keymap::kKeymapTypeGame, "exit", _("Exit keymappings"));
|
||||
Keymap *quitDialogKeymap = new Keymap(Keymap::kKeymapTypeGame, "quit-dialog", _("Quit dialog keymappings"));
|
||||
Keymap *gameKeymap = new Keymap(Keymap::kKeymapTypeGame, "game-shortcuts", _("Game keymappings"));
|
||||
Keymap *invKeymap = new Keymap(Keymap::kKeymapTypeGame, "inventory", _("Inventory keymappings"));
|
||||
Keymap *introKeymap = new Keymap(Keymap::kKeymapTypeGame, "intro", _("Intro keymappings"));
|
||||
Keymap *mapKeymap = new Keymap(Keymap::kKeymapTypeGame, "map", _("Map keymappings"));
|
||||
Keymap *journalKeymap = new Keymap(Keymap::kKeymapTypeGame, "journal", _("Journal keymappings"));
|
||||
|
||||
Common::Action *act;
|
||||
|
||||
act = new Common::Action(kStandardActionLeftClick, _("Interact"));
|
||||
act->setLeftClickEvent();
|
||||
act->addDefaultInputMapping("MOUSE_LEFT");
|
||||
act->addDefaultInputMapping("JOY_A");
|
||||
engineKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action(kStandardActionRightClick, _("Exit"));
|
||||
act->setRightClickEvent();
|
||||
act->addDefaultInputMapping("MOUSE_RIGHT");
|
||||
act->addDefaultInputMapping("JOY_B");
|
||||
engineKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("QUIT", _("Quit"));
|
||||
act->setCustomEngineActionEvent(kActionQuit);
|
||||
act->addDefaultInputMapping("q");
|
||||
act->addDefaultInputMapping("x");
|
||||
act->addDefaultInputMapping("JOY_DOWN");
|
||||
engineKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("RAISESOUND", _("Raise the sound volume"));
|
||||
act->setCustomEngineActionEvent(kActionSoundRaise);
|
||||
act->addDefaultInputMapping("RIGHTBRACKET");
|
||||
act->addDefaultInputMapping("JOY_LEFT_SHOULDER");
|
||||
engineKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("LOWERSOUND", _("Lower the sound volume"));
|
||||
act->setCustomEngineActionEvent(kActionSoundLower);
|
||||
act->addDefaultInputMapping("LEFTBRACKET");
|
||||
act->addDefaultInputMapping("JOY_RIGHT_SHOULDER");
|
||||
engineKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("EXIT", _("Exit"));
|
||||
act->setCustomEngineActionEvent(kActionExit);
|
||||
act->addDefaultInputMapping("ESCAPE");
|
||||
act->addDefaultInputMapping("JOY_Y");
|
||||
exitKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("YES", _("Yes"));
|
||||
act->setCustomEngineActionEvent(kActionQuitDialogYes);
|
||||
act->addDefaultInputMapping("y");
|
||||
act->addDefaultInputMapping("q");
|
||||
act->addDefaultInputMapping("JOY_A");
|
||||
quitDialogKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("NO", _("No"));
|
||||
act->setCustomEngineActionEvent(kActionQuitDialogNo);
|
||||
act->addDefaultInputMapping("JOY_B");
|
||||
quitDialogKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("SKIP_INTRO", _("Skip intro"));
|
||||
act->setCustomEngineActionEvent(kActionSkipIntro);
|
||||
act->addDefaultInputMapping("MOUSE_RIGHT");
|
||||
act->addDefaultInputMapping("ESCAPE");
|
||||
act->addDefaultInputMapping("JOY_X");
|
||||
introKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("INTERACT", _("Interact with object with chosen action"));
|
||||
act->setCustomEngineActionEvent(kActionInteract);
|
||||
act->addDefaultInputMapping("RETURN");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("TAKE", _("Take object"));
|
||||
act->setCustomEngineActionEvent(kActionTake);
|
||||
act->addDefaultInputMapping("t");
|
||||
act->addDefaultInputMapping("1");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("MOVE", _("Move or manipulate object"));
|
||||
act->setCustomEngineActionEvent(kActionMove);
|
||||
act->addDefaultInputMapping("m");
|
||||
act->addDefaultInputMapping("2");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("OPEN", _("Open door or object"));
|
||||
act->setCustomEngineActionEvent(kActionOpen);
|
||||
act->addDefaultInputMapping("o");
|
||||
act->addDefaultInputMapping("3");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("CLOSE", _("Close door or object"));
|
||||
act->setCustomEngineActionEvent(kActionClose);
|
||||
act->addDefaultInputMapping("c");
|
||||
act->addDefaultInputMapping("4");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("LOOK", _("Look at object close-up"));
|
||||
act->setCustomEngineActionEvent(kActionLook);
|
||||
act->addDefaultInputMapping("l");
|
||||
act->addDefaultInputMapping("5");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("INVENTORY", _("Switch to inventory display"));
|
||||
act->setCustomEngineActionEvent(kActionInv);
|
||||
act->addDefaultInputMapping("i");
|
||||
act->addDefaultInputMapping("6");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("LEFT", _("Turn left"));
|
||||
act->setCustomEngineActionEvent(kActionLeft);
|
||||
act->addDefaultInputMapping("LEFT");
|
||||
act->addDefaultInputMapping("7");
|
||||
act->addDefaultInputMapping("JOY_LEFT");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("FORWARD", _("Walk forward"));
|
||||
act->setCustomEngineActionEvent(kActionForward);
|
||||
act->addDefaultInputMapping("UP");
|
||||
act->addDefaultInputMapping("8");
|
||||
act->addDefaultInputMapping("JOY_UP");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("RIGHT", _("Turn right"));
|
||||
act->setCustomEngineActionEvent(kActionRight);
|
||||
act->addDefaultInputMapping("RIGHT");
|
||||
act->addDefaultInputMapping("9");
|
||||
act->addDefaultInputMapping("JOY_RIGHT");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("MAP", _("Show map"));
|
||||
act->setCustomEngineActionEvent(kActionMap);
|
||||
act->addDefaultInputMapping("p");
|
||||
act->addDefaultInputMapping("0");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("FOCUS", _("Move focus to interactive object"));
|
||||
act->setCustomEngineActionEvent(kActionFocusOnNextInteractiveItem);
|
||||
act->addDefaultInputMapping("TAB");
|
||||
act->addDefaultInputMapping("JOY_X");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
if (parsePlatform(ConfMan.get("platform")) == Common::kPlatformWindows) {
|
||||
|
||||
act = new Common::Action("STARTBREADCRUMB", _("Start dropping virtual bread crumbs"));
|
||||
act->setCustomEngineActionEvent(kActionDropBreadcrumb);
|
||||
act->addDefaultInputMapping("b");
|
||||
act->addDefaultInputMapping("JOY_LEFT_TRIGGER");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("FOLLOWBREADCRUMBS", _("Follow virtual bread crumbs"));
|
||||
act->setCustomEngineActionEvent(kActionFollowBreadcrumbs);
|
||||
act->addDefaultInputMapping("f");
|
||||
act->addDefaultInputMapping("JOY_RIGHT_TRIGGER");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("RUNFOLLOWINGBREADCRUMBS", _("Run while following virtual bread crumbs"));
|
||||
act->setCustomEngineActionEvent(kActionRunWhileFollowingBreadcrumbs);
|
||||
act->addDefaultInputMapping("r");
|
||||
act->addDefaultInputMapping("JOY_X");
|
||||
gameKeymap->addAction(act);
|
||||
}
|
||||
|
||||
act = new Common::Action("MAINDISPLAY", _("Switch to main display"));
|
||||
act->setCustomEngineActionEvent(kActionMainDisplay);
|
||||
act->addDefaultInputMapping("ESCAPE");
|
||||
act->addDefaultInputMapping("1");
|
||||
invKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("SAVELOAD", _("Open save / load dialog"));
|
||||
act->setCustomEngineActionEvent(kActionSaveLoad);
|
||||
act->addDefaultInputMapping("g");
|
||||
act->addDefaultInputMapping("2");
|
||||
invKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("USE", _("Use"));
|
||||
act->setCustomEngineActionEvent(kActionUse);
|
||||
act->addDefaultInputMapping("u");
|
||||
act->addDefaultInputMapping("3");
|
||||
invKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("LOOKSCENE", _("Look at scene"));
|
||||
act->setCustomEngineActionEvent(kActionInvLook);
|
||||
act->addDefaultInputMapping("l");
|
||||
act->addDefaultInputMapping("4");
|
||||
invKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("PREV", _("Previous inventory item"));
|
||||
act->setCustomEngineActionEvent(kActionPrev);
|
||||
act->addDefaultInputMapping("LEFT");
|
||||
act->addDefaultInputMapping("5");
|
||||
act->addDefaultInputMapping("JOY_LEFT");
|
||||
invKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("NEXT", _("Next inventory item"));
|
||||
act->setCustomEngineActionEvent(kActionNext);
|
||||
act->addDefaultInputMapping("RIGHT");
|
||||
act->addDefaultInputMapping("6");
|
||||
act->addDefaultInputMapping("JOY_RIGHT");
|
||||
invKeymap->addAction(act);
|
||||
|
||||
|
||||
if (parsePlatform(ConfMan.get("platform")) == Common::kPlatformWindows) {
|
||||
|
||||
act = new Common::Action("STARTBREADCRUMB", _("Start dropping virtual bread crumbs"));
|
||||
act->setCustomEngineActionEvent(kActionDropBreadcrumb);
|
||||
act->addDefaultInputMapping("b");
|
||||
act->addDefaultInputMapping("7");
|
||||
act->addDefaultInputMapping("JOY_LEFT_TRIGGER");
|
||||
invKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("FOLLOWBREADCRUMBS", _("Follow virtual bread crumbs"));
|
||||
act->setCustomEngineActionEvent(kActionFollowBreadcrumbs);
|
||||
act->addDefaultInputMapping("f");
|
||||
act->addDefaultInputMapping("8");
|
||||
act->addDefaultInputMapping("JOY_RIGHT_TRIGGER");
|
||||
invKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("RUNFOLLOWINGBREADCRUMBS", _("Run while following virtual bread crumbs"));
|
||||
act->setCustomEngineActionEvent(kActionRunWhileFollowingBreadcrumbs);
|
||||
act->addDefaultInputMapping("r");
|
||||
act->addDefaultInputMapping("JOY_X");
|
||||
invKeymap->addAction(act);
|
||||
}
|
||||
|
||||
act = new Common::Action("EXITMAP", _("Exit map display"));
|
||||
act->setCustomEngineActionEvent(kActionMapExit);
|
||||
act->addDefaultInputMapping("ESCAPE");
|
||||
act->addDefaultInputMapping("1");
|
||||
mapKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("UPLEVEL", _("Up one level"));
|
||||
act->setCustomEngineActionEvent(kActionUpperFloor);
|
||||
act->addDefaultInputMapping("UP");
|
||||
act->addDefaultInputMapping("2");
|
||||
mapKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("DOWNLEVEL", _("Down one level"));
|
||||
act->setCustomEngineActionEvent(kActionLowerFloor);
|
||||
act->addDefaultInputMapping("DOWN");
|
||||
act->addDefaultInputMapping("3");
|
||||
mapKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("JOURNALBACK", _("Go back in journal"));
|
||||
act->setCustomEngineActionEvent(kActionJournalBack);
|
||||
act->addDefaultInputMapping("LEFT");
|
||||
act->addDefaultInputMapping("1");
|
||||
journalKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("EXITJOURNAL", _("Exit journal"));
|
||||
act->setCustomEngineActionEvent(kActionJournalExit);
|
||||
act->addDefaultInputMapping("2");
|
||||
journalKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("JOURNALFORWARD", _("Go forward in journal"));
|
||||
act->setCustomEngineActionEvent(kActionJournalForward);
|
||||
act->addDefaultInputMapping("RIGHT");
|
||||
act->addDefaultInputMapping("3");
|
||||
journalKeymap->addAction(act);
|
||||
|
||||
KeymapArray keymaps(8);
|
||||
|
||||
keymaps[0] = engineKeymap;
|
||||
keymaps[1] = exitKeymap;
|
||||
keymaps[2] = gameKeymap;
|
||||
keymaps[3] = invKeymap;
|
||||
keymaps[4] = introKeymap;
|
||||
keymaps[5] = mapKeymap;
|
||||
keymaps[6] = quitDialogKeymap;
|
||||
keymaps[7] = journalKeymap;
|
||||
|
||||
invKeymap->setEnabled(false);
|
||||
introKeymap->setEnabled(false);
|
||||
mapKeymap->setEnabled(false);
|
||||
quitDialogKeymap->setEnabled(false);
|
||||
journalKeymap->setEnabled(false);
|
||||
|
||||
return keymaps;
|
||||
}
|
||||
|
||||
#if PLUGIN_ENABLED_DYNAMIC(LAB)
|
||||
REGISTER_PLUGIN_DYNAMIC(LAB, PLUGIN_TYPE_ENGINE, LabMetaEngine);
|
||||
#else
|
||||
REGISTER_PLUGIN_STATIC(LAB, PLUGIN_TYPE_ENGINE, LabMetaEngine);
|
||||
#endif
|
||||
33
engines/lab/module.mk
Normal file
33
engines/lab/module.mk
Normal file
@@ -0,0 +1,33 @@
|
||||
MODULE := engines/lab
|
||||
|
||||
MODULE_OBJS := \
|
||||
anim.o \
|
||||
console.o \
|
||||
dispman.o \
|
||||
engine.o \
|
||||
eventman.o \
|
||||
image.o \
|
||||
interface.o \
|
||||
intro.o \
|
||||
lab.o \
|
||||
labsets.o \
|
||||
map.o \
|
||||
metaengine.o \
|
||||
music.o \
|
||||
processroom.o \
|
||||
resource.o \
|
||||
savegame.o \
|
||||
special.o \
|
||||
speciallocks.o \
|
||||
utils.o
|
||||
|
||||
# This module can be built as a plugin
|
||||
ifeq ($(ENABLE_LAB), DYNAMIC_PLUGIN)
|
||||
PLUGIN := 1
|
||||
endif
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/rules.mk
|
||||
|
||||
# Detection objects
|
||||
DETECT_OBJS += $(MODULE)/detection.o
|
||||
170
engines/lab/music.cpp
Normal file
170
engines/lab/music.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/file.h"
|
||||
#include "audio/audiostream.h"
|
||||
#include "audio/decoders/raw.h"
|
||||
|
||||
#include "lab/lab.h"
|
||||
|
||||
#include "lab/anim.h"
|
||||
#include "lab/eventman.h"
|
||||
#include "lab/music.h"
|
||||
#include "lab/resource.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
#define CLOWNROOM 123
|
||||
#define DIMROOM 80
|
||||
|
||||
Music::Music(LabEngine *vm) : _vm(vm) {
|
||||
_musicFile = nullptr;
|
||||
_storedPos = 0;
|
||||
}
|
||||
|
||||
byte Music::getSoundFlags() {
|
||||
byte soundFlags = Audio::FLAG_LITTLE_ENDIAN;
|
||||
if (_vm->getPlatform() == Common::kPlatformWindows)
|
||||
soundFlags |= Audio::FLAG_16BITS;
|
||||
else if (_vm->getPlatform() == Common::kPlatformDOS)
|
||||
soundFlags |= Audio::FLAG_UNSIGNED;
|
||||
|
||||
return soundFlags;
|
||||
}
|
||||
|
||||
void Music::loadSoundEffect(const Common::String &filename, bool loop, bool waitTillFinished) {
|
||||
stopSoundEffect();
|
||||
|
||||
Common::File *file = _vm->_resource->openDataFile(filename, MKTAG('D', 'I', 'F', 'F'));
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
_vm->_anim->_doBlack = false;
|
||||
|
||||
uint32 magicBytes = file->readUint32LE();
|
||||
if (magicBytes != 1219009121) {
|
||||
warning("readSound: Bad signature, skipping");
|
||||
return;
|
||||
}
|
||||
uint32 soundTag = file->readUint32LE();
|
||||
uint32 soundSize = file->readUint32LE();
|
||||
|
||||
if (soundTag != 0)
|
||||
return;
|
||||
|
||||
file->skip(soundSize); // skip the header
|
||||
|
||||
while (soundTag != 65535) {
|
||||
_vm->updateEvents();
|
||||
soundTag = file->readUint32LE();
|
||||
soundSize = file->readUint32LE() - 8;
|
||||
|
||||
if ((soundTag == 30) || (soundTag == 31)) {
|
||||
if (waitTillFinished) {
|
||||
while (isSoundEffectActive()) {
|
||||
_vm->updateEvents();
|
||||
_vm->waitTOF();
|
||||
}
|
||||
}
|
||||
|
||||
file->skip(4);
|
||||
|
||||
uint16 sampleRate = file->readUint16LE();
|
||||
file->skip(2);
|
||||
playSoundEffect(sampleRate, soundSize, loop, file);
|
||||
} else if (soundTag == 65535) {
|
||||
if (waitTillFinished) {
|
||||
while (isSoundEffectActive()) {
|
||||
_vm->updateEvents();
|
||||
_vm->waitTOF();
|
||||
}
|
||||
}
|
||||
} else
|
||||
file->skip(soundSize);
|
||||
}
|
||||
}
|
||||
|
||||
void Music::playSoundEffect(uint16 sampleSpeed, uint32 length, bool loop, Common::File *dataFile) {
|
||||
stopSoundEffect();
|
||||
|
||||
// NOTE: We need to use malloc(), cause this will be freed with free()
|
||||
// by the music code
|
||||
byte *soundData = (byte *)malloc(length);
|
||||
dataFile->read(soundData, length);
|
||||
|
||||
Audio::SeekableAudioStream *audioStream = Audio::makeRawStream((const byte *)soundData, length, MAX<uint16>(sampleSpeed, 4000), getSoundFlags());
|
||||
_vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, new Audio::LoopingAudioStream(audioStream, (loop) ? 0 : 1));
|
||||
}
|
||||
|
||||
void Music::stopSoundEffect() {
|
||||
if (isSoundEffectActive())
|
||||
_vm->_mixer->stopHandle(_sfxHandle);
|
||||
}
|
||||
|
||||
bool Music::isSoundEffectActive() const {
|
||||
return _vm->_mixer->isSoundHandleActive(_sfxHandle);
|
||||
}
|
||||
|
||||
void Music::changeMusic(const Common::String &filename, bool storeCurPos, bool seektoStoredPos) {
|
||||
if (storeCurPos)
|
||||
_storedPos = _musicFile->pos();
|
||||
|
||||
stopSoundEffect();
|
||||
freeMusic();
|
||||
_musicFile = _vm->_resource->openDataFile(filename);
|
||||
if (seektoStoredPos)
|
||||
_musicFile->seek(_storedPos);
|
||||
|
||||
Audio::SeekableAudioStream *audioStream = Audio::makeRawStream(_musicFile, 15000, getSoundFlags());
|
||||
_vm->_mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, new Audio::LoopingAudioStream(audioStream, 0, DisposeAfterUse::YES, false));
|
||||
}
|
||||
|
||||
void Music::resetMusic(bool seektoStoredPos) {
|
||||
if (_vm->getPlatform() != Common::kPlatformAmiga)
|
||||
changeMusic("Music:BackGrou", false, seektoStoredPos);
|
||||
else
|
||||
changeMusic("Music:BackGround", false, seektoStoredPos);
|
||||
}
|
||||
|
||||
void Music::checkRoomMusic(uint16 prevRoom, uint16 newRoom) {
|
||||
if (newRoom == CLOWNROOM)
|
||||
changeMusic("Music:Laugh", true, false);
|
||||
else if (newRoom == DIMROOM)
|
||||
changeMusic("Music:Rm81", true, false);
|
||||
else if (prevRoom == CLOWNROOM || prevRoom == DIMROOM)
|
||||
resetMusic(true);
|
||||
}
|
||||
|
||||
void Music::freeMusic() {
|
||||
_vm->_mixer->stopHandle(_musicHandle);
|
||||
_vm->_mixer->stopHandle(_sfxHandle);
|
||||
_musicFile = nullptr;
|
||||
}
|
||||
|
||||
} // End of namespace Lab
|
||||
95
engines/lab/music.h
Normal file
95
engines/lab/music.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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LAB_MUSIC_H
|
||||
#define LAB_MUSIC_H
|
||||
|
||||
#include "audio/mixer.h"
|
||||
|
||||
namespace Common {
|
||||
class File;
|
||||
}
|
||||
|
||||
namespace Lab {
|
||||
|
||||
class LabEngine;
|
||||
|
||||
//---------------------------
|
||||
//----- From LabMusic.c -----
|
||||
//---------------------------
|
||||
|
||||
#define MAXBUFFERS 5
|
||||
|
||||
class Music {
|
||||
private:
|
||||
LabEngine *_vm;
|
||||
|
||||
Common::File *_musicFile;
|
||||
uint32 _storedPos;
|
||||
|
||||
Audio::SoundHandle _musicHandle;
|
||||
Audio::SoundHandle _sfxHandle;
|
||||
|
||||
private:
|
||||
byte getSoundFlags();
|
||||
|
||||
public:
|
||||
Music(LabEngine *vm);
|
||||
|
||||
/**
|
||||
* Changes the background music to something else.
|
||||
*/
|
||||
void changeMusic(const Common::String &filename, bool storeCurPos, bool seektoStoredPos);
|
||||
|
||||
void resetMusic(bool seekToStoredPos);
|
||||
|
||||
/**
|
||||
* Checks the music that should be playing in a particular room.
|
||||
*/
|
||||
void checkRoomMusic(uint16 prevRoom, uint16 newRoom);
|
||||
|
||||
/**
|
||||
* Frees up the music buffers and closes the file.
|
||||
*/
|
||||
void freeMusic();
|
||||
|
||||
bool isSoundEffectActive() const;
|
||||
void playSoundEffect(uint16 sampleSpeed, uint32 length, bool loop, Common::File *dataFile);
|
||||
|
||||
/**
|
||||
* Reads in a sound effect file. Ignores any graphics.
|
||||
*/
|
||||
void loadSoundEffect(const Common::String &filename, bool loop, bool waitTillFinished);
|
||||
|
||||
void stopSoundEffect();
|
||||
};
|
||||
|
||||
} // End of namespace Lab
|
||||
|
||||
#endif // LAB_MUSIC_H
|
||||
623
engines/lab/processroom.cpp
Normal file
623
engines/lab/processroom.cpp
Normal file
@@ -0,0 +1,623 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/translation.h"
|
||||
#include "gui/message.h"
|
||||
|
||||
#include "lab/lab.h"
|
||||
|
||||
#include "lab/anim.h"
|
||||
#include "lab/dispman.h"
|
||||
#include "lab/labsets.h"
|
||||
#include "lab/music.h"
|
||||
#include "lab/processroom.h"
|
||||
#include "lab/resource.h"
|
||||
#include "lab/utils.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
#define NOFILE "no file"
|
||||
|
||||
bool LabEngine::checkConditions(const Common::Array<int16> &condition) {
|
||||
for (unsigned int i = 0; i < condition.size(); ++i)
|
||||
if (!_conditions->in(condition[i]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ViewData *LabEngine::getViewData(uint16 roomNum, uint16 direction) {
|
||||
if (_rooms[roomNum]._roomMsg.empty())
|
||||
_resource->readViews(roomNum);
|
||||
|
||||
ViewDataList &views = _rooms[roomNum]._view[direction];
|
||||
|
||||
for (auto &view : views) {
|
||||
if (checkConditions(view._condition))
|
||||
return &view;
|
||||
}
|
||||
|
||||
error("No view with matching condition found");
|
||||
}
|
||||
|
||||
const CloseData *LabEngine::getObject(Common::Point pos, const CloseData *closePtr) {
|
||||
const CloseDataList *list;
|
||||
if (!closePtr)
|
||||
list = &(getViewData(_roomNum, _direction)->_closeUps);
|
||||
else
|
||||
list = &(closePtr->_subCloseUps);
|
||||
|
||||
for (auto &closeData : *list) {
|
||||
Common::Rect objRect = _utils->rectScale(closeData._x1, closeData._y1, closeData._x2, closeData._y2);
|
||||
if (objRect.contains(pos))
|
||||
return &closeData;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const CloseData *LabEngine::findClosePtrMatch(const CloseData *closePtr, const CloseDataList &list) {
|
||||
for (const auto &closeData : list) {
|
||||
if ((closePtr->_x1 == closeData._x1) && (closePtr->_x2 == closeData._x2) &&
|
||||
(closePtr->_y1 == closeData._y1) && (closePtr->_y2 == closeData._y2) &&
|
||||
(closePtr->_depth == closeData._depth))
|
||||
return &closeData;
|
||||
|
||||
const CloseData *resClosePtr = findClosePtrMatch(closePtr, closeData._subCloseUps);
|
||||
|
||||
if (resClosePtr)
|
||||
return resClosePtr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Common::String LabEngine::getPictName(bool useClose) {
|
||||
ViewData *viewPtr = getViewData(_roomNum, _direction);
|
||||
|
||||
if (useClose && _closeDataPtr) {
|
||||
_closeDataPtr = findClosePtrMatch(_closeDataPtr, viewPtr->_closeUps);
|
||||
|
||||
if (_closeDataPtr)
|
||||
return _closeDataPtr->_graphicName;
|
||||
}
|
||||
|
||||
return viewPtr->_graphicName;
|
||||
}
|
||||
|
||||
void LabEngine::drawDirection(const CloseData *closePtr) {
|
||||
if (closePtr && !closePtr->_message.empty()) {
|
||||
_graphics->drawMessage(closePtr->_message, false);
|
||||
return;
|
||||
}
|
||||
|
||||
Common::String message;
|
||||
|
||||
if (!_rooms[_roomNum]._roomMsg.empty())
|
||||
message = _rooms[_roomNum]._roomMsg + ", ";
|
||||
|
||||
if (_direction == kDirectionNorth)
|
||||
message += _resource->getStaticText(kTextFacingNorth);
|
||||
else if (_direction == kDirectionEast)
|
||||
message += _resource->getStaticText(kTextFacingEast);
|
||||
else if (_direction == kDirectionSouth)
|
||||
message += _resource->getStaticText(kTextFacingSouth);
|
||||
else if (_direction == kDirectionWest)
|
||||
message += _resource->getStaticText(kTextFacingWest);
|
||||
|
||||
_graphics->drawMessage(message, false);
|
||||
}
|
||||
|
||||
uint16 LabEngine::processArrow(uint16 curDirection, uint16 arrow) {
|
||||
if (arrow == 1) { // Forward
|
||||
uint16 room = _rooms[_roomNum]._doors[curDirection];
|
||||
if (room != 0) {
|
||||
_music->checkRoomMusic(_roomNum, room);
|
||||
_roomNum = room;
|
||||
}
|
||||
|
||||
return curDirection;
|
||||
} else if (arrow == 0) { // Left
|
||||
if (curDirection == kDirectionNorth)
|
||||
return kDirectionWest;
|
||||
else if (curDirection == kDirectionWest)
|
||||
return kDirectionSouth;
|
||||
else if (curDirection == kDirectionSouth)
|
||||
return kDirectionEast;
|
||||
else
|
||||
return kDirectionNorth;
|
||||
} else if (arrow == 2) { // Right
|
||||
if (curDirection == kDirectionNorth)
|
||||
return kDirectionEast;
|
||||
else if (curDirection == kDirectionEast)
|
||||
return kDirectionSouth;
|
||||
else if (curDirection == kDirectionSouth)
|
||||
return kDirectionWest;
|
||||
else
|
||||
return kDirectionNorth;
|
||||
}
|
||||
|
||||
// Should never reach here!
|
||||
return curDirection;
|
||||
}
|
||||
|
||||
void LabEngine::setCurrentClose(Common::Point pos, const CloseData **closePtrList, bool useAbsoluteCoords, bool next) {
|
||||
const CloseDataList *list;
|
||||
|
||||
if (!*closePtrList)
|
||||
list = &(getViewData(_roomNum, _direction)->_closeUps);
|
||||
else
|
||||
list = &((*closePtrList)->_subCloseUps);
|
||||
|
||||
CloseDataList::const_iterator closePtr;
|
||||
for (closePtr = list->begin(); closePtr != list->end(); ++closePtr) {
|
||||
Common::Rect target;
|
||||
if (!useAbsoluteCoords)
|
||||
target = Common::Rect(closePtr->_x1, closePtr->_y1, closePtr->_x2, closePtr->_y2);
|
||||
else
|
||||
target = _utils->rectScale(closePtr->_x1, closePtr->_y1, closePtr->_x2, closePtr->_y2);
|
||||
|
||||
if (target.contains(pos) && (next || !closePtr->_graphicName.empty())) {
|
||||
|
||||
if (next) {
|
||||
// cycle to the next one
|
||||
++closePtr;
|
||||
if (closePtr == list->end())
|
||||
closePtr = list->begin();
|
||||
}
|
||||
*closePtrList = &(*closePtr);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If we got here, no match was found. If we want the "next" close-up,
|
||||
// return the first one in the list, if any.
|
||||
if (next) {
|
||||
if (!list->empty())
|
||||
*closePtrList = &(*list->begin());
|
||||
}
|
||||
}
|
||||
|
||||
bool LabEngine::takeItem(Common::Point pos) {
|
||||
const CloseDataList *list;
|
||||
if (!_closeDataPtr) {
|
||||
list = &(getViewData(_roomNum, _direction)->_closeUps);
|
||||
} else if (_closeDataPtr->_closeUpType < 0) {
|
||||
_conditions->inclElement(abs(_closeDataPtr->_closeUpType));
|
||||
return true;
|
||||
} else
|
||||
list = &(_closeDataPtr->_subCloseUps);
|
||||
|
||||
for (auto &closeData : *list) {
|
||||
Common::Rect objRect = _utils->rectScale(closeData._x1, closeData._y1, closeData._x2, closeData._y2);
|
||||
if (objRect.contains(pos) && (closeData._closeUpType < 0)) {
|
||||
_conditions->inclElement(abs(closeData._closeUpType));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LabEngine::doActions(const ActionList &actionList) {
|
||||
for (const auto &action : actionList) {
|
||||
updateEvents();
|
||||
if (_quitLab || shouldQuit())
|
||||
return;
|
||||
|
||||
switch (action._actionType) {
|
||||
case kActionPlaySound:
|
||||
_music->loadSoundEffect(action._messages[0], false, true);
|
||||
break;
|
||||
|
||||
case kActionPlaySoundNoWait: // only used in scene 7 (street, when teleporting to the surreal maze)
|
||||
_music->loadSoundEffect(action._messages[0], false, false);
|
||||
break;
|
||||
|
||||
case kActionPlaySoundLooping:
|
||||
_music->loadSoundEffect(action._messages[0], true, false);
|
||||
break;
|
||||
|
||||
case kActionShowDiff:
|
||||
_graphics->readPict(action._messages[0], true);
|
||||
break;
|
||||
|
||||
case kActionShowDiffLooping: // used in scene 44 (heart of the labyrinth, minotaur)
|
||||
_graphics->readPict(action._messages[0], false);
|
||||
break;
|
||||
|
||||
case kActionLoadDiff:
|
||||
if (!action._messages[0].empty())
|
||||
// Puts a file into memory
|
||||
_graphics->loadPict(action._messages[0]);
|
||||
break;
|
||||
|
||||
case kActionLoadBitmap:
|
||||
error("Unused opcode kActionLoadBitmap has been called");
|
||||
|
||||
case kActionShowBitmap:
|
||||
error("Unused opcode kActionShowBitmap has been called");
|
||||
|
||||
case kActionTransition:
|
||||
_graphics->doTransition((TransitionType)action._param1, action._messages[0].c_str());
|
||||
break;
|
||||
|
||||
case kActionNoUpdate:
|
||||
_noUpdateDiff = true;
|
||||
_anim->_doBlack = false;
|
||||
break;
|
||||
|
||||
case kActionForceUpdate:
|
||||
_curFileName = " ";
|
||||
break;
|
||||
|
||||
case kActionShowCurPict: {
|
||||
Common::String test = getPictName(true);
|
||||
|
||||
if (test != _curFileName) {
|
||||
_curFileName = test;
|
||||
_graphics->readPict(_curFileName);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case kActionSetElement:
|
||||
_conditions->inclElement(action._param1);
|
||||
break;
|
||||
|
||||
case kActionUnsetElement:
|
||||
_conditions->exclElement(action._param1);
|
||||
break;
|
||||
|
||||
case kActionShowMessage:
|
||||
if (_graphics->_longWinInFront)
|
||||
_graphics->longDrawMessage(action._messages[0], true);
|
||||
else
|
||||
_graphics->drawMessage(action._messages[0], true);
|
||||
break;
|
||||
|
||||
case kActionCShowMessage:
|
||||
if (!_closeDataPtr)
|
||||
_graphics->drawMessage(action._messages[0], true);
|
||||
break;
|
||||
|
||||
case kActionShowMessages:
|
||||
_graphics->drawMessage(action._messages[_utils->getRandom(action._param1)], true);
|
||||
break;
|
||||
|
||||
case kActionChangeRoom:
|
||||
if (action._param1 & 0x8000) {
|
||||
// This is a Wyrmkeep Windows trial version, thus stop at this
|
||||
// point, since we can't check for game payment status
|
||||
_graphics->readPict(getPictName(true));
|
||||
GUI::MessageDialog trialMessage(_("This is the end of the trial version. You can play the full game using the original interpreter from Wyrmkeep"));
|
||||
trialMessage.runModal();
|
||||
break;
|
||||
}
|
||||
|
||||
_music->checkRoomMusic(_roomNum, action._param1);
|
||||
_roomNum = action._param1;
|
||||
_direction = action._param2 - 1;
|
||||
_closeDataPtr = nullptr;
|
||||
_anim->_doBlack = true;
|
||||
break;
|
||||
|
||||
case kActionSetCloseup: {
|
||||
Common::Point curPos = Common::Point(_utils->scaleX(action._param1), _utils->scaleY(action._param2));
|
||||
const CloseData *tmpClosePtr = getObject(curPos, _closeDataPtr);
|
||||
|
||||
if (tmpClosePtr)
|
||||
_closeDataPtr = tmpClosePtr;
|
||||
}
|
||||
break;
|
||||
|
||||
case kActionMainView:
|
||||
_closeDataPtr = nullptr;
|
||||
break;
|
||||
|
||||
case kActionSubInv:
|
||||
if (_inventory[action._param1]._quantity)
|
||||
(_inventory[action._param1]._quantity)--;
|
||||
|
||||
if (_inventory[action._param1]._quantity == 0)
|
||||
_conditions->exclElement(action._param1);
|
||||
|
||||
break;
|
||||
|
||||
case kActionAddInv:
|
||||
(_inventory[action._param1]._quantity) += action._param2;
|
||||
_conditions->inclElement(action._param1);
|
||||
break;
|
||||
|
||||
case kActionShowDir:
|
||||
_graphics->setActionMessage(false);
|
||||
break;
|
||||
|
||||
case kActionWaitSecs: {
|
||||
uint32 targetMillis = _system->getMillis() + action._param1 * 1000;
|
||||
|
||||
_graphics->screenUpdate();
|
||||
|
||||
while (_system->getMillis() < targetMillis) {
|
||||
updateEvents();
|
||||
if (_quitLab || shouldQuit())
|
||||
return;
|
||||
_anim->diffNextFrame();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case kActionStopMusic: // used in scene 44 (heart of the labyrinth, minotaur)
|
||||
_music->freeMusic();
|
||||
break;
|
||||
|
||||
case kActionStartMusic: // unused
|
||||
error("Unused opcode kActionStartMusic has been called");
|
||||
break;
|
||||
|
||||
case kActionChangeMusic: // used in scene 46 (museum exhibit, for the alarm)
|
||||
_music->changeMusic(action._messages[0], true, false);
|
||||
break;
|
||||
|
||||
case kActionResetMusic: // used in scene 45 (sheriff's office, after museum)
|
||||
_music->resetMusic(true);
|
||||
break;
|
||||
|
||||
case kActionFillMusic:
|
||||
error("Unused opcode kActionFillMusic has been called");
|
||||
break;
|
||||
|
||||
case kActionWaitSound: // used in scene 44 (heart of the labyrinth / ending)
|
||||
while (_music->isSoundEffectActive()) {
|
||||
updateEvents();
|
||||
if (_quitLab || shouldQuit())
|
||||
return;
|
||||
_anim->diffNextFrame();
|
||||
waitTOF();
|
||||
}
|
||||
break;
|
||||
|
||||
case kActionClearSound:
|
||||
_music->stopSoundEffect();
|
||||
break;
|
||||
|
||||
case kActionWinMusic: // used in scene 44 (heart of the labyrinth / ending)
|
||||
_music->freeMusic();
|
||||
_music->changeMusic("Music:WinGame", false, false);
|
||||
break;
|
||||
|
||||
case kActionWinGame: // used in scene 44 (heart of the labyrinth / ending)
|
||||
_quitLab = true;
|
||||
showLab2Teaser();
|
||||
break;
|
||||
|
||||
case kActionLostGame:
|
||||
error("Unused opcode kActionLostGame has been called");
|
||||
|
||||
case kActionResetBuffer:
|
||||
_graphics->freePict();
|
||||
break;
|
||||
|
||||
case kActionSpecialCmd:
|
||||
if (action._param1 == 0)
|
||||
_anim->_doBlack = true;
|
||||
else if (action._param1 == 1)
|
||||
_anim->_doBlack = (_closeDataPtr == nullptr);
|
||||
else if (action._param1 == 2)
|
||||
_anim->_doBlack = (_closeDataPtr != nullptr);
|
||||
else if (action._param1 == 5) {
|
||||
// inverse the palette
|
||||
for (int idx = (8 * 3); idx < (255 * 3); idx++)
|
||||
_anim->_diffPalette[idx] = 255 - _anim->_diffPalette[idx];
|
||||
|
||||
waitTOF();
|
||||
_graphics->setPalette(_anim->_diffPalette, 256);
|
||||
waitTOF();
|
||||
waitTOF();
|
||||
} else if (action._param1 == 4) {
|
||||
// white the palette
|
||||
_graphics->whiteScreen();
|
||||
waitTOF();
|
||||
waitTOF();
|
||||
} else if (action._param1 == 6) {
|
||||
// Restore the palette
|
||||
waitTOF();
|
||||
_graphics->setPalette(_anim->_diffPalette, 256);
|
||||
waitTOF();
|
||||
waitTOF();
|
||||
} else if (action._param1 == 7) {
|
||||
// Quick pause
|
||||
waitTOF();
|
||||
waitTOF();
|
||||
waitTOF();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_music->stopSoundEffect();
|
||||
}
|
||||
|
||||
bool LabEngine::doActionRuleSub(int16 action, int16 roomNum, const CloseData *closePtr, bool allowDefaults) {
|
||||
action++;
|
||||
|
||||
if (closePtr) {
|
||||
RuleList *rules = &(_rooms[_roomNum]._rules);
|
||||
|
||||
if (rules->empty() && (roomNum == 0)) {
|
||||
_resource->readViews(roomNum);
|
||||
rules = &(_rooms[roomNum]._rules);
|
||||
}
|
||||
|
||||
for (auto &rule : *rules) {
|
||||
if ((rule._ruleType == kRuleTypeAction) &&
|
||||
((rule._param1 == action) || ((rule._param1 == 0) && allowDefaults))) {
|
||||
if (((rule._param2 == closePtr->_closeUpType) ||
|
||||
((rule._param2 == 0) && allowDefaults)) ||
|
||||
((action == 1) && (rule._param2 == -closePtr->_closeUpType))) {
|
||||
if (checkConditions(rule._condition)) {
|
||||
doActions(rule._actionList);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LabEngine::doActionRule(Common::Point pos, int16 action, int16 roomNum) {
|
||||
if (roomNum)
|
||||
_newFileName = NOFILE;
|
||||
else
|
||||
_newFileName = _curFileName;
|
||||
|
||||
const CloseData *curClosePtr = getObject(pos, _closeDataPtr);
|
||||
|
||||
if (doActionRuleSub(action, roomNum, curClosePtr, false))
|
||||
return true;
|
||||
else if (doActionRuleSub(action, roomNum, _closeDataPtr, false))
|
||||
return true;
|
||||
else if (doActionRuleSub(action, roomNum, curClosePtr, true))
|
||||
return true;
|
||||
else if (doActionRuleSub(action, roomNum, _closeDataPtr, true))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LabEngine::doOperateRuleSub(int16 itemNum, int16 roomNum, const CloseData *closePtr, bool allowDefaults) {
|
||||
if (closePtr)
|
||||
if (closePtr->_closeUpType > 0) {
|
||||
RuleList *rules = &(_rooms[roomNum]._rules);
|
||||
|
||||
if (rules->empty() && (roomNum == 0)) {
|
||||
_resource->readViews(roomNum);
|
||||
rules = &(_rooms[roomNum]._rules);
|
||||
}
|
||||
|
||||
for (auto &rule : *rules) {
|
||||
if ((rule._ruleType == kRuleTypeOperate) &&
|
||||
((rule._param1 == itemNum) || ((rule._param1 == 0) && allowDefaults)) &&
|
||||
((rule._param2 == closePtr->_closeUpType) || ((rule._param2 == 0) && allowDefaults))) {
|
||||
if (checkConditions(rule._condition)) {
|
||||
doActions(rule._actionList);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LabEngine::doOperateRule(Common::Point pos, int16 ItemNum) {
|
||||
_newFileName = NOFILE;
|
||||
const CloseData *closePtr = getObject(pos, _closeDataPtr);
|
||||
|
||||
if (doOperateRuleSub(ItemNum, _roomNum, closePtr, false))
|
||||
return true;
|
||||
else if (doOperateRuleSub(ItemNum, _roomNum, _closeDataPtr, false))
|
||||
return true;
|
||||
else if (doOperateRuleSub(ItemNum, _roomNum, closePtr, true))
|
||||
return true;
|
||||
else if (doOperateRuleSub(ItemNum, _roomNum, _closeDataPtr, true))
|
||||
return true;
|
||||
else {
|
||||
_newFileName = _curFileName;
|
||||
|
||||
if (doOperateRuleSub(ItemNum, 0, closePtr, false))
|
||||
return true;
|
||||
else if (doOperateRuleSub(ItemNum, 0, _closeDataPtr, false))
|
||||
return true;
|
||||
else if (doOperateRuleSub(ItemNum, 0, closePtr, true))
|
||||
return true;
|
||||
else if (doOperateRuleSub(ItemNum, 0, _closeDataPtr, true))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LabEngine::doGoForward() {
|
||||
RuleList &rules = _rooms[_roomNum]._rules;
|
||||
|
||||
for (auto &rule : rules) {
|
||||
if ((rule._ruleType == kRuleTypeGoForward) && (rule._param1 == (_direction + 1))) {
|
||||
if (checkConditions(rule._condition)) {
|
||||
doActions(rule._actionList);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LabEngine::doTurn(uint16 from, uint16 to) {
|
||||
from++;
|
||||
to++;
|
||||
|
||||
RuleList &rules = _rooms[_roomNum]._rules;
|
||||
|
||||
for (auto &rule : rules) {
|
||||
if ((rule._ruleType == kRuleTypeTurn) ||
|
||||
((rule._ruleType == kRuleTypeTurnFromTo) &&
|
||||
(rule._param1 == from) && (rule._param2 == to))) {
|
||||
if (checkConditions(rule._condition)) {
|
||||
doActions(rule._actionList);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LabEngine::doMainView() {
|
||||
RuleList &rules = _rooms[_roomNum]._rules;
|
||||
for (auto &rule : rules) {
|
||||
if (rule._ruleType == kRuleTypeGoMainView) {
|
||||
if (checkConditions(rule._condition)) {
|
||||
doActions(rule._actionList);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Lab
|
||||
189
engines/lab/processroom.h
Normal file
189
engines/lab/processroom.h
Normal file
@@ -0,0 +1,189 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LAB_PROCESSROOM_H
|
||||
#define LAB_PROCESSROOM_H
|
||||
|
||||
namespace Lab {
|
||||
|
||||
enum ActionType {
|
||||
kActionPlaySound = 1,
|
||||
kActionPlaySoundLooping = 2,
|
||||
kActionShowDiff = 3,
|
||||
kActionShowDiffLooping = 4,
|
||||
kActionLoadDiff = 5,
|
||||
kActionLoadBitmap = 6, // unused
|
||||
kActionShowBitmap = 7, // unused
|
||||
kActionTransition = 8,
|
||||
kActionNoUpdate = 9,
|
||||
kActionForceUpdate = 10,
|
||||
kActionShowCurPict = 11,
|
||||
kActionSetElement = 12,
|
||||
kActionUnsetElement = 13,
|
||||
kActionShowMessage = 14,
|
||||
kActionShowMessages = 15,
|
||||
kActionChangeRoom = 16,
|
||||
kActionSetCloseup = 17,
|
||||
kActionMainView = 18,
|
||||
kActionSubInv = 19,
|
||||
kActionAddInv = 20,
|
||||
kActionShowDir = 21,
|
||||
kActionWaitSecs = 22,
|
||||
kActionStopMusic = 23,
|
||||
kActionStartMusic = 24,
|
||||
kActionChangeMusic = 25,
|
||||
kActionResetMusic = 26,
|
||||
kActionFillMusic = 27,
|
||||
kActionWaitSound = 28,
|
||||
kActionClearSound = 29,
|
||||
kActionWinMusic = 30,
|
||||
kActionWinGame = 31,
|
||||
kActionLostGame = 32, // unused
|
||||
kActionResetBuffer = 33,
|
||||
kActionSpecialCmd = 34,
|
||||
kActionCShowMessage = 35,
|
||||
kActionPlaySoundNoWait = 36
|
||||
};
|
||||
|
||||
enum RuleType {
|
||||
kRuleTypeNone = 0,
|
||||
kRuleTypeAction = 1,
|
||||
kRuleTypeOperate = 2,
|
||||
kRuleTypeGoForward = 3,
|
||||
kRuleTypeConditions = 4, // unused?
|
||||
kRuleTypeTurn = 5,
|
||||
kRuleTypeGoMainView = 6,
|
||||
kRuleTypeTurnFromTo = 7
|
||||
};
|
||||
|
||||
enum RuleAction {
|
||||
kRuleActionTake = 0,
|
||||
kRuleActionMove = 1, // unused?
|
||||
kRuleActionOpenDoor = 2, // unused?
|
||||
kRuleActionCloseDoor = 3, // unused?
|
||||
kRuleActionTakeDef = 4
|
||||
};
|
||||
|
||||
enum Condition {
|
||||
kCondBeltGlowing = 70,
|
||||
kCondBridge1 = 104,
|
||||
kCondNoNews = 135,
|
||||
kCondBridge0 = 148,
|
||||
kCondLampOn = 151,
|
||||
kCondNoClean = 152,
|
||||
kCondDirty = 175,
|
||||
kCondUsedHelmet = 184
|
||||
};
|
||||
|
||||
enum MapDoors {
|
||||
kDoorLeftNorth = 1,
|
||||
kDoorLeftEast = 2,
|
||||
kDoorLeftSouth = 4,
|
||||
kDoorLeftWest = 8,
|
||||
|
||||
kDoorMiddleNorth = 16,
|
||||
kDoorRightNorth = 32,
|
||||
kDoorMiddleSouth = 64,
|
||||
kDoorRightSouth = 128,
|
||||
|
||||
kDoorMiddleEast = 16,
|
||||
kDoorBottomEast = 32,
|
||||
kDoorMiddleWest = 64,
|
||||
kDoorBottomWest = 128
|
||||
};
|
||||
|
||||
enum SpecialRoom {
|
||||
kNormalRoom = 0,
|
||||
kUpArrowRoom,
|
||||
kDownArrowRoom,
|
||||
kBridgeRoom,
|
||||
kVerticalCorridor,
|
||||
kHorizontalCorridor,
|
||||
kMedMaze,
|
||||
kHedgeMaze,
|
||||
kSurMaze,
|
||||
kMultiMazeF1,
|
||||
kMultiMazeF2,
|
||||
kMultiMazeF3
|
||||
};
|
||||
|
||||
struct CloseData {
|
||||
uint16 _x1, _y1, _x2, _y2;
|
||||
int16 _closeUpType; // if > 0, an object. If < 0, an item
|
||||
uint16 _depth; // Level of the closeup.
|
||||
Common::String _graphicName;
|
||||
Common::String _message;
|
||||
CloseDataList _subCloseUps;
|
||||
};
|
||||
|
||||
struct ViewData {
|
||||
Common::Array<int16> _condition;
|
||||
Common::String _graphicName;
|
||||
CloseDataList _closeUps;
|
||||
};
|
||||
|
||||
struct Action {
|
||||
ActionType _actionType;
|
||||
int16 _param1;
|
||||
int16 _param2;
|
||||
int16 _param3;
|
||||
Common::Array<Common::String> _messages;
|
||||
};
|
||||
|
||||
struct Rule {
|
||||
RuleType _ruleType;
|
||||
int16 _param1;
|
||||
int16 _param2;
|
||||
Common::Array<int16> _condition;
|
||||
ActionList _actionList;
|
||||
};
|
||||
|
||||
struct RoomData {
|
||||
uint16 _doors[4];
|
||||
byte _transitionType;
|
||||
ViewDataList _view[4];
|
||||
RuleList _rules;
|
||||
Common::String _roomMsg;
|
||||
};
|
||||
|
||||
struct InventoryData {
|
||||
uint16 _quantity;
|
||||
Common::String _name;
|
||||
Common::String _bitmapName;
|
||||
};
|
||||
|
||||
struct MapData {
|
||||
uint16 _x, _y, _pageNumber;
|
||||
SpecialRoom _specialID;
|
||||
uint32 _mapFlags;
|
||||
};
|
||||
|
||||
} // End of namespace Lab
|
||||
|
||||
#endif // LAB_PROCESSROOM_H
|
||||
343
engines/lab/resource.cpp
Normal file
343
engines/lab/resource.cpp
Normal file
@@ -0,0 +1,343 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/file.h"
|
||||
|
||||
#include "lab/lab.h"
|
||||
|
||||
#include "lab/dispman.h"
|
||||
#include "lab/music.h"
|
||||
#include "lab/processroom.h"
|
||||
#include "lab/resource.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
Resource::Resource(LabEngine *vm) : _vm(vm) {
|
||||
readStaticText();
|
||||
}
|
||||
|
||||
void Resource::readStaticText() {
|
||||
Common::File *labTextFile = openDataFile("Lab:Rooms/LabText");
|
||||
|
||||
for (int i = 0; i < 48; i++)
|
||||
_staticText[i] = labTextFile->readLine();
|
||||
|
||||
delete labTextFile;
|
||||
}
|
||||
|
||||
TextFont *Resource::getFont(const Common::String &fileName) {
|
||||
// TODO: Add support for the font format of the Amiga version
|
||||
Common::File *dataFile = openDataFile(fileName, MKTAG('V', 'G', 'A', 'F'));
|
||||
|
||||
uint32 headerSize = 4 + 2 + 256 * 3 + 4;
|
||||
uint32 fileSize = dataFile->size();
|
||||
if (fileSize <= headerSize)
|
||||
return nullptr;
|
||||
|
||||
TextFont *textfont = new TextFont();
|
||||
textfont->_dataLength = fileSize - headerSize;
|
||||
textfont->_height = dataFile->readUint16LE();
|
||||
dataFile->read(textfont->_widths, 256);
|
||||
for (int i = 0; i < 256; i++)
|
||||
textfont->_offsets[i] = dataFile->readUint16LE();
|
||||
dataFile->skip(4);
|
||||
textfont->_data = new byte[textfont->_dataLength + 4];
|
||||
dataFile->read(textfont->_data, textfont->_dataLength);
|
||||
delete dataFile;
|
||||
return textfont;
|
||||
}
|
||||
|
||||
Common::String Resource::getText(const Common::String &fileName) {
|
||||
Common::File *dataFile = openDataFile(fileName);
|
||||
|
||||
uint32 count = dataFile->size();
|
||||
byte *buffer = new byte[count];
|
||||
byte *text = buffer;
|
||||
dataFile->read(buffer, count);
|
||||
|
||||
while (text && (*text != '\0'))
|
||||
*text++ -= (byte)95;
|
||||
|
||||
delete dataFile;
|
||||
|
||||
Common::String str = (char *)buffer;
|
||||
delete[] buffer;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void Resource::readRoomData(const Common::String &fileName) {
|
||||
Common::File *dataFile = openDataFile(fileName, MKTAG('D', 'O', 'R', '1'));
|
||||
|
||||
_vm->_manyRooms = dataFile->readUint16LE();
|
||||
_vm->_highestCondition = dataFile->readUint16LE();
|
||||
_vm->_rooms = new RoomData[_vm->_manyRooms + 1];
|
||||
|
||||
for (int i = 1; i <= _vm->_manyRooms; i++) {
|
||||
RoomData *curRoom = &_vm->_rooms[i];
|
||||
curRoom->_doors[kDirectionNorth] = dataFile->readUint16LE();
|
||||
curRoom->_doors[kDirectionSouth] = dataFile->readUint16LE();
|
||||
curRoom->_doors[kDirectionEast] = dataFile->readUint16LE();
|
||||
curRoom->_doors[kDirectionWest] = dataFile->readUint16LE();
|
||||
curRoom->_transitionType = dataFile->readByte();
|
||||
}
|
||||
|
||||
delete dataFile;
|
||||
}
|
||||
|
||||
InventoryData *Resource::readInventory(const Common::String &fileName) {
|
||||
Common::File *dataFile = openDataFile(fileName, MKTAG('I', 'N', 'V', '1'));
|
||||
|
||||
_vm->_numInv = dataFile->readUint16LE();
|
||||
InventoryData *inventory = new InventoryData[_vm->_numInv + 1];
|
||||
|
||||
for (int i = 1; i <= _vm->_numInv; i++) {
|
||||
inventory[i]._quantity = dataFile->readUint16LE();
|
||||
inventory[i]._name = readString(dataFile);
|
||||
inventory[i]._bitmapName = readString(dataFile);
|
||||
}
|
||||
|
||||
delete dataFile;
|
||||
return inventory;
|
||||
}
|
||||
|
||||
void Resource::readViews(uint16 roomNum) {
|
||||
Common::String fileName = "LAB:Rooms/" + Common::String::format("%d", roomNum);
|
||||
Common::File *dataFile = openDataFile(fileName, MKTAG('R', 'O', 'M', '4'));
|
||||
|
||||
RoomData *curRoom = &_vm->_rooms[roomNum];
|
||||
|
||||
curRoom->_roomMsg = readString(dataFile);
|
||||
readView(dataFile, curRoom->_view[kDirectionNorth]);
|
||||
readView(dataFile, curRoom->_view[kDirectionSouth]);
|
||||
readView(dataFile, curRoom->_view[kDirectionEast]);
|
||||
readView(dataFile, curRoom->_view[kDirectionWest]);
|
||||
readRule(dataFile, curRoom->_rules);
|
||||
|
||||
delete dataFile;
|
||||
}
|
||||
|
||||
Common::Path Resource::translateFileName(const Common::String &filename) {
|
||||
Common::String upperFilename;
|
||||
|
||||
// The DOS and Windows version aren't looking for the right file,
|
||||
if (!filename.compareToIgnoreCase("P:ZigInt/BLK") && (_vm->getPlatform() != Common::kPlatformAmiga))
|
||||
upperFilename = "P:ZigInt/ZIGINT.BLK";
|
||||
else
|
||||
upperFilename = filename;
|
||||
|
||||
upperFilename.toUppercase();
|
||||
Common::String fileNameStrFinal;
|
||||
|
||||
if (upperFilename.hasPrefix("P:") || upperFilename.hasPrefix("F:")) {
|
||||
if (_vm->_isHiRes)
|
||||
fileNameStrFinal = "SPICT/";
|
||||
else
|
||||
fileNameStrFinal = "PICT/";
|
||||
|
||||
if (_vm->getPlatform() == Common::kPlatformAmiga) {
|
||||
if (upperFilename.hasPrefix("P:")) {
|
||||
fileNameStrFinal = "PICT/";
|
||||
} else {
|
||||
fileNameStrFinal = "LABFONTS/";
|
||||
upperFilename += "T"; // all the Amiga fonts have a ".FONT" suffix
|
||||
}
|
||||
}
|
||||
} else if (upperFilename.hasPrefix("LAB:")) {
|
||||
// Look inside the game folder
|
||||
} else if (upperFilename.hasPrefix("MUSIC:")) {
|
||||
fileNameStrFinal = "MUSIC/";
|
||||
}
|
||||
|
||||
if (upperFilename.contains(':')) {
|
||||
while (upperFilename[0] != ':') {
|
||||
upperFilename.deleteChar(0);
|
||||
}
|
||||
|
||||
upperFilename.deleteChar(0);
|
||||
}
|
||||
|
||||
if (_vm->getPlatform() == Common::kPlatformDOS) {
|
||||
// Some script of the DOS version uses names used in the Amiga (and Windows) version,
|
||||
// which isn't limited to 8.3 characters. We need to parse upperFilename to detect
|
||||
// the filename, and fix it if required so it matches a DOS filename.
|
||||
while (upperFilename.contains('/') && upperFilename.size()) {
|
||||
fileNameStrFinal += upperFilename[0];
|
||||
upperFilename.deleteChar(0);
|
||||
}
|
||||
|
||||
for (int i = 0; (i < 8) && upperFilename.size() && (upperFilename[0] != '.'); i++) {
|
||||
fileNameStrFinal += upperFilename[0];
|
||||
upperFilename.deleteChar(0);
|
||||
}
|
||||
|
||||
// Remove the extra character in the filename
|
||||
while (upperFilename.size() && (upperFilename[0] != '.'))
|
||||
upperFilename.deleteChar(0);
|
||||
|
||||
// copy max 4 characters for the extension ('.foo')
|
||||
for (int i = 0; (i < 4) && upperFilename.size(); i++) {
|
||||
fileNameStrFinal += upperFilename[0];
|
||||
upperFilename.deleteChar(0);
|
||||
}
|
||||
|
||||
// Skip the extra characters of the extension
|
||||
upperFilename.clear();
|
||||
}
|
||||
|
||||
fileNameStrFinal += upperFilename;
|
||||
|
||||
return Common::Path(fileNameStrFinal);
|
||||
}
|
||||
|
||||
Common::File *Resource::openDataFile(const Common::String &filename, uint32 fileHeader) {
|
||||
Common::File *dataFile = new Common::File();
|
||||
dataFile->open(translateFileName(filename));
|
||||
|
||||
if (!dataFile->isOpen()) {
|
||||
// The DOS version is known to have some missing files
|
||||
if (_vm->getPlatform() == Common::kPlatformDOS) {
|
||||
warning("Incomplete DOS version, skipping file %s", filename.c_str());
|
||||
delete dataFile;
|
||||
return nullptr;
|
||||
} else
|
||||
error("openDataFile: Couldn't open %s (%s)", translateFileName(filename).toString().c_str(), filename.c_str());
|
||||
}
|
||||
if (fileHeader > 0) {
|
||||
uint32 headerTag = dataFile->readUint32BE();
|
||||
if (headerTag != fileHeader) {
|
||||
dataFile->close();
|
||||
error("openDataFile: Unexpected header in %s (%s) - expected: %d, got: %d", translateFileName(filename).toString().c_str(), filename.c_str(), fileHeader, headerTag);
|
||||
}
|
||||
}
|
||||
|
||||
return dataFile;
|
||||
}
|
||||
|
||||
Common::String Resource::readString(Common::File *file) {
|
||||
byte size = file->readByte();
|
||||
if (!size)
|
||||
return Common::String("");
|
||||
|
||||
char *str = new char[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
char c = file->readByte();
|
||||
// Decrypt char
|
||||
c = (i < size - 1) ? c - 95 : '\0';
|
||||
str[i] = c;
|
||||
}
|
||||
|
||||
Common::String result = str;
|
||||
delete[] str;
|
||||
return result;
|
||||
}
|
||||
|
||||
Common::Array<int16> Resource::readConditions(Common::File *file) {
|
||||
int16 cond;
|
||||
Common::Array<int16> list;
|
||||
|
||||
while ((cond = file->readUint16LE()) != 0)
|
||||
list.push_back(cond);
|
||||
|
||||
if (list.size() > 24) {
|
||||
// The original only allocated 24 elements, and silently
|
||||
// dropped remaining parts.
|
||||
warning("More than 24 parts in condition");
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void Resource::readRule(Common::File *file, RuleList &rules) {
|
||||
rules.clear();
|
||||
while (file->readByte() == 1) {
|
||||
rules.push_back(Rule());
|
||||
Rule &rule = rules.back();
|
||||
|
||||
rule._ruleType = (RuleType)file->readSint16LE();
|
||||
rule._param1 = file->readSint16LE();
|
||||
rule._param2 = file->readSint16LE();
|
||||
rule._condition = readConditions(file);
|
||||
readAction(file, rule._actionList);
|
||||
}
|
||||
}
|
||||
|
||||
void Resource::readAction(Common::File *file, ActionList &list) {
|
||||
list.clear();
|
||||
|
||||
while (file->readByte() == 1) {
|
||||
list.push_back(Action());
|
||||
Action &action = list.back();
|
||||
|
||||
action._actionType = (ActionType)file->readSint16LE();
|
||||
action._param1 = file->readSint16LE();
|
||||
action._param2 = file->readSint16LE();
|
||||
action._param3 = file->readSint16LE();
|
||||
|
||||
if (action._actionType == kActionShowMessages) {
|
||||
action._messages.reserve(action._param1);
|
||||
for (int i = 0; i < action._param1; i++)
|
||||
action._messages.push_back(readString(file));
|
||||
} else {
|
||||
action._messages.push_back(readString(file));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Resource::readCloseUps(uint16 depth, Common::File *file, CloseDataList &list) {
|
||||
list.clear();
|
||||
while (file->readByte() != '\0') {
|
||||
list.push_back(CloseData());
|
||||
CloseData &closeup = list.back();
|
||||
|
||||
closeup._x1 = file->readUint16LE();
|
||||
closeup._y1 = file->readUint16LE();
|
||||
closeup._x2 = file->readUint16LE();
|
||||
closeup._y2 = file->readUint16LE();
|
||||
closeup._closeUpType = file->readSint16LE();
|
||||
closeup._depth = depth;
|
||||
closeup._graphicName = readString(file);
|
||||
closeup._message = readString(file);
|
||||
readCloseUps(depth + 1, file, closeup._subCloseUps);
|
||||
}
|
||||
}
|
||||
|
||||
void Resource::readView(Common::File *file, ViewDataList &list) {
|
||||
list.clear();
|
||||
while (file->readByte() == 1) {
|
||||
list.push_back(ViewData());
|
||||
ViewData &view = list.back();
|
||||
|
||||
view._condition = readConditions(file);
|
||||
view._graphicName = readString(file);
|
||||
readCloseUps(0, file, view._closeUps);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Lab
|
||||
123
engines/lab/resource.h
Normal file
123
engines/lab/resource.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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LAB_RESOURCE_H
|
||||
#define LAB_RESOURCE_H
|
||||
|
||||
namespace Lab {
|
||||
|
||||
struct ViewData;
|
||||
|
||||
enum StaticText {
|
||||
kTextLowerFloor,
|
||||
kTextMiddleFloor,
|
||||
kTextUpperFloor,
|
||||
kTextMedMazeFloor,
|
||||
kTextHedgeMazeFloor,
|
||||
kTextSurMazeFloor,
|
||||
kTextCarnivalFloor,
|
||||
|
||||
kTextSurmazeMessage,
|
||||
|
||||
kTextFacingNorth,
|
||||
kTextFacingEast,
|
||||
kTextFacingSouth,
|
||||
kTextFacingWest,
|
||||
|
||||
kTextkLampOn,
|
||||
|
||||
kTextTurnLeft,
|
||||
kTextTurnRight,
|
||||
kTextGoForward,
|
||||
kTextNoPath,
|
||||
kTextTakeItem,
|
||||
kTextSave,
|
||||
kTextLoad,
|
||||
kTextBookmark,
|
||||
kTextPersonal,
|
||||
kTextDisk,
|
||||
kTextSaveBook,
|
||||
kTextRestoreBook,
|
||||
kTextSaveFlash,
|
||||
kTextRestoreFlash,
|
||||
kTextSaveDisk,
|
||||
kTextRestoreDisk,
|
||||
kTextNoDiskInDrive,
|
||||
kTextWriteProtected,
|
||||
kTextSelectDisk,
|
||||
kTextFormatFloppy,
|
||||
kTextFormatting,
|
||||
|
||||
kTextNothing,
|
||||
kTextUseOnWhat,
|
||||
kTextTakeWhat,
|
||||
kTextMoveWhat,
|
||||
kTextOpenWhat,
|
||||
kTextCloseWhat,
|
||||
kTextLookWhat,
|
||||
|
||||
kTextUseMap,
|
||||
kTextUseJournal,
|
||||
kTextTurnkLampOn,
|
||||
kTextTurnLampOff,
|
||||
kTextUseWhiskey,
|
||||
kTextUsePith,
|
||||
kTextUseHelmet
|
||||
};
|
||||
|
||||
class Resource {
|
||||
public:
|
||||
Resource(LabEngine *vm);
|
||||
~Resource() {}
|
||||
|
||||
Common::File *openDataFile(const Common::String &filename, uint32 fileHeader = 0);
|
||||
void readRoomData(const Common::String &fileName);
|
||||
InventoryData *readInventory(const Common::String &fileName);
|
||||
void readViews(uint16 roomNum);
|
||||
TextFont *getFont(const Common::String &fileName);
|
||||
Common::String getText(const Common::String &fileName);
|
||||
Common::String getStaticText(byte index) const { return _staticText[index]; }
|
||||
|
||||
private:
|
||||
LabEngine *_vm;
|
||||
Common::String readString(Common::File *file);
|
||||
Common::Array<int16> readConditions(Common::File *file);
|
||||
void readRule(Common::File *file, RuleList &rules);
|
||||
void readAction(Common::File *file, ActionList &action);
|
||||
void readCloseUps(uint16 depth, Common::File *file, CloseDataList &close);
|
||||
void readView(Common::File *file, ViewDataList &view);
|
||||
void readStaticText();
|
||||
Common::Path translateFileName(const Common::String &filename);
|
||||
|
||||
Common::String _staticText[48];
|
||||
};
|
||||
|
||||
} // End of namespace Lab
|
||||
|
||||
#endif // LAB_RESOURCE_H
|
||||
268
engines/lab/savegame.cpp
Normal file
268
engines/lab/savegame.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/savefile.h"
|
||||
#include "common/translation.h"
|
||||
|
||||
#include "gui/message.h"
|
||||
#include "gui/saveload.h"
|
||||
|
||||
#include "graphics/thumbnail.h"
|
||||
#include "engines/savestate.h"
|
||||
|
||||
#include "lab/lab.h"
|
||||
#include "lab/dispman.h"
|
||||
#include "lab/eventman.h"
|
||||
#include "lab/labsets.h"
|
||||
#include "lab/music.h"
|
||||
#include "lab/processroom.h"
|
||||
#include "lab/speciallocks.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
#define SAVEGAME_ID MKTAG('L', 'O', 'T', 'S')
|
||||
#define SAVEGAME_VERSION 1
|
||||
|
||||
void LabEngine::writeSaveGameHeader(Common::OutSaveFile *out, const Common::String &saveName) {
|
||||
out->writeUint32BE(SAVEGAME_ID);
|
||||
|
||||
// Write version
|
||||
out->writeByte(SAVEGAME_VERSION);
|
||||
|
||||
// Write savegame name
|
||||
out->writeString(saveName);
|
||||
out->writeByte(0);
|
||||
|
||||
// Save the game thumbnail
|
||||
Graphics::saveThumbnail(*out);
|
||||
|
||||
// Creation date/time
|
||||
TimeDate curTime;
|
||||
_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);
|
||||
uint32 playTime = getTotalPlayTime() / 1000;
|
||||
|
||||
out->writeUint32BE(saveDate);
|
||||
out->writeUint16BE(saveTime);
|
||||
out->writeUint32BE(playTime);
|
||||
}
|
||||
|
||||
WARN_UNUSED_RESULT bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header, bool skipThumbnail) {
|
||||
uint32 id = in->readUint32BE();
|
||||
|
||||
// Check if it's a valid ScummVM savegame
|
||||
if (id != SAVEGAME_ID)
|
||||
return false;
|
||||
|
||||
// Read in the version
|
||||
header._version = in->readByte();
|
||||
|
||||
// Check that the save version isn't newer than this binary
|
||||
if (header._version > SAVEGAME_VERSION)
|
||||
return false;
|
||||
|
||||
// Read in the save name
|
||||
Common::String saveName;
|
||||
char ch;
|
||||
while ((ch = (char)in->readByte()) != '\0')
|
||||
saveName += ch;
|
||||
header._descr.setDescription(saveName);
|
||||
|
||||
// Get the thumbnail
|
||||
Graphics::Surface *thumbnail = nullptr;
|
||||
if (!Graphics::loadThumbnail(*in, thumbnail, skipThumbnail)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
header._descr.setThumbnail(thumbnail);
|
||||
|
||||
uint32 saveDate = in->readUint32BE();
|
||||
uint16 saveTime = in->readUint16BE();
|
||||
uint32 playTime = in->readUint32BE();
|
||||
|
||||
int day = (saveDate >> 24) & 0xFF;
|
||||
int month = (saveDate >> 16) & 0xFF;
|
||||
int year = saveDate & 0xFFFF;
|
||||
header._descr.setSaveDate(year, month, day);
|
||||
|
||||
int hour = (saveTime >> 8) & 0xFF;
|
||||
int minutes = saveTime & 0xFF;
|
||||
header._descr.setSaveTime(hour, minutes);
|
||||
|
||||
header._descr.setPlayTime(playTime * 1000);
|
||||
if (g_engine)
|
||||
g_engine->setTotalPlayTime(playTime * 1000);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LabEngine::saveGame(int slot, const Common::String &desc) {
|
||||
Common::String fileName = getSaveStateName(slot);
|
||||
Common::SaveFileManager *saveFileManager = _system->getSavefileManager();
|
||||
Common::OutSaveFile *file = saveFileManager->openForSaving(fileName);
|
||||
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
// Load scene pic
|
||||
_graphics->readPict(getPictName(false));
|
||||
|
||||
|
||||
writeSaveGameHeader(file, desc);
|
||||
file->writeUint16LE(_roomNum);
|
||||
file->writeUint16LE(getDirection());
|
||||
file->writeUint16LE(getQuarters());
|
||||
|
||||
// Conditions
|
||||
for (int i = 0; i < _conditions->_lastElement / (8 * 2); i++)
|
||||
file->writeUint16LE(_conditions->_array[i]);
|
||||
|
||||
// Rooms found
|
||||
for (int i = 0; i < _roomsFound->_lastElement / (8 * 2); i++)
|
||||
file->writeUint16LE(_roomsFound->_array[i]);
|
||||
|
||||
_specialLocks->save(file);
|
||||
|
||||
// Breadcrumbs
|
||||
for (uint i = 0; i < MAX_CRUMBS; i++) {
|
||||
file->writeUint16LE(_breadCrumbs[i]._crumbRoomNum);
|
||||
file->writeUint16LE(_breadCrumbs[i]._crumbDirection);
|
||||
}
|
||||
|
||||
file->flush();
|
||||
file->finalize();
|
||||
delete file;
|
||||
|
||||
_mainDisplay = true;
|
||||
_alternate = false;
|
||||
_event->simulateEvent();
|
||||
_graphics->screenUpdate();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LabEngine::loadGame(int slot) {
|
||||
Common::String fileName = getSaveStateName(slot);
|
||||
Common::SaveFileManager *saveFileManager = _system->getSavefileManager();
|
||||
Common::InSaveFile *file = saveFileManager->openForLoading(fileName);
|
||||
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
SaveGameHeader header;
|
||||
if (!readSaveGameHeader(file, header)) {
|
||||
delete file;
|
||||
return false;
|
||||
}
|
||||
|
||||
_roomNum = file->readUint16LE();
|
||||
_music->checkRoomMusic(1, _roomNum);
|
||||
_direction = file->readUint16LE();
|
||||
setQuarters(file->readUint16LE());
|
||||
|
||||
// Conditions
|
||||
for (int i = 0; i < _conditions->_lastElement / (8 * 2); i++)
|
||||
_conditions->_array[i] = file->readUint16LE();
|
||||
|
||||
// Rooms found
|
||||
for (int i = 0; i < _roomsFound->_lastElement / (8 * 2); i++)
|
||||
_roomsFound->_array[i] = file->readUint16LE();
|
||||
|
||||
_specialLocks->load(file);
|
||||
|
||||
// Breadcrumbs
|
||||
for (int i = 0; i < MAX_CRUMBS; i++) {
|
||||
_breadCrumbs[i]._crumbRoomNum = file->readUint16LE();
|
||||
_breadCrumbs[i]._crumbDirection = file->readUint16LE();
|
||||
}
|
||||
|
||||
_droppingCrumbs = (_breadCrumbs[0]._crumbRoomNum != 0);
|
||||
_followingCrumbs = false;
|
||||
|
||||
for (int i = 0; i < MAX_CRUMBS; i++) {
|
||||
if (_breadCrumbs[i]._crumbRoomNum == 0)
|
||||
break;
|
||||
_numCrumbs = i;
|
||||
}
|
||||
|
||||
delete file;
|
||||
|
||||
_curFileName = " ";
|
||||
_closeDataPtr = nullptr;
|
||||
_followingCrumbs = false;
|
||||
_graphics->_longWinInFront = false;
|
||||
_event->initMouse();
|
||||
|
||||
_mainDisplay = true;
|
||||
_alternate = false;
|
||||
_event->simulateEvent();
|
||||
_graphics->screenUpdate();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LabEngine::saveRestoreGame() {
|
||||
bool isOK = false;
|
||||
|
||||
// The original had one screen for saving/loading. We have two.
|
||||
// Ask the user which screen to use.
|
||||
GUI::MessageDialog saveOrLoad(_("Would you like to save or restore a game?"), _("Save"), _("Restore"));
|
||||
|
||||
int choice = saveOrLoad.runModal();
|
||||
if (choice == GUI::kMessageOK) {
|
||||
// Save
|
||||
GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
|
||||
int slot = dialog->runModalWithCurrentTarget();
|
||||
if (slot >= 0) {
|
||||
Common::String desc = dialog->getResultString();
|
||||
|
||||
if (desc.empty()) {
|
||||
// create our own description for the saved game, the user didn't enter it
|
||||
desc = dialog->createDefaultSaveDescription(slot);
|
||||
}
|
||||
|
||||
isOK = saveGame(slot, desc);
|
||||
}
|
||||
delete dialog;
|
||||
} else {
|
||||
// Restore
|
||||
GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
|
||||
int slot = dialog->runModalWithCurrentTarget();
|
||||
if (slot >= 0) {
|
||||
isOK = loadGame(slot);
|
||||
}
|
||||
delete dialog;
|
||||
}
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
} // End of namespace Lab
|
||||
476
engines/lab/special.cpp
Normal file
476
engines/lab/special.cpp
Normal file
@@ -0,0 +1,476 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/file.h"
|
||||
|
||||
#include "lab/lab.h"
|
||||
|
||||
#include "lab/anim.h"
|
||||
#include "lab/dispman.h"
|
||||
#include "lab/eventman.h"
|
||||
#include "lab/image.h"
|
||||
#include "lab/interface.h"
|
||||
#include "lab/labsets.h"
|
||||
#include "lab/music.h"
|
||||
#include "lab/processroom.h"
|
||||
#include "lab/resource.h"
|
||||
#include "lab/utils.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
void LabEngine::doNotes() {
|
||||
TextFont *noteFont = _resource->getFont("F:Note.fon");
|
||||
Common::String noteText = _resource->getText("Lab:Rooms/Notes");
|
||||
|
||||
Common::Rect textRect = Common::Rect(_utils->vgaScaleX(25) + _utils->svgaCord(15), _utils->vgaScaleY(50), _utils->vgaScaleX(295) - _utils->svgaCord(15), _utils->vgaScaleY(148));
|
||||
_graphics->flowText(noteFont, -2 + _utils->svgaCord(1), 0, 0, false, false, true, true, textRect, noteText.c_str());
|
||||
_graphics->setPalette(_anim->_diffPalette, 256);
|
||||
_graphics->freeFont(¬eFont);
|
||||
}
|
||||
|
||||
void LabEngine::doWestPaper() {
|
||||
TextFont *paperFont = _resource->getFont("F:News22.fon");
|
||||
Common::String paperText = _resource->getText("Lab:Rooms/Date");
|
||||
|
||||
Common::Rect textRect = Common::Rect(_utils->vgaScaleX(57), _utils->vgaScaleY(77) + _utils->svgaCord(2), _utils->vgaScaleX(262), _utils->vgaScaleY(91));
|
||||
_graphics->flowText(paperFont, 0, 0, 0, false, true, false, true, textRect, paperText.c_str());
|
||||
_graphics->freeFont(&paperFont);
|
||||
|
||||
paperFont = _resource->getFont("F:News32.fon");
|
||||
paperText = _resource->getText("Lab:Rooms/Headline");
|
||||
|
||||
int fileLen = paperText.size() - 1;
|
||||
textRect = Common::Rect(_utils->vgaScaleX(57), _utils->vgaScaleY(86) - _utils->svgaCord(2), _utils->vgaScaleX(262), _utils->vgaScaleY(118));
|
||||
int charsPrinted = _graphics->flowText(paperFont, -8, 0, 0, false, true, false, true, textRect, paperText.c_str());
|
||||
|
||||
uint16 y;
|
||||
|
||||
if (charsPrinted < fileLen) {
|
||||
y = 130 - _utils->svgaCord(5);
|
||||
textRect = Common::Rect(_utils->vgaScaleX(57), _utils->vgaScaleY(86) - _utils->svgaCord(2), _utils->vgaScaleX(262), _utils->vgaScaleY(132));
|
||||
_graphics->flowText(paperFont, -8 - _utils->svgaCord(1), 0, 0, false, true, false, true, textRect, paperText.c_str());
|
||||
} else
|
||||
y = 115 - _utils->svgaCord(5);
|
||||
|
||||
_graphics->freeFont(&paperFont);
|
||||
|
||||
paperFont = _resource->getFont("F:Note.fon");
|
||||
paperText = _resource->getText("Lab:Rooms/Col1");
|
||||
_graphics->flowText(paperFont, -4, 0, 0, false, false, false, true, _utils->vgaRectScale(45, y, 158, 148), paperText.c_str());
|
||||
|
||||
paperText = _resource->getText("Lab:Rooms/Col2");
|
||||
_graphics->flowText(paperFont, -4, 0, 0, false, false, false, true, _utils->vgaRectScale(162, y, 275, 148), paperText.c_str());
|
||||
|
||||
_graphics->freeFont(&paperFont);
|
||||
_graphics->setPalette(_anim->_diffPalette, 256);
|
||||
}
|
||||
|
||||
void LabEngine::loadJournalData() {
|
||||
if (_journalFont)
|
||||
_graphics->freeFont(&_journalFont);
|
||||
|
||||
_journalFont = _resource->getFont("F:Journal.fon");
|
||||
updateEvents();
|
||||
|
||||
Common::String filename = "Lab:Rooms/j";
|
||||
|
||||
bool bridge = _conditions->in(kCondBridge0) || _conditions->in(kCondBridge1);
|
||||
bool dirty = _conditions->in(kCondDirty);
|
||||
bool news = !_conditions->in(kCondNoNews);
|
||||
bool clean = !_conditions->in(kCondNoClean);
|
||||
|
||||
if (bridge && clean && news)
|
||||
filename += '8';
|
||||
else if (clean && news)
|
||||
filename += '9';
|
||||
else if (bridge && clean)
|
||||
filename += '6';
|
||||
else if (clean)
|
||||
filename += '7';
|
||||
else if (bridge && dirty && news)
|
||||
filename += '4';
|
||||
else if (dirty && news)
|
||||
filename += '5';
|
||||
else if (bridge && dirty)
|
||||
filename += '2';
|
||||
else if (dirty)
|
||||
filename += '3';
|
||||
else if (bridge)
|
||||
filename += '1';
|
||||
else
|
||||
filename += '0';
|
||||
|
||||
_journalText = _resource->getText(filename);
|
||||
_journalTextTitle = _resource->getText("Lab:Rooms/jt");
|
||||
|
||||
Common::File *journalFile = _resource->openDataFile("P:JImage");
|
||||
_journalButtonList.push_back(_interface->createButton( 80, _utils->vgaScaleY(162) + _utils->svgaCord(1), 0, kActionJournalBack, new Image(journalFile, this), new Image(journalFile, this))); // back
|
||||
_journalButtonList.push_back(_interface->createButton(194, _utils->vgaScaleY(162) + _utils->svgaCord(1), 2, kActionJournalForward, new Image(journalFile, this), new Image(journalFile, this))); // forward
|
||||
_journalButtonList.push_back(_interface->createButton(144, _utils->vgaScaleY(164) - _utils->svgaCord(1), 1, kActionJournalExit, new Image(journalFile, this), new Image(journalFile, this))); // cancel
|
||||
delete journalFile;
|
||||
|
||||
_anim->_noPalChange = true;
|
||||
_journalBackImage->setData(new byte[_graphics->_screenBytesPerPage]);
|
||||
_graphics->readPict("P:Journal.pic", true, false, _journalBackImage->_imageData);
|
||||
_anim->_noPalChange = false;
|
||||
|
||||
// Keep a copy of the blank journal
|
||||
_blankJournal = new byte[_graphics->_screenBytesPerPage];
|
||||
memcpy(_blankJournal, _journalBackImage->_imageData, _graphics->_screenBytesPerPage);
|
||||
}
|
||||
|
||||
void LabEngine::drawJournalText() {
|
||||
uint16 drawingToPage = 1;
|
||||
const char *curText = _journalText.c_str();
|
||||
|
||||
assert((_journalPage & 1) == 0);
|
||||
|
||||
while (drawingToPage < _journalPage) {
|
||||
updateEvents();
|
||||
|
||||
// flowText without output
|
||||
curText += _graphics->flowText(_journalFont, -2, 2, 0, false, false, false, false, _utils->vgaRectScale(52, 32, 152, 148), curText);
|
||||
|
||||
_lastPage = (*curText == 0);
|
||||
|
||||
if (_lastPage) {
|
||||
// Reset _journalPage to this page, in case it was set too high
|
||||
_journalPage = (drawingToPage / 2) * 2;
|
||||
break;
|
||||
}
|
||||
|
||||
drawingToPage++;
|
||||
}
|
||||
|
||||
if (_journalPage == 0) {
|
||||
// draw title page centered
|
||||
_graphics->flowText(_journalFont, -2, 2, 0, false, true, true, true, _utils->vgaRectScale(52, 32, 152, 148), _journalTextTitle.c_str(), _journalBackImage);
|
||||
} else {
|
||||
curText += _graphics->flowText(_journalFont, -2, 2, 0, false, false, false, true, _utils->vgaRectScale(52, 32, 152, 148), curText, _journalBackImage);
|
||||
}
|
||||
|
||||
updateEvents();
|
||||
curText += _graphics->flowText(_journalFont, -2, 2, 0, false, false, false, true, _utils->vgaRectScale(171, 32, 271, 148), curText, _journalBackImage);
|
||||
|
||||
_lastPage = (*curText == 0);
|
||||
}
|
||||
|
||||
void LabEngine::turnPage(bool fromLeft) {
|
||||
if (fromLeft) {
|
||||
for (int i = 0; i < _graphics->_screenWidth; i += 8) {
|
||||
updateEvents();
|
||||
waitTOF();
|
||||
_journalBackImage->blitBitmap(i, 0, nullptr, i, 0, 8, _graphics->_screenHeight, false);
|
||||
}
|
||||
} else {
|
||||
for (int i = (_graphics->_screenWidth - 8); i > 0; i -= 8) {
|
||||
updateEvents();
|
||||
waitTOF();
|
||||
_journalBackImage->blitBitmap(i, 0, nullptr, i, 0, 8, _graphics->_screenHeight, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LabEngine::drawJournal(uint16 wipenum, bool needFade) {
|
||||
_event->mouseHide();
|
||||
updateEvents();
|
||||
drawJournalText();
|
||||
_graphics->loadBackPict("P:Journal.pic", _highPalette);
|
||||
|
||||
if (wipenum == 0)
|
||||
_journalBackImage->blitBitmap(0, 0, nullptr, 0, 0, _graphics->_screenWidth, _graphics->_screenHeight, false);
|
||||
else
|
||||
turnPage((wipenum == 1));
|
||||
|
||||
_interface->toggleButton(_interface->getButton(0), 15, (_journalPage > 0)); // back button
|
||||
_interface->toggleButton(_interface->getButton(2), 15, (!_lastPage)); // forward button
|
||||
|
||||
if (needFade)
|
||||
_graphics->fade(true);
|
||||
|
||||
// Reset the journal background, so that all the text that has been blitted on it is erased
|
||||
memcpy(_journalBackImage->_imageData, _blankJournal, _graphics->_screenBytesPerPage);
|
||||
|
||||
eatMessages();
|
||||
_event->mouseShow();
|
||||
}
|
||||
|
||||
void LabEngine::processJournal() {
|
||||
while (1) {
|
||||
IntuiMessage *msg = _event->getMsg();
|
||||
if (shouldQuit()) {
|
||||
_quitLab = true;
|
||||
return;
|
||||
}
|
||||
|
||||
updateEvents();
|
||||
_graphics->screenUpdate();
|
||||
_system->delayMillis(10);
|
||||
|
||||
if (!msg)
|
||||
continue;
|
||||
|
||||
MessageClass msgClass = msg->_msgClass;
|
||||
|
||||
if ((msgClass == kMessageRightClick) ||
|
||||
((msgClass == kMessageAction) && (msg->_code == kActionExit)))
|
||||
return;
|
||||
else if (msgClass == kMessageButtonUp) {
|
||||
uint16 buttonId = msg->_code;
|
||||
if (buttonId == 0) {
|
||||
if (_journalPage >= 2) {
|
||||
_journalPage -= 2;
|
||||
drawJournal(1, false);
|
||||
}
|
||||
} else if (buttonId == 1) {
|
||||
return;
|
||||
} else if (buttonId == 2) {
|
||||
if (!_lastPage) {
|
||||
_journalPage += 2;
|
||||
drawJournal(2, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // while
|
||||
}
|
||||
|
||||
void LabEngine::doJournal() {
|
||||
_graphics->blackAllScreen();
|
||||
_lastPage = false;
|
||||
|
||||
_journalBackImage->_width = _graphics->_screenWidth;
|
||||
_journalBackImage->_height = _graphics->_screenHeight;
|
||||
_journalBackImage->setData(nullptr, true);
|
||||
|
||||
updateEvents();
|
||||
loadJournalData();
|
||||
_interface->attachButtonList(&_journalButtonList);
|
||||
drawJournal(0, true);
|
||||
_event->mouseShow();
|
||||
processJournal();
|
||||
_interface->attachButtonList(nullptr);
|
||||
_graphics->fade(false);
|
||||
_event->mouseHide();
|
||||
|
||||
delete[] _blankJournal;
|
||||
_blankJournal = nullptr;
|
||||
_journalBackImage->setData(nullptr, true);
|
||||
|
||||
_interface->freeButtonList(&_journalButtonList);
|
||||
_graphics->freeFont(&_journalFont);
|
||||
|
||||
_graphics->rectFill(0, 0, _graphics->_screenWidth - 1, _graphics->_screenHeight - 1, 0);
|
||||
_graphics->blackScreen();
|
||||
}
|
||||
|
||||
void LabEngine::drawMonText(const char *text, TextFont *monitorFont, Common::Rect textRect, bool isinteractive) {
|
||||
uint16 drawingToPage = 0, yspacing = 0;
|
||||
|
||||
_event->mouseHide();
|
||||
|
||||
if (*text == '%') {
|
||||
text++;
|
||||
uint16 numlines = (*text - '0') * 10;
|
||||
text++;
|
||||
numlines += (*text - '0');
|
||||
text += 2;
|
||||
|
||||
uint16 fheight = _graphics->textHeight(monitorFont);
|
||||
textRect.left = _monitorButton->_width + _utils->vgaScaleX(3);
|
||||
_monitorButtonHeight = _monitorButton->_height + _utils->vgaScaleY(3);
|
||||
|
||||
if (_monitorButtonHeight > fheight)
|
||||
yspacing = _monitorButtonHeight - fheight;
|
||||
else
|
||||
_monitorButtonHeight = fheight;
|
||||
|
||||
_graphics->rectFill(0, 0, _graphics->_screenWidth - 1, textRect.bottom, 0);
|
||||
|
||||
for (int i = 0; i < numlines; i++)
|
||||
_monitorButton->drawImage(0, i * _monitorButtonHeight);
|
||||
} else if (isinteractive) {
|
||||
_graphics->rectFill(0, 0, _graphics->_screenWidth - 1, textRect.bottom, 0);
|
||||
} else {
|
||||
_graphics->rectFill(textRect, 0);
|
||||
}
|
||||
|
||||
const char *curText = text;
|
||||
while (drawingToPage < _monitorPage) {
|
||||
updateEvents();
|
||||
curText += _graphics->flowText(monitorFont, yspacing, 0, 0, false, false, false, false, textRect, curText);
|
||||
_lastPage = (*curText == 0);
|
||||
|
||||
if (_lastPage)
|
||||
_monitorPage = drawingToPage;
|
||||
else
|
||||
drawingToPage++;
|
||||
}
|
||||
|
||||
curText += _graphics->flowText(monitorFont, yspacing, 2, 0, false, false, false, true, textRect, curText);
|
||||
_lastPage = (*curText == 0);
|
||||
_event->mouseShow();
|
||||
}
|
||||
|
||||
void LabEngine::processMonitor(const Common::String &ntext, TextFont *monitorFont, bool isInteractive, Common::Rect textRect) {
|
||||
Common::String startFileName = _monitorTextFilename;
|
||||
const CloseData *startClosePtr = _closeDataPtr, *lastClosePtr[10];
|
||||
uint16 depth = 0;
|
||||
Common::String text = ntext;
|
||||
|
||||
lastClosePtr[0] = _closeDataPtr;
|
||||
|
||||
while (1) {
|
||||
if (isInteractive) {
|
||||
if (!_closeDataPtr)
|
||||
_closeDataPtr = startClosePtr;
|
||||
|
||||
Common::String filename;
|
||||
if (_closeDataPtr == startClosePtr)
|
||||
filename = startFileName;
|
||||
else
|
||||
filename = _closeDataPtr->_graphicName;
|
||||
|
||||
if (filename != _monitorTextFilename) {
|
||||
_monitorPage = 0;
|
||||
_monitorTextFilename = filename;
|
||||
|
||||
text = _resource->getText(_monitorTextFilename);
|
||||
_graphics->fade(false);
|
||||
drawMonText(text.c_str(), monitorFont, textRect, isInteractive);
|
||||
_graphics->fade(true);
|
||||
}
|
||||
}
|
||||
|
||||
IntuiMessage *msg = _event->getMsg();
|
||||
if (shouldQuit()) {
|
||||
_quitLab = true;
|
||||
return;
|
||||
}
|
||||
|
||||
updateEvents();
|
||||
_graphics->screenUpdate();
|
||||
_system->delayMillis(10);
|
||||
|
||||
if (!msg)
|
||||
continue;
|
||||
|
||||
MessageClass msgClass = msg->_msgClass;
|
||||
|
||||
if ((msgClass == kMessageRightClick) ||
|
||||
((msgClass == kMessageAction) && (msg->_code == kActionExit)))
|
||||
return;
|
||||
|
||||
if (msgClass == kMessageLeftClick) {
|
||||
int16 mouseX = msg->_mouse.x;
|
||||
int16 mouseY = msg->_mouse.y;
|
||||
|
||||
// Check if mouse was in button bar
|
||||
if ((mouseY >= _utils->vgaScaleY(171)) && (mouseY <= _utils->vgaScaleY(200))) {
|
||||
if (mouseX <= _utils->vgaScaleX(31)) {
|
||||
// Exit button
|
||||
return;
|
||||
}
|
||||
|
||||
if (mouseX <= _utils->vgaScaleX(59)) {
|
||||
// Back button
|
||||
if (isInteractive) {
|
||||
_monitorPage = 0;
|
||||
|
||||
if (depth) {
|
||||
depth--;
|
||||
_closeDataPtr = lastClosePtr[depth];
|
||||
}
|
||||
} else if (_monitorPage > 0) {
|
||||
_monitorPage = 0;
|
||||
drawMonText(text.c_str(), monitorFont, textRect, isInteractive);
|
||||
}
|
||||
} else if (mouseX < _utils->vgaScaleX(259)) {
|
||||
// empty region; ignore
|
||||
} else if (mouseX <= _utils->vgaScaleX(289)) {
|
||||
// Page down button
|
||||
if (!_lastPage) {
|
||||
_monitorPage += 1;
|
||||
drawMonText(text.c_str(), monitorFont, textRect, isInteractive);
|
||||
}
|
||||
} else if (_monitorPage >= 1) {
|
||||
// Page up button
|
||||
_monitorPage -= 1;
|
||||
drawMonText(text.c_str(), monitorFont, textRect, isInteractive);
|
||||
}
|
||||
} else if (isInteractive) {
|
||||
const CloseData *tmpClosePtr = _closeDataPtr;
|
||||
mouseY = 64 + (mouseY / _monitorButtonHeight) * 42;
|
||||
mouseX = 101;
|
||||
setCurrentClose(Common::Point(mouseX, mouseY), &_closeDataPtr, false);
|
||||
|
||||
if (tmpClosePtr != _closeDataPtr) {
|
||||
lastClosePtr[depth] = tmpClosePtr;
|
||||
depth++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // while
|
||||
}
|
||||
|
||||
void LabEngine::doMonitor(const Common::String &background, const Common::String &textfile, bool isinteractive, Common::Rect textRect) {
|
||||
Common::Rect scaledRect = _utils->vgaRectScale(textRect.left, textRect.top, textRect.right, textRect.bottom);
|
||||
_monitorTextFilename = textfile;
|
||||
|
||||
_graphics->blackAllScreen();
|
||||
_graphics->readPict("P:Mon/Monitor.1");
|
||||
_graphics->readPict("P:Mon/NWD1");
|
||||
_graphics->readPict("P:Mon/NWD2");
|
||||
_graphics->readPict("P:Mon/NWD3");
|
||||
_graphics->blackAllScreen();
|
||||
|
||||
_monitorPage = 0;
|
||||
_lastPage = false;
|
||||
_graphics->_fadePalette = _highPalette;
|
||||
|
||||
TextFont *monitorFont = _resource->getFont("F:Map.fon");
|
||||
Common::File *buttonFile = _resource->openDataFile("P:MonImage");
|
||||
_monitorButton = new Image(buttonFile, this);
|
||||
delete buttonFile;
|
||||
|
||||
Common::String ntext = _resource->getText(textfile);
|
||||
_graphics->loadBackPict(background, _highPalette);
|
||||
drawMonText(ntext.c_str(), monitorFont, scaledRect, isinteractive);
|
||||
_event->mouseShow();
|
||||
_graphics->fade(true);
|
||||
processMonitor(ntext, monitorFont, isinteractive, scaledRect);
|
||||
_graphics->fade(false);
|
||||
_event->mouseHide();
|
||||
_graphics->freeFont(&monitorFont);
|
||||
|
||||
_graphics->rectFill(0, 0, _graphics->_screenWidth - 1, _graphics->_screenHeight - 1, 0);
|
||||
_graphics->blackAllScreen();
|
||||
_graphics->freePict();
|
||||
}
|
||||
|
||||
} // End of namespace Lab
|
||||
395
engines/lab/speciallocks.cpp
Normal file
395
engines/lab/speciallocks.cpp
Normal file
@@ -0,0 +1,395 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/file.h"
|
||||
#include "common/translation.h"
|
||||
|
||||
#include "gui/message.h"
|
||||
|
||||
#include "lab/lab.h"
|
||||
#include "lab/anim.h"
|
||||
#include "lab/dispman.h"
|
||||
#include "lab/image.h"
|
||||
#include "lab/labsets.h"
|
||||
#include "lab/resource.h"
|
||||
#include "lab/speciallocks.h"
|
||||
#include "lab/utils.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
#define BRICKOPEN 115
|
||||
#define COMBINATIONUNLOCKED 130
|
||||
|
||||
enum TileScroll {
|
||||
kScrollLeft = 1,
|
||||
kScrollRight = 2,
|
||||
kScrollUp = 3,
|
||||
kScrollDown = 4
|
||||
};
|
||||
|
||||
const uint16 INIT_TILE[4][4] = {
|
||||
{ 1, 5, 9, 13 },
|
||||
{ 2, 6, 10, 14 },
|
||||
{ 3, 7, 11, 15 },
|
||||
{ 4, 8, 12, 0 }
|
||||
};
|
||||
|
||||
const uint16 SOLUTION[4][4] = {
|
||||
{ 7, 1, 8, 3 },
|
||||
{ 2, 11, 15, 4 },
|
||||
{ 9, 5, 14, 6 },
|
||||
{ 10, 13, 12, 0 }
|
||||
};
|
||||
|
||||
const int COMBINATION_X[6] = { 45, 83, 129, 166, 211, 248 };
|
||||
|
||||
SpecialLocks::SpecialLocks(LabEngine *vm) : _vm(vm) {
|
||||
for (int i = 0; i < 16; i++)
|
||||
_tiles[i] = nullptr;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++)
|
||||
_curTile[i][j] = INIT_TILE[i][j];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
_combination[i] = 0;
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
_numberImages[i] = nullptr;
|
||||
}
|
||||
|
||||
SpecialLocks::~SpecialLocks() {
|
||||
for (int i = 0; i < 16; i++)
|
||||
delete _tiles[i];
|
||||
|
||||
for (int imgIdx = 0; imgIdx < 10; imgIdx++) {
|
||||
delete _numberImages[imgIdx];
|
||||
_numberImages[imgIdx] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void SpecialLocks::tileClick(Common::Point pos) {
|
||||
Common::Point realPos = _vm->_utils->vgaUnscale(pos);
|
||||
|
||||
if ((realPos.x < 101) || (realPos.y < 26))
|
||||
return;
|
||||
|
||||
int tileX = (realPos.x - 101) / 30;
|
||||
int tileY = (realPos.y - 26) / 25;
|
||||
|
||||
if ((tileX < 4) && (tileY < 4))
|
||||
changeTile(tileX, tileY);
|
||||
}
|
||||
|
||||
void SpecialLocks::changeTile(uint16 col, uint16 row) {
|
||||
int16 scrolltype = -1;
|
||||
|
||||
if (row > 0) {
|
||||
if (_curTile[col][row - 1] == 0) {
|
||||
_curTile[col][row - 1] = _curTile[col][row];
|
||||
_curTile[col][row] = 0;
|
||||
scrolltype = kScrollDown;
|
||||
}
|
||||
}
|
||||
|
||||
if (col > 0) {
|
||||
if (_curTile[col - 1][row] == 0) {
|
||||
_curTile[col - 1][row] = _curTile[col][row];
|
||||
_curTile[col][row] = 0;
|
||||
scrolltype = kScrollRight;
|
||||
}
|
||||
}
|
||||
|
||||
if (row < 3) {
|
||||
if (_curTile[col][row + 1] == 0) {
|
||||
_curTile[col][row + 1] = _curTile[col][row];
|
||||
_curTile[col][row] = 0;
|
||||
scrolltype = kScrollUp;
|
||||
}
|
||||
}
|
||||
|
||||
if (col < 3) {
|
||||
if (_curTile[col + 1][row] == 0) {
|
||||
_curTile[col + 1][row] = _curTile[col][row];
|
||||
_curTile[col][row] = 0;
|
||||
scrolltype = kScrollLeft;
|
||||
}
|
||||
}
|
||||
|
||||
if (scrolltype != -1) {
|
||||
if (_vm->getFeatures() & GF_WINDOWS_TRIAL) {
|
||||
GUI::MessageDialog trialMessage(_("This puzzle is not available in the trial version of the game"));
|
||||
trialMessage.runModal();
|
||||
return;
|
||||
}
|
||||
|
||||
doTileScroll(col, row, scrolltype);
|
||||
bool check = true;
|
||||
row = 0;
|
||||
col = 0;
|
||||
|
||||
while (row < 4) {
|
||||
while (col < 4) {
|
||||
check &= (_curTile[row][col] == SOLUTION[row][col]);
|
||||
col++;
|
||||
}
|
||||
|
||||
row++;
|
||||
col = 0;
|
||||
}
|
||||
|
||||
if (check) {
|
||||
// unlocked combination
|
||||
_vm->_conditions->inclElement(BRICKOPEN);
|
||||
_vm->_anim->_doBlack = true;
|
||||
_vm->_graphics->readPict("p:Up/BDOpen");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpecialLocks::combinationClick(Common::Point pos) {
|
||||
Common::Point realPos = _vm->_utils->vgaUnscale(pos);
|
||||
|
||||
if (!Common::Rect(44, 63, 285, 99).contains(realPos))
|
||||
return;
|
||||
|
||||
uint16 number = 0;
|
||||
if (realPos.x < 83)
|
||||
number = 0;
|
||||
else if (realPos.x < 127)
|
||||
number = 1;
|
||||
else if (realPos.x < 165)
|
||||
number = 2;
|
||||
else if (realPos.x < 210)
|
||||
number = 3;
|
||||
else if (realPos.x < 245)
|
||||
number = 4;
|
||||
else if (realPos.x < 286)
|
||||
number = 5;
|
||||
|
||||
changeCombination(number);
|
||||
}
|
||||
|
||||
void SpecialLocks::doTile(bool showsolution) {
|
||||
uint16 row = 0, col = 0, rowm, colm, num;
|
||||
int16 rows, cols;
|
||||
|
||||
if (showsolution) {
|
||||
rowm = _vm->_utils->vgaScaleY(23);
|
||||
colm = _vm->_utils->vgaScaleX(27);
|
||||
|
||||
rows = _vm->_utils->vgaScaleY(31);
|
||||
cols = _vm->_utils->vgaScaleX(105);
|
||||
} else {
|
||||
_vm->_graphics->rectFillScaled(97, 22, 220, 126, 0);
|
||||
|
||||
rowm = _vm->_utils->vgaScaleY(25);
|
||||
colm = _vm->_utils->vgaScaleX(30);
|
||||
|
||||
rows = _vm->_utils->vgaScaleY(25);
|
||||
cols = _vm->_utils->vgaScaleX(100);
|
||||
}
|
||||
|
||||
while (row < 4) {
|
||||
while (col < 4) {
|
||||
if (showsolution)
|
||||
num = SOLUTION[col][row];
|
||||
else
|
||||
num = _curTile[col][row];
|
||||
|
||||
if (showsolution || num)
|
||||
_tiles[num]->drawImage(cols + (col * colm), rows + (row * rowm));
|
||||
|
||||
col++;
|
||||
}
|
||||
|
||||
row++;
|
||||
col = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SpecialLocks::showTileLock(const Common::String &filename, bool showSolution) {
|
||||
_vm->_anim->_doBlack = true;
|
||||
_vm->_anim->_noPalChange = true;
|
||||
_vm->_graphics->readPict(filename);
|
||||
_vm->_anim->_noPalChange = false;
|
||||
_vm->_graphics->blackScreen();
|
||||
|
||||
Common::File *tileFile;
|
||||
if (_vm->getPlatform() == Common::kPlatformDOS)
|
||||
tileFile = _vm->_resource->openDataFile(showSolution ? "P:TileSolu" : "P:Tile");
|
||||
else
|
||||
// Windows and Amiga versions use TileSolution and Tile
|
||||
tileFile = _vm->_resource->openDataFile(showSolution ? "P:TileSolution" : "P:Tile");
|
||||
|
||||
int start = showSolution ? 0 : 1;
|
||||
|
||||
for (int curBit = start; curBit < 16; curBit++)
|
||||
_tiles[curBit] = new Image(tileFile, _vm);
|
||||
|
||||
delete tileFile;
|
||||
|
||||
doTile(showSolution);
|
||||
_vm->_graphics->setPalette(_vm->_anim->_diffPalette, 256);
|
||||
}
|
||||
|
||||
void SpecialLocks::doTileScroll(uint16 col, uint16 row, uint16 scrolltype) {
|
||||
int16 dX = 0, dY = 0, dx = 0, dy = 0, sx = 0, sy = 0;
|
||||
int last = 0;
|
||||
|
||||
if (scrolltype == kScrollLeft) {
|
||||
dX = _vm->_utils->vgaScaleX(5);
|
||||
sx = _vm->_utils->vgaScaleX(5);
|
||||
last = 6;
|
||||
} else if (scrolltype == kScrollRight) {
|
||||
dX = _vm->_utils->vgaScaleX(-5);
|
||||
dx = _vm->_utils->vgaScaleX(-5);
|
||||
sx = _vm->_utils->vgaScaleX(5);
|
||||
last = 6;
|
||||
} else if (scrolltype == kScrollUp) {
|
||||
dY = _vm->_utils->vgaScaleY(5);
|
||||
sy = _vm->_utils->vgaScaleY(5);
|
||||
last = 5;
|
||||
} else if (scrolltype == kScrollDown) {
|
||||
dY = _vm->_utils->vgaScaleY(-5);
|
||||
dy = _vm->_utils->vgaScaleY(-5);
|
||||
sy = _vm->_utils->vgaScaleY(5);
|
||||
last = 5;
|
||||
}
|
||||
|
||||
sx += _vm->_utils->svgaCord(2);
|
||||
|
||||
uint16 x1 = _vm->_utils->vgaScaleX(100) + (col * _vm->_utils->vgaScaleX(30)) + dx;
|
||||
uint16 y1 = _vm->_utils->vgaScaleY(25) + (row * _vm->_utils->vgaScaleY(25)) + dy;
|
||||
|
||||
byte *buffer = new byte[_tiles[1]->_width * _tiles[1]->_height * 2];
|
||||
|
||||
for (int i = 0; i < last; i++) {
|
||||
_vm->waitTOF();
|
||||
scrollRaster(dX, dY, x1, y1, x1 + _vm->_utils->vgaScaleX(28) + sx, y1 + _vm->_utils->vgaScaleY(23) + sy, buffer);
|
||||
x1 += dX;
|
||||
y1 += dY;
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
void SpecialLocks::scrollRaster(int16 dx, int16 dy, uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte *buffer) {
|
||||
if (dx)
|
||||
_vm->_graphics->scrollDisplayX(dx, x1, y1, x2, y2, buffer);
|
||||
|
||||
if (dy)
|
||||
_vm->_graphics->scrollDisplayY(dy, x1, y1, x2, y2, buffer);
|
||||
}
|
||||
|
||||
void SpecialLocks::changeCombination(uint16 number) {
|
||||
const int solution[6] = { 0, 4, 0, 8, 7, 2 };
|
||||
|
||||
Image display(_vm);
|
||||
|
||||
if (_combination[number] < 9)
|
||||
(_combination[number])++;
|
||||
else
|
||||
_combination[number] = 0;
|
||||
|
||||
uint16 combnum = _combination[number];
|
||||
|
||||
display.setData(_vm->_graphics->getCurrentDrawingBuffer(), false);
|
||||
display._width = _vm->_graphics->_screenWidth;
|
||||
display._height = _vm->_graphics->_screenHeight;
|
||||
|
||||
byte *buffer = new byte[_numberImages[1]->_width * _numberImages[1]->_height * 2];
|
||||
|
||||
for (int i = 1; i <= (_numberImages[combnum]->_height / 2); i++) {
|
||||
if (i & 1)
|
||||
_vm->waitTOF();
|
||||
|
||||
display.setData(_vm->_graphics->getCurrentDrawingBuffer(), false);
|
||||
_vm->_graphics->scrollDisplayY(2, _vm->_utils->vgaScaleX(COMBINATION_X[number]), _vm->_utils->vgaScaleY(65), _vm->_utils->vgaScaleX(COMBINATION_X[number]) + (_numberImages[combnum])->_width - 1, _vm->_utils->vgaScaleY(65) + (_numberImages[combnum])->_height, buffer);
|
||||
_numberImages[combnum]->blitBitmap(0, (_numberImages[combnum])->_height - (2 * i), &(display), _vm->_utils->vgaScaleX(COMBINATION_X[number]), _vm->_utils->vgaScaleY(65), (_numberImages[combnum])->_width, 2, false);
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
|
||||
bool unlocked = true;
|
||||
for (int i = 0; i < 6; i++)
|
||||
unlocked &= (_combination[i] == solution[i]);
|
||||
|
||||
if (unlocked)
|
||||
_vm->_conditions->inclElement(COMBINATIONUNLOCKED);
|
||||
else
|
||||
_vm->_conditions->exclElement(COMBINATIONUNLOCKED);
|
||||
}
|
||||
|
||||
void SpecialLocks::showCombinationLock(const Common::String &filename) {
|
||||
_vm->_anim->_doBlack = true;
|
||||
_vm->_anim->_noPalChange = true;
|
||||
_vm->_graphics->readPict(filename);
|
||||
_vm->_anim->_noPalChange = false;
|
||||
|
||||
_vm->_graphics->blackScreen();
|
||||
|
||||
Common::File *numFile = _vm->_resource->openDataFile("P:Numbers");
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
_numberImages[i] = new Image(numFile, _vm);
|
||||
}
|
||||
|
||||
delete numFile;
|
||||
|
||||
for (int i = 0; i <= 5; i++)
|
||||
_numberImages[_combination[i]]->drawImage(_vm->_utils->vgaScaleX(COMBINATION_X[i]), _vm->_utils->vgaScaleY(65));
|
||||
|
||||
_vm->_graphics->setPalette(_vm->_anim->_diffPalette, 256);
|
||||
}
|
||||
|
||||
void SpecialLocks::save(Common::OutSaveFile *file) {
|
||||
// Combination lock
|
||||
for (int i = 0; i < 6; i++)
|
||||
file->writeByte(_combination[i]);
|
||||
|
||||
// Tiles
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
file->writeUint16LE(_curTile[i][j]);
|
||||
}
|
||||
|
||||
void SpecialLocks::load(Common::InSaveFile *file) {
|
||||
// Combination lock
|
||||
for (int i = 0; i < 6; i++)
|
||||
_combination[i] = file->readByte();
|
||||
|
||||
// Tiles
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
_curTile[i][j] = file->readUint16LE();
|
||||
}
|
||||
|
||||
} // End of namespace Lab
|
||||
93
engines/lab/speciallocks.h
Normal file
93
engines/lab/speciallocks.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LAB_TILEPUZZLE_H
|
||||
#define LAB_TILEPUZZLE_H
|
||||
|
||||
#include "common/savefile.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
class LabEngine;
|
||||
|
||||
class SpecialLocks {
|
||||
private:
|
||||
LabEngine *_vm;
|
||||
Image *_tiles[16];
|
||||
Image *_numberImages[10];
|
||||
uint16 _curTile[4][4];
|
||||
byte _combination[6];
|
||||
|
||||
public:
|
||||
SpecialLocks(LabEngine *vm);
|
||||
~SpecialLocks();
|
||||
|
||||
void showTileLock(const Common::String &filename, bool showSolution);
|
||||
|
||||
/**
|
||||
* Processes mouse clicks and changes tile positions.
|
||||
*/
|
||||
void tileClick(Common::Point pos);
|
||||
|
||||
void showCombinationLock(const Common::String &filename);
|
||||
|
||||
/**
|
||||
* Processes mouse clicks and changes the door combination.
|
||||
*/
|
||||
void combinationClick(Common::Point pos);
|
||||
|
||||
void save(Common::OutSaveFile *file);
|
||||
void load(Common::InSaveFile *file);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Changes the combination number of one of the slots
|
||||
*/
|
||||
void changeCombination(uint16 number);
|
||||
|
||||
/**
|
||||
* Changes the tile positions in the tile puzzle
|
||||
*/
|
||||
void changeTile(uint16 col, uint16 row);
|
||||
|
||||
/**
|
||||
* Draws the images of the combination lock to the display bitmap.
|
||||
*/
|
||||
void doTile(bool showsolution);
|
||||
|
||||
/**
|
||||
* Does the scrolling for the tiles on the tile puzzle.
|
||||
*/
|
||||
void doTileScroll(uint16 col, uint16 row, uint16 scrolltype);
|
||||
void scrollRaster(int16 dx, int16 dy, uint16 x1, uint16 y1, uint16 x2, uint16 y2, byte *buffer);
|
||||
};
|
||||
|
||||
} // End of namespace Lab
|
||||
|
||||
#endif // LAB_TILEPUZZLE_H
|
||||
271
engines/lab/utils.cpp
Normal file
271
engines/lab/utils.cpp
Normal file
@@ -0,0 +1,271 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/file.h"
|
||||
|
||||
#include "lab/lab.h"
|
||||
#include "lab/utils.h"
|
||||
|
||||
namespace Lab {
|
||||
Utils::Utils(LabEngine *vm) : _vm(vm), _rnd("lab") {
|
||||
_dataBytesPerRow = 0;
|
||||
}
|
||||
|
||||
uint16 Utils::scaleX(uint16 x) {
|
||||
if (_vm->_isHiRes)
|
||||
return (uint16)((x * 16) / 9);
|
||||
else
|
||||
return (uint16)((x * 8) / 9);
|
||||
}
|
||||
|
||||
uint16 Utils::scaleY(uint16 y) {
|
||||
if (_vm->_isHiRes)
|
||||
return (y + (y / 14));
|
||||
else
|
||||
return ((y * 10) / 24);
|
||||
}
|
||||
|
||||
Common::Rect Utils::rectScale(int16 x1, int16 y1, int16 x2, int16 y2) {
|
||||
return Common::Rect(scaleX(x1), scaleY(y1), scaleX(x2), scaleY(y2));
|
||||
}
|
||||
|
||||
uint16 Utils::mapScaleX(uint16 x) {
|
||||
if (_vm->_isHiRes)
|
||||
return (x - 45);
|
||||
else
|
||||
return ((x - 45) >> 1);
|
||||
}
|
||||
|
||||
uint16 Utils::mapScaleY(uint16 y) {
|
||||
if (_vm->_isHiRes)
|
||||
return y;
|
||||
else
|
||||
return ((y - 35) >> 1) - (y >> 6);
|
||||
}
|
||||
|
||||
Common::Rect Utils::mapRectScale(int16 x1, int16 y1, int16 x2, int16 y2) {
|
||||
return Common::Rect(mapScaleX(x1), mapScaleY(y1), mapScaleX(x2), mapScaleY(y2));
|
||||
}
|
||||
|
||||
int16 Utils::vgaScaleX(int16 x) {
|
||||
if (_vm->_isHiRes)
|
||||
return (x * 2);
|
||||
else
|
||||
return x;
|
||||
}
|
||||
|
||||
int16 Utils::vgaScaleY(int16 y) {
|
||||
if (_vm->_isHiRes)
|
||||
return ((y * 12) / 5);
|
||||
else
|
||||
return y;
|
||||
}
|
||||
|
||||
Common::Rect Utils::vgaRectScale(int16 x1, int16 y1, int16 x2, int16 y2) {
|
||||
return Common::Rect(vgaScaleX(x1), vgaScaleY(y1), vgaScaleX(x2), vgaScaleY(y2));
|
||||
}
|
||||
|
||||
uint16 Utils::svgaCord(uint16 cord) {
|
||||
if (_vm->_isHiRes)
|
||||
return cord;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
Common::Point Utils::vgaUnscale(Common::Point pos) {
|
||||
Common::Point result;
|
||||
if (_vm->_isHiRes) {
|
||||
result.x = pos.x / 2;
|
||||
result.y = (pos.y * 5) / 12;
|
||||
} else
|
||||
result = pos;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Utils::unDiff(T *dest, Common::File *sourceFile) {
|
||||
byte bytesPerWord = sizeof(T);
|
||||
|
||||
while (1) {
|
||||
uint16 skip = sourceFile->readByte();
|
||||
uint16 copy = sourceFile->readByte();
|
||||
|
||||
if (skip == 255) {
|
||||
if (copy == 0) {
|
||||
skip = sourceFile->readUint16LE();
|
||||
copy = sourceFile->readUint16LE();
|
||||
} else if (copy == 255)
|
||||
return;
|
||||
}
|
||||
|
||||
dest += skip;
|
||||
|
||||
if (bytesPerWord == 1) {
|
||||
sourceFile->read(dest, copy);
|
||||
dest += copy;
|
||||
} else {
|
||||
while (copy) {
|
||||
*dest = sourceFile->readUint16LE();
|
||||
dest++;
|
||||
copy--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Utils::verticalUnDiff(T *dest, Common::File *sourceFile, uint16 bytesPerRow) {
|
||||
uint16 counter = 0;
|
||||
byte bytesPerWord = sizeof(T);
|
||||
uint16 wordsPerRow = bytesPerRow / bytesPerWord;
|
||||
|
||||
while (counter < wordsPerRow) {
|
||||
T *curPtr = dest + counter;
|
||||
|
||||
for (;;) {
|
||||
uint16 skip = sourceFile->readByte();
|
||||
uint16 copy = sourceFile->readByte();
|
||||
|
||||
if (skip == 255) {
|
||||
counter += copy;
|
||||
break;
|
||||
} else {
|
||||
curPtr += (skip * wordsPerRow);
|
||||
|
||||
while (copy) {
|
||||
if (bytesPerWord == 1)
|
||||
*curPtr = sourceFile->readByte();
|
||||
else if (bytesPerWord == 2)
|
||||
*curPtr = sourceFile->readUint16LE();
|
||||
else if (bytesPerWord == 4)
|
||||
*curPtr = sourceFile->readUint32LE();
|
||||
else
|
||||
error("verticalUnDiff: Invalid bytesPerWord (%d)", bytesPerWord);
|
||||
curPtr += wordsPerRow;
|
||||
copy--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Utils::runLengthDecode(byte *dest, Common::File *sourceFile) {
|
||||
int8 num;
|
||||
int16 count;
|
||||
|
||||
while (1) {
|
||||
num = sourceFile->readSByte();
|
||||
|
||||
if (num == 127) {
|
||||
return;
|
||||
} else if (num > '\0') {
|
||||
sourceFile->read(dest, num);
|
||||
dest += num;
|
||||
} else {
|
||||
count = (int16)(-num);
|
||||
num = sourceFile->readSByte();
|
||||
|
||||
while (count) {
|
||||
*dest = num;
|
||||
dest++;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Utils::verticalRunLengthDecode(byte *dest, Common::File *sourceFile, uint16 bytesPerRow) {
|
||||
int16 count;
|
||||
byte *top = dest;
|
||||
|
||||
for (int i = 0; i < _dataBytesPerRow; i++) {
|
||||
dest = top;
|
||||
dest += i;
|
||||
|
||||
int8 num = sourceFile->readSByte();
|
||||
|
||||
while (num != 127) {
|
||||
if (num > '\0') {
|
||||
while (num) {
|
||||
*dest = sourceFile->readByte();
|
||||
dest += bytesPerRow;
|
||||
num--;
|
||||
}
|
||||
} else {
|
||||
count = (int16)(-num);
|
||||
num = sourceFile->readSByte();
|
||||
|
||||
while (count) {
|
||||
*dest = num;
|
||||
dest += bytesPerRow;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
||||
num = sourceFile->readSByte();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Utils::unDiff(byte *newBuf, byte *oldBuf, Common::File *sourceFile, uint16 bytesPerRow, bool isVertical) {
|
||||
sourceFile->skip(1);
|
||||
byte bufType = sourceFile->readByte();
|
||||
|
||||
if (isVertical) {
|
||||
if (bufType == 0)
|
||||
verticalUnDiff<byte>(newBuf, sourceFile, bytesPerRow);
|
||||
else if (bufType == 1)
|
||||
verticalUnDiff<uint16>((uint16 *)newBuf, sourceFile, bytesPerRow);
|
||||
else if (bufType == 3)
|
||||
verticalUnDiff<uint32>((uint32 *)newBuf, sourceFile, bytesPerRow);
|
||||
else
|
||||
error("Unexpected variable compression scheme %d", bufType);
|
||||
} else {
|
||||
if (bufType == 0)
|
||||
unDiff<byte>(newBuf, sourceFile);
|
||||
else if (bufType == 1)
|
||||
unDiff<uint16>((uint16 *)newBuf, sourceFile);
|
||||
else
|
||||
error("Unexpected compression scheme %d", bufType);
|
||||
}
|
||||
}
|
||||
|
||||
void Utils::setBytesPerRow(int num) {
|
||||
_dataBytesPerRow = num;
|
||||
}
|
||||
|
||||
uint16 Utils::getRandom(uint16 max) {
|
||||
if (max > 1)
|
||||
return _rnd.getRandomNumber(max - 1);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // End of namespace Lab
|
||||
104
engines/lab/utils.h
Normal file
104
engines/lab/utils.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LAB_UTILS_H
|
||||
#define LAB_UTILS_H
|
||||
|
||||
namespace Lab {
|
||||
|
||||
class Utils {
|
||||
private:
|
||||
LabEngine *_vm;
|
||||
uint16 _dataBytesPerRow;
|
||||
|
||||
/**
|
||||
* Undiffs a piece of memory based on the header size.
|
||||
*/
|
||||
template<typename T>
|
||||
void unDiff(T *dest, Common::File *sourceFile);
|
||||
|
||||
/**
|
||||
* Undiffs a piece of memory when header size is a byte, and copy/skip size
|
||||
* is a byte or a word or a double word.
|
||||
*/
|
||||
template<typename T>
|
||||
void verticalUnDiff(T *dest, Common::File *sourceFile, uint16 bytesPerRow);
|
||||
|
||||
public:
|
||||
Utils(LabEngine *vm);
|
||||
|
||||
Common::RandomSource _rnd;
|
||||
|
||||
/**
|
||||
* Scales the x co-ordinates to that of the new display. In the room parser
|
||||
* file, co-ordinates are set up on a 360x336 display.
|
||||
*/
|
||||
uint16 scaleX(uint16 x);
|
||||
|
||||
/**
|
||||
* Scales the y co-ordinates to that of the new display. In the room parser
|
||||
* file, co-ordinates are set up on a 368x336 display.
|
||||
*/
|
||||
uint16 scaleY(uint16 y);
|
||||
Common::Rect rectScale(int16 x1, int16 y1, int16 x2, int16 y2);
|
||||
|
||||
/**
|
||||
* Scales the VGA x coords to SVGA if necessary; otherwise, returns VGA coords.
|
||||
*/
|
||||
int16 vgaScaleX(int16 x);
|
||||
|
||||
/**
|
||||
* Scales the VGA y coords to SVGA if necessary; otherwise, returns VGA coords.
|
||||
*/
|
||||
int16 vgaScaleY(int16 y);
|
||||
Common::Rect vgaRectScale(int16 x1, int16 y1, int16 x2, int16 y2);
|
||||
uint16 svgaCord(uint16 cord);
|
||||
uint16 mapScaleX(uint16 x);
|
||||
uint16 mapScaleY(uint16 y);
|
||||
Common::Rect mapRectScale(int16 x1, int16 y1, int16 x2, int16 y2);
|
||||
|
||||
/**
|
||||
* Converts SVGA coords to VGA if necessary, otherwise returns VGA coords.
|
||||
*/
|
||||
Common::Point vgaUnscale(Common::Point pos);
|
||||
|
||||
/**
|
||||
* Does the undiffing between the bitmaps.
|
||||
*/
|
||||
void unDiff(byte *newBuf, byte *oldBuf, Common::File *sourceFile, uint16 bytesPerRow, bool isVertical);
|
||||
void runLengthDecode(byte *dest, Common::File *sourceFile);
|
||||
void verticalRunLengthDecode(byte *dest, Common::File *sourceFile, uint16 bytesPerRow);
|
||||
void setBytesPerRow(int num);
|
||||
uint16 getRandom(uint16 max);
|
||||
};
|
||||
|
||||
|
||||
} // End of namespace Lab
|
||||
|
||||
#endif // LAB_UTILS_H
|
||||
Reference in New Issue
Block a user