mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-23 12:44:02 +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;
|
||||
_rightPressed = _rightReleased = false;
|
||||
_oldButtons = _oldRightButton = false;
|
||||
|
||||
loadCursors("rmouse.vgs");
|
||||
}
|
||||
|
||||
Events::~Events() {
|
||||
@ -73,6 +75,14 @@ void Events::setCursor(const Graphics::Surface &src) {
|
||||
showCursor();
|
||||
}
|
||||
|
||||
void Events::animateCursorIfNeeded() {
|
||||
if (_cursorId >= WAIT && _cursorId < (WAIT + 3)) {
|
||||
CursorId newId = (WAIT + 2) ? WAIT : (CursorId)((int)_cursorId + 1);
|
||||
setCursor(newId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Events::showCursor() {
|
||||
CursorMan.showMouse(true);
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ namespace Sherlock {
|
||||
#define GAME_FRAME_RATE 60
|
||||
#define GAME_FRAME_TIME (1000 / GAME_FRAME_RATE)
|
||||
|
||||
enum CursorId { ARROW = 0, MAGNIFY = 1, WAIT = 2, INVALID_CURSOR = -1 };
|
||||
enum CursorId { ARROW = 0, MAGNIFY = 1, WAIT = 2, EXIT_ZONES_START = 5, INVALID_CURSOR = -1 };
|
||||
|
||||
class SherlockEngine;
|
||||
|
||||
@ -77,6 +77,11 @@ public:
|
||||
*/
|
||||
void setCursor(const Graphics::Surface &src);
|
||||
|
||||
/**
|
||||
* Animates the mouse cursor if the Wait cursor is showing
|
||||
*/
|
||||
void animateCursorIfNeeded();
|
||||
|
||||
/**
|
||||
* Show the mouse cursor
|
||||
*/
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "sherlock/inventory.h"
|
||||
#include "sherlock/sherlock.h"
|
||||
#include "sherlock/scalpel/scalpel_user_interface.h"
|
||||
|
||||
namespace Sherlock {
|
||||
|
||||
@ -200,29 +201,29 @@ void Inventory::drawInventory(InvNewMode mode) {
|
||||
INV_BACKGROUND);
|
||||
|
||||
// Draw the buttons
|
||||
screen.makeButton(Common::Rect(INVENTORY_POINTS[0][0], CONTROLS_Y1, INVENTORY_POINTS[0][1],
|
||||
CONTROLS_Y1 + 10), INVENTORY_POINTS[0][2] - screen.stringWidth("Exit") / 2, "Exit");
|
||||
screen.makeButton(Common::Rect(INVENTORY_POINTS[1][0], CONTROLS_Y1, INVENTORY_POINTS[1][1],
|
||||
CONTROLS_Y1 + 10), INVENTORY_POINTS[1][2] - screen.stringWidth("Look") / 2, "Look");
|
||||
screen.makeButton(Common::Rect(INVENTORY_POINTS[2][0], CONTROLS_Y1, INVENTORY_POINTS[2][1],
|
||||
CONTROLS_Y1 + 10), INVENTORY_POINTS[2][2] - screen.stringWidth("Use") / 2, "Use");
|
||||
screen.makeButton(Common::Rect(INVENTORY_POINTS[3][0], CONTROLS_Y1, INVENTORY_POINTS[3][1],
|
||||
CONTROLS_Y1 + 10), INVENTORY_POINTS[3][2] - screen.stringWidth("Give") / 2, "Give");
|
||||
screen.makeButton(Common::Rect(INVENTORY_POINTS[4][0], CONTROLS_Y1, INVENTORY_POINTS[4][1],
|
||||
CONTROLS_Y1 + 10), INVENTORY_POINTS[4][2], "^^");
|
||||
screen.makeButton(Common::Rect(INVENTORY_POINTS[5][0], CONTROLS_Y1, INVENTORY_POINTS[5][1],
|
||||
CONTROLS_Y1 + 10), INVENTORY_POINTS[5][2], "^");
|
||||
screen.makeButton(Common::Rect(INVENTORY_POINTS[6][0], CONTROLS_Y1, INVENTORY_POINTS[6][1],
|
||||
CONTROLS_Y1 + 10), INVENTORY_POINTS[6][2], "_");
|
||||
screen.makeButton(Common::Rect(INVENTORY_POINTS[7][0], CONTROLS_Y1, INVENTORY_POINTS[7][1],
|
||||
CONTROLS_Y1 + 10), INVENTORY_POINTS[7][2], "__");
|
||||
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[0][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[0][1],
|
||||
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[0][2] - screen.stringWidth("Exit") / 2, "Exit");
|
||||
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[1][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[1][1],
|
||||
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[1][2] - screen.stringWidth("Look") / 2, "Look");
|
||||
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[2][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[2][1],
|
||||
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[2][2] - screen.stringWidth("Use") / 2, "Use");
|
||||
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[3][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[3][1],
|
||||
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[3][2] - screen.stringWidth("Give") / 2, "Give");
|
||||
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[4][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[4][1],
|
||||
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[4][2], "^^");
|
||||
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[5][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[5][1],
|
||||
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[5][2], "^");
|
||||
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[6][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[6][1],
|
||||
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[6][2], "_");
|
||||
screen.makeButton(Common::Rect(Scalpel::INVENTORY_POINTS[7][0], CONTROLS_Y1, Scalpel::INVENTORY_POINTS[7][1],
|
||||
CONTROLS_Y1 + 10), Scalpel::INVENTORY_POINTS[7][2], "__");
|
||||
|
||||
if (tempMode == INVENTORY_DONT_DISPLAY)
|
||||
mode = LOOK_INVENTORY_MODE;
|
||||
_invMode = (InvMode)mode;
|
||||
|
||||
if (mode != PLAIN_INVENTORY) {
|
||||
ui._oldKey = INVENTORY_COMMANDS[(int)mode];
|
||||
ui._oldKey = Scalpel::INVENTORY_COMMANDS[(int)mode];
|
||||
} else {
|
||||
ui._oldKey = -1;
|
||||
}
|
||||
@ -243,7 +244,8 @@ void Inventory::drawInventory(InvNewMode mode) {
|
||||
screen._backBuffer = &screen._backBuffer1;
|
||||
}
|
||||
|
||||
ui._oldUse = -1;
|
||||
assert(IS_SERRATED_SCALPEL);
|
||||
((Scalpel::ScalpelUserInterface *)_vm->_ui)->_oldUse = -1;
|
||||
}
|
||||
|
||||
void Inventory::invCommands(bool slamIt) {
|
||||
@ -251,55 +253,55 @@ void Inventory::invCommands(bool slamIt) {
|
||||
UserInterface &ui = *_vm->_ui;
|
||||
|
||||
if (slamIt) {
|
||||
screen.buttonPrint(Common::Point(INVENTORY_POINTS[0][2], CONTROLS_Y1),
|
||||
screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[0][2], CONTROLS_Y1),
|
||||
_invMode == INVMODE_EXIT ? COMMAND_HIGHLIGHTED :COMMAND_FOREGROUND,
|
||||
true, "Exit");
|
||||
screen.buttonPrint(Common::Point(INVENTORY_POINTS[1][2], CONTROLS_Y1),
|
||||
screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[1][2], CONTROLS_Y1),
|
||||
_invMode == INVMODE_LOOK ? COMMAND_HIGHLIGHTED :COMMAND_FOREGROUND,
|
||||
true, "Look");
|
||||
screen.buttonPrint(Common::Point(INVENTORY_POINTS[2][2], CONTROLS_Y1),
|
||||
screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[2][2], CONTROLS_Y1),
|
||||
_invMode == INVMODE_USE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
|
||||
true, "Use");
|
||||
screen.buttonPrint(Common::Point(INVENTORY_POINTS[3][2], CONTROLS_Y1),
|
||||
screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[3][2], CONTROLS_Y1),
|
||||
_invMode == INVMODE_GIVE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
|
||||
true, "Give");
|
||||
screen.print(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1 + 1),
|
||||
screen.print(Common::Point(Scalpel::INVENTORY_POINTS[4][2], CONTROLS_Y1 + 1),
|
||||
_invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
|
||||
"^^");
|
||||
screen.print(Common::Point(INVENTORY_POINTS[5][2], CONTROLS_Y1 + 1),
|
||||
screen.print(Common::Point(Scalpel::INVENTORY_POINTS[5][2], CONTROLS_Y1 + 1),
|
||||
_invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
|
||||
"^");
|
||||
screen.print(Common::Point(INVENTORY_POINTS[6][2], CONTROLS_Y1 + 1),
|
||||
screen.print(Common::Point(Scalpel::INVENTORY_POINTS[6][2], CONTROLS_Y1 + 1),
|
||||
(_holdings - _invIndex <= 6) ? COMMAND_NULL : COMMAND_FOREGROUND,
|
||||
"_");
|
||||
screen.print(Common::Point(INVENTORY_POINTS[7][2], CONTROLS_Y1 + 1),
|
||||
screen.print(Common::Point(Scalpel::INVENTORY_POINTS[7][2], CONTROLS_Y1 + 1),
|
||||
(_holdings - _invIndex <= 6) ? COMMAND_NULL : COMMAND_FOREGROUND,
|
||||
"__");
|
||||
if (_invMode != INVMODE_LOOK)
|
||||
ui.clearInfo();
|
||||
} else {
|
||||
screen.buttonPrint(Common::Point(INVENTORY_POINTS[0][2], CONTROLS_Y1),
|
||||
screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[0][2], CONTROLS_Y1),
|
||||
_invMode == INVMODE_EXIT ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
|
||||
false, "Exit");
|
||||
screen.buttonPrint(Common::Point(INVENTORY_POINTS[1][2], CONTROLS_Y1),
|
||||
screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[1][2], CONTROLS_Y1),
|
||||
_invMode == INVMODE_LOOK ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
|
||||
false, "Look");
|
||||
screen.buttonPrint(Common::Point(INVENTORY_POINTS[2][2], CONTROLS_Y1),
|
||||
screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[2][2], CONTROLS_Y1),
|
||||
_invMode == INVMODE_USE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
|
||||
false, "Use");
|
||||
screen.buttonPrint(Common::Point(INVENTORY_POINTS[3][2], CONTROLS_Y1),
|
||||
screen.buttonPrint(Common::Point(Scalpel::INVENTORY_POINTS[3][2], CONTROLS_Y1),
|
||||
_invMode == INVMODE_GIVE ? COMMAND_HIGHLIGHTED : COMMAND_FOREGROUND,
|
||||
false, "Give");
|
||||
screen.gPrint(Common::Point(INVENTORY_POINTS[4][2], CONTROLS_Y1),
|
||||
screen.gPrint(Common::Point(Scalpel::INVENTORY_POINTS[4][2], CONTROLS_Y1),
|
||||
_invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
|
||||
"^^");
|
||||
screen.gPrint(Common::Point(INVENTORY_POINTS[5][2], CONTROLS_Y1),
|
||||
screen.gPrint(Common::Point(Scalpel::INVENTORY_POINTS[5][2], CONTROLS_Y1),
|
||||
_invIndex == 0 ? COMMAND_NULL : COMMAND_FOREGROUND,
|
||||
"^");
|
||||
screen.gPrint(Common::Point(INVENTORY_POINTS[6][2], CONTROLS_Y1),
|
||||
screen.gPrint(Common::Point(Scalpel::INVENTORY_POINTS[6][2], CONTROLS_Y1),
|
||||
(_holdings - _invIndex < 7) ? COMMAND_NULL : COMMAND_FOREGROUND,
|
||||
"_");
|
||||
screen.gPrint(Common::Point(INVENTORY_POINTS[7][2], CONTROLS_Y1),
|
||||
screen.gPrint(Common::Point(Scalpel::INVENTORY_POINTS[7][2], CONTROLS_Y1),
|
||||
(_holdings - _invIndex < 7) ? COMMAND_NULL : COMMAND_FOREGROUND,
|
||||
"__");
|
||||
}
|
||||
@ -318,9 +320,12 @@ void Inventory::highlight(int index, byte color) {
|
||||
}
|
||||
|
||||
void Inventory::refreshInv() {
|
||||
if (IS_ROSE_TATTOO)
|
||||
return;
|
||||
|
||||
Screen &screen = *_vm->_screen;
|
||||
Talk &talk = *_vm->_talk;
|
||||
UserInterface &ui = *_vm->_ui;
|
||||
Scalpel::ScalpelUserInterface &ui = *(Scalpel::ScalpelUserInterface *)_vm->_ui;
|
||||
|
||||
ui._invLookFlag = true;
|
||||
freeInv();
|
||||
|
@ -135,6 +135,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
|
||||
Screen &screen = *_vm->_screen;
|
||||
Talk &talk = *_vm->_talk;
|
||||
JournalEntry &journalEntry = _journal[_index];
|
||||
const byte *opcodes = talk._opcodes;
|
||||
|
||||
Common::String dirFilename = _directory[journalEntry._converseNum];
|
||||
bool replyOnly = journalEntry._replyOnly;
|
||||
@ -243,7 +244,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
|
||||
byte c = *replyP++;
|
||||
|
||||
// Is it a control character?
|
||||
if (c < SWITCH_SPEAKER) {
|
||||
if (c < opcodes[0]) {
|
||||
// Nope. Set flag for allowing control codes to insert spaces
|
||||
ctrlSpace = true;
|
||||
assert(c >= ' ');
|
||||
@ -290,7 +291,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
|
||||
byte v;
|
||||
do {
|
||||
v = *strP++;
|
||||
} while (v && (v < SWITCH_SPEAKER) && (v != '.') && (v != '!') && (v != '?'));
|
||||
} while (v && (v < opcodes[0]) && (v != '.') && (v != '!') && (v != '?'));
|
||||
|
||||
if (v == '?')
|
||||
journalString += " asked, \"";
|
||||
@ -306,11 +307,11 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
|
||||
journalString += c;
|
||||
do {
|
||||
journalString += *replyP++;
|
||||
} while (*replyP && *replyP < SWITCH_SPEAKER && *replyP != '{' && *replyP != '}');
|
||||
} while (*replyP && *replyP < opcodes[0] && *replyP != '{' && *replyP != '}');
|
||||
|
||||
commentJustPrinted = false;
|
||||
}
|
||||
} else if (c == SWITCH_SPEAKER) {
|
||||
} else if (c == opcodes[OP_SWITCH_SPEAKER]) {
|
||||
if (!startOfReply) {
|
||||
if (!commentFlag && !commentJustPrinted)
|
||||
journalString += "\"\n";
|
||||
@ -337,7 +338,7 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
|
||||
byte v;
|
||||
do {
|
||||
v = *strP++;
|
||||
} while (v && v < SWITCH_SPEAKER && v != '.' && v != '!' && v != '?');
|
||||
} while (v && v < opcodes[0] && v != '.' && v != '!' && v != '?');
|
||||
|
||||
if (v == '?')
|
||||
journalString += " asked, \"";
|
||||
@ -345,59 +346,42 @@ void Journal::loadJournalFile(bool alreadyLoaded) {
|
||||
journalString += " said, \"";
|
||||
} else {
|
||||
// Control code, so move past it and any parameters
|
||||
switch (c) {
|
||||
case RUN_CANIMATION:
|
||||
case ASSIGN_PORTRAIT_LOCATION:
|
||||
case PAUSE:
|
||||
case PAUSE_WITHOUT_CONTROL:
|
||||
case WALK_TO_CANIMATION:
|
||||
if (c == opcodes[OP_RUN_CANIMATION] || c == opcodes[OP_ASSIGN_PORTRAIT_LOCATION] ||
|
||||
c == opcodes[OP_PAUSE] || c == opcodes[OP_PAUSE_WITHOUT_CONTROL] ||
|
||||
c == opcodes[OP_WALK_TO_CANIMATION]) {
|
||||
// These commands have a single parameter
|
||||
++replyP;
|
||||
break;
|
||||
|
||||
case ADJUST_OBJ_SEQUENCE:
|
||||
} else if (c == opcodes[OP_ADJUST_OBJ_SEQUENCE]) {
|
||||
replyP += (replyP[0] & 127) + replyP[1] + 2;
|
||||
break;
|
||||
|
||||
case WALK_TO_COORDS:
|
||||
case MOVE_MOUSE:
|
||||
} else if (c == opcodes[OP_WALK_TO_COORDS] || c == opcodes[OP_MOVE_MOUSE]) {
|
||||
replyP += 4;
|
||||
break;
|
||||
|
||||
case SET_FLAG:
|
||||
case IF_STATEMENT:
|
||||
|
||||
} else if (c == opcodes[OP_SET_FLAG] || c == opcodes[OP_IF_STATEMENT]) {
|
||||
replyP += 2;
|
||||
break;
|
||||
|
||||
case SFX_COMMAND:
|
||||
case PLAY_PROLOGUE:
|
||||
case CALL_TALK_FILE:
|
||||
} else if (c == opcodes[OP_SFX_COMMAND] || c == opcodes[OP_PLAY_PROLOGUE] ||
|
||||
c == opcodes[OP_CALL_TALK_FILE]) {
|
||||
replyP += 8;
|
||||
break;
|
||||
|
||||
case TOGGLE_OBJECT:
|
||||
case ADD_ITEM_TO_INVENTORY:
|
||||
case SET_OBJECT:
|
||||
case DISPLAY_INFO_LINE:
|
||||
case REMOVE_ITEM_FROM_INVENTORY:
|
||||
} else if (c == opcodes[OP_TOGGLE_OBJECT] || c == opcodes[OP_ADD_ITEM_TO_INVENTORY] ||
|
||||
c == opcodes[OP_SET_OBJECT] || c == opcodes[OP_DISPLAY_INFO_LINE] ||
|
||||
c == opcodes[OP_REMOVE_ITEM_FROM_INVENTORY]) {
|
||||
replyP += (*replyP & 127) + 1;
|
||||
break;
|
||||
|
||||
case GOTO_SCENE:
|
||||
} else if (c == opcodes[OP_GOTO_SCENE]) {
|
||||
replyP += 5;
|
||||
break;
|
||||
|
||||
case CARRIAGE_RETURN:
|
||||
} else if (c == opcodes[OP_CARRIAGE_RETURN]) {
|
||||
journalString += "\n";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Put a space in the output for a control character, unless it's
|
||||
// immediately coming after another control character
|
||||
if (ctrlSpace && c != ASSIGN_PORTRAIT_LOCATION && c != CARRIAGE_RETURN && !commentJustPrinted) {
|
||||
if (ctrlSpace && c != opcodes[OP_ASSIGN_PORTRAIT_LOCATION] && c != opcodes[OP_CARRIAGE_RETURN] &&
|
||||
!commentJustPrinted) {
|
||||
journalString += " ";
|
||||
ctrlSpace = false;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "sherlock/map.h"
|
||||
#include "sherlock/sherlock.h"
|
||||
#include "common/system.h"
|
||||
|
||||
namespace Sherlock {
|
||||
|
||||
@ -50,7 +51,7 @@ const byte *MapPaths::getPath(int srcLocation, int destLocation) {
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
Map::Map(SherlockEngine *vm) : _vm(vm), _topLine(SHERLOCK_SCREEN_WIDTH, 12) {
|
||||
Map::Map(SherlockEngine *vm): _vm(vm), _topLine(g_system->getWidth(), 12) {
|
||||
_active = false;
|
||||
_mapCursors = nullptr;
|
||||
_shapes = nullptr;
|
||||
@ -64,8 +65,12 @@ Map::Map(SherlockEngine *vm) : _vm(vm), _topLine(SHERLOCK_SCREEN_WIDTH, 12) {
|
||||
_oldCharPoint = 0;
|
||||
_frameChangeFlag = false;
|
||||
|
||||
for (int idx = 0; idx < MAX_HOLMES_SEQUENCE; ++idx)
|
||||
Common::fill(&_sequences[idx][0], &_sequences[idx][MAX_FRAME], 0);
|
||||
// Initialise the initial walk sequence set
|
||||
_walkSequences.resize(MAX_HOLMES_SEQUENCE);
|
||||
for (int idx = 0; idx < MAX_HOLMES_SEQUENCE; ++idx) {
|
||||
_walkSequences[idx]._sequences.resize(MAX_FRAME);
|
||||
Common::fill(&_walkSequences[idx]._sequences[0], &_walkSequences[idx]._sequences[0] + MAX_FRAME, 0);
|
||||
}
|
||||
|
||||
if (!_vm->isDemo())
|
||||
loadData();
|
||||
@ -79,12 +84,17 @@ void Map::loadPoints(int count, const int *xList, const int *yList, const int *t
|
||||
|
||||
void Map::loadSequences(int count, const byte *seq) {
|
||||
for (int idx = 0; idx < count; ++idx, seq += MAX_FRAME)
|
||||
Common::copy(seq, seq + MAX_FRAME, &_sequences[idx][0]);
|
||||
Common::copy(seq, seq + MAX_FRAME, &_walkSequences[idx]._sequences[0]);
|
||||
}
|
||||
|
||||
void Map::loadData() {
|
||||
// TODO: Remove this
|
||||
if (_vm->getGameID() == GType_RoseTattoo)
|
||||
return;
|
||||
|
||||
// Load the list of location names
|
||||
Common::SeekableReadStream *txtStream = _vm->_res->load("chess.txt");
|
||||
Common::SeekableReadStream *txtStream = _vm->_res->load(
|
||||
_vm->getGameID() == GType_SerratedScalpel ? "chess.txt" : "map.txt");
|
||||
|
||||
int streamSize = txtStream->size();
|
||||
while (txtStream->pos() < streamSize) {
|
||||
@ -283,7 +293,6 @@ void Map::setupSprites() {
|
||||
p._type = CHARACTER;
|
||||
p._position = Common::Point(12400, 5000);
|
||||
p._sequenceNumber = 0;
|
||||
p._sequences = &_sequences;
|
||||
p._images = _shapes;
|
||||
p._imageFrame = nullptr;
|
||||
p._frameNumber = 0;
|
||||
@ -296,8 +305,8 @@ void Map::setupSprites() {
|
||||
p._noShapeSize = Common::Point(0, 0);
|
||||
p._goto = Common::Point(28000, 15000);
|
||||
p._status = 0;
|
||||
p._walkSequences = _walkSequences;
|
||||
p.setImageFrame();
|
||||
|
||||
scene._bgShapes.clear();
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,7 @@ private:
|
||||
ImageFile *_mapCursors;
|
||||
ImageFile *_shapes;
|
||||
ImageFile *_iconShapes;
|
||||
byte _sequences[MAX_HOLMES_SEQUENCE][MAX_FRAME];
|
||||
WalkSequences _walkSequences;
|
||||
Point32 _lDrawnPos;
|
||||
int _point;
|
||||
bool _placesShown;
|
||||
|
@ -4,7 +4,12 @@ MODULE_OBJS = \
|
||||
scalpel/darts.o \
|
||||
scalpel/scalpel.o \
|
||||
scalpel/drivers/adlib.o \
|
||||
scalpel/scalpel_scene.o \
|
||||
scalpel/scalpel_user_interface.o \
|
||||
scalpel/settings.o \
|
||||
tattoo/tattoo.o \
|
||||
tattoo/tattoo_scene.o \
|
||||
tattoo/tattoo_user_interface.o \
|
||||
animation.o \
|
||||
debugger.o \
|
||||
detection.o \
|
||||
@ -19,7 +24,6 @@ MODULE_OBJS = \
|
||||
saveload.o \
|
||||
scene.o \
|
||||
screen.o \
|
||||
settings.o \
|
||||
sherlock.o \
|
||||
sound.o \
|
||||
surface.o \
|
||||
|
@ -272,6 +272,11 @@ bool Music::loadSong(int songNumber) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Music::loadSong(const Common::String &songName) {
|
||||
warning("TODO: Music::loadSong");
|
||||
return false;
|
||||
}
|
||||
|
||||
void Music::syncMusicSettings() {
|
||||
_musicOn = !ConfMan.getBool("mute") && !ConfMan.getBool("music_mute");
|
||||
}
|
||||
|
@ -73,6 +73,11 @@ public:
|
||||
*/
|
||||
bool loadSong(int songNumber);
|
||||
|
||||
/**
|
||||
* Load a specified song
|
||||
*/
|
||||
bool loadSong(const Common::String &songName);
|
||||
|
||||
/**
|
||||
* Start playing a song
|
||||
*/
|
||||
|
@ -46,7 +46,7 @@ void Sprite::clear() {
|
||||
_description = "";
|
||||
_examine.clear();
|
||||
_pickUp = "";
|
||||
_sequences = nullptr;
|
||||
_walkSequences.clear();
|
||||
_images = nullptr;
|
||||
_imageFrame = nullptr;
|
||||
_walkCount = 0;
|
||||
@ -63,12 +63,26 @@ void Sprite::clear() {
|
||||
_status = 0;
|
||||
_misc = 0;
|
||||
_numFrames = 0;
|
||||
_altImages = nullptr;
|
||||
_altSequences = false;
|
||||
Common::fill(&_stopFrames[0], &_stopFrames[8], (ImageFrame *)nullptr);
|
||||
}
|
||||
|
||||
void Sprite::setImageFrame() {
|
||||
int imageNumber = (*_sequences)[_sequenceNumber][_frameNumber] +
|
||||
(*_sequences)[_sequenceNumber][0] - 2;
|
||||
_imageFrame = &(*_images)[imageNumber];
|
||||
int frameNum = MAX(_frameNumber, 0);
|
||||
int imageNumber = _walkSequences[_sequenceNumber][frameNum];
|
||||
|
||||
if (IS_SERRATED_SCALPEL)
|
||||
imageNumber = imageNumber + _walkSequences[_sequenceNumber][0] - 2;
|
||||
else if (imageNumber > _numFrames)
|
||||
imageNumber = 1;
|
||||
|
||||
// Get the images to use
|
||||
ImageFile *images = _altSequences ? _altImages : _images;
|
||||
assert(images);
|
||||
|
||||
// Set the frame pointer
|
||||
_imageFrame = &(*images)[imageNumber];
|
||||
}
|
||||
|
||||
void Sprite::adjustSprite() {
|
||||
@ -113,14 +127,14 @@ void Sprite::adjustSprite() {
|
||||
people.gotoStand(*this);
|
||||
}
|
||||
} else if (!map._active) {
|
||||
_position.y = CLIP((int)_position.y, UPPER_LIMIT, LOWER_LIMIT);
|
||||
_position.x = CLIP((int)_position.x, LEFT_LIMIT, RIGHT_LIMIT);
|
||||
_position.y = CLIP((int)_position.y, (int)UPPER_LIMIT, (int)LOWER_LIMIT);
|
||||
_position.x = CLIP((int)_position.x, (int)LEFT_LIMIT, (int)RIGHT_LIMIT);
|
||||
}
|
||||
|
||||
if (!map._active || (map._frameChangeFlag = !map._frameChangeFlag))
|
||||
++_frameNumber;
|
||||
|
||||
if ((*_sequences)[_sequenceNumber][_frameNumber] == 0) {
|
||||
if (_walkSequences[_sequenceNumber][_frameNumber] == 0) {
|
||||
switch (_sequenceNumber) {
|
||||
case STOP_UP:
|
||||
case STOP_DOWN:
|
||||
@ -352,6 +366,34 @@ void Sprite::checkSprite() {
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
void WalkSequence::load(Common::SeekableReadStream &s) {
|
||||
char buffer[9];
|
||||
s.read(buffer, 9);
|
||||
_vgsName = Common::String(buffer);
|
||||
_horizFlip = s.readByte() != 0;
|
||||
|
||||
_sequences.resize(s.readUint16LE());
|
||||
s.read(&_sequences[0], _sequences.size());
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
WalkSequences &WalkSequences::operator=(const WalkSequences &src) {
|
||||
resize(src.size());
|
||||
for (uint idx = 0; idx < size(); ++idx) {
|
||||
const WalkSequence &wSrc = src[idx];
|
||||
WalkSequence &wDest = (*this)[idx];
|
||||
wDest._horizFlip = wSrc._horizFlip;
|
||||
|
||||
wDest._sequences.resize(wSrc._sequences.size());
|
||||
Common::copy(&wSrc._sequences[0], &wSrc._sequences[0] + wSrc._sequences.size(), &wDest._sequences[0]);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
void ActionType::load(Common::SeekableReadStream &s) {
|
||||
char buffer[12];
|
||||
|
||||
@ -373,9 +415,14 @@ UseType::UseType() {
|
||||
_useFlag = 0;
|
||||
}
|
||||
|
||||
void UseType::load(Common::SeekableReadStream &s) {
|
||||
void UseType::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
|
||||
char buffer[12];
|
||||
|
||||
if (isRoseTattoo) {
|
||||
s.read(buffer, 12);
|
||||
_verb = Common::String(buffer);
|
||||
}
|
||||
|
||||
_cAnimNum = s.readByte();
|
||||
_cAnimSpeed = s.readByte();
|
||||
if (_cAnimSpeed & 0x80)
|
||||
@ -387,7 +434,9 @@ void UseType::load(Common::SeekableReadStream &s) {
|
||||
}
|
||||
|
||||
_useFlag = s.readSint16LE();
|
||||
s.skip(6);
|
||||
|
||||
if (!isRoseTattoo)
|
||||
s.skip(6);
|
||||
|
||||
s.read(buffer, 12);
|
||||
_target = Common::String(buffer);
|
||||
@ -434,9 +483,16 @@ Object::Object() {
|
||||
_descOffset = 0;
|
||||
_seqCounter2 = 0;
|
||||
_seqSize = 0;
|
||||
|
||||
_quickDraw = 0;
|
||||
_scaleVal = 0;
|
||||
_requiredFlag1 = 0;
|
||||
_gotoSeq = 0;
|
||||
_talkSeq = 0;
|
||||
_restoreSlot = 0;
|
||||
}
|
||||
|
||||
void Object::load(Common::SeekableReadStream &s) {
|
||||
void Object::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
|
||||
char buffer[41];
|
||||
s.read(buffer, 12);
|
||||
_name = Common::String(buffer);
|
||||
@ -468,10 +524,10 @@ void Object::load(Common::SeekableReadStream &s) {
|
||||
_goto.x = s.readSint16LE();
|
||||
_goto.y = s.readSint16LE();
|
||||
|
||||
_pickup = s.readByte();
|
||||
_defaultCommand = s.readByte();
|
||||
_lookFlag = s.readUint16LE();
|
||||
_pickupFlag = s.readUint16LE();
|
||||
_pickup = isRoseTattoo ? 0 : s.readByte();
|
||||
_defaultCommand = isRoseTattoo ? 0 : s.readByte();
|
||||
_lookFlag = s.readSint16LE();
|
||||
_pickupFlag = isRoseTattoo ? 0 : s.readSint16LE();
|
||||
_requiredFlag = s.readSint16LE();
|
||||
_noShapeSize.x = s.readUint16LE();
|
||||
_noShapeSize.y = s.readUint16LE();
|
||||
@ -479,26 +535,45 @@ void Object::load(Common::SeekableReadStream &s) {
|
||||
_misc = s.readByte();
|
||||
_maxFrames = s.readUint16LE();
|
||||
_flags = s.readByte();
|
||||
_aOpen.load(s);
|
||||
|
||||
if (!isRoseTattoo)
|
||||
_aOpen.load(s);
|
||||
|
||||
_aType = (AType)s.readByte();
|
||||
_lookFrames = s.readByte();
|
||||
_seqCounter = s.readByte();
|
||||
_lookPosition.x = s.readUint16LE();
|
||||
_lookPosition.y = s.readByte();
|
||||
_lookPosition.y = isRoseTattoo ? s.readSint16LE() : s.readByte();
|
||||
_lookFacing = s.readByte();
|
||||
_lookcAnim = s.readByte();
|
||||
_aClose.load(s);
|
||||
|
||||
if (!isRoseTattoo)
|
||||
_aClose.load(s);
|
||||
|
||||
_seqStack = s.readByte();
|
||||
_seqTo = s.readByte();
|
||||
_descOffset = s.readUint16LE();
|
||||
_seqCounter2 = s.readByte();
|
||||
_seqSize = s.readUint16LE();
|
||||
s.skip(1);
|
||||
_aMove.load(s);
|
||||
s.skip(8);
|
||||
|
||||
for (int idx = 0; idx < USE_COUNT; ++idx)
|
||||
_use[idx].load(s);
|
||||
if (isRoseTattoo) {
|
||||
for (int idx = 0; idx < 6; ++idx)
|
||||
_use[idx].load(s, true);
|
||||
|
||||
_quickDraw = s.readByte();
|
||||
_scaleVal = s.readUint16LE();
|
||||
_requiredFlag1 = s.readSint16LE();
|
||||
_gotoSeq = s.readByte();
|
||||
_talkSeq = s.readByte();
|
||||
_restoreSlot = s.readByte();
|
||||
} else {
|
||||
s.skip(1);
|
||||
_aMove.load(s);
|
||||
s.skip(8);
|
||||
|
||||
for (int idx = 0; idx < 4; ++idx)
|
||||
_use[idx].load(s, false);
|
||||
}
|
||||
}
|
||||
|
||||
void Object::toggleHidden() {
|
||||
@ -1032,17 +1107,30 @@ const Common::Rect Object::getOldBounds() const {
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
void CAnim::load(Common::SeekableReadStream &s) {
|
||||
void CAnim::load(Common::SeekableReadStream &s, bool isRoseTattoo) {
|
||||
char buffer[12];
|
||||
s.read(buffer, 12);
|
||||
_name = Common::String(buffer);
|
||||
|
||||
s.read(_sequences, 30);
|
||||
if (isRoseTattoo) {
|
||||
Common::fill(&_sequences[0], &_sequences[30], 0);
|
||||
_size = s.readUint32LE();
|
||||
} else {
|
||||
s.read(_sequences, 30);
|
||||
}
|
||||
|
||||
_position.x = s.readSint16LE();
|
||||
_position.y = s.readSint16LE();
|
||||
_size = s.readUint32LE();
|
||||
_type = (SpriteType)s.readUint16LE();
|
||||
_flags = s.readByte();
|
||||
|
||||
if (isRoseTattoo) {
|
||||
_flags = s.readByte();
|
||||
_scaleVal = s.readSint16LE();
|
||||
} else {
|
||||
_size = s.readUint32LE();
|
||||
_type = (SpriteType)s.readUint16LE();
|
||||
_flags = s.readByte();
|
||||
}
|
||||
|
||||
_goto.x = s.readSint16LE();
|
||||
_goto.y = s.readSint16LE();
|
||||
_gotoDir = s.readSint16LE();
|
||||
@ -1053,6 +1141,22 @@ void CAnim::load(Common::SeekableReadStream &s) {
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
CAnimStream::CAnimStream() {
|
||||
_stream = nullptr;
|
||||
_frameSize = 0;
|
||||
_images = nullptr;
|
||||
_imageFrame = nullptr;
|
||||
_flags = 0;
|
||||
_scaleVal = 0;
|
||||
_zPlacement = 0;
|
||||
}
|
||||
|
||||
void CAnimStream::getNextFrame() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
SceneImage::SceneImage() {
|
||||
_images = nullptr;
|
||||
_maxFrames = 0;
|
||||
|
@ -46,7 +46,10 @@ enum SpriteType {
|
||||
REMOVE = 5, // Object should be removed next frame
|
||||
NO_SHAPE = 6, // Background object with no shape
|
||||
HIDDEN = 7, // Hidden backgruond object
|
||||
HIDE_SHAPE = 8 // Object needs to be hidden
|
||||
HIDE_SHAPE = 8, // Object needs to be hidden
|
||||
|
||||
// Rose Tattoo
|
||||
HIDDEN_CHARACTER = 128
|
||||
};
|
||||
|
||||
enum AType {
|
||||
@ -73,6 +76,7 @@ enum {
|
||||
|
||||
#define MAX_HOLMES_SEQUENCE 16
|
||||
#define MAX_FRAME 30
|
||||
#define FIXED_INT_MULTIPLIER 100
|
||||
|
||||
// code put into sequences to defines 1-10 type seqs
|
||||
#define SEQ_TO_CODE 67
|
||||
@ -98,65 +102,24 @@ public:
|
||||
void operator-=(const Point32 &delta) { x -= delta.x; y -= delta.y; }
|
||||
};
|
||||
|
||||
class Sprite {
|
||||
private:
|
||||
static SherlockEngine *_vm;
|
||||
|
||||
struct WalkSequence {
|
||||
Common::String _vgsName;
|
||||
bool _horizFlip;
|
||||
Common::Array<byte> _sequences;
|
||||
|
||||
WalkSequence() : _horizFlip(false) {}
|
||||
const byte &operator[](int idx) { return _sequences[idx]; }
|
||||
|
||||
/**
|
||||
* Load data for the sequence from a stream
|
||||
*/
|
||||
void load(Common::SeekableReadStream &s);
|
||||
};
|
||||
|
||||
class WalkSequences : public Common::Array < WalkSequence > {
|
||||
public:
|
||||
Common::String _name;
|
||||
Common::String _description;
|
||||
Common::StringArray _examine; // Examine in-depth description
|
||||
Common::String _pickUp; // Message for if you can't pick up object
|
||||
|
||||
const uint8 (*_sequences)[MAX_HOLMES_SEQUENCE][MAX_FRAME]; // Holds animation sequences
|
||||
ImageFile *_images; // Sprite images
|
||||
ImageFrame *_imageFrame; // Pointer to shape in the images
|
||||
int _walkCount; // Character walk counter
|
||||
int _allow; // Allowed menu commands - ObjectAllow
|
||||
int _frameNumber; // Frame number in rame sequence to draw
|
||||
int _sequenceNumber; // Sequence being used
|
||||
Point32 _position; // Current position
|
||||
Point32 _delta; // Momvement delta
|
||||
Common::Point _oldPosition; // Old position
|
||||
Common::Point _oldSize; // Image's old size
|
||||
Common::Point _goto; // Walk destination
|
||||
SpriteType _type; // Type of object
|
||||
Common::Point _noShapeSize; // Size of a NO_SHAPE
|
||||
int _status; // Status: open/closed, moved/not moved
|
||||
int8 _misc; // Miscellaneous use
|
||||
int _numFrames; // How many frames the object has
|
||||
public:
|
||||
Sprite() { clear(); }
|
||||
static void setVm(SherlockEngine *vm) { _vm = vm; }
|
||||
|
||||
/**
|
||||
* Reset the data for the sprite
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Updates the image frame poiner for the sprite
|
||||
*/
|
||||
void setImageFrame();
|
||||
|
||||
/**
|
||||
* This adjusts the sprites position, as well as it's animation sequence:
|
||||
*/
|
||||
void adjustSprite();
|
||||
|
||||
/**
|
||||
* Checks the sprite's position to see if it's collided with any special objects
|
||||
*/
|
||||
void checkSprite();
|
||||
|
||||
/**
|
||||
* Return frame width
|
||||
*/
|
||||
int frameWidth() const { return _imageFrame ? _imageFrame->_frame.w : 0; }
|
||||
|
||||
/**
|
||||
* Return frame height
|
||||
*/
|
||||
int frameHeight() const { return _imageFrame ? _imageFrame->_frame.h : 0; }
|
||||
WalkSequences &operator=(const WalkSequences &src);
|
||||
};
|
||||
|
||||
enum { REVERSE_DIRECTION = 0x80 };
|
||||
@ -179,13 +142,106 @@ struct UseType {
|
||||
Common::String _names[NAMES_COUNT];
|
||||
int _useFlag; // Which flag USE will set (if any)
|
||||
Common::String _target;
|
||||
Common::String _verb;
|
||||
|
||||
UseType();
|
||||
|
||||
/**
|
||||
* Load the data for the UseType
|
||||
*/
|
||||
void load(Common::SeekableReadStream &s);
|
||||
void load(Common::SeekableReadStream &s, bool isRoseTattoo);
|
||||
};
|
||||
|
||||
|
||||
class Sprite {
|
||||
private:
|
||||
static SherlockEngine *_vm;
|
||||
public:
|
||||
Common::String _name;
|
||||
Common::String _description;
|
||||
Common::String _examine; // Examine in-depth description
|
||||
Common::String _pickUp; // Message for if you can't pick up object
|
||||
|
||||
WalkSequences _walkSequences; // Holds animation sequences
|
||||
ImageFile *_images; // Sprite images
|
||||
ImageFrame *_imageFrame; // Pointer to shape in the images
|
||||
int _walkCount; // Character walk counter
|
||||
int _allow; // Allowed menu commands - ObjectAllow
|
||||
int _frameNumber; // Frame number in rame sequence to draw
|
||||
int _sequenceNumber; // Sequence being used
|
||||
Point32 _position; // Current position
|
||||
Point32 _delta; // Momvement delta
|
||||
Common::Point _oldPosition; // Old position
|
||||
Common::Point _oldSize; // Image's old size
|
||||
Common::Point _goto; // Walk destination
|
||||
SpriteType _type; // Type of object
|
||||
Common::Point _noShapeSize; // Size of a NO_SHAPE
|
||||
int _status; // Status: open/closed, moved/not moved
|
||||
int8 _misc; // Miscellaneous use
|
||||
int _numFrames; // How many frames the object has
|
||||
|
||||
// Rose Tattoo fields
|
||||
int _startSeq; // Frame sequence starts at
|
||||
int _flags; // Flags for the sprite
|
||||
int _aType; // Tells if this is an object, person, talk, etc.
|
||||
int _lookFrames; // How many frames to play of a canim before pausing
|
||||
int _seqCounter; // How many times the sequence has been run
|
||||
Common::Point _lookPosition; // Where to look when examining object
|
||||
int _lookFacing; // Direction to face when examining object
|
||||
int _lookCAnim;
|
||||
int _seqStack; // Allow gosubs to return to calling frame
|
||||
int _seqTo; // Allows 1-5, 8-3 type sequences encoded in 2 bytes
|
||||
uint _descOffset; // Tells where description starts in description text for scene
|
||||
int _seqCounter2; // Counter of calling frame sequence
|
||||
uint _seqSize; // Size of sequence
|
||||
UseType _use[6];
|
||||
int _quickDraw; // Flag telling whether to use quick draw routine or not
|
||||
int _scaleVal; // Tells how to scale the sprite
|
||||
int _requiredFlags1; // This flag must also be set, or the sprite is hidden
|
||||
int _gotoSeq; // Used by Talk to tell which sequence to goto when able
|
||||
int _talkSeq; // Tells which talk sequence currently in use (Talk or Listen)
|
||||
int _restoreSlot; // Used when talk returns to the previous sequence
|
||||
|
||||
ImageFrame *_stopFrames[8]; // Stop/rest frame for each direction
|
||||
ImageFile *_altImages; // Images used for alternate NPC sequences
|
||||
bool _altSequences; // Which of the sequences the alt graphics apply to (0: main, 1=NPC seq)
|
||||
int _centerWalk; // Flag telling the walk code to offset the walk destination
|
||||
Common::Point _adjust; // Fine tuning adjustment to position when drawn
|
||||
int _oldWalkSequence;
|
||||
public:
|
||||
Sprite() { clear(); }
|
||||
|
||||
static void setVm(SherlockEngine *vm) { _vm = vm; }
|
||||
|
||||
/**
|
||||
* Reset the data for the sprite
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Updates the image frame poiner for the sprite
|
||||
*/
|
||||
void setImageFrame();
|
||||
|
||||
/**
|
||||
* This adjusts the sprites position, as well as it's animation sequence:
|
||||
*/
|
||||
void adjustSprite();
|
||||
|
||||
/**
|
||||
* Checks the sprite's position to see if it's collided with any special objects
|
||||
*/
|
||||
void checkSprite();
|
||||
|
||||
/**
|
||||
* Return frame width
|
||||
*/
|
||||
int frameWidth() const { return _imageFrame ? _imageFrame->_frame.w : 0; }
|
||||
|
||||
/**
|
||||
* Return frame height
|
||||
*/
|
||||
int frameHeight() const { return _imageFrame ? _imageFrame->_frame.h : 0; }
|
||||
};
|
||||
|
||||
enum { OBJ_BEHIND = 1, OBJ_FLIPPED = 2, OBJ_FORWARD = 4, TURNON_OBJ = 0x20, TURNOFF_OBJ = 0x40 };
|
||||
@ -233,35 +289,45 @@ public:
|
||||
int _pickup;
|
||||
int _defaultCommand; // Default right-click command
|
||||
int _lookFlag; // Which flag LOOK will set (if any)
|
||||
int _pickupFlag; // Which flag PICKUP will set (if any)
|
||||
int _requiredFlag; // Object will be hidden if not set
|
||||
Common::Point _noShapeSize; // Size of a NO_SHAPE
|
||||
int _status; // Status (open/closed, moved/not)
|
||||
int8 _misc; // Misc field -- use varies with type
|
||||
int _maxFrames; // Number of frames
|
||||
int _flags; // Tells if object can be walked behind
|
||||
ActionType _aOpen; // Holds data for moving object
|
||||
AType _aType; // Tells if this is an object, person, talk, etc.
|
||||
int _lookFrames; // How many frames to play of the look anim before pausing
|
||||
int _seqCounter; // How many times this sequence has been executed
|
||||
Common::Point _lookPosition; // Where to walk when examining object
|
||||
int _lookFacing; // Direction to face when examining object
|
||||
int _lookcAnim;
|
||||
ActionType _aClose;
|
||||
int _seqStack; // Allows gosubs to return to calling frame
|
||||
int _seqTo; // Allows 1-5, 8-3 type sequences encoded in 2 bytes
|
||||
uint _descOffset; // Tells where description starts in DescText
|
||||
int _seqCounter2; // Counter of calling frame sequence
|
||||
uint _seqSize; // Tells where description starts
|
||||
UseType _use[6]; // Serrated Scalpel uses 4, Rose Tattoo 6
|
||||
|
||||
// Serrated Scalpel fields
|
||||
int _pickupFlag; // Which flag PICKUP will set (if any)
|
||||
ActionType _aOpen; // Holds data for moving object
|
||||
ActionType _aClose;
|
||||
ActionType _aMove;
|
||||
UseType _use[USE_COUNT];
|
||||
|
||||
// Rose Tattoo fields
|
||||
int _quickDraw;
|
||||
int _scaleVal;
|
||||
int _requiredFlag1;
|
||||
int _gotoSeq;
|
||||
int _talkSeq;
|
||||
int _restoreSlot;
|
||||
|
||||
Object();
|
||||
|
||||
/**
|
||||
* Load the data for the object
|
||||
*/
|
||||
void load(Common::SeekableReadStream &s);
|
||||
void load(Common::SeekableReadStream &s, bool isRoseTattoo);
|
||||
|
||||
/**
|
||||
* Toggle the type of an object between hidden and active
|
||||
@ -326,20 +392,45 @@ public:
|
||||
|
||||
struct CAnim {
|
||||
Common::String _name; // Name
|
||||
byte _sequences[MAX_FRAME]; // Animation sequences
|
||||
Common::Point _position; // Position
|
||||
int _size; // Size of uncompressed animation
|
||||
SpriteType _type;
|
||||
int _flags; // Tells if can be walked behind
|
||||
Common::Point _goto; // coords holmes should walk to before starting canim
|
||||
int _gotoDir;
|
||||
Common::Point _teleportPos; // Location Holmes shoul teleport to after
|
||||
int _teleportDir; // playing canim
|
||||
|
||||
// Scalpel specific
|
||||
byte _sequences[MAX_FRAME]; // Animation sequences
|
||||
SpriteType _type;
|
||||
|
||||
// Rose Tattoo specific
|
||||
int _scaleVal; // How much the canim is scaled
|
||||
|
||||
/**
|
||||
* Load the data for the animation
|
||||
*/
|
||||
void load(Common::SeekableReadStream &s);
|
||||
void load(Common::SeekableReadStream &s, bool isRoseTattoo);
|
||||
};
|
||||
|
||||
struct CAnimStream {
|
||||
Common::SeekableReadStream *_stream; // Stream to read frames from
|
||||
int _frameSize; // Temporary used to store the frame size
|
||||
|
||||
void *_images; // TOOD: FIgure out hwo to hook up ImageFile with streaming support
|
||||
ImageFrame *_imageFrame;
|
||||
|
||||
Common::Point _position; // Animation position
|
||||
Common::Rect _oldBounds; // Bounds of previous frame
|
||||
Common::Rect _removeBounds; // Remove area for just drawn frame
|
||||
|
||||
int _flags; // Flags
|
||||
int _scaleVal; // Specifies the scale amount
|
||||
int _zPlacement; // Used by doBgAnim for determining Z order
|
||||
|
||||
CAnimStream();
|
||||
|
||||
void getNextFrame();
|
||||
};
|
||||
|
||||
struct SceneImage {
|
||||
|
@ -50,10 +50,38 @@ static const uint8 CHARACTER_SEQUENCES[MAX_HOLMES_SEQUENCE][MAX_FRAME] = {
|
||||
{ 52, 1, 2, 3, 4, 0 } // Goto Stand Down Left
|
||||
};
|
||||
|
||||
// Rose Tattoo walk image libraries
|
||||
// Walk resources within WALK.LIB
|
||||
#define NUM_IN_WALK_LIB 10
|
||||
const char *const WALK_LIB_NAMES[10] = {
|
||||
"SVGAWALK.VGS",
|
||||
"COATWALK.VGS",
|
||||
"WATSON.VGS",
|
||||
"NOHAT.VGS",
|
||||
"TUPRIGHT.VGS",
|
||||
"TRIGHT.VGS",
|
||||
"TDOWNRG.VGS",
|
||||
"TWUPRIGH.VGS",
|
||||
"TWRIGHT.VGS",
|
||||
"TWDOWNRG.VGS"
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
Person::Person() : Sprite(), _walkLoaded(false), _npcIndex(0), _npcStack(0), _npcPause(false) {
|
||||
Common::fill(&_npcPath[0], &_npcPath[MAX_NPC_PATH], 0);
|
||||
_tempX = _tempScaleVal = 0;
|
||||
}
|
||||
|
||||
void Person::clearNPC() {
|
||||
Common::fill(&_npcPath[0], &_npcPath[MAX_NPC_PATH], 0);
|
||||
_npcIndex = _npcStack = 0;
|
||||
_npcName = "";
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
People::People(SherlockEngine *vm) : _vm(vm), _player(_data[0]) {
|
||||
_walkLoaded = false;
|
||||
_holmesOn = true;
|
||||
_oldWalkSequence = -1;
|
||||
_allowWalkAbort = false;
|
||||
@ -68,66 +96,168 @@ People::People(SherlockEngine *vm) : _vm(vm), _player(_data[0]) {
|
||||
_holmesQuotient = 0;
|
||||
_hSavedPos = Common::Point(-1, -1);
|
||||
_hSavedFacing = -1;
|
||||
_forceWalkReload = false;
|
||||
_useWalkLib = false;
|
||||
_walkControl = 0;
|
||||
|
||||
_portrait._sequences = new byte[32];
|
||||
}
|
||||
|
||||
People::~People() {
|
||||
if (_walkLoaded)
|
||||
delete _data[PLAYER]._images;
|
||||
for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
|
||||
if (_data[idx]._walkLoaded)
|
||||
delete _data[PLAYER]._images;
|
||||
}
|
||||
|
||||
delete _talkPics;
|
||||
delete[] _portrait._sequences;
|
||||
}
|
||||
|
||||
void People::reset() {
|
||||
// Note: The engine has theoretical support for two player characters but only the first one is used.
|
||||
// Watson is, instead, handled by a different sprite in each scene, with a very simple initial movement, if any
|
||||
Sprite &p = _data[PLAYER];
|
||||
_data[0]._description = "Sherlock Holmes!";
|
||||
|
||||
p._description = "Sherlock Holmes!";
|
||||
p._type = CHARACTER;
|
||||
p._position = Common::Point(10000, 11000);
|
||||
p._sequenceNumber = STOP_DOWNRIGHT;
|
||||
p._sequences = &CHARACTER_SEQUENCES;
|
||||
p._imageFrame = nullptr;
|
||||
p._frameNumber = 1;
|
||||
p._delta = Common::Point(0, 0);
|
||||
p._oldPosition = Common::Point(0, 0);
|
||||
p._oldSize = Common::Point(0, 0);
|
||||
p._misc = 0;
|
||||
p._walkCount = 0;
|
||||
p._pickUp = "";
|
||||
p._allow = 0;
|
||||
p._noShapeSize = Common::Point(0, 0);
|
||||
p._goto = Common::Point(0, 0);
|
||||
p._status = 0;
|
||||
// Note: Serrated Scalpel only uses a single Person slot for Sherlock.. Watson is handled by scene sprites
|
||||
int count = IS_SERRATED_SCALPEL ? 1 : MAX_CHARACTERS;
|
||||
for (int idx = 0; idx < count; ++idx) {
|
||||
Sprite &p = _data[idx];
|
||||
|
||||
p._type = (idx == 0) ? CHARACTER : INVALID;
|
||||
if (IS_SERRATED_SCALPEL)
|
||||
p._position = Point32(10000, 11000);
|
||||
else
|
||||
p._position = Point32(36000, 29000);
|
||||
|
||||
p._sequenceNumber = STOP_DOWNRIGHT;
|
||||
p._imageFrame = nullptr;
|
||||
p._frameNumber = 1;
|
||||
p._delta = Common::Point(0, 0);
|
||||
p._oldPosition = Common::Point(0, 0);
|
||||
p._oldSize = Common::Point(0, 0);
|
||||
p._misc = 0;
|
||||
p._walkCount = 0;
|
||||
p._pickUp = "";
|
||||
p._allow = 0;
|
||||
p._noShapeSize = Common::Point(0, 0);
|
||||
p._goto = Common::Point(0, 0);
|
||||
p._status = 0;
|
||||
p._seqTo = 0;
|
||||
p._seqCounter = p._seqCounter2 = 0;
|
||||
p._seqStack = 0;
|
||||
p._gotoSeq = p._talkSeq = 0;
|
||||
p._restoreSlot = 0;
|
||||
p._startSeq = 0;
|
||||
p._altImages = nullptr;
|
||||
p._altSequences = 0;
|
||||
p._centerWalk = true;
|
||||
p._adjust = Common::Point(0, 0);
|
||||
|
||||
// Load the default walk sequences
|
||||
p._oldWalkSequence = -1;
|
||||
p._walkSequences.clear();
|
||||
if (IS_SERRATED_SCALPEL) {
|
||||
p._walkSequences.resize(MAX_HOLMES_SEQUENCE);
|
||||
for (int seqIdx = 0; seqIdx < MAX_HOLMES_SEQUENCE; ++seqIdx) {
|
||||
p._walkSequences[seqIdx]._sequences.clear();
|
||||
|
||||
const byte *pSrc = &CHARACTER_SEQUENCES[seqIdx][0];
|
||||
do {
|
||||
p._walkSequences[seqIdx]._sequences.push_back(*pSrc);
|
||||
} while (*pSrc++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset any walk path in progress when Sherlock leaves scenes
|
||||
_walkTo.clear();
|
||||
}
|
||||
|
||||
bool People::loadWalk() {
|
||||
if (_walkLoaded) {
|
||||
return false;
|
||||
} else {
|
||||
_data[PLAYER]._images = new ImageFile("walk.vgs");
|
||||
_data[PLAYER].setImageFrame();
|
||||
_walkLoaded = true;
|
||||
Resources &res = *_vm->_res;
|
||||
bool result = false;
|
||||
|
||||
return true;
|
||||
if (IS_SERRATED_SCALPEL) {
|
||||
if (_data[PLAYER]._walkLoaded) {
|
||||
return false;
|
||||
} else {
|
||||
_data[PLAYER]._images = new ImageFile("walk.vgs");
|
||||
_data[PLAYER].setImageFrame();
|
||||
_data[PLAYER]._walkLoaded = true;
|
||||
|
||||
result = true;
|
||||
}
|
||||
} else {
|
||||
for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
|
||||
if (!_data[idx]._walkLoaded && (_data[idx]._type == CHARACTER || _data[idx]._type == HIDDEN_CHARACTER)) {
|
||||
if (_data[idx]._type == HIDDEN_CHARACTER)
|
||||
_data[idx]._type = INVALID;
|
||||
|
||||
// See if this is one of the more used Walk Graphics stored in WALK.LIB
|
||||
for (int libNum = 0; libNum < NUM_IN_WALK_LIB; ++libNum) {
|
||||
if (!_data[0]._walkVGSName.compareToIgnoreCase(WALK_LIB_NAMES[libNum])) {
|
||||
_useWalkLib = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Load the images for the character
|
||||
_data[idx]._images = new ImageFile(_data[idx]._walkVGSName, false);
|
||||
_data[idx]._numFrames = _data[idx]._images->size();
|
||||
|
||||
// Load walk sequence data
|
||||
Common::String fname = Common::String(_data[idx]._walkVGSName.c_str(), strchr(_data[idx]._walkVGSName.c_str(), '.'));
|
||||
fname += ".SEQ";
|
||||
|
||||
// Load the walk sequence data
|
||||
Common::SeekableReadStream *stream = res.load(fname, _useWalkLib ? "walk.lib" : "vgs.lib");
|
||||
|
||||
_data[idx]._walkSequences.resize(stream->readByte());
|
||||
|
||||
for (uint seqNum = 0; seqNum < _data[idx]._walkSequences.size(); ++seqNum)
|
||||
_data[idx]._walkSequences[seqNum].load(*stream);
|
||||
|
||||
// Close the sequences resource
|
||||
delete stream;
|
||||
_useWalkLib = false;
|
||||
|
||||
_data[idx]._frameNumber = 0;
|
||||
_data[idx].setImageFrame();
|
||||
|
||||
// Set the stop Frames pointers
|
||||
for (int dirNum = 0; dirNum < 8; ++dirNum) {
|
||||
int count = 0;
|
||||
while (_data[idx]._walkSequences[dirNum + 8][count] != 0)
|
||||
++count;
|
||||
count += 2;
|
||||
count = _data[idx]._walkSequences[dirNum + 8][count] - 1;
|
||||
_data[idx]._stopFrames[dirNum] = &(*_data[idx]._images)[count];
|
||||
}
|
||||
|
||||
result = true;
|
||||
_data[idx]._walkLoaded = true;
|
||||
} else if (_data[idx]._type != CHARACTER) {
|
||||
_data[idx]._walkLoaded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_forceWalkReload = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool People::freeWalk() {
|
||||
if (_walkLoaded) {
|
||||
delete _player._images;
|
||||
_player._images = nullptr;
|
||||
bool result = false;
|
||||
|
||||
_walkLoaded = false;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
|
||||
if (_data[idx]._walkLoaded) {
|
||||
delete _data[idx]._images;
|
||||
_data[idx]._images = nullptr;
|
||||
|
||||
_data[idx]._walkLoaded = false;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void People::setWalking() {
|
||||
@ -553,9 +683,24 @@ void People::setTalking(int speaker) {
|
||||
|
||||
void People::synchronize(Common::Serializer &s) {
|
||||
s.syncAsByte(_holmesOn);
|
||||
s.syncAsSint16LE(_player._position.x);
|
||||
s.syncAsSint16LE(_player._position.y);
|
||||
s.syncAsSint16LE(_player._sequenceNumber);
|
||||
|
||||
if (IS_SERRATED_SCALPEL) {
|
||||
s.syncAsSint16LE(_player._position.x);
|
||||
s.syncAsSint16LE(_player._position.y);
|
||||
s.syncAsSint16LE(_player._sequenceNumber);
|
||||
} else {
|
||||
for (int idx = 0; idx < MAX_CHARACTERS; ++idx) {
|
||||
Person &p = _data[idx];
|
||||
s.syncAsSint16LE(p._position.x);
|
||||
s.syncAsSint16LE(p._position.y);
|
||||
s.syncAsSint16LE(p._sequenceNumber);
|
||||
s.syncAsSint16LE(p._type);
|
||||
s.syncString(p._walkVGSName);
|
||||
s.syncString(p._description);
|
||||
s.syncString(p._examine);
|
||||
}
|
||||
}
|
||||
|
||||
s.syncAsSint16LE(_holmesQuotient);
|
||||
|
||||
if (s.isLoading()) {
|
||||
|
@ -30,13 +30,13 @@
|
||||
|
||||
namespace Sherlock {
|
||||
|
||||
// Player definitions. The game has theoretical support for two player characters but only the first one is used.
|
||||
// Watson is, instead, handled by a different sprite in each scene, with a very simple initial movement, if any
|
||||
enum PeopleId {
|
||||
PLAYER = 0,
|
||||
AL = 0,
|
||||
PEG = 1,
|
||||
MAX_PLAYERS = 2
|
||||
MAX_CHARACTERS = 6,
|
||||
MAX_NPC = 5,
|
||||
MAX_NPC_PATH = 200
|
||||
};
|
||||
|
||||
// Animation sequence identifiers for characters
|
||||
@ -63,20 +63,37 @@ struct PersonData {
|
||||
_name(name), _portrait(portrait), _stillSequences(stillSequences), _talkSequences(talkSequences) {}
|
||||
};
|
||||
|
||||
class SherlockEngine;
|
||||
|
||||
class Person : public Sprite {
|
||||
public:
|
||||
Person() : Sprite() {}
|
||||
|
||||
bool _walkLoaded;
|
||||
Common::String _portrait;
|
||||
|
||||
// NPC related fields
|
||||
int _npcIndex;
|
||||
int _npcStack;
|
||||
bool _npcPause;
|
||||
byte _npcPath[MAX_NPC_PATH];
|
||||
Common::String _npcName;
|
||||
int _tempX;
|
||||
int _tempScaleVal;
|
||||
|
||||
// Rose Tattoo fields
|
||||
Common::String _walkVGSName; // Name of walk library person is using
|
||||
public:
|
||||
Person();
|
||||
|
||||
/**
|
||||
* Clear the NPC related data
|
||||
*/
|
||||
void clearNPC();
|
||||
};
|
||||
|
||||
class SherlockEngine;
|
||||
|
||||
class People {
|
||||
private:
|
||||
SherlockEngine *_vm;
|
||||
Person _data[MAX_PLAYERS];
|
||||
bool _walkLoaded;
|
||||
Person _data[MAX_CHARACTERS];
|
||||
int _oldWalkSequence;
|
||||
int _srcZone, _destZone;
|
||||
public:
|
||||
@ -97,24 +114,23 @@ public:
|
||||
bool _speakerFlip;
|
||||
bool _holmesFlip;
|
||||
int _holmesQuotient;
|
||||
bool _forceWalkReload;
|
||||
bool _useWalkLib;
|
||||
|
||||
int _walkControl;
|
||||
public:
|
||||
People(SherlockEngine *vm);
|
||||
~People();
|
||||
|
||||
Person &operator[](PeopleId id) {
|
||||
assert(id < MAX_PLAYERS);
|
||||
assert(id < MAX_CHARACTERS);
|
||||
return _data[id];
|
||||
}
|
||||
Person &operator[](int idx) {
|
||||
assert(idx < MAX_PLAYERS);
|
||||
assert(idx < MAX_CHARACTERS);
|
||||
return _data[idx];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if Sherlock is visible on the screen and enabled
|
||||
*/
|
||||
bool isHolmesActive() const { return _walkLoaded && _holmesOn; }
|
||||
|
||||
/**
|
||||
* Reset the player data
|
||||
*/
|
||||
|
@ -65,7 +65,7 @@ void Cache::load(const Common::String &name, Common::SeekableReadStream &stream)
|
||||
// Check whether the file is compressed
|
||||
if (signature == MKTAG('L', 'Z', 'V', 26)) {
|
||||
// It's compressed, so decompress the file and store it's data in the cache entry
|
||||
Common::SeekableReadStream *decompressed = _vm->_res->decompressLZ(stream);
|
||||
Common::SeekableReadStream *decompressed = _vm->_res->decompress(stream);
|
||||
cacheEntry.resize(decompressed->size());
|
||||
decompressed->read(&cacheEntry[0], decompressed->size());
|
||||
|
||||
@ -91,9 +91,12 @@ Resources::Resources(SherlockEngine *vm) : _vm(vm), _cache(vm) {
|
||||
if (_vm->_interactiveFl) {
|
||||
addToCache("vgs.lib");
|
||||
addToCache("talk.lib");
|
||||
addToCache("sequence.txt");
|
||||
addToCache("journal.txt");
|
||||
addToCache("portrait.lib");
|
||||
|
||||
if (IS_SERRATED_SCALPEL) {
|
||||
addToCache("sequence.txt");
|
||||
addToCache("portrait.lib");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,8 +106,11 @@ void Resources::addToCache(const Common::String &filename) {
|
||||
// Check to see if the file is a library
|
||||
Common::SeekableReadStream *stream = load(filename);
|
||||
uint32 header = stream->readUint32BE();
|
||||
|
||||
if (header == MKTAG('L', 'I', 'B', 26))
|
||||
loadLibraryIndex(filename, stream);
|
||||
loadLibraryIndex(filename, stream, false);
|
||||
else if (header == MKTAG('L', 'I', 'C', 26))
|
||||
loadLibraryIndex(filename, stream, true);
|
||||
|
||||
delete stream;
|
||||
}
|
||||
@ -159,12 +165,14 @@ Common::SeekableReadStream *Resources::load(const Common::String &filename) {
|
||||
|
||||
void Resources::decompressIfNecessary(Common::SeekableReadStream *&stream) {
|
||||
bool isCompressed = stream->readUint32BE() == MKTAG('L', 'Z', 'V', 26);
|
||||
stream->seek(-4, SEEK_CUR);
|
||||
|
||||
if (isCompressed) {
|
||||
Common::SeekableReadStream *newStream = decompressLZ(*stream);
|
||||
int outSize = stream->readUint32LE();
|
||||
Common::SeekableReadStream *newStream = decompressLZ(*stream, outSize);
|
||||
delete stream;
|
||||
stream = newStream;
|
||||
} else {
|
||||
stream->seek(-4, SEEK_CUR);
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,7 +182,7 @@ Common::SeekableReadStream *Resources::load(const Common::String &filename, cons
|
||||
|
||||
// Check if the library has already had it's index read, and if not, load it
|
||||
if (!_indexes.contains(libraryFile))
|
||||
loadLibraryIndex(libraryFile, libStream);
|
||||
loadLibraryIndex(libraryFile, libStream, false);
|
||||
|
||||
// Extract the data for the specified resource and return it
|
||||
LibraryEntry &entry = _indexes[libraryFile][filename];
|
||||
@ -192,7 +200,7 @@ bool Resources::exists(const Common::String &filename) const {
|
||||
}
|
||||
|
||||
void Resources::loadLibraryIndex(const Common::String &libFilename,
|
||||
Common::SeekableReadStream *stream) {
|
||||
Common::SeekableReadStream *stream, bool isNewStyle) {
|
||||
uint32 offset, nextOffset;
|
||||
|
||||
// Create an index entry
|
||||
@ -203,6 +211,9 @@ void Resources::loadLibraryIndex(const Common::String &libFilename,
|
||||
stream->seek(4);
|
||||
int count = stream->readUint16LE();
|
||||
|
||||
if (isNewStyle)
|
||||
stream->seek((count + 1) * 8, SEEK_CUR);
|
||||
|
||||
// Loop through reading in the entries
|
||||
for (int idx = 0; idx < count; ++idx) {
|
||||
// Read the name of the resource
|
||||
@ -231,24 +242,48 @@ int Resources::resourceIndex() const {
|
||||
return _resourceIndex;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &source) {
|
||||
if (_vm->getGameID() == GType_SerratedScalpel) {
|
||||
uint32 id = source.readUint32BE();
|
||||
assert(id == MKTAG('L', 'Z', 'V', 0x1A));
|
||||
}
|
||||
Common::SeekableReadStream *Resources::decompress(Common::SeekableReadStream &source) {
|
||||
// This variation can't be used by Rose Tattoo, since compressed resources include the input size,
|
||||
// not the output size. Which means their decompression has to be done via passed buffers
|
||||
assert(_vm->getGameID() == GType_SerratedScalpel);
|
||||
|
||||
uint32 size = source.readUint32LE();
|
||||
return decompressLZ(source, size);
|
||||
uint32 id = source.readUint32BE();
|
||||
assert(id == MKTAG('L', 'Z', 'V', 0x1A));
|
||||
|
||||
uint32 outputSize = source.readUint32LE();
|
||||
return decompressLZ(source, outputSize);
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *Resources::decompress(Common::SeekableReadStream &source, uint32 outSize) {
|
||||
int inSize = (_vm->getGameID() == GType_RoseTattoo) ? source.readUint32LE() : -1;
|
||||
byte *outBuffer = (byte *)malloc(outSize);
|
||||
Common::MemoryReadStream *outStream = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES);
|
||||
|
||||
decompressLZ(source, outBuffer, outSize, inSize);
|
||||
|
||||
return outStream;
|
||||
}
|
||||
|
||||
void Resources::decompress(Common::SeekableReadStream &source, byte *buffer, uint32 outSize) {
|
||||
int inputSize = (_vm->getGameID() == GType_RoseTattoo) ? source.readUint32LE() : -1;
|
||||
|
||||
decompressLZ(source, buffer, outSize, inputSize);
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &source, uint32 outSize) {
|
||||
byte *dataOut = (byte *)malloc(outSize);
|
||||
decompressLZ(source, dataOut, outSize, -1);
|
||||
|
||||
return new Common::MemoryReadStream(dataOut, outSize, DisposeAfterUse::YES);
|
||||
}
|
||||
|
||||
void Resources::decompressLZ(Common::SeekableReadStream &source, byte *outBuffer, int32 outSize, int32 inSize) {
|
||||
byte lzWindow[4096];
|
||||
uint16 lzWindowPos;
|
||||
uint16 cmd;
|
||||
|
||||
byte *outBuffer = (byte *)malloc(outSize);
|
||||
byte *outBufferEnd = outBuffer + outSize;
|
||||
Common::MemoryReadStream *outS = new Common::MemoryReadStream(outBuffer, outSize, DisposeAfterUse::YES);
|
||||
int endPos = source.pos() + inSize;
|
||||
|
||||
memset(lzWindow, 0xFF, 0xFEE);
|
||||
lzWindowPos = 0xFEE;
|
||||
@ -264,8 +299,7 @@ Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &
|
||||
*outBuffer++ = literal;
|
||||
lzWindow[lzWindowPos] = literal;
|
||||
lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
int copyPos, copyLen;
|
||||
copyPos = source.readByte();
|
||||
copyLen = source.readByte();
|
||||
@ -279,9 +313,7 @@ Common::SeekableReadStream *Resources::decompressLZ(Common::SeekableReadStream &
|
||||
lzWindowPos = (lzWindowPos + 1) & 0x0FFF;
|
||||
}
|
||||
}
|
||||
} while (outBuffer < outBufferEnd);
|
||||
|
||||
return outS;
|
||||
} while ((outSize == -1 || outBuffer < outBufferEnd) && (inSize == -1 || source.pos() < endPos));
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
@ -325,13 +357,14 @@ void ImageFile::load(Common::SeekableReadStream &stream, bool skipPalette, bool
|
||||
// Animation cutscene image files use a 16-bit x offset
|
||||
frame._offset.x = stream.readUint16LE();
|
||||
frame._rleEncoded = (frame._offset.x & 0xff) == 1;
|
||||
frame._offset.y = stream.readByte();
|
||||
} else {
|
||||
// Standard image files have a separate byte for the RLE flag, and an 8-bit X offset
|
||||
frame._rleEncoded = stream.readByte() == 1;
|
||||
frame._offset.x = stream.readByte();
|
||||
frame._offset.y = stream.readByte();
|
||||
}
|
||||
|
||||
frame._offset.y = stream.readByte();
|
||||
frame._rleEncoded = !skipPalette && frame._rleEncoded;
|
||||
|
||||
if (frame._paletteBase) {
|
||||
@ -385,6 +418,28 @@ void ImageFile::decompressFrame(ImageFrame &frame, const byte *src) {
|
||||
*pDest++ = *src & 0xF;
|
||||
*pDest++ = (*src >> 4);
|
||||
}
|
||||
} else if (frame._rleEncoded && _vm->getGameID() == GType_RoseTattoo) {
|
||||
// Rose Tattoo run length encoding doesn't use the RLE marker byte
|
||||
byte *dst = (byte *)frame._frame.getPixels();
|
||||
|
||||
for (int yp = 0; yp < frame._height; ++yp) {
|
||||
int xSize = frame._width;
|
||||
while (xSize > 0) {
|
||||
// Skip a given number of pixels
|
||||
byte skip = *src++;
|
||||
dst += skip;
|
||||
xSize -= skip;
|
||||
if (!xSize)
|
||||
break;
|
||||
|
||||
// Get a run length, and copy the following number of pixels
|
||||
int rleCount = *src++;
|
||||
xSize -= rleCount;
|
||||
while (rleCount-- > 0)
|
||||
*dst++ = *src++;
|
||||
}
|
||||
assert(xSize == 0);
|
||||
}
|
||||
} else if (frame._rleEncoded) {
|
||||
// RLE encoded
|
||||
byte *dst = (byte *)frame._frame.getPixels();
|
||||
@ -411,4 +466,34 @@ void ImageFile::decompressFrame(ImageFrame &frame, const byte *src) {
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
int ImageFrame::sDrawXSize(int scaleVal) const {
|
||||
int width = _width;
|
||||
int scale = scaleVal == 0 ? 1 : scaleVal;
|
||||
|
||||
if (scaleVal >= 256)
|
||||
--width;
|
||||
|
||||
int result = width * 256 / scale;
|
||||
if (scaleVal >= 256)
|
||||
++result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int ImageFrame::sDrawYSize(int scaleVal) const {
|
||||
int height = _height;
|
||||
int scale = scaleVal == 0 ? 1 : scaleVal;
|
||||
|
||||
if (scaleVal >= 256)
|
||||
--height;
|
||||
|
||||
int result = height * 256 / scale;
|
||||
if (scaleVal >= 256)
|
||||
++result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // End of namespace Sherlock
|
||||
|
@ -90,7 +90,7 @@ private:
|
||||
/**
|
||||
* Reads in the index from a library file, and caches it's index for later use
|
||||
*/
|
||||
void loadLibraryIndex(const Common::String &libFilename, Common::SeekableReadStream *stream);
|
||||
void loadLibraryIndex(const Common::String &libFilename, Common::SeekableReadStream *stream, bool isNewStyle);
|
||||
public:
|
||||
Resources(SherlockEngine *vm);
|
||||
|
||||
@ -140,14 +140,29 @@ public:
|
||||
int resourceIndex() const;
|
||||
|
||||
/**
|
||||
* Decompresses an LZW block of data with a specified output size
|
||||
* Decompresses LZW compressed data
|
||||
*/
|
||||
Common::SeekableReadStream *decompress(Common::SeekableReadStream &source);
|
||||
|
||||
/**
|
||||
* Decompresses LZW compressed data
|
||||
*/
|
||||
Common::SeekableReadStream *decompress(Common::SeekableReadStream &source, uint32 outSize);
|
||||
|
||||
/**
|
||||
* Decompresses LZW compressed data
|
||||
*/
|
||||
void decompress(Common::SeekableReadStream &source, byte *buffer, uint32 outSize);
|
||||
|
||||
/**
|
||||
* Decompresses LZW compressed data
|
||||
*/
|
||||
static Common::SeekableReadStream *decompressLZ(Common::SeekableReadStream &source, uint32 outSize);
|
||||
|
||||
|
||||
/**
|
||||
* Decompress an LZW compressed resource
|
||||
* Decompresses LZW compressed data
|
||||
*/
|
||||
Common::SeekableReadStream *decompressLZ(Common::SeekableReadStream &source);
|
||||
static void decompressLZ(Common::SeekableReadStream &source, byte *outBuffer, int32 outSize, int32 inSize);
|
||||
};
|
||||
|
||||
struct ImageFrame {
|
||||
@ -158,6 +173,16 @@ struct ImageFrame {
|
||||
Common::Point _offset;
|
||||
byte _rleMarker;
|
||||
Graphics::Surface _frame;
|
||||
|
||||
/**
|
||||
* Return the frame width adjusted by a specified scale amount
|
||||
*/
|
||||
int sDrawXSize(int scaleVal) const;
|
||||
|
||||
/**
|
||||
* Return the frame height adjusted by a specified scale amount
|
||||
*/
|
||||
int sDrawYSize(int scaleVal) const;
|
||||
};
|
||||
|
||||
class ImageFile : public Common::Array<ImageFrame> {
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "sherlock/sherlock.h"
|
||||
#include "sherlock/music.h"
|
||||
#include "sherlock/animation.h"
|
||||
#include "engines/util.h"
|
||||
|
||||
namespace Sherlock {
|
||||
|
||||
@ -379,6 +380,9 @@ ScalpelEngine::~ScalpelEngine() {
|
||||
}
|
||||
|
||||
void ScalpelEngine::initialize() {
|
||||
initGraphics(320, 200, false);
|
||||
|
||||
// Let the base engine intialize
|
||||
SherlockEngine::initialize();
|
||||
|
||||
_darts = new Darts(this);
|
||||
@ -580,9 +584,9 @@ bool ScalpelEngine::scrollCredits() {
|
||||
_screen->transBlitFrom(creditsImages[1], Common::Point(10, 400 - idx), false, 0);
|
||||
|
||||
// Don't show credit text on the top and bottom ten rows of the screen
|
||||
_screen->blitFrom(_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, 10));
|
||||
_screen->blitFrom(_screen->_backBuffer1, Common::Point(0, SHERLOCK_SCREEN_HEIGHT - 10),
|
||||
Common::Rect(0, SHERLOCK_SCREEN_HEIGHT - 10, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
|
||||
_screen->blitFrom(_screen->_backBuffer1, Common::Point(0, 0), Common::Rect(0, 0, _screen->w(), 10));
|
||||
_screen->blitFrom(_screen->_backBuffer1, Common::Point(0, _screen->h() - 10),
|
||||
Common::Rect(0, _screen->h() - 10, _screen->w(), _screen->h()));
|
||||
|
||||
_events->delay(100);
|
||||
}
|
||||
@ -804,7 +808,6 @@ void ScalpelEngine::startScene() {
|
||||
break;
|
||||
}
|
||||
|
||||
_events->loadCursors("rmouse.vgs");
|
||||
_events->setCursor(ARROW);
|
||||
|
||||
if (_scene->_goToScene == 99) {
|
||||
@ -828,9 +831,11 @@ void ScalpelEngine::eraseMirror12() {
|
||||
|
||||
void ScalpelEngine::doMirror12() {
|
||||
People &people = *_people;
|
||||
Person &player = people._player;
|
||||
|
||||
Common::Point pt((*_people)[AL]._position.x / 100, (*_people)[AL]._position.y / 100);
|
||||
int frameNum = (*people[AL]._sequences)[people[AL]._sequenceNumber][people[AL]._frameNumber] +
|
||||
(*people[AL]._sequences)[people[AL]._sequenceNumber][0] - 2;
|
||||
int frameNum = player._walkSequences[player._sequenceNumber][player._frameNumber] +
|
||||
player._walkSequences[player._sequenceNumber][0] - 2;
|
||||
|
||||
switch ((*_people)[AL]._sequenceNumber) {
|
||||
case WALK_DOWN:
|
||||
|
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/settings.h"
|
||||
#include "sherlock/scalpel/settings.h"
|
||||
#include "sherlock/scalpel/scalpel_user_interface.h"
|
||||
|
||||
namespace Sherlock {
|
||||
|
||||
namespace Scalpel {
|
||||
|
||||
static const int SETUP_POINTS[12][4] = {
|
||||
{ 4, 154, 101, 53 }, // Exit
|
||||
{ 4, 165, 101, 53 }, // Music Toggle
|
||||
@ -212,9 +215,10 @@ void Settings::show(SherlockEngine *vm) {
|
||||
Sound &sound = *vm->_sound;
|
||||
Music &music = *vm->_music;
|
||||
Talk &talk = *vm->_talk;
|
||||
UserInterface &ui = *vm->_ui;
|
||||
ScalpelUserInterface &ui = *(ScalpelUserInterface *)vm->_ui;
|
||||
bool updateConfig = false;
|
||||
|
||||
assert(vm->getGameID() == GType_SerratedScalpel);
|
||||
Settings settings(vm);
|
||||
settings.drawInteface(false);
|
||||
|
||||
@ -332,4 +336,6 @@ void Settings::show(SherlockEngine *vm) {
|
||||
ui._key = -1;
|
||||
}
|
||||
|
||||
} // End of namespace Scalpel
|
||||
|
||||
} // End of namespace Sherlock
|
@ -28,7 +28,8 @@
|
||||
namespace Sherlock {
|
||||
|
||||
class SherlockEngine;
|
||||
class UserInterface;
|
||||
|
||||
namespace Scalpel {
|
||||
|
||||
class Settings {
|
||||
private:
|
||||
@ -55,6 +56,8 @@ public:
|
||||
static void show(SherlockEngine *vm);
|
||||
};
|
||||
|
||||
} // End of namespace Scalpel
|
||||
|
||||
} // End of namespace Sherlock
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -29,6 +29,7 @@
|
||||
#include "common/serializer.h"
|
||||
#include "sherlock/objects.h"
|
||||
#include "sherlock/resources.h"
|
||||
#include "sherlock/screen.h"
|
||||
|
||||
namespace Sherlock {
|
||||
|
||||
@ -44,12 +45,23 @@ struct BgFileHeader {
|
||||
int _numcAnimations;
|
||||
int _descSize;
|
||||
int _seqSize;
|
||||
|
||||
// Serrated Scalpel
|
||||
int _fill;
|
||||
|
||||
// Rose Tattoo
|
||||
int _scrollSize;
|
||||
int _bytesWritten; // Size of the main body of the RRM
|
||||
int _fadeStyle; // Fade style
|
||||
byte _palette[PALETTE_SIZE]; // Palette
|
||||
|
||||
|
||||
BgFileHeader();
|
||||
|
||||
/**
|
||||
* Load the data for the object
|
||||
*/
|
||||
void load(Common::SeekableReadStream &s);
|
||||
void load(Common::SeekableReadStream &s, bool isRoseTattoo);
|
||||
};
|
||||
|
||||
struct BgFileHeaderInfo {
|
||||
@ -63,18 +75,20 @@ struct BgFileHeaderInfo {
|
||||
void load(Common::SeekableReadStream &s);
|
||||
};
|
||||
|
||||
struct Exit {
|
||||
Common::Rect _bounds;
|
||||
|
||||
class Exit: public Common::Rect {
|
||||
public:
|
||||
int _scene;
|
||||
int _allow;
|
||||
Common::Point _people;
|
||||
int _peopleDir;
|
||||
|
||||
Common::String _dest;
|
||||
int _image; // Arrow image to use
|
||||
|
||||
/**
|
||||
* Load the data for the object
|
||||
*/
|
||||
void load(Common::SeekableReadStream &s);
|
||||
void load(Common::SeekableReadStream &s, bool isRoseTattoo);
|
||||
};
|
||||
|
||||
struct SceneEntry {
|
||||
@ -106,9 +120,26 @@ public:
|
||||
int indexOf(const Object &obj) const;
|
||||
};
|
||||
|
||||
class ScaleZone: public Common::Rect {
|
||||
public:
|
||||
int _topNumber; // Numerator of scale size at the top of the zone
|
||||
int _bottomNumber; // Numerator of scale size at the bottom of the zone
|
||||
|
||||
void load(Common::SeekableReadStream &s);
|
||||
};
|
||||
|
||||
struct SceneTripEntry {
|
||||
bool _flag;
|
||||
int _sceneNumber;
|
||||
int _numTimes;
|
||||
|
||||
SceneTripEntry() : _flag(false), _sceneNumber(0), _numTimes(0) {}
|
||||
SceneTripEntry(bool flag, int sceneNumber, int numTimes) : _flag(flag),
|
||||
_sceneNumber(sceneNumber), _numTimes(numTimes) {}
|
||||
};
|
||||
|
||||
class Scene {
|
||||
private:
|
||||
SherlockEngine *_vm;
|
||||
Common::String _rrmName;
|
||||
bool _loadingSavedGame;
|
||||
|
||||
@ -123,6 +154,11 @@ private:
|
||||
*/
|
||||
bool loadScene(const Common::String &filename);
|
||||
|
||||
/**
|
||||
* Loads sounds for the scene
|
||||
*/
|
||||
void loadSceneSounds();
|
||||
|
||||
/**
|
||||
* Set objects to their current persistent state. This includes things such as
|
||||
* opening or moving them
|
||||
@ -142,18 +178,27 @@ private:
|
||||
*/
|
||||
void transitionToScene();
|
||||
|
||||
/**
|
||||
* Checks all the background shapes. If a background shape is animating,
|
||||
* it will flag it as needing to be drawn. If a non-animating shape is
|
||||
* colliding with another shape, it will also flag it as needing drawing
|
||||
*/
|
||||
void checkBgShapes(ImageFrame *frame, const Common::Point &pt);
|
||||
|
||||
/**
|
||||
* Restores objects to the correct status. This ensures that things like being opened or moved
|
||||
* will remain the same on future visits to the scene
|
||||
*/
|
||||
void saveSceneStatus();
|
||||
protected:
|
||||
SherlockEngine *_vm;
|
||||
|
||||
/**
|
||||
* Checks all the background shapes. If a background shape is animating,
|
||||
* it will flag it as needing to be drawn. If a non-animating shape is
|
||||
* colliding with another shape, it will also flag it as needing drawing
|
||||
*/
|
||||
virtual void checkBgShapes();
|
||||
|
||||
/**
|
||||
* Draw all the shapes, people and NPCs in the correct order
|
||||
*/
|
||||
void drawAllShapes();
|
||||
|
||||
Scene(SherlockEngine *vm);
|
||||
public:
|
||||
int _currentScene;
|
||||
int _goToScene;
|
||||
@ -173,17 +218,21 @@ public:
|
||||
int _walkDirectory[MAX_ZONES][MAX_ZONES];
|
||||
Common::Array<byte> _walkData;
|
||||
Common::Array<Exit> _exits;
|
||||
int _exitZone;
|
||||
SceneEntry _entrance;
|
||||
Common::Array<SceneSound> _sounds;
|
||||
ObjectArray _canimShapes;
|
||||
Common::Array<ScaleZone> _scaleZones;
|
||||
Common::StringArray _objSoundList;
|
||||
bool _restoreFlag;
|
||||
int _animating;
|
||||
bool _doBgAnimDone;
|
||||
int _tempFadeStyle;
|
||||
int _cAnimFramePause;
|
||||
Common::Array<SceneTripEntry> _sceneTripCounters;
|
||||
public:
|
||||
Scene(SherlockEngine *vm);
|
||||
~Scene();
|
||||
static Scene *init(SherlockEngine *vm);
|
||||
virtual ~Scene();
|
||||
|
||||
/**
|
||||
* Handles loading the scene specified by _goToScene
|
||||
@ -223,11 +272,6 @@ public:
|
||||
*/
|
||||
int toggleObject(const Common::String &name);
|
||||
|
||||
/**
|
||||
* Animate all objects and people.
|
||||
*/
|
||||
void doBgAnim();
|
||||
|
||||
/**
|
||||
* Attempts to find a background shape within the passed bounds. If found,
|
||||
* it will return the shape number, or -1 on failure.
|
||||
@ -250,16 +294,28 @@ public:
|
||||
*/
|
||||
int closestZone(const Common::Point &pt);
|
||||
|
||||
/**
|
||||
* Update the screen back buffer with all of the scene objects which need
|
||||
* to be drawn
|
||||
*/
|
||||
void updateBackground();
|
||||
|
||||
/**
|
||||
* Synchronize the data for a savegame
|
||||
*/
|
||||
void synchronize(Common::Serializer &s);
|
||||
|
||||
/**
|
||||
* Resets the NPC path information when entering a new scene.
|
||||
* @remarks The default talk file for the given NPC is set to WATS##A, where ## is
|
||||
* the scene number being entered
|
||||
*/
|
||||
void setNPCPath(int npc);
|
||||
public:
|
||||
/**
|
||||
* Draw all objects and characters.
|
||||
*/
|
||||
virtual void doBgAnim() = 0;
|
||||
|
||||
/**
|
||||
* Update the screen back buffer with all of the scene objects which need
|
||||
* to be drawn
|
||||
*/
|
||||
virtual void updateBackground();
|
||||
};
|
||||
|
||||
} // End of namespace Sherlock
|
||||
|
@ -28,9 +28,9 @@
|
||||
|
||||
namespace Sherlock {
|
||||
|
||||
Screen::Screen(SherlockEngine *vm) : Surface(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT), _vm(vm),
|
||||
_backBuffer1(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT),
|
||||
_backBuffer2(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT),
|
||||
Screen::Screen(SherlockEngine *vm) : Surface(g_system->getWidth(), g_system->getHeight()), _vm(vm),
|
||||
_backBuffer1(g_system->getWidth(), g_system->getHeight()),
|
||||
_backBuffer2(g_system->getWidth(), g_system->getHeight()),
|
||||
_backBuffer(&_backBuffer1) {
|
||||
_transitionSeed = 1;
|
||||
_fadeStyle = false;
|
||||
@ -38,7 +38,17 @@ Screen::Screen(SherlockEngine *vm) : Surface(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCR
|
||||
_fontHeight = 0;
|
||||
Common::fill(&_cMap[0], &_cMap[PALETTE_SIZE], 0);
|
||||
Common::fill(&_sMap[0], &_sMap[PALETTE_SIZE], 0);
|
||||
setFont(1);
|
||||
Common::fill(&_tMap[0], &_tMap[PALETTE_SIZE], 0);
|
||||
setFont(IS_SERRATED_SCALPEL ? 1 : 4);
|
||||
|
||||
// Rose Tattoo specific fields
|
||||
_fadeBytesRead = _fadeBytesToRead = 0;
|
||||
_oldFadePercent = 0;
|
||||
_scrollSize = 0;
|
||||
_scrollSpeed = 0;
|
||||
_currentScroll = 0;
|
||||
_targetScroll = 0;
|
||||
_flushScreen = false;
|
||||
}
|
||||
|
||||
Screen::~Screen() {
|
||||
@ -174,12 +184,13 @@ void Screen::randomTransition() {
|
||||
Events &events = *_vm->_events;
|
||||
const int TRANSITION_MULTIPLIER = 0x15a4e35;
|
||||
_dirtyRects.clear();
|
||||
assert(IS_SERRATED_SCALPEL);
|
||||
|
||||
for (int idx = 0; idx <= 65535 && !_vm->shouldQuit(); ++idx) {
|
||||
_transitionSeed = _transitionSeed * TRANSITION_MULTIPLIER + 1;
|
||||
int offset = _transitionSeed & 0xFFFF;
|
||||
|
||||
if (offset < (SHERLOCK_SCREEN_WIDTH * SHERLOCK_SCREEN_HEIGHT))
|
||||
if (offset < (this->w() * this->h()))
|
||||
*((byte *)getPixels() + offset) = *((const byte *)_backBuffer->getPixels() + offset);
|
||||
|
||||
if (idx != 0 && (idx % 300) == 0) {
|
||||
@ -199,12 +210,12 @@ void Screen::randomTransition() {
|
||||
void Screen::verticalTransition() {
|
||||
Events &events = *_vm->_events;
|
||||
|
||||
byte table[SHERLOCK_SCREEN_WIDTH];
|
||||
Common::fill(&table[0], &table[SHERLOCK_SCREEN_WIDTH], 0);
|
||||
byte table[640];
|
||||
Common::fill(&table[0], &table[640], 0);
|
||||
|
||||
for (int yp = 0; yp < SHERLOCK_SCREEN_HEIGHT; ++yp) {
|
||||
for (int xp = 0; xp < SHERLOCK_SCREEN_WIDTH; ++xp) {
|
||||
int temp = (table[xp] >= 197) ? SHERLOCK_SCREEN_HEIGHT - table[xp] :
|
||||
for (int yp = 0; yp < this->h(); ++yp) {
|
||||
for (int xp = 0; xp < this->w(); ++xp) {
|
||||
int temp = (table[xp] >= (this->h() - 3)) ? this->h() - table[xp] :
|
||||
_vm->getRandomNumber(3) + 1;
|
||||
|
||||
if (temp) {
|
||||
@ -221,7 +232,7 @@ void Screen::verticalTransition() {
|
||||
void Screen::restoreBackground(const Common::Rect &r) {
|
||||
if (r.width() > 0 && r.height() > 0) {
|
||||
Common::Rect tempRect = r;
|
||||
tempRect.clip(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCENE_HEIGHT));
|
||||
tempRect.clip(Common::Rect(0, 0, this->w(), SHERLOCK_SCENE_HEIGHT));
|
||||
|
||||
if (tempRect.isValidRect())
|
||||
_backBuffer1.blitFrom(_backBuffer2, Common::Point(tempRect.left, tempRect.top), tempRect);
|
||||
@ -235,31 +246,62 @@ void Screen::slamArea(int16 xp, int16 yp, int16 width, int16 height) {
|
||||
void Screen::slamRect(const Common::Rect &r) {
|
||||
if (r.width() && r.height() > 0) {
|
||||
Common::Rect tempRect = r;
|
||||
tempRect.clip(Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT));
|
||||
tempRect.clip(Common::Rect(0, 0, this->w(), this->h()));
|
||||
|
||||
if (tempRect.isValidRect())
|
||||
blitFrom(*_backBuffer, Common::Point(tempRect.left, tempRect.top), tempRect);
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::flushImage(ImageFrame *frame, const Common::Point &pt,
|
||||
int16 *xp, int16 *yp, int16 *width, int16 *height) {
|
||||
void Screen::flushImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp,
|
||||
int16 *width, int16 *height) {
|
||||
Common::Point imgPos = pt + frame->_offset;
|
||||
Common::Rect newBounds(imgPos.x, imgPos.y, imgPos.x + frame->_frame.w, imgPos.y + frame->_frame.h);
|
||||
Common::Rect oldBounds(*xp, *yp, *xp + *width, *yp + *height);
|
||||
|
||||
// See if the areas of the old and new overlap, and if so combine the areas
|
||||
if (newBounds.intersects(oldBounds)) {
|
||||
Common::Rect mergedBounds = newBounds;
|
||||
mergedBounds.extend(oldBounds);
|
||||
mergedBounds.right += 1;
|
||||
mergedBounds.bottom += 1;
|
||||
if (!_flushScreen) {
|
||||
// See if the areas of the old and new overlap, and if so combine the areas
|
||||
if (newBounds.intersects(oldBounds)) {
|
||||
Common::Rect mergedBounds = newBounds;
|
||||
mergedBounds.extend(oldBounds);
|
||||
mergedBounds.right += 1;
|
||||
mergedBounds.bottom += 1;
|
||||
|
||||
slamRect(mergedBounds);
|
||||
} else {
|
||||
// The two areas are independent, so copy them both
|
||||
slamRect(newBounds);
|
||||
slamRect(oldBounds);
|
||||
slamRect(mergedBounds);
|
||||
} else {
|
||||
// The two areas are independent, so copy them both
|
||||
slamRect(newBounds);
|
||||
slamRect(oldBounds);
|
||||
}
|
||||
}
|
||||
|
||||
*xp = newBounds.left;
|
||||
*yp = newBounds.top;
|
||||
*width = newBounds.width();
|
||||
*height = newBounds.height();
|
||||
}
|
||||
|
||||
void Screen::flushScaleImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp,
|
||||
int16 *width, int16 *height, int scaleVal) {
|
||||
Common::Point imgPos = pt + frame->_offset;
|
||||
Common::Rect newBounds(imgPos.x, imgPos.y, imgPos.x + frame->sDrawXSize(scaleVal),
|
||||
imgPos.y + frame->sDrawYSize(scaleVal));
|
||||
Common::Rect oldBounds(*xp, *yp, *xp + *width, *yp + *height);
|
||||
|
||||
if (!_flushScreen) {
|
||||
// See if the areas of the old and new overlap, and if so combine the areas
|
||||
if (newBounds.intersects(oldBounds)) {
|
||||
Common::Rect mergedBounds = newBounds;
|
||||
mergedBounds.extend(oldBounds);
|
||||
mergedBounds.right += 1;
|
||||
mergedBounds.bottom += 1;
|
||||
|
||||
slamRect(mergedBounds);
|
||||
} else {
|
||||
// The two areas are independent, so copy them both
|
||||
slamRect(newBounds);
|
||||
slamRect(oldBounds);
|
||||
}
|
||||
}
|
||||
|
||||
*xp = newBounds.left;
|
||||
@ -281,13 +323,13 @@ void Screen::print(const Common::Point &pt, byte color, const char *formatStr, .
|
||||
pos.y--; // Font is always drawing one line higher
|
||||
if (!pos.x)
|
||||
// Center text horizontally
|
||||
pos.x = (SHERLOCK_SCREEN_WIDTH - width) / 2;
|
||||
pos.x = (this->w() - width) / 2;
|
||||
|
||||
Common::Rect textBounds(pos.x, pos.y, pos.x + width, pos.y + _fontHeight);
|
||||
if (textBounds.right > SHERLOCK_SCREEN_WIDTH)
|
||||
textBounds.moveTo(SHERLOCK_SCREEN_WIDTH - width, textBounds.top);
|
||||
if (textBounds.bottom > SHERLOCK_SCREEN_HEIGHT)
|
||||
textBounds.moveTo(textBounds.left, SHERLOCK_SCREEN_HEIGHT - _fontHeight);
|
||||
if (textBounds.right > this->w())
|
||||
textBounds.moveTo(this->w() - width, textBounds.top);
|
||||
if (textBounds.bottom > this->h())
|
||||
textBounds.moveTo(textBounds.left, this->h() - _fontHeight);
|
||||
|
||||
// Write out the string at the given position
|
||||
writeString(str, Common::Point(textBounds.left, textBounds.top), color);
|
||||
@ -416,7 +458,7 @@ void Screen::resetDisplayBounds() {
|
||||
|
||||
Common::Rect Screen::getDisplayBounds() {
|
||||
return (_backBuffer == &_sceneSurface) ? Common::Rect(0, 0, _sceneSurface.w(), _sceneSurface.h()) :
|
||||
Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT);
|
||||
Common::Rect(0, 0, this->w(), this->h());
|
||||
}
|
||||
|
||||
void Screen::synchronize(Common::Serializer &s) {
|
||||
@ -426,4 +468,41 @@ void Screen::synchronize(Common::Serializer &s) {
|
||||
setFont(fontNumb);
|
||||
}
|
||||
|
||||
void Screen::initPaletteFade(int bytesToRead) {
|
||||
Common::copy(&_cMap[0], &_cMap[PALETTE_SIZE], &_sMap[0]);
|
||||
Common::copy(&_cMap[0], &_cMap[PALETTE_SIZE], &_tMap[0]);
|
||||
|
||||
// Set how many bytes need to be read / have been read
|
||||
_fadeBytesRead = 0;
|
||||
_fadeBytesToRead = bytesToRead;
|
||||
_oldFadePercent = 0;
|
||||
}
|
||||
|
||||
int Screen::fadeRead(Common::SeekableReadStream &stream, byte *buf, int totalSize) {
|
||||
warning("TODO: fadeRead");
|
||||
stream.read(buf, totalSize);
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a grey-scale version of the passed palette
|
||||
*/
|
||||
void Screen::setupBGArea(const byte cMap[PALETTE_SIZE]) {
|
||||
warning("TODO");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes scroll variables
|
||||
*/
|
||||
void Screen::initScrollVars() {
|
||||
_scrollSize = 0;
|
||||
_currentScroll = 0;
|
||||
_targetScroll = 0;
|
||||
}
|
||||
|
||||
void Screen::translatePalette(byte palette[PALETTE_SIZE]) {
|
||||
for (int idx = 0; idx < PALETTE_SIZE; ++idx)
|
||||
palette[idx] = VGA_COLOR_TRANS(palette[idx]);
|
||||
}
|
||||
|
||||
} // End of namespace Sherlock
|
||||
|
@ -66,6 +66,12 @@ private:
|
||||
int _fontHeight;
|
||||
Surface _sceneSurface;
|
||||
|
||||
// Rose Tattoo fields
|
||||
int _fadeBytesRead, _fadeBytesToRead;
|
||||
int _oldFadePercent;
|
||||
byte _lookupTable[PALETTE_COUNT];
|
||||
byte _lookupTable1[PALETTE_COUNT];
|
||||
private:
|
||||
/**
|
||||
* Merges together overlapping dirty areas of the screen
|
||||
*/
|
||||
@ -92,6 +98,10 @@ public:
|
||||
bool _fadeStyle;
|
||||
byte _cMap[PALETTE_SIZE];
|
||||
byte _sMap[PALETTE_SIZE];
|
||||
byte _tMap[PALETTE_SIZE];
|
||||
int _currentScroll, _targetScroll;
|
||||
int _scrollSize, _scrollSpeed;
|
||||
bool _flushScreen;
|
||||
public:
|
||||
Screen(SherlockEngine *vm);
|
||||
virtual ~Screen();
|
||||
@ -171,8 +181,15 @@ public:
|
||||
* Copy an image from the back buffer to the screen, taking care of both the
|
||||
* new area covered by the shape as well as the old area, which must be restored
|
||||
*/
|
||||
void flushImage(ImageFrame *frame, const Common::Point &pt,
|
||||
int16 *xp, int16 *yp, int16 *width, int16 *height);
|
||||
void flushImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp,
|
||||
int16 *width, int16 *height);
|
||||
|
||||
/**
|
||||
* Similar to flushImage, this method takes in an extra parameter for the scale proporation,
|
||||
* which affects the calculated bounds accordingly
|
||||
*/
|
||||
void flushScaleImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp,
|
||||
int16 *width, int16 *height, int scaleVal);
|
||||
|
||||
/**
|
||||
* Returns the width of a string in pixels
|
||||
@ -232,6 +249,21 @@ public:
|
||||
* Synchronize the data for a savegame
|
||||
*/
|
||||
void synchronize(Common::Serializer &s);
|
||||
|
||||
// Rose Tattoo specific methods
|
||||
void initPaletteFade(int bytesToRead);
|
||||
|
||||
int fadeRead(Common::SeekableReadStream &stream, byte *buf, int totalSize);
|
||||
|
||||
void setupBGArea(const byte cMap[PALETTE_SIZE]);
|
||||
|
||||
void initScrollVars();
|
||||
|
||||
/**
|
||||
* Translate a palette from 6-bit RGB values to full 8-bit values suitable for passing
|
||||
* to the underlying palette manager
|
||||
*/
|
||||
static void translatePalette(byte palette[PALETTE_SIZE]);
|
||||
};
|
||||
|
||||
} // End of namespace Sherlock
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "common/scummsys.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/debug-channels.h"
|
||||
#include "engines/util.h"
|
||||
|
||||
namespace Sherlock {
|
||||
|
||||
@ -72,8 +71,6 @@ SherlockEngine::~SherlockEngine() {
|
||||
}
|
||||
|
||||
void SherlockEngine::initialize() {
|
||||
initGraphics(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT, false);
|
||||
|
||||
DebugMan.addDebugChannel(kDebugScript, "scripts", "Script debug level");
|
||||
|
||||
ImageFile::setVm(this);
|
||||
@ -98,11 +95,11 @@ void SherlockEngine::initialize() {
|
||||
_journal = new Journal(this);
|
||||
_people = new People(this);
|
||||
_saves = new SaveManager(this, _targetName);
|
||||
_scene = new Scene(this);
|
||||
_scene = Scene::init(this);
|
||||
_screen = new Screen(this);
|
||||
_sound = new Sound(this, _mixer);
|
||||
_talk = new Talk(this);
|
||||
_ui = new UserInterface(this);
|
||||
_talk = Talk::init(this);
|
||||
_ui = UserInterface::init(this);
|
||||
|
||||
// Load game settings
|
||||
loadConfig();
|
||||
@ -213,7 +210,9 @@ void SherlockEngine::loadConfig() {
|
||||
ConfMan.registerDefault("font", 1);
|
||||
|
||||
_screen->setFont(ConfMan.getInt("font"));
|
||||
_screen->_fadeStyle = ConfMan.getBool("fade_style");
|
||||
if (getGameID() == GType_SerratedScalpel)
|
||||
_screen->_fadeStyle = ConfMan.getBool("fade_style");
|
||||
|
||||
_ui->_helpStyle = ConfMan.getBool("help_style");
|
||||
_ui->_slideWindows = ConfMan.getBool("window_style");
|
||||
_people->_portraitsOn = ConfMan.getBool("portraits_on");
|
||||
|
@ -59,9 +59,9 @@ enum GameType {
|
||||
GType_RoseTattoo = 1
|
||||
};
|
||||
|
||||
#define SHERLOCK_SCREEN_WIDTH 320
|
||||
#define SHERLOCK_SCREEN_HEIGHT 200
|
||||
#define SHERLOCK_SCENE_HEIGHT 138
|
||||
#define SHERLOCK_SCREEN_WIDTH _vm->_screen->w()
|
||||
#define SHERLOCK_SCREEN_HEIGHT _vm->_screen->h()
|
||||
#define SHERLOCK_SCENE_HEIGHT (IS_SERRATED_SCALPEL ? 138 : 480)
|
||||
|
||||
struct SherlockGameDescription;
|
||||
|
||||
@ -199,6 +199,9 @@ public:
|
||||
void synchronize(Common::Serializer &s);
|
||||
};
|
||||
|
||||
#define IS_ROSE_TATTOO (_vm->getGameID() == GType_RoseTattoo)
|
||||
#define IS_SERRATED_SCALPEL (_vm->getGameID() == GType_SerratedScalpel)
|
||||
|
||||
} // End of namespace Sherlock
|
||||
|
||||
#endif
|
||||
|
@ -58,18 +58,27 @@ Sound::Sound(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
|
||||
_soundIsOn = &_soundPlaying;
|
||||
_curPriority = 0;
|
||||
_digiBuf = nullptr;
|
||||
_midiDrvLoaded = false;
|
||||
_musicVolume = 0;
|
||||
|
||||
_soundOn = true;
|
||||
_speechOn = true;
|
||||
|
||||
_vm->_res->addToCache("MUSIC.LIB");
|
||||
if (!_vm->_interactiveFl)
|
||||
_vm->_res->addToCache("TITLE.SND");
|
||||
else {
|
||||
_vm->_res->addToCache("SND.SND");
|
||||
_vm->_res->addToCache("MUSIC.LIB");
|
||||
|
||||
if (IS_ROSE_TATTOO) {
|
||||
_vm->_res->addToCache("SOUND.LIB");
|
||||
} else {
|
||||
_vm->_res->addToCache("SND.SND");
|
||||
|
||||
if (!_vm->isDemo()) {
|
||||
_vm->_res->addToCache("TITLE.SND");
|
||||
_vm->_res->addToCache("EPILOGUE.SND");
|
||||
if (!_vm->isDemo()) {
|
||||
_vm->_res->addToCache("TITLE.SND");
|
||||
_vm->_res->addToCache("EPILOGUE.SND");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -210,5 +219,9 @@ void Sound::freeDigiSound() {
|
||||
_soundPlaying = false;
|
||||
}
|
||||
|
||||
void Sound::setMIDIVolume(int volume) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
} // End of namespace Sherlock
|
||||
|
||||
|
@ -56,6 +56,9 @@ public:
|
||||
bool _soundPlaying;
|
||||
bool *_soundIsOn;
|
||||
byte *_digiBuf;
|
||||
bool _midiDrvLoaded;
|
||||
Common::String _currentSongName, _nextSongName;
|
||||
int _musicVolume;
|
||||
public:
|
||||
Sound(SherlockEngine *vm, Audio::Mixer *mixer);
|
||||
|
||||
@ -91,6 +94,7 @@ public:
|
||||
|
||||
void stopSndFuncPtr(int v1, int v2);
|
||||
void freeDigiSound();
|
||||
void setMIDIVolume(int volume);
|
||||
};
|
||||
|
||||
} // End of namespace Sherlock
|
||||
|
@ -96,6 +96,12 @@ void Surface::transBlitFrom(const ImageFrame &src, const Common::Point &pt,
|
||||
transBlitFrom(src._frame, pt + src._offset, flipped, overrideColor);
|
||||
}
|
||||
|
||||
void Surface::transBlitFrom(const Surface &src, const Common::Point &pt,
|
||||
bool flipped, int overrideColor) {
|
||||
const Graphics::Surface &s = src._surface;
|
||||
transBlitFrom(s, pt, flipped, overrideColor);
|
||||
}
|
||||
|
||||
void Surface::transBlitFrom(const Graphics::Surface &src, const Common::Point &pt,
|
||||
bool flipped, int overrideColor) {
|
||||
Common::Rect drawRect(0, 0, src.w, src.h);
|
||||
@ -186,4 +192,10 @@ void Surface::setPixels(byte *pixels, int width, int height) {
|
||||
_surface.setPixels(pixels);
|
||||
}
|
||||
|
||||
void Surface::maskArea(const ImageFrame &src, const Common::Point &pt, int scrollX) {
|
||||
// TODO
|
||||
error("TODO: maskArea");
|
||||
}
|
||||
|
||||
|
||||
} // End of namespace Sherlock
|
||||
|
@ -126,6 +126,8 @@ public:
|
||||
*/
|
||||
void fillRect(const Common::Rect &r, byte color);
|
||||
|
||||
void maskArea(const ImageFrame &src, const Common::Point &pt, int scrollX);
|
||||
|
||||
/**
|
||||
* Clear the screen
|
||||
*/
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -36,42 +36,83 @@ namespace Sherlock {
|
||||
#define MAX_TALK_FILES 500
|
||||
|
||||
enum {
|
||||
SWITCH_SPEAKER = 128,
|
||||
RUN_CANIMATION = 129,
|
||||
ASSIGN_PORTRAIT_LOCATION = 130,
|
||||
PAUSE = 131,
|
||||
REMOVE_PORTRAIT = 132,
|
||||
CLEAR_WINDOW = 133,
|
||||
ADJUST_OBJ_SEQUENCE = 134,
|
||||
WALK_TO_COORDS = 135,
|
||||
PAUSE_WITHOUT_CONTROL = 136,
|
||||
BANISH_WINDOW = 137,
|
||||
SUMMON_WINDOW = 138,
|
||||
SET_FLAG = 139,
|
||||
SFX_COMMAND = 140,
|
||||
TOGGLE_OBJECT = 141,
|
||||
STEALTH_MODE_ACTIVE = 142,
|
||||
IF_STATEMENT = 143,
|
||||
ELSE_STATEMENT = 144,
|
||||
END_IF_STATEMENT = 145,
|
||||
STEALTH_MODE_DEACTIVATE = 146,
|
||||
TURN_HOLMES_OFF = 147,
|
||||
TURN_HOLMES_ON = 148,
|
||||
GOTO_SCENE = 149,
|
||||
PLAY_PROLOGUE = 150,
|
||||
ADD_ITEM_TO_INVENTORY = 151,
|
||||
SET_OBJECT = 152,
|
||||
CALL_TALK_FILE = 153,
|
||||
MOVE_MOUSE = 154,
|
||||
DISPLAY_INFO_LINE = 155,
|
||||
CLEAR_INFO_LINE = 156,
|
||||
WALK_TO_CANIMATION = 157,
|
||||
REMOVE_ITEM_FROM_INVENTORY = 158,
|
||||
ENABLE_END_KEY = 159,
|
||||
DISABLE_END_KEY = 160,
|
||||
CARRIAGE_RETURN = 161
|
||||
OP_SWITCH_SPEAKER = 0,
|
||||
OP_RUN_CANIMATION = 1,
|
||||
OP_ASSIGN_PORTRAIT_LOCATION = 2,
|
||||
OP_PAUSE = 3,
|
||||
OP_REMOVE_PORTRAIT = 4,
|
||||
OP_CLEAR_WINDOW = 5,
|
||||
OP_ADJUST_OBJ_SEQUENCE = 6,
|
||||
OP_WALK_TO_COORDS = 7,
|
||||
OP_PAUSE_WITHOUT_CONTROL = 8,
|
||||
OP_BANISH_WINDOW = 9,
|
||||
OP_SUMMON_WINDOW = 10,
|
||||
OP_SET_FLAG = 11,
|
||||
OP_SFX_COMMAND = 12,
|
||||
OP_TOGGLE_OBJECT = 13,
|
||||
OP_STEALTH_MODE_ACTIVE = 14,
|
||||
OP_IF_STATEMENT = 15,
|
||||
OP_ELSE_STATEMENT = 16,
|
||||
OP_END_IF_STATEMENT = 17,
|
||||
OP_STEALTH_MODE_DEACTIVATE = 18,
|
||||
OP_TURN_HOLMES_OFF = 19,
|
||||
OP_TURN_HOLMES_ON = 20,
|
||||
OP_GOTO_SCENE = 21,
|
||||
OP_PLAY_PROLOGUE = 22,
|
||||
OP_ADD_ITEM_TO_INVENTORY = 23,
|
||||
OP_SET_OBJECT = 24,
|
||||
OP_CALL_TALK_FILE = 25,
|
||||
OP_MOVE_MOUSE = 26,
|
||||
OP_DISPLAY_INFO_LINE = 27,
|
||||
OP_CLEAR_INFO_LINE = 28,
|
||||
OP_WALK_TO_CANIMATION = 29,
|
||||
OP_REMOVE_ITEM_FROM_INVENTORY = 30,
|
||||
OP_ENABLE_END_KEY = 31,
|
||||
OP_DISABLE_END_KEY = 32,
|
||||
OP_CARRIAGE_RETURN = 33,
|
||||
|
||||
OP_MOUSE_OFF_ON = 34,
|
||||
OP_SET_WALK_CONTROL = 35,
|
||||
OP_SET_TALK_SEQUENCE = 36,
|
||||
OP_PLAY_SONG = 37,
|
||||
OP_WALK_HOLMES_AND_NPC_TO_CANIM = 38,
|
||||
OP_SET_NPC_PATH_DEST = 39,
|
||||
OP_NEXT_SONG = 40,
|
||||
OP_SET_NPC_PATH_PAUSE = 41,
|
||||
OP_NEED_PASSWORD = 42,
|
||||
OP_SET_SCENE_ENTRY_FLAG = 43,
|
||||
OP_WALK_NPC_TO_CANIM = 44,
|
||||
OP_WALK_HOLMES_AND_NPC_TO_COORDS = 45,
|
||||
OP_SET_NPC_TALK_FILE = 46,
|
||||
OP_TURN_NPC_OFF = 47,
|
||||
OP_TURN_NPC_ON = 48,
|
||||
OP_NPC_DESC_ON_OFF = 49,
|
||||
OP_NPC_PATH_PAUSE_TAKING_NOTES = 50,
|
||||
OP_NPC_PATH_PAUSE_LOOKING_HOLMES = 51,
|
||||
OP_ENABLE_TALK_INTERRUPTS = 52,
|
||||
OP_DISABLE_TALK_INTERRUPTS = 53,
|
||||
OP_SET_NPC_INFO_LINE = 54,
|
||||
OP_SET_NPC_POSITION = 54,
|
||||
OP_NPC_PATH_LABEL = 55,
|
||||
OP_PATH_GOTO_LABEL = 56,
|
||||
OP_PATH_IF_FLAG_GOTO_LABEL = 57,
|
||||
OP_NPC_WALK_GRAPHICS = 58,
|
||||
OP_NPC_VERB = 59,
|
||||
OP_NPC_VERB_CANIM = 60,
|
||||
OP_NPC_VERB_SCRIPT = 61,
|
||||
OP_RESTORE_PEOPLE_SEQUENCE = 62,
|
||||
OP_NPC_VERB_TARGET = 63,
|
||||
OP_TURN_SOUNDS_OFF = 64
|
||||
};
|
||||
|
||||
enum OpcodeReturn { RET_EXIT = -1, RET_SUCCESS = 0, RET_CONTINUE = 1 };
|
||||
|
||||
class SherlockEngine;
|
||||
class Talk;
|
||||
namespace Scalpel { class ScalpelUserInterface; };
|
||||
|
||||
typedef OpcodeReturn(Talk::*OpcodeMethod)(const byte *&str);
|
||||
|
||||
struct SequenceEntry {
|
||||
int _objNum;
|
||||
Common::Array<byte> _sequences;
|
||||
@ -122,24 +163,8 @@ struct TalkSequences {
|
||||
void clear();
|
||||
};
|
||||
|
||||
class SherlockEngine;
|
||||
class UserInterface;
|
||||
|
||||
class Talk {
|
||||
friend class UserInterface;
|
||||
private:
|
||||
SherlockEngine *_vm;
|
||||
Common::Stack<SequenceEntry> _savedSequences;
|
||||
Common::Stack<SequenceEntry> _sequenceStack;
|
||||
Common::Stack<ScriptStackEntry> _scriptStack;
|
||||
Common::Array<Statement> _statements;
|
||||
TalkHistoryEntry _talkHistory[MAX_TALK_FILES];
|
||||
int _speaker;
|
||||
int _talkIndex;
|
||||
int _scriptSelect;
|
||||
int _talkStealth;
|
||||
int _talkToFlag;
|
||||
int _scriptSaveIndex;
|
||||
friend class Scalpel::ScalpelUserInterface;
|
||||
private:
|
||||
/**
|
||||
* Remove any voice commands from a loaded statement list
|
||||
@ -173,6 +198,55 @@ private:
|
||||
* the amount of text that's been displayed
|
||||
*/
|
||||
int waitForMore(int delay);
|
||||
protected:
|
||||
SherlockEngine *_vm;
|
||||
OpcodeMethod *_opcodeTable;
|
||||
Common::Stack<SequenceEntry> _savedSequences;
|
||||
Common::Stack<SequenceEntry> _sequenceStack;
|
||||
Common::Stack<ScriptStackEntry> _scriptStack;
|
||||
Common::Array<Statement> _statements;
|
||||
TalkHistoryEntry _talkHistory[MAX_TALK_FILES];
|
||||
int _speaker;
|
||||
int _talkIndex;
|
||||
int _scriptSelect;
|
||||
int _talkStealth;
|
||||
int _talkToFlag;
|
||||
int _scriptSaveIndex;
|
||||
|
||||
// These fields are used solely by doScript, but are fields because all the script opcodes are
|
||||
// separate methods now, and need access to these fields
|
||||
int _yp;
|
||||
int _charCount;
|
||||
int _line;
|
||||
int _wait;
|
||||
bool _pauseFlag;
|
||||
bool _endStr, _noTextYet;
|
||||
int _seqCount;
|
||||
const byte *_scriptStart, *_scriptEnd;
|
||||
protected:
|
||||
Talk(SherlockEngine *vm);
|
||||
|
||||
OpcodeReturn cmdAddItemToInventory(const byte *&str);
|
||||
OpcodeReturn cmdAdjustObjectSequence(const byte *&str);
|
||||
OpcodeReturn cmdBanishWindow(const byte *&str);
|
||||
OpcodeReturn cmdCallTalkFile(const byte *&str);
|
||||
OpcodeReturn cmdDisableEndKey(const byte *&str);
|
||||
OpcodeReturn cmdEnableEndKey(const byte *&str);
|
||||
OpcodeReturn cmdGotoScene(const byte *&str);
|
||||
OpcodeReturn cmdHolmesOff(const byte *&str);
|
||||
OpcodeReturn cmdHolmesOn(const byte *&str);
|
||||
OpcodeReturn cmdPause(const byte *&str);
|
||||
OpcodeReturn cmdPauseWithoutControl(const byte *&str);
|
||||
OpcodeReturn cmdRemoveItemFromInventory(const byte *&str);
|
||||
OpcodeReturn cmdRunCAnimation(const byte *&str);
|
||||
OpcodeReturn cmdSetFlag(const byte *&str);
|
||||
OpcodeReturn cmdSetObject(const byte *&str);
|
||||
OpcodeReturn cmdStealthModeActivate(const byte *&str);
|
||||
OpcodeReturn cmdStealthModeDeactivate(const byte *&str);
|
||||
OpcodeReturn cmdSwitchSpeaker(const byte *&str);
|
||||
OpcodeReturn cmdToggleObject(const byte *&str);
|
||||
OpcodeReturn cmdWalkToCAnimation(const byte *&str);
|
||||
OpcodeReturn cmdWalkToCoords(const byte *&str);
|
||||
public:
|
||||
bool _talkToAbort;
|
||||
int _talkCounter;
|
||||
@ -181,8 +255,11 @@ public:
|
||||
Common::String _scriptName;
|
||||
bool _moreTalkUp, _moreTalkDown;
|
||||
int _converseNum;
|
||||
const byte *_opcodes;
|
||||
|
||||
public:
|
||||
Talk(SherlockEngine *vm);
|
||||
static Talk *init(SherlockEngine *vm);
|
||||
virtual ~Talk() {}
|
||||
|
||||
/**
|
||||
* Return a given talk statement
|
||||
@ -267,6 +344,65 @@ public:
|
||||
void synchronize(Common::Serializer &s);
|
||||
};
|
||||
|
||||
class ScalpelTalk : public Talk {
|
||||
protected:
|
||||
OpcodeReturn cmdAssignPortraitLocation(const byte *&str);
|
||||
OpcodeReturn cmdClearInfoLine(const byte *&str);
|
||||
OpcodeReturn cmdClearWindow(const byte *&str);
|
||||
OpcodeReturn cmdDisplayInfoLine(const byte *&str);
|
||||
OpcodeReturn cmdElse(const byte *&str);
|
||||
OpcodeReturn cmdIf(const byte *&str);
|
||||
OpcodeReturn cmdMoveMouse(const byte *&str);
|
||||
OpcodeReturn cmdPlayPrologue(const byte *&str);
|
||||
OpcodeReturn cmdRemovePortrait(const byte *&str);
|
||||
OpcodeReturn cmdSfxCommand(const byte *&str);
|
||||
OpcodeReturn cmdSummonWindow(const byte *&str);
|
||||
OpcodeReturn cmdCarriageReturn(const byte *&str);
|
||||
public:
|
||||
ScalpelTalk(SherlockEngine *vm);
|
||||
virtual ~ScalpelTalk() {}
|
||||
};
|
||||
|
||||
class TattooTalk : public Talk {
|
||||
protected:
|
||||
OpcodeReturn cmdMouseOnOff(const byte *&str);
|
||||
OpcodeReturn cmdNextSong(const byte *&str);
|
||||
OpcodeReturn cmdPassword(const byte *&str);
|
||||
OpcodeReturn cmdPlaySong(const byte *&str);
|
||||
OpcodeReturn cmdRestorePeopleSequence(const byte *&str);
|
||||
OpcodeReturn cmdSetNPCDescOnOff(const byte *&str);
|
||||
OpcodeReturn cmdSetNPCInfoLine(const byte *&str);
|
||||
OpcodeReturn cmdNPCLabelGoto(const byte *&str);
|
||||
OpcodeReturn cmdNPCLabelIfFlagGoto(const byte *&str);
|
||||
OpcodeReturn cmdNPCLabelSet(const byte *&str);
|
||||
OpcodeReturn cmdSetNPCOff(const byte *&str);
|
||||
OpcodeReturn cmdSetNPCOn(const byte *&str);
|
||||
OpcodeReturn cmdSetNPCPathDest(const byte *&str);
|
||||
OpcodeReturn cmdSetNPCPathPause(const byte *&str);
|
||||
OpcodeReturn cmdSetNPCPathPauseTakingNotes(const byte *&str);
|
||||
OpcodeReturn cmdSetNPCPathPauseLookingHolmes(const byte *&str);
|
||||
OpcodeReturn cmdSetNPCPosition(const byte *&str);
|
||||
OpcodeReturn cmdSetNPCTalkFile(const byte *&str);
|
||||
OpcodeReturn cmdSetNPCVerb(const byte *&str);
|
||||
OpcodeReturn cmdSetNPCVerbCAnimation(const byte *&str);
|
||||
OpcodeReturn cmdSetNPCVerbScript(const byte *&str);
|
||||
OpcodeReturn cmdSetNPCVerbTarget(const byte *&str);
|
||||
OpcodeReturn cmdSetNPCWalkGraphics(const byte *&str);
|
||||
OpcodeReturn cmdSetSceneEntryFlag(const byte *&str);
|
||||
OpcodeReturn cmdSetTalkSequence(const byte *&str);
|
||||
OpcodeReturn cmdSetWalkControl(const byte *&str);
|
||||
OpcodeReturn cmdTalkInterruptsDisable(const byte *&str);
|
||||
OpcodeReturn cmdTalkInterruptsEnable(const byte *&str);
|
||||
OpcodeReturn cmdTurnSoundsOff(const byte *&str);
|
||||
OpcodeReturn cmdWalkHolmesAndNPCToCAnimation(const byte *&str);
|
||||
OpcodeReturn cmdWalkNPCToCAnimation(const byte *&str);
|
||||
OpcodeReturn cmdWalkNPCToCoords(const byte *&str);
|
||||
OpcodeReturn cmdWalkHomesAndNPCToCoords(const byte *&str);
|
||||
public:
|
||||
TattooTalk(SherlockEngine *vm);
|
||||
virtual ~TattooTalk() {}
|
||||
};
|
||||
|
||||
} // End of namespace Sherlock
|
||||
|
||||
#endif
|
||||
|
@ -21,15 +21,61 @@
|
||||
*/
|
||||
|
||||
#include "sherlock/tattoo/tattoo.h"
|
||||
#include "engines/util.h"
|
||||
|
||||
namespace Sherlock {
|
||||
|
||||
namespace Tattoo {
|
||||
|
||||
TattooEngine::TattooEngine(OSystem *syst, const SherlockGameDescription *gameDesc) :
|
||||
SherlockEngine(syst, gameDesc) {
|
||||
_creditsActive = false;
|
||||
}
|
||||
|
||||
void TattooEngine::showOpening() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void TattooEngine::initialize() {
|
||||
initGraphics(640, 480, true);
|
||||
|
||||
// Initialize the base engine
|
||||
SherlockEngine::initialize();
|
||||
|
||||
_flags.resize(100 * 8);
|
||||
|
||||
// Add some more files to the cache
|
||||
_res->addToCache("walk.lib");
|
||||
|
||||
// Starting scene
|
||||
_scene->_goToScene = 91;
|
||||
|
||||
// Load an initial palette
|
||||
loadInitialPalette();
|
||||
}
|
||||
|
||||
void TattooEngine::startScene() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void TattooEngine::loadInitialPalette() {
|
||||
byte palette[768];
|
||||
Common::SeekableReadStream *stream = _res->load("room.pal");
|
||||
stream->read(palette, PALETTE_SIZE);
|
||||
_screen->translatePalette(palette);
|
||||
_screen->setPalette(palette);
|
||||
|
||||
delete stream;
|
||||
}
|
||||
|
||||
void TattooEngine::drawCredits() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void TattooEngine::eraseCredits() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
} // End of namespace Tattoo
|
||||
|
||||
} // End of namespace Scalpel
|
||||
|
@ -30,12 +30,38 @@ namespace Sherlock {
|
||||
namespace Tattoo {
|
||||
|
||||
class TattooEngine : public SherlockEngine {
|
||||
private:
|
||||
/**
|
||||
* Loads the initial palette for the game
|
||||
*/
|
||||
void loadInitialPalette();
|
||||
protected:
|
||||
/**
|
||||
* Initialize the engine
|
||||
*/
|
||||
virtual void initialize();
|
||||
|
||||
virtual void showOpening();
|
||||
|
||||
/**
|
||||
* Starting a scene within the game
|
||||
*/
|
||||
virtual void startScene();
|
||||
public:
|
||||
TattooEngine(OSystem *syst, const SherlockGameDescription *gameDesc) :
|
||||
SherlockEngine(syst, gameDesc) {}
|
||||
bool _creditsActive;
|
||||
public:
|
||||
TattooEngine(OSystem *syst, const SherlockGameDescription *gameDesc);
|
||||
virtual ~TattooEngine() {}
|
||||
|
||||
/**
|
||||
* Draw credits on the screen
|
||||
*/
|
||||
void drawCredits();
|
||||
|
||||
/**
|
||||
* Erase any area of the screen covered by credits
|
||||
*/
|
||||
void eraseCredits();
|
||||
};
|
||||
|
||||
} // End of namespace Tattoo
|
||||
|
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
|
||||
};
|
||||
|
||||
extern const char COMMANDS[13];
|
||||
extern const int MENU_POINTS[12][4];
|
||||
|
||||
extern const int INVENTORY_POINTS[8][3];
|
||||
extern const char INVENTORY_COMMANDS[9];
|
||||
extern const char *const PRESS_KEY_FOR_MORE;
|
||||
extern const char *const PRESS_KEY_TO_CONTINUE;
|
||||
|
||||
class SherlockEngine;
|
||||
class Inventory;
|
||||
class Talk;
|
||||
class UserInterface;
|
||||
|
||||
class UserInterface {
|
||||
friend class Inventory;
|
||||
friend class Settings;
|
||||
friend class Talk;
|
||||
private:
|
||||
protected:
|
||||
SherlockEngine *_vm;
|
||||
ImageFile *_controlPanel;
|
||||
ImageFile *_controls;
|
||||
int _bgFound;
|
||||
int _oldBgFound;
|
||||
char _keyPress;
|
||||
int _lookHelp;
|
||||
int _help, _oldHelp;
|
||||
char _key, _oldKey;
|
||||
int _temp, _oldTemp;
|
||||
int _oldLook;
|
||||
bool _keyboardInput;
|
||||
bool _pause;
|
||||
int _cNum;
|
||||
int _selector, _oldSelector;
|
||||
Common::String _cAnimStr;
|
||||
bool _lookScriptFlag;
|
||||
Common::Rect _windowBounds;
|
||||
Common::String _descStr;
|
||||
int _find;
|
||||
int _oldUse;
|
||||
private:
|
||||
/**
|
||||
* Draws the image for a user interface button in the down/pressed state.
|
||||
*/
|
||||
void depressButton(int num);
|
||||
|
||||
/**
|
||||
* If he mouse button is pressed, then calls depressButton to draw the button
|
||||
* as pressed; if not, it will show it as released with a call to "restoreButton".
|
||||
*/
|
||||
void pushButton(int num);
|
||||
|
||||
/**
|
||||
* By the time this method has been called, the graphics for the button change
|
||||
* have already been drawn. This simply takes care of switching the mode around
|
||||
* accordingly
|
||||
*/
|
||||
void toggleButton(int num);
|
||||
|
||||
/**
|
||||
* Creates a text window and uses it to display the in-depth description
|
||||
* of the highlighted object
|
||||
*/
|
||||
void examine();
|
||||
|
||||
/**
|
||||
* Print the name of an object in the scene
|
||||
*/
|
||||
void lookScreen(const Common::Point &pt);
|
||||
|
||||
/**
|
||||
* Gets the item in the inventory the mouse is on and display's it's description
|
||||
*/
|
||||
void lookInv();
|
||||
|
||||
/**
|
||||
* Handles input when the file list window is being displayed
|
||||
*/
|
||||
void doEnvControl();
|
||||
|
||||
/**
|
||||
* Handle input whilst the inventory is active
|
||||
*/
|
||||
void doInvControl();
|
||||
|
||||
/**
|
||||
* Handles waiting whilst an object's description window is open.
|
||||
*/
|
||||
void doLookControl();
|
||||
|
||||
/**
|
||||
* Handles input until one of the user interface buttons/commands is selected
|
||||
*/
|
||||
void doMainControl();
|
||||
|
||||
/**
|
||||
* Handles the input for the MOVE, OPEN, and CLOSE commands
|
||||
*/
|
||||
void doMiscControl(int allowed);
|
||||
|
||||
/**
|
||||
* Handles input for picking up items
|
||||
*/
|
||||
void doPickControl();
|
||||
|
||||
/**
|
||||
* Handles input when in talk mode. It highlights the buttons and available statements,
|
||||
* and handles allowing the user to click on them
|
||||
*/
|
||||
void doTalkControl();
|
||||
|
||||
/**
|
||||
* Handles events when the Journal is active.
|
||||
* @remarks Whilst this would in theory be better in the Journal class, since it displays in
|
||||
* the user interface, it uses so many internal UI fields, that it sort of made some sense
|
||||
* to put it in the UserInterface class.
|
||||
*/
|
||||
void journalControl();
|
||||
|
||||
/**
|
||||
* Checks to see whether a USE action is valid on the given object
|
||||
*/
|
||||
void checkUseAction(const UseType *use, const Common::String &invName, const char *const messages[],
|
||||
int objNum, bool giveMode);
|
||||
|
||||
/**
|
||||
* Called for OPEN, CLOSE, and MOVE actions are being done
|
||||
*/
|
||||
void checkAction(ActionType &action, const char *const messages[], int objNum);
|
||||
UserInterface(SherlockEngine *vm);
|
||||
public:
|
||||
MenuMode _menuMode;
|
||||
int _menuCounter;
|
||||
@ -185,74 +62,67 @@ public:
|
||||
bool _windowOpen;
|
||||
bool _endKeyActive;
|
||||
int _invLookFlag;
|
||||
int _temp1;
|
||||
bool _slideWindows;
|
||||
bool _helpStyle;
|
||||
Common::Rect _windowBounds;
|
||||
bool _lookScriptFlag;
|
||||
|
||||
// TODO: Not so sure these should be in the base class. May want to refactor them to SherlockEngine, or refactor
|
||||
// various Scalpel dialogs to keep their own private state of key/selections
|
||||
char _key, _oldKey;
|
||||
int _selector, _oldSelector;
|
||||
int _temp, _oldTemp;
|
||||
int _temp1;
|
||||
int _lookHelp;
|
||||
public:
|
||||
UserInterface(SherlockEngine *vm);
|
||||
~UserInterface();
|
||||
static UserInterface *init(SherlockEngine *vm);
|
||||
virtual ~UserInterface() {}
|
||||
|
||||
/**
|
||||
* Resets the user interface
|
||||
*/
|
||||
void reset();
|
||||
virtual void reset() {}
|
||||
|
||||
/**
|
||||
* Draw the user interface onto the screen's back buffers
|
||||
*/
|
||||
void drawInterface(int bufferNum = 3);
|
||||
*/
|
||||
virtual void drawInterface(int bufferNum = 3) {}
|
||||
|
||||
/**
|
||||
* Main input handler for the user interface
|
||||
*/
|
||||
void handleInput();
|
||||
|
||||
/**
|
||||
* Clears the info line of the screen
|
||||
*/
|
||||
void clearInfo();
|
||||
|
||||
/**
|
||||
* Clear any active text window
|
||||
*/
|
||||
void clearWindow();
|
||||
|
||||
/**
|
||||
* Handles counting down whilst checking for input, then clears the info line.
|
||||
*/
|
||||
void whileMenuCounter();
|
||||
|
||||
/**
|
||||
* Print the description of an object
|
||||
*/
|
||||
void printObjectDesc(const Common::String &str, bool firstTime);
|
||||
|
||||
/**
|
||||
* Print the previously selected object's decription
|
||||
*/
|
||||
void printObjectDesc();
|
||||
virtual void handleInput() {}
|
||||
|
||||
/**
|
||||
* Displays a passed window by gradually scrolling it vertically on-screen
|
||||
*/
|
||||
void summonWindow(const Surface &bgSurface, bool slideUp = true);
|
||||
|
||||
virtual void summonWindow(const Surface &bgSurface, bool slideUp = true) {}
|
||||
|
||||
/**
|
||||
* Slide the window stored in the back buffer onto the screen
|
||||
*/
|
||||
void summonWindow(bool slideUp = true, int height = CONTROLS_Y);
|
||||
|
||||
virtual void summonWindow(bool slideUp = true, int height = CONTROLS_Y) {}
|
||||
|
||||
/**
|
||||
* Close a currently open window
|
||||
* @param flag 0 = slide old window down, 1 = slide prior UI back up
|
||||
*/
|
||||
void banishWindow(bool slideUp = true);
|
||||
virtual void banishWindow(bool slideUp = true) {}
|
||||
|
||||
/**
|
||||
* Draws the image for the given user interface button in the up
|
||||
* (not selected) position
|
||||
* Clears the info line of the screen
|
||||
*/
|
||||
void restoreButton(int num);
|
||||
virtual void clearInfo() {}
|
||||
|
||||
/**
|
||||
* Clear any active text window
|
||||
*/
|
||||
virtual void clearWindow() {}
|
||||
|
||||
/**
|
||||
* Print the previously selected object's decription
|
||||
*/
|
||||
virtual void printObjectDesc() {}
|
||||
};
|
||||
|
||||
} // End of namespace Sherlock
|
||||
|
Loading…
x
Reference in New Issue
Block a user