SHERLOCK: Implement Scalpel-specific scene starting

This commit is contained in:
Paul Gilbert
2015-03-18 22:32:41 -04:00
parent b8ad1ce140
commit 2dc355ff6e
14 changed files with 297 additions and 31 deletions
+20 -4
View File
@@ -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();
}
/**
+6 -4
View File
@@ -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 -16
View File
@@ -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))
+3
View File
@@ -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);
+1 -1
View File
@@ -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
+3
View File
@@ -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();
};
+177
View File
@@ -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
+10 -2
View File
@@ -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() {}
};
+1
View File
@@ -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);
}
+1
View File
@@ -51,6 +51,7 @@ protected:
virtual void addDirtyRect(const Common::Rect &r);
public:
Surface _backBuffer, _backBuffer2;
bool _fadeStyle;
public:
Screen(SherlockEngine *vm);
+12 -4
View File
@@ -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;
}
+4
View File
@@ -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();
+14
View File
@@ -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
+4
View File
@@ -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();