Merge branch 'sherlock2'

This commit is contained in:
Paul Gilbert 2015-05-30 10:46:19 -04:00
commit 6b95fc6b11
43 changed files with 6392 additions and 3721 deletions

View File

@ -0,0 +1,128 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "sherlock/decompress.h"
namespace Sherlock {
/**
* Decompresses an LZW compressed resource. If no outSize is specified, it will
* decompress the entire resource. If, however, an explicit size is specified,
* then it means we're already within a resource, and only want to decompress
* part of it.
*/
Common::SeekableReadStream *decompressLZ(Common::SeekableReadStream &source, int32 outSize) {
if (outSize == -1) {
source.seek(5);
outSize = source.readSint32LE();
}
byte lzWindow[4096];
uint16 lzWindowPos;
uint16 cmd;
byte *outBuffer = new byte[outSize];
byte *outBufferEnd = outBuffer + outSize;
Common::MemoryReadStream *outS = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES);
memset(lzWindow, 0xFF, 0xFEE);
lzWindowPos = 0xFEE;
cmd = 0;
do {
cmd >>= 1;
if (!(cmd & 0x100))
cmd = source.readByte() | 0xFF00;
if (cmd & 1) {
byte literal = source.readByte();
*outBuffer++ = literal;
lzWindow[lzWindowPos] = literal;
lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
} else {
int copyPos, copyLen;
copyPos = source.readByte();
copyLen = source.readByte();
copyPos = copyPos | ((copyLen & 0xF0) << 4);
copyLen = (copyLen & 0x0F) + 3;
while (copyLen--) {
byte literal = lzWindow[copyPos];
copyPos = (copyPos + 1) & 0x0FFF;
*outBuffer++ = literal;
lzWindow[lzWindowPos] = literal;
lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
}
}
} while (outBuffer < outBufferEnd);
return outS;
}
/**
* Decompresses a Rose Tattoo resource
*
Common::SeekableReadStream *decompress32(Common::SeekableReadStream &source, int32 outSize) {
if (outSize == -1) {
outSize = source.readSint32LE();
}
byte lzWindow[8192];
byte *outBuffer = new byte[outSize];
byte *outBufferEnd = outBuffer + outSize;
Common::MemoryReadStream *outS = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES);
memset(lzWindow, 0xFF, 8192);
int lzWindowPos = 0xFEE;
int cmd = 0;
do {
cmd >>= 1;
if (!(cmd & 0x100))
cmd = source.readByte() | 0xFF00;
if (cmd & 1) {
byte literal = source.readByte();
*outBuffer++ = literal;
lzWindow[lzWindowPos] = literal;
lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
} else {
int copyPos, copyLen;
copyPos = source.readByte();
copyLen = source.readByte();
copyPos = copyPos | ((copyLen & 0xF0) << 4);
copyLen = (copyLen & 0x0F) + 3;
while (copyLen--) {
byte literal = lzWindow[copyPos];
copyPos = (copyPos + 1) & 0x0FFF;
*outBuffer++ = literal;
lzWindow[lzWindowPos] = literal;
lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
}
}
} while (outBuffer < outBufferEnd);
return outS;
}
*/
} // namespace Sherlock

View File

