mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
SHERLOCK: Implement Scalpel-specific scene starting
This commit is contained in:
@@ -32,7 +32,8 @@ namespace Sherlock {
|
||||
|
||||
EventsManager::EventsManager(SherlockEngine *vm) {
|
||||
_vm = vm;
|
||||
_cursorId = CURSOR_NONE;
|
||||
_cursorSprites = nullptr;
|
||||
_cursorIndex = -1;
|
||||
_frameCounter = 1;
|
||||
_priorFrameTime = 0;
|
||||
_mouseClicked = false;
|
||||
@@ -40,15 +41,30 @@ EventsManager::EventsManager(SherlockEngine *vm) {
|
||||
}
|
||||
|
||||
EventsManager::~EventsManager() {
|
||||
delete _cursorSprites;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a set of cursors from the specified file
|
||||
*/
|
||||
void EventsManager::loadCursors(const Common::String &filename) {
|
||||
hideCursor();
|
||||
delete _cursorSprites;
|
||||
|
||||
_cursorSprites = new Sprite(filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cursor to show
|
||||
*/
|
||||
void EventsManager::setCursor(CursorType cursorId) {
|
||||
_cursorId = cursorId;
|
||||
void EventsManager::changeCursor(int cursorIndex) {
|
||||
_cursorIndex = cursorIndex;
|
||||
|
||||
// TODO: Cursor handling
|
||||
// Set the cursor data
|
||||
Graphics::Surface &s = (*_cursorSprites)[cursorIndex];
|
||||
CursorMan.replaceCursor(s.getPixels(), s.w, s.h, s.w / 2, s.h / 2, 0xff);
|
||||
|
||||
showCursor();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,11 +26,10 @@
|
||||
#include "common/scummsys.h"
|
||||
#include "common/events.h"
|
||||
#include "common/stack.h"
|
||||
#include "sherlock/sprite.h"
|
||||
|
||||
namespace Sherlock {
|
||||
|
||||
enum CursorType { CURSOR_NONE = 0 };
|
||||
|
||||
#define GAME_FRAME_RATE 60
|
||||
#define GAME_FRAME_TIME (1000 / GAME_FRAME_RATE)
|
||||
|
||||
@@ -42,10 +41,11 @@ private:
|
||||
uint32 _frameCounter;
|
||||
uint32 _priorFrameTime;
|
||||
Common::Point _mousePos;
|
||||
Sprite *_cursorSprites;
|
||||
|
||||
bool checkForNextFrameCounter();
|
||||
public:
|
||||
CursorType _cursorId;
|
||||
int _cursorIndex;
|
||||
byte _mouseButtons;
|
||||
bool _mouseClicked;
|
||||
Common::Stack<Common::KeyState> _pendingKeys;
|
||||
@@ -53,7 +53,9 @@ public:
|
||||
EventsManager(SherlockEngine *vm);
|
||||
~EventsManager();
|
||||
|
||||
void setCursor(CursorType cursorId);
|
||||
void loadCursors(const Common::String &filename);
|
||||
|
||||
void changeCursor(int cursorIndex);
|
||||
|
||||
void showCursor();
|
||||
|
||||
|
||||
@@ -41,43 +41,57 @@ bool Cache::isCached(const Common::String &filename) const {
|
||||
* If the file is LZW compressed, automatically decompresses it and loads
|
||||
* the uncompressed version into memory
|
||||
*/
|
||||
void Cache::load(const Common::String &filename) {
|
||||
void Cache::load(const Common::String &name) {
|
||||
// First check if the entry already exists
|
||||
if (_resources.contains(filename))
|
||||
if (_resources.contains(name))
|
||||
return;
|
||||
|
||||
// Allocate a new cache entry
|
||||
_resources[filename] = CacheEntry();
|
||||
CacheEntry &cacheEntry = _resources[filename];
|
||||
|
||||
// Open the file for reading
|
||||
Common::File f;
|
||||
if (!f.open(filename))
|
||||
error("Could not read file - %s", filename.c_str());
|
||||
if (!f.open(name))
|
||||
error("Could not read file - %s", name.c_str());
|
||||
|
||||
load(name, f);
|
||||
|
||||
f.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a cache entry based on a passed stream
|
||||
*/
|
||||
void Cache::load(const Common::String &name, Common::SeekableReadStream &stream) {
|
||||
// First check if the entry already exists
|
||||
if (_resources.contains(name))
|
||||
return;
|
||||
|
||||
// Check whether the file is compressed
|
||||
const char LZW_HEADER[5] = { "LZV\x1a" };
|
||||
char header[5];
|
||||
f.read(header, 5);
|
||||
stream.read(header, 5);
|
||||
bool isCompressed = !strncmp(header, LZW_HEADER, 5);
|
||||
f.seek(0);
|
||||
stream.seek(0);
|
||||
|
||||
// Allocate a new cache entry
|
||||
_resources[name] = CacheEntry();
|
||||
CacheEntry &cacheEntry = _resources[name];
|
||||
|
||||
if (isCompressed) {
|
||||
// It's compressed, so decompress the file and store it's data in the cache entry
|
||||
Common::SeekableReadStream *decompressed = decompressLZ(f);
|
||||
Common::SeekableReadStream *decompressed = decompressLZ(stream);
|
||||
cacheEntry.resize(decompressed->size());
|
||||
decompressed->read(&cacheEntry[0], decompressed->size());
|
||||
|
||||
delete decompressed;
|
||||
} else {
|
||||
// It's not, so read the raw data of the file into the cache entry
|
||||
cacheEntry.resize(f.size());
|
||||
f.read(&cacheEntry[0], f.size());
|
||||
cacheEntry.resize(stream.size());
|
||||
stream.read(&cacheEntry[0], stream.size());
|
||||
}
|
||||
|
||||
f.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a file from the cache
|
||||
*/
|
||||
Common::SeekableReadStream *Cache::get(const Common::String &filename) const {
|
||||
// Return a memory stream that encapsulates the data
|
||||
const CacheEntry &cacheEntry = _resources[filename];
|
||||
@@ -96,7 +110,6 @@ Resources::Resources() {
|
||||
addToCache("portrait.lib");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds the specified file to the cache. If it's a library file, takes care of
|
||||
* loading it's index for future use
|
||||
@@ -113,6 +126,18 @@ void Resources::addToCache(const Common::String &filename) {
|
||||
delete stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a resource from a library file tot he cache
|
||||
*/
|
||||
void Resources::addToCache(const Common::String &filename, const Common::String &libFilename) {
|
||||
// Get the resource
|
||||
Common::SeekableReadStream *stream = load(filename, libFilename);
|
||||
|
||||
_cache.load(filename, *stream);
|
||||
|
||||
delete stream;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *Resources::load(const Common::String &filename) {
|
||||
// First check if the file is directly in the cache
|
||||
if (_cache.isCached(filename))
|
||||
|
||||
@@ -57,6 +57,7 @@ public:
|
||||
bool isCached(const Common::String &filename) const;
|
||||
|
||||
void load(const Common::String &name);
|
||||
void load(const Common::String &name, Common::SeekableReadStream &stream);
|
||||
|
||||
Common::SeekableReadStream *get(const Common::String &filename) const;
|
||||
};
|
||||
@@ -72,6 +73,8 @@ public:
|
||||
Resources();
|
||||
|
||||
void addToCache(const Common::String &filename);
|
||||
void addToCache(const Common::String &filename, const Common::String &libFilename);
|
||||
bool isInCache(const Common::String &filename) const { return _cache.isCached(filename); }
|
||||
|
||||
Common::SeekableReadStream *load(const Common::String &filename);
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ namespace Sherlock {
|
||||
Rooms::Rooms() {
|
||||
for (int roomNum = 0; roomNum < ROOMS_COUNT; ++roomNum)
|
||||
Common::fill(&_stats[roomNum][0], &_stats[roomNum][9], false);
|
||||
|
||||
_goToRoom = -1;
|
||||
_oldCharPoint = 0;
|
||||
}
|
||||
|
||||
} // End of namespace Sherlock
|
||||
|
||||
@@ -94,6 +94,9 @@ public:
|
||||
bool _stats[ROOMS_COUNT][9];
|
||||
bool _savedStats[ROOMS_COUNT][9];
|
||||
int _goToRoom;
|
||||
Common::Point _bigPos;
|
||||
Common::Point _overPos;
|
||||
int _oldCharPoint;
|
||||
public:
|
||||
Rooms();
|
||||
};
|
||||
|
||||
@@ -27,6 +27,12 @@ namespace Sherlock {
|
||||
|
||||
namespace Scalpel {
|
||||
|
||||
ScalpelEngine::ScalpelEngine(OSystem *syst, const SherlockGameDescription *gameDesc) :
|
||||
SherlockEngine(syst, gameDesc) {
|
||||
_tempFadeStyle = 0;
|
||||
_chessResult = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Game initialization
|
||||
*/
|
||||
@@ -131,17 +137,188 @@ bool ScalpelEngine::showCityCutscene() {
|
||||
}
|
||||
|
||||
bool ScalpelEngine::showAlleyCutscene() {
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScalpelEngine::showStreetCutscene() {
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScalpelEngine::showOfficeCutscene() {
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
int ScalpelEngine::doChessBoard() {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ScalpelEngine::playDarts() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
/**
|
||||
* Starting a scene within the game
|
||||
*/
|
||||
void ScalpelEngine::startScene() {
|
||||
if (_rooms->_goToRoom == 100 || _rooms->_goToRoom == 98) {
|
||||
// Chessboard selection
|
||||
if (_sound->_musicEnabled) {
|
||||
if (_sound->loadSong(100)) {
|
||||
if (_sound->_music)
|
||||
_sound->startSong();
|
||||
}
|
||||
}
|
||||
|
||||
_rooms->_goToRoom = doChessBoard();
|
||||
|
||||
_sound->freeSong();
|
||||
_hsavedPos = Common::Point(-1, -1);
|
||||
_hsavedFs = -1;
|
||||
}
|
||||
|
||||
// Some rooms are prologue cutscenes, rather than normal game scenes. These are:
|
||||
// 2: Blackwood's capture
|
||||
// 52: Rescuing Anna
|
||||
// 53: Moorehead's death / subway train
|
||||
// 55: Fade out and exit
|
||||
// 70: Brumwell suicide
|
||||
switch (_rooms->_goToRoom) {
|
||||
case 2:
|
||||
case 52:
|
||||
case 53:
|
||||
case 70:
|
||||
if (_sound->_musicEnabled && _sound->loadSong(_rooms->_goToRoom)) {
|
||||
if (_sound->_music)
|
||||
_sound->startSong();
|
||||
}
|
||||
|
||||
switch (_rooms->_goToRoom) {
|
||||
case 2:
|
||||
// Blackwood's capture
|
||||
_res->addToCache("final2.vda", "epilogue.lib");
|
||||
_res->addToCache("final2.vdx", "epilogue.lib");
|
||||
_animation->playPrologue("final1", 1, 3, true, 4);
|
||||
_animation->playPrologue("final22", 1, 0, false, 4);
|
||||
break;
|
||||
|
||||
case 52:
|
||||
// Rescuing Anna
|
||||
_res->addToCache("finalr2.vda", "epilogue.lib");
|
||||
_res->addToCache("finalr2.vdx", "epilogue.lib");
|
||||
_res->addToCache("finale1.vda", "epilogue.lib");
|
||||
_res->addToCache("finale1.vdx", "epilogue.lib");
|
||||
_res->addToCache("finale2.vda", "epilogue.lib");
|
||||
_res->addToCache("finale2.vdx", "epilogue.lib");
|
||||
_res->addToCache("finale3.vda", "epilogue.lib");
|
||||
_res->addToCache("finale3.vdx", "epilogue.lib");
|
||||
_res->addToCache("finale4.vda", "EPILOG2.lib");
|
||||
_res->addToCache("finale4.vdx", "EPILOG2.lib");
|
||||
|
||||
_animation->playPrologue("finalr1", 1, 3, true, 4);
|
||||
_animation->playPrologue("finalr2", 1, 0, false, 4);
|
||||
|
||||
if (!_res->isInCache("finale2.vda")) {
|
||||
// Finale file isn't cached
|
||||
_res->addToCache("finale2.vda", "epilogue.lib");
|
||||
_res->addToCache("finale2.vdx", "epilogue.lib");
|
||||
_res->addToCache("finale3.vda", "epilogue.lib");
|
||||
_res->addToCache("finale3.vdx", "epilogue.lib");
|
||||
_res->addToCache("finale4.vda", "EPILOG2.lib");
|
||||
_res->addToCache("finale4.vdx", "EPILOG2.lib");
|
||||
}
|
||||
|
||||
_animation->playPrologue("finale1", 1, 0, false, 4);
|
||||
_animation->playPrologue("finale2", 1, 0, false, 4);
|
||||
_animation->playPrologue("finale3", 1, 0, false, 4);
|
||||
|
||||
_useEpilogue2 = true;
|
||||
_animation->playPrologue("finale4", 1, 0, false, 4);
|
||||
_useEpilogue2 = false;
|
||||
break;
|
||||
|
||||
case 53:
|
||||
// Moorehead's death / subway train
|
||||
_res->addToCache("SUBWAY2.vda", "epilogue.lib");
|
||||
_res->addToCache("SUBWAY2.vdx", "epilogue.lib");
|
||||
_res->addToCache("SUBWAY3.vda", "epilogue.lib");
|
||||
_res->addToCache("SUBWAY3.vdx", "epilogue.lib");
|
||||
|
||||
_animation->playPrologue("SUBWAY1", 1, 3, true, 4);
|
||||
_animation->playPrologue("SUBWAY2", 1, 0, false, 4);
|
||||
_animation->playPrologue("SUBWAY3", 1, 0, false, 4);
|
||||
|
||||
// Set fading to direct fade temporary so the transition goes quickly.
|
||||
_tempFadeStyle = _screen->_fadeStyle ? 257 : 256;
|
||||
_screen->_fadeStyle = false;
|
||||
break;
|
||||
|
||||
case 70:
|
||||
// Brumwell suicide
|
||||
_animation->playPrologue("suicid", 1, 3, true, 4);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Except for the Moorehead Murder scene, fade to black first
|
||||
if (_rooms->_goToRoom != 53) {
|
||||
_events->wait(40);
|
||||
_screen->fadeToBlack(3);
|
||||
}
|
||||
|
||||
switch (_rooms->_goToRoom) {
|
||||
case 52:
|
||||
_rooms->_goToRoom = 27; // Go to the Lawyer's Office
|
||||
_rooms->_bigPos = Common::Point(0, 0); // Overland scroll position
|
||||
_rooms->_overPos = Common::Point(22900 - 600, 9400 + 900); // Overland position
|
||||
_rooms->_oldCharPoint = 27;
|
||||
break;
|
||||
|
||||
case 53:
|
||||
_rooms->_goToRoom = 17; // Go to St. Pancras Station
|
||||
_rooms->_bigPos = Common::Point(0, 0); // Overland scroll position
|
||||
_rooms->_overPos = Common::Point(32500 - 600, 3000 + 900); // Overland position
|
||||
_rooms->_oldCharPoint = 17;
|
||||
break;
|
||||
|
||||
default:
|
||||
_rooms->_goToRoom = 4; // Back to Baker st.
|
||||
_rooms->_bigPos = Common::Point(0, 0); // Overland scroll position
|
||||
_rooms->_overPos = Common::Point(14500 - 600, 8400 + 900); // Overland position
|
||||
_rooms->_oldCharPoint = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
// Free any song from the previous scene
|
||||
_sound->freeSong();
|
||||
break;
|
||||
|
||||
case 55:
|
||||
// Exit game
|
||||
_screen->fadeToBlack(3);
|
||||
quitGame();
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
_events->loadCursors("rmouse.vgs");
|
||||
_events->changeCursor(0);
|
||||
|
||||
if (_rooms->_goToRoom == 99) {
|
||||
// Chess Board
|
||||
playDarts();
|
||||
_chessResult = _rooms->_goToRoom = 19; // Go back to the bar
|
||||
}
|
||||
|
||||
_chessResult = _rooms->_goToRoom;
|
||||
}
|
||||
|
||||
} // End of namespace Scalpel
|
||||
|
||||
} // End of namespace Scalpel
|
||||
|
||||
@@ -31,17 +31,25 @@ namespace Scalpel {
|
||||
|
||||
class ScalpelEngine : public SherlockEngine {
|
||||
private:
|
||||
int _tempFadeStyle;
|
||||
int _chessResult;
|
||||
|
||||
bool showCityCutscene();
|
||||
bool showAlleyCutscene();
|
||||
bool showStreetCutscene();
|
||||
bool showOfficeCutscene();
|
||||
|
||||
int doChessBoard();
|
||||
|
||||
void playDarts();
|
||||
protected:
|
||||
virtual void initialize();
|
||||
|
||||
virtual void showOpening();
|
||||
|
||||
virtual void startScene();
|
||||
public:
|
||||
ScalpelEngine(OSystem *syst, const SherlockGameDescription *gameDesc) :
|
||||
SherlockEngine(syst, gameDesc) {}
|
||||
ScalpelEngine(OSystem *syst, const SherlockGameDescription *gameDesc);
|
||||
virtual ~ScalpelEngine() {}
|
||||
};
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ Screen::Screen(SherlockEngine *vm) : Surface(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCR
|
||||
_backBuffer(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT),
|
||||
_backBuffer2(SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT) {
|
||||
_transitionSeed = 1;
|
||||
_fadeStyle = false;
|
||||
setFont(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ protected:
|
||||
virtual void addDirtyRect(const Common::Rect &r);
|
||||
public:
|
||||
Surface _backBuffer, _backBuffer2;
|
||||
bool _fadeStyle;
|
||||
public:
|
||||
Screen(SherlockEngine *vm);
|
||||
|
||||
|
||||
@@ -40,9 +40,10 @@ SherlockEngine::SherlockEngine(OSystem *syst, const SherlockGameDescription *gam
|
||||
_sound = nullptr;
|
||||
_talk = nullptr;
|
||||
_useEpilogue2 = false;
|
||||
_hsavedPos = Common::Point(-1, -1);
|
||||
_hsavedFs = -1;
|
||||
}
|
||||
|
||||
|
||||
SherlockEngine::~SherlockEngine() {
|
||||
delete _animation;
|
||||
delete _debugger;
|
||||
@@ -73,11 +74,11 @@ void SherlockEngine::initialize() {
|
||||
_midi->setNativeMT32(native_mt32);
|
||||
*/
|
||||
|
||||
_res = new Resources();
|
||||
_animation = new Animation(this);
|
||||
_debugger = new Debugger(this);
|
||||
_events = new EventsManager(this);
|
||||
_journal = new Journal();
|
||||
_res = new Resources();
|
||||
_rooms = new Rooms();
|
||||
_screen = new Screen(this);
|
||||
_sound = new Sound(this);
|
||||
@@ -90,8 +91,15 @@ Common::Error SherlockEngine::run() {
|
||||
|
||||
showOpening();
|
||||
|
||||
// TODO: Rest of game
|
||||
|
||||
while (!shouldQuit()) {
|
||||
// Prepare for scene, and handle any game-specific scenes
|
||||
startScene();
|
||||
|
||||
// TODO: Implement game and remove this dummy loop
|
||||
while (!shouldQuit())
|
||||
_events->pollEventsAndWait();
|
||||
}
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,8 @@ protected:
|
||||
virtual void initialize();
|
||||
|
||||
virtual void showOpening() = 0;
|
||||
|
||||
virtual void startScene() {}
|
||||
public:
|
||||
const SherlockGameDescription *_gameDescription;
|
||||
Animation *_animation;
|
||||
@@ -85,6 +87,8 @@ public:
|
||||
Common::String _soundOverride;
|
||||
Common::String _titleOverride;
|
||||
bool _useEpilogue2;
|
||||
Common::Point _hsavedPos;
|
||||
int _hsavedFs;
|
||||
public:
|
||||
SherlockEngine(OSystem *syst, const SherlockGameDescription *gameDesc);
|
||||
virtual ~SherlockEngine();
|
||||
|
||||
@@ -29,6 +29,7 @@ Sound::Sound(SherlockEngine *vm): _vm(vm) {
|
||||
_musicEnabled = true;
|
||||
_voicesEnabled = true;
|
||||
_playingEpilogue = false;
|
||||
_music = false;
|
||||
}
|
||||
|
||||
void Sound::playSound(const Common::String &name, WaitType waitType) {
|
||||
@@ -59,5 +60,18 @@ void Sound::stopMusic() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
int Sound::loadSong(int songNumber) {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Sound::startSong() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void Sound::freeSong() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
} // End of namespace Sherlock
|
||||
|
||||
@@ -42,6 +42,7 @@ public:
|
||||
bool _musicEnabled;
|
||||
bool _voicesEnabled;
|
||||
bool _playingEpilogue;
|
||||
bool _music;
|
||||
public:
|
||||
Sound(SherlockEngine *vm);
|
||||
|
||||
@@ -50,6 +51,9 @@ public:
|
||||
void playCachedSound(int index);
|
||||
void clearCache();
|
||||
void stopSound();
|
||||
int loadSong(int songNumber);
|
||||
void startSong();
|
||||
void freeSong();
|
||||
|
||||
void playMusic(const Common::String &name);
|
||||
void stopMusic();
|
||||
|
||||
Reference in New Issue
Block a user