mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-23 20:51:14 +00:00
Merge branch 'sherlock2'
This commit is contained in:
commit
6b95fc6b11
128
engines/sherlock/decompress.cpp
Normal file
128
engines/sherlock/decompress.cpp
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "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
|
@ -42,6 +42,8 @@ Events::Events(SherlockEngine *vm) {
|
|||||||
_pressed = _released = false;
|
_pressed = _released = false;
|
||||||
_rightPressed = _rightReleased = false;
|
_rightPressed = _rightReleased = false;
|
||||||
_oldButtons = _oldRightButton = false;
|
_oldButtons = _oldRightButton = false;
|
||||||
|
|
||||||
|
loadCursors("rmouse.vgs");
|
||||||
}
|
}
|
||||||
|
|
||||||
Events::~Events() {
|
Events::~Events() {
|
||||||
@ -73,6 +75,14 @@ void Events::setCursor(const Graphics::Surface &src) {
|
|||||||
showCursor();
|
showCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Events::animateCursorIfNeeded() {
|
||||||
|
if (_cursorId >= WAIT && _cursorId < (WAIT + 3)) {
|
||||||
|
CursorId newId = (WAIT + 2) ? WAIT : (CursorId)((int)_cursorId + 1);
|
||||||
|
setCursor(newId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Events::showCursor() {
|
void Events::showCursor() {
|
||||||
CursorMan.showMouse(true);
|
CursorMan.showMouse(true);
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ namespace Sherlock {
|
|||||||
#define GAME_FRAME_RATE 60
|
#define GAME_FRAME_RATE 60
|
||||||
#define GAME_FRAME_TIME (1000 / GAME_FRAME_RATE)
|
#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;
|
class SherlockEngine;
|
||||||
|
|
||||||
@ -77,6 +77,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
void setCursor(const Graphics::Surface &src);
|
void setCursor(const Graphics::Surface &src);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animates the mouse cursor if the Wait cursor is showing
|
||||||
|
*/
|
||||||
|
void animateCursorIfNeeded();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the mouse cursor
|
* Show the mouse cursor
|
||||||
*/
|
*/
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include "sherlock/inventory.h"
|
#include "sherlock/inventory.h"
|
||||||
#include "sherlock/sherlock.h"
|
#include "sherlock/sherlock.h"
|
||||||
|
#include "sherlock/scalpel/scalpel_user_interface.h"
|
||||||
|
|
||||||
namespace Sherlock {
|
namespace Sherlock {
|
||||||
|
|
||||||
@ -200,29 +201,29 @@ void Inventory::drawInventory(InvNewMode mode) {
|
|||||||
INV_BACKGROUND);
|
INV_BACKGROUND);
|
||||||
|
|
||||||
// Draw the buttons
|
// Draw the buttons
|
||||||
screen.makeButton(Common::Rect(INVENTORY_POINTS[0][0], CONTROLS_Y1, INVENTORY_POINTS[0][1],
|
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[0][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[0][1],
|
||||||
CONTROLS_Y1 + 10), INVENTORY_POINTS[0][2] - screen.stringWidth("Exit") / 2, "Exit");
|
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[0][2] - screen.stringWidth("Exit") / 2, "Exit");
|
||||||
screen.makeButton(Common::Rect(INVENTORY_POINTS[1][0], CONTROLS_Y1, INVENTORY_POINTS[1][1],
|
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[1][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[1][1],
|
||||||
CONTROLS_Y1 + 10), INVENTORY_POINTS[1][2] - screen.stringWidth("Look") / 2, "Look");
|
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[1][2] - screen.stringWidth("Look") / 2, "Look");
|
||||||
screen.makeButton(Common::Rect(INVENTORY_POINTS[2][0], CONTROLS_Y1, INVENTORY_POINTS[2][1],
|
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[2][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[2][1],
|
||||||
CONTROLS_Y1 + 10), INVENTORY_POINTS[2][2] - screen.stringWidth("Use") / 2, "Use");
|
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[2][2] - screen.stringWidth("Use") / 2, "Use");
|
||||||
screen.makeButton(Common::Rect(INVENTORY_POINTS[3][0], CONTROLS_Y1, INVENTORY_POINTS[3][1],
|
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[3][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[3][1],
|
||||||
CONTROLS_Y1 + 10), INVENTORY_POINTS[3][2] - screen.stringWidth("Give") / 2, "Give");
|
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[3][2] - screen.stringWidth("Give") / 2, "Give");
|
||||||
screen.makeButton(Common::Rect(INVENTORY_POINTS[4][0], CONTROLS_Y1, INVENTORY_POINTS[4][1],
|
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[4][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[4][1],
|
||||||
CONTROLS_Y1 + 10), INVENTORY_POINTS[4][2], "^^");
|
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[4][2], "^^");
|
||||||
screen.makeButton(Common::Rect(INVENTORY_POINTS[5][0], CONTROLS_Y1, INVENTORY_POINTS[5][1],
|
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[5][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[5][1],
|
||||||
CONTROLS_Y1 + 10), INVENTORY_POINTS[5][2], "^");
|
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[5][2], "^");
|
||||||
screen.makeButton(Common::Rect(INVENTORY_POINTS[6][0], CONTROLS_Y1, INVENTORY_POINTS[6][1],
|
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[6][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[6][1],
|
||||||
CONTROLS_Y1 + 10), INVENTORY_POINTS[6][2], "_");
|
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[6][2], "_");
|
||||||
screen.makeButton(Common::Rect(INVENTORY_POINTS[7][0], CONTROLS_Y1, INVENTORY_POINTS[7][1],
|
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[7][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[7][1],
|
||||||
CONTROLS_Y1 + 10), INVENTORY_POINTS[7][2], "__");
|
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[7][2], "__");
|
||||||
|
|
||||||
if (tempMode == INVENTORY_DONT_DISPLAY)
|
if (tempMode == INVENTORY_DONT_DISPLAY)
|
||||||
mode = LOOK_INVENTORY_MODE;
|
mode = LOOK_INVENTORY_MODE;
|
||||||
_invMode = (InvMode)mode;
|
_invMode = (InvMode)mode;
|
||||||
|
|
||||||
if (mode != PLAIN_INVENTORY) {
|
if (mode != PLAIN_INVENTORY) {
|
||||||
ui._oldKey = INVENTORY_COMMANDS[(int)mode];
|
ui._oldKey = Scalpel::INVENTORY_COMMANDS[(int)mode];
|
||||||
} else {
|
} else {
|
||||||
ui._oldKey = -1;
|
ui._oldKey = -1;
|
||||||
}
|
}
|
||||||
@ -243,7 +244,8 @@ void Inventory::drawInventory(InvNewMode mode) {
|
|||||||
screen._backBuffer = &screen._backBuffer1;
|
screen._backBuffer = &screen._backBuffer1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui._oldUse = -1;
|
assert(IS_SERRATED_SCALPEL);
|
||||||
|
((Scalpel::ScalpelUserInterface *)_vm->_ui)->_oldUse = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Inventory::invCommands(bool slamIt) {
|
void Inventory::invCommands(bool slamIt) {
|
||||||
@ -251,55 +253,55 @@ void Inventory::invCommands(bool slamIt) {
|
|||||||
UserInterface &ui = *_vm->_ui;
|
UserInterface &ui = *_vm->_ui;
|
||||||
|
|
||||||
if (slamIt) {
|
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,
|
_invMode == INVMODE_EXIT ? COMMAND_HIGHLIGHTED :COMMAND_FOREGROUND,
|
||||||
true, "Exit");
|
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,
|
_invMode == INVMODE_LOOK ? COMMAND_HIGHLIGHTED :COMMAND_FOREGROUND,
|
||||||
true, "Look");
|
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,
|
_invMode == INVMODE_USE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
|
||||||
true, "Use");
|
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,
|
_invMode == INVMODE_GIVE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
|
||||||
true, "Give");
|
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,
|
_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,
|
_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,
|
(_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,
|
(_holdings - _invIndex <= 6) ? COMMAND_NULL : COMMAND_FOREGROUND,
|
||||||
"__");
|
"__");
|
||||||
if (_invMode != INVMODE_LOOK)
|
if (_invMode != INVMODE_LOOK)
|
||||||
ui.clearInfo();
|
ui.clearInfo();
|
||||||
} else {
|
} 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,
|
_invMode == INVMODE_EXIT ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
|
||||||
false, "Exit");
|
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,
|
_invMode == INVMODE_LOOK ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
|
||||||
false, "Look");
|
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,
|
_invMode == INVMODE_USE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
|
||||||
false, "Use");
|
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,
|
_invMode == INVMODE_GIVE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
|
||||||
false, "Give");
|
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,
|
_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,
|
_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,
|
(_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,
|
(_holdings - _invIndex < 7) ? COMMAND_NULL : COMMAND_FOREGROUND,
|
||||||
"__");
|
"__");
|
||||||
}
|
}
|
||||||
@ -318,9 +320,12 @@ void Inventory::highlight(int index, byte color) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Inventory::refreshInv() {
|
void Inventory::refreshInv() {
|
||||||
|
if (IS_ROSE_TATTOO)
|
||||||
|
return;
|
||||||
|
|
||||||
Screen &screen = *_vm->_screen;
|
Screen &screen = *_vm->_screen;
|
||||||
Talk &talk = *_vm->_talk;
|
Talk &talk = *_vm->_talk;
|
||||||
UserInterface &ui = *_vm->_ui;
|
Scalpel::ScalpelUserInterface &ui = *(Scalpel::ScalpelUserInterface *)_vm->_ui;
|
||||||
|
|
||||||
ui._invLookFlag = true;
|
ui._invLookFlag = true;
|
||||||
freeInv();
|
freeInv();
|
||||||
|
@ -135,6 +135,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
|
|||||||
Screen &screen = *_vm->_screen;
|
Screen &screen = *_vm->_screen;
|
||||||
Talk &talk = *_vm->_talk;
|
Talk &talk = *_vm->_talk;
|
||||||
JournalEntry &journalEntry = _journal[_index];
|
JournalEntry &journalEntry = _journal[_index];
|
||||||
|
const byte *opcodes = talk._opcodes;
|
||||||
|
|
||||||
Common::String dirFilename = _directory[journalEntry._converseNum];
|
Common::String dirFilename = _directory[journalEntry._converseNum];
|
||||||
bool replyOnly = journalEntry._replyOnly;
|
bool replyOnly = journalEntry._replyOnly;
|
||||||
@ -243,7 +244,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
|
|||||||
byte c = *replyP++;
|
byte c = *replyP++;
|
||||||
|
|
||||||
// Is it a control character?
|
// Is it a control character?
|
||||||
if (c < SWITCH_SPEAKER) {
|
if (c < opcodes[0]) {
|
||||||
// Nope. Set flag for allowing control codes to insert spaces
|
// Nope. Set flag for allowing control codes to insert spaces
|
||||||
ctrlSpace = true;
|
ctrlSpace = true;
|
||||||
assert(c >= ' ');
|
assert(c >= ' ');
|
||||||
@ -290,7 +291,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
|
|||||||
byte v;
|
byte v;
|
||||||
do {
|
do {
|
||||||
v = *strP++;
|
v = *strP++;
|
||||||
} while (v && (v < SWITCH_SPEAKER) && (v != '.') && (v != '!') && (v != '?'));
|
} while (v && (v < opcodes[0]) && (v != '.') && (v != '!') && (v != '?'));
|
||||||
|
|
||||||
if (v == '?')
|
if (v == '?')
|
||||||
journalString += " asked, \"";
|
journalString += " asked, \"";
|
||||||
@ -306,11 +307,11 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
|
|||||||
journalString += c;
|
journalString += c;
|
||||||
do {
|
do {
|
||||||
journalString += *replyP++;
|
journalString += *replyP++;
|
||||||
} while (*replyP && *replyP < SWITCH_SPEAKER && *replyP != '{' && *replyP != '}');
|
} while (*replyP && *replyP < opcodes[0] && *replyP != '{' && *replyP != '}');
|
||||||
|
|
||||||
commentJustPrinted = false;
|
commentJustPrinted = false;
|
||||||
}
|
}
|
||||||
} else if (c == SWITCH_SPEAKER) {
|
} else if (c == opcodes[OP_SWITCH_SPEAKER]) {
|
||||||
if (!startOfReply) {
|
if (!startOfReply) {
|
||||||
if (!commentFlag && !commentJustPrinted)
|
if (!commentFlag && !commentJustPrinted)
|
||||||
journalString += "\"\n";
|
journalString += "\"\n";
|
||||||
@ -337,7 +338,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
|
|||||||
byte v;
|
byte v;
|
||||||
do {
|
do {
|
||||||
v = *strP++;
|
v = *strP++;
|
||||||
} while (v && v < SWITCH_SPEAKER && v != '.' && v != '!' && v != '?');
|
} while (v && v < opcodes[0] && v != '.' && v != '!' && v != '?');
|
||||||
|
|
||||||
if (v == '?')
|
if (v == '?')
|
||||||
journalString += " asked, \"";
|
journalString += " asked, \"";
|
||||||
@ -345,59 +346,42 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
|
|||||||
journalString += " said, \"";
|
journalString += " said, \"";
|
||||||
} else {
|
} else {
|
||||||
// Control code, so move past it and any parameters
|
// Control code, so move past it and any parameters
|
||||||
switch (c) {
|
if (c == opcodes[OP_RUN_CANIMATION] || c == opcodes[OP_ASSIGN_PORTRAIT_LOCATION] ||
|
||||||
case RUN_CANIMATION:
|
c == opcodes[OP_PAUSE] || c == opcodes[OP_PAUSE_WITHOUT_CONTROL] ||
|
||||||
case ASSIGN_PORTRAIT_LOCATION:
|
c == opcodes[OP_WALK_TO_CANIMATION]) {
|
||||||
case PAUSE:
|
|
||||||
case PAUSE_WITHOUT_CONTROL:
|
|
||||||
case WALK_TO_CANIMATION:
|
|
||||||
// These commands have a single parameter
|
// These commands have a single parameter
|
||||||
++replyP;
|
++replyP;
|
||||||
break;
|
|
||||||
|
|
||||||
case ADJUST_OBJ_SEQUENCE:
|
} else if (c == opcodes[OP_ADJUST_OBJ_SEQUENCE]) {
|
||||||
replyP += (replyP[0] & 127) + replyP[1] + 2;
|
replyP += (replyP[0] & 127) + replyP[1] + 2;
|
||||||
break;
|
|
||||||
|
|
||||||
case WALK_TO_COORDS:
|
} else if (c == opcodes[OP_WALK_TO_COORDS] || c == opcodes[OP_MOVE_MOUSE]) {
|
||||||
case MOVE_MOUSE:
|
|
||||||
replyP += 4;
|
replyP += 4;
|
||||||
break;
|
|
||||||
|
} else if (c == opcodes[OP_SET_FLAG] || c == opcodes[OP_IF_STATEMENT]) {
|
||||||
case SET_FLAG:
|
|
||||||
case IF_STATEMENT:
|
|
||||||
replyP += 2;
|
replyP += 2;
|
||||||
break;
|
|
||||||
|
|
||||||
case SFX_COMMAND:
|
} else if (c == opcodes[OP_SFX_COMMAND] || c == opcodes[OP_PLAY_PROLOGUE] ||
|
||||||
case PLAY_PROLOGUE:
|
c == opcodes[OP_CALL_TALK_FILE]) {
|
||||||
case CALL_TALK_FILE:
|
|
||||||
replyP += 8;
|
replyP += 8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOGGLE_OBJECT:
|
} else if (c == opcodes[OP_TOGGLE_OBJECT] || c == opcodes[OP_ADD_ITEM_TO_INVENTORY] ||
|
||||||
case ADD_ITEM_TO_INVENTORY:
|
c == opcodes[OP_SET_OBJECT] || c == opcodes[OP_DISPLAY_INFO_LINE] ||
|
||||||
case SET_OBJECT:
|
c == opcodes[OP_REMOVE_ITEM_FROM_INVENTORY]) {
|
||||||
case DISPLAY_INFO_LINE:
|
|
||||||
case REMOVE_ITEM_FROM_INVENTORY:
|
|
||||||
replyP += (*replyP & 127) + 1;
|
replyP += (*replyP & 127) + 1;
|
||||||
break;
|
|
||||||
|
|
||||||
case GOTO_SCENE:
|
} else if (c == opcodes[OP_GOTO_SCENE]) {
|
||||||
replyP += 5;
|
replyP += 5;
|
||||||
break;
|
|
||||||
|
|
||||||
case CARRIAGE_RETURN:
|
} else if (c == opcodes[OP_CARRIAGE_RETURN]) {
|
||||||
journalString += "\n";
|
journalString += "\n";
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put a space in the output for a control character, unless it's
|
// Put a space in the output for a control character, unless it's
|
||||||
// immediately coming after another control character
|
// 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 += " ";
|
journalString += " ";
|
||||||
ctrlSpace = false;
|
ctrlSpace = false;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include "sherlock/map.h"
|
#include "sherlock/map.h"
|
||||||
#include "sherlock/sherlock.h"
|
#include "sherlock/sherlock.h"
|
||||||
|
#include "common/system.h"
|
||||||
|
|
||||||
namespace Sherlock {
|
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;
|
_active = false;
|
||||||
_mapCursors = nullptr;
|
_mapCursors = nullptr;
|
||||||
_shapes = nullptr;
|
_shapes = nullptr;
|
||||||
@ -64,8 +65,12 @@ Map::Map(SherlockEngine *vm) : _vm(vm), _topLine(SHERLOCK_SCREEN_WIDTH, 12) {
|
|||||||
_oldCharPoint = 0;
|
_oldCharPoint = 0;
|
||||||
_frameChangeFlag = false;
|
_frameChangeFlag = false;
|
||||||
|
|
||||||
for (int idx = 0; idx < MAX_HOLMES_SEQUENCE; ++idx)
|
// Initialise the initial walk sequence set
|
||||||
Common::fill(&_sequences[idx][0], &_sequences[idx][MAX_FRAME], 0);
|
_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())
|
if (!_vm->isDemo())
|
||||||
loadData();
|
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) {
|
void Map::loadSequences(int count, const byte *seq) {
|
||||||
for (int idx = 0; idx < count; ++idx, seq += MAX_FRAME)
|
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() {
|
void Map::loadData() {
|
||||||
|
// TODO: Remove this
|
||||||
|
if (_vm->getGameID() == GType_RoseTattoo)
|
||||||
|
return;
|
||||||
|
|
||||||
// Load the list of location names
|
// 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();
|
int streamSize = txtStream->size();
|
||||||
while (txtStream->pos() < streamSize) {
|
while (txtStream->pos() < streamSize) {
|
||||||
@ -283,7 +293,6 @@ void Map::setupSprites() {
|
|||||||
p._type = CHARACTER;
|
p._type = CHARACTER;
|
||||||
p._position = Common::Point(12400, 5000);
|
p._position = Common::Point(12400, 5000);
|
||||||
p._sequenceNumber = 0;
|
p._sequenceNumber = 0;
|
||||||
p._sequences = &_sequences;
|
|
||||||
p._images = _shapes;
|
p._images = _shapes;
|
||||||
p._imageFrame = nullptr;
|
p._imageFrame = nullptr;
|
||||||
p._frameNumber = 0;
|
p._frameNumber = 0;
|
||||||
@ -296,8 +305,8 @@ void Map::setupSprites() {
|
|||||||
p._noShapeSize = Common::Point(0, 0);
|
p._noShapeSize = Common::Point(0, 0);
|
||||||
p._goto = Common::Point(28000, 15000);
|
p._goto = Common::Point(28000, 15000);
|
||||||
p._status = 0;
|
p._status = 0;
|
||||||
|
p._walkSequences = _walkSequences;
|
||||||
p.setImageFrame();
|
p.setImageFrame();
|
||||||
|
|
||||||
scene._bgShapes.clear();
|
scene._bgShapes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ private:
|
|||||||
ImageFile *_mapCursors;
|
ImageFile *_mapCursors;
|
||||||
ImageFile *_shapes;
|
ImageFile *_shapes;
|
||||||
ImageFile *_iconShapes;
|
ImageFile *_iconShapes;
|
||||||
byte _sequences[MAX_HOLMES_SEQUENCE][MAX_FRAME];
|
WalkSequences _walkSequences;
|
||||||
Point32 _lDrawnPos;
|
Point32 _lDrawnPos;
|
||||||
int _point;
|
int _point;
|
||||||
bool _placesShown;
|
bool _placesShown;
|
||||||
|
@ -4,7 +4,12 @@ MODULE_OBJS = \
|
|||||||
scalpel/darts.o \
|
scalpel/darts.o \
|
||||||
scalpel/scalpel.o \
|
scalpel/scalpel.o \
|
||||||
scalpel/drivers/adlib.o \
|
scalpel/drivers/adlib.o \
|
||||||
|
scalpel/scalpel_scene.o \
|
||||||
|
scalpel/scalpel_user_interface.o \
|
||||||
|
scalpel/settings.o \
|
||||||
tattoo/tattoo.o \
|
tattoo/tattoo.o \
|
||||||
|
tattoo/tattoo_scene.o \
|
||||||
|
tattoo/tattoo_user_interface.o \
|
||||||
animation.o \
|
animation.o \
|
||||||
debugger.o \
|
debugger.o \
|
||||||
detection.o \
|
detection.o \
|
||||||
@ -19,7 +24,6 @@ MODULE_OBJS = \
|
|||||||
saveload.o \
|
saveload.o \
|
||||||
scene.o \
|
scene.o \
|
||||||
screen.o \
|
screen.o \
|
||||||
settings.o \
|
|
||||||
sherlock.o \
|
sherlock.o \
|
||||||
sound.o \
|
sound.o \
|
||||||
surface.o \
|
surface.o \
|
||||||
|
@ -272,6 +272,11 @@ bool Music::loadSong(int songNumber) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Music::loadSong(const Common::String &songName) {
|
||||||
|
warning("TODO: Music::loadSong");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Music::syncMusicSettings() {
|
void Music::syncMusicSettings() {
|
||||||
_musicOn = !ConfMan.getBool("mute") && !ConfMan.getBool("music_mute");
|
_musicOn = !ConfMan.getBool("mute") && !ConfMan.getBool("music_mute");
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool loadSong(int songNumber);
|
bool loadSong(int songNumber);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a specified song
|
||||||
|
*/
|
||||||
|
bool loadSong(const Common::String &songName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start playing a song
|
* Start playing a song
|
||||||
*/
|
*/
|
||||||
|
@ -46,7 +46,7 @@ void Sprite::clear() {
|
|||||||
_description = "";
|
_description = "";
|
||||||
_examine.clear();
|
_examine.clear();
|
||||||
_pickUp = "";
|
_pickUp = "";
|
||||||
_sequences = nullptr;
|
_walkSequences.clear();
|
||||||
_images = nullptr;
|
_images = nullptr;
|
||||||
_imageFrame = nullptr;
|
_imageFrame = nullptr;
|
||||||
_walkCount = 0;
|
_walkCount = 0;
|
||||||
@ -63,12 +63,26 @@ void Sprite::clear() {
|
|||||||
_status = 0;
|
_status = 0;
|
||||||
_misc = 0;
|
_misc = 0;
|
||||||
_numFrames = 0;
|
_numFrames = 0;
|
||||||
|
_altImages = nullptr;
|
||||||
|
_altSequences = false;
|
||||||
|
Common::fill(&_stopFrames[0], &_stopFrames[8], (ImageFrame *)nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sprite::setImageFrame() {
|
void Sprite::setImageFrame() {
|
||||||
int imageNumber = (*_sequences)[_sequenceNumber][_frameNumber] +
|
int frameNum = MAX(_frameNumber, 0);
|
||||||
(*_sequences)[_sequenceNumber][0] - 2;
|
int imageNumber = _walkSequences[_sequenceNumber][frameNum];
|
||||||
_imageFrame = &(*_images)[imageNumber];
|
|
||||||
|
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() {
|
void Sprite::adjustSprite() {
|
||||||
@ -113,14 +127,14 @@ void Sprite::adjustSprite() {
|
|||||||
people.gotoStand(*this);
|
people.gotoStand(*this);
|
||||||
}
|
}
|
||||||
} else if (!map._active) {
|
} else if (!map._active) {
|
||||||
_position.y = CLIP((int)_position.y, UPPER_LIMIT, LOWER_LIMIT);
|
_position.y = CLIP((int)_position.y, (int)UPPER_LIMIT, (int)LOWER_LIMIT);
|
||||||
_position.x = CLIP((int)_position.x, LEFT_LIMIT, RIGHT_LIMIT);
|
_position.x = CLIP((int)_position.x, (int)LEFT_LIMIT, (int)RIGHT_LIMIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!map._active || (map._frameChangeFlag = !map._frameChangeFlag))
|
if (!map._active || (map._frameChangeFlag = !map._frameChangeFlag))
|
||||||
++_frameNumber;
|
++_frameNumber;
|
||||||
|
|
||||||
if ((*_sequences)[_sequenceNumber][_frameNumber] == 0) {
|
if (_walkSequences[_sequenceNumber][_frameNumber] == 0) {
|
||||||
switch (_sequenceNumber) {
|
switch (_sequenceNumber) {
|
||||||
case STOP_UP:
|
case STOP_UP:
|
||||||
case STOP_DOWN:
|
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) {
|
void ActionType::load(Common::SeekableReadStream &s) {
|
||||||
char buffer[12];
|
char buffer[12];
|
||||||
|
|
||||||
@ -373,9 +415,14 @@ UseType::UseType() {
|
|||||||
_useFlag = 0;
|
_useFlag = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UseType::load(Common::SeekableReadStream &s) {
|
void UseType::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
|
||||||
char buffer[12];
|
char buffer[12];
|
||||||
|
|
||||||
|
if (isRoseTattoo) {
|
||||||
|
s.read(buffer, 12);
|
||||||
|
_verb = Common::String(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
_cAnimNum = s.readByte();
|
_cAnimNum = s.readByte();
|
||||||
_cAnimSpeed = s.readByte();
|
_cAnimSpeed = s.readByte();
|
||||||
if (_cAnimSpeed & 0x80)
|
if (_cAnimSpeed & 0x80)
|
||||||
@ -387,7 +434,9 @@ void UseType::load(Common::SeekableReadStream &s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_useFlag = s.readSint16LE();
|
_useFlag = s.readSint16LE();
|
||||||
s.skip(6);
|
|
||||||
|
if (!isRoseTattoo)
|
||||||
|
s.skip(6);
|
||||||
|
|
||||||
s.read(buffer, 12);
|
s.read(buffer, 12);
|
||||||
_target = Common::String(buffer);
|
_target = Common::String(buffer);
|
||||||
@ -434,9 +483,16 @@ Object::Object() {
|
|||||||
_descOffset = 0;
|
_descOffset = 0;
|
||||||
_seqCounter2 = 0;
|
_seqCounter2 = 0;
|
||||||
_seqSize = 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];
|
char buffer[41];
|
||||||
s.read(buffer, 12);
|
s.read(buffer, 12);
|
||||||
_name = Common::String(buffer);
|
_name = Common::String(buffer);
|
||||||
@ -468,10 +524,10 @@ void Object::load(Common::SeekableReadStream &s) {
|
|||||||
_goto.x = s.readSint16LE();
|
_goto.x = s.readSint16LE();
|
||||||
_goto.y = s.readSint16LE();
|
_goto.y = s.readSint16LE();
|
||||||
|
|
||||||
_pickup = s.readByte();
|
_pickup = isRoseTattoo ? 0 : s.readByte();
|
||||||
_defaultCommand = s.readByte();
|
_defaultCommand = isRoseTattoo ? 0 : s.readByte();
|
||||||
_lookFlag = s.readUint16LE();
|
_lookFlag = s.readSint16LE();
|
||||||
_pickupFlag = s.readUint16LE();
|
_pickupFlag = isRoseTattoo ? 0 : s.readSint16LE();
|
||||||
_requiredFlag = s.readSint16LE();
|
_requiredFlag = s.readSint16LE();
|
||||||
_noShapeSize.x = s.readUint16LE();
|
_noShapeSize.x = s.readUint16LE();
|
||||||
_noShapeSize.y = s.readUint16LE();
|
_noShapeSize.y = s.readUint16LE();
|
||||||
@ -479,26 +535,45 @@ void Object::load(Common::SeekableReadStream &s) {
|
|||||||
_misc = s.readByte();
|
_misc = s.readByte();
|
||||||
_maxFrames = s.readUint16LE();
|
_maxFrames = s.readUint16LE();
|
||||||
_flags = s.readByte();
|
_flags = s.readByte();
|
||||||
_aOpen.load(s);
|
|
||||||
|
if (!isRoseTattoo)
|
||||||
|
_aOpen.load(s);
|
||||||
|
|
||||||
_aType = (AType)s.readByte();
|
_aType = (AType)s.readByte();
|
||||||
_lookFrames = s.readByte();
|
_lookFrames = s.readByte();
|
||||||
_seqCounter = s.readByte();
|
_seqCounter = s.readByte();
|
||||||
_lookPosition.x = s.readUint16LE();
|
_lookPosition.x = s.readUint16LE();
|
||||||
_lookPosition.y = s.readByte();
|
_lookPosition.y = isRoseTattoo ? s.readSint16LE() : s.readByte();
|
||||||
_lookFacing = s.readByte();
|
_lookFacing = s.readByte();
|
||||||
_lookcAnim = s.readByte();
|
_lookcAnim = s.readByte();
|
||||||
_aClose.load(s);
|
|
||||||
|
if (!isRoseTattoo)
|
||||||
|
_aClose.load(s);
|
||||||
|
|
||||||
_seqStack = s.readByte();
|
_seqStack = s.readByte();
|
||||||
_seqTo = s.readByte();
|
_seqTo = s.readByte();
|
||||||
_descOffset = s.readUint16LE();
|
_descOffset = s.readUint16LE();
|
||||||
_seqCounter2 = s.readByte();
|
_seqCounter2 = s.readByte();
|
||||||
_seqSize = s.readUint16LE();
|
_seqSize = s.readUint16LE();
|
||||||
s.skip(1);
|
|
||||||
_aMove.load(s);
|
|
||||||
s.skip(8);
|
|
||||||
|
|
||||||
for (int idx = 0; idx < USE_COUNT; ++idx)
|
if (isRoseTattoo) {
|
||||||
_use[idx].load(s);
|
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() {
|
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];
|
char buffer[12];
|
||||||
s.read(buffer, 12);
|
s.read(buffer, 12);
|
||||||
_name = Common::String(buffer);
|
_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.x = s.readSint16LE();
|
||||||
_position.y = s.readSint16LE();
|
_position.y = s.readSint16LE();
|
||||||
_size = s.readUint32LE();
|
|
||||||
_type = (SpriteType)s.readUint16LE();
|
if (isRoseTattoo) {
|
||||||
_flags = s.readByte();
|
_flags = s.readByte();
|
||||||
|
_scaleVal = s.readSint16LE();
|
||||||
|
} else {
|
||||||
|
_size = s.readUint32LE();
|
||||||
|
_type = (SpriteType)s.readUint16LE();
|
||||||
|
_flags = s.readByte();
|
||||||
|
}
|
||||||
|
|
||||||
_goto.x = s.readSint16LE();
|
_goto.x = s.readSint16LE();
|
||||||
_goto.y = s.readSint16LE();
|
_goto.y = s.readSint16LE();
|
||||||
_gotoDir = 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() {
|
SceneImage::SceneImage() {
|
||||||
_images = nullptr;
|
_images = nullptr;
|
||||||
_maxFrames = 0;
|
_maxFrames = 0;
|
||||||
|
@ -46,7 +46,10 @@ enum SpriteType {
|
|||||||
REMOVE = 5, // Object should be removed next frame
|
REMOVE = 5, // Object should be removed next frame
|
||||||
NO_SHAPE = 6, // Background object with no shape
|
NO_SHAPE = 6, // Background object with no shape
|
||||||
HIDDEN = 7, // Hidden backgruond object
|
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 {
|
enum AType {
|
||||||
@ -73,6 +76,7 @@ enum {
|
|||||||
|
|
||||||
#define MAX_HOLMES_SEQUENCE 16
|
#define MAX_HOLMES_SEQUENCE 16
|
||||||
#define MAX_FRAME 30
|
#define MAX_FRAME 30
|
||||||
|
#define FIXED_INT_MULTIPLIER 100
|
||||||
|
|
||||||
// code put into sequences to defines 1-10 type seqs
|
// code put into sequences to defines 1-10 type seqs
|
||||||
#define SEQ_TO_CODE 67
|
#define SEQ_TO_CODE 67
|
||||||
@ -98,65 +102,24 @@ public:
|
|||||||
void operator-=(const Point32 &delta) { x -= delta.x; y -= delta.y; }
|
void operator-=(const Point32 &delta) { x -= delta.x; y -= delta.y; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Sprite {
|
|
||||||
private:
|
struct WalkSequence {
|
||||||
static SherlockEngine *_vm;
|
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:
|
public:
|
||||||
Common::String _name;
|
WalkSequences &operator=(const WalkSequences &src);
|
||||||
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; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { REVERSE_DIRECTION = 0x80 };
|
enum { REVERSE_DIRECTION = 0x80 };
|
||||||
@ -179,13 +142,106 @@ struct UseType {
|
|||||||
Common::String _names[NAMES_COUNT];
|
Common::String _names[NAMES_COUNT];
|
||||||
int _useFlag; // Which flag USE will set (if any)
|
int _useFlag; // Which flag USE will set (if any)
|
||||||
Common::String _target;
|
Common::String _target;
|
||||||
|
Common::String _verb;
|
||||||
|
|
||||||
UseType();
|
UseType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the data for the 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 };
|
enum { OBJ_BEHIND = 1, OBJ_FLIPPED = 2, OBJ_FORWARD = 4, TURNON_OBJ = 0x20, TURNOFF_OBJ = 0x40 };
|
||||||
@ -233,35 +289,45 @@ public:
|
|||||||
int _pickup;
|
int _pickup;
|
||||||
int _defaultCommand; // Default right-click command
|
int _defaultCommand; // Default right-click command
|
||||||
int _lookFlag; // Which flag LOOK will set (if any)
|
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
|
int _requiredFlag; // Object will be hidden if not set
|
||||||
Common::Point _noShapeSize; // Size of a NO_SHAPE
|
Common::Point _noShapeSize; // Size of a NO_SHAPE
|
||||||
int _status; // Status (open/closed, moved/not)
|
int _status; // Status (open/closed, moved/not)
|
||||||
int8 _misc; // Misc field -- use varies with type
|
int8 _misc; // Misc field -- use varies with type
|
||||||
int _maxFrames; // Number of frames
|
int _maxFrames; // Number of frames
|
||||||
int _flags; // Tells if object can be walked behind
|
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.
|
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 _lookFrames; // How many frames to play of the look anim before pausing
|
||||||
int _seqCounter; // How many times this sequence has been executed
|
int _seqCounter; // How many times this sequence has been executed
|
||||||
Common::Point _lookPosition; // Where to walk when examining object
|
Common::Point _lookPosition; // Where to walk when examining object
|
||||||
int _lookFacing; // Direction to face when examining object
|
int _lookFacing; // Direction to face when examining object
|
||||||
int _lookcAnim;
|
int _lookcAnim;
|
||||||
ActionType _aClose;
|
|
||||||
int _seqStack; // Allows gosubs to return to calling frame
|
int _seqStack; // Allows gosubs to return to calling frame
|
||||||
int _seqTo; // Allows 1-5, 8-3 type sequences encoded in 2 bytes
|
int _seqTo; // Allows 1-5, 8-3 type sequences encoded in 2 bytes
|
||||||
uint _descOffset; // Tells where description starts in DescText
|
uint _descOffset; // Tells where description starts in DescText
|
||||||
int _seqCounter2; // Counter of calling frame sequence
|
int _seqCounter2; // Counter of calling frame sequence
|
||||||
uint _seqSize; // Tells where description starts
|
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;
|
ActionType _aMove;
|
||||||
UseType _use[USE_COUNT];
|
|
||||||
|
// Rose Tattoo fields
|
||||||
|
int _quickDraw;
|
||||||
|
int _scaleVal;
|
||||||
|
int _requiredFlag1;
|
||||||
|
int _gotoSeq;
|
||||||
|
int _talkSeq;
|
||||||
|
int _restoreSlot;
|
||||||
|
|
||||||
Object();
|
Object();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the data for the 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
|
* Toggle the type of an object between hidden and active
|
||||||
@ -326,20 +392,45 @@ public:
|
|||||||
|
|
||||||
struct CAnim {
|
struct CAnim {
|
||||||
Common::String _name; // Name
|
Common::String _name; // Name
|
||||||
byte _sequences[MAX_FRAME]; // Animation sequences
|
|
||||||
Common::Point _position; // Position
|
Common::Point _position; // Position
|
||||||
int _size; // Size of uncompressed animation
|
int _size; // Size of uncompressed animation
|
||||||
SpriteType _type;
|
|
||||||
int _flags; // Tells if can be walked behind
|
int _flags; // Tells if can be walked behind
|
||||||
Common::Point _goto; // coords holmes should walk to before starting canim
|
Common::Point _goto; // coords holmes should walk to before starting canim
|
||||||
int _gotoDir;
|
int _gotoDir;
|
||||||
Common::Point _teleportPos; // Location Holmes shoul teleport to after
|
Common::Point _teleportPos; // Location Holmes shoul teleport to after
|
||||||
int _teleportDir; // playing canim
|
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
|
* 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 {
|
struct SceneImage {
|
||||||
|
@ -50,10 +50,38 @@ static const uint8 CHARACTER_SEQUENCES[MAX_HOLMES_SEQUENCE][MAX_FRAME] = {
|
|||||||
{ 52, 1, 2, 3, 4, 0 } // Goto Stand Down Left
|
{ 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]) {
|
People::People(SherlockEngine *vm) : _vm(vm), _player(_data[0]) {
|
||||||
_walkLoaded = false;
|
|
||||||
_holmesOn = true;
|
_holmesOn = true;
|
||||||
_oldWalkSequence = -1;
|
_oldWalkSequence = -1;
|
||||||
_allowWalkAbort = false;
|
_allowWalkAbort = false;
|
||||||
@ -68,66 +96,168 @@ People::People(SherlockEngine *vm) : _vm(vm), _player(_data[0]) {
|
|||||||
_holmesQuotient = 0;
|
_holmesQuotient = 0;
|
||||||
_hSavedPos = Common::Point(-1, -1);
|
_hSavedPos = Common::Point(-1, -1);
|
||||||
_hSavedFacing = -1;
|
_hSavedFacing = -1;
|
||||||
|
_forceWalkReload = false;
|
||||||
|
_useWalkLib = false;
|
||||||
|
_walkControl = 0;
|
||||||
|
|
||||||
_portrait._sequences = new byte[32];
|
_portrait._sequences = new byte[32];
|
||||||
}
|
}
|
||||||
|
|
||||||
People::~People() {
|
People::~People() {
|
||||||
if (_walkLoaded)
|
for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
|
||||||
delete _data[PLAYER]._images;
|
if (_data[idx]._walkLoaded)
|
||||||
|
delete _data[PLAYER]._images;
|
||||||
|
}
|
||||||
|
|
||||||
delete _talkPics;
|
delete _talkPics;
|
||||||
delete[] _portrait._sequences;
|
delete[] _portrait._sequences;
|
||||||
}
|
}
|
||||||
|
|
||||||
void People::reset() {
|
void People::reset() {
|
||||||
// Note: The engine has theoretical support for two player characters but only the first one is used.
|
_data[0]._description = "Sherlock Holmes!";
|
||||||
// Watson is, instead, handled by a different sprite in each scene, with a very simple initial movement, if any
|
|
||||||
Sprite &p = _data[PLAYER];
|
|
||||||
|
|
||||||
p._description = "Sherlock Holmes!";
|
// Note: Serrated Scalpel only uses a single Person slot for Sherlock.. Watson is handled by scene sprites
|
||||||
p._type = CHARACTER;
|
int count = IS_SERRATED_SCALPEL ? 1 : MAX_CHARACTERS;
|
||||||
p._position = Common::Point(10000, 11000);
|
for (int idx = 0; idx < count; ++idx) {
|
||||||
p._sequenceNumber = STOP_DOWNRIGHT;
|
Sprite &p = _data[idx];
|
||||||
p._sequences = &CHARACTER_SEQUENCES;
|
|
||||||
p._imageFrame = nullptr;
|
p._type = (idx == 0) ? CHARACTER : INVALID;
|
||||||
p._frameNumber = 1;
|
if (IS_SERRATED_SCALPEL)
|
||||||
p._delta = Common::Point(0, 0);
|
p._position = Point32(10000, 11000);
|
||||||
p._oldPosition = Common::Point(0, 0);
|
else
|
||||||
p._oldSize = Common::Point(0, 0);
|
p._position = Point32(36000, 29000);
|
||||||
p._misc = 0;
|
|
||||||
p._walkCount = 0;
|
p._sequenceNumber = STOP_DOWNRIGHT;
|
||||||
p._pickUp = "";
|
p._imageFrame = nullptr;
|
||||||
p._allow = 0;
|
p._frameNumber = 1;
|
||||||
p._noShapeSize = Common::Point(0, 0);
|
p._delta = Common::Point(0, 0);
|
||||||
p._goto = Common::Point(0, 0);
|
p._oldPosition = Common::Point(0, 0);
|
||||||
p._status = 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
|
// Reset any walk path in progress when Sherlock leaves scenes
|
||||||
_walkTo.clear();
|
_walkTo.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool People::loadWalk() {
|
bool People::loadWalk() {
|
||||||
if (_walkLoaded) {
|
Resources &res = *_vm->_res;
|
||||||
return false;
|
bool result = false;
|
||||||
} else {
|
|
||||||
_data[PLAYER]._images = new ImageFile("walk.vgs");
|
|
||||||
_data[PLAYER].setImageFrame();
|
|
||||||
_walkLoaded = true;
|
|
||||||
|
|
||||||
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() {
|
bool People::freeWalk() {
|
||||||
if (_walkLoaded) {
|
bool result = false;
|
||||||
delete _player._images;
|
|
||||||
_player._images = nullptr;
|
|
||||||
|
|
||||||
_walkLoaded = false;
|
for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
|
||||||
return true;
|
if (_data[idx]._walkLoaded) {
|
||||||
} else {
|
delete _data[idx]._images;
|
||||||
return false;
|
_data[idx]._images = nullptr;
|
||||||
|
|
||||||
|
_data[idx]._walkLoaded = false;
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void People::setWalking() {
|
void People::setWalking() {
|
||||||
@ -553,9 +683,24 @@ void People::setTalking(int speaker) {
|
|||||||
|
|
||||||
void People::synchronize(Common::Serializer &s) {
|
void People::synchronize(Common::Serializer &s) {
|
||||||
s.syncAsByte(_holmesOn);
|
s.syncAsByte(_holmesOn);
|
||||||
s.syncAsSint16LE(_player._position.x);
|
|
||||||
s.syncAsSint16LE(_player._position.y);
|
if (IS_SERRATED_SCALPEL) {
|
||||||
s.syncAsSint16LE(_player._sequenceNumber);
|
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);
|
s.syncAsSint16LE(_holmesQuotient);
|
||||||
|
|
||||||
if (s.isLoading()) {
|
if (s.isLoading()) {
|
||||||
|
@ -30,13 +30,13 @@
|
|||||||
|
|
||||||
namespace Sherlock {
|
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 {
|
enum PeopleId {
|
||||||
PLAYER = 0,
|
PLAYER = 0,
|
||||||
AL = 0,
|
AL = 0,
|
||||||
PEG = 1,
|
PEG = 1,
|
||||||
MAX_PLAYERS = 2
|
MAX_CHARACTERS = 6,
|
||||||
|
MAX_NPC = 5,
|
||||||
|
MAX_NPC_PATH = 200
|
||||||
};
|
};
|
||||||
|
|
||||||
// Animation sequence identifiers for characters
|
// Animation sequence identifiers for characters
|
||||||
@ -63,20 +63,37 @@ struct PersonData {
|
|||||||
_name(name), _portrait(portrait), _stillSequences(stillSequences), _talkSequences(talkSequences) {}
|
_name(name), _portrait(portrait), _stillSequences(stillSequences), _talkSequences(talkSequences) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SherlockEngine;
|
|
||||||
|
|
||||||
class Person : public Sprite {
|
class Person : public Sprite {
|
||||||
public:
|
public:
|
||||||
Person() : Sprite() {}
|
bool _walkLoaded;
|
||||||
|
|
||||||
Common::String _portrait;
|
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 {
|
class People {
|
||||||
private:
|
private:
|
||||||
SherlockEngine *_vm;
|
SherlockEngine *_vm;
|
||||||
Person _data[MAX_PLAYERS];
|
Person _data[MAX_CHARACTERS];
|
||||||
bool _walkLoaded;
|
|
||||||
int _oldWalkSequence;
|
int _oldWalkSequence;
|
||||||
int _srcZone, _destZone;
|
int _srcZone, _destZone;
|
||||||
public:
|
public:
|
||||||
@ -97,24 +114,23 @@ public:
|
|||||||
bool _speakerFlip;
|
bool _speakerFlip;
|
||||||
bool _holmesFlip;
|
bool _holmesFlip;
|
||||||
int _holmesQuotient;
|
int _holmesQuotient;
|
||||||
|
bool _forceWalkReload;
|
||||||
|
bool _useWalkLib;
|
||||||
|
|
||||||
|
int _walkControl;
|
||||||
public:
|
public:
|
||||||
People(SherlockEngine *vm);
|
People(SherlockEngine *vm);
|
||||||
~People();
|
~People();
|
||||||
|
|
||||||
Person &operator[](PeopleId id) {
|
Person &operator[](PeopleId id) {
|
||||||
assert(id < MAX_PLAYERS);
|
assert(id < MAX_CHARACTERS);
|
||||||
return _data[id];
|
return _data[id];
|
||||||
}
|
}
|
||||||
Person &operator[](int idx) {
|
Person &operator[](int idx) {
|
||||||
assert(idx < MAX_PLAYERS);
|
assert(idx < MAX_CHARACTERS);
|
||||||
return _data[idx];
|
return _data[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if Sherlock is visible on the screen and enabled
|
|
||||||
*/
|
|
||||||
bool isHolmesActive() const { return _walkLoaded && _holmesOn; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset the player data
|
* Reset the player data
|
||||||
*/
|
*/
|
||||||
|
@ -65,7 +65,7 @@ void Cache::load(const Common::String &name, Common::SeekableReadStream &stream)
|
|||||||
// Check whether the file is compressed
|
// Check whether the file is compressed
|
||||||
if (signature == MKTAG('L', 'Z', 'V', 26)) {
|
if (signature == MKTAG('L', 'Z', 'V', 26)) {
|
||||||
// It's compressed, so decompress the file and store it's data in the cache entry
|
// 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());
|
cacheEntry.resize(decompressed->size());
|
||||||
decompressed->read(&cacheEntry[0], decompressed->size());
|
decompressed->read(&cacheEntry[0], decompressed->size());
|
||||||
|
|
||||||
@ -91,9 +91,12 @@ Resources::Resources(SherlockEngine *vm) : _vm(vm), _cache(vm) {
|
|||||||
if (_vm->_interactiveFl) {
|
if (_vm->_interactiveFl) {
|
||||||
addToCache("vgs.lib");
|
addToCache("vgs.lib");
|
||||||
addToCache("talk.lib");
|
addToCache("talk.lib");
|
||||||
addToCache("sequence.txt");
|
|
||||||
addToCache("journal.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
|
// Check to see if the file is a library
|
||||||
Common::SeekableReadStream *stream = load(filename);
|
Common::SeekableReadStream *stream = load(filename);
|
||||||
uint32 header = stream->readUint32BE();
|
uint32 header = stream->readUint32BE();
|
||||||
|
|
||||||
if (header == MKTAG('L', 'I', 'B', 26))
|
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;
|
delete stream;
|
||||||
}
|
}
|
||||||
@ -159,12 +165,14 @@ Common::SeekableReadStream *Resources::load(const Common::String &filename) {
|
|||||||
|
|
||||||
void Resources::decompressIfNecessary(Common::SeekableReadStream *&stream) {
|
void Resources::decompressIfNecessary(Common::SeekableReadStream *&stream) {
|
||||||
bool isCompressed = stream->readUint32BE() == MKTAG('L', 'Z', 'V', 26);
|
bool isCompressed = stream->readUint32BE() == MKTAG('L', 'Z', 'V', 26);
|
||||||
stream->seek(-4, SEEK_CUR);
|
|
||||||
|
|
||||||
if (isCompressed) {
|
if (isCompressed) {
|
||||||
Common::SeekableReadStream *newStream = decompressLZ(*stream);
|
int outSize = stream->readUint32LE();
|
||||||
|
Common::SeekableReadStream *newStream = decompressLZ(*stream, outSize);
|
||||||
delete stream;
|
delete stream;
|
||||||
stream = newStream;
|
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
|
// Check if the library has already had it's index read, and if not, load it
|
||||||
if (!_indexes.contains(libraryFile))
|
if (!_indexes.contains(libraryFile))
|
||||||
loadLibraryIndex(libraryFile, libStream);
|
loadLibraryIndex(libraryFile, libStream, false);
|
||||||
|
|
||||||
// Extract the data for the specified resource and return it
|
// Extract the data for the specified resource and return it
|
||||||
LibraryEntry &entry = _indexes[libraryFile][filename];
|
LibraryEntry &entry = _indexes[libraryFile][filename];
|
||||||
@ -192,7 +200,7 @@ bool Resources::exists(const Common::String &filename) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Resources::loadLibraryIndex(const Common::String &libFilename,
|
void Resources::loadLibraryIndex(const Common::String &libFilename,
|
||||||
Common::SeekableReadStream *stream) {
|
Common::SeekableReadStream *stream, bool isNewStyle) {
|
||||||
uint32 offset, nextOffset;
|
uint32 offset, nextOffset;
|
||||||
|
|
||||||
// Create an index entry
|
// Create an index entry
|
||||||
@ -203,6 +211,9 @@ void Resources::loadLibraryIndex(const Common::String &libFilename,
|
|||||||
stream->seek(4);
|
stream->seek(4);
|
||||||
int count = stream->readUint16LE();
|
int count = stream->readUint16LE();
|
||||||
|
|
||||||
|
if (isNewStyle)
|
||||||
|
stream->seek((count + 1) * 8, SEEK_CUR);
|
||||||
|
|
||||||
// Loop through reading in the entries
|
// Loop through reading in the entries
|
||||||
for (int idx = 0; idx < count; ++idx) {
|
for (int idx = 0; idx < count; ++idx) {
|
||||||
// Read the name of the resource
|
// Read the name of the resource
|
||||||
@ -231,24 +242,48 @@ int Resources::resourceIndex() const {
|
|||||||
return _resourceIndex;
|
return _resourceIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &source) {
|
Common::SeekableReadStream *Resources::decompress(Common::SeekableReadStream &source) {
|
||||||
if (_vm->getGameID() == GType_SerratedScalpel) {
|
// This variation can't be used by Rose Tattoo, since compressed resources include the input size,
|
||||||
uint32 id = source.readUint32BE();
|
// not the output size. Which means their decompression has to be done via passed buffers
|
||||||
assert(id == MKTAG('L', 'Z', 'V', 0x1A));
|
assert(_vm->getGameID() == GType_SerratedScalpel);
|
||||||
}
|
|
||||||
|
|
||||||
uint32 size = source.readUint32LE();
|
uint32 id = source.readUint32BE();
|
||||||
return decompressLZ(source, size);
|
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) {
|
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];
|
byte lzWindow[4096];
|
||||||
uint16 lzWindowPos;
|
uint16 lzWindowPos;
|
||||||
uint16 cmd;
|
uint16 cmd;
|
||||||
|
|
||||||
byte *outBuffer = (byte *)malloc(outSize);
|
|
||||||
byte *outBufferEnd = outBuffer + outSize;
|
byte *outBufferEnd = outBuffer + outSize;
|
||||||
Common::MemoryReadStream *outS = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES);
|
int endPos = source.pos() + inSize;
|
||||||
|
|
||||||
memset(lzWindow, 0xFF, 0xFEE);
|
memset(lzWindow, 0xFF, 0xFEE);
|
||||||
lzWindowPos = 0xFEE;
|
lzWindowPos = 0xFEE;
|
||||||
@ -264,8 +299,7 @@ Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &
|
|||||||
*outBuffer++ = literal;
|
*outBuffer++ = literal;
|
||||||
lzWindow[lzWindowPos] = literal;
|
lzWindow[lzWindowPos] = literal;
|
||||||
lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
|
lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
int copyPos, copyLen;
|
int copyPos, copyLen;
|
||||||
copyPos = source.readByte();
|
copyPos = source.readByte();
|
||||||
copyLen = source.readByte();
|
copyLen = source.readByte();
|
||||||
@ -279,9 +313,7 @@ Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &
|
|||||||
lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
|
lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (outBuffer < outBufferEnd);
|
} while ((outSize == -1 || outBuffer < outBufferEnd) && (inSize == -1 || source.pos() < endPos));
|
||||||
|
|
||||||
return outS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------*/
|
/*----------------------------------------------------------------*/
|
||||||
@ -325,13 +357,14 @@ void ImageFile::load(Common::SeekableReadStream &stream, bool skipPalette, bool
|
|||||||
// Animation cutscene image files use a 16-bit x offset
|
// Animation cutscene image files use a 16-bit x offset
|
||||||
frame._offset.x = stream.readUint16LE();
|
frame._offset.x = stream.readUint16LE();
|
||||||
frame._rleEncoded = (frame._offset.x & 0xff) == 1;
|
frame._rleEncoded = (frame._offset.x & 0xff) == 1;
|
||||||
|
frame._offset.y = stream.readByte();
|
||||||
} else {
|
} else {
|
||||||
// Standard image files have a separate byte for the RLE flag, and an 8-bit X offset
|
// Standard image files have a separate byte for the RLE flag, and an 8-bit X offset
|
||||||
frame._rleEncoded = stream.readByte() == 1;
|
frame._rleEncoded = stream.readByte() == 1;
|
||||||
frame._offset.x = stream.readByte();
|
frame._offset.x = stream.readByte();
|
||||||
|
frame._offset.y = stream.readByte();
|
||||||
}
|
}
|
||||||
|
|
||||||
frame._offset.y = stream.readByte();
|
|
||||||
frame._rleEncoded = !skipPalette && frame._rleEncoded;
|
frame._rleEncoded = !skipPalette && frame._rleEncoded;
|
||||||
|
|
||||||
if (frame._paletteBase) {
|
if (frame._paletteBase) {
|
||||||
@ -385,6 +418,28 @@ void ImageFile::decompressFrame(ImageFrame &frame, const byte *src) {
|
|||||||
*pDest++ = *src & 0xF;
|
*pDest++ = *src & 0xF;
|
||||||
*pDest++ = (*src >> 4);
|
*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) {
|
} else if (frame._rleEncoded) {
|
||||||
// RLE encoded
|
// RLE encoded
|
||||||
byte *dst = (byte *)frame._frame.getPixels();
|
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
|
} // End of namespace Sherlock
|
||||||
|
@ -90,7 +90,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Reads in the index from a library file, and caches it's index for later use
|
* 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:
|
public:
|
||||||
Resources(SherlockEngine *vm);
|
Resources(SherlockEngine *vm);
|
||||||
|
|
||||||
@ -140,14 +140,29 @@ public:
|
|||||||
int resourceIndex() const;
|
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);
|
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 {
|
struct ImageFrame {
|
||||||
@ -158,6 +173,16 @@ struct ImageFrame {
|
|||||||
Common::Point _offset;
|
Common::Point _offset;
|
||||||
byte _rleMarker;
|
byte _rleMarker;
|
||||||
Graphics::Surface _frame;
|
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> {
|
class ImageFile : public Common::Array<ImageFrame> {
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include "sherlock/sherlock.h"
|
#include "sherlock/sherlock.h"
|
||||||
#include "sherlock/music.h"
|
#include "sherlock/music.h"
|
||||||
#include "sherlock/animation.h"
|
#include "sherlock/animation.h"
|
||||||
|
#include "engines/util.h"
|
||||||
|
|
||||||
namespace Sherlock {
|
namespace Sherlock {
|
||||||
|
|
||||||
@ -379,6 +380,9 @@ ScalpelEngine::~ScalpelEngine() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ScalpelEngine::initialize() {
|
void ScalpelEngine::initialize() {
|
||||||
|
initGraphics(320, 200, false);
|
||||||
|
|
||||||
|
// Let the base engine intialize
|
||||||
SherlockEngine::initialize();
|
SherlockEngine::initialize();
|
||||||
|
|
||||||
_darts = new Darts(this);
|
_darts = new Darts(this);
|
||||||
@ -580,9 +584,9 @@ bool ScalpelEngine::scrollCredits() {
|
|||||||
_screen->transBlitFrom(creditsImages[1], Common::Point(10, 400 - idx), false, 0);
|
_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
|
// 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, 0), Common::Rect(0, 0, _screen->w(), 10));
|
||||||
_screen->blitFrom(_screen->_backBuffer1, Common::Point(0, SHERLOCK_SCREEN_HEIGHT - 10),
|
_screen->blitFrom(_screen->_backBuffer1, Common::Point(0, _screen->h() - 10),
|
||||||
Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - 10, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
|
Common::Rect(0, _screen->h() - 10, _screen->w(), _screen->h()));
|
||||||
|
|
||||||
_events->delay(100);
|
_events->delay(100);
|
||||||
}
|
}
|
||||||
@ -804,7 +808,6 @@ void ScalpelEngine::startScene() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_events->loadCursors("rmouse.vgs");
|
|
||||||
_events->setCursor(ARROW);
|
_events->setCursor(ARROW);
|
||||||
|
|
||||||
if (_scene->_goToScene == 99) {
|
if (_scene->_goToScene == 99) {
|
||||||
@ -828,9 +831,11 @@ void ScalpelEngine::eraseMirror12() {
|
|||||||
|
|
||||||
void ScalpelEngine::doMirror12() {
|
void ScalpelEngine::doMirror12() {
|
||||||
People &people = *_people;
|
People &people = *_people;
|
||||||
|
Person &player = people._player;
|
||||||
|
|
||||||
Common::Point pt((*_people)[AL]._position.x / 100, (*_people)[AL]._position.y / 100);
|
Common::Point pt((*_people)[AL]._position.x / 100, (*_people)[AL]._position.y / 100);
|
||||||
int frameNum = (*people[AL]._sequences)[people[AL]._sequenceNumber][people[AL]._frameNumber] +
|
int frameNum = player._walkSequences[player._sequenceNumber][player._frameNumber] +
|
||||||
(*people[AL]._sequences)[people[AL]._sequenceNumber][0] - 2;
|
player._walkSequences[player._sequenceNumber][0] - 2;
|
||||||
|
|
||||||
switch ((*_people)[AL]._sequenceNumber) {
|
switch ((*_people)[AL]._sequenceNumber) {
|
||||||
case WALK_DOWN:
|
case WALK_DOWN:
|
||||||
|
381
engines/sherlock/scalpel/scalpel_scene.cpp
Normal file
381
engines/sherlock/scalpel/scalpel_scene.cpp
Normal 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
|
61
engines/sherlock/scalpel/scalpel_scene.h
Normal file
61
engines/sherlock/scalpel/scalpel_scene.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
2276
engines/sherlock/scalpel/scalpel_user_interface.cpp
Normal file
2276
engines/sherlock/scalpel/scalpel_user_interface.cpp
Normal file
File diff suppressed because it is too large
Load Diff
227
engines/sherlock/scalpel/scalpel_user_interface.h
Normal file
227
engines/sherlock/scalpel/scalpel_user_interface.h
Normal 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
|
@ -21,10 +21,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sherlock/sherlock.h"
|
#include "sherlock/sherlock.h"
|
||||||
#include "sherlock/settings.h"
|
#include "sherlock/scalpel/settings.h"
|
||||||
|
#include "sherlock/scalpel/scalpel_user_interface.h"
|
||||||
|
|
||||||
namespace Sherlock {
|
namespace Sherlock {
|
||||||
|
|
||||||
|
namespace Scalpel {
|
||||||
|
|
||||||
static const int SETUP_POINTS[12][4] = {
|
static const int SETUP_POINTS[12][4] = {
|
||||||
{ 4, 154, 101, 53 }, // Exit
|
{ 4, 154, 101, 53 }, // Exit
|
||||||
{ 4, 165, 101, 53 }, // Music Toggle
|
{ 4, 165, 101, 53 }, // Music Toggle
|
||||||
@ -212,9 +215,10 @@ void Settings::show(SherlockEngine *vm) {
|
|||||||
Sound &sound = *vm->_sound;
|
Sound &sound = *vm->_sound;
|
||||||
Music &music = *vm->_music;
|
Music &music = *vm->_music;
|
||||||
Talk &talk = *vm->_talk;
|
Talk &talk = *vm->_talk;
|
||||||
UserInterface &ui = *vm->_ui;
|
ScalpelUserInterface &ui = *(ScalpelUserInterface *)vm->_ui;
|
||||||
bool updateConfig = false;
|
bool updateConfig = false;
|
||||||
|
|
||||||
|
assert(vm->getGameID() == GType_SerratedScalpel);
|
||||||
Settings settings(vm);
|
Settings settings(vm);
|
||||||
settings.drawInteface(false);
|
settings.drawInteface(false);
|
||||||
|
|
||||||
@ -332,4 +336,6 @@ void Settings::show(SherlockEngine *vm) {
|
|||||||
ui._key = -1;
|
ui._key = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // End of namespace Scalpel
|
||||||
|
|
||||||
} // End of namespace Sherlock
|
} // End of namespace Sherlock
|
@ -28,7 +28,8 @@
|
|||||||
namespace Sherlock {
|
namespace Sherlock {
|
||||||
|
|
||||||
class SherlockEngine;
|
class SherlockEngine;
|
||||||
class UserInterface;
|
|
||||||
|
namespace Scalpel {
|
||||||
|
|
||||||
class Settings {
|
class Settings {
|
||||||
private:
|
private:
|
||||||
@ -55,6 +56,8 @@ public:
|
|||||||
static void show(SherlockEngine *vm);
|
static void show(SherlockEngine *vm);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // End of namespace Scalpel
|
||||||
|
|
||||||
} // End of namespace Sherlock
|
} // End of namespace Sherlock
|
||||||
|
|
||||||
#endif
|
#endif
|
File diff suppressed because it is too large
Load Diff
@ -29,6 +29,7 @@
|
|||||||
#include "common/serializer.h"
|
#include "common/serializer.h"
|
||||||
#include "sherlock/objects.h"
|
#include "sherlock/objects.h"
|
||||||
#include "sherlock/resources.h"
|
#include "sherlock/resources.h"
|
||||||
|
#include "sherlock/screen.h"
|
||||||
|
|
||||||
namespace Sherlock {
|
namespace Sherlock {
|
||||||
|
|
||||||
@ -44,12 +45,23 @@ struct BgFileHeader {
|
|||||||
int _numcAnimations;
|
int _numcAnimations;
|
||||||
int _descSize;
|
int _descSize;
|
||||||
int _seqSize;
|
int _seqSize;
|
||||||
|
|
||||||
|
// Serrated Scalpel
|
||||||
int _fill;
|
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
|
* Load the data for the object
|
||||||
*/
|
*/
|
||||||
void load(Common::SeekableReadStream &s);
|
void load(Common::SeekableReadStream &s, bool isRoseTattoo);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BgFileHeaderInfo {
|
struct BgFileHeaderInfo {
|
||||||
@ -63,18 +75,20 @@ struct BgFileHeaderInfo {
|
|||||||
void load(Common::SeekableReadStream &s);
|
void load(Common::SeekableReadStream &s);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Exit {
|
class Exit: public Common::Rect {
|
||||||
Common::Rect _bounds;
|
public:
|
||||||
|
|
||||||
int _scene;
|
int _scene;
|
||||||
int _allow;
|
int _allow;
|
||||||
Common::Point _people;
|
Common::Point _people;
|
||||||
int _peopleDir;
|
int _peopleDir;
|
||||||
|
|
||||||
|
Common::String _dest;
|
||||||
|
int _image; // Arrow image to use
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the data for the object
|
* Load the data for the object
|
||||||
*/
|
*/
|
||||||
void load(Common::SeekableReadStream &s);
|
void load(Common::SeekableReadStream &s, bool isRoseTattoo);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SceneEntry {
|
struct SceneEntry {
|
||||||
@ -106,9 +120,26 @@ public:
|
|||||||
int indexOf(const Object &obj) const;
|
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 {
|
class Scene {
|
||||||
private:
|
private:
|
||||||
SherlockEngine *_vm;
|
|
||||||
Common::String _rrmName;
|
Common::String _rrmName;
|
||||||
bool _loadingSavedGame;
|
bool _loadingSavedGame;
|
||||||
|
|
||||||
@ -123,6 +154,11 @@ private:
|
|||||||
*/
|
*/
|
||||||
bool loadScene(const Common::String &filename);
|
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
|
* Set objects to their current persistent state. This includes things such as
|
||||||
* opening or moving them
|
* opening or moving them
|
||||||
@ -142,18 +178,27 @@ private:
|
|||||||
*/
|
*/
|
||||||
void transitionToScene();
|
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
|
* 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
|
* will remain the same on future visits to the scene
|
||||||
*/
|
*/
|
||||||
void saveSceneStatus();
|
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:
|
public:
|
||||||
int _currentScene;
|
int _currentScene;
|
||||||
int _goToScene;
|
int _goToScene;
|
||||||
@ -173,17 +218,21 @@ public:
|
|||||||
int _walkDirectory[MAX_ZONES][MAX_ZONES];
|
int _walkDirectory[MAX_ZONES][MAX_ZONES];
|
||||||
Common::Array<byte> _walkData;
|
Common::Array<byte> _walkData;
|
||||||
Common::Array<Exit> _exits;
|
Common::Array<Exit> _exits;
|
||||||
|
int _exitZone;
|
||||||
SceneEntry _entrance;
|
SceneEntry _entrance;
|
||||||
Common::Array<SceneSound> _sounds;
|
Common::Array<SceneSound> _sounds;
|
||||||
ObjectArray _canimShapes;
|
ObjectArray _canimShapes;
|
||||||
|
Common::Array<ScaleZone> _scaleZones;
|
||||||
|
Common::StringArray _objSoundList;
|
||||||
bool _restoreFlag;
|
bool _restoreFlag;
|
||||||
int _animating;
|
int _animating;
|
||||||
bool _doBgAnimDone;
|
bool _doBgAnimDone;
|
||||||
int _tempFadeStyle;
|
int _tempFadeStyle;
|
||||||
int _cAnimFramePause;
|
int _cAnimFramePause;
|
||||||
|
Common::Array<SceneTripEntry> _sceneTripCounters;
|
||||||
public:
|
public:
|
||||||
Scene(SherlockEngine *vm);
|
static Scene *init(SherlockEngine *vm);
|
||||||
~Scene();
|
virtual ~Scene();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles loading the scene specified by _goToScene
|
* Handles loading the scene specified by _goToScene
|
||||||
@ -223,11 +272,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
int toggleObject(const Common::String &name);
|
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,
|
* Attempts to find a background shape within the passed bounds. If found,
|
||||||
* it will return the shape number, or -1 on failure.
|
* it will return the shape number, or -1 on failure.
|
||||||
@ -250,16 +294,28 @@ public:
|
|||||||
*/
|
*/
|
||||||
int closestZone(const Common::Point &pt);
|
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
|
* Synchronize the data for a savegame
|
||||||
*/
|
*/
|
||||||
void synchronize(Common::Serializer &s);
|
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
|
} // End of namespace Sherlock
|
||||||
|
@ -28,9 +28,9 @@
|
|||||||
|
|
||||||
namespace Sherlock {
|
namespace Sherlock {
|
||||||
|
|
||||||
Screen::Screen(SherlockEngine *vm) : Surface(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), _vm(vm),
|
Screen::Screen(SherlockEngine *vm) : Surface(g_system->getWidth(), g_system->getHeight()), _vm(vm),
|
||||||
_backBuffer1(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT),
|
_backBuffer1(g_system->getWidth(), g_system->getHeight()),
|
||||||
_backBuffer2(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT),
|
_backBuffer2(g_system->getWidth(), g_system->getHeight()),
|
||||||
_backBuffer(&_backBuffer1) {
|
_backBuffer(&_backBuffer1) {
|
||||||
_transitionSeed = 1;
|
_transitionSeed = 1;
|
||||||
_fadeStyle = false;
|
_fadeStyle = false;
|
||||||
@ -38,7 +38,17 @@ Screen::Screen(SherlockEngine *vm) : Surface(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCR
|
|||||||
_fontHeight = 0;
|
_fontHeight = 0;
|
||||||
Common::fill(&_cMap[0], &_cMap[PALETTE_SIZE], 0);
|
Common::fill(&_cMap[0], &_cMap[PALETTE_SIZE], 0);
|
||||||
Common::fill(&_sMap[0], &_sMap[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() {
|
Screen::~Screen() {
|
||||||
@ -174,12 +184,13 @@ void Screen::randomTransition() {
|
|||||||
Events &events = *_vm->_events;
|
Events &events = *_vm->_events;
|
||||||
const int TRANSITION_MULTIPLIER = 0x15a4e35;
|
const int TRANSITION_MULTIPLIER = 0x15a4e35;
|
||||||
_dirtyRects.clear();
|
_dirtyRects.clear();
|
||||||
|
assert(IS_SERRATED_SCALPEL);
|
||||||
|
|
||||||
for (int idx = 0; idx <= 65535 && !_vm->shouldQuit(); ++idx) {
|
for (int idx = 0; idx <= 65535 && !_vm->shouldQuit(); ++idx) {
|
||||||
_transitionSeed = _transitionSeed * TRANSITION_MULTIPLIER + 1;
|
_transitionSeed = _transitionSeed * TRANSITION_MULTIPLIER + 1;
|
||||||
int offset = _transitionSeed & 0xFFFF;
|
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);
|
*((byte *)getPixels() + offset) = *((const byte *)_backBuffer->getPixels() + offset);
|
||||||
|
|
||||||
if (idx != 0 && (idx % 300) == 0) {
|
if (idx != 0 && (idx % 300) == 0) {
|
||||||
@ -199,12 +210,12 @@ void Screen::randomTransition() {
|
|||||||
void Screen::verticalTransition() {
|
void Screen::verticalTransition() {
|
||||||
Events &events = *_vm->_events;
|
Events &events = *_vm->_events;
|
||||||
|
|
||||||
byte table[SHERLOCK_SCREEN_WIDTH];
|
byte table[640];
|
||||||
Common::fill(&table[0], &table[SHERLOCK_SCREEN_WIDTH], 0);
|
Common::fill(&table[0], &table[640], 0);
|
||||||
|
|
||||||
for (int yp = 0; yp < SHERLOCK_SCREEN_HEIGHT; ++yp) {
|
for (int yp = 0; yp < this->h(); ++yp) {
|
||||||
for (int xp = 0; xp < SHERLOCK_SCREEN_WIDTH; ++xp) {
|
for (int xp = 0; xp < this->w(); ++xp) {
|
||||||
int temp = (table[xp] >= 197) ? SHERLOCK_SCREEN_HEIGHT - table[xp] :
|
int temp = (table[xp] >= (this->h() - 3)) ? this->h() - table[xp] :
|
||||||
_vm->getRandomNumber(3) + 1;
|
_vm->getRandomNumber(3) + 1;
|
||||||
|
|
||||||
if (temp) {
|
if (temp) {
|
||||||
@ -221,7 +232,7 @@ void Screen::verticalTransition() {
|
|||||||
void Screen::restoreBackground(const Common::Rect &r) {
|
void Screen::restoreBackground(const Common::Rect &r) {
|
||||||
if (r.width() > 0 && r.height() > 0) {
|
if (r.width() > 0 && r.height() > 0) {
|
||||||
Common::Rect tempRect = r;
|
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())
|
if (tempRect.isValidRect())
|
||||||
_backBuffer1.blitFrom(_backBuffer2, Common::Point(tempRect.left, tempRect.top), tempRect);
|
_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) {
|
void Screen::slamRect(const Common::Rect &r) {
|
||||||
if (r.width() && r.height() > 0) {
|
if (r.width() && r.height() > 0) {
|
||||||
Common::Rect tempRect = r;
|
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())
|
if (tempRect.isValidRect())
|
||||||
blitFrom(*_backBuffer, Common::Point(tempRect.left, tempRect.top), tempRect);
|
blitFrom(*_backBuffer, Common::Point(tempRect.left, tempRect.top), tempRect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screen::flushImage(ImageFrame *frame, const Common::Point &pt,
|
void Screen::flushImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp,
|
||||||
int16 *xp, int16 *yp, int16 *width, int16 *height) {
|
int16 *width, int16 *height) {
|
||||||
Common::Point imgPos = pt + frame->_offset;
|
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 newBounds(imgPos.x, imgPos.y, imgPos.x + frame->_frame.w, imgPos.y + frame->_frame.h);
|
||||||
Common::Rect oldBounds(*xp, *yp, *xp + *width, *yp + *height);
|
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 (!_flushScreen) {
|
||||||
if (newBounds.intersects(oldBounds)) {
|
// See if the areas of the old and new overlap, and if so combine the areas
|
||||||
Common::Rect mergedBounds = newBounds;
|
if (newBounds.intersects(oldBounds)) {
|
||||||
mergedBounds.extend(oldBounds);
|
Common::Rect mergedBounds = newBounds;
|
||||||
mergedBounds.right += 1;
|
mergedBounds.extend(oldBounds);
|
||||||
mergedBounds.bottom += 1;
|
mergedBounds.right += 1;
|
||||||
|
mergedBounds.bottom += 1;
|
||||||
|
|
||||||
slamRect(mergedBounds);
|
slamRect(mergedBounds);
|
||||||
} else {
|
} else {
|
||||||
// The two areas are independent, so copy them both
|
// The two areas are independent, so copy them both
|
||||||
slamRect(newBounds);
|
slamRect(newBounds);
|
||||||
slamRect(oldBounds);
|
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;
|
*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
|
pos.y--; // Font is always drawing one line higher
|
||||||
if (!pos.x)
|
if (!pos.x)
|
||||||
// Center text horizontally
|
// 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);
|
Common::Rect textBounds(pos.x, pos.y, pos.x + width, pos.y + _fontHeight);
|
||||||
if (textBounds.right > SHERLOCK_SCREEN_WIDTH)
|
if (textBounds.right > this->w())
|
||||||
textBounds.moveTo(SHERLOCK_SCREEN_WIDTH - width, textBounds.top);
|
textBounds.moveTo(this->w() - width, textBounds.top);
|
||||||
if (textBounds.bottom > SHERLOCK_SCREEN_HEIGHT)
|
if (textBounds.bottom > this->h())
|
||||||
textBounds.moveTo(textBounds.left, SHERLOCK_SCREEN_HEIGHT - _fontHeight);
|
textBounds.moveTo(textBounds.left, this->h() - _fontHeight);
|
||||||
|
|
||||||
// Write out the string at the given position
|
// Write out the string at the given position
|
||||||
writeString(str, Common::Point(textBounds.left, textBounds.top), color);
|
writeString(str, Common::Point(textBounds.left, textBounds.top), color);
|
||||||
@ -416,7 +458,7 @@ void Screen::resetDisplayBounds() {
|
|||||||
|
|
||||||
Common::Rect Screen::getDisplayBounds() {
|
Common::Rect Screen::getDisplayBounds() {
|
||||||
return (_backBuffer == &_sceneSurface) ? Common::Rect(0, 0, _sceneSurface.w(), _sceneSurface.h()) :
|
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) {
|
void Screen::synchronize(Common::Serializer &s) {
|
||||||
@ -426,4 +468,41 @@ void Screen::synchronize(Common::Serializer &s) {
|
|||||||
setFont(fontNumb);
|
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
|
} // End of namespace Sherlock
|
||||||
|
@ -66,6 +66,12 @@ private:
|
|||||||
int _fontHeight;
|
int _fontHeight;
|
||||||
Surface _sceneSurface;
|
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
|
* Merges together overlapping dirty areas of the screen
|
||||||
*/
|
*/
|
||||||
@ -92,6 +98,10 @@ public:
|
|||||||
bool _fadeStyle;
|
bool _fadeStyle;
|
||||||
byte _cMap[PALETTE_SIZE];
|
byte _cMap[PALETTE_SIZE];
|
||||||
byte _sMap[PALETTE_SIZE];
|
byte _sMap[PALETTE_SIZE];
|
||||||
|
byte _tMap[PALETTE_SIZE];
|
||||||
|
int _currentScroll, _targetScroll;
|
||||||
|
int _scrollSize, _scrollSpeed;
|
||||||
|
bool _flushScreen;
|
||||||
public:
|
public:
|
||||||
Screen(SherlockEngine *vm);
|
Screen(SherlockEngine *vm);
|
||||||
virtual ~Screen();
|
virtual ~Screen();
|
||||||
@ -171,8 +181,15 @@ public:
|
|||||||
* Copy an image from the back buffer to the screen, taking care of both the
|
* 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
|
* new area covered by the shape as well as the old area, which must be restored
|
||||||
*/
|
*/
|
||||||
void flushImage(ImageFrame *frame, const Common::Point &pt,
|
void flushImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp,
|
||||||
int16 *xp, int16 *yp, int16 *width, int16 *height);
|
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
|
* Returns the width of a string in pixels
|
||||||
@ -232,6 +249,21 @@ public:
|
|||||||
* Synchronize the data for a savegame
|
* Synchronize the data for a savegame
|
||||||
*/
|
*/
|
||||||
void synchronize(Common::Serializer &s);
|
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
|
} // End of namespace Sherlock
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
#include "common/scummsys.h"
|
#include "common/scummsys.h"
|
||||||
#include "common/config-manager.h"
|
#include "common/config-manager.h"
|
||||||
#include "common/debug-channels.h"
|
#include "common/debug-channels.h"
|
||||||
#include "engines/util.h"
|
|
||||||
|
|
||||||
namespace Sherlock {
|
namespace Sherlock {
|
||||||
|
|
||||||
@ -72,8 +71,6 @@ SherlockEngine::~SherlockEngine() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SherlockEngine::initialize() {
|
void SherlockEngine::initialize() {
|
||||||
initGraphics(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT, false);
|
|
||||||
|
|
||||||
DebugMan.addDebugChannel(kDebugScript, "scripts", "Script debug level");
|
DebugMan.addDebugChannel(kDebugScript, "scripts", "Script debug level");
|
||||||
|
|
||||||
ImageFile::setVm(this);
|
ImageFile::setVm(this);
|
||||||
@ -98,11 +95,11 @@ void SherlockEngine::initialize() {
|
|||||||
_journal = new Journal(this);
|
_journal = new Journal(this);
|
||||||
_people = new People(this);
|
_people = new People(this);
|
||||||
_saves = new SaveManager(this, _targetName);
|
_saves = new SaveManager(this, _targetName);
|
||||||
_scene = new Scene(this);
|
_scene = Scene::init(this);
|
||||||
_screen = new Screen(this);
|
_screen = new Screen(this);
|
||||||
_sound = new Sound(this, _mixer);
|
_sound = new Sound(this, _mixer);
|
||||||
_talk = new Talk(this);
|
_talk = Talk::init(this);
|
||||||
_ui = new UserInterface(this);
|
_ui = UserInterface::init(this);
|
||||||
|
|
||||||
// Load game settings
|
// Load game settings
|
||||||
loadConfig();
|
loadConfig();
|
||||||
@ -213,7 +210,9 @@ void SherlockEngine::loadConfig() {
|
|||||||
ConfMan.registerDefault("font", 1);
|
ConfMan.registerDefault("font", 1);
|
||||||
|
|
||||||
_screen->setFont(ConfMan.getInt("font"));
|
_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->_helpStyle = ConfMan.getBool("help_style");
|
||||||
_ui->_slideWindows = ConfMan.getBool("window_style");
|
_ui->_slideWindows = ConfMan.getBool("window_style");
|
||||||
_people->_portraitsOn = ConfMan.getBool("portraits_on");
|
_people->_portraitsOn = ConfMan.getBool("portraits_on");
|
||||||
|
@ -59,9 +59,9 @@ enum GameType {
|
|||||||
GType_RoseTattoo = 1
|
GType_RoseTattoo = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SHERLOCK_SCREEN_WIDTH 320
|
#define SHERLOCK_SCREEN_WIDTH _vm->_screen->w()
|
||||||
#define SHERLOCK_SCREEN_HEIGHT 200
|
#define SHERLOCK_SCREEN_HEIGHT _vm->_screen->h()
|
||||||
#define SHERLOCK_SCENE_HEIGHT 138
|
#define SHERLOCK_SCENE_HEIGHT (IS_SERRATED_SCALPEL ? 138 : 480)
|
||||||
|
|
||||||
struct SherlockGameDescription;
|
struct SherlockGameDescription;
|
||||||
|
|
||||||
@ -199,6 +199,9 @@ public:
|
|||||||
void synchronize(Common::Serializer &s);
|
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
|
} // End of namespace Sherlock
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -58,18 +58,27 @@ Sound::Sound(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
|
|||||||
_soundIsOn = &_soundPlaying;
|
_soundIsOn = &_soundPlaying;
|
||||||
_curPriority = 0;
|
_curPriority = 0;
|
||||||
_digiBuf = nullptr;
|
_digiBuf = nullptr;
|
||||||
|
_midiDrvLoaded = false;
|
||||||
|
_musicVolume = 0;
|
||||||
|
|
||||||
_soundOn = true;
|
_soundOn = true;
|
||||||
_speechOn = true;
|
_speechOn = true;
|
||||||
|
|
||||||
|
_vm->_res->addToCache("MUSIC.LIB");
|
||||||
if (!_vm->_interactiveFl)
|
if (!_vm->_interactiveFl)
|
||||||
_vm->_res->addToCache("TITLE.SND");
|
_vm->_res->addToCache("TITLE.SND");
|
||||||
else {
|
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()) {
|
if (!_vm->isDemo()) {
|
||||||
_vm->_res->addToCache("TITLE.SND");
|
_vm->_res->addToCache("TITLE.SND");
|
||||||
_vm->_res->addToCache("EPILOGUE.SND");
|
_vm->_res->addToCache("EPILOGUE.SND");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,5 +219,9 @@ void Sound::freeDigiSound() {
|
|||||||
_soundPlaying = false;
|
_soundPlaying = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sound::setMIDIVolume(int volume) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
} // End of namespace Sherlock
|
} // End of namespace Sherlock
|
||||||
|
|
||||||
|
@ -56,6 +56,9 @@ public:
|
|||||||
bool _soundPlaying;
|
bool _soundPlaying;
|
||||||
bool *_soundIsOn;
|
bool *_soundIsOn;
|
||||||
byte *_digiBuf;
|
byte *_digiBuf;
|
||||||
|
bool _midiDrvLoaded;
|
||||||
|
Common::String _currentSongName, _nextSongName;
|
||||||
|
int _musicVolume;
|
||||||
public:
|
public:
|
||||||
Sound(SherlockEngine *vm, Audio::Mixer *mixer);
|
Sound(SherlockEngine *vm, Audio::Mixer *mixer);
|
||||||
|
|
||||||
@ -91,6 +94,7 @@ public:
|
|||||||
|
|
||||||
void stopSndFuncPtr(int v1, int v2);
|
void stopSndFuncPtr(int v1, int v2);
|
||||||
void freeDigiSound();
|
void freeDigiSound();
|
||||||
|
void setMIDIVolume(int volume);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace Sherlock
|
} // End of namespace Sherlock
|
||||||
|
@ -96,6 +96,12 @@ void Surface::transBlitFrom(const ImageFrame &src, const Common::Point &pt,
|
|||||||
transBlitFrom(src._frame, pt + src._offset, flipped, overrideColor);
|
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,
|
void Surface::transBlitFrom(const Graphics::Surface &src, const Common::Point &pt,
|
||||||
bool flipped, int overrideColor) {
|
bool flipped, int overrideColor) {
|
||||||
Common::Rect drawRect(0, 0, src.w, src.h);
|
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);
|
_surface.setPixels(pixels);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Surface::maskArea(const ImageFrame &src, const Common::Point &pt, int scrollX) {
|
||||||
|
// TODO
|
||||||
|
error("TODO: maskArea");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // End of namespace Sherlock
|
} // End of namespace Sherlock
|
||||||
|
@ -126,6 +126,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
void fillRect(const Common::Rect &r, byte color);
|
void fillRect(const Common::Rect &r, byte color);
|
||||||
|
|
||||||
|
void maskArea(const ImageFrame &src, const Common::Point &pt, int scrollX);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear the screen
|
* Clear the screen
|
||||||
*/
|
*/
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -36,42 +36,83 @@ namespace Sherlock {
|
|||||||
#define MAX_TALK_FILES 500
|
#define MAX_TALK_FILES 500
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SWITCH_SPEAKER = 128,
|
OP_SWITCH_SPEAKER = 0,
|
||||||
RUN_CANIMATION = 129,
|
OP_RUN_CANIMATION = 1,
|
||||||
ASSIGN_PORTRAIT_LOCATION = 130,
|
OP_ASSIGN_PORTRAIT_LOCATION = 2,
|
||||||
PAUSE = 131,
|
OP_PAUSE = 3,
|
||||||
REMOVE_PORTRAIT = 132,
|
OP_REMOVE_PORTRAIT = 4,
|
||||||
CLEAR_WINDOW = 133,
|
OP_CLEAR_WINDOW = 5,
|
||||||
ADJUST_OBJ_SEQUENCE = 134,
|
OP_ADJUST_OBJ_SEQUENCE = 6,
|
||||||
WALK_TO_COORDS = 135,
|
OP_WALK_TO_COORDS = 7,
|
||||||
PAUSE_WITHOUT_CONTROL = 136,
|
OP_PAUSE_WITHOUT_CONTROL = 8,
|
||||||
BANISH_WINDOW = 137,
|
OP_BANISH_WINDOW = 9,
|
||||||
SUMMON_WINDOW = 138,
|
OP_SUMMON_WINDOW = 10,
|
||||||
SET_FLAG = 139,
|
OP_SET_FLAG = 11,
|
||||||
SFX_COMMAND = 140,
|
OP_SFX_COMMAND = 12,
|
||||||
TOGGLE_OBJECT = 141,
|
OP_TOGGLE_OBJECT = 13,
|
||||||
STEALTH_MODE_ACTIVE = 142,
|
OP_STEALTH_MODE_ACTIVE = 14,
|
||||||
IF_STATEMENT = 143,
|
OP_IF_STATEMENT = 15,
|
||||||
ELSE_STATEMENT = 144,
|
OP_ELSE_STATEMENT = 16,
|
||||||
END_IF_STATEMENT = 145,
|
OP_END_IF_STATEMENT = 17,
|
||||||
STEALTH_MODE_DEACTIVATE = 146,
|
OP_STEALTH_MODE_DEACTIVATE = 18,
|
||||||
TURN_HOLMES_OFF = 147,
|
OP_TURN_HOLMES_OFF = 19,
|
||||||
TURN_HOLMES_ON = 148,
|
OP_TURN_HOLMES_ON = 20,
|
||||||
GOTO_SCENE = 149,
|
OP_GOTO_SCENE = 21,
|
||||||
PLAY_PROLOGUE = 150,
|
OP_PLAY_PROLOGUE = 22,
|
||||||
ADD_ITEM_TO_INVENTORY = 151,
|
OP_ADD_ITEM_TO_INVENTORY = 23,
|
||||||
SET_OBJECT = 152,
|
OP_SET_OBJECT = 24,
|
||||||
CALL_TALK_FILE = 153,
|
OP_CALL_TALK_FILE = 25,
|
||||||
MOVE_MOUSE = 154,
|
OP_MOVE_MOUSE = 26,
|
||||||
DISPLAY_INFO_LINE = 155,
|
OP_DISPLAY_INFO_LINE = 27,
|
||||||
CLEAR_INFO_LINE = 156,
|
OP_CLEAR_INFO_LINE = 28,
|
||||||
WALK_TO_CANIMATION = 157,
|
OP_WALK_TO_CANIMATION = 29,
|
||||||
REMOVE_ITEM_FROM_INVENTORY = 158,
|
OP_REMOVE_ITEM_FROM_INVENTORY = 30,
|
||||||
ENABLE_END_KEY = 159,
|
OP_ENABLE_END_KEY = 31,
|
||||||
DISABLE_END_KEY = 160,
|
OP_DISABLE_END_KEY = 32,
|
||||||
CARRIAGE_RETURN = 161
|
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 {
|
struct SequenceEntry {
|
||||||
int _objNum;
|
int _objNum;
|
||||||
Common::Array<byte> _sequences;
|
Common::Array<byte> _sequences;
|
||||||
@ -122,24 +163,8 @@ struct TalkSequences {
|
|||||||
void clear();
|
void clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
class SherlockEngine;
|
|
||||||
class UserInterface;
|
|
||||||
|
|
||||||
class Talk {
|
class Talk {
|
||||||
friend class UserInterface;
|
friend class Scalpel::ScalpelUserInterface;
|
||||||
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;
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Remove any voice commands from a loaded statement list
|
* Remove any voice commands from a loaded statement list
|
||||||
@ -173,6 +198,55 @@ private:
|
|||||||
* the amount of text that's been displayed
|
* the amount of text that's been displayed
|
||||||
*/
|
*/
|
||||||
int waitForMore(int delay);
|
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:
|
public:
|
||||||
bool _talkToAbort;
|
bool _talkToAbort;
|
||||||
int _talkCounter;
|
int _talkCounter;
|
||||||
@ -181,8 +255,11 @@ public:
|
|||||||
Common::String _scriptName;
|
Common::String _scriptName;
|
||||||
bool _moreTalkUp, _moreTalkDown;
|
bool _moreTalkUp, _moreTalkDown;
|
||||||
int _converseNum;
|
int _converseNum;
|
||||||
|
const byte *_opcodes;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Talk(SherlockEngine *vm);
|
static Talk *init(SherlockEngine *vm);
|
||||||
|
virtual ~Talk() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a given talk statement
|
* Return a given talk statement
|
||||||
@ -267,6 +344,65 @@ public:
|
|||||||
void synchronize(Common::Serializer &s);
|
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
|
} // End of namespace Sherlock
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,15 +21,61 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sherlock/tattoo/tattoo.h"
|
#include "sherlock/tattoo/tattoo.h"
|
||||||
|
#include "engines/util.h"
|
||||||
|
|
||||||
namespace Sherlock {
|
namespace Sherlock {
|
||||||
|
|
||||||
namespace Tattoo {
|
namespace Tattoo {
|
||||||
|
|
||||||
|
TattooEngine::TattooEngine(OSystem *syst, const SherlockGameDescription *gameDesc) :
|
||||||
|
SherlockEngine(syst, gameDesc) {
|
||||||
|
_creditsActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
void TattooEngine::showOpening() {
|
void TattooEngine::showOpening() {
|
||||||
// TODO
|
// 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 Tattoo
|
||||||
|
|
||||||
} // End of namespace Scalpel
|
} // End of namespace Scalpel
|
||||||
|
@ -30,12 +30,38 @@ namespace Sherlock {
|
|||||||
namespace Tattoo {
|
namespace Tattoo {
|
||||||
|
|
||||||
class TattooEngine : public SherlockEngine {
|
class TattooEngine : public SherlockEngine {
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Loads the initial palette for the game
|
||||||
|
*/
|
||||||
|
void loadInitialPalette();
|
||||||
protected:
|
protected:
|
||||||
|
/**
|
||||||
|
* Initialize the engine
|
||||||
|
*/
|
||||||
|
virtual void initialize();
|
||||||
|
|
||||||
virtual void showOpening();
|
virtual void showOpening();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starting a scene within the game
|
||||||
|
*/
|
||||||
|
virtual void startScene();
|
||||||
public:
|
public:
|
||||||
TattooEngine(OSystem *syst, const SherlockGameDescription *gameDesc) :
|
bool _creditsActive;
|
||||||
SherlockEngine(syst, gameDesc) {}
|
public:
|
||||||
|
TattooEngine(OSystem *syst, const SherlockGameDescription *gameDesc);
|
||||||
virtual ~TattooEngine() {}
|
virtual ~TattooEngine() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw credits on the screen
|
||||||
|
*/
|
||||||
|
void drawCredits();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erase any area of the screen covered by credits
|
||||||
|
*/
|
||||||
|
void eraseCredits();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End of namespace Tattoo
|
} // End of namespace Tattoo
|
||||||
|
402
engines/sherlock/tattoo/tattoo_scene.cpp
Normal file
402
engines/sherlock/tattoo/tattoo_scene.cpp
Normal 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
|
77
engines/sherlock/tattoo/tattoo_scene.h
Normal file
77
engines/sherlock/tattoo/tattoo_scene.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
150
engines/sherlock/tattoo/tattoo_user_interface.cpp
Normal file
150
engines/sherlock/tattoo/tattoo_user_interface.cpp
Normal 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
|
83
engines/sherlock/tattoo/tattoo_user_interface.h
Normal file
83
engines/sherlock/tattoo/tattoo_user_interface.h
Normal 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
@ -50,134 +50,11 @@ enum MenuMode {
|
|||||||
SETUP_MODE = 12
|
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 {
|
class UserInterface {
|
||||||
friend class Inventory;
|
protected:
|
||||||
friend class Settings;
|
|
||||||
friend class Talk;
|
|
||||||
private:
|
|
||||||
SherlockEngine *_vm;
|
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);
|
|
||||||
|
|
||||||
/**
|
UserInterface(SherlockEngine *vm);
|
||||||
* 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);
|
|
||||||
public:
|
public:
|
||||||
MenuMode _menuMode;
|
MenuMode _menuMode;
|
||||||
int _menuCounter;
|
int _menuCounter;
|
||||||
@ -185,74 +62,67 @@ public:
|
|||||||
bool _windowOpen;
|
bool _windowOpen;
|
||||||
bool _endKeyActive;
|
bool _endKeyActive;
|
||||||
int _invLookFlag;
|
int _invLookFlag;
|
||||||
int _temp1;
|
|
||||||
bool _slideWindows;
|
bool _slideWindows;
|
||||||
bool _helpStyle;
|
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:
|
public:
|
||||||
UserInterface(SherlockEngine *vm);
|
static UserInterface *init(SherlockEngine *vm);
|
||||||
~UserInterface();
|
virtual ~UserInterface() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resets the user interface
|
* Resets the user interface
|
||||||
*/
|
*/
|
||||||
void reset();
|
virtual void reset() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw the user interface onto the screen's back buffers
|
* 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
|
* Main input handler for the user interface
|
||||||
*/
|
*/
|
||||||
void handleInput();
|
virtual 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();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays a passed window by gradually scrolling it vertically on-screen
|
* 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
|
* 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
|
* Close a currently open window
|
||||||
* @param flag 0 = slide old window down, 1 = slide prior UI back up
|
* @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
|
* Clears the info line of the screen
|
||||||
* (not selected) position
|
|
||||||
*/
|
*/
|
||||||
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
|
} // End of namespace Sherlock
|
||||||
|
Loading…
x
Reference in New Issue
Block a user