@ -42,6 +42,8 @@ Events::Events(SherlockEngine *vm) {
_pressed = _released = false;
_rightPressed = _rightReleased = false;
_oldButtons = _oldRightButton = false;
loadCursors("rmouse.vgs");
}
Events::~Events() {
@ -73,6 +75,14 @@ void Events::setCursor(const Graphics::Surface &src) {
showCursor();
}
void Events::animateCursorIfNeeded() {
if (_cursorId >= WAIT && _cursorId < (WAIT + 3)) {
CursorId newId = (WAIT + 2) ? WAIT : (CursorId)((int)_cursorId + 1);
setCursor(newId);
}
}
void Events::showCursor() {
CursorMan.showMouse(true);
}

View File

@ -33,7 +33,7 @@ namespace Sherlock {
#define GAME_FRAME_RATE 60
#define GAME_FRAME_TIME (1000 / GAME_FRAME_RATE)
enum CursorId { ARROW = 0, MAGNIFY = 1, WAIT = 2, INVALID_CURSOR = -1 };
enum CursorId { ARROW = 0, MAGNIFY = 1, WAIT = 2, EXIT_ZONES_START = 5, INVALID_CURSOR = -1 };
class SherlockEngine;
@ -77,6 +77,11 @@ public:
*/
void setCursor(const Graphics::Surface &src);
/**
* Animates the mouse cursor if the Wait cursor is showing
*/
void animateCursorIfNeeded();
/**
* Show the mouse cursor
*/

View File

@ -22,6 +22,7 @@
#include "sherlock/inventory.h"
#include "sherlock/sherlock.h"
#include "sherlock/scalpel/scalpel_user_interface.h"
namespace Sherlock {
@ -200,29 +201,29 @@ void Inventory::drawInventory(InvNewMode mode) {
INV_BACKGROUND);
// Draw the buttons
screen.makeButton(Common::Rect(INVENTORY_POINTS[0][0], CONTROLS_Y1, INVENTORY_POINTS[0][1],
CONTROLS_Y1 + 10), INVENTORY_POINTS[0][2] - screen.stringWidth("Exit") / 2, "Exit");
screen.makeButton(Common::Rect(INVENTORY_POINTS[1][0], CONTROLS_Y1, INVENTORY_POINTS[1][1],
CONTROLS_Y1 + 10), INVENTORY_POINTS[1][2] - screen.stringWidth("Look") / 2, "Look");
screen.makeButton(Common::Rect(INVENTORY_POINTS[2][0], CONTROLS_Y1, INVENTORY_POINTS[2][1],
CONTROLS_Y1 + 10), INVENTORY_POINTS[2][2] - screen.stringWidth("Use") / 2, "Use");
screen.makeButton(Common::Rect(INVENTORY_POINTS[3][0], CONTROLS_Y1, INVENTORY_POINTS[3][1],
CONTROLS_Y1 + 10), INVENTORY_POINTS[3][2] - screen.stringWidth("Give") / 2, "Give");
screen.makeButton(Common::Rect(INVENTORY_POINTS[4][0], CONTROLS_Y1, INVENTORY_POINTS[4][1],
CONTROLS_Y1 + 10), INVENTORY_POINTS[4][2], "^^");
screen.makeButton(Common::Rect(INVENTORY_POINTS[5][0], CONTROLS_Y1, INVENTORY_POINTS[5][1],
CONTROLS_Y1 + 10), INVENTORY_POINTS[5][2], "^");
screen.makeButton(Common::Rect(INVENTORY_POINTS[6][0], CONTROLS_Y1, INVENTORY_POINTS[6][1],
CONTROLS_Y1 + 10), INVENTORY_POINTS[6][2], "_");
screen.makeButton(Common::Rect(INVENTORY_POINTS[7][0], CONTROLS_Y1, INVENTORY_POINTS[7][1],
CONTROLS_Y1 + 10), INVENTORY_POINTS[7][2], "__");
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[0][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[0][1],
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[0][2] - screen.stringWidth("Exit") / 2, "Exit");
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[1][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[1][1],
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[1][2] - screen.stringWidth("Look") / 2, "Look");
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[2][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[2][1],
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[2][2] - screen.stringWidth("Use") / 2, "Use");
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[3][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[3][1],
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[3][2] - screen.stringWidth("Give") / 2, "Give");
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[4][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[4][1],
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[4][2], "^^");
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[5][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[5][1],
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[5][2], "^");
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[6][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[6][1],
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[6][2], "_");
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[7][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[7][1],
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[7][2], "__");
if (tempMode == INVENTORY_DONT_DISPLAY)
mode = LOOK_INVENTORY_MODE;
_invMode = (InvMode)mode;
if (mode != PLAIN_INVENTORY) {
ui._oldKey = INVENTORY_COMMANDS[(int)mode];
ui._oldKey = Scalpel::INVENTORY_COMMANDS[(int)mode];
} else {
ui._oldKey = -1;
}
@ -243,7 +244,8 @@ void Inventory::drawInventory(InvNewMode mode) {
screen._backBuffer = &screen._backBuffer1;
}
ui._oldUse = -1;
assert(IS_SERRATED_SCALPEL);
((Scalpel::ScalpelUserInterface *)_vm->_ui)->_oldUse = -1;
}
void Inventory::invCommands(bool slamIt) {
@ -251,55 +253,55 @@ void Inventory::invCommands(bool slamIt) {
UserInterface &ui = *_vm->_ui;
if (slamIt) {
screen.buttonPrint(Common::Point(INVENTORY_POINTS[0][2], CONTROLS_Y1),
screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[0][2], CONTROLS_Y1),
_invMode == INVMODE_EXIT ? COMMAND_HIGHLIGHTED :COMMAND_FOREGROUND,
true, "Exit");
screen.buttonPrint(Common::Point(INVENTORY_POINTS[1][2], CONTROLS_Y1),
screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[1][2], CONTROLS_Y1),
_invMode == INVMODE_LOOK ? COMMAND_HIGHLIGHTED :COMMAND_FOREGROUND,
true, "Look");
screen.buttonPrint(Common::Point(INVENTORY_POINTS[2][2], CONTROLS_Y1),
screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[2][2], CONTROLS_Y1),
_invMode == INVMODE_USE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
true, "Use");
screen.buttonPrint(Common::Point(INVENTORY_POINTS[3][2], CONTROLS_Y1),
screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[3][2], CONTROLS_Y1),
_invMode == INVMODE_GIVE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
true, "Give");
screen.print(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1 + 1),
screen.print(Common::Point(Scalpel::INVENTORY_POINTS[4][2], CONTROLS_Y1 + 1),
_invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
"^^");
screen.print(Common::Point(INVENTORY_POINTS[5][2], CONTROLS_Y1 + 1),
screen.print(Common::Point(Scalpel::INVENTORY_POINTS[5][2], CONTROLS_Y1 + 1),
_invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
"^");
screen.print(Common::Point(INVENTORY_POINTS[6][2], CONTROLS_Y1 + 1),
screen.print(Common::Point(Scalpel::INVENTORY_POINTS[6][2], CONTROLS_Y1 + 1),
(_holdings - _invIndex <= 6) ? COMMAND_NULL : COMMAND_FOREGROUND,
"_");
screen.print(Common::Point(INVENTORY_POINTS[7][2], CONTROLS_Y1 + 1),
screen.print(Common::Point(Scalpel::INVENTORY_POINTS[7][2], CONTROLS_Y1 + 1),
(_holdings - _invIndex <= 6) ? COMMAND_NULL : COMMAND_FOREGROUND,
"__");
if (_invMode != INVMODE_LOOK)
ui.clearInfo();
} else {
screen.buttonPrint(Common::Point(INVENTORY_POINTS[0][2], CONTROLS_Y1),
screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[0][2], CONTROLS_Y1),
_invMode == INVMODE_EXIT ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
false, "Exit");
screen.buttonPrint(Common::Point(INVENTORY_POINTS[1][2], CONTROLS_Y1),
screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[1][2], CONTROLS_Y1),
_invMode == INVMODE_LOOK ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
false, "Look");
screen.buttonPrint(Common::Point(INVENTORY_POINTS[2][2], CONTROLS_Y1),
screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[2][2], CONTROLS_Y1),
_invMode == INVMODE_USE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
false, "Use");
screen.buttonPrint(Common::Point(INVENTORY_POINTS[3][2], CONTROLS_Y1),
screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[3][2], CONTROLS_Y1),
_invMode == INVMODE_GIVE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
false, "Give");
screen.gPrint(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1),
screen.gPrint(Common::Point(Scalpel::INVENTORY_POINTS[4][2], CONTROLS_Y1),
_invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
"^^");
screen.gPrint(Common::Point(INVENTORY_POINTS[5][2], CONTROLS_Y1),
screen.gPrint(Common::Point(Scalpel::INVENTORY_POINTS[5][2], CONTROLS_Y1),
_invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
"^");
screen.gPrint(Common::Point(INVENTORY_POINTS[6][2], CONTROLS_Y1),
screen.gPrint(Common::Point(Scalpel::INVENTORY_POINTS[6][2], CONTROLS_Y1),
(_holdings - _invIndex < 7) ? COMMAND_NULL : COMMAND_FOREGROUND,
"_");
screen.gPrint(Common::Point(INVENTORY_POINTS[7][2], CONTROLS_Y1),
screen.gPrint(Common::Point(Scalpel::INVENTORY_POINTS[7][2], CONTROLS_Y1),
(_holdings - _invIndex < 7) ? COMMAND_NULL : COMMAND_FOREGROUND,
"__");
}
@ -318,9 +320,12 @@ void Inventory::highlight(int index, byte color) {
}
void Inventory::refreshInv() {
if (IS_ROSE_TATTOO)
return;
Screen &screen = *_vm->_screen;
Talk &talk = *_vm->_talk;
UserInterface &ui = *_vm->_ui;
Scalpel::ScalpelUserInterface &ui = *(Scalpel::ScalpelUserInterface *)_vm->_ui;
ui._invLookFlag = true;
freeInv();

View File

@ -135,6 +135,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
Screen &screen = *_vm->_screen;
Talk &talk = *_vm->_talk;
JournalEntry &journalEntry = _journal[_index];
const byte *opcodes = talk._opcodes;
Common::String dirFilename = _directory[journalEntry._converseNum];
bool replyOnly = journalEntry._replyOnly;
@ -243,7 +244,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
byte c = *replyP++;
// Is it a control character?
if (c < SWITCH_SPEAKER) {
if (c < opcodes[0]) {
// Nope. Set flag for allowing control codes to insert spaces
ctrlSpace = true;
assert(c >= ' ');
@ -290,7 +291,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
byte v;
do {
v = *strP++;
} while (v && (v < SWITCH_SPEAKER) && (v != '.') && (v != '!') && (v != '?'));
} while (v && (v < opcodes[0]) && (v != '.') && (v != '!') && (v != '?'));
if (v == '?')
journalString += " asked, \"";
@ -306,11 +307,11 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
journalString += c;
do {
journalString += *replyP++;
} while (*replyP && *replyP < SWITCH_SPEAKER && *replyP != '{' && *replyP != '}');
} while (*replyP && *replyP < opcodes[0] && *replyP != '{' && *replyP != '}');
commentJustPrinted = false;
}
} else if (c == SWITCH_SPEAKER) {
} else if (c == opcodes[OP_SWITCH_SPEAKER]) {
if (!startOfReply) {
if (!commentFlag && !commentJustPrinted)
journalString += "\"\n";
@ -337,7 +338,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
byte v;
do {
v = *strP++;
} while (v && v < SWITCH_SPEAKER && v != '.' && v != '!' && v != '?');
} while (v && v < opcodes[0] && v != '.' && v != '!' && v != '?');
if (v == '?')
journalString += " asked, \"";
@ -345,59 +346,42 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
journalString += " said, \"";
} else {
// Control code, so move past it and any parameters
switch (c) {
case RUN_CANIMATION:
case ASSIGN_PORTRAIT_LOCATION:
case PAUSE:
case PAUSE_WITHOUT_CONTROL:
case WALK_TO_CANIMATION:
if (c == opcodes[OP_RUN_CANIMATION] || c == opcodes[OP_ASSIGN_PORTRAIT_LOCATION] ||
c == opcodes[OP_PAUSE] || c == opcodes[OP_PAUSE_WITHOUT_CONTROL] ||
c == opcodes[OP_WALK_TO_CANIMATION]) {
// These commands have a single parameter
++replyP;
break;
case ADJUST_OBJ_SEQUENCE:
} else if (c == opcodes[OP_ADJUST_OBJ_SEQUENCE]) {
replyP += (replyP[0] & 127) + replyP[1] + 2;
break;
case WALK_TO_COORDS:
case MOVE_MOUSE:
} else if (c == opcodes[OP_WALK_TO_COORDS] || c == opcodes[OP_MOVE_MOUSE]) {
replyP += 4;
break;
case SET_FLAG:
case IF_STATEMENT:
} else if (c == opcodes[OP_SET_FLAG] || c == opcodes[OP_IF_STATEMENT]) {
replyP += 2;
break;
case SFX_COMMAND:
case PLAY_PROLOGUE:
case CALL_TALK_FILE:
} else if (c == opcodes[OP_SFX_COMMAND] || c == opcodes[OP_PLAY_PROLOGUE] ||
c == opcodes[OP_CALL_TALK_FILE]) {
replyP += 8;
break;
case TOGGLE_OBJECT:
case ADD_ITEM_TO_INVENTORY:
case SET_OBJECT:
case DISPLAY_INFO_LINE:
case REMOVE_ITEM_FROM_INVENTORY:
} else if (c == opcodes[OP_TOGGLE_OBJECT] || c == opcodes[OP_ADD_ITEM_TO_INVENTORY] ||
c == opcodes[OP_SET_OBJECT] || c == opcodes[OP_DISPLAY_INFO_LINE] ||
c == opcodes[OP_REMOVE_ITEM_FROM_INVENTORY]) {
replyP += (*replyP & 127) + 1;
break;
case GOTO_SCENE:
} else if (c == opcodes[OP_GOTO_SCENE]) {
replyP += 5;
break;
case CARRIAGE_RETURN:
} else if (c == opcodes[OP_CARRIAGE_RETURN]) {
journalString += "\n";
break;
default:
break;
}
// Put a space in the output for a control character, unless it's
// immediately coming after another control character
if (ctrlSpace && c != ASSIGN_PORTRAIT_LOCATION && c != CARRIAGE_RETURN && !commentJustPrinted) {
if (ctrlSpace && c != opcodes[OP_ASSIGN_PORTRAIT_LOCATION] && c != opcodes[OP_CARRIAGE_RETURN] &&
!commentJustPrinted) {
journalString += " ";
ctrlSpace = false;
}

View File

@ -22,6 +22,7 @@
#include "sherlock/map.h"
#include "sherlock/sherlock.h"
#include "common/system.h"
namespace Sherlock {
@ -50,7 +51,7 @@ const byte *MapPaths::getPath(int srcLocation, int destLocation) {
/*----------------------------------------------------------------*/
Map::Map(SherlockEngine *vm) : _vm(vm), _topLine(SHERLOCK_SCREEN_WIDTH, 12) {
Map::Map(SherlockEngine *vm): _vm(vm), _topLine(g_system->getWidth(), 12) {
_active = false;
_mapCursors = nullptr;
_shapes = nullptr;
@ -64,8 +65,12 @@ Map::Map(SherlockEngine *vm) : _vm(vm), _topLine(SHERLOCK_SCREEN_WIDTH, 12) {
_oldCharPoint = 0;
_frameChangeFlag = false;
for (int idx = 0; idx < MAX_HOLMES_SEQUENCE; ++idx)
Common::fill(&_sequences[idx][0], &_sequences[idx][MAX_FRAME], 0);
// Initialise the initial walk sequence set
_walkSequences.resize(MAX_HOLMES_SEQUENCE);
for (int idx = 0; idx < MAX_HOLMES_SEQUENCE; ++idx) {
_walkSequences[idx]._sequences.resize(MAX_FRAME);
Common::fill(&_walkSequences[idx]._sequences[0], &_walkSequences[idx]._sequences[0] + MAX_FRAME, 0);
}
if (!_vm->isDemo())
loadData();
@ -79,12 +84,17 @@ void Map::loadPoints(int count, const int *xList, const int *yList, const int *t
void Map::loadSequences(int count, const byte *seq) {
for (int idx = 0; idx < count; ++idx, seq += MAX_FRAME)
Common::copy(seq, seq + MAX_FRAME, &_sequences[idx][0]);
Common::copy(seq, seq + MAX_FRAME, &_walkSequences[idx]._sequences[0]);
}
void Map::loadData() {
// TODO: Remove this
if (_vm->getGameID() == GType_RoseTattoo)
return;
// Load the list of location names
Common::SeekableReadStream *txtStream = _vm->_res->load("chess.txt");
Common::SeekableReadStream *txtStream = _vm->_res->load(
_vm->getGameID() == GType_SerratedScalpel ? "chess.txt" : "map.txt");
int streamSize = txtStream->size();
while (txtStream->pos() < streamSize) {
@ -283,7 +293,6 @@ void Map::setupSprites() {
p._type = CHARACTER;
p._position = Common::Point(12400, 5000);
p._sequenceNumber = 0;
p._sequences = &_sequences;
p._images = _shapes;
p._imageFrame = nullptr;
p._frameNumber = 0;
@ -296,8 +305,8 @@ void Map::setupSprites() {
p._noShapeSize = Common::Point(0, 0);
p._goto = Common::Point(28000, 15000);
p._status = 0;
p._walkSequences = _walkSequences;
p.setImageFrame();
scene._bgShapes.clear();
}

View File

@ -76,7 +76,7 @@ private:
ImageFile *_mapCursors;
ImageFile *_shapes;
ImageFile *_iconShapes;
byte _sequences[MAX_HOLMES_SEQUENCE][MAX_FRAME];
WalkSequences _walkSequences;
Point32 _lDrawnPos;
int _point;
bool _placesShown;

View File

@ -4,7 +4,12 @@ MODULE_OBJS = \
scalpel/darts.o \
scalpel/scalpel.o \
scalpel/drivers/adlib.o \
scalpel/scalpel_scene.o \
scalpel/scalpel_user_interface.o \
scalpel/settings.o \
tattoo/tattoo.o \
tattoo/tattoo_scene.o \
tattoo/tattoo_user_interface.o \
animation.o \
debugger.o \
detection.o \
@ -19,7 +24,6 @@ MODULE_OBJS = \
saveload.o \
scene.o \
screen.o \
settings.o \
sherlock.o \
sound.o \
surface.o \

View File

@ -272,6 +272,11 @@ bool Music::loadSong(int songNumber) {
return true;
}
bool Music::loadSong(const Common::String &songName) {
warning("TODO: Music::loadSong");
return false;
}
void Music::syncMusicSettings() {
_musicOn = !ConfMan.getBool("mute") && !ConfMan.getBool("music_mute");
}

View File

@ -73,6 +73,11 @@ public:
*/
bool loadSong(int songNumber);
/**
* Load a specified song
*/
bool loadSong(const Common::String &songName);
/**
* Start playing a song
*/

View File

@ -46,7 +46,7 @@ void Sprite::clear() {
_description = "";
_examine.clear();
_pickUp = "";
_sequences = nullptr;
_walkSequences.clear();
_images = nullptr;
_imageFrame = nullptr;
_walkCount = 0;
@ -63,12 +63,26 @@ void Sprite::clear() {
_status = 0;
_misc = 0;
_numFrames = 0;
_altImages = nullptr;
_altSequences = false;
Common::fill(&_stopFrames[0], &_stopFrames[8], (ImageFrame *)nullptr);
}
void Sprite::setImageFrame() {
int imageNumber = (*_sequences)[_sequenceNumber][_frameNumber] +
(*_sequences)[_sequenceNumber][0] - 2;
_imageFrame = &(*_images)[imageNumber];
int frameNum = MAX(_frameNumber, 0);
int imageNumber = _walkSequences[_sequenceNumber][frameNum];
if (IS_SERRATED_SCALPEL)
imageNumber = imageNumber + _walkSequences[_sequenceNumber][0] - 2;
else if (imageNumber > _numFrames)
imageNumber = 1;
// Get the images to use
ImageFile *images = _altSequences ? _altImages : _images;
assert(images);
// Set the frame pointer
_imageFrame = &(*images)[imageNumber];
}
void Sprite::adjustSprite() {
@ -113,14 +127,14 @@ void Sprite::adjustSprite() {
people.gotoStand(*this);
}
} else if (!map._active) {
_position.y = CLIP((int)_position.y, UPPER_LIMIT, LOWER_LIMIT);
_position.x = CLIP((int)_position.x, LEFT_LIMIT, RIGHT_LIMIT);
_position.y = CLIP((int)_position.y, (int)UPPER_LIMIT, (int)LOWER_LIMIT);
_position.x = CLIP((int)_position.x, (int)LEFT_LIMIT, (int)RIGHT_LIMIT);
}
if (!map._active || (map._frameChangeFlag = !map._frameChangeFlag))
++_frameNumber;
if ((*_sequences)[_sequenceNumber][_frameNumber] == 0) {
if (_walkSequences[_sequenceNumber][_frameNumber] == 0) {
switch (_sequenceNumber) {
case STOP_UP:
case STOP_DOWN:
@ -352,6 +366,34 @@ void Sprite::checkSprite() {
/*----------------------------------------------------------------*/
void WalkSequence::load(Common::SeekableReadStream &s) {
char buffer[9];
s.read(buffer, 9);
_vgsName = Common::String(buffer);
_horizFlip = s.readByte() != 0;
_sequences.resize(s.readUint16LE());
s.read(&_sequences[0], _sequences.size());
}
/*----------------------------------------------------------------*/
WalkSequences &WalkSequences::operator=(const WalkSequences &src) {
resize(src.size());
for (uint idx = 0; idx < size(); ++idx) {
const WalkSequence &wSrc = src[idx];
WalkSequence &wDest = (*this)[idx];
wDest._horizFlip = wSrc._horizFlip;
wDest._sequences.resize(wSrc._sequences.size());
Common::copy(&wSrc._sequences[0], &wSrc._sequences[0] + wSrc._sequences.size(), &wDest._sequences[0]);
}
return *this;
}
/*----------------------------------------------------------------*/
void ActionType::load(Common::SeekableReadStream &s) {
char buffer[12];
@ -373,9 +415,14 @@ UseType::UseType() {
_useFlag = 0;
}
void UseType::load(Common::SeekableReadStream &s) {
void UseType::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
char buffer[12];
if (isRoseTattoo) {
s.read(buffer, 12);
_verb = Common::String(buffer);
}
_cAnimNum = s.readByte();
_cAnimSpeed = s.readByte();
if (_cAnimSpeed & 0x80)
@ -387,7 +434,9 @@ void UseType::load(Common::SeekableReadStream &s) {
}
_useFlag = s.readSint16LE();
s.skip(6);
if (!isRoseTattoo)
s.skip(6);
s.read(buffer, 12);
_target = Common::String(buffer);
@ -434,9 +483,16 @@ Object::Object() {
_descOffset = 0;
_seqCounter2 = 0;
_seqSize = 0;
_quickDraw = 0;
_scaleVal = 0;
_requiredFlag1 = 0;
_gotoSeq = 0;
_talkSeq = 0;
_restoreSlot = 0;
}
void Object::load(Common::SeekableReadStream &s) {
void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
char buffer[41];
s.read(buffer, 12);
_name = Common::String(buffer);
@ -468,10 +524,10 @@ void Object::load(Common::SeekableReadStream &s) {
_goto.x = s.readSint16LE();
_goto.y = s.readSint16LE();
_pickup = s.readByte();
_defaultCommand = s.readByte();
_lookFlag = s.readUint16LE();
_pickupFlag = s.readUint16LE();
_pickup = isRoseTattoo ? 0 : s.readByte();
_defaultCommand = isRoseTattoo ? 0 : s.readByte();
_lookFlag = s.readSint16LE();
_pickupFlag = isRoseTattoo ? 0 : s.readSint16LE();
_requiredFlag = s.readSint16LE();
_noShapeSize.x = s.readUint16LE();
_noShapeSize.y = s.readUint16LE();
@ -479,26 +535,45 @@ void Object::load(Common::SeekableReadStream &s) {
_misc = s.readByte();
_maxFrames = s.readUint16LE();
_flags = s.readByte();
_aOpen.load(s);
if (!isRoseTattoo)
_aOpen.load(s);
_aType = (AType)s.readByte();
_lookFrames = s.readByte();
_seqCounter = s.readByte();
_lookPosition.x = s.readUint16LE();
_lookPosition.y = s.readByte();
_lookPosition.y = isRoseTattoo ? s.readSint16LE() : s.readByte();
_lookFacing = s.readByte();
_lookcAnim = s.readByte();
_aClose.load(s);
if (!isRoseTattoo)
_aClose.load(s);
_seqStack = s.readByte();
_seqTo = s.readByte();
_descOffset = s.readUint16LE();
_seqCounter2 = s.readByte();
_seqSize = s.readUint16LE();
s.skip(1);
_aMove.load(s);
s.skip(8);
for (int idx = 0; idx < USE_COUNT; ++idx)
_use[idx].load(s);
if (isRoseTattoo) {
for (int idx = 0; idx < 6; ++idx)
_use[idx].load(s, true);
_quickDraw = s.readByte();
_scaleVal = s.readUint16LE();
_requiredFlag1 = s.readSint16LE();
_gotoSeq = s.readByte();
_talkSeq = s.readByte();
_restoreSlot = s.readByte();
} else {
s.skip(1);
_aMove.load(s);
s.skip(8);
for (int idx = 0; idx < 4; ++idx)
_use[idx].load(s, false);
}
}
void Object::toggleHidden() {
@ -1032,17 +1107,30 @@ const Common::Rect Object::getOldBounds() const {
/*----------------------------------------------------------------*/
void CAnim::load(Common::SeekableReadStream &s) {
void CAnim::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
char buffer[12];
s.read(buffer, 12);
_name = Common::String(buffer);
s.read(_sequences, 30);
if (isRoseTattoo) {
Common::fill(&_sequences[0], &_sequences[30], 0);
_size = s.readUint32LE();
} else {
s.read(_sequences, 30);
}
_position.x = s.readSint16LE();
_position.y = s.readSint16LE();
_size = s.readUint32LE();
_type = (SpriteType)s.readUint16LE();
_flags = s.readByte();
if (isRoseTattoo) {
_flags = s.readByte();
_scaleVal = s.readSint16LE();
} else {
_size = s.readUint32LE();
_type = (SpriteType)s.readUint16LE();
_flags = s.readByte();
}
_goto.x = s.readSint16LE();
_goto.y = s.readSint16LE();
_gotoDir = s.readSint16LE();
@ -1053,6 +1141,22 @@ void CAnim::load(Common::SeekableReadStream &s) {
/*----------------------------------------------------------------*/
CAnimStream::CAnimStream() {
_stream = nullptr;
_frameSize = 0;
_images = nullptr;
_imageFrame = nullptr;
_flags = 0;
_scaleVal = 0;
_zPlacement = 0;
}
void CAnimStream::getNextFrame() {
// TODO
}
/*----------------------------------------------------------------*/
SceneImage::SceneImage() {
_images = nullptr;
_maxFrames = 0;

View File

@ -46,7 +46,10 @@ enum SpriteType {
REMOVE = 5, // Object should be removed next frame
NO_SHAPE = 6, // Background object with no shape
HIDDEN = 7, // Hidden backgruond object
HIDE_SHAPE = 8 // Object needs to be hidden
HIDE_SHAPE = 8, // Object needs to be hidden
// Rose Tattoo
HIDDEN_CHARACTER = 128
};
enum AType {
@ -73,6 +76,7 @@ enum {
#define MAX_HOLMES_SEQUENCE 16
#define MAX_FRAME 30
#define FIXED_INT_MULTIPLIER 100
// code put into sequences to defines 1-10 type seqs
#define SEQ_TO_CODE 67
@ -98,65 +102,24 @@ public:
void operator-=(const Point32 &delta) { x -= delta.x; y -= delta.y; }
};
class Sprite {
private:
static SherlockEngine *_vm;
struct WalkSequence {
Common::String _vgsName;
bool _horizFlip;
Common::Array<byte> _sequences;
WalkSequence() : _horizFlip(false) {}
const byte &operator[](int idx) { return _sequences[idx]; }
/**
* Load data for the sequence from a stream
*/
void load(Common::SeekableReadStream &s);
};
class WalkSequences : public Common::Array < WalkSequence > {
public:
Common::String _name;
Common::String _description;
Common::StringArray _examine; // Examine in-depth description
Common::String _pickUp; // Message for if you can't pick up object
const uint8 (*_sequences)[MAX_HOLMES_SEQUENCE][MAX_FRAME]; // Holds animation sequences
ImageFile *_images; // Sprite images
ImageFrame *_imageFrame; // Pointer to shape in the images
int _walkCount; // Character walk counter
int _allow; // Allowed menu commands - ObjectAllow
int _frameNumber; // Frame number in rame sequence to draw
int _sequenceNumber; // Sequence being used
Point32 _position; // Current position
Point32 _delta; // Momvement delta
Common::Point _oldPosition; // Old position
Common::Point _oldSize; // Image's old size
Common::Point _goto; // Walk destination
SpriteType _type; // Type of object
Common::Point _noShapeSize; // Size of a NO_SHAPE
int _status; // Status: open/closed, moved/not moved
int8 _misc; // Miscellaneous use
int _numFrames; // How many frames the object has
public:
Sprite() { clear(); }
static void setVm(SherlockEngine *vm) { _vm = vm; }
/**
* Reset the data for the sprite
*/
void clear();
/**
* Updates the image frame poiner for the sprite
*/
void setImageFrame();
/**
* This adjusts the sprites position, as well as it's animation sequence:
*/
void adjustSprite();
/**
* Checks the sprite's position to see if it's collided with any special objects
*/
void checkSprite();
/**
* Return frame width
*/
int frameWidth() const { return _imageFrame ? _imageFrame->_frame.w : 0; }
/**
* Return frame height
*/
int frameHeight() const { return _imageFrame ? _imageFrame->_frame.h : 0; }
WalkSequences &operator=(const WalkSequences &src);
};
enum { REVERSE_DIRECTION = 0x80 };
@ -179,13 +142,106 @@ struct UseType {
Common::String _names[NAMES_COUNT];
int _useFlag; // Which flag USE will set (if any)
Common::String _target;
Common::String _verb;
UseType();
/**
* Load the data for the UseType
*/
void load(Common::SeekableReadStream &s);
void load(Common::SeekableReadStream &s, bool isRoseTattoo);
};
class Sprite {
private:
static SherlockEngine *_vm;
public:
Common::String _name;
Common::String _description;
Common::String _examine; // Examine in-depth description
Common::String _pickUp; // Message for if you can't pick up object
WalkSequences _walkSequences; // Holds animation sequences
ImageFile *_images; // Sprite images
ImageFrame *_imageFrame; // Pointer to shape in the images
int _walkCount; // Character walk counter
int _allow; // Allowed menu commands - ObjectAllow
int _frameNumber; // Frame number in rame sequence to draw
int _sequenceNumber; // Sequence being used
Point32 _position; // Current position
Point32 _delta; // Momvement delta
Common::Point _oldPosition; // Old position
Common::Point _oldSize; // Image's old size
Common::Point _goto; // Walk destination
SpriteType _type; // Type of object
Common::Point _noShapeSize; // Size of a NO_SHAPE
int _status; // Status: open/closed, moved/not moved
int8 _misc; // Miscellaneous use
int _numFrames; // How many frames the object has
// Rose Tattoo fields
int _startSeq; // Frame sequence starts at
int _flags; // Flags for the sprite
int _aType; // Tells if this is an object, person, talk, etc.
int _lookFrames; // How many frames to play of a canim before pausing
int _seqCounter; // How many times the sequence has been run
Common::Point _lookPosition; // Where to look when examining object
int _lookFacing; // Direction to face when examining object
int _lookCAnim;
int _seqStack; // Allow gosubs to return to calling frame
int _seqTo; // Allows 1-5, 8-3 type sequences encoded in 2 bytes
uint _descOffset; // Tells where description starts in description text for scene
int _seqCounter2; // Counter of calling frame sequence
uint _seqSize; // Size of sequence
UseType _use[6];
int _quickDraw; // Flag telling whether to use quick draw routine or not
int _scaleVal; // Tells how to scale the sprite
int _requiredFlags1; // This flag must also be set, or the sprite is hidden
int _gotoSeq; // Used by Talk to tell which sequence to goto when able
int _talkSeq; // Tells which talk sequence currently in use (Talk or Listen)
int _restoreSlot; // Used when talk returns to the previous sequence
ImageFrame *_stopFrames[8]; // Stop/rest frame for each direction
ImageFile *_altImages; // Images used for alternate NPC sequences
bool _altSequences; // Which of the sequences the alt graphics apply to (0: main, 1=NPC seq)
int _centerWalk; // Flag telling the walk code to offset the walk destination
Common::Point _adjust; // Fine tuning adjustment to position when drawn
int _oldWalkSequence;
public:
Sprite() { clear(); }
static void setVm(SherlockEngine *vm) { _vm = vm; }
/**
* Reset the data for the sprite
*/
void clear();
/**
* Updates the image frame poiner for the sprite
*/
void setImageFrame();
/**
* This adjusts the sprites position, as well as it's animation sequence:
*/
void adjustSprite();
/**
* Checks the sprite's position to see if it's collided with any special objects
*/
void checkSprite();
/**
* Return frame width
*/
int frameWidth() const { return _imageFrame ? _imageFrame->_frame.w : 0; }
/**
* Return frame height
*/
int frameHeight() const { return _imageFrame ? _imageFrame->_frame.h : 0; }
};
enum { OBJ_BEHIND = 1, OBJ_FLIPPED = 2, OBJ_FORWARD = 4, TURNON_OBJ = 0x20, TURNOFF_OBJ = 0x40 };
@ -233,35 +289,45 @@ public:
int _pickup;
int _defaultCommand; // Default right-click command
int _lookFlag; // Which flag LOOK will set (if any)
int _pickupFlag; // Which flag PICKUP will set (if any)
int _requiredFlag; // Object will be hidden if not set
Common::Point _noShapeSize; // Size of a NO_SHAPE
int _status; // Status (open/closed, moved/not)
int8 _misc; // Misc field -- use varies with type
int _maxFrames; // Number of frames
int _flags; // Tells if object can be walked behind
ActionType _aOpen; // Holds data for moving object
AType _aType; // Tells if this is an object, person, talk, etc.
int _lookFrames; // How many frames to play of the look anim before pausing
int _seqCounter; // How many times this sequence has been executed
Common::Point _lookPosition; // Where to walk when examining object
int _lookFacing; // Direction to face when examining object
int _lookcAnim;
ActionType _aClose;
int _seqStack; // Allows gosubs to return to calling frame
int _seqTo; // Allows 1-5, 8-3 type sequences encoded in 2 bytes
uint _descOffset; // Tells where description starts in DescText
int _seqCounter2; // Counter of calling frame sequence
uint _seqSize; // Tells where description starts
UseType _use[6]; // Serrated Scalpel uses 4, Rose Tattoo 6
// Serrated Scalpel fields
int _pickupFlag; // Which flag PICKUP will set (if any)
ActionType _aOpen; // Holds data for moving object
ActionType _aClose;
ActionType _aMove;
UseType _use[USE_COUNT];
// Rose Tattoo fields
int _quickDraw;
int _scaleVal;
int _requiredFlag1;
int _gotoSeq;
int _talkSeq;
int _restoreSlot;
Object();
/**
* Load the data for the object
*/
void load(Common::SeekableReadStream &s);
void load(Common::SeekableReadStream &s, bool isRoseTattoo);
/**
* Toggle the type of an object between hidden and active
@ -326,20 +392,45 @@ public:
struct CAnim {
Common::String _name; // Name
byte _sequences[MAX_FRAME]; // Animation sequences
Common::Point _position; // Position
int _size; // Size of uncompressed animation
SpriteType _type;
int _flags; // Tells if can be walked behind
Common::Point _goto; // coords holmes should walk to before starting canim
int _gotoDir;
Common::Point _teleportPos; // Location Holmes shoul teleport to after
int _teleportDir; // playing canim
// Scalpel specific
byte _sequences[MAX_FRAME]; // Animation sequences
SpriteType _type;
// Rose Tattoo specific
int _scaleVal; // How much the canim is scaled
/**
* Load the data for the animation
*/
void load(Common::SeekableReadStream &s);
void load(Common::SeekableReadStream &s, bool isRoseTattoo);
};
struct CAnimStream {
Common::SeekableReadStream *_stream; // Stream to read frames from
int _frameSize; // Temporary used to store the frame size
void *_images; // TOOD: FIgure out hwo to hook up ImageFile with streaming support
ImageFrame *_imageFrame;
Common::Point _position; // Animation position
Common::Rect _oldBounds; // Bounds of previous frame
Common::Rect _removeBounds; // Remove area for just drawn frame
int _flags; // Flags
int _scaleVal; // Specifies the scale amount
int _zPlacement; // Used by doBgAnim for determining Z order
CAnimStream();
void getNextFrame();
};
struct SceneImage {

View File

@ -50,10 +50,38 @@ static const uint8 CHARACTER_SEQUENCES[MAX_HOLMES_SEQUENCE][MAX_FRAME] = {
{ 52, 1, 2, 3, 4, 0 } // Goto Stand Down Left
};
// Rose Tattoo walk image libraries
// Walk resources within WALK.LIB
#define NUM_IN_WALK_LIB 10
const char *const WALK_LIB_NAMES[10] = {
"SVGAWALK.VGS",
"COATWALK.VGS",
"WATSON.VGS",
"NOHAT.VGS",
"TUPRIGHT.VGS",
"TRIGHT.VGS",
"TDOWNRG.VGS",
"TWUPRIGH.VGS",
"TWRIGHT.VGS",
"TWDOWNRG.VGS"
};
/*----------------------------------------------------------------*/
Person::Person() : Sprite(), _walkLoaded(false), _npcIndex(0), _npcStack(0), _npcPause(false) {
Common::fill(&_npcPath[0], &_npcPath[MAX_NPC_PATH], 0);
_tempX = _tempScaleVal = 0;
}
void Person::clearNPC() {
Common::fill(&_npcPath[0], &_npcPath[MAX_NPC_PATH], 0);
_npcIndex = _npcStack = 0;
_npcName = "";
}
/*----------------------------------------------------------------*/
People::People(SherlockEngine *vm) : _vm(vm), _player(_data[0]) {
_walkLoaded = false;
_holmesOn = true;
_oldWalkSequence = -1;
_allowWalkAbort = false;
@ -68,66 +96,168 @@ People::People(SherlockEngine *vm) : _vm(vm), _player(_data[0]) {
_holmesQuotient = 0;
_hSavedPos = Common::Point(-1, -1);
_hSavedFacing = -1;
_forceWalkReload = false;
_useWalkLib = false;
_walkControl = 0;
_portrait._sequences = new byte[32];
}
People::~People() {
if (_walkLoaded)
delete _data[PLAYER]._images;
for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
if (_data[idx]._walkLoaded)
delete _data[PLAYER]._images;
}
delete _talkPics;
delete[] _portrait._sequences;
}
void People::reset() {
// Note: The engine has theoretical support for two player characters but only the first one is used.
// Watson is, instead, handled by a different sprite in each scene, with a very simple initial movement, if any
Sprite &p = _data[PLAYER];
_data[0]._description = "Sherlock Holmes!";
p._description = "Sherlock Holmes!";
p._type = CHARACTER;
p._position = Common::Point(10000, 11000);
p._sequenceNumber = STOP_DOWNRIGHT;
p._sequences = &CHARACTER_SEQUENCES;
p._imageFrame = nullptr;
p._frameNumber = 1;
p._delta = Common::Point(0, 0);
p._oldPosition = Common::Point(0, 0);
p._oldSize = Common::Point(0, 0);
p._misc = 0;
p._walkCount = 0;
p._pickUp = "";
p._allow = 0;
p._noShapeSize = Common::Point(0, 0);
p._goto = Common::Point(0, 0);
p._status = 0;
// Note: Serrated Scalpel only uses a single Person slot for Sherlock.. Watson is handled by scene sprites
int count = IS_SERRATED_SCALPEL ? 1 : MAX_CHARACTERS;
for (int idx = 0; idx < count; ++idx) {
Sprite &p = _data[idx];
p._type = (idx == 0) ? CHARACTER : INVALID;
if (IS_SERRATED_SCALPEL)
p._position = Point32(10000, 11000);
else
p._position = Point32(36000, 29000);
p._sequenceNumber = STOP_DOWNRIGHT;
p._imageFrame = nullptr;
p._frameNumber = 1;
p._delta = Common::Point(0, 0);
p._oldPosition = Common::Point(0, 0);
p._oldSize = Common::Point(0, 0);
p._misc = 0;
p._walkCount = 0;
p._pickUp = "";
p._allow = 0;
p._noShapeSize = Common::Point(0, 0);
p._goto = Common::Point(0, 0);
p._status = 0;
p._seqTo = 0;
p._seqCounter = p._seqCounter2 = 0;
p._seqStack = 0;
p._gotoSeq = p._talkSeq = 0;
p._restoreSlot = 0;
p._startSeq = 0;
p._altImages = nullptr;
p._altSequences = 0;
p._centerWalk = true;
p._adjust = Common::Point(0, 0);
// Load the default walk sequences
p._oldWalkSequence = -1;
p._walkSequences.clear();
if (IS_SERRATED_SCALPEL) {
p._walkSequences.resize(MAX_HOLMES_SEQUENCE);
for (int seqIdx = 0; seqIdx < MAX_HOLMES_SEQUENCE; ++seqIdx) {
p._walkSequences[seqIdx]._sequences.clear();
const byte *pSrc = &CHARACTER_SEQUENCES[seqIdx][0];
do {
p._walkSequences[seqIdx]._sequences.push_back(*pSrc);
} while (*pSrc++);
}
}
}
// Reset any walk path in progress when Sherlock leaves scenes
_walkTo.clear();
}
bool People::loadWalk() {
if (_walkLoaded) {
return false;
} else {
_data[PLAYER]._images = new ImageFile("walk.vgs");
_data[PLAYER].setImageFrame();
_walkLoaded = true;
Resources &res = *_vm->_res;
bool result = false;
return true;
if (IS_SERRATED_SCALPEL) {
if (_data[PLAYER]._walkLoaded) {
return false;
} else {
_data[PLAYER]._images = new ImageFile("walk.vgs");
_data[PLAYER].setImageFrame();
_data[PLAYER]._walkLoaded = true;
result = true;
}
} else {
for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
if (!_data[idx]._walkLoaded && (_data[idx]._type == CHARACTER || _data[idx]._type == HIDDEN_CHARACTER)) {
if (_data[idx]._type == HIDDEN_CHARACTER)
_data[idx]._type = INVALID;
// See if this is one of the more used Walk Graphics stored in WALK.LIB
for (int libNum = 0; libNum < NUM_IN_WALK_LIB; ++libNum) {
if (!_data[0]._walkVGSName.compareToIgnoreCase(WALK_LIB_NAMES[libNum])) {
_useWalkLib = true;
break;
}
}
// Load the images for the character
_data[idx]._images = new ImageFile(_data[idx]._walkVGSName, false);
_data[idx]._numFrames = _data[idx]._images->size();
// Load walk sequence data
Common::String fname = Common::String(_data[idx]._walkVGSName.c_str(), strchr(_data[idx]._walkVGSName.c_str(), '.'));
fname += ".SEQ";
// Load the walk sequence data
Common::SeekableReadStream *stream = res.load(fname, _useWalkLib ? "walk.lib" : "vgs.lib");
_data[idx]._walkSequences.resize(stream->readByte());
for (uint seqNum = 0; seqNum < _data[idx]._walkSequences.size(); ++seqNum)
_data[idx]._walkSequences[seqNum].load(*stream);
// Close the sequences resource
delete stream;
_useWalkLib = false;
_data[idx]._frameNumber = 0;
_data[idx].setImageFrame();
// Set the stop Frames pointers
for (int dirNum = 0; dirNum < 8; ++dirNum) {
int count = 0;
while (_data[idx]._walkSequences[dirNum + 8][count] != 0)
++count;
count += 2;
count = _data[idx]._walkSequences[dirNum + 8][count] - 1;
_data[idx]._stopFrames[dirNum] = &(*_data[idx]._images)[count];
}
result = true;
_data[idx]._walkLoaded = true;
} else if (_data[idx]._type != CHARACTER) {
_data[idx]._walkLoaded = false;
}
}
}
_forceWalkReload = false;
return result;
}
bool People::freeWalk() {
if (_walkLoaded) {
delete _player._images;
_player._images = nullptr;
bool result = false;
_walkLoaded = false;
return true;
} else {
return false;
for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
if (_data[idx]._walkLoaded) {
delete _data[idx]._images;
_data[idx]._images = nullptr;
_data[idx]._walkLoaded = false;
result = true;
}
}
return result;
}
void People::setWalking() {
@ -553,9 +683,24 @@ void People::setTalking(int speaker) {
void People::synchronize(Common::Serializer &s) {
s.syncAsByte(_holmesOn);
s.syncAsSint16LE(_player._position.x);
s.syncAsSint16LE(_player._position.y);
s.syncAsSint16LE(_player._sequenceNumber);
if (IS_SERRATED_SCALPEL) {
s.syncAsSint16LE(_player._position.x);
s.syncAsSint16LE(_player._position.y);
s.syncAsSint16LE(_player._sequenceNumber);
} else {
for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
Person &p = _data[idx];
s.syncAsSint16LE(p._position.x);
s.syncAsSint16LE(p._position.y);
s.syncAsSint16LE(p._sequenceNumber);
s.syncAsSint16LE(p._type);
s.syncString(p._walkVGSName);
s.syncString(p._description);
s.syncString(p._examine);
}
}
s.syncAsSint16LE(_holmesQuotient);
if (s.isLoading()) {

View File

@ -30,13 +30,13 @@
namespace Sherlock {
// Player definitions. The game has theoretical support for two player characters but only the first one is used.
// Watson is, instead, handled by a different sprite in each scene, with a very simple initial movement, if any
enum PeopleId {
PLAYER = 0,
AL = 0,
PEG = 1,
MAX_PLAYERS = 2
MAX_CHARACTERS = 6,
MAX_NPC = 5,
MAX_NPC_PATH = 200
};
// Animation sequence identifiers for characters
@ -63,20 +63,37 @@ struct PersonData {
_name(name), _portrait(portrait), _stillSequences(stillSequences), _talkSequences(talkSequences) {}
};
class SherlockEngine;
class Person : public Sprite {
public:
Person() : Sprite() {}
bool _walkLoaded;
Common::String _portrait;
// NPC related fields
int _npcIndex;
int _npcStack;
bool _npcPause;
byte _npcPath[MAX_NPC_PATH];
Common::String _npcName;
int _tempX;
int _tempScaleVal;
// Rose Tattoo fields
Common::String _walkVGSName; // Name of walk library person is using
public:
Person();
/**
* Clear the NPC related data
*/
void clearNPC();
};
class SherlockEngine;
class People {
private:
SherlockEngine *_vm;
Person _data[MAX_PLAYERS];
bool _walkLoaded;
Person _data[MAX_CHARACTERS];
int _oldWalkSequence;
int _srcZone, _destZone;
public:
@ -97,24 +114,23 @@ public:
bool _speakerFlip;
bool _holmesFlip;
int _holmesQuotient;
bool _forceWalkReload;
bool _useWalkLib;
int _walkControl;
public:
People(SherlockEngine *vm);
~People();
Person &operator[](PeopleId id) {
assert(id < MAX_PLAYERS);
assert(id < MAX_CHARACTERS);
return _data[id];
}
Person &operator[](int idx) {
assert(idx < MAX_PLAYERS);
assert(idx < MAX_CHARACTERS);
return _data[idx];
}
/**
* Returns true if Sherlock is visible on the screen and enabled
*/
bool isHolmesActive() const { return _walkLoaded && _holmesOn; }
/**
* Reset the player data
*/

View File

@ -65,7 +65,7 @@ void Cache::load(const Common::String &name, Common::SeekableReadStream &stream)
// Check whether the file is compressed
if (signature == MKTAG('L', 'Z', 'V', 26)) {
// It's compressed, so decompress the file and store it's data in the cache entry
Common::SeekableReadStream *decompressed = _vm->_res->decompressLZ(stream);
Common::SeekableReadStream *decompressed = _vm->_res->decompress(stream);
cacheEntry.resize(decompressed->size());
decompressed->read(&cacheEntry[0], decompressed->size());
@ -91,9 +91,12 @@ Resources::Resources(SherlockEngine *vm) : _vm(vm), _cache(vm) {
if (_vm->_interactiveFl) {
addToCache("vgs.lib");
addToCache("talk.lib");
addToCache("sequence.txt");
addToCache("journal.txt");
addToCache("portrait.lib");
if (IS_SERRATED_SCALPEL) {
addToCache("sequence.txt");
addToCache("portrait.lib");
}
}
}
@ -103,8 +106,11 @@ void Resources::addToCache(const Common::String &filename) {
// Check to see if the file is a library
Common::SeekableReadStream *stream = load(filename);
uint32 header = stream->readUint32BE();
if (header == MKTAG('L', 'I', 'B', 26))
loadLibraryIndex(filename, stream);
loadLibraryIndex(filename, stream, false);
else if (header == MKTAG('L', 'I', 'C', 26))
loadLibraryIndex(filename, stream, true);
delete stream;
}
@ -159,12 +165,14 @@ Common::SeekableReadStream *Resources::load(const Common::String &filename) {
void Resources::decompressIfNecessary(Common::SeekableReadStream *&stream) {
bool isCompressed = stream->readUint32BE() == MKTAG('L', 'Z', 'V', 26);
stream->seek(-4, SEEK_CUR);
if (isCompressed) {
Common::SeekableReadStream *newStream = decompressLZ(*stream);
int outSize = stream->readUint32LE();
Common::SeekableReadStream *newStream = decompressLZ(*stream, outSize);
delete stream;
stream = newStream;
} else {
stream->seek(-4, SEEK_CUR);
}
}
@ -174,7 +182,7 @@ Common::SeekableReadStream *Resources::load(const Common::String &filename, cons
// Check if the library has already had it's index read, and if not, load it
if (!_indexes.contains(libraryFile))
loadLibraryIndex(libraryFile, libStream);
loadLibraryIndex(libraryFile, libStream, false);
// Extract the data for the specified resource and return it
LibraryEntry &entry = _indexes[libraryFile][filename];
@ -192,7 +200,7 @@ bool Resources::exists(const Common::String &filename) const {
}
void Resources::loadLibraryIndex(const Common::String &libFilename,
Common::SeekableReadStream *stream) {
Common::SeekableReadStream *stream, bool isNewStyle) {
uint32 offset, nextOffset;
// Create an index entry
@ -203,6 +211,9 @@ void Resources::loadLibraryIndex(const Common::String &libFilename,
stream->seek(4);
int count = stream->readUint16LE();
if (isNewStyle)
stream->seek((count + 1) * 8, SEEK_CUR);
// Loop through reading in the entries
for (int idx = 0; idx < count; ++idx) {
// Read the name of the resource
@ -231,24 +242,48 @@ int Resources::resourceIndex() const {
return _resourceIndex;
}
Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &source) {
if (_vm->getGameID() == GType_SerratedScalpel) {
uint32 id = source.readUint32BE();
assert(id == MKTAG('L', 'Z', 'V', 0x1A));
}
Common::SeekableReadStream *Resources::decompress(Common::SeekableReadStream &source) {
// This variation can't be used by Rose Tattoo, since compressed resources include the input size,
// not the output size. Which means their decompression has to be done via passed buffers
assert(_vm->getGameID() == GType_SerratedScalpel);
uint32 size = source.readUint32LE();
return decompressLZ(source, size);
uint32 id = source.readUint32BE();
assert(id == MKTAG('L', 'Z', 'V', 0x1A));
uint32 outputSize = source.readUint32LE();
return decompressLZ(source, outputSize);
}
Common::SeekableReadStream *Resources::decompress(Common::SeekableReadStream &source, uint32 outSize) {
int inSize = (_vm->getGameID() == GType_RoseTattoo) ? source.readUint32LE() : -1;
byte *outBuffer = (byte *)malloc(outSize);
Common::MemoryReadStream *outStream = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES);
decompressLZ(source, outBuffer, outSize, inSize);
return outStream;
}
void Resources::decompress(Common::SeekableReadStream &source, byte *buffer, uint32 outSize) {
int inputSize = (_vm->getGameID() == GType_RoseTattoo) ? source.readUint32LE() : -1;
decompressLZ(source, buffer, outSize, inputSize);
}
Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &source, uint32 outSize) {
byte *dataOut = (byte *)malloc(outSize);
decompressLZ(source, dataOut, outSize, -1);
return new Common::MemoryReadStream(dataOut, outSize, DisposeAfterUse::YES);
}
void Resources::decompressLZ(Common::SeekableReadStream &source, byte *outBuffer, int32 outSize, int32 inSize) {
byte lzWindow[4096];
uint16 lzWindowPos;
uint16 cmd;
byte *outBuffer = (byte *)malloc(outSize);
byte *outBufferEnd = outBuffer + outSize;
Common::MemoryReadStream *outS = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES);
int endPos = source.pos() + inSize;
memset(lzWindow, 0xFF, 0xFEE);
lzWindowPos = 0xFEE;
@ -264,8 +299,7 @@ Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &
*outBuffer++ = literal;
lzWindow[lzWindowPos] = literal;
lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
}
else {
} else {
int copyPos, copyLen;
copyPos = source.readByte();
copyLen = source.readByte();
@ -279,9 +313,7 @@ Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &
lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
}
}
} while (outBuffer < outBufferEnd);
return outS;
} while ((outSize == -1 || outBuffer < outBufferEnd) && (inSize == -1 || source.pos() < endPos));
}
/*----------------------------------------------------------------*/
@ -325,13 +357,14 @@ void ImageFile::load(Common::SeekableReadStream &stream, bool skipPalette, bool
// Animation cutscene image files use a 16-bit x offset
frame._offset.x = stream.readUint16LE();
frame._rleEncoded = (frame._offset.x & 0xff) == 1;
frame._offset.y = stream.readByte();
} else {
// Standard image files have a separate byte for the RLE flag, and an 8-bit X offset
frame._rleEncoded = stream.readByte() == 1;
frame._offset.x = stream.readByte();
frame._offset.y = stream.readByte();
}
frame._offset.y = stream.readByte();
frame._rleEncoded = !skipPalette && frame._rleEncoded;
if (frame._paletteBase) {
@ -385,6 +418,28 @@ void ImageFile::decompressFrame(ImageFrame &frame, const byte *src) {
*pDest++ = *src & 0xF;
*pDest++ = (*src >> 4);
}
} else if (frame._rleEncoded && _vm->getGameID() == GType_RoseTattoo) {
// Rose Tattoo run length encoding doesn't use the RLE marker byte
byte *dst = (byte *)frame._frame.getPixels();
for (int yp = 0; yp < frame._height; ++yp) {
int xSize = frame._width;
while (xSize > 0) {
// Skip a given number of pixels
byte skip = *src++;
dst += skip;
xSize -= skip;
if (!xSize)
break;
// Get a run length, and copy the following number of pixels
int rleCount = *src++;
xSize -= rleCount;
while (rleCount-- > 0)
*dst++ = *src++;
}
assert(xSize == 0);
}
} else if (frame._rleEncoded) {
// RLE encoded
byte *dst = (byte *)frame._frame.getPixels();
@ -411,4 +466,34 @@ void ImageFile::decompressFrame(ImageFrame &frame, const byte *src) {
}
}
/*----------------------------------------------------------------*/
int ImageFrame::sDrawXSize(int scaleVal) const {
int width = _width;
int scale = scaleVal == 0 ? 1 : scaleVal;
if (scaleVal >= 256)
--width;
int result = width * 256 / scale;
if (scaleVal >= 256)
++result;
return result;
}
int ImageFrame::sDrawYSize(int scaleVal) const {
int height = _height;
int scale = scaleVal == 0 ? 1 : scaleVal;
if (scaleVal >= 256)
--height;
int result = height * 256 / scale;
if (scaleVal >= 256)
++result;
return result;
}
} // End of namespace Sherlock

View File

@ -90,7 +90,7 @@ private:
/**
* Reads in the index from a library file, and caches it's index for later use
*/
void loadLibraryIndex(const Common::String &libFilename, Common::SeekableReadStream *stream);
void loadLibraryIndex(const Common::String &libFilename, Common::SeekableReadStream *stream, bool isNewStyle);
public:
Resources(SherlockEngine *vm);
@ -140,14 +140,29 @@ public:
int resourceIndex() const;
/**
* Decompresses an LZW block of data with a specified output size
* Decompresses LZW compressed data
*/
Common::SeekableReadStream *decompress(Common::SeekableReadStream &source);
/**
* Decompresses LZW compressed data
*/
Common::SeekableReadStream *decompress(Common::SeekableReadStream &source, uint32 outSize);
/**
* Decompresses LZW compressed data
*/
void decompress(Common::SeekableReadStream &source, byte *buffer, uint32 outSize);
/**
* Decompresses LZW compressed data
*/
static Common::SeekableReadStream *decompressLZ(Common::SeekableReadStream &source, uint32 outSize);
/**
* Decompress an LZW compressed resource
* Decompresses LZW compressed data
*/
Common::SeekableReadStream *decompressLZ(Common::SeekableReadStream &source);
static void decompressLZ(Common::SeekableReadStream &source, byte *outBuffer, int32 outSize, int32 inSize);
};
struct ImageFrame {
@ -158,6 +173,16 @@ struct ImageFrame {
Common::Point _offset;
byte _rleMarker;
Graphics::Surface _frame;
/**
* Return the frame width adjusted by a specified scale amount
*/
int sDrawXSize(int scaleVal) const;
/**
* Return the frame height adjusted by a specified scale amount
*/
int sDrawYSize(int scaleVal) const;
};
class ImageFile : public Common::Array<ImageFrame> {

View File

@ -24,6 +24,7 @@
#include "sherlock/sherlock.h"
#include "sherlock/music.h"
#include "sherlock/animation.h"
#include "engines/util.h"
namespace Sherlock {
@ -379,6 +380,9 @@ ScalpelEngine::~ScalpelEngine() {
}
void ScalpelEngine::initialize() {
initGraphics(320, 200, false);
// Let the base engine intialize
SherlockEngine::initialize();
_darts = new Darts(this);
@ -580,9 +584,9 @@ bool ScalpelEngine::scrollCredits() {
_screen->transBlitFrom(creditsImages[1], Common::Point(10, 400 - idx), false, 0);
// Don't show credit text on the top and bottom ten rows of the screen
_screen->blitFrom(_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, 10));
_screen->blitFrom(_screen->_backBuffer1, Common::Point(0, SHERLOCK_SCREEN_HEIGHT - 10),
Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - 10, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
_screen->blitFrom(_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, _screen->w(), 10));
_screen->blitFrom(_screen->_backBuffer1, Common::Point(0, _screen->h() - 10),
Common::Rect(0, _screen->h() - 10, _screen->w(), _screen->h()));
_events->delay(100);
}
@ -804,7 +808,6 @@ void ScalpelEngine::startScene() {
break;
}
_events->loadCursors("rmouse.vgs");
_events->setCursor(ARROW);
if (_scene->_goToScene == 99) {
@ -828,9 +831,11 @@ void ScalpelEngine::eraseMirror12() {
void ScalpelEngine::doMirror12() {
People &people = *_people;
Person &player = people._player;
Common::Point pt((*_people)[AL]._position.x / 100, (*_people)[AL]._position.y / 100);
int frameNum = (*people[AL]._sequences)[people[AL]._sequenceNumber][people[AL]._frameNumber] +
(*people[AL]._sequences)[people[AL]._sequenceNumber][0] - 2;
int frameNum = player._walkSequences[player._sequenceNumber][player._frameNumber] +
player._walkSequences[player._sequenceNumber][0] - 2;
switch ((*_people)[AL]._sequenceNumber) {
case WALK_DOWN:

View File

@ -0,0 +1,381 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "sherlock/scalpel/scalpel_scene.h"
#include "sherlock/scalpel/scalpel.h"
#include "sherlock/events.h"
#include "sherlock/people.h"
#include "sherlock/screen.h"
namespace Sherlock {
namespace Scalpel {
void ScalpelScene::checkBgShapes() {
People &people = *_vm->_people;
Person &holmes = people._player;
Common::Point pt(holmes._position.x / FIXED_INT_MULTIPLIER, holmes._position.y / FIXED_INT_MULTIPLIER);
// Call the base scene method to handle bg shapes
Scene::checkBgShapes();
// Iterate through the canim list
for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
Object &obj = _canimShapes[idx];
if (obj._type == STATIC_BG_SHAPE || obj._type == ACTIVE_BG_SHAPE) {
if ((obj._flags & 5) == 1) {
obj._misc = (pt.y < (obj._position.y + obj._imageFrame->_frame.h - 1)) ?
NORMAL_FORWARD : NORMAL_BEHIND;
} else if (!(obj._flags & 1)) {
obj._misc = BEHIND;
} else if (obj._flags & 4) {
obj._misc = FORWARD;
}
}
}
}
void ScalpelScene::doBgAnimCheckCursor() {
Inventory &inv = *_vm->_inventory;
Events &events = *_vm->_events;
Sound &sound = *_vm->_sound;
UserInterface &ui = *_vm->_ui;
Common::Point mousePos = events.mousePos();
if (ui._menuMode == LOOK_MODE) {
if (mousePos.y > CONTROLS_Y1)
events.setCursor(ARROW);
else if (mousePos.y < CONTROLS_Y)
events.setCursor(MAGNIFY);
}
// Check for setting magnifying glass cursor
if (ui._menuMode == INV_MODE || ui._menuMode == USE_MODE || ui._menuMode == GIVE_MODE) {
if (inv._invMode == INVMODE_LOOK) {
// Only show Magnifying glass cursor if it's not on the inventory command line
if (mousePos.y < CONTROLS_Y || mousePos.y >(CONTROLS_Y1 + 13))
events.setCursor(MAGNIFY);
else
events.setCursor(ARROW);
} else {
events.setCursor(ARROW);
}
}
if (sound._diskSoundPlaying && !*sound._soundIsOn) {
// Loaded sound just finished playing
sound.freeDigiSound();
}
}
void ScalpelScene::doBgAnim() {
ScalpelEngine &vm = *((ScalpelEngine *)_vm);
Events &events = *_vm->_events;
People &people = *_vm->_people;
Screen &screen = *_vm->_screen;
Talk &talk = *_vm->_talk;
screen.setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
talk._talkToAbort = false;
if (_restoreFlag) {
for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
if (people[idx]._type == CHARACTER)
people[idx].checkSprite();
}
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
if (_bgShapes[idx]._type == ACTIVE_BG_SHAPE)
_bgShapes[idx].checkObject();
}
if (people._portraitLoaded && people._portrait._type == ACTIVE_BG_SHAPE)
people._portrait.checkObject();
for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
if (_canimShapes[idx]._type != INVALID && _canimShapes[idx]._type != REMOVE)
_canimShapes[idx].checkObject();
}
if (_currentScene == 12)
vm.eraseMirror12();
// Restore the back buffer from the back buffer 2 in the changed area
Common::Rect bounds(people[AL]._oldPosition.x, people[AL]._oldPosition.y,
people[AL]._oldPosition.x + people[AL]._oldSize.x,
people[AL]._oldPosition.y + people[AL]._oldSize.y);
Common::Point pt(bounds.left, bounds.top);
if (people[AL]._type == CHARACTER)
screen.restoreBackground(bounds);
else if (people[AL]._type == REMOVE)
screen._backBuffer->blitFrom(screen._backBuffer2, pt, bounds);
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &o = _bgShapes[idx];
if (o._type == ACTIVE_BG_SHAPE || o._type == HIDE_SHAPE || o._type == REMOVE)
screen.restoreBackground(o.getOldBounds());
}
if (people._portraitLoaded)
screen.restoreBackground(Common::Rect(
people._portrait._oldPosition.x, people._portrait._oldPosition.y,
people._portrait._oldPosition.x + people._portrait._oldSize.x,
people._portrait._oldPosition.y + people._portrait._oldSize.y
));
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &o = _bgShapes[idx];
if (o._type == NO_SHAPE && ((o._flags & OBJ_BEHIND) == 0)) {
// Restore screen area
screen._backBuffer->blitFrom(screen._backBuffer2, o._position,
Common::Rect(o._position.x, o._position.y,
o._position.x + o._noShapeSize.x, o._position.y + o._noShapeSize.y));
o._oldPosition = o._position;
o._oldSize = o._noShapeSize;
}
}
for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
Object &o = _canimShapes[idx];
if (o._type == ACTIVE_BG_SHAPE || o._type == HIDE_SHAPE || o._type == REMOVE)
screen.restoreBackground(Common::Rect(o._oldPosition.x, o._oldPosition.y,
o._oldPosition.x + o._oldSize.x, o._oldPosition.y + o._oldSize.y));
}
}
//
// Update the background objects and canimations
//
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &o = _bgShapes[idx];
if (o._type == ACTIVE_BG_SHAPE || o._type == NO_SHAPE)
o.adjustObject();
}
if (people._portraitLoaded && people._portrait._type == ACTIVE_BG_SHAPE)
people._portrait.adjustObject();
for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
if (_canimShapes[idx]._type != INVALID)
_canimShapes[idx].adjustObject();
}
if (people[AL]._type == CHARACTER && people._holmesOn)
people[AL].adjustSprite();
// Flag the bg shapes which need to be redrawn
checkBgShapes();
if (_currentScene == 12)
vm.doMirror12();
// Draw all active shapes which are behind the person
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &o = _bgShapes[idx];
if (o._type == ACTIVE_BG_SHAPE && o._misc == BEHIND)
screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
}
// Draw all canimations which are behind the person
for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
Object &o = _canimShapes[idx];
if (o._type == ACTIVE_BG_SHAPE && o._misc == BEHIND) {
screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
}
}
// Draw all active shapes which are HAPPEN and behind the person
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &o = _bgShapes[idx];
if (o._type == ACTIVE_BG_SHAPE && o._misc == NORMAL_BEHIND)
screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
}
// Draw all canimations which are NORMAL and behind the person
for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
Object &o = _canimShapes[idx];
if (o._type == ACTIVE_BG_SHAPE && o._misc == NORMAL_BEHIND) {
screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
}
}
// Draw the person if not animating
if (people[AL]._type == CHARACTER && people[AL]._walkLoaded) {
// If Holmes is too far to the right, move him back so he's on-screen
int xRight = SHERLOCK_SCREEN_WIDTH - 2 - people[AL]._imageFrame->_frame.w;
int tempX = MIN(people[AL]._position.x / FIXED_INT_MULTIPLIER, xRight);
bool flipped = people[AL]._sequenceNumber == WALK_LEFT || people[AL]._sequenceNumber == STOP_LEFT ||
people[AL]._sequenceNumber == WALK_UPLEFT || people[AL]._sequenceNumber == STOP_UPLEFT ||
people[AL]._sequenceNumber == WALK_DOWNRIGHT || people[AL]._sequenceNumber == STOP_DOWNRIGHT;
screen._backBuffer->transBlitFrom(*people[AL]._imageFrame,
Common::Point(tempX, people[AL]._position.y / FIXED_INT_MULTIPLIER - people[AL]._imageFrame->_frame.h), flipped);
}
// Draw all static and active shapes are NORMAL and are in front of the person
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &o = _bgShapes[idx];
if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == NORMAL_FORWARD)
screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
}
// Draw all static and active canimations that are NORMAL and are in front of the person
for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
Object &o = _canimShapes[idx];
if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == NORMAL_FORWARD) {
screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
}
}
// Draw all static and active shapes that are in front of the person
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &o = _bgShapes[idx];
if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == FORWARD)
screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
}
// Draw any active portrait
if (people._portraitLoaded && people._portrait._type == ACTIVE_BG_SHAPE)
screen._backBuffer->transBlitFrom(*people._portrait._imageFrame,
people._portrait._position, people._portrait._flags & OBJ_FLIPPED);
// Draw all static and active canimations that are in front of the person
for (uint idx = 0; idx < _canimShapes.size(); ++idx) {
Object &o = _canimShapes[idx];
if ((o._type == ACTIVE_BG_SHAPE || o._type == STATIC_BG_SHAPE) && o._misc == FORWARD) {
screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
}
}
// Draw all NO_SHAPE shapes which have flag bit 0 clear
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &o = _bgShapes[idx];
if (o._type == NO_SHAPE && (o._flags & OBJ_BEHIND) == 0)
screen._backBuffer->transBlitFrom(*o._imageFrame, o._position, o._flags & OBJ_FLIPPED);
}
// Bring the newly built picture to the screen
if (_animating == 2) {
_animating = 0;
screen.slamRect(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
} else {
if (people[AL]._type != INVALID && ((_goToScene == -1 || _canimShapes.empty()))) {
if (people[AL]._type == REMOVE) {
screen.slamRect(Common::Rect(
people[AL]._oldPosition.x, people[AL]._oldPosition.y,
people[AL]._oldPosition.x + people[AL]._oldSize.x,
people[AL]._oldPosition.y + people[AL]._oldSize.y
));
people[AL]._type = INVALID;
} else {
screen.flushImage(people[AL]._imageFrame,
Common::Point(people[AL]._position.x / FIXED_INT_MULTIPLIER,
people[AL]._position.y / FIXED_INT_MULTIPLIER - people[AL].frameHeight()),
&people[AL]._oldPosition.x, &people[AL]._oldPosition.y,
&people[AL]._oldSize.x, &people[AL]._oldSize.y);
}
}
if (_currentScene == 12)
vm.flushMirror12();
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &o = _bgShapes[idx];
if ((o._type == ACTIVE_BG_SHAPE || o._type == REMOVE) && _goToScene == -1) {
screen.flushImage(o._imageFrame, o._position,
&o._oldPosition.x, &o._oldPosition.y, &o._oldSize.x, &o._oldSize.y);
}
}
if (people._portraitLoaded) {
if (people._portrait._type == REMOVE)
screen.slamRect(Common::Rect(
people._portrait._position.x, people._portrait._position.y,
people._portrait._position.x + people._portrait._delta.x,
people._portrait._position.y + people._portrait._delta.y
));
else
screen.flushImage(people._portrait._imageFrame, people._portrait._position,
&people._portrait._oldPosition.x, &people._portrait._oldPosition.y,
&people._portrait._oldSize.x, &people._portrait._oldSize.y);
if (people._portrait._type == REMOVE)
people._portrait._type = INVALID;
}
if (_goToScene == -1) {
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &o = _bgShapes[idx];
if (o._type == NO_SHAPE && (o._flags & OBJ_BEHIND) == 0) {
screen.slamArea(o._position.x, o._position.y, o._oldSize.x, o._oldSize.y);
screen.slamArea(o._oldPosition.x, o._oldPosition.y, o._oldSize.x, o._oldSize.y);
} else if (o._type == HIDE_SHAPE) {
// Hiding shape, so flush it out and mark it as hidden
screen.flushImage(o._imageFrame, o._position,
&o._oldPosition.x, &o._oldPosition.y, &o._oldSize.x, &o._oldSize.y);
o._type = HIDDEN;
}
}
}
for (int idx = _canimShapes.size() - 1; idx >= 0; --idx) {
Object &o = _canimShapes[idx];
if (o._type == INVALID) {
// Anim shape was invalidated by checkEndOfSequence, so at this point we can remove it
_canimShapes.remove_at(idx);
} else if (o._type == REMOVE) {
if (_goToScene == -1)
screen.slamArea(o._position.x, o._position.y, o._delta.x, o._delta.y);
// Shape for an animation is no longer needed, so remove it completely
_canimShapes.remove_at(idx);
} else if (o._type == ACTIVE_BG_SHAPE) {
screen.flushImage(o._imageFrame, o._position,
&o._oldPosition.x, &o._oldPosition.y, &o._oldSize.x, &o._oldSize.y);
}
}
}
_restoreFlag = true;
_doBgAnimDone = true;
events.wait(3);
screen.resetDisplayBounds();
// Check if the method was called for calling a portrait, and a talk was
// interrupting it. This talk file would not have been executed at the time,
// since we needed to finish the 'doBgAnim' to finish clearing the portrait
if (people._clearingThePortrait && talk._scriptMoreFlag == 3) {
// Reset the flags and call to talk
people._clearingThePortrait = false;
talk._scriptMoreFlag = 0;
talk.talkTo(talk._scriptName);
}
}
} // End of namespace Scalpel
} // End of namespace Sherlock

View File

@ -0,0 +1,61 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef SHERLOCK_SCALPEL_SCENE_H
#define SHERLOCK_SCALPEL_SCENE_H
#include "common/scummsys.h"
#include "common/array.h"
#include "common/rect.h"
#include "common/serializer.h"
#include "sherlock/objects.h"
#include "sherlock/scene.h"
#include "sherlock/screen.h"
namespace Sherlock {
namespace Scalpel {
class ScalpelScene : public Scene {
private:
void doBgAnimCheckCursor();
protected:
/**
* Checks all the background shapes. If a background shape is animating,
* it will flag it as needing to be drawn. If a non-animating shape is
* colliding with another shape, it will also flag it as needing drawing
*/
virtual void checkBgShapes();
public:
ScalpelScene(SherlockEngine *vm) : Scene(vm) {}
/**
* Draw all objects and characters.
*/
virtual void doBgAnim();
};
} // End of namespace Scalpel
} // End of namespace Sherlock
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,227 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef SHERLOCK_SCALPEL_UI_H
#define SHERLOCK_SCALPEL_UI_H
#include "common/scummsys.h"
#include "sherlock/user_interface.h"
namespace Sherlock {
class Inventory;
class Talk;
namespace Scalpel {
extern const char COMMANDS[13];
extern const int MENU_POINTS[12][4];
extern const int INVENTORY_POINTS[8][3];
extern const char INVENTORY_COMMANDS[9];
extern const char *const PRESS_KEY_FOR_MORE;
extern const char *const PRESS_KEY_TO_CONTINUE;
class Settings;
class ScalpelUserInterface: public UserInterface {
friend class Inventory;
friend class Settings;
friend class Talk;
private:
ImageFile *_controlPanel;
ImageFile *_controls;
char _keyPress;
int _lookHelp;
int _bgFound, _oldBgFound;
int _help, _oldHelp;
char _key, _oldKey;
int _temp, _oldTemp;
int _oldLook;
bool _keyboardInput;
bool _pause;
int _cNum;
Common::String _cAnimStr;
Common::String _descStr;
int _find;
int _oldUse;
private:
/**
* Draws the image for a user interface button in the down/pressed state.
*/
void depressButton(int num);
/**
* If he mouse button is pressed, then calls depressButton to draw the button
* as pressed; if not, it will show it as released with a call to "restoreButton".
*/
void pushButton(int num);
/**
* By the time this method has been called, the graphics for the button change
* have already been drawn. This simply takes care of switching the mode around
* accordingly
*/
void toggleButton(int num);
/**
* Creates a text window and uses it to display the in-depth description
* of the highlighted object
*/
void examine();
/**
* Print the name of an object in the scene
*/
void lookScreen(const Common::Point &pt);
/**
* Gets the item in the inventory the mouse is on and display's it's description
*/
void lookInv();
/**
* Handles input when the file list window is being displayed
*/
void doEnvControl();
/**
* Handle input whilst the inventory is active
*/
void doInvControl();
/**
* Handles waiting whilst an object's description window is open.
*/
void doLookControl();
/**
* Handles input until one of the user interface buttons/commands is selected
*/
void doMainControl();
/**
* Handles the input for the MOVE, OPEN, and CLOSE commands
*/
void doMiscControl(int allowed);
/**
* Handles input for picking up items
*/
void doPickControl();
/**
* Handles input when in talk mode. It highlights the buttons and available statements,
* and handles allowing the user to click on them
*/
void doTalkControl();
/**
* Handles events when the Journal is active.
* @remarks Whilst this would in theory be better in the Journal class, since it displays in
* the user interface, it uses so many internal UI fields, that it sort of made some sense
* to put it in the UserInterface class.
*/
void journalControl();
/**
* Checks to see whether a USE action is valid on the given object
*/
void checkUseAction(const UseType *use, const Common::String &invName, const char *const messages[],
int objNum, bool giveMode);
/**
* Called for OPEN, CLOSE, and MOVE actions are being done
*/
void checkAction(ActionType &action, const char *const messages[], int objNum);
/**
* Print the previously selected object's decription
*/
void printObjectDesc(const Common::String &str, bool firstTime);
public:
ScalpelUserInterface(SherlockEngine *vm);
virtual ~ScalpelUserInterface();
/**
* Handles counting down whilst checking for input, then clears the info line.
*/
void whileMenuCounter();
/**
* Draws the image for the given user interface button in the up
* (not selected) position
*/
void restoreButton(int num);
public:
/**
* Resets the user interface
*/
virtual void reset();
/**
* Main input handler for the user interface
*/
virtual void handleInput();
/**
* Draw the user interface onto the screen's back buffers
*/
virtual void drawInterface(int bufferNum = 3);
/**
* Displays a passed window by gradually scrolling it vertically on-screen
*/
virtual void summonWindow(const Surface &bgSurface, bool slideUp = true);
/**
* Slide the window stored in the back buffer onto the screen
*/
virtual void summonWindow(bool slideUp = true, int height = CONTROLS_Y);
/**
* Close a currently open window
* @param flag 0 = slide old window down, 1 = slide prior UI back up
*/
virtual void banishWindow(bool slideUp = true);
/**
* Clears the info line of the screen
*/
virtual void clearInfo();
/**
* Clear any active text window
*/
virtual void clearWindow();
/**
* Print the previously selected object's decription
*/
virtual void printObjectDesc();
};
} // End of namespace Scalpel
} // End of namespace Sherlock
#endif

View File

@ -21,10 +21,13 @@
*/
#include "sherlock/sherlock.h"
#include "sherlock/settings.h"
#include "sherlock/scalpel/settings.h"
#include "sherlock/scalpel/scalpel_user_interface.h"
namespace Sherlock {
namespace Scalpel {
static const int SETUP_POINTS[12][4] = {
{ 4, 154, 101, 53 }, // Exit
{ 4, 165, 101, 53 }, // Music Toggle
@ -212,9 +215,10 @@ void Settings::show(SherlockEngine *vm) {
Sound &sound = *vm->_sound;
Music &music = *vm->_music;
Talk &talk = *vm->_talk;
UserInterface &ui = *vm->_ui;
ScalpelUserInterface &ui = *(ScalpelUserInterface *)vm->_ui;
bool updateConfig = false;
assert(vm->getGameID() == GType_SerratedScalpel);
Settings settings(vm);
settings.drawInteface(false);
@ -332,4 +336,6 @@ void Settings::show(SherlockEngine *vm) {
ui._key = -1;
}
} // End of namespace Scalpel
} // End of namespace Sherlock

View File

@ -28,7 +28,8 @@
namespace Sherlock {
class SherlockEngine;
class UserInterface;
namespace Scalpel {
class Settings {
private:
@ -55,6 +56,8 @@ public:
static void show(SherlockEngine *vm);
};
} // End of namespace Scalpel
} // End of namespace Sherlock
#endif

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,7 @@
#include "common/serializer.h"
#include "sherlock/objects.h"
#include "sherlock/resources.h"
#include "sherlock/screen.h"
namespace Sherlock {
@ -44,12 +45,23 @@ struct BgFileHeader {
int _numcAnimations;
int _descSize;
int _seqSize;
// Serrated Scalpel
int _fill;
// Rose Tattoo
int _scrollSize;
int _bytesWritten; // Size of the main body of the RRM
int _fadeStyle; // Fade style
byte _palette[PALETTE_SIZE]; // Palette
BgFileHeader();
/**
* Load the data for the object
*/
void load(Common::SeekableReadStream &s);
void load(Common::SeekableReadStream &s, bool isRoseTattoo);
};
struct BgFileHeaderInfo {
@ -63,18 +75,20 @@ struct BgFileHeaderInfo {
void load(Common::SeekableReadStream &s);
};
struct Exit {
Common::Rect _bounds;
class Exit: public Common::Rect {
public:
int _scene;
int _allow;
Common::Point _people;
int _peopleDir;
Common::String _dest;
int _image; // Arrow image to use
/**
* Load the data for the object
*/
void load(Common::SeekableReadStream &s);
void load(Common::SeekableReadStream &s, bool isRoseTattoo);
};
struct SceneEntry {
@ -106,9 +120,26 @@ public:
int indexOf(const Object &obj) const;
};
class ScaleZone: public Common::Rect {
public:
int _topNumber; // Numerator of scale size at the top of the zone
int _bottomNumber; // Numerator of scale size at the bottom of the zone
void load(Common::SeekableReadStream &s);
};
struct SceneTripEntry {
bool _flag;
int _sceneNumber;
int _numTimes;
SceneTripEntry() : _flag(false), _sceneNumber(0), _numTimes(0) {}
SceneTripEntry(bool flag, int sceneNumber, int numTimes) : _flag(flag),
_sceneNumber(sceneNumber), _numTimes(numTimes) {}
};
class Scene {
private:
SherlockEngine *_vm;
Common::String _rrmName;
bool _loadingSavedGame;
@ -123,6 +154,11 @@ private:
*/
bool loadScene(const Common::String &filename);
/**
* Loads sounds for the scene
*/
void loadSceneSounds();
/**
* Set objects to their current persistent state. This includes things such as
* opening or moving them
@ -142,18 +178,27 @@ private:
*/
void transitionToScene();
/**
* Checks all the background shapes. If a background shape is animating,
* it will flag it as needing to be drawn. If a non-animating shape is
* colliding with another shape, it will also flag it as needing drawing
*/
void checkBgShapes(ImageFrame *frame, const Common::Point &pt);
/**
* Restores objects to the correct status. This ensures that things like being opened or moved
* will remain the same on future visits to the scene
*/
void saveSceneStatus();
protected:
SherlockEngine *_vm;
/**
* Checks all the background shapes. If a background shape is animating,
* it will flag it as needing to be drawn. If a non-animating shape is
* colliding with another shape, it will also flag it as needing drawing
*/
virtual void checkBgShapes();
/**
* Draw all the shapes, people and NPCs in the correct order
*/
void drawAllShapes();
Scene(SherlockEngine *vm);
public:
int _currentScene;
int _goToScene;
@ -173,17 +218,21 @@ public:
int _walkDirectory[MAX_ZONES][MAX_ZONES];
Common::Array<byte> _walkData;
Common::Array<Exit> _exits;
int _exitZone;
SceneEntry _entrance;
Common::Array<SceneSound> _sounds;
ObjectArray _canimShapes;
Common::Array<ScaleZone> _scaleZones;
Common::StringArray _objSoundList;
bool _restoreFlag;
int _animating;
bool _doBgAnimDone;
int _tempFadeStyle;
int _cAnimFramePause;
Common::Array<SceneTripEntry> _sceneTripCounters;
public:
Scene(SherlockEngine *vm);
~Scene();
static Scene *init(SherlockEngine *vm);
virtual ~Scene();
/**
* Handles loading the scene specified by _goToScene
@ -223,11 +272,6 @@ public:
*/
int toggleObject(const Common::String &name);
/**
* Animate all objects and people.
*/
void doBgAnim();
/**
* Attempts to find a background shape within the passed bounds. If found,
* it will return the shape number, or -1 on failure.
@ -250,16 +294,28 @@ public:
*/
int closestZone(const Common::Point &pt);
/**
* Update the screen back buffer with all of the scene objects which need
* to be drawn
*/
void updateBackground();
/**
* Synchronize the data for a savegame
*/
void synchronize(Common::Serializer &s);
/**
* Resets the NPC path information when entering a new scene.
* @remarks The default talk file for the given NPC is set to WATS##A, where ## is
* the scene number being entered
*/
void setNPCPath(int npc);
public:
/**
* Draw all objects and characters.
*/
virtual void doBgAnim() = 0;
/**
* Update the screen back buffer with all of the scene objects which need
* to be drawn
*/
virtual void updateBackground();
};
} // End of namespace Sherlock

View File

@ -28,9 +28,9 @@
namespace Sherlock {
Screen::Screen(SherlockEngine *vm) : Surface(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), _vm(vm),
_backBuffer1(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT),
_backBuffer2(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT),
Screen::Screen(SherlockEngine *vm) : Surface(g_system->getWidth(), g_system->getHeight()), _vm(vm),
_backBuffer1(g_system->getWidth(), g_system->getHeight()),
_backBuffer2(g_system->getWidth(), g_system->getHeight()),
_backBuffer(&_backBuffer1) {
_transitionSeed = 1;
_fadeStyle = false;
@ -38,7 +38,17 @@ Screen::Screen(SherlockEngine *vm) : Surface(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCR
_fontHeight = 0;
Common::fill(&_cMap[0], &_cMap[PALETTE_SIZE], 0);
Common::fill(&_sMap[0], &_sMap[PALETTE_SIZE], 0);
setFont(1);
Common::fill(&_tMap[0], &_tMap[PALETTE_SIZE], 0);
setFont(IS_SERRATED_SCALPEL ? 1 : 4);
// Rose Tattoo specific fields
_fadeBytesRead = _fadeBytesToRead = 0;
_oldFadePercent = 0;
_scrollSize = 0;
_scrollSpeed = 0;
_currentScroll = 0;
_targetScroll = 0;
_flushScreen = false;
}
Screen::~Screen() {
@ -174,12 +184,13 @@ void Screen::randomTransition() {
Events &events = *_vm->_events;
const int TRANSITION_MULTIPLIER = 0x15a4e35;
_dirtyRects.clear();
assert(IS_SERRATED_SCALPEL);
for (int idx = 0; idx <= 65535 && !_vm->shouldQuit(); ++idx) {
_transitionSeed = _transitionSeed * TRANSITION_MULTIPLIER + 1;
int offset = _transitionSeed & 0xFFFF;
if (offset < (SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT))
if (offset < (this->w() * this->h()))
*((byte *)getPixels() + offset) = *((const byte *)_backBuffer->getPixels() + offset);
if (idx != 0 && (idx % 300) == 0) {
@ -199,12 +210,12 @@ void Screen::randomTransition() {
void Screen::verticalTransition() {
Events &events = *_vm->_events;
byte table[SHERLOCK_SCREEN_WIDTH];
Common::fill(&table[0], &table[SHERLOCK_SCREEN_WIDTH], 0);
byte table[640];
Common::fill(&table[0], &table[640], 0);
for (int yp = 0; yp < SHERLOCK_SCREEN_HEIGHT; ++yp) {
for (int xp = 0; xp < SHERLOCK_SCREEN_WIDTH; ++xp) {
int temp = (table[xp] >= 197) ? SHERLOCK_SCREEN_HEIGHT - table[xp] :
for (int yp = 0; yp < this->h(); ++yp) {
for (int xp = 0; xp < this->w(); ++xp) {
int temp = (table[xp] >= (this->h() - 3)) ? this->h() - table[xp] :
_vm->getRandomNumber(3) + 1;
if (temp) {
@ -221,7 +232,7 @@ void Screen::verticalTransition() {
void Screen::restoreBackground(const Common::Rect &r) {
if (r.width() > 0 && r.height() > 0) {
Common::Rect tempRect = r;
tempRect.clip(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
tempRect.clip(Common::Rect(0, 0, this->w(), SHERLOCK_SCENE_HEIGHT));
if (tempRect.isValidRect())
_backBuffer1.blitFrom(_backBuffer2, Common::Point(tempRect.left, tempRect.top), tempRect);
@ -235,31 +246,62 @@ void Screen::slamArea(int16 xp, int16 yp, int16 width, int16 height) {
void Screen::slamRect(const Common::Rect &r) {
if (r.width() && r.height() > 0) {
Common::Rect tempRect = r;
tempRect.clip(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
tempRect.clip(Common::Rect(0, 0, this->w(), this->h()));
if (tempRect.isValidRect())
blitFrom(*_backBuffer, Common::Point(tempRect.left, tempRect.top), tempRect);
}
}
void Screen::flushImage(ImageFrame *frame, const Common::Point &pt,
int16 *xp, int16 *yp, int16 *width, int16 *height) {
void Screen::flushImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp,
int16 *width, int16 *height) {
Common::Point imgPos = pt + frame->_offset;
Common::Rect newBounds(imgPos.x, imgPos.y, imgPos.x + frame->_frame.w, imgPos.y + frame->_frame.h);
Common::Rect oldBounds(*xp, *yp, *xp + *width, *yp + *height);
// See if the areas of the old and new overlap, and if so combine the areas
if (newBounds.intersects(oldBounds)) {
Common::Rect mergedBounds = newBounds;
mergedBounds.extend(oldBounds);
mergedBounds.right += 1;
mergedBounds.bottom += 1;
if (!_flushScreen) {
// See if the areas of the old and new overlap, and if so combine the areas
if (newBounds.intersects(oldBounds)) {
Common::Rect mergedBounds = newBounds;
mergedBounds.extend(oldBounds);
mergedBounds.right += 1;
mergedBounds.bottom += 1;
slamRect(mergedBounds);
} else {
// The two areas are independent, so copy them both
slamRect(newBounds);
slamRect(oldBounds);
slamRect(mergedBounds);
} else {
// The two areas are independent, so copy them both
slamRect(newBounds);
slamRect(oldBounds);
}
}
*xp = newBounds.left;
*yp = newBounds.top;
*width = newBounds.width();
*height = newBounds.height();
}
void Screen::flushScaleImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp,
int16 *width, int16 *height, int scaleVal) {
Common::Point imgPos = pt + frame->_offset;
Common::Rect newBounds(imgPos.x, imgPos.y, imgPos.x + frame->sDrawXSize(scaleVal),
imgPos.y + frame->sDrawYSize(scaleVal));
Common::Rect oldBounds(*xp, *yp, *xp + *width, *yp + *height);
if (!_flushScreen) {
// See if the areas of the old and new overlap, and if so combine the areas
if (newBounds.intersects(oldBounds)) {
Common::Rect mergedBounds = newBounds;
mergedBounds.extend(oldBounds);
mergedBounds.right += 1;
mergedBounds.bottom += 1;
slamRect(mergedBounds);
} else {
// The two areas are independent, so copy them both
slamRect(newBounds);
slamRect(oldBounds);
}
}
*xp = newBounds.left;
@ -281,13 +323,13 @@ void Screen::print(const Common::Point &pt, byte color, const char *formatStr, .
pos.y--; // Font is always drawing one line higher
if (!pos.x)
// Center text horizontally
pos.x = (SHERLOCK_SCREEN_WIDTH - width) / 2;
pos.x = (this->w() - width) / 2;
Common::Rect textBounds(pos.x, pos.y, pos.x + width, pos.y + _fontHeight);
if (textBounds.right > SHERLOCK_SCREEN_WIDTH)
textBounds.moveTo(SHERLOCK_SCREEN_WIDTH - width, textBounds.top);
if (textBounds.bottom > SHERLOCK_SCREEN_HEIGHT)
textBounds.moveTo(textBounds.left, SHERLOCK_SCREEN_HEIGHT - _fontHeight);
if (textBounds.right > this->w())
textBounds.moveTo(this->w() - width, textBounds.top);
if (textBounds.bottom > this->h())
textBounds.moveTo(textBounds.left, this->h() - _fontHeight);
// Write out the string at the given position
writeString(str, Common::Point(textBounds.left, textBounds.top), color);
@ -416,7 +458,7 @@ void Screen::resetDisplayBounds() {
Common::Rect Screen::getDisplayBounds() {
return (_backBuffer == &_sceneSurface) ? Common::Rect(0, 0, _sceneSurface.w(), _sceneSurface.h()) :
Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
Common::Rect(0, 0, this->w(), this->h());
}
void Screen::synchronize(Common::Serializer &s) {
@ -426,4 +468,41 @@ void Screen::synchronize(Common::Serializer &s) {
setFont(fontNumb);
}
void Screen::initPaletteFade(int bytesToRead) {
Common::copy(&_cMap[0], &_cMap[PALETTE_SIZE], &_sMap[0]);
Common::copy(&_cMap[0], &_cMap[PALETTE_SIZE], &_tMap[0]);
// Set how many bytes need to be read / have been read
_fadeBytesRead = 0;
_fadeBytesToRead = bytesToRead;
_oldFadePercent = 0;
}
int Screen::fadeRead(Common::SeekableReadStream &stream, byte *buf, int totalSize) {
warning("TODO: fadeRead");
stream.read(buf, totalSize);
return totalSize;
}
/**
* Creates a grey-scale version of the passed palette
*/
void Screen::setupBGArea(const byte cMap[PALETTE_SIZE]) {
warning("TODO");
}
/**
* Initializes scroll variables
*/
void Screen::initScrollVars() {
_scrollSize = 0;
_currentScroll = 0;
_targetScroll = 0;
}
void Screen::translatePalette(byte palette[PALETTE_SIZE]) {
for (int idx = 0; idx < PALETTE_SIZE; ++idx)
palette[idx] = VGA_COLOR_TRANS(palette[idx]);
}
} // End of namespace Sherlock

View File

@ -66,6 +66,12 @@ private:
int _fontHeight;
Surface _sceneSurface;
// Rose Tattoo fields
int _fadeBytesRead, _fadeBytesToRead;
int _oldFadePercent;
byte _lookupTable[PALETTE_COUNT];
byte _lookupTable1[PALETTE_COUNT];
private:
/**
* Merges together overlapping dirty areas of the screen
*/
@ -92,6 +98,10 @@ public:
bool _fadeStyle;
byte _cMap[PALETTE_SIZE];
byte _sMap[PALETTE_SIZE];
byte _tMap[PALETTE_SIZE];
int _currentScroll, _targetScroll;
int _scrollSize, _scrollSpeed;
bool _flushScreen;
public:
Screen(SherlockEngine *vm);
virtual ~Screen();
@ -171,8 +181,15 @@ public:
* Copy an image from the back buffer to the screen, taking care of both the
* new area covered by the shape as well as the old area, which must be restored
*/
void flushImage(ImageFrame *frame, const Common::Point &pt,
int16 *xp, int16 *yp, int16 *width, int16 *height);
void flushImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp,
int16 *width, int16 *height);
/**
* Similar to flushImage, this method takes in an extra parameter for the scale proporation,
* which affects the calculated bounds accordingly
*/
void flushScaleImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp,
int16 *width, int16 *height, int scaleVal);
/**
* Returns the width of a string in pixels
@ -232,6 +249,21 @@ public:
* Synchronize the data for a savegame
*/
void synchronize(Common::Serializer &s);
// Rose Tattoo specific methods
void initPaletteFade(int bytesToRead);
int fadeRead(Common::SeekableReadStream &stream, byte *buf, int totalSize);
void setupBGArea(const byte cMap[PALETTE_SIZE]);
void initScrollVars();
/**
* Translate a palette from 6-bit RGB values to full 8-bit values suitable for passing
* to the underlying palette manager
*/
static void translatePalette(byte palette[PALETTE_SIZE]);
};
} // End of namespace Sherlock

View File

@ -25,7 +25,6 @@
#include "common/scummsys.h"
#include "common/config-manager.h"
#include "common/debug-channels.h"
#include "engines/util.h"
namespace Sherlock {
@ -72,8 +71,6 @@ SherlockEngine::~SherlockEngine() {
}
void SherlockEngine::initialize() {
initGraphics(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT, false);
DebugMan.addDebugChannel(kDebugScript, "scripts", "Script debug level");
ImageFile::setVm(this);
@ -98,11 +95,11 @@ void SherlockEngine::initialize() {
_journal = new Journal(this);
_people = new People(this);
_saves = new SaveManager(this, _targetName);
_scene = new Scene(this);
_scene = Scene::init(this);
_screen = new Screen(this);
_sound = new Sound(this, _mixer);
_talk = new Talk(this);
_ui = new UserInterface(this);
_talk = Talk::init(this);
_ui = UserInterface::init(this);
// Load game settings
loadConfig();
@ -213,7 +210,9 @@ void SherlockEngine::loadConfig() {
ConfMan.registerDefault("font", 1);
_screen->setFont(ConfMan.getInt("font"));
_screen->_fadeStyle = ConfMan.getBool("fade_style");
if (getGameID() == GType_SerratedScalpel)
_screen->_fadeStyle = ConfMan.getBool("fade_style");
_ui->_helpStyle = ConfMan.getBool("help_style");
_ui->_slideWindows = ConfMan.getBool("window_style");
_people->_portraitsOn = ConfMan.getBool("portraits_on");

View File

@ -59,9 +59,9 @@ enum GameType {
GType_RoseTattoo = 1
};
#define SHERLOCK_SCREEN_WIDTH 320
#define SHERLOCK_SCREEN_HEIGHT 200
#define SHERLOCK_SCENE_HEIGHT 138
#define SHERLOCK_SCREEN_WIDTH _vm->_screen->w()
#define SHERLOCK_SCREEN_HEIGHT _vm->_screen->h()
#define SHERLOCK_SCENE_HEIGHT (IS_SERRATED_SCALPEL ? 138 : 480)
struct SherlockGameDescription;
@ -199,6 +199,9 @@ public:
void synchronize(Common::Serializer &s);
};
#define IS_ROSE_TATTOO (_vm->getGameID() == GType_RoseTattoo)
#define IS_SERRATED_SCALPEL (_vm->getGameID() == GType_SerratedScalpel)
} // End of namespace Sherlock
#endif

View File

@ -58,18 +58,27 @@ Sound::Sound(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
_soundIsOn = &_soundPlaying;
_curPriority = 0;
_digiBuf = nullptr;
_midiDrvLoaded = false;
_musicVolume = 0;
_soundOn = true;
_speechOn = true;
_vm->_res->addToCache("MUSIC.LIB");
if (!_vm->_interactiveFl)
_vm->_res->addToCache("TITLE.SND");
else {
_vm->_res->addToCache("SND.SND");
_vm->_res->addToCache("MUSIC.LIB");
if (IS_ROSE_TATTOO) {
_vm->_res->addToCache("SOUND.LIB");
} else {
_vm->_res->addToCache("SND.SND");
if (!_vm->isDemo()) {
_vm->_res->addToCache("TITLE.SND");
_vm->_res->addToCache("EPILOGUE.SND");
if (!_vm->isDemo()) {
_vm->_res->addToCache("TITLE.SND");
_vm->_res->addToCache("EPILOGUE.SND");
}
}
}
}
@ -210,5 +219,9 @@ void Sound::freeDigiSound() {
_soundPlaying = false;
}
void Sound::setMIDIVolume(int volume) {
// TODO
}
} // End of namespace Sherlock

View File

@ -56,6 +56,9 @@ public:
bool _soundPlaying;
bool *_soundIsOn;
byte *_digiBuf;
bool _midiDrvLoaded;
Common::String _currentSongName, _nextSongName;
int _musicVolume;
public:
Sound(SherlockEngine *vm, Audio::Mixer *mixer);
@ -91,6 +94,7 @@ public:
void stopSndFuncPtr(int v1, int v2);
void freeDigiSound();
void setMIDIVolume(int volume);
};
} // End of namespace Sherlock

View File

@ -96,6 +96,12 @@ void Surface::transBlitFrom(const ImageFrame &src, const Common::Point &pt,
transBlitFrom(src._frame, pt + src._offset, flipped, overrideColor);
}
void Surface::transBlitFrom(const Surface &src, const Common::Point &pt,
bool flipped, int overrideColor) {
const Graphics::Surface &s = src._surface;
transBlitFrom(s, pt, flipped, overrideColor);
}
void Surface::transBlitFrom(const Graphics::Surface &src, const Common::Point &pt,
bool flipped, int overrideColor) {
Common::Rect drawRect(0, 0, src.w, src.h);
@ -186,4 +192,10 @@ void Surface::setPixels(byte *pixels, int width, int height) {
_surface.setPixels(pixels);
}
void Surface::maskArea(const ImageFrame &src, const Common::Point &pt, int scrollX) {
// TODO
error("TODO: maskArea");
}
} // End of namespace Sherlock

View File

@ -126,6 +126,8 @@ public:
*/
void fillRect(const Common::Rect &r, byte color);
void maskArea(const ImageFrame &src, const Common::Point &pt, int scrollX);
/**
* Clear the screen
*/

File diff suppressed because it is too large Load Diff

View File

@ -36,42 +36,83 @@ namespace Sherlock {
#define MAX_TALK_FILES 500
enum {
SWITCH_SPEAKER = 128,
RUN_CANIMATION = 129,
ASSIGN_PORTRAIT_LOCATION = 130,
PAUSE = 131,
REMOVE_PORTRAIT = 132,
CLEAR_WINDOW = 133,
ADJUST_OBJ_SEQUENCE = 134,
WALK_TO_COORDS = 135,
PAUSE_WITHOUT_CONTROL = 136,
BANISH_WINDOW = 137,
SUMMON_WINDOW = 138,
SET_FLAG = 139,
SFX_COMMAND = 140,
TOGGLE_OBJECT = 141,
STEALTH_MODE_ACTIVE = 142,
IF_STATEMENT = 143,
ELSE_STATEMENT = 144,
END_IF_STATEMENT = 145,
STEALTH_MODE_DEACTIVATE = 146,
TURN_HOLMES_OFF = 147,
TURN_HOLMES_ON = 148,
GOTO_SCENE = 149,
PLAY_PROLOGUE = 150,
ADD_ITEM_TO_INVENTORY = 151,
SET_OBJECT = 152,
CALL_TALK_FILE = 153,
MOVE_MOUSE = 154,
DISPLAY_INFO_LINE = 155,
CLEAR_INFO_LINE = 156,
WALK_TO_CANIMATION = 157,
REMOVE_ITEM_FROM_INVENTORY = 158,
ENABLE_END_KEY = 159,
DISABLE_END_KEY = 160,
CARRIAGE_RETURN = 161
OP_SWITCH_SPEAKER = 0,
OP_RUN_CANIMATION = 1,
OP_ASSIGN_PORTRAIT_LOCATION = 2,
OP_PAUSE = 3,
OP_REMOVE_PORTRAIT = 4,
OP_CLEAR_WINDOW = 5,
OP_ADJUST_OBJ_SEQUENCE = 6,
OP_WALK_TO_COORDS = 7,
OP_PAUSE_WITHOUT_CONTROL = 8,
OP_BANISH_WINDOW = 9,
OP_SUMMON_WINDOW = 10,
OP_SET_FLAG = 11,
OP_SFX_COMMAND = 12,
OP_TOGGLE_OBJECT = 13,
OP_STEALTH_MODE_ACTIVE = 14,
OP_IF_STATEMENT = 15,
OP_ELSE_STATEMENT = 16,
OP_END_IF_STATEMENT = 17,
OP_STEALTH_MODE_DEACTIVATE = 18,
OP_TURN_HOLMES_OFF = 19,
OP_TURN_HOLMES_ON = 20,
OP_GOTO_SCENE = 21,
OP_PLAY_PROLOGUE = 22,
OP_ADD_ITEM_TO_INVENTORY = 23,
OP_SET_OBJECT = 24,
OP_CALL_TALK_FILE = 25,
OP_MOVE_MOUSE = 26,
OP_DISPLAY_INFO_LINE = 27,
OP_CLEAR_INFO_LINE = 28,
OP_WALK_TO_CANIMATION = 29,
OP_REMOVE_ITEM_FROM_INVENTORY = 30,
OP_ENABLE_END_KEY = 31,
OP_DISABLE_END_KEY = 32,
OP_CARRIAGE_RETURN = 33,
OP_MOUSE_OFF_ON = 34,
OP_SET_WALK_CONTROL = 35,
OP_SET_TALK_SEQUENCE = 36,
OP_PLAY_SONG = 37,
OP_WALK_HOLMES_AND_NPC_TO_CANIM = 38,
OP_SET_NPC_PATH_DEST = 39,
OP_NEXT_SONG = 40,
OP_SET_NPC_PATH_PAUSE = 41,
OP_NEED_PASSWORD = 42,
OP_SET_SCENE_ENTRY_FLAG = 43,
OP_WALK_NPC_TO_CANIM = 44,
OP_WALK_HOLMES_AND_NPC_TO_COORDS = 45,
OP_SET_NPC_TALK_FILE = 46,
OP_TURN_NPC_OFF = 47,
OP_TURN_NPC_ON = 48,
OP_NPC_DESC_ON_OFF = 49,
OP_NPC_PATH_PAUSE_TAKING_NOTES = 50,
OP_NPC_PATH_PAUSE_LOOKING_HOLMES = 51,
OP_ENABLE_TALK_INTERRUPTS = 52,
OP_DISABLE_TALK_INTERRUPTS = 53,
OP_SET_NPC_INFO_LINE = 54,
OP_SET_NPC_POSITION = 54,
OP_NPC_PATH_LABEL = 55,
OP_PATH_GOTO_LABEL = 56,
OP_PATH_IF_FLAG_GOTO_LABEL = 57,
OP_NPC_WALK_GRAPHICS = 58,
OP_NPC_VERB = 59,
OP_NPC_VERB_CANIM = 60,
OP_NPC_VERB_SCRIPT = 61,
OP_RESTORE_PEOPLE_SEQUENCE = 62,
OP_NPC_VERB_TARGET = 63,
OP_TURN_SOUNDS_OFF = 64
};
enum OpcodeReturn { RET_EXIT = -1, RET_SUCCESS = 0, RET_CONTINUE = 1 };
class SherlockEngine;
class Talk;
namespace Scalpel { class ScalpelUserInterface; };
typedef OpcodeReturn(Talk::*OpcodeMethod)(const byte *&str);
struct SequenceEntry {
int _objNum;
Common::Array<byte> _sequences;
@ -122,24 +163,8 @@ struct TalkSequences {
void clear();
};
class SherlockEngine;
class UserInterface;
class Talk {
friend class UserInterface;
private:
SherlockEngine *_vm;
Common::Stack<SequenceEntry> _savedSequences;
Common::Stack<SequenceEntry> _sequenceStack;
Common::Stack<ScriptStackEntry> _scriptStack;
Common::Array<Statement> _statements;
TalkHistoryEntry _talkHistory[MAX_TALK_FILES];
int _speaker;
int _talkIndex;
int _scriptSelect;
int _talkStealth;
int _talkToFlag;
int _scriptSaveIndex;
friend class Scalpel::ScalpelUserInterface;
private:
/**
* Remove any voice commands from a loaded statement list
@ -173,6 +198,55 @@ private:
* the amount of text that's been displayed
*/
int waitForMore(int delay);
protected:
SherlockEngine *_vm;
OpcodeMethod *_opcodeTable;
Common::Stack<SequenceEntry> _savedSequences;
Common::Stack<SequenceEntry> _sequenceStack;
Common::Stack<ScriptStackEntry> _scriptStack;
Common::Array<Statement> _statements;
TalkHistoryEntry _talkHistory[MAX_TALK_FILES];
int _speaker;
int _talkIndex;
int _scriptSelect;
int _talkStealth;
int _talkToFlag;
int _scriptSaveIndex;
// These fields are used solely by doScript, but are fields because all the script opcodes are
// separate methods now, and need access to these fields
int _yp;
int _charCount;
int _line;
int _wait;
bool _pauseFlag;
bool _endStr, _noTextYet;
int _seqCount;
const byte *_scriptStart, *_scriptEnd;
protected:
Talk(SherlockEngine *vm);
OpcodeReturn cmdAddItemToInventory(const byte *&str);
OpcodeReturn cmdAdjustObjectSequence(const byte *&str);
OpcodeReturn cmdBanishWindow(const byte *&str);
OpcodeReturn cmdCallTalkFile(const byte *&str);
OpcodeReturn cmdDisableEndKey(const byte *&str);
OpcodeReturn cmdEnableEndKey(const byte *&str);
OpcodeReturn cmdGotoScene(const byte *&str);
OpcodeReturn cmdHolmesOff(const byte *&str);
OpcodeReturn cmdHolmesOn(const byte *&str);
OpcodeReturn cmdPause(const byte *&str);
OpcodeReturn cmdPauseWithoutControl(const byte *&str);
OpcodeReturn cmdRemoveItemFromInventory(const byte *&str);
OpcodeReturn cmdRunCAnimation(const byte *&str);
OpcodeReturn cmdSetFlag(const byte *&str);
OpcodeReturn cmdSetObject(const byte *&str);
OpcodeReturn cmdStealthModeActivate(const byte *&str);
OpcodeReturn cmdStealthModeDeactivate(const byte *&str);
OpcodeReturn cmdSwitchSpeaker(const byte *&str);
OpcodeReturn cmdToggleObject(const byte *&str);
OpcodeReturn cmdWalkToCAnimation(const byte *&str);
OpcodeReturn cmdWalkToCoords(const byte *&str);
public:
bool _talkToAbort;
int _talkCounter;
@ -181,8 +255,11 @@ public:
Common::String _scriptName;
bool _moreTalkUp, _moreTalkDown;
int _converseNum;
const byte *_opcodes;
public:
Talk(SherlockEngine *vm);
static Talk *init(SherlockEngine *vm);
virtual ~Talk() {}
/**
* Return a given talk statement
@ -267,6 +344,65 @@ public:
void synchronize(Common::Serializer &s);
};
class ScalpelTalk : public Talk {
protected:
OpcodeReturn cmdAssignPortraitLocation(const byte *&str);
OpcodeReturn cmdClearInfoLine(const byte *&str);
OpcodeReturn cmdClearWindow(const byte *&str);
OpcodeReturn cmdDisplayInfoLine(const byte *&str);
OpcodeReturn cmdElse(const byte *&str);
OpcodeReturn cmdIf(const byte *&str);
OpcodeReturn cmdMoveMouse(const byte *&str);
OpcodeReturn cmdPlayPrologue(const byte *&str);
OpcodeReturn cmdRemovePortrait(const byte *&str);
OpcodeReturn cmdSfxCommand(const byte *&str);
OpcodeReturn cmdSummonWindow(const byte *&str);
OpcodeReturn cmdCarriageReturn(const byte *&str);
public:
ScalpelTalk(SherlockEngine *vm);
virtual ~ScalpelTalk() {}
};
class TattooTalk : public Talk {
protected:
OpcodeReturn cmdMouseOnOff(const byte *&str);
OpcodeReturn cmdNextSong(const byte *&str);
OpcodeReturn cmdPassword(const byte *&str);
OpcodeReturn cmdPlaySong(const byte *&str);
OpcodeReturn cmdRestorePeopleSequence(const byte *&str);
OpcodeReturn cmdSetNPCDescOnOff(const byte *&str);
OpcodeReturn cmdSetNPCInfoLine(const byte *&str);
OpcodeReturn cmdNPCLabelGoto(const byte *&str);
OpcodeReturn cmdNPCLabelIfFlagGoto(const byte *&str);
OpcodeReturn cmdNPCLabelSet(const byte *&str);
OpcodeReturn cmdSetNPCOff(const byte *&str);
OpcodeReturn cmdSetNPCOn(const byte *&str);
OpcodeReturn cmdSetNPCPathDest(const byte *&str);
OpcodeReturn cmdSetNPCPathPause(const byte *&str);
OpcodeReturn cmdSetNPCPathPauseTakingNotes(const byte *&str);
OpcodeReturn cmdSetNPCPathPauseLookingHolmes(const byte *&str);
OpcodeReturn cmdSetNPCPosition(const byte *&str);
OpcodeReturn cmdSetNPCTalkFile(const byte *&str);
OpcodeReturn cmdSetNPCVerb(const byte *&str);
OpcodeReturn cmdSetNPCVerbCAnimation(const byte *&str);
OpcodeReturn cmdSetNPCVerbScript(const byte *&str);
OpcodeReturn cmdSetNPCVerbTarget(const byte *&str);
OpcodeReturn cmdSetNPCWalkGraphics(const byte *&str);
OpcodeReturn cmdSetSceneEntryFlag(const byte *&str);
OpcodeReturn cmdSetTalkSequence(const byte *&str);
OpcodeReturn cmdSetWalkControl(const byte *&str);
OpcodeReturn cmdTalkInterruptsDisable(const byte *&str);
OpcodeReturn cmdTalkInterruptsEnable(const byte *&str);
OpcodeReturn cmdTurnSoundsOff(const byte *&str);
OpcodeReturn cmdWalkHolmesAndNPCToCAnimation(const byte *&str);
OpcodeReturn cmdWalkNPCToCAnimation(const byte *&str);
OpcodeReturn cmdWalkNPCToCoords(const byte *&str);
OpcodeReturn cmdWalkHomesAndNPCToCoords(const byte *&str);
public:
TattooTalk(SherlockEngine *vm);
virtual ~TattooTalk() {}
};
} // End of namespace Sherlock
#endif

View File

@ -21,15 +21,61 @@
*/
#include "sherlock/tattoo/tattoo.h"
#include "engines/util.h"
namespace Sherlock {
namespace Tattoo {
TattooEngine::TattooEngine(OSystem *syst, const SherlockGameDescription *gameDesc) :
SherlockEngine(syst, gameDesc) {
_creditsActive = false;
}
void TattooEngine::showOpening() {
// TODO
}
void TattooEngine::initialize() {
initGraphics(640, 480, true);
// Initialize the base engine
SherlockEngine::initialize();
_flags.resize(100 * 8);
// Add some more files to the cache
_res->addToCache("walk.lib");
// Starting scene
_scene->_goToScene = 91;
// Load an initial palette
loadInitialPalette();
}
void TattooEngine::startScene() {
// TODO
}
void TattooEngine::loadInitialPalette() {
byte palette[768];
Common::SeekableReadStream *stream = _res->load("room.pal");
stream->read(palette, PALETTE_SIZE);
_screen->translatePalette(palette);
_screen->setPalette(palette);
delete stream;
}
void TattooEngine::drawCredits() {
// TODO
}
void TattooEngine::eraseCredits() {
// TODO
}
} // End of namespace Tattoo
} // End of namespace Scalpel

View File

@ -30,12 +30,38 @@ namespace Sherlock {
namespace Tattoo {
class TattooEngine : public SherlockEngine {
private:
/**
* Loads the initial palette for the game
*/
void loadInitialPalette();
protected:
/**
* Initialize the engine
*/
virtual void initialize();
virtual void showOpening();
/**
* Starting a scene within the game
*/
virtual void startScene();
public:
TattooEngine(OSystem *syst, const SherlockGameDescription *gameDesc) :
SherlockEngine(syst, gameDesc) {}
bool _creditsActive;
public:
TattooEngine(OSystem *syst, const SherlockGameDescription *gameDesc);
virtual ~TattooEngine() {}
/**
* Draw credits on the screen
*/
void drawCredits();
/**
* Erase any area of the screen covered by credits
*/
void eraseCredits();
};
} // End of namespace Tattoo

View File

@ -0,0 +1,402 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "sherlock/tattoo/tattoo_scene.h"
#include "sherlock/tattoo/tattoo.h"
#include "sherlock/tattoo/tattoo_user_interface.h"
#include "sherlock/events.h"
#include "sherlock/people.h"
namespace Sherlock {
namespace Tattoo {
TattooScene::TattooScene(SherlockEngine *vm) : Scene(vm) {
_arrowZone = -1;
_mask = _mask1 = nullptr;
_maskCounter = 0;
}
void TattooScene::checkBgShapes() {
People &people = *_vm->_people;
Person &holmes = people._player;
Common::Point pt(holmes._position.x / FIXED_INT_MULTIPLIER, holmes._position.y / FIXED_INT_MULTIPLIER);
// Call the base scene method to handle bg shapes
Scene::checkBgShapes();
// Check for any active playing animation
if (_activeCAnim._images && _activeCAnim._zPlacement != REMOVE) {
switch (_activeCAnim._flags & 3) {
case 0:
_activeCAnim._zPlacement = BEHIND;
break;
case 1:
_activeCAnim._zPlacement = ((_activeCAnim._position.y + _activeCAnim._imageFrame->_frame.h - 1)) ?
NORMAL_FORWARD : NORMAL_BEHIND;
break;
case 2:
_activeCAnim._zPlacement = FORWARD;
break;
default:
break;
}
}
}
void TattooScene::doBgAnimCheckCursor() {
Events &events = *_vm->_events;
UserInterface &ui = *_vm->_ui;
Common::Point mousePos = events.mousePos();
// If we're in Look Mode, make sure the cursor is the magnifying glass
if (ui._menuMode == LOOK_MODE && events.getCursor() != MAGNIFY)
events.setCursor(MAGNIFY);
// See if the mouse is over any of the arrow zones, and if so, change the cursor to the correct
// arrow cursor indicating the direcetion of the exit
if (events.getCursor() == ARROW || events.getCursor() >= EXIT_ZONES_START) {
CursorId cursorId = ARROW;
if (ui._menuMode == STD_MODE && _arrowZone != -1 && _currentScene != 90) {
for (uint idx = 0; idx < _exits.size(); ++idx) {
Exit &exit = _exits[idx];
if (exit.contains(mousePos))
cursorId = (CursorId)(exit._image + EXIT_ZONES_START);
}
}
events.setCursor(cursorId);
}
}
void TattooScene::doBgAnimEraseBackground() {
TattooEngine &vm = *((TattooEngine *)_vm);
People &people = *_vm->_people;
Screen &screen = *_vm->_screen;
TattooUserInterface &ui = *((TattooUserInterface *)_vm->_ui);
static const int16 OFFSETS[16] = { -1, -2, -3, -3, -2, -1, -1, 0, 1, 2, 3, 3, 2, 1, 0, 0 };
if (_mask != nullptr) {
if (screen._backBuffer1.w() > screen.w())
screen.blitFrom(screen._backBuffer1, Common::Point(0, 0), Common::Rect(screen._currentScroll, 0,
screen._currentScroll + screen.w(), screen.h()));
else
screen.blitFrom(screen._backBuffer1);
switch (_currentScene) {
case 7:
if (++_maskCounter == 2) {
_maskCounter = 0;
if (--_maskOffset.x < 0)
_maskOffset.x = SHERLOCK_SCREEN_WIDTH - 1;
}
break;
case 8:
_maskOffset.x += 2;
if (_maskOffset.x >= SHERLOCK_SCREEN_WIDTH)
_maskOffset.x = 0;
break;
case 18:
case 68:
++_maskCounter;
if (_maskCounter / 4 >= 16)
_maskCounter = 0;
_maskOffset.x = OFFSETS[_maskCounter / 4];
break;
case 53:
if (++_maskCounter == 2) {
_maskCounter = 0;
if (++_maskOffset.x == screen._backBuffer1.w())
_maskOffset.x = 0;
}
break;
default:
break;
}
} else {
// Standard scene without mask, so call user interface to erase any UI elements as necessary
ui.doBgAnimRestoreUI();
// Restore background for any areas covered by characters and shapes
for (uint idx = 0; idx < MAX_CHARACTERS; ++idx)
screen.restoreBackground(Common::Rect(people[idx]._oldPosition.x, people[idx]._oldPosition.y,
people[idx]._oldPosition.x + people[idx]._oldSize.x, people[idx]._oldPosition.y + people[idx]._oldSize.y));
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &obj = _bgShapes[idx];
if ((obj._type == ACTIVE_BG_SHAPE && (obj._maxFrames > 1 || obj._delta.x != 0 || obj._delta.y != 0)) ||
obj._type == HIDE_SHAPE || obj._type == REMOVE)
screen._backBuffer1.blitFrom(*obj._imageFrame, obj._oldPosition,
Common::Rect(obj._oldPosition.x, obj._oldPosition.y, obj._oldPosition.x + obj._oldSize.x,
obj._oldPosition.y + obj._oldSize.y));
}
// If credits are active, erase the area they cover
if (vm._creditsActive)
vm.eraseCredits();
}
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &obj = _bgShapes[idx];
if (obj._type == NO_SHAPE && (obj._flags & 1) == 0) {
screen._backBuffer1.blitFrom(screen._backBuffer2, obj._position, obj.getNoShapeBounds());
obj._oldPosition = obj._position;
obj._oldSize = obj._noShapeSize;
}
}
// Adjust the Target Scroll if needed
if ((people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER - screen._currentScroll) <
(SHERLOCK_SCREEN_WIDTH / 8) && people[people._walkControl]._delta.x < 0) {
screen._targetScroll = (short)(people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER -
SHERLOCK_SCREEN_WIDTH / 8 - 250);
if (screen._targetScroll < 0)
screen._targetScroll = 0;
}
if ((people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER - screen._currentScroll) > (SHERLOCK_SCREEN_WIDTH / 4 * 3)
&& people[people._walkControl]._delta.x > 0)
screen._targetScroll = (short)(people[people._walkControl]._position.x / FIXED_INT_MULTIPLIER -
SHERLOCK_SCREEN_WIDTH / 4 * 3 + 250);
if (screen._targetScroll > screen._scrollSize)
screen._targetScroll = screen._scrollSize;
ui.doScroll();
}
void TattooScene::doBgAnim() {
TattooUserInterface &ui = *((TattooUserInterface *)_vm->_ui);
doBgAnimCheckCursor();
// Events &events = *_vm->_events;
People &people = *_vm->_people;
// Scene &scene = *_vm->_scene;
Screen &screen = *_vm->_screen;
Talk &talk = *_vm->_talk;
screen.setDisplayBounds(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
talk._talkToAbort = false;
// Check the characters and sprites for updates
for (uint idx = 0; idx < MAX_CHARACTERS; ++idx) {
if (people[idx]._type == CHARACTER)
people[idx].checkSprite();
}
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
if (_bgShapes[idx]._type == ACTIVE_BG_SHAPE)
_bgShapes[idx].checkObject();
}
// Erase any affected background areas
doBgAnimEraseBackground();
doBgAnimUpdateBgObjectsAndAnim();
ui.drawInterface();
}
void TattooScene::doBgAnimUpdateBgObjectsAndAnim() {
TattooEngine &vm = *((TattooEngine *)_vm);
People &people = *_vm->_people;
Screen &screen = *_vm->_screen;
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &obj = _bgShapes[idx];
if (obj._type == ACTIVE_BG_SHAPE || obj._type == NO_SHAPE)
obj.adjustObject();
}
for (uint idx = 0; idx < MAX_CHARACTERS; ++idx) {
if (people[idx]._type == CHARACTER)
people[idx].adjustSprite();
}
if (_activeCAnim._images != nullptr != _activeCAnim._zPlacement != REMOVE) {
_activeCAnim.getNextFrame();
}
// Flag the bg shapes which need to be redrawn
checkBgShapes();
drawAllShapes();
if (_mask != nullptr) {
switch (_currentScene) {
case 7:
screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x - SHERLOCK_SCREEN_WIDTH, 110), screen._currentScroll);
screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 110), screen._currentScroll);
screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x + SHERLOCK_SCREEN_WIDTH, 110), screen._currentScroll);
break;
case 8:
screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x - SHERLOCK_SCREEN_WIDTH, 180), screen._currentScroll);
screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 180), screen._currentScroll);
screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x + SHERLOCK_SCREEN_WIDTH, 180), screen._currentScroll);
if (!_vm->readFlags(880))
screen._backBuffer1.maskArea((*_mask1)[0], Common::Point(940, 300), screen._currentScroll);
break;
case 18:
screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 203), screen._currentScroll);
if (!_vm->readFlags(189))
screen._backBuffer1.maskArea((*_mask1)[0], Common::Point(124 + _maskOffset.x, 239), screen._currentScroll);
break;
case 53:
screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 110), screen._currentScroll);
screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x - SHERLOCK_SCREEN_WIDTH, 110), screen._currentScroll);
break;
case 68:
screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 203), screen._currentScroll);
screen._backBuffer1.maskArea((*_mask1)[0], Common::Point(124 + _maskOffset.x, 239), screen._currentScroll);
break;
}
}
}
void TattooScene::updateBackground() {
People &people = *_vm->_people;
Screen &screen = *_vm->_screen;
Scene::updateBackground();
if (_mask != nullptr) {
switch (_currentScene) {
case 7:
screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x - SHERLOCK_SCREEN_WIDTH, 110), screen._currentScroll);
screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 110), screen._currentScroll);
screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x + SHERLOCK_SCREEN_WIDTH, 110), screen._currentScroll);
break;
case 8:
screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x - SHERLOCK_SCREEN_WIDTH, 180), screen._currentScroll);
screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 180), screen._currentScroll);
screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x + SHERLOCK_SCREEN_WIDTH, 180), screen._currentScroll);
if (!_vm->readFlags(880))
screen._backBuffer1.maskArea((*_mask1)[0], Common::Point(940, 300), screen._currentScroll);
break;
case 18:
screen._backBuffer1.maskArea((*_mask)[0], Common::Point(0, 203), screen._currentScroll);
if (!_vm->readFlags(189))
screen._backBuffer1.maskArea((*_mask1)[0], Common::Point(124, 239), screen._currentScroll);
break;
case 53:
screen._backBuffer1.maskArea((*_mask)[0], Common::Point(_maskOffset.x, 110), screen._currentScroll);
break;
case 68:
screen._backBuffer1.maskArea((*_mask)[0], Common::Point(0, 203), screen._currentScroll);
screen._backBuffer1.maskArea((*_mask1)[0], Common::Point(124, 239), screen._currentScroll);
break;
default:
break;
}
}
screen._flushScreen = true;
for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
Person &p = people[idx];
if (p._type != INVALID) {
if (_goToScene == -1 || _cAnim.size() == 0) {
if (p._type == REMOVE) {
screen.slamArea(p._oldPosition.x, p._oldPosition.y, p._oldSize.x, p._oldSize.y);
p._type = INVALID;
} else {
if (p._tempScaleVal == 256) {
screen.flushImage(p._imageFrame, Common::Point(p._tempX, p._position.y / FIXED_INT_MULTIPLIER
- p._imageFrame->_width), &p._oldPosition.x, &p._oldPosition.y, &p._oldSize.x, &p._oldSize.y);
} else {
int ts = p._imageFrame->sDrawYSize(p._tempScaleVal);
int ty = p._position.y / FIXED_INT_MULTIPLIER - ts;
screen.flushScaleImage(p._imageFrame, Common::Point(p._tempX, ty),
&p._oldPosition.x, &p._oldPosition.y, &p._oldSize.x, &p._oldSize.y, p._tempScaleVal);
}
}
}
}
}
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &obj = _bgShapes[idx];
if (obj._type == ACTIVE_BG_SHAPE || obj._type == REMOVE) {
if (_goToScene == -1) {
if (obj._scaleVal == 256)
screen.flushImage(obj._imageFrame, obj._position, &obj._oldPosition.x, &obj._oldPosition.y,
&obj._oldSize.x, &obj._oldSize.y);
else
screen.flushScaleImage(obj._imageFrame, obj._position, &obj._oldPosition.x, &obj._oldPosition.y,
&obj._oldSize.x, &obj._oldSize.y, obj._scaleVal);
if (obj._type == REMOVE)
obj._type = INVALID;
}
}
}
for (uint idx = 0; idx < _bgShapes.size(); ++idx) {
Object &obj = _bgShapes[idx];
if (_goToScene == -1) {
if (obj._type == NO_SHAPE && (obj._flags & 1) == 0) {
screen.slamRect(obj.getNoShapeBounds());
screen.slamRect(obj.getOldBounds());
} else if (obj._type == HIDE_SHAPE) {
if (obj._scaleVal == 256)
screen.flushImage(obj._imageFrame, obj._position, &obj._oldPosition.x, &obj._oldPosition.y,
&obj._oldSize.x, &obj._oldSize.y);
else
screen.flushScaleImage(obj._imageFrame, obj._position, &obj._oldPosition.x, &obj._oldPosition.y,
&obj._oldSize.x, &obj._oldSize.y, obj._scaleVal);
obj._type = HIDDEN;
}
}
}
screen._flushScreen = false;
}
} // End of namespace Tattoo
} // End of namespace Sherlock

View File

@ -0,0 +1,77 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef SHERLOCK_TATTOO_SCENE_H
#define SHERLOCK_TATTOO_SCENE_H
#include "common/scummsys.h"
#include "sherlock/scene.h"
namespace Sherlock {
namespace Tattoo {
class TattooScene : public Scene {
private:
int _arrowZone;
int _maskCounter;
Common::Point _maskOffset;
private:
void doBgAnimCheckCursor();
void doBgAnimEraseBackground();
/**
* Update the background objects and canimations as part of doBgAnim
*/
void doBgAnimUpdateBgObjectsAndAnim();
protected:
/**
* Checks all the background shapes. If a background shape is animating,
* it will flag it as needing to be drawn. If a non-animating shape is
* colliding with another shape, it will also flag it as needing drawing
*/
virtual void checkBgShapes();
public:
ImageFile *_mask, *_mask1;
CAnimStream _activeCAnim;
public:
TattooScene(SherlockEngine *vm);
/**
* Draw all objects and characters.
*/
virtual void doBgAnim();
/**
* Update the screen back buffer with all of the scene objects which need
* to be drawn
*/
virtual void updateBackground();
};
} // End of namespace Tattoo
} // End of namespace Sherlock
#endif

View File

@ -0,0 +1,150 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "sherlock/tattoo/tattoo_user_interface.h"
#include "sherlock/tattoo/tattoo_scene.h"
#include "sherlock/tattoo/tattoo.h"
namespace Sherlock {
namespace Tattoo {
TattooUserInterface::TattooUserInterface(SherlockEngine *vm): UserInterface(vm) {
_menuBuffer = nullptr;
_invMenuBuffer = nullptr;
_tagBuffer = nullptr;
_invGraphic = nullptr;
}
void TattooUserInterface::handleInput() {
// TODO
_vm->_events->pollEventsAndWait();
}
void TattooUserInterface::drawInterface(int bufferNum) {
Screen &screen = *_vm->_screen;
TattooEngine &vm = *((TattooEngine *)_vm);
if (_invMenuBuffer != nullptr) {
Common::Rect r = _invMenuBounds;
r.grow(-3);
r.translate(-screen._currentScroll, 0);
_grayAreas.clear();
_grayAreas.push_back(r);
drawGrayAreas();
screen._backBuffer1.transBlitFrom(*_invMenuBuffer, Common::Point(_invMenuBounds.left, _invMenuBounds.top));
}
if (_menuBuffer != nullptr) {
Common::Rect r = _menuBounds;
r.grow(-3);
r.translate(-screen._currentScroll, 0);
_grayAreas.clear();
_grayAreas.push_back(r);
drawGrayAreas();
screen._backBuffer1.transBlitFrom(*_menuBuffer, Common::Point(_invMenuBounds.left, _invMenuBounds.top));
}
// See if we need to draw a Text Tag floating with the cursor
if (_tagBuffer != nullptr)
screen._backBuffer1.transBlitFrom(*_tagBuffer, Common::Point(_tagBounds.left, _tagBounds.top));
// See if we need to draw an Inventory Item Graphic floating with the cursor
if (_invGraphic != nullptr)
screen._backBuffer1.transBlitFrom(*_invGraphic, Common::Point(_invGraphicBounds.left, _invGraphicBounds.top));
if (vm._creditsActive)
vm.drawCredits();
}
void TattooUserInterface::doBgAnimRestoreUI() {
TattooScene &scene = *((TattooScene *)_vm->_scene);
Screen &screen = *_vm->_screen;
// If _oldMenuBounds was set, then either a new menu has been opened or the current menu has been closed.
// Either way, we need to restore the area where the menu was displayed
if (_oldMenuBounds.width() > 0)
screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldMenuBounds.left, _oldMenuBounds.top),
_oldMenuBounds);
if (_oldInvMenuBounds.width() > 0)
screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldInvMenuBounds.left, _oldInvMenuBounds.top),
_oldInvMenuBounds);
if (_menuBuffer != nullptr)
screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_menuBounds.left, _menuBounds.top), _menuBounds);
if (_invMenuBuffer != nullptr)
screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_invMenuBounds.left, _invMenuBounds.top), _invMenuBounds);
// If there is a Text Tag being display, restore the area underneath it
if (_oldTagBounds.width() > 0)
screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldTagBounds.left, _oldTagBounds.top),
_oldTagBounds);
// If there is an Inventory being shown, restore the graphics underneath it
if (_oldInvGraphicBounds.width() > 0)
screen._backBuffer1.blitFrom(screen._backBuffer2, Common::Point(_oldInvGraphicBounds.left, _oldInvGraphicBounds.top),
_oldInvGraphicBounds);
// If a canimation is active, restore the graphics underneath it
if (scene._activeCAnim._images != nullptr)
screen.restoreBackground(scene._activeCAnim._oldBounds);
// If a canimation just ended, remove it's graphics from the backbuffer
if (scene._activeCAnim._removeBounds.width() > 0)
screen.restoreBackground(scene._activeCAnim._removeBounds);
}
void TattooUserInterface::doScroll() {
Screen &screen = *_vm->_screen;
int oldScroll = screen._currentScroll;
// If we're already at the target scroll position, nothing needs to be done
if (screen._targetScroll == screen._currentScroll)
return;
screen._flushScreen = true;
if (screen._targetScroll > screen._currentScroll) {
screen._currentScroll += screen._scrollSpeed;
if (screen._currentScroll > screen._targetScroll)
screen._currentScroll = screen._targetScroll;
} else if (screen._targetScroll < screen._currentScroll) {
screen._currentScroll -= screen._scrollSpeed;
if (screen._currentScroll < screen._targetScroll)
screen._currentScroll = screen._targetScroll;
}
if (_menuBuffer != nullptr)
_menuBounds.translate(screen._currentScroll - oldScroll, 0);
if (_invMenuBuffer != nullptr)
_invMenuBounds.translate(screen._currentScroll - oldScroll, 0);
}
void TattooUserInterface::drawGrayAreas() {
// TODO
}
} // End of namespace Tattoo
} // End of namespace Sherlock

View File

@ -0,0 +1,83 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef SHERLOCK_TATTOO_UI_H
#define SHERLOCK_TATTOO_UI_H
#include "common/scummsys.h"
#include "sherlock/user_interface.h"
namespace Sherlock {
namespace Tattoo {
class TattooUserInterface : public UserInterface {
private:
Common::Rect _menuBounds;
Common::Rect _oldMenuBounds;
Common::Rect _invMenuBounds;
Common::Rect _oldInvMenuBounds;
Common::Rect _tagBounds;
Common::Rect _oldTagBounds;
Common::Rect _invGraphicBounds;
Common::Rect _oldInvGraphicBounds;
Surface *_menuBuffer;
Surface *_invMenuBuffer;
Surface *_tagBuffer;
Surface *_invGraphic;
Common::Array<Common::Rect> _grayAreas;
private:
/**
* Draws designated areas of the screen that are meant to be grayed out using grayscale colors
*/
void drawGrayAreas();
public:
TattooUserInterface(SherlockEngine *vm);
/**
* Handles restoring any areas of the back buffer that were/are covered by UI elements
*/
void doBgAnimRestoreUI();
/**
* Checks to see if the screen needs to be scrolled. If so, scrolls it towards the target position
*/
void doScroll();
public:
virtual ~TattooUserInterface() {}
/**
* Main input handler for the user interface
*/
virtual void handleInput();
/**
* Draw the user interface onto the screen's back buffers
*/
virtual void drawInterface(int bufferNum = 3);
};
} // End of namespace Tattoo
} // End of namespace Sherlock
#endif

File diff suppressed because it is too large Load Diff

View File

@ -50,134 +50,11 @@ enum MenuMode {
SETUP_MODE = 12
};
extern const char COMMANDS[13];
extern const int MENU_POINTS[12][4];
extern const int INVENTORY_POINTS[8][3];
extern const char INVENTORY_COMMANDS[9];
extern const char *const PRESS_KEY_FOR_MORE;
extern const char *const PRESS_KEY_TO_CONTINUE;
class SherlockEngine;
class Inventory;
class Talk;
class UserInterface;
class UserInterface {
friend class Inventory;
friend class Settings;
friend class Talk;
private:
protected:
SherlockEngine *_vm;
ImageFile *_controlPanel;
ImageFile *_controls;
int _bgFound;
int _oldBgFound;
char _keyPress;
int _lookHelp;
int _help, _oldHelp;
char _key, _oldKey;
int _temp, _oldTemp;
int _oldLook;
bool _keyboardInput;
bool _pause;
int _cNum;
int _selector, _oldSelector;
Common::String _cAnimStr;
bool _lookScriptFlag;
Common::Rect _windowBounds;
Common::String _descStr;
int _find;
int _oldUse;
private:
/**
* Draws the image for a user interface button in the down/pressed state.
*/
void depressButton(int num);
/**
* If he mouse button is pressed, then calls depressButton to draw the button
* as pressed; if not, it will show it as released with a call to "restoreButton".
*/
void pushButton(int num);
/**
* By the time this method has been called, the graphics for the button change
* have already been drawn. This simply takes care of switching the mode around
* accordingly
*/
void toggleButton(int num);
/**
* Creates a text window and uses it to display the in-depth description
* of the highlighted object
*/
void examine();
/**
* Print the name of an object in the scene
*/
void lookScreen(const Common::Point &pt);
/**
* Gets the item in the inventory the mouse is on and display's it's description
*/
void lookInv();
/**
* Handles input when the file list window is being displayed
*/
void doEnvControl();
/**
* Handle input whilst the inventory is active
*/
void doInvControl();
/**
* Handles waiting whilst an object's description window is open.
*/
void doLookControl();
/**
* Handles input until one of the user interface buttons/commands is selected
*/
void doMainControl();
/**
* Handles the input for the MOVE, OPEN, and CLOSE commands
*/
void doMiscControl(int allowed);
/**
* Handles input for picking up items
*/
void doPickControl();
/**
* Handles input when in talk mode. It highlights the buttons and available statements,
* and handles allowing the user to click on them
*/
void doTalkControl();
/**
* Handles events when the Journal is active.
* @remarks Whilst this would in theory be better in the Journal class, since it displays in
* the user interface, it uses so many internal UI fields, that it sort of made some sense
* to put it in the UserInterface class.
*/
void journalControl();
/**
* Checks to see whether a USE action is valid on the given object
*/
void checkUseAction(const UseType *use, const Common::String &invName, const char *const messages[],
int objNum, bool giveMode);
/**
* Called for OPEN, CLOSE, and MOVE actions are being done
*/
void checkAction(ActionType &action, const char *const messages[], int objNum);
UserInterface(SherlockEngine *vm);
public:
MenuMode _menuMode;
int _menuCounter;
@ -185,74 +62,67 @@ public:
bool _windowOpen;
bool _endKeyActive;
int _invLookFlag;
int _temp1;
bool _slideWindows;
bool _helpStyle;
Common::Rect _windowBounds;
bool _lookScriptFlag;
// TODO: Not so sure these should be in the base class. May want to refactor them to SherlockEngine, or refactor
// various Scalpel dialogs to keep their own private state of key/selections
char _key, _oldKey;
int _selector, _oldSelector;
int _temp, _oldTemp;
int _temp1;
int _lookHelp;
public:
UserInterface(SherlockEngine *vm);
~UserInterface();
static UserInterface *init(SherlockEngine *vm);
virtual ~UserInterface() {}
/**
* Resets the user interface
*/
void reset();
virtual void reset() {}
/**
* Draw the user interface onto the screen's back buffers
*/
void drawInterface(int bufferNum = 3);
*/
virtual void drawInterface(int bufferNum = 3) {}
/**
* Main input handler for the user interface
*/
void handleInput();
/**
* Clears the info line of the screen
*/
void clearInfo();
/**
* Clear any active text window
*/
void clearWindow();
/**
* Handles counting down whilst checking for input, then clears the info line.
*/
void whileMenuCounter();
/**
* Print the description of an object
*/
void printObjectDesc(const Common::String &str, bool firstTime);
/**
* Print the previously selected object's decription
*/
void printObjectDesc();
virtual void handleInput() {}
/**
* Displays a passed window by gradually scrolling it vertically on-screen
*/
void summonWindow(const Surface &bgSurface, bool slideUp = true);
virtual void summonWindow(const Surface &bgSurface, bool slideUp = true) {}
/**
* Slide the window stored in the back buffer onto the screen
*/
void summonWindow(bool slideUp = true, int height = CONTROLS_Y);
virtual void summonWindow(bool slideUp = true, int height = CONTROLS_Y) {}
/**
* Close a currently open window
* @param flag 0 = slide old window down, 1 = slide prior UI back up
*/
void banishWindow(bool slideUp = true);
virtual void banishWindow(bool slideUp = true) {}
/**
* Draws the image for the given user interface button in the up
* (not selected) position
* Clears the info line of the screen
*/
void restoreButton(int num);
virtual void clearInfo() {}
/**
* Clear any active text window
*/
virtual void clearWindow() {}
/**
* Print the previously selected object's decription
*/
virtual void printObjectDesc() {}
};
} // End of namespace Sherlock