Initial commit
This commit is contained in:
173
engines/asylum/system/config.cpp
Normal file
173
engines/asylum/system/config.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "asylum/system/config.h"
|
||||
|
||||
#include "asylum/system/sound.h"
|
||||
|
||||
namespace Common {
|
||||
DECLARE_SINGLETON(Asylum::ConfigurationManager);
|
||||
}
|
||||
|
||||
namespace Asylum {
|
||||
|
||||
static bool g_config_initialized = false;
|
||||
|
||||
ConfigurationManager::ConfigurationManager() {
|
||||
if (!g_config_initialized) {
|
||||
g_config_initialized = true;
|
||||
}
|
||||
|
||||
// Register engine-specific options
|
||||
ConfMan.registerDefault("show_encounter_subtitles", true);
|
||||
ConfMan.registerDefault("gamma_level", 0);
|
||||
ConfMan.registerDefault("ambient_volume", -750);
|
||||
ConfMan.registerDefault("movie_volume", -500);
|
||||
ConfMan.registerDefault("music_volume", -1500);
|
||||
ConfMan.registerDefault("sfx_volume", -1000);
|
||||
ConfMan.registerDefault("speech_volume", -750);
|
||||
|
||||
ConfMan.registerDefault("music_status", true);
|
||||
ConfMan.registerDefault("reverse_stereo", false);
|
||||
ConfMan.registerDefault("performance", 4);
|
||||
ConfMan.registerDefault("animations_speed", 1);
|
||||
ConfMan.registerDefault("key_showVersion", 'v');
|
||||
ConfMan.registerDefault("key_quickLoad", 'L');
|
||||
ConfMan.registerDefault("key_quickSave", 'S');
|
||||
ConfMan.registerDefault("key_switchToSara", 's');
|
||||
ConfMan.registerDefault("key_switchToGrimwall", 'g');
|
||||
ConfMan.registerDefault("key_switchToOlmec", 'o');
|
||||
|
||||
// Special debug options
|
||||
ConfMan.registerDefault("show_scene_loading", true);
|
||||
ConfMan.registerDefault("show_intro", true);
|
||||
|
||||
// Init values
|
||||
musicVolume = 0;
|
||||
ambientVolume = 0;
|
||||
sfxVolume = 0;
|
||||
voiceVolume = 0;
|
||||
movieVolume = 0;
|
||||
|
||||
musicStatus = true;
|
||||
reverseStereo = false;
|
||||
|
||||
showMovieSubtitles = false;
|
||||
showEncounterSubtitles = true;
|
||||
showSceneLoading = true;
|
||||
showIntro = true;
|
||||
|
||||
gammaLevel = 0;
|
||||
performance = 0;
|
||||
animationsSpeed = 1;
|
||||
|
||||
keyShowVersion = 'v';
|
||||
keyQuickLoad = 'L';
|
||||
keyQuickSave = 'S';
|
||||
keySwitchToSara = 's';
|
||||
keySwitchToGrimwall = 'g';
|
||||
keySwitchToOlmec = 'o';
|
||||
}
|
||||
|
||||
ConfigurationManager::~ConfigurationManager() {
|
||||
}
|
||||
|
||||
void ConfigurationManager::read() {
|
||||
// Default options
|
||||
musicVolume = ConfMan.getInt("music_volume");
|
||||
sfxVolume = ConfMan.getInt("sfx_volume");
|
||||
voiceVolume = ConfMan.getInt("speech_volume");
|
||||
showMovieSubtitles = ConfMan.getBool("subtitles");
|
||||
|
||||
// Convert volumes to engine-values
|
||||
Sound::convertVolumeTo(musicVolume);
|
||||
Sound::convertVolumeTo(sfxVolume);
|
||||
Sound::convertVolumeTo(voiceVolume);
|
||||
|
||||
// Engine options
|
||||
showEncounterSubtitles = ConfMan.getBool("show_encounter_subtitles");
|
||||
gammaLevel = ConfMan.getInt("gamma_level");
|
||||
ambientVolume = ConfMan.getInt("ambient_volume");
|
||||
movieVolume = ConfMan.getInt("movie_volume");
|
||||
musicStatus = ConfMan.getBool("music_status");
|
||||
reverseStereo = ConfMan.getBool("reverse_stereo");
|
||||
performance = ConfMan.getInt("performance");
|
||||
animationsSpeed = ConfMan.getInt("animations_speed");
|
||||
|
||||
// Misc options
|
||||
showSceneLoading = ConfMan.getBool("show_scene_loading");
|
||||
showIntro = ConfMan.getBool("show_intro");
|
||||
|
||||
// Keyboard shortcuts
|
||||
keyShowVersion = (char)ConfMan.getInt("key_showVersion");
|
||||
keyQuickLoad = (char)ConfMan.getInt("key_quickLoad");
|
||||
keyQuickSave = (char)ConfMan.getInt("key_quickSave");
|
||||
keySwitchToSara = (char)ConfMan.getInt("key_switchToSara");
|
||||
keySwitchToGrimwall = (char)ConfMan.getInt("key_switchToGrimwall");
|
||||
keySwitchToOlmec = (char)ConfMan.getInt("key_switchToOlmec");
|
||||
}
|
||||
|
||||
void ConfigurationManager::write() {
|
||||
int32 mixerMusicVolume = musicVolume;
|
||||
int32 mixerSfxVolume = sfxVolume;
|
||||
int32 mixerVoiceVolume = voiceVolume;
|
||||
|
||||
// Convert volumes to mixer-values
|
||||
Sound::convertVolumeFrom(mixerMusicVolume);
|
||||
Sound::convertVolumeFrom(mixerSfxVolume);
|
||||
Sound::convertVolumeFrom(mixerVoiceVolume);
|
||||
|
||||
// Default options
|
||||
ConfMan.setInt("music_volume", mixerMusicVolume);
|
||||
ConfMan.setInt("sfx_volume", mixerSfxVolume);
|
||||
ConfMan.setInt("speech_volume", mixerVoiceVolume);
|
||||
ConfMan.setBool("subtitles", showMovieSubtitles);
|
||||
|
||||
// Engine options
|
||||
ConfMan.setBool("show_encounter_subtitles", showEncounterSubtitles);
|
||||
ConfMan.setInt("gamma_level", gammaLevel);
|
||||
ConfMan.setInt("ambient_volume", ambientVolume);
|
||||
ConfMan.setInt("movie_volume", movieVolume);
|
||||
ConfMan.setBool("music_status", musicStatus);
|
||||
ConfMan.setBool("reverse_stereo", reverseStereo);
|
||||
ConfMan.setInt("performance", performance);
|
||||
ConfMan.setInt("animations_speed", animationsSpeed);
|
||||
|
||||
// Misc Options
|
||||
ConfMan.setBool("show_scene_loading", showSceneLoading);
|
||||
ConfMan.setBool("show_intro", showIntro);
|
||||
|
||||
// Keyboard shortcuts
|
||||
ConfMan.setInt("key_showVersion", (int)keyShowVersion);
|
||||
ConfMan.setInt("key_quickLoad", (int)keyQuickLoad);
|
||||
ConfMan.setInt("key_quickSave", (int)keyQuickSave);
|
||||
ConfMan.setInt("key_switchToSara", (int)keySwitchToSara);
|
||||
ConfMan.setInt("key_switchToGrimwall", (int)keySwitchToGrimwall);
|
||||
ConfMan.setInt("key_switchToOlmec", (int)keySwitchToOlmec);
|
||||
|
||||
ConfMan.flushToDisk();
|
||||
}
|
||||
|
||||
bool ConfigurationManager::isKeyAssigned(char key) const {
|
||||
return (keyShowVersion == key || keyQuickLoad == key || keyQuickSave == key || keySwitchToSara == key || keySwitchToGrimwall == key || keySwitchToOlmec == key);
|
||||
}
|
||||
|
||||
} // end of namespace Asylum
|
||||
109
engines/asylum/system/config.h
Normal file
109
engines/asylum/system/config.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ASYLUM_SYSTEM_CONFIG_H
|
||||
#define ASYLUM_SYSTEM_CONFIG_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/singleton.h"
|
||||
#include "common/config-manager.h"
|
||||
|
||||
namespace Asylum {
|
||||
|
||||
/**
|
||||
* The ConfigurationManager is where the common configuration options used
|
||||
* by the engine are bound.
|
||||
*
|
||||
* These options can be set through the main menu
|
||||
*/
|
||||
class ConfigurationManager: public Common::Singleton<ConfigurationManager> {
|
||||
public:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Normal configuration
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Default options
|
||||
int32 musicVolume;
|
||||
int32 sfxVolume;
|
||||
int32 voiceVolume;
|
||||
bool showMovieSubtitles;
|
||||
|
||||
// Engine options
|
||||
bool showEncounterSubtitles;
|
||||
int gammaLevel;
|
||||
int32 ambientVolume;
|
||||
int32 movieVolume;
|
||||
bool musicStatus; // On or Off
|
||||
bool reverseStereo;
|
||||
int performance; ///< performance only affects sound: perf > 0 ? 22050hz/16bit : 11025hz/8bit
|
||||
int animationsSpeed;
|
||||
char keyShowVersion;
|
||||
char keyQuickSave;
|
||||
char keyQuickLoad;
|
||||
char keySwitchToSara;
|
||||
char keySwitchToGrimwall;
|
||||
char keySwitchToOlmec;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Misc configuration options (not shown in GUI)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This will play the scene title loading up progress before the scene is entered.
|
||||
// This is just a convenience, as there's no need for the type of pre-loading that
|
||||
// was performed in the original
|
||||
bool showSceneLoading;
|
||||
|
||||
// This option will prevent the intro movies from being played whenever the engine is started
|
||||
bool showIntro;
|
||||
|
||||
/**
|
||||
* Load configuration file
|
||||
*/
|
||||
void read();
|
||||
|
||||
/**
|
||||
* Save a value to the configuration file
|
||||
*/
|
||||
void write();
|
||||
|
||||
/**
|
||||
* Query if 'key' is assigned.
|
||||
*
|
||||
* @param key The key.
|
||||
*
|
||||
* @return true if key assigned, false if not.
|
||||
*/
|
||||
bool isKeyAssigned(char key) const;
|
||||
|
||||
private:
|
||||
friend class Common::Singleton<SingletonBaseType>;
|
||||
|
||||
ConfigurationManager();
|
||||
virtual ~ConfigurationManager();
|
||||
|
||||
};
|
||||
|
||||
#define Config (::Asylum::ConfigurationManager::instance())
|
||||
|
||||
} // end of namespace Asylum
|
||||
|
||||
#endif // ASYLUM_SYSTEM_CONFIG_H
|
||||
171
engines/asylum/system/cursor.cpp
Normal file
171
engines/asylum/system/cursor.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "asylum/system/cursor.h"
|
||||
|
||||
#include "asylum/system/graphics.h"
|
||||
|
||||
#include "asylum/asylum.h"
|
||||
|
||||
#include "graphics/cursorman.h"
|
||||
|
||||
namespace Asylum {
|
||||
|
||||
const uint32 CURSOR_UPDATE_TICKS = 100;
|
||||
|
||||
Cursor::Cursor(AsylumEngine *engine) : _vm(engine),
|
||||
_cursorRes(nullptr), _nextTick(0), _frameStep(0),
|
||||
_graphicResourceId(kResourceNone), _currentFrame(0), _lastFrameIndex(0), _counter(0), _animation(kCursorAnimationNone),
|
||||
_forceHide(false) {
|
||||
}
|
||||
|
||||
Cursor::~Cursor() {
|
||||
delete _cursorRes;
|
||||
}
|
||||
|
||||
void Cursor::hide() const {
|
||||
CursorMan.showMouse(false);
|
||||
}
|
||||
|
||||
void Cursor::show() const {
|
||||
if (!_forceHide)
|
||||
CursorMan.showMouse(true);
|
||||
}
|
||||
|
||||
void Cursor::set(ResourceId resourceId, int32 cnt, CursorAnimation anim, int32 frames) {
|
||||
bool wasHidden = isHidden();
|
||||
|
||||
hide();
|
||||
|
||||
delete _cursorRes;
|
||||
_cursorRes = new GraphicResource(_vm, resourceId);
|
||||
|
||||
// Set next update
|
||||
_nextTick = _vm->getTick() + CURSOR_UPDATE_TICKS;
|
||||
|
||||
// Get frame count
|
||||
if (frames >= 0)
|
||||
_lastFrameIndex = (uint32)frames;
|
||||
else
|
||||
_lastFrameIndex = _cursorRes->count() - 1;
|
||||
|
||||
this->_graphicResourceId = resourceId;
|
||||
this->_animation = anim;
|
||||
this->_counter = cnt;
|
||||
_currentFrame = 0;
|
||||
_frameStep = 1;
|
||||
|
||||
// Do not animate if no frames (and the other way around)
|
||||
if (_lastFrameIndex == 0 || anim == kCursorAnimationNone) {
|
||||
_lastFrameIndex = 0;
|
||||
_animation = kCursorAnimationNone;
|
||||
}
|
||||
|
||||
if (_lastFrameIndex >= _cursorRes->count())
|
||||
_lastFrameIndex = _cursorRes->count() - 1;
|
||||
|
||||
update();
|
||||
|
||||
if (!wasHidden)
|
||||
show();
|
||||
}
|
||||
|
||||
void Cursor::update() {
|
||||
if (!_cursorRes)
|
||||
error("[Cursor::update] Cursor resources not initialized properly!");
|
||||
|
||||
Common::Point hotspot = getHotspot(_currentFrame);
|
||||
|
||||
GraphicFrame *frame = _cursorRes->getFrame(_currentFrame);
|
||||
CursorMan.replaceCursor(frame->surface, hotspot.x, hotspot.y, 0);
|
||||
}
|
||||
|
||||
void Cursor::animate() {
|
||||
if (isHidden() || !_animation || _nextTick > _vm->getTick())
|
||||
return;
|
||||
|
||||
bool notifyHandler = false;
|
||||
int32 frame = 0;
|
||||
|
||||
if (_animation == kCursorAnimationLinear) {
|
||||
if (_currentFrame == _lastFrameIndex) {
|
||||
_currentFrame = frame = 0;
|
||||
} else {
|
||||
_currentFrame += _frameStep;
|
||||
frame = _currentFrame;
|
||||
}
|
||||
} else if (_animation == kCursorAnimationMirror) {
|
||||
_currentFrame += _frameStep;
|
||||
frame = _currentFrame;
|
||||
|
||||
if (_currentFrame == 0 || _currentFrame == _lastFrameIndex)
|
||||
_frameStep = -_frameStep;
|
||||
}
|
||||
|
||||
if (frame == 0) {
|
||||
if (_counter != -1) {
|
||||
--_counter;
|
||||
|
||||
if (!_counter) {
|
||||
_animation = kCursorAnimationNone;
|
||||
notifyHandler = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_nextTick = _vm->getTick() + CURSOR_UPDATE_TICKS;
|
||||
|
||||
if (notifyHandler)
|
||||
_vm->notify(EVENT_ASYLUM_CURSOR);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
Common::Point Cursor::getHotspot(uint32 frameIndex) {
|
||||
if (!_cursorRes)
|
||||
error("[Cursor::getHotspot] Cursor resource not initialized properly");
|
||||
|
||||
Common::Point point;
|
||||
uint32 resFlags = _cursorRes->getData().flags;
|
||||
|
||||
if (BYTE1(resFlags) & 0x10) {
|
||||
// XXX removed a check for frameIndex >= 0 as it will always
|
||||
// evaluate to true since frameIndex is unsigned
|
||||
if (frameIndex > _cursorRes->count()) {
|
||||
GraphicFrame *frame = _cursorRes->getFrame(_currentFrame);
|
||||
|
||||
point.x = frame->x;
|
||||
point.y = frame->y;
|
||||
}
|
||||
}
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
bool Cursor::isHidden() const {
|
||||
return !CursorMan.isVisible();
|
||||
}
|
||||
|
||||
const Common::Point Cursor::position() const {
|
||||
return g_system->getEventManager()->getMousePos();
|
||||
}
|
||||
|
||||
} // end of namespace Asylum
|
||||
155
engines/asylum/system/cursor.h
Normal file
155
engines/asylum/system/cursor.h
Normal file
@@ -0,0 +1,155 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ASYLUM_SYSTEM_CURSOR_H
|
||||
#define ASYLUM_SYSTEM_CURSOR_H
|
||||
|
||||
#include "common/events.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
#include "asylum/shared.h"
|
||||
|
||||
namespace Asylum {
|
||||
|
||||
class AsylumEngine;
|
||||
class GraphicResource;
|
||||
|
||||
enum CursorAnimation {
|
||||
kCursorAnimationNone = 0,
|
||||
kCursorAnimationLinear = 1,
|
||||
kCursorAnimationMirror = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* Asylum cursors are GraphicResources, and are stored in
|
||||
* ResourcePacks, as are all game assets.
|
||||
*/
|
||||
class Cursor {
|
||||
public:
|
||||
Cursor(AsylumEngine *engine);
|
||||
virtual ~Cursor();
|
||||
|
||||
/**
|
||||
* Show the current cursor
|
||||
*/
|
||||
void show() const;
|
||||
|
||||
/**
|
||||
* Hide the current cursor
|
||||
*/
|
||||
void hide() const;
|
||||
|
||||
/**
|
||||
* Query if the cursor is hidden.
|
||||
*
|
||||
* @return true if hidden, false if not.
|
||||
*/
|
||||
bool isHidden() const;
|
||||
|
||||
/**
|
||||
* Set the current cursor instance to the graphic resource provide. The frames parameter defaults to -1, which in this case means that the frame count
|
||||
* should be derived from the graphic resource as opposed to being explicitly set.
|
||||
*
|
||||
* @param resourceId Identifier for the resource.
|
||||
* @param cnt The counter.
|
||||
* @param anim The animation type
|
||||
* @param frames The frames.
|
||||
*/
|
||||
void set(ResourceId resourceId, int32 cnt = 0, CursorAnimation anim = kCursorAnimationMirror, int32 frames = -1);
|
||||
|
||||
/**
|
||||
* Get the next logical frame from the currently loaded
|
||||
* cursorResource and draw it
|
||||
*/
|
||||
void animate();
|
||||
|
||||
// Accessors
|
||||
void setForceHide(bool state) { _forceHide = state; }
|
||||
ResourceId getResourceId() { return _graphicResourceId; }
|
||||
CursorAnimation getAnimation() { return _animation; }
|
||||
|
||||
/**
|
||||
* Return the cursor's position on the screen
|
||||
*/
|
||||
const Common::Point position() const;
|
||||
|
||||
private:
|
||||
AsylumEngine *_vm;
|
||||
|
||||
// Cursor resource
|
||||
GraphicResource *_cursorRes;
|
||||
|
||||
/** the point on the screen the cursor is at */
|
||||
Common::Point _pos;
|
||||
|
||||
/** the point of the cursor that triggers click hits */
|
||||
Common::Point _hotspot;
|
||||
|
||||
// The number of milliseconds between cursor gfx updates
|
||||
uint32 _nextTick;
|
||||
|
||||
int32 _frameStep;
|
||||
|
||||
// NOTE: The original engine contains a function that assigns global variables to a
|
||||
// struct associated with cursor graphics info. Since this functionality only
|
||||
// ever seems to be used to reference cursor info, the struct members
|
||||
// may as well be class members in order to simplify the logic a bit
|
||||
ResourceId _graphicResourceId;
|
||||
uint32 _currentFrame;
|
||||
uint32 _lastFrameIndex;
|
||||
int32 _counter;
|
||||
CursorAnimation _animation;
|
||||
|
||||
/**
|
||||
* Since the cursor is updated by various event handlers, if an action is
|
||||
* currently being processed that requires the cursor to remain hidden, another
|
||||
* event may override that request and show the cursor regardless
|
||||
*
|
||||
* This is currently used during the intro speech in Scene 1 after the intro
|
||||
* video plays
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
bool _forceHide;
|
||||
|
||||
/**
|
||||
* Updates the cursor
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
* Updates the cursor current frame.
|
||||
*/
|
||||
void updateFrame();
|
||||
|
||||
/**
|
||||
* Gets the hotspot for a specific frame.
|
||||
*
|
||||
* @param frameIndex Zero-based index of the frame.
|
||||
*
|
||||
* @return The hotspot.
|
||||
*/
|
||||
Common::Point getHotspot(uint32 frameIndex);
|
||||
};
|
||||
|
||||
} // end of namespace Asylum
|
||||
|
||||
#endif // ASYLUM_SYSTEM_CURSOR_H
|
||||
174
engines/asylum/system/graphics.cpp
Normal file
174
engines/asylum/system/graphics.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "asylum/system/graphics.h"
|
||||
|
||||
#include "asylum/asylum.h"
|
||||
#include "asylum/respack.h"
|
||||
|
||||
namespace Asylum {
|
||||
|
||||
GraphicResource::GraphicResource(AsylumEngine *engine) : _vm(engine), _resourceId(kResourceNone) {
|
||||
}
|
||||
|
||||
GraphicResource::GraphicResource(AsylumEngine *engine, ResourceId id) : _vm(engine), _resourceId(kResourceNone) {
|
||||
if (!load(id))
|
||||
error("[GraphicResource::GraphicResource] Error loading resource (0x%X)", id);
|
||||
}
|
||||
|
||||
GraphicResource::~GraphicResource() {
|
||||
clear();
|
||||
}
|
||||
|
||||
bool GraphicResource::load(ResourceId id) {
|
||||
if (id == kResourceNone)
|
||||
error("[GraphicResource::load] Trying to load an invalid resource!");
|
||||
|
||||
// Clear previously loaded data
|
||||
clear();
|
||||
|
||||
ResourceEntry *resEntry = getResource()->get(id);
|
||||
if (!resEntry)
|
||||
return false;
|
||||
|
||||
_resourceId = id;
|
||||
init(resEntry->data, resEntry->size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GraphicResource::clear() {
|
||||
for (uint32 i = 0; i < _frames.size(); i++) {
|
||||
_frames[i].surface.free();
|
||||
}
|
||||
|
||||
_frames.clear();
|
||||
}
|
||||
|
||||
GraphicFrame *GraphicResource::getFrame(uint32 frame) {
|
||||
if (frame >= _frames.size())
|
||||
error("[GraphicResource::getFrame] Invalid frame index (was: %d, max:%d)", frame, _frames.size() - 1);
|
||||
|
||||
return &_frames[frame];
|
||||
}
|
||||
|
||||
void GraphicResource::init(byte *data, int32 size) {
|
||||
byte *dataPtr = data;
|
||||
|
||||
// Read tag
|
||||
for (uint i = 0; i < sizeof(_data.tag); i++) {
|
||||
_data.tag[i] = *dataPtr;
|
||||
++dataPtr;
|
||||
}
|
||||
|
||||
_data.flags = READ_LE_UINT32(dataPtr);
|
||||
dataPtr += 4;
|
||||
|
||||
int32 contentOffset = (int32)READ_LE_UINT32(dataPtr);
|
||||
dataPtr += 4;
|
||||
|
||||
_data.field_C = READ_LE_UINT32(dataPtr);
|
||||
dataPtr += 4;
|
||||
|
||||
_data.field_10 = READ_LE_UINT32(dataPtr);
|
||||
dataPtr += 4;
|
||||
|
||||
_data.field_14 = READ_LE_UINT32(dataPtr);
|
||||
dataPtr += 4;
|
||||
|
||||
uint16 frameCount = READ_LE_UINT16(dataPtr);
|
||||
dataPtr += 2;
|
||||
|
||||
_data.maxWidth = READ_LE_UINT16(dataPtr);
|
||||
dataPtr += 2;
|
||||
|
||||
_frames.resize(frameCount);
|
||||
|
||||
// Read frame offsets
|
||||
int32 prevOffset = (int32)READ_LE_UINT32(dataPtr) + contentOffset;
|
||||
dataPtr += 4;
|
||||
int32 nextOffset = 0;
|
||||
|
||||
for (int32 i = 0; i < frameCount; i++) {
|
||||
GraphicFrame frame;
|
||||
frame.offset = prevOffset;
|
||||
|
||||
// Read the offset of the next entry to determine the size of this one
|
||||
nextOffset = (i < frameCount - 1) ? (int32)READ_LE_UINT32(dataPtr) + contentOffset : size;
|
||||
dataPtr += 4; // offset
|
||||
frame.size = (nextOffset > 0) ? nextOffset - prevOffset : size - prevOffset;
|
||||
|
||||
_frames[i] = frame;
|
||||
|
||||
prevOffset = nextOffset;
|
||||
}
|
||||
|
||||
// Reset pointer
|
||||
dataPtr = data;
|
||||
|
||||
// Read frame data
|
||||
for (uint32 i = 0; i < frameCount; i++) {
|
||||
dataPtr = data + _frames[i].offset;
|
||||
|
||||
dataPtr += 4; // size
|
||||
dataPtr += 4; // flag
|
||||
|
||||
_frames[i].x = (int16)READ_LE_UINT16(dataPtr);
|
||||
dataPtr += 2;
|
||||
_frames[i].y = (int16)READ_LE_UINT16(dataPtr);
|
||||
dataPtr += 2;
|
||||
|
||||
uint16 height = READ_LE_UINT16(dataPtr);
|
||||
dataPtr += 2;
|
||||
uint16 width = READ_LE_UINT16(dataPtr);
|
||||
dataPtr += 2;
|
||||
|
||||
if (width > 0 && height > 0) {
|
||||
_frames[i].surface.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
|
||||
_frames[i].surface.copyRectToSurface(dataPtr, width, 0, 0, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Helper functions
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint32 GraphicResource::getFrameCount(AsylumEngine *engine, ResourceId id) {
|
||||
GraphicResource *resource = new GraphicResource(engine, id);
|
||||
uint32 frameCount = resource->count();
|
||||
delete resource;
|
||||
|
||||
return frameCount;
|
||||
}
|
||||
|
||||
Common::Rect GraphicResource::getFrameRect(AsylumEngine *engine, ResourceId id, uint32 index) {
|
||||
GraphicResource *resource = new GraphicResource(engine, id);
|
||||
GraphicFrame *frame = resource->getFrame(index);
|
||||
|
||||
Common::Rect rect = frame->getRect();
|
||||
|
||||
delete resource;
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
} // end of namespace Asylum
|
||||
121
engines/asylum/system/graphics.h
Normal file
121
engines/asylum/system/graphics.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ASYLUM_SYSTEM_GRAPHICS_H
|
||||
#define ASYLUM_SYSTEM_GRAPHICS_H
|
||||
|
||||
#include "common/rect.h"
|
||||
#include "common/array.h"
|
||||
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "asylum/shared.h"
|
||||
|
||||
namespace Asylum {
|
||||
|
||||
class AsylumEngine;
|
||||
|
||||
struct GraphicFrame {
|
||||
int32 size;
|
||||
int32 offset;
|
||||
|
||||
int16 x;
|
||||
int16 y;
|
||||
Graphics::Surface surface;
|
||||
|
||||
uint16 getWidth() { return surface.w; }
|
||||
uint16 getHeight() { return surface.h; }
|
||||
|
||||
GraphicFrame() {
|
||||
size = offset = 0;
|
||||
x = y = 0;
|
||||
}
|
||||
|
||||
Common::Rect getRect() {
|
||||
return Common::Rect(x, y, x + getWidth(), y + getHeight());
|
||||
}
|
||||
};
|
||||
|
||||
// Graphic resources can be sprites or images, with multiple frames
|
||||
class GraphicResource {
|
||||
public:
|
||||
struct ResourceData {
|
||||
char tag[4];
|
||||
uint32 flags;
|
||||
// contentOffset
|
||||
uint32 field_C;
|
||||
uint32 field_10;
|
||||
uint32 field_14;
|
||||
// frameCount
|
||||
uint16 maxWidth;
|
||||
// Offsets
|
||||
|
||||
ResourceData() {
|
||||
memset(&tag, 0, sizeof(tag));
|
||||
flags = 0;
|
||||
field_C = 0;
|
||||
field_10 = 0;
|
||||
field_14 = 0;
|
||||
maxWidth = 0;
|
||||
}
|
||||
};
|
||||
|
||||
GraphicResource(AsylumEngine *engine);
|
||||
GraphicResource(AsylumEngine *engine, ResourceId id);
|
||||
~GraphicResource();
|
||||
|
||||
bool load(ResourceId id);
|
||||
|
||||
/**
|
||||
* Copies an animation frame to the target buffer
|
||||
*/
|
||||
void copyFrameToDest(byte *dest, uint32 frame);
|
||||
|
||||
/**
|
||||
* Copies a sprite to the target buffer, with transparency
|
||||
*/
|
||||
void copySpriteToDest(byte *dest, uint32 frame);
|
||||
|
||||
GraphicFrame *getFrame(uint32 frame);
|
||||
ResourceId getResourceId() { return _resourceId; }
|
||||
uint32 count() { return _frames.size(); }
|
||||
|
||||
// FIXME: flags are coordinates for the sound origin!
|
||||
ResourceData getData() { return _data; }
|
||||
|
||||
// Helper functions
|
||||
static uint32 getFrameCount(AsylumEngine *engine, ResourceId id);
|
||||
static Common::Rect getFrameRect(AsylumEngine *engine, ResourceId id, uint32 index);
|
||||
|
||||
private:
|
||||
AsylumEngine *_vm;
|
||||
|
||||
ResourceId _resourceId;
|
||||
ResourceData _data;
|
||||
Common::Array<GraphicFrame> _frames;
|
||||
|
||||
void init(byte *data, int32 size);
|
||||
void clear();
|
||||
};
|
||||
|
||||
} // end of namespace Asylum
|
||||
|
||||
#endif // ASYLUM_SYSTEM_GRAPHICS_H
|
||||
470
engines/asylum/system/savegame.cpp
Normal file
470
engines/asylum/system/savegame.cpp
Normal file
@@ -0,0 +1,470 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/file.h"
|
||||
|
||||
#include "asylum/system/savegame.h"
|
||||
|
||||
#include "asylum/puzzles/puzzles.h"
|
||||
|
||||
#include "asylum/resources/encounters.h"
|
||||
#include "asylum/resources/script.h"
|
||||
#include "asylum/resources/worldstats.h"
|
||||
|
||||
#include "asylum/system/cursor.h"
|
||||
#include "asylum/system/screen.h"
|
||||
#include "asylum/system/text.h"
|
||||
|
||||
#include "asylum/views/menu.h"
|
||||
#include "asylum/views/scene.h"
|
||||
|
||||
#include "asylum/asylum.h"
|
||||
|
||||
namespace Asylum {
|
||||
|
||||
#define SAVEGAME_BUILD 851
|
||||
#define SAVEGAME_VERSION_SIZE 11
|
||||
#define SAVEGAME_NAME_SIZE 45
|
||||
|
||||
#define SAVEGAME_QUICKSLOT 24
|
||||
|
||||
static const char *savegame_version = "v1.01 FINAL";
|
||||
|
||||
Savegame::Savegame(AsylumEngine *engine) : _vm(engine), _index(0) {
|
||||
memset(&_moviesViewed, 0, sizeof(_moviesViewed));
|
||||
memset(&_savegames, 0, sizeof(_savegames));
|
||||
memset(&_savegameToScene, 0, sizeof(_savegameToScene));
|
||||
resetVersion();
|
||||
}
|
||||
|
||||
void Savegame::resetVersion() {
|
||||
_version = savegame_version;
|
||||
_build = SAVEGAME_BUILD;
|
||||
}
|
||||
|
||||
bool Savegame::hasSavegames() const {
|
||||
for (uint i = 0; i < SAVEGAME_COUNT; i++)
|
||||
if (isSavegamePresent(getFilename(i)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Savegame::loadList() {
|
||||
for (uint32 i = 0; i < SAVEGAME_COUNT; i++) {
|
||||
if (isSavegamePresent(getFilename(i))) {
|
||||
Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(getFilename(i));
|
||||
if (!file)
|
||||
error("[Savegame::loadList] Cannot open savegame: %s", getFilename(i).c_str());
|
||||
|
||||
// Check file size (we handle empty files, but not invalid ones)
|
||||
if (file->size() == 0) {
|
||||
_names[i] = getText()->get(MAKE_RESOURCE(kResourcePackText, 1324));
|
||||
_savegames[i] = false;
|
||||
} else {
|
||||
_savegameToScene[i] = read(file, "Level");
|
||||
_names[i] = read(file, 45, "Game Name");
|
||||
_savegames[i] = true;
|
||||
}
|
||||
|
||||
delete file;
|
||||
} else {
|
||||
_names[i] = getText()->get(MAKE_RESOURCE(kResourcePackText, 1324));
|
||||
_savegames[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Savegame::load() {
|
||||
getCursor()->hide();
|
||||
// Original clears the graphic cache
|
||||
getScript()->resetQueue();
|
||||
getSound()->playMusic(kResourceNone, 0);
|
||||
getScene()->load((ResourcePackId)(_savegameToScene[_index] + 4));
|
||||
_vm->reset();
|
||||
// Original loads encounter data
|
||||
|
||||
loadData(getFilename(_index));
|
||||
|
||||
loadMoviesViewed();
|
||||
|
||||
getMenu()->setDword455C80(false);
|
||||
getScreen()->clear();
|
||||
}
|
||||
|
||||
bool Savegame::quickLoad() {
|
||||
if (!isSavegamePresent(getFilename(SAVEGAME_QUICKSLOT)))
|
||||
return false;
|
||||
|
||||
_index = SAVEGAME_QUICKSLOT;
|
||||
(void)_vm->startGame(getScenePack(), AsylumEngine::kStartGameLoad);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Savegame::save() {
|
||||
// Original creates a folder to hold saved games and checks for disk space, we can skip that
|
||||
getCursor()->hide();
|
||||
|
||||
saveData(getFilename(_index), _names[_index], getWorld()->chapter);
|
||||
_savegames[_index] = true;
|
||||
getMenu()->setDword455C78(true);
|
||||
getMenu()->setDword455C80(false);
|
||||
getCursor()->show();
|
||||
}
|
||||
|
||||
bool Savegame::quickSave() {
|
||||
_index = 24;
|
||||
|
||||
// Check if there is a quick save already
|
||||
if (!isSavegamePresent(getFilename(SAVEGAME_QUICKSLOT))) {
|
||||
_names[_index] = getText()->get(MAKE_RESOURCE(kResourcePackText, 1342));
|
||||
|
||||
save();
|
||||
} else {
|
||||
Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(getFilename(SAVEGAME_QUICKSLOT));
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
// Read game name
|
||||
seek(file, 1, "Level");
|
||||
_names[_index] = read(file, 45, "Game Name");
|
||||
|
||||
delete file;
|
||||
|
||||
save();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Savegame::remove() {
|
||||
if (_index >= ARRAYSIZE(_savegames))
|
||||
error("[Savegame::remove] Invalid savegame index");
|
||||
|
||||
getCursor()->hide();
|
||||
g_system->getSavefileManager()->removeSavefile(getFilename(_index));
|
||||
|
||||
// Update status and name
|
||||
_savegames[_index] = false;
|
||||
_names[_index] = getText()->get(MAKE_RESOURCE(kResourcePackText, 1344));
|
||||
|
||||
getMenu()->setDword455C80(false);
|
||||
getCursor()->show();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Helpers
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool Savegame::isCompatible() {
|
||||
Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(getFilename(_index));
|
||||
|
||||
assert(file);
|
||||
seek(file, 2, "Level and Name");
|
||||
bool result = readHeader(file);
|
||||
|
||||
delete file;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Common::String Savegame::getFilename(uint32 index) const {
|
||||
if (index > SAVEGAME_COUNT - 1)
|
||||
error("[Savegame::getFilename] Invalid savegame index (was:%d, valid: [0-24])", index);
|
||||
|
||||
return _vm->getSaveStateName(index);
|
||||
}
|
||||
|
||||
bool Savegame::isSavegamePresent(const Common::String &filename) const {
|
||||
if (g_system->getSavefileManager()->listSavefiles(filename).size() == 0)
|
||||
return false;
|
||||
|
||||
Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(filename);
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
bool isSaveValid = (file->size() == 0) ? false : true;
|
||||
|
||||
delete file;
|
||||
|
||||
return isSaveValid;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Reading & writing
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool Savegame::readHeader(Common::InSaveFile *file) {
|
||||
uint32 versionLength = read(file, "Version Length");
|
||||
_version = read(file, versionLength, "Version");
|
||||
_build = read(file, "Build");
|
||||
|
||||
// Original does not do any version check
|
||||
return !strcmp(_version.c_str(), savegame_version) && _build == SAVEGAME_BUILD;
|
||||
}
|
||||
|
||||
void Savegame::writeHeader(Common::OutSaveFile *file) const {
|
||||
// We write saved games with a 1.01 final version (build 851)
|
||||
|
||||
write(file, SAVEGAME_VERSION_SIZE, "Version Length");
|
||||
write(file, Common::String(savegame_version), SAVEGAME_VERSION_SIZE, "Version");
|
||||
write(file, SAVEGAME_BUILD, "Build");
|
||||
}
|
||||
|
||||
void Savegame::loadData(const Common::String &filename) {
|
||||
Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(filename);
|
||||
assert(file);
|
||||
|
||||
seek(file, 1, "Level");
|
||||
seek(file, 1, "Game Name");
|
||||
|
||||
(void)readHeader(file);
|
||||
|
||||
read(file, _vm, 1512, 1, "Game Stats");
|
||||
read(file, getWorld(), 951928, 1, "World Stats");
|
||||
read(file, getPuzzles(), 752, 1, "Blowup Puzzle Data");
|
||||
read(file, getEncounter()->items(), 109, getEncounter()->items()->size(), "Encounter Data");
|
||||
read(file, getEncounter()->variables(), 2, getEncounter()->variables()->size(), "Encounter Variables");
|
||||
|
||||
getScript()->reset(getWorld()->numScripts);
|
||||
|
||||
if (getWorld()->numScripts)
|
||||
read(file, getScript(), 7096, (uint32)getWorld()->numScripts, "Action Lists");
|
||||
|
||||
uint32 tick = read(file, "Time");
|
||||
|
||||
_vm->setTick(tick);
|
||||
|
||||
delete file;
|
||||
}
|
||||
|
||||
void Savegame::saveData(const Common::String &filename, const Common::String &name, ChapterIndex chapter) {
|
||||
Common::OutSaveFile *file = g_system->getSavefileManager()->openForSaving(filename);
|
||||
assert(file);
|
||||
|
||||
write(file, (unsigned) (int32)chapter, "Level");
|
||||
write(file, name, SAVEGAME_NAME_SIZE, "Game Name");
|
||||
writeHeader(file);
|
||||
write(file, _vm, 1512, 1, "Game Stats");
|
||||
write(file, getWorld(), 951928, 1, "World Stats");
|
||||
write(file, getPuzzles(), 752, 1, "Blowup Puzzle Data");
|
||||
write(file, getEncounter()->items(), 109, getEncounter()->items()->size(), "Encounter Data");
|
||||
write(file, getEncounter()->variables(), 2, getEncounter()->variables()->size(), "Encounter Variables");
|
||||
|
||||
if (getWorld()->numScripts)
|
||||
write(file, getScript(), 7096, (uint32)getWorld()->numScripts, "Action Lists");
|
||||
|
||||
write(file, _vm->getTick(), "Time");
|
||||
|
||||
_vm->getMetaEngine()->appendExtendedSaveToStream(file, _vm->getTotalPlayTime() / 1000, name, false);
|
||||
|
||||
delete file;
|
||||
}
|
||||
|
||||
void Savegame::seek(Common::InSaveFile *file, uint32 offset, const Common::String &description) {
|
||||
debugC(kDebugLevelSavegame, "[Savegame] Seeking to offset: %s", description.c_str());
|
||||
|
||||
if (offset == 0)
|
||||
return;
|
||||
|
||||
uint32 size = 0;
|
||||
uint32 count = 0;
|
||||
|
||||
for (uint i = 0; i < offset; i++) {
|
||||
size = file->readUint32LE();
|
||||
count = file->readUint32LE();
|
||||
|
||||
file->seek(size * count, SEEK_CUR);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Savegame::read(Common::InSaveFile *file, const Common::String &description) {
|
||||
debugC(kDebugLevelSavegame, "[Savegame] Reading %s", description.c_str());
|
||||
|
||||
uint32 size = file->readUint32LE();
|
||||
uint32 count = file->readUint32LE();
|
||||
|
||||
if (size * count == 0)
|
||||
return 0;
|
||||
|
||||
return file->readUint32LE();
|
||||
}
|
||||
|
||||
Common::String Savegame::read(Common::InSaveFile *file, uint32 strLength, const Common::String &description) {
|
||||
debugC(kDebugLevelSavegame, "[Savegame] Reading %s (of length %d)", description.c_str(), strLength);
|
||||
|
||||
/*uint32 size =*/ file->readUint32LE();
|
||||
uint32 count = file->readUint32LE();
|
||||
|
||||
if (strLength > count)
|
||||
error("[Savegame::read] Count too large (asked: %d, present: %d)", strLength, count);
|
||||
|
||||
char *str = new char[strLength + 1]();
|
||||
file->read(str, strLength);
|
||||
|
||||
Common::String ret(str);
|
||||
|
||||
delete[] str;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Savegame::read(Common::InSaveFile *file, Common::Serializable *data, uint32 size, uint32 count, const Common::String &description) {
|
||||
debugC(kDebugLevelSavegame, "[Savegame] Reading %s (%d block(s) of size %d)", description.c_str(), size, count);
|
||||
|
||||
uint32 fileSize = file->readUint32LE();
|
||||
if (size > fileSize)
|
||||
error("[Savegame::read] Size too large (asked: %d, present: %d)", size, fileSize);
|
||||
|
||||
uint32 fileCount = file->readUint32LE();
|
||||
if (count > fileCount)
|
||||
error("[Savegame::read] Count too large (asked: %d, present: %d)", count, fileCount);
|
||||
|
||||
if (fileCount * fileSize == 0)
|
||||
return;
|
||||
|
||||
Common::Serializer ser(file, nullptr);
|
||||
data->saveLoadWithSerializer(ser);
|
||||
}
|
||||
|
||||
void Savegame::write(Common::OutSaveFile *file, uint32 val, const Common::String &description) {
|
||||
debugC(kDebugLevelSavegame, "[Savegame] Writing %s: %d", description.c_str(), val);
|
||||
|
||||
file->writeUint32LE(4);
|
||||
file->writeUint32LE(1);
|
||||
|
||||
file->writeUint32LE(val);
|
||||
}
|
||||
|
||||
void Savegame::write(Common::OutSaveFile *file, const Common::String &val, uint32 strLength, const Common::String &description) {
|
||||
debugC(kDebugLevelSavegame, "[Savegame] Writing %s (of length %d): %s", description.c_str(), strLength, val.c_str());
|
||||
|
||||
if (val.size() > strLength)
|
||||
error("[Savegame::write] Trying to save a string that is longer than the specified size (string size: %d, size: %d)", val.size(), strLength);
|
||||
|
||||
file->writeUint32LE(1);
|
||||
file->writeUint32LE(strLength);
|
||||
|
||||
file->writeString(val);
|
||||
|
||||
// Add padding
|
||||
if (val.size() < strLength) {
|
||||
for (uint32 i = 0; i < (strLength - val.size()); i++)
|
||||
file->writeByte(0);
|
||||
}
|
||||
}
|
||||
|
||||
void Savegame::write(Common::OutSaveFile *file, Common::Serializable *data, uint32 size, uint32 count, const Common::String &description) {
|
||||
debugC(kDebugLevelSavegame, "[Savegame] Writing %s (%d block(s) of size %d)", description.c_str(), size, count);
|
||||
|
||||
file->writeUint32LE(size);
|
||||
file->writeUint32LE(count);
|
||||
|
||||
if (size * count == 0)
|
||||
return;
|
||||
|
||||
Common::Serializer ser(nullptr, file);
|
||||
uint before = ser.bytesSynced();
|
||||
|
||||
// Save the data
|
||||
data->saveLoadWithSerializer(ser);
|
||||
|
||||
// Check we wrote the correct amount of data
|
||||
uint after = ser.bytesSynced();
|
||||
|
||||
if ((after - before) != (size * count))
|
||||
error("[Savegame::write] Invalid number of bytes written to file (was: %d, expected: %d)", after - before, size * count);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Movies
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void Savegame::setMovieViewed(uint32 index) {
|
||||
if (index >= ARRAYSIZE(_moviesViewed))
|
||||
error("[Savegame::setMovieViewed] Invalid movie index!");
|
||||
|
||||
if (!_moviesViewed[index]) {
|
||||
_moviesViewed[index] = 1;
|
||||
|
||||
// Write data to disk
|
||||
Common::OutSaveFile *movies = g_system->getSavefileManager()->openForSaving(_vm->getMoviesFileName());
|
||||
if (!movies)
|
||||
error("[Savegame::setMovieViewed] Could not open viewed movie list!");
|
||||
|
||||
movies->write((byte *)&_moviesViewed, sizeof(_moviesViewed));
|
||||
|
||||
delete movies;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Savegame::getMoviesViewed(int32 *movieList) const {
|
||||
memset(movieList, -1, 196 * sizeof(int32));
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
for (uint32 i = 0; i < ARRAYSIZE(_moviesViewed); i++) {
|
||||
if (_moviesViewed[i]) {
|
||||
movieList[count] = i;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void Savegame::loadMoviesViewed() {
|
||||
if (!isSavegamePresent(_vm->getMoviesFileName()))
|
||||
return;
|
||||
|
||||
// Load data from disk
|
||||
Common::InSaveFile *movies = g_system->getSavefileManager()->openForLoading(_vm->getMoviesFileName());
|
||||
if (!movies)
|
||||
error("[Savegame::setMovieViewed] Could not open viewed movie list!");
|
||||
|
||||
movies->read((byte *)&_moviesViewed, sizeof(_moviesViewed));
|
||||
|
||||
delete movies;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Accessors
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void Savegame::setName(uint32 index, const Common::String &name) {
|
||||
if (index >= ARRAYSIZE(_names))
|
||||
error("[Savegame::setName] Invalid index (was: %d, max: %d)", index, ARRAYSIZE(_names) - 1);
|
||||
|
||||
_names[index] = name;
|
||||
}
|
||||
|
||||
Common::String Savegame::getName(uint32 index) const {
|
||||
if (index >= ARRAYSIZE(_names))
|
||||
error("[Savegame::getName] Invalid index (was: %d, max: %d)", index, ARRAYSIZE(_names) - 1);
|
||||
|
||||
return _names[index];
|
||||
}
|
||||
|
||||
bool Savegame::hasSavegame(uint32 index) const {
|
||||
if (index >= ARRAYSIZE(_savegames))
|
||||
error("[Savegame::hasSavegame] Invalid index (was: %d, max: %d)", index, ARRAYSIZE(_savegames) - 1);
|
||||
|
||||
return _savegames[index];
|
||||
}
|
||||
|
||||
} // End of namespace Asylum
|
||||
263
engines/asylum/system/savegame.h
Normal file
263
engines/asylum/system/savegame.h
Normal file
@@ -0,0 +1,263 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ASYLUM_SYSTEM_SAVEGAME_H
|
||||
#define ASYLUM_SYSTEM_SAVEGAME_H
|
||||
|
||||
#include "common/savefile.h"
|
||||
#include "common/serializer.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include "asylum/shared.h"
|
||||
|
||||
namespace Asylum {
|
||||
|
||||
#define SAVEGAME_COUNT 25
|
||||
|
||||
class AsylumEngine;
|
||||
|
||||
class Savegame {
|
||||
public:
|
||||
Savegame(AsylumEngine *engine);
|
||||
~Savegame() {};
|
||||
|
||||
/**
|
||||
* Checks if saved games are present
|
||||
*
|
||||
* @return true if it succeeds, false if it fails.
|
||||
*/
|
||||
bool hasSavegames() const;
|
||||
|
||||
/**
|
||||
* Loads the list of saved games.
|
||||
*/
|
||||
void loadList();
|
||||
|
||||
/**
|
||||
* Loads a game
|
||||
*/
|
||||
void load();
|
||||
|
||||
/**
|
||||
* Quick loads a game
|
||||
*
|
||||
* @return true if it succeeds, false if it fails.
|
||||
*/
|
||||
bool quickLoad();
|
||||
|
||||
/**
|
||||
* Saves a game
|
||||
*
|
||||
* @return true if it succeeds, false if it fails.
|
||||
*/
|
||||
void save();
|
||||
|
||||
/**
|
||||
* Quick saves a game
|
||||
*
|
||||
* @return true if it succeeds, false if it fails.
|
||||
*/
|
||||
bool quickSave();
|
||||
|
||||
/**
|
||||
* Removes a savegame
|
||||
*/
|
||||
void remove();
|
||||
|
||||
/**
|
||||
* Checks if a savegame is compatible
|
||||
*
|
||||
* @return true if it is, false otherwise.
|
||||
*/
|
||||
bool isCompatible();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Static methods
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Seeks to a specific place in the file
|
||||
*
|
||||
* @param [in,out] file If non-null, the file.
|
||||
* @param offset Offset index of the info into the file
|
||||
* @param description The description.
|
||||
*/
|
||||
static void seek(Common::InSaveFile *file, uint32 offset, const Common::String &description);
|
||||
|
||||
/**
|
||||
* Reads data from a file.
|
||||
*
|
||||
* @param [in,out] file If non-null, the file.
|
||||
* @param description The description.
|
||||
*
|
||||
* @return the value
|
||||
*/
|
||||
static uint32 read(Common::InSaveFile *file, const Common::String &description);
|
||||
|
||||
/**
|
||||
* Reads data from a file.
|
||||
*
|
||||
* @param [in,out] file If non-null, the file.
|
||||
* @param strLength Length of the string.
|
||||
* @param description The description.
|
||||
*
|
||||
* @return the string
|
||||
*/
|
||||
static Common::String read(Common::InSaveFile *file, uint32 strLength, const Common::String &description);
|
||||
|
||||
/**
|
||||
* Reads data from a file.
|
||||
*
|
||||
* @param [in,out] file If non-null, the file.
|
||||
* @param [in,out] data If non-null, the data.
|
||||
* @param size The size.
|
||||
* @param count Number of.
|
||||
* @param description The description.
|
||||
*/
|
||||
static void read(Common::InSaveFile *file, Common::Serializable *data, uint32 size, uint32 count, const Common::String &description);
|
||||
|
||||
/**
|
||||
* Writes data to a file.
|
||||
*
|
||||
* @param [in,out] file If non-null, the file.
|
||||
* @param val The value
|
||||
* @param description The description.
|
||||
*/
|
||||
static void write(Common::OutSaveFile *file, uint32 val, const Common::String &description);
|
||||
|
||||
/**
|
||||
* Writes data to a file.
|
||||
*
|
||||
* @param [in,out] file If non-null, the file.
|
||||
* @param val The string
|
||||
* @param strLength The size of the string.
|
||||
* @param description The description.
|
||||
*/
|
||||
static void write(Common::OutSaveFile *file, const Common::String &val, uint32 strLength, const Common::String &description);
|
||||
|
||||
/**
|
||||
* Writes data to a file.
|
||||
*
|
||||
* @param [in,out] file If non-null, the file.
|
||||
* @param [in,out] data If non-null, the data.
|
||||
* @param size The size.
|
||||
* @param count Number of.
|
||||
* @param description The description.
|
||||
*/
|
||||
static void write(Common::OutSaveFile *file, Common::Serializable *data, uint32 size, uint32 count, const Common::String &description);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Movies
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void setMovieViewed(uint32 index);
|
||||
uint32 getMoviesViewed(int32 *movieList) const;
|
||||
void loadMoviesViewed();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Accessors
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void setName(uint32 index, const Common::String &name);
|
||||
Common::String getName(uint32 index) const;
|
||||
|
||||
Common::String *getName() { return &_names[_index]; }
|
||||
void setIndex(uint32 index) { _index = index; }
|
||||
uint32 getIndex() { return _index; }
|
||||
|
||||
bool hasSavegame(uint32 index) const;
|
||||
ResourcePackId getScenePack() { return (ResourcePackId)(_savegameToScene[_index] + 4); }
|
||||
|
||||
void resetVersion();
|
||||
const char *getVersion() { return _version.c_str(); }
|
||||
uint32 getBuild() { return _build; }
|
||||
|
||||
private:
|
||||
AsylumEngine *_vm;
|
||||
|
||||
uint32 _index;
|
||||
byte _moviesViewed[196];
|
||||
uint32 _savegameToScene[SAVEGAME_COUNT];
|
||||
bool _savegames[SAVEGAME_COUNT];
|
||||
Common::String _names[SAVEGAME_COUNT];
|
||||
Common::String _version;
|
||||
uint32 _build;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Helpers
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Gets a filename for a given save index
|
||||
*
|
||||
* @param index Zero-based index of the savegame
|
||||
*
|
||||
* @return The filename.
|
||||
*/
|
||||
Common::String getFilename(uint32 index) const;
|
||||
|
||||
/**
|
||||
* Check if a specific savegame exists
|
||||
*
|
||||
* @param filename Filename of the file.
|
||||
*
|
||||
* @return true if savegame present, false if not.
|
||||
*/
|
||||
bool isSavegamePresent(const Common::String &filename) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Reading & writing
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Reads a savegame header.
|
||||
*
|
||||
* @param [in,out] file If non-null, the file.
|
||||
*
|
||||
* @return true if it succeeds, false if it fails.
|
||||
*/
|
||||
bool readHeader(Common::InSaveFile *file);
|
||||
|
||||
/**
|
||||
* Writes a savegame header.
|
||||
*
|
||||
* @param [in,out] file If non-null, the file.
|
||||
*/
|
||||
void writeHeader(Common::OutSaveFile *file) const;
|
||||
|
||||
/**
|
||||
* Loads savegame data
|
||||
*
|
||||
* @param filename Filename of the file.
|
||||
*/
|
||||
void loadData(const Common::String &filename);
|
||||
|
||||
/**
|
||||
* Save savegame data.
|
||||
*
|
||||
* @param filename Filename of the file.
|
||||
* @param name The name.
|
||||
* @param chapter The chapter.
|
||||
*/
|
||||
void saveData(const Common::String &filename, const Common::String &name, ChapterIndex chapter);
|
||||
};
|
||||
|
||||
} // End of namespace Asylum
|
||||
|
||||
#endif // ASYLUM_SYSTEM_SAVEGAME_H
|
||||
1244
engines/asylum/system/screen.cpp
Normal file
1244
engines/asylum/system/screen.cpp
Normal file
File diff suppressed because it is too large
Load Diff
216
engines/asylum/system/screen.h
Normal file
216
engines/asylum/system/screen.h
Normal file
@@ -0,0 +1,216 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ASYLUM_SYSTEM_SCREEN_H
|
||||
#define ASYLUM_SYSTEM_SCREEN_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/queue.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "asylum/shared.h"
|
||||
|
||||
namespace Asylum {
|
||||
|
||||
#define PALETTE_SIZE (256 * 3)
|
||||
|
||||
class AsylumEngine;
|
||||
class GraphicResource;
|
||||
class ResourcePack;
|
||||
|
||||
struct GraphicFrame;
|
||||
|
||||
enum GraphicItemType {
|
||||
kGraphicItemNormal = 1,
|
||||
kGraphicItemMasked = 5
|
||||
};
|
||||
|
||||
typedef struct GraphicQueueItem {
|
||||
int32 priority;
|
||||
|
||||
GraphicItemType type;
|
||||
ResourceId resourceId;
|
||||
uint32 frameIndex;
|
||||
Common::Point source;
|
||||
ResourceId resourceIdDestination;
|
||||
Common::Point destination;
|
||||
DrawFlags flags;
|
||||
int32 transTableNum;
|
||||
|
||||
GraphicQueueItem() {
|
||||
priority = 0;
|
||||
|
||||
type = kGraphicItemNormal;
|
||||
resourceId = kResourceNone;
|
||||
frameIndex = 0;
|
||||
resourceIdDestination = kResourceNone;
|
||||
flags = kDrawFlagNone;
|
||||
transTableNum = 0;
|
||||
}
|
||||
} GraphicQueueItem;
|
||||
|
||||
struct FadeParameters {
|
||||
ResourceId resourceId;
|
||||
int ticksWait;
|
||||
int delta;
|
||||
uint nextTick;
|
||||
int step;
|
||||
};
|
||||
|
||||
class Screen {
|
||||
public:
|
||||
Screen(AsylumEngine *_vm);
|
||||
~Screen();
|
||||
|
||||
// Drawing
|
||||
void draw(ResourceId resourceId);
|
||||
void draw(ResourceId resourceId, uint32 frameIndex, const Common::Point &source, DrawFlags flags = kDrawFlagNone, bool colorKey = true);
|
||||
void draw(ResourceId resourceId, uint32 frameIndex, const int16 (*srcPtr)[2], DrawFlags flags = kDrawFlagNone, bool colorKey = true);
|
||||
void draw(GraphicResource *resource, uint32 frameIndex, const Common::Point &source, DrawFlags flags = kDrawFlagNone, bool colorKey = true);
|
||||
void drawTransparent(ResourceId resourceId, uint32 frameIndex, const Common::Point &source, DrawFlags flags, uint32 transTableNum);
|
||||
void drawTransparent(GraphicResource *resource, uint32 frameIndex, const Common::Point &source, DrawFlags flags, uint32 transTableNum);
|
||||
void draw(ResourceId resourceId, uint32 frameIndex, const Common::Point &source, DrawFlags flags, ResourceId resourceId2, const Common::Point &destination, bool colorKey = true);
|
||||
void draw(const Graphics::Surface &surface, int x, int y);
|
||||
|
||||
// Misc
|
||||
void clear();
|
||||
void clearDefaultColor() { memset(_mainPalette, 0, 3); setupPalette(NULL, 0, 0); }
|
||||
void drawWideScreenBars(int16 barSize) const;
|
||||
void fillRect(int16 x, int16 y, int16 x2, int16 y2, uint32 color);
|
||||
void copyBackBufferToScreen();
|
||||
void setFlag(int16 val) { _flag = (val < -1) ? -1 : val; }
|
||||
int16 getFlag() { return _flag; }
|
||||
|
||||
// Palette
|
||||
void setPalette(ResourceId id);
|
||||
const byte *getPalette() { return _mainPalette; }
|
||||
void setMainPalette(const byte *data);
|
||||
void loadGrayPalette();
|
||||
void updatePalette();
|
||||
void updatePalette(int32 param);
|
||||
void setupPalette(byte *buffer, int start, int count);
|
||||
|
||||
bool isFading() { return _isFading; }
|
||||
void queuePaletteFade(ResourceId resourceId, int32 ticksWait, int32 delta);
|
||||
void paletteFade(uint32 start, int32 ticksWait, int32 delta);
|
||||
void stopPaletteFade(char red, char green, char blue);
|
||||
void stopPaletteFadeAndSet(ResourceId id, int32 ticksWait, int32 delta);
|
||||
void processPaletteFadeQueue();
|
||||
|
||||
// Gamma
|
||||
void setPaletteGamma(ResourceId id);
|
||||
void setGammaLevel(ResourceId id);
|
||||
|
||||
// Transparency tables
|
||||
void setupTransTable(ResourceId resourceId);
|
||||
void setupTransTables(uint32 count, ...);
|
||||
void selectTransTable(uint32 index);
|
||||
|
||||
// Graphic queue
|
||||
void addGraphicToQueue(ResourceId resourceId, uint32 frameIndex, const Common::Point &point, DrawFlags flags, int32 transTableNum, int32 priority);
|
||||
void addGraphicToQueue(ResourceId resourceId, uint32 frameIndex, const int16 (*pointPtr)[2], DrawFlags flags, int32 transTableNum, int32 priority);
|
||||
void addGraphicToQueueCrossfade(ResourceId resourceId, uint32 frameIndex, const Common::Point &source, int32 objectResourceId, const Common::Point &destination, uint32 transTableNum);
|
||||
void addGraphicToQueueMasked(ResourceId resourceId, uint32 frameIndex, const Common::Point &source, int32 objectResourceId, const Common::Point &destination, DrawFlags flags, int32 priority);
|
||||
void addGraphicToQueue(GraphicQueueItem const &item);
|
||||
void drawGraphicsInQueue();
|
||||
void clearGraphicsInQueue();
|
||||
void deleteGraphicFromQueue(ResourceId resourceId);
|
||||
bool isGraphicQueueEmpty() { return _queueItems.empty(); }
|
||||
|
||||
// Used by Video
|
||||
void copyToBackBuffer(const byte *buffer, int32 pitch, int16 x, int16 y, uint16 width, uint16 height, bool mirrored = false);
|
||||
|
||||
// Debug
|
||||
void drawLine(const Common::Point &source, const Common::Point &destination, uint32 color = 0xFF);
|
||||
void drawLine(const int16 (*srcPtr)[2], const int16 (*dstPtr)[2], uint32 color = 0xFF);
|
||||
void drawRect(const Common::Rect &rect, uint32 color = 0xFF);
|
||||
void copyToBackBufferClipped(Graphics::Surface *surface, int16 x, int16 y);
|
||||
|
||||
// Used by Writings puzzle and Chinese renderer
|
||||
Graphics::Surface *getSurface() { return &_backBuffer; };
|
||||
|
||||
private:
|
||||
AsylumEngine *_vm;
|
||||
|
||||
Graphics::Surface _backBuffer;
|
||||
Common::Rect _clipRect;
|
||||
Common::Array<GraphicQueueItem> _queueItems;
|
||||
|
||||
int16 _flag;
|
||||
bool _useColorKey;
|
||||
|
||||
// Transparency tables
|
||||
uint32 _transTableCount;
|
||||
byte *_transTable;
|
||||
byte *_transTableBuffer;
|
||||
void clearTransTables();
|
||||
|
||||
// Palette
|
||||
byte _currentPalette[PALETTE_SIZE];
|
||||
byte _mainPalette[PALETTE_SIZE];
|
||||
byte _fromPalette[PALETTE_SIZE];
|
||||
byte _toPalette[PALETTE_SIZE];
|
||||
bool _isFading;
|
||||
bool _fadeStop;
|
||||
Common::Queue<FadeParameters> _fadeQueue;
|
||||
|
||||
byte *getPaletteData(ResourceId id);
|
||||
void setPaletteGamma(byte *data, byte *target = NULL);
|
||||
|
||||
void stopQueuedPaletteFade();
|
||||
void initQueuedPaletteFade(ResourceId id, int32 delta);
|
||||
void runQueuedPaletteFade(ResourceId id, int32 delta, int i);
|
||||
|
||||
// Graphic queue
|
||||
static bool graphicQueueItemComparator(const GraphicQueueItem &item1, const GraphicQueueItem &item2);
|
||||
|
||||
// Misc
|
||||
void clip(Common::Rect *source, Common::Rect *destination, int32 flags) const;
|
||||
|
||||
void draw(GraphicResource *resource, uint32 frameIndex, const Common::Point &source, DrawFlags flags, ResourceId resourceId2, const Common::Point &destination, bool colorKey = true);
|
||||
|
||||
// Screen blitting
|
||||
void blit(GraphicFrame *frame, Common::Rect *source, Common::Rect *destination, int32 flags);
|
||||
void blitMasked(GraphicFrame *frame, Common::Rect *source, byte *maskData, Common::Rect *sourceMask, Common::Rect *destMask, uint16 maskWidth, Common::Rect *destination, int32 flags);
|
||||
void blitTranstable (byte *dstBuffer, byte *srcBuffer, int16 height, int16 width, uint16 srcPitch, uint16 dstPitch) const;
|
||||
void blitTranstableMirrored(byte *dstBuffer, byte *srcBuffer, int16 height, int16 width, uint16 srcPitch, uint16 dstPitch) const;
|
||||
void blitMirrored (byte *dstBuffer, byte *srcBuffer, int16 height, int16 width, uint16 srcPitch, uint16 dstPitch) const;
|
||||
void blitMirroredColorKey (byte *dstBuffer, byte *srcBuffer, int16 height, int16 width, uint16 srcPitch, uint16 dstPitch) const;
|
||||
void blitRaw (byte *dstBuffer, byte *srcBuffer, int16 height, int16 width, uint16 srcPitch, uint16 dstPitch) const;
|
||||
void blitRawColorKey (byte *dstBuffer, byte *srcBuffer, int16 height, int16 width, uint16 srcPitch, uint16 dstPitch) const;
|
||||
void blitCrossfade (byte *dstBuffer, byte *srcBuffer, byte *objectBuffer, int16 height, int16 width, uint16 srcPitch, uint16 dstPitch, uint16 objectPitch) const;
|
||||
void bltMasked (byte *srcBuffer, byte *maskBuffer, int16 height, int16 width, uint16 srcPitch, uint16 maskPitch, byte zoom, byte *dstBuffer, uint16 dstPitch) const;
|
||||
|
||||
// DirectDraw-equivalent functions
|
||||
void blt(Common::Rect *dest, GraphicFrame *frame, Common::Rect *source, int32 flags);
|
||||
void bltFast(int16 dX, int16 dY, GraphicFrame *frame, Common::Rect *source);
|
||||
|
||||
void copyToBackBufferWithTransparency(byte *buffer, int32 pitch, int16 x, int16 y, uint16 width, uint16 height, bool mirrored = false);
|
||||
|
||||
// Debug
|
||||
void drawZoomedMask(byte *mask, uint16 height, uint16 width, uint16 maskPitch);
|
||||
};
|
||||
|
||||
} // end of namespace Asylum
|
||||
|
||||
#endif // ASYLUM_SYSTEM_SCREEN_H
|
||||
407
engines/asylum/system/sound.cpp
Normal file
407
engines/asylum/system/sound.cpp
Normal file
@@ -0,0 +1,407 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/memstream.h"
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
#include "audio/decoders/adpcm.h"
|
||||
#include "audio/decoders/wave.h"
|
||||
|
||||
#include "asylum/system/config.h"
|
||||
#include "asylum/system/sound.h"
|
||||
|
||||
#include "asylum/resources/actor.h"
|
||||
#include "asylum/resources/worldstats.h"
|
||||
|
||||
#include "asylum/views/scene.h"
|
||||
|
||||
#include "asylum/asylum.h"
|
||||
#include "asylum/respack.h"
|
||||
|
||||
namespace Asylum {
|
||||
|
||||
Sound::Sound(AsylumEngine *engine, Audio::Mixer *mixer) : _vm(engine), _mixer(mixer), _musicVolume(-10000) {
|
||||
}
|
||||
|
||||
Sound::~Sound() {
|
||||
cleanupQueue();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Playing sounds & music
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Sound::playSound(ResourceId resourceId, bool looping, int32 volume, int32 panning) {
|
||||
debugC(kDebugLevelSound, "[Sound] Playing Sound 0x%08X", resourceId);
|
||||
|
||||
// Cleanup sound queue
|
||||
cleanupQueue();
|
||||
|
||||
if (volume <= -10000)
|
||||
return;
|
||||
|
||||
if (_vm->checkGameVersion("Demo") && RESOURCE_PACK(resourceId) == kResourcePackSound)
|
||||
resourceId = MAKE_RESOURCE(kResourcePackShared, RESOURCE_INDEX(resourceId));
|
||||
|
||||
SoundQueueItem *item = getItem(resourceId);
|
||||
if (item) {
|
||||
// Duplicate the queue entry
|
||||
item = addToQueue(item->resourceId);
|
||||
} else {
|
||||
// Check that the sound is valid
|
||||
if (!isValidSoundResource(resourceId))
|
||||
return;
|
||||
|
||||
item = addToQueue(resourceId);
|
||||
}
|
||||
|
||||
// Original sets position back to 0
|
||||
_mixer->stopHandle(item->handle);
|
||||
|
||||
Audio::Mixer::SoundType soundType;
|
||||
switch (RESOURCE_PACK(resourceId)) {
|
||||
case kResourcePackShared:
|
||||
soundType = Audio::Mixer::kPlainSoundType;
|
||||
break;
|
||||
|
||||
case kResourcePackSpeech:
|
||||
case kResourcePackSharedSound:
|
||||
soundType = Audio::Mixer::kSpeechSoundType;
|
||||
break;
|
||||
|
||||
default:
|
||||
soundType = Audio::Mixer::kSFXSoundType;
|
||||
break;
|
||||
}
|
||||
|
||||
ResourceEntry *resource = getResource()->get(resourceId);
|
||||
playSoundData(soundType, &item->handle, resource->data, resource->size, looping, volume, panning);
|
||||
}
|
||||
|
||||
void Sound::playMusic(ResourceId resourceId, int32 volume) {
|
||||
debugC(kDebugLevelSound, "[Sound] Playing Music 0x%08X", resourceId);
|
||||
if (resourceId == kResourceNone) {
|
||||
stopMusic();
|
||||
return;
|
||||
}
|
||||
|
||||
// Sets the music volume
|
||||
setMusicVolume(volume);
|
||||
|
||||
// Check if music is already playing
|
||||
if (_mixer->isSoundHandleActive(_musicHandle))
|
||||
stopMusic();
|
||||
|
||||
if (!isValidSoundResource(resourceId))
|
||||
return;
|
||||
|
||||
ResourceEntry *resource = getResource()->get(resourceId);
|
||||
playSoundData(Audio::Mixer::kMusicSoundType, &_musicHandle, resource->data, resource->size, true, volume, 0);
|
||||
}
|
||||
|
||||
void Sound::changeMusic(int32 index, int32 musicStatusExt) {
|
||||
if (index != getWorld()->musicCurrentResourceIndex) {
|
||||
getWorld()->musicResourceIndex = index;
|
||||
getWorld()->musicStatusExt = musicStatusExt;
|
||||
getWorld()->musicFlag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool Sound::isPlaying(ResourceId resourceId) {
|
||||
return (getPlayingItem(resourceId) != nullptr);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Volume & panning
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Sound::setVolume(ResourceId resourceId, int32 volume) {
|
||||
SoundQueueItem *item = getPlayingItem(resourceId);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
convertVolumeFrom(volume);
|
||||
|
||||
_mixer->setChannelVolume(item->handle, (byte)volume);
|
||||
}
|
||||
|
||||
void Sound::setMusicVolume(int32 volume) {
|
||||
if (volume < -10000)
|
||||
return;
|
||||
|
||||
// Save music volume (we need to be able to return it to the logic code
|
||||
_musicVolume = volume;
|
||||
|
||||
convertVolumeFrom(volume);
|
||||
|
||||
_mixer->setChannelVolume(_musicHandle, (byte)volume);
|
||||
}
|
||||
|
||||
void Sound::setPanning(ResourceId resourceId, int32 panning) {
|
||||
if (Config.performance == 1)
|
||||
return;
|
||||
|
||||
SoundQueueItem *item = getPlayingItem(resourceId);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
convertPan(panning);
|
||||
|
||||
_mixer->setChannelBalance(item->handle, (int8)panning);
|
||||
}
|
||||
|
||||
int32 Sound::calculateVolumeAdjustement(const Common::Point &point, int32 attenuation, int32 delta) {
|
||||
if (!attenuation)
|
||||
return -(delta * delta);
|
||||
|
||||
Actor *player = getScene()->getActor();
|
||||
Common::Point adjusted(point);
|
||||
Common::Point sumPlayer = *player->getPoint1() + *player->getPoint2();
|
||||
|
||||
if (getSharedData()->getGlobalPoint().x == -1)
|
||||
adjusted -= sumPlayer;
|
||||
else
|
||||
adjusted -= getSharedData()->getGlobalPoint();
|
||||
|
||||
int32 adjustedVolume = getAdjustedVolume(adjusted.x * adjusted.x + adjusted.y * adjusted.y);
|
||||
|
||||
Common::Rational invAtt(100, attenuation);
|
||||
Common::Rational v;
|
||||
if (invAtt.toInt())
|
||||
v = Common::Rational(adjustedVolume, 1) / invAtt;
|
||||
else
|
||||
v = Common::Rational(delta, 1);
|
||||
|
||||
int32 volume = (v.toInt() - delta) * (v.toInt() - delta);
|
||||
|
||||
if (volume > 10000)
|
||||
return -10000;
|
||||
|
||||
return -volume;
|
||||
}
|
||||
|
||||
int32 Sound::getAdjustedVolume(int32 volume) const {
|
||||
if (volume < 2)
|
||||
return volume;
|
||||
|
||||
uint32 counter = (uint32)(log((double)volume) / log(2.0)) / 2;
|
||||
uint32 adjustedVolume = (uint32)pow(2.0, (int32)counter);
|
||||
|
||||
uint32 offset = adjustedVolume;
|
||||
uint32 base = adjustedVolume << counter;
|
||||
|
||||
for (;;) {
|
||||
--counter;
|
||||
if ((int32)counter < 0)
|
||||
break;
|
||||
|
||||
offset /= 2;
|
||||
uint32 val = base + ((offset + 2 * (uint32)volume) << counter);
|
||||
|
||||
if (val <= (uint32)volume) {
|
||||
adjustedVolume += offset;
|
||||
base = val;
|
||||
}
|
||||
}
|
||||
|
||||
return adjustedVolume;
|
||||
}
|
||||
|
||||
int32 Sound::calculatePanningAtPoint(const Common::Point &point) {
|
||||
// point.y does not seem to be used at all :S
|
||||
|
||||
int delta = point.x - getWorld()->xLeft;
|
||||
|
||||
if (delta < 0)
|
||||
return (getWorld()->reverseStereo ? 10000 : -10000);
|
||||
|
||||
if (delta >= 640)
|
||||
return (getWorld()->reverseStereo ? -10000 : 10000);
|
||||
|
||||
|
||||
int sign, absDelta;
|
||||
if (delta > 320) {
|
||||
absDelta = delta - 320;
|
||||
sign = (getWorld()->reverseStereo ? -1 : 1);
|
||||
} else {
|
||||
absDelta = 320 - delta;
|
||||
sign = (getWorld()->reverseStereo ? 1 : -1);
|
||||
}
|
||||
|
||||
Common::Rational v(absDelta, 6);
|
||||
int32 volume = v.toInt() * v.toInt();
|
||||
|
||||
if (volume > 10000)
|
||||
volume = 10000;
|
||||
|
||||
return volume * sign;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Stopping sounds
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void Sound::stop(ResourceId resourceId) {
|
||||
SoundQueueItem *item = getPlayingItem(resourceId);
|
||||
|
||||
if (item != nullptr)
|
||||
_mixer->stopHandle(item->handle);
|
||||
}
|
||||
|
||||
void Sound::stopAll(ResourceId resourceId) {
|
||||
for (auto &sound : _soundQueue)
|
||||
if (sound.resourceId == resourceId)
|
||||
_mixer->stopHandle(sound.handle);
|
||||
}
|
||||
|
||||
void Sound::stopAll() {
|
||||
for (auto &sound : _soundQueue)
|
||||
_mixer->stopHandle(sound.handle);
|
||||
}
|
||||
|
||||
void Sound::stopMusic() {
|
||||
_mixer->stopHandle(_musicHandle);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Helper functions
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Sound::playSoundData(Audio::Mixer::SoundType type, Audio::SoundHandle *handle, byte *soundData, uint32 soundDataLength, bool loop, int32 vol, int32 pan) {
|
||||
Common::MemoryReadStream *stream = new Common::MemoryReadStream(soundData, soundDataLength);
|
||||
Audio::RewindableAudioStream *sndStream = Audio::makeWAVStream(stream, DisposeAfterUse::YES);
|
||||
|
||||
// Convert volume and panning
|
||||
convertVolumeFrom(vol);
|
||||
convertPan(pan);
|
||||
|
||||
_mixer->playStream(type, handle, Audio::makeLoopingAudioStream(sndStream, loop ? 0 : 1), -1, (byte)vol, (int8)pan);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Sound buffer
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SoundQueueItem *Sound::getItem(ResourceId resourceId) {
|
||||
for (uint32 i = 0; i < _soundQueue.size(); i++)
|
||||
if (resourceId == _soundQueue[i].resourceId)
|
||||
return &_soundQueue[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SoundQueueItem *Sound::getPlayingItem(ResourceId resourceId) {
|
||||
for (uint32 i = 0; i < _soundQueue.size(); i++)
|
||||
if (resourceId == _soundQueue[i].resourceId
|
||||
&& _mixer->isSoundHandleActive(_soundQueue[i].handle))
|
||||
return &_soundQueue[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SoundQueueItem *Sound::addToQueue(ResourceId resourceId) {
|
||||
debugC(kDebugLevelSound, "[Sound] Queueing Sound 0x%08X", resourceId);
|
||||
SoundQueueItem sound;
|
||||
sound.resourceId = resourceId;
|
||||
_soundQueue.push_back(sound);
|
||||
|
||||
return &_soundQueue.back();
|
||||
}
|
||||
|
||||
void Sound::cleanupQueue() {
|
||||
for (uint i = 0; i < _soundQueue.size(); i++) {
|
||||
if (_mixer->isSoundHandleActive(_soundQueue[i].handle))
|
||||
continue;
|
||||
|
||||
// Remove the finished sound from the queue
|
||||
_soundQueue.remove_at(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Helper functions
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool Sound::isValidSoundResource(ResourceId resourceId) {
|
||||
ResourceEntry *entry = getResource()->get(resourceId);
|
||||
|
||||
if (memcmp(entry->data, "RIFF", 4) != 0)
|
||||
return false;
|
||||
|
||||
if (memcmp(&entry->data[8], "WAVE", 4) != 0)
|
||||
return false;
|
||||
|
||||
// Original checks for "fmt " and "data" tags and return values to the calling function
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Conversion functions
|
||||
//
|
||||
// Those are from engines/agos/sound.cpp (FIXME: Move to common code?)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Sound::convertVolumeFrom(int32 &vol) {
|
||||
// DirectSound was originally used, which specifies volume
|
||||
// and panning differently than ScummVM does, using a logarithmic scale
|
||||
// rather than a linear one.
|
||||
//
|
||||
// Volume is a value between -10,000 and 0.
|
||||
//
|
||||
// In both cases, the -10,000 represents -100 dB. When panning, only
|
||||
// one speaker's volume is affected - just like in ScummVM - with
|
||||
// negative values affecting the left speaker, and positive values
|
||||
// affecting the right speaker. Thus -10,000 means the left speaker is
|
||||
// silent.
|
||||
|
||||
int32 v = CLIP<int32>(vol, -10000, 0);
|
||||
if (v) {
|
||||
vol = (int)((double)Audio::Mixer::kMaxChannelVolume * pow(10.0, (double)v / 2000.0) + 0.5);
|
||||
} else {
|
||||
vol = Audio::Mixer::kMaxChannelVolume;
|
||||
}
|
||||
}
|
||||
|
||||
void Sound::convertVolumeTo(int32 &vol) {
|
||||
vol = vol ? (int32)log10((vol - 0.5) / Audio::Mixer::kMaxChannelVolume) * 2000 : -9999;
|
||||
}
|
||||
|
||||
void Sound::convertPan(int32 &pan) {
|
||||
// DirectSound was originally used, which specifies volume
|
||||
// and panning differently than ScummVM does, using a logarithmic scale
|
||||
// rather than a linear one.
|
||||
//
|
||||
// Panning is a value between -10,000 and 10,000.
|
||||
//
|
||||
// In both cases, the -10,000 represents -100 dB. When panning, only
|
||||
// one speaker's volume is affected - just like in ScummVM - with
|
||||
// negative values affecting the left speaker, and positive values
|
||||
// affecting the right speaker. Thus -10,000 means the left speaker is
|
||||
// silent.
|
||||
|
||||
int32 p = CLIP<int32>(pan, -10000, 10000);
|
||||
if (p < 0) {
|
||||
pan = 129 * (1 - pow(10.0, p / 5000.0));
|
||||
} else {
|
||||
pan = -129 * (1 - pow(10.0, p / -5000.0));
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace Asylum
|
||||
339
engines/asylum/system/sound.h
Normal file
339
engines/asylum/system/sound.h
Normal file
@@ -0,0 +1,339 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ASYLUM_SYSTEM_SOUND_H
|
||||
#define ASYLUM_SYSTEM_SOUND_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
#include "audio/mixer.h"
|
||||
|
||||
#include "asylum/system/config.h"
|
||||
|
||||
#include "asylum/shared.h"
|
||||
|
||||
namespace Asylum {
|
||||
|
||||
class AsylumEngine;
|
||||
|
||||
struct ResourceEntry;
|
||||
|
||||
struct SoundItem {
|
||||
ResourceId resourceId;
|
||||
int32 field_4;
|
||||
int32 field_8;
|
||||
int32 field_C;
|
||||
|
||||
SoundItem() {
|
||||
resourceId = kResourceNone;
|
||||
field_4 = 0;
|
||||
field_8 = 0;
|
||||
field_C = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct FrameSoundItem {
|
||||
ResourceId resourceId;
|
||||
uint32 frameIndex;
|
||||
int32 index;
|
||||
int32 field_C;
|
||||
int32 field_10;
|
||||
int32 field_14;
|
||||
|
||||
FrameSoundItem() {
|
||||
resourceId = kResourceNone;
|
||||
frameIndex = 0;
|
||||
index = 0;
|
||||
field_C = 0;
|
||||
field_10 = 0;
|
||||
field_14 = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct AmbientSoundItem {
|
||||
int32 field_0;
|
||||
int32 flags;
|
||||
ResourceId resourceId;
|
||||
int32 delta;
|
||||
int32 attenuation;
|
||||
int32 nextTick;
|
||||
int32 flagNum[6];
|
||||
Common::Point point;
|
||||
|
||||
AmbientSoundItem() {
|
||||
field_0 = 0;
|
||||
flags = 0;
|
||||
resourceId = kResourceNone;
|
||||
delta = 0;
|
||||
attenuation = 0;
|
||||
nextTick = 0;
|
||||
memset(&flagNum, 0, sizeof(flagNum));
|
||||
}
|
||||
};
|
||||
|
||||
struct SoundQueueItem {
|
||||
ResourceId resourceId;
|
||||
Audio::SoundHandle handle;
|
||||
|
||||
SoundQueueItem() {
|
||||
resourceId = kResourceNone;
|
||||
}
|
||||
};
|
||||
|
||||
class Sound {
|
||||
public:
|
||||
Sound(AsylumEngine *engine, Audio::Mixer *mixer);
|
||||
~Sound();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Playing sounds & music
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Play sound
|
||||
*
|
||||
* @param resourceId Identifier for the resource.
|
||||
* @param looping true to looping.
|
||||
* @param volume The volume.
|
||||
* @param panning The panning.
|
||||
*/
|
||||
void playSound(ResourceId resourceId, bool looping = false, int32 volume = Config.sfxVolume, int32 panning = 0);
|
||||
|
||||
/**
|
||||
* Play music
|
||||
*
|
||||
* @param resourceId Identifier for the resource.
|
||||
* @param volume The volume.
|
||||
*/
|
||||
void playMusic(ResourceId resourceId, int32 volume = Config.musicVolume);
|
||||
|
||||
/**
|
||||
* Change music
|
||||
*
|
||||
* @param index Zero-based index of the music
|
||||
* @param musicStatusExt The music status.
|
||||
*/
|
||||
void changeMusic(int32 index, int32 musicStatusExt);
|
||||
|
||||
/**
|
||||
* Query if a sound with the resource id is playing.
|
||||
*
|
||||
* @param resourceId Identifier for the resource.
|
||||
*
|
||||
* @return true if playing, false if not.
|
||||
*/
|
||||
bool isPlaying(ResourceId resourceId);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Volume & panning
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Sets the volume for a buffered sound resource
|
||||
*
|
||||
* @param resourceId Identifier for the resource.
|
||||
* @param volume The volume.
|
||||
*/
|
||||
void setVolume(ResourceId resourceId, int32 volume);
|
||||
|
||||
/**
|
||||
* Sets the music volume.
|
||||
*
|
||||
* @param volume The volume.
|
||||
*/
|
||||
void setMusicVolume(int32 volume);
|
||||
|
||||
/**
|
||||
* Gets the music volume.
|
||||
*
|
||||
* @return The music volume.
|
||||
*/
|
||||
int32 getMusicVolume() { return _musicVolume; }
|
||||
|
||||
/**
|
||||
* Sets the panning for a buffered sound resource
|
||||
*
|
||||
* @param resourceId Identifier for the resource.
|
||||
* @param panning The panning.
|
||||
*/
|
||||
void setPanning(ResourceId resourceId, int32 panning);
|
||||
|
||||
/**
|
||||
* Determine the amount to increase the supplied sound sample's volume based on the position.
|
||||
*
|
||||
* @param point The coordinates
|
||||
* @param attenuation The attenuation.
|
||||
* @param delta The delta.
|
||||
*
|
||||
* @return The calculated volume adjustement.
|
||||
*/
|
||||
int32 calculateVolumeAdjustement(const Common::Point &point, int32 attenuation, int32 delta);
|
||||
|
||||
/**
|
||||
* Gets an adjusted volume.
|
||||
*
|
||||
* @param volume The volume.
|
||||
*
|
||||
* @return The adjusted volume.
|
||||
*/
|
||||
int32 getAdjustedVolume(int32 volume) const;
|
||||
|
||||
/**
|
||||
* Calculates the panning at point.
|
||||
*
|
||||
* @param point The coordinates.
|
||||
*
|
||||
* @return The calculated panning at point.
|
||||
*/
|
||||
int32 calculatePanningAtPoint(const Common::Point &point);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Stopping sounds
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Stop the first playing sound with the ResourceId
|
||||
*
|
||||
* @param resourceId Identifier for the resource.
|
||||
*/
|
||||
void stop(ResourceId resourceId);
|
||||
|
||||
/**
|
||||
* Stop all sounds with the ResourceId
|
||||
*
|
||||
* @param resourceId Identifier for the resource.
|
||||
*/
|
||||
void stopAll(ResourceId resourceId);
|
||||
|
||||
/**
|
||||
* Stop all buffered sounds
|
||||
*/
|
||||
void stopAll();
|
||||
|
||||
/**
|
||||
* Stop music.
|
||||
*/
|
||||
void stopMusic();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Conversion functions
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Convert volume to a ScummVM mixer value
|
||||
*
|
||||
* @param [in,out] vol The volume.
|
||||
*/
|
||||
static void convertVolumeFrom(int32 &vol);
|
||||
|
||||
/**
|
||||
* Convert ScummVM mixer value to a volume
|
||||
*
|
||||
* @param [in,out] vol The volume.
|
||||
*/
|
||||
static void convertVolumeTo(int32 &vol);
|
||||
|
||||
private:
|
||||
AsylumEngine *_vm;
|
||||
|
||||
Audio::Mixer *_mixer;
|
||||
|
||||
Audio::SoundHandle _musicHandle;
|
||||
int32 _musicVolume;
|
||||
|
||||
Common::Array<SoundQueueItem> _soundQueue;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Sound queue
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Find the index within the sound queue of the sound sample with provided id.
|
||||
*
|
||||
* @param resourceId Identifier for the resource.
|
||||
*
|
||||
* @return The item.
|
||||
*/
|
||||
SoundQueueItem *getItem(ResourceId resourceId);
|
||||
|
||||
/**
|
||||
* Find the index within the sound queue of the playing sound sample with provided id.
|
||||
*
|
||||
* @param resourceId Identifier for the resource.
|
||||
*
|
||||
* @return The playing item.
|
||||
*/
|
||||
SoundQueueItem *getPlayingItem(ResourceId resourceId);
|
||||
|
||||
/**
|
||||
* Adds a sound to the sound queue.
|
||||
*
|
||||
* @param resourceId Identifier for the resource.
|
||||
*
|
||||
* @return the sound buffer item
|
||||
*/
|
||||
SoundQueueItem *addToQueue(ResourceId resourceId);
|
||||
|
||||
/**
|
||||
* Clears the sound queue from finished sounds
|
||||
*/
|
||||
void cleanupQueue();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Helper functions
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Checks if the sound file is valid
|
||||
*
|
||||
* @return true if valid, false if not.
|
||||
*/
|
||||
bool isValidSoundResource(ResourceId resourceId);
|
||||
|
||||
/**
|
||||
* Play sound data.
|
||||
*
|
||||
* @param type The type.
|
||||
* @param handle The handle.
|
||||
* @param soundData The sound data
|
||||
* @param soundDataLength Length of the sound data.
|
||||
* @param loop true to loop.
|
||||
* @param vol The volume.
|
||||
* @param pan The pan.
|
||||
*/
|
||||
void playSoundData(Audio::Mixer::SoundType type, Audio::SoundHandle *handle, byte *soundData, uint32 soundDataLength, bool loop = false, int32 vol = 0, int32 pan = 0);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Conversion functions
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Convert pan.
|
||||
*
|
||||
* @param [in,out] pan The pan.
|
||||
*/
|
||||
static void convertPan(int32 &pan);
|
||||
};
|
||||
|
||||
} // end of namespace Asylum
|
||||
|
||||
#endif // ASYLUM_SYSTEM_SOUND_H
|
||||
287
engines/asylum/system/speech.cpp
Normal file
287
engines/asylum/system/speech.cpp
Normal file
@@ -0,0 +1,287 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "asylum/system/speech.h"
|
||||
|
||||
#include "asylum/resources/actor.h"
|
||||
#include "asylum/resources/worldstats.h"
|
||||
|
||||
#include "asylum/system/text.h"
|
||||
|
||||
#include "asylum/views/scene.h"
|
||||
|
||||
#include "asylum/asylum.h"
|
||||
#include "asylum/staticres.h"
|
||||
|
||||
namespace Asylum {
|
||||
|
||||
Speech::Speech(AsylumEngine *engine): _vm(engine), _textData(nullptr), _textDataPos(nullptr) {
|
||||
_tick = _vm->getTick();
|
||||
_soundResourceId = kResourceNone;
|
||||
_textResourceId = kResourceNone;
|
||||
}
|
||||
|
||||
ResourceId Speech::play(ResourceId soundResourceId, ResourceId textResourceId) {
|
||||
if (soundResourceId)
|
||||
if (getSound()->isPlaying(_soundResourceId))
|
||||
getSound()->stopAll(_soundResourceId);
|
||||
|
||||
_soundResourceId = soundResourceId;
|
||||
_textResourceId = textResourceId;
|
||||
|
||||
prepareSpeech();
|
||||
|
||||
return soundResourceId;
|
||||
}
|
||||
|
||||
ResourceId Speech::playIndexed(int32 index) {
|
||||
int processedIndex;
|
||||
|
||||
if (_vm->checkGameVersion("Demo")) {
|
||||
switch (index) {
|
||||
default:
|
||||
case 1:
|
||||
processedIndex = 43 + _vm->getRandom(5);
|
||||
break;
|
||||
case 3:
|
||||
processedIndex = 58 + _vm->getRandom(5);
|
||||
break;
|
||||
}
|
||||
} else if (getWorld()->actorType || index != -1) {
|
||||
processedIndex = (int)speechIndex[index + 5 * getWorld()->actorType] + (int)rnd(speechIndexRandom[index + 5 * getWorld()->actorType]);
|
||||
} else {
|
||||
switch (_vm->getRandom(3)) {
|
||||
default:
|
||||
case 0:
|
||||
processedIndex = 23;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
processedIndex = 400;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
processedIndex = 401;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
processedIndex = index;
|
||||
break;
|
||||
}
|
||||
|
||||
if (processedIndex >= 259)
|
||||
processedIndex -=9;
|
||||
}
|
||||
|
||||
switch (getWorld()->actorType) {
|
||||
default:
|
||||
break;
|
||||
|
||||
case kActorMax:
|
||||
if (_vm->checkGameVersion("Demo"))
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, processedIndex), MAKE_RESOURCE(kResourcePackText, processedIndex - 1));
|
||||
else
|
||||
return play(MAKE_RESOURCE(kResourcePackSpeech, processedIndex), MAKE_RESOURCE(kResourcePackText, processedIndex + 83));
|
||||
|
||||
case kActorSarah:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, processedIndex + 1927), MAKE_RESOURCE(kResourcePackText, processedIndex + 586));
|
||||
|
||||
case kActorCyclops:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, processedIndex + 2084), MAKE_RESOURCE(kResourcePackText, processedIndex + 743));
|
||||
|
||||
case kActorAztec:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, processedIndex + 2234), MAKE_RESOURCE(kResourcePackText, processedIndex + 893));
|
||||
}
|
||||
|
||||
return kResourceNone;
|
||||
}
|
||||
|
||||
ResourceId Speech::playScene(int32 type, int32 index) {
|
||||
switch (type) {
|
||||
default:
|
||||
play(kResourceNone, kResourceNone);
|
||||
break;
|
||||
|
||||
case 0:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 2363), MAKE_RESOURCE(kResourcePackText, index + 1022));
|
||||
|
||||
case 1:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 2366), MAKE_RESOURCE(kResourcePackText, index + 1025));
|
||||
|
||||
case 2:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 2371), MAKE_RESOURCE(kResourcePackText, index + 1030));
|
||||
|
||||
case 3:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 2398), MAKE_RESOURCE(kResourcePackText, index + 1057));
|
||||
|
||||
case 4:
|
||||
return play(MAKE_RESOURCE(kResourcePackSpeech, index + 503), MAKE_RESOURCE(kResourcePackText, index + 1060));
|
||||
|
||||
case 5:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 2401), MAKE_RESOURCE(kResourcePackText, index + 1068));
|
||||
|
||||
case 6:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 2409), MAKE_RESOURCE(kResourcePackText, index + 1076));
|
||||
|
||||
case 7:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 2415), MAKE_RESOURCE(kResourcePackText, index + 1082));
|
||||
|
||||
case 8:
|
||||
return play(MAKE_RESOURCE(kResourcePackSpeech, index + 511), MAKE_RESOURCE(kResourcePackText, index + 1084));
|
||||
|
||||
case 9:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 2417), MAKE_RESOURCE(kResourcePackText, index + 1088));
|
||||
|
||||
case 10:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 2417), MAKE_RESOURCE(kResourcePackText, index + 1093));
|
||||
|
||||
case 11:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 2424), MAKE_RESOURCE(kResourcePackText, index + 1100));
|
||||
|
||||
case 12:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 2424), MAKE_RESOURCE(kResourcePackText, index + 1102));
|
||||
|
||||
case 13:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 2430), MAKE_RESOURCE(kResourcePackText, index + 1108));
|
||||
|
||||
case 14:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 2432), MAKE_RESOURCE(kResourcePackText, index + 1110));
|
||||
|
||||
case 15:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 2434), MAKE_RESOURCE(kResourcePackText, index + 1112));
|
||||
|
||||
case 16:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 2435), MAKE_RESOURCE(kResourcePackText, index + 1113));
|
||||
|
||||
case 17:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 2436), MAKE_RESOURCE(kResourcePackText, index + 1114));
|
||||
|
||||
case 18:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 2438), MAKE_RESOURCE(kResourcePackText, index + 1116));
|
||||
|
||||
case 19:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 2439), MAKE_RESOURCE(kResourcePackText, index + 1117));
|
||||
}
|
||||
|
||||
return kResourceNone;
|
||||
}
|
||||
|
||||
ResourceId Speech::playPlayer(int32 index) {
|
||||
switch (getWorld()->actorType) {
|
||||
default:
|
||||
break;
|
||||
|
||||
case kActorMax: {
|
||||
int32 soundResourceIndex = index;
|
||||
int32 textResourceIndex = index;
|
||||
|
||||
if (index >= 259) {
|
||||
soundResourceIndex -= 9;
|
||||
textResourceIndex -= 9;
|
||||
}
|
||||
|
||||
ResourceId soundResourceId;
|
||||
if (_vm->checkGameVersion("Demo")) {
|
||||
soundResourceId = MAKE_RESOURCE(kResourcePackSharedSound, soundResourceIndex + 21 + 7 * _vm->isAltDemo());
|
||||
return play(soundResourceId, MAKE_RESOURCE(kResourcePackText, textResourceIndex + 20));
|
||||
} else {
|
||||
soundResourceId = MAKE_RESOURCE(kResourcePackSpeech, soundResourceIndex);
|
||||
return play(soundResourceId, MAKE_RESOURCE(kResourcePackText, textResourceIndex + 83));
|
||||
}
|
||||
}
|
||||
|
||||
case kActorSarah:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 1927), MAKE_RESOURCE(kResourcePackText, index + 586));
|
||||
|
||||
case kActorCyclops:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 2084), MAKE_RESOURCE(kResourcePackText, index + 743));
|
||||
|
||||
case kActorAztec:
|
||||
return play(MAKE_RESOURCE(kResourcePackSharedSound, index + 2234), MAKE_RESOURCE(kResourcePackText, index + 893));
|
||||
}
|
||||
|
||||
return kResourceNone;
|
||||
}
|
||||
|
||||
void Speech::resetResourceIds() {
|
||||
_soundResourceId = kResourceNone;
|
||||
_textResourceId = kResourceNone;
|
||||
}
|
||||
|
||||
void Speech::resetTextData() {
|
||||
_textData = nullptr;
|
||||
_textDataPos = nullptr;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Private methods
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Speech::prepareSpeech() {
|
||||
int32 startTick = _vm->getTick();
|
||||
|
||||
if (_soundResourceId) {
|
||||
if (!getSound()->isPlaying(_soundResourceId) || (_tick && startTick >= _tick))
|
||||
process();
|
||||
|
||||
if (Config.showEncounterSubtitles) {
|
||||
Common::Point point;
|
||||
Actor *actor = getScene()->getActor();
|
||||
actor->adjustCoordinates(&point);
|
||||
|
||||
int16 posY = (point.y >= 240) ? 40 : 320;
|
||||
|
||||
getText()->draw(_textDataPos, getWorld()->font3, posY);
|
||||
getText()->draw(_textData, getWorld()->font1, posY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Speech::process() {
|
||||
_tick = 0;
|
||||
|
||||
char *txt = getText()->get(_textResourceId);
|
||||
|
||||
if (*(txt + strlen((const char *)txt) - 2) == 1) {
|
||||
_textResourceId = kResourceNone;
|
||||
_textData = nullptr;
|
||||
_textDataPos = nullptr;
|
||||
} else if (*txt == '{') {
|
||||
_textData = txt + 3;
|
||||
_textDataPos = nullptr;
|
||||
|
||||
getText()->loadFont(getWorld()->font1);
|
||||
getSound()->playSound(_soundResourceId, false, Config.voiceVolume, 0);
|
||||
} else {
|
||||
_textData = nullptr;
|
||||
_textDataPos = txt;
|
||||
|
||||
if (*txt == '/') {
|
||||
_textDataPos = txt + 2;
|
||||
}
|
||||
|
||||
getText()->loadFont(getWorld()->font3);
|
||||
getSound()->playSound(_soundResourceId, false, Config.voiceVolume, 0);
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace Asylum
|
||||
179
engines/asylum/system/speech.h
Normal file
179
engines/asylum/system/speech.h
Normal file
@@ -0,0 +1,179 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ASYLUM_SYSTEM_SPEECH_H
|
||||
#define ASYLUM_SYSTEM_SPEECH_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
#include "asylum/shared.h"
|
||||
|
||||
namespace Asylum {
|
||||
|
||||
class AsylumEngine;
|
||||
|
||||
class Speech {
|
||||
public:
|
||||
Speech(AsylumEngine *engine);
|
||||
~Speech() {};
|
||||
|
||||
/**
|
||||
* Play speech
|
||||
*
|
||||
* @param soundResourceId The sound resource id.
|
||||
* @param textResourceId The text resource id.
|
||||
*/
|
||||
ResourceId play(ResourceId soundResourceId, ResourceId textResourceId);
|
||||
|
||||
/**
|
||||
* Prepare speech to play
|
||||
* - Process sound speech and draws dialog in screen
|
||||
*/
|
||||
void prepareSpeech();
|
||||
|
||||
/**
|
||||
* Play speech by index offset.
|
||||
*
|
||||
* @param index The index offset.
|
||||
*
|
||||
* @return the ResourceId for the sound played
|
||||
*/
|
||||
ResourceId playIndexed(int32 index);
|
||||
|
||||
/**
|
||||
* Play scene speech.
|
||||
*
|
||||
* @param type The type of speech to play.
|
||||
* @param index The index offset.
|
||||
*
|
||||
* @return the ResourceId for the sound played
|
||||
*/
|
||||
ResourceId playScene(int32 type, int32 index);
|
||||
|
||||
/**
|
||||
* Play speech by index offset (based on player type)
|
||||
*
|
||||
* @param index The index offset.
|
||||
*
|
||||
* @return the ResourceId for the sound played
|
||||
*/
|
||||
ResourceId playPlayer(int32 index);
|
||||
|
||||
/**
|
||||
* Resets the resource identifiers.
|
||||
*/
|
||||
void resetResourceIds();
|
||||
|
||||
/**
|
||||
* Resets text data
|
||||
*/
|
||||
void resetTextData();
|
||||
|
||||
/**
|
||||
* Gets the sound resource identifier.
|
||||
*
|
||||
* @return The sound resource identifier.
|
||||
*/
|
||||
ResourceId getSoundResourceId() const { return _soundResourceId; }
|
||||
|
||||
/**
|
||||
* Sets the tick.
|
||||
*
|
||||
* @param val The value.
|
||||
*/
|
||||
void setTick(int32 val) { _tick = val;}
|
||||
|
||||
/**
|
||||
* Gets the tick.
|
||||
*
|
||||
* @return The tick.
|
||||
*/
|
||||
uint32 getTick() { return _tick; }
|
||||
|
||||
/**
|
||||
* Sets the sound resource identifier
|
||||
*
|
||||
* @param id The sound resource identifier.
|
||||
*/
|
||||
void setSoundResourceId(ResourceId id) { _soundResourceId = id; }
|
||||
|
||||
/**
|
||||
* Sets the text resource identifier
|
||||
*
|
||||
* @param id The text resource identifier.
|
||||
*/
|
||||
void setTextResourceId(ResourceId id) { _textResourceId = id; }
|
||||
|
||||
/**
|
||||
* Gets the text resource identifier.
|
||||
*
|
||||
* @return The text resource identifier.
|
||||
*/
|
||||
ResourceId getTextResourceId() { return _textResourceId; }
|
||||
|
||||
/**
|
||||
* Sets text data.
|
||||
*
|
||||
* @param text The text.
|
||||
*/
|
||||
void setTextData(char *text) { _textData = text; }
|
||||
|
||||
/**
|
||||
* Get text data
|
||||
*
|
||||
* @return the text data
|
||||
*/
|
||||
char *getTextData() { return _textData; }
|
||||
|
||||
/**
|
||||
* Sets text data position.
|
||||
*
|
||||
* @param text The text.
|
||||
*/
|
||||
void setTextDataPos(char *text) { _textDataPos = text; }
|
||||
|
||||
/**
|
||||
* Get text data position
|
||||
*
|
||||
* @return the text data position
|
||||
*/
|
||||
char *getTextDataPos() { return _textDataPos; }
|
||||
|
||||
private:
|
||||
AsylumEngine *_vm;
|
||||
|
||||
int32 _tick;
|
||||
char *_textData;
|
||||
char *_textDataPos;
|
||||
|
||||
ResourceId _soundResourceId;
|
||||
ResourceId _textResourceId;
|
||||
|
||||
/**
|
||||
* Process speech and prepare for display
|
||||
*/
|
||||
void process();
|
||||
|
||||
};
|
||||
|
||||
} // end of namespace Asylum
|
||||
|
||||
#endif // ASYLUM_SYSTEM_SPEECH_H
|
||||
428
engines/asylum/system/text.cpp
Normal file
428
engines/asylum/system/text.cpp
Normal file
@@ -0,0 +1,428 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/rational.h"
|
||||
#include "common/unicode-bidi.h"
|
||||
|
||||
#include "asylum/system/text.h"
|
||||
|
||||
#include "asylum/system/graphics.h"
|
||||
#include "asylum/system/screen.h"
|
||||
|
||||
#include "asylum/asylum.h"
|
||||
#include "asylum/respack.h"
|
||||
|
||||
#if defined(USE_FREETYPE2)
|
||||
#include "graphics/fonts/ttf.h"
|
||||
#endif
|
||||
|
||||
namespace Asylum {
|
||||
|
||||
Text::Text(AsylumEngine *engine) : _vm(engine), _fontResource(nullptr), _transTableNum(0), _curFontFlags(0), _chineseFontLoadAttempted(false) {
|
||||
}
|
||||
|
||||
Text::~Text() {
|
||||
delete _fontResource;
|
||||
}
|
||||
|
||||
ResourceId Text::loadFont(ResourceId resourceId) {
|
||||
if (_fontResource && resourceId == _fontResource->getResourceId())
|
||||
return resourceId;
|
||||
|
||||
ResourceId previousFont = _fontResource ? _fontResource->getResourceId() : kResourceNone;
|
||||
|
||||
delete _fontResource;
|
||||
_fontResource = nullptr;
|
||||
|
||||
if (resourceId != kResourceNone) {
|
||||
_fontResource = new GraphicResource(_vm, resourceId);
|
||||
_curFontFlags = Common::Rational(_fontResource->getData().flags, 16).toInt() & 0x0F;
|
||||
}
|
||||
|
||||
return previousFont;
|
||||
}
|
||||
|
||||
void Text::loadChineseFont() {
|
||||
if (_chineseFontLoadAttempted)
|
||||
return;
|
||||
|
||||
_chineseFontLoadAttempted = true;
|
||||
|
||||
#if defined(USE_FREETYPE2)
|
||||
_chineseFont.reset(Graphics::loadTTFFontFromArchive("NotoSansSC-Regular.otf", 16, Graphics::kTTFSizeModeCharacter, 0, 0, Graphics::kTTFRenderModeLight));
|
||||
#endif
|
||||
}
|
||||
|
||||
void Text::setPosition(const Common::Point &point) {
|
||||
_position = point;
|
||||
}
|
||||
|
||||
int16 Text::getWidth(char c) {
|
||||
if (!_fontResource)
|
||||
error("[Text::getWidth] Font not initialized properly");
|
||||
|
||||
GraphicFrame *font = _fontResource->getFrame((uint8)c);
|
||||
|
||||
return (int16)(font->surface.w + font->x - _curFontFlags);
|
||||
}
|
||||
|
||||
int16 Text::getChineseWidth(const Common::U32String &utext) {
|
||||
loadChineseFont();
|
||||
if (!_chineseFont)
|
||||
return 0;
|
||||
|
||||
return _chineseFont->getStringWidth(utext);
|
||||
}
|
||||
|
||||
int16 Text::getWidth(const char *text) {
|
||||
if (!_fontResource)
|
||||
error("[Text::getWidth] font resource hasn't been loaded yet!");
|
||||
|
||||
if (_vm->getLanguage() == Common::Language::ZH_CHN) {
|
||||
return getChineseWidth(Common::U32String(text, Common::CodePage::kGBK));
|
||||
}
|
||||
|
||||
int16 width = 0;
|
||||
char character = *text;
|
||||
|
||||
while (character) {
|
||||
GraphicFrame *font = _fontResource->getFrame((uint8)character);
|
||||
width += (int16)(font->surface.w + font->x - _curFontFlags);
|
||||
|
||||
text++;
|
||||
character = *text;
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
int16 Text::getWidth(const char *text, int16 length) {
|
||||
if (!_fontResource)
|
||||
error("[Text::getWidth] font resource hasn't been loaded yet!");
|
||||
|
||||
if (length == 0)
|
||||
return 0;
|
||||
|
||||
if (_vm->getLanguage() == Common::Language::ZH_CHN) {
|
||||
return getChineseWidth(Common::U32String(text, length, Common::CodePage::kGBK));
|
||||
}
|
||||
|
||||
int16 width = 0;
|
||||
char character = *text;
|
||||
|
||||
while (character && length > 0) {
|
||||
GraphicFrame *font = _fontResource->getFrame((uint8)character);
|
||||
width += (int16)(font->surface.w + font->x - _curFontFlags);
|
||||
|
||||
text++;
|
||||
character = *text;
|
||||
length--;
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
int16 Text::getWidth(ResourceId resourceId) {
|
||||
return getWidth(get(resourceId));
|
||||
}
|
||||
|
||||
char *Text::get(ResourceId resourceId) {
|
||||
ResourceEntry *textRes = getResource()->get(resourceId);
|
||||
return (char *)textRes->data;
|
||||
}
|
||||
|
||||
void Text::drawChar(char character) {
|
||||
if (!_fontResource)
|
||||
error("[Text::drawChar] font resource hasn't been loaded yet!");
|
||||
|
||||
if (_transTableNum) {
|
||||
getScreen()->drawTransparent(_fontResource, (uint8)character, _position, kDrawFlagNone, _transTableNum);
|
||||
} else {
|
||||
getScreen()->draw(_fontResource, (uint8)character, _position);
|
||||
}
|
||||
|
||||
GraphicFrame *fontLetter = _fontResource->getFrame((uint8)character);
|
||||
_position.x += (int16)fontLetter->surface.w + fontLetter->x - _curFontFlags;
|
||||
}
|
||||
|
||||
void Text::drawChinese(const Common::U32String &utext) {
|
||||
loadChineseFont();
|
||||
if (!_chineseFont)
|
||||
return;
|
||||
Graphics::Surface *surf = getScreen()->getSurface();
|
||||
uint8 color = 0;
|
||||
// TODO: Add more colors
|
||||
switch ((uint32_t)_fontResource->getResourceId()) {
|
||||
case 0: // Case to quiet VS C4065 warning
|
||||
default:
|
||||
debug(5, "Unrecognized font resource 0x%x for string %s", _fontResource->getResourceId(), utext.encode().c_str());
|
||||
color = 1;
|
||||
break;
|
||||
case 0x80010039:
|
||||
color = 0xff;
|
||||
break;
|
||||
case 0x8005000d:
|
||||
color = 0x10;
|
||||
break;
|
||||
case 0x8005000e:
|
||||
color = 0x25;
|
||||
break;
|
||||
case 0x8005000f:
|
||||
color = 0x1f;
|
||||
break;
|
||||
case 0x80120012:
|
||||
color = 0x69;
|
||||
break;
|
||||
}
|
||||
|
||||
_chineseFont->drawString(surf, utext, _position.x, _position.y, surf->w - _position.x, color);
|
||||
_position.x += _chineseFont->getStringWidth(utext);
|
||||
}
|
||||
|
||||
void Text::draw(const char *text) {
|
||||
if (!text)
|
||||
return;
|
||||
|
||||
if (_vm->getLanguage() == Common::Language::ZH_CHN) {
|
||||
drawChinese(Common::U32String(text, Common::CodePage::kGBK));
|
||||
return;
|
||||
}
|
||||
|
||||
Common::String textRef;
|
||||
|
||||
if (_vm->getLanguage() == Common::HE_ISR) {
|
||||
textRef = Common::convertBiDiString(text, Common::kWindows1255);
|
||||
text = textRef.c_str();
|
||||
}
|
||||
while (*text) {
|
||||
drawChar(text[0]);
|
||||
text++;
|
||||
}
|
||||
}
|
||||
|
||||
void Text::draw(const char *text, int16 length) {
|
||||
if (length == 0)
|
||||
return;
|
||||
|
||||
if (!text)
|
||||
return;
|
||||
|
||||
if (_vm->getLanguage() == Common::Language::ZH_CHN) {
|
||||
drawChinese(Common::U32String(text, length, Common::CodePage::kGBK));
|
||||
return;
|
||||
}
|
||||
|
||||
if (_vm->getLanguage() == Common::HE_ISR)
|
||||
text = Common::convertBiDiString(Common::String(text, length), Common::kWindows1255).c_str();
|
||||
for (int16 i = 0; i < length; i++)
|
||||
drawChar(text[i]);
|
||||
}
|
||||
|
||||
void Text::draw(ResourceId resourceId) {
|
||||
ResourceEntry *textRes = getResource()->get(resourceId);
|
||||
draw((char *)textRes->data);
|
||||
}
|
||||
|
||||
void Text::draw(const Common::Point &point, const char *text) {
|
||||
setPosition(Common::Point(point.x - (int16)getWidth(text), point.y));
|
||||
draw(text);
|
||||
}
|
||||
|
||||
void Text::draw(const Common::Point &point, ResourceId resourceId) {
|
||||
draw(point, get(resourceId));
|
||||
}
|
||||
|
||||
void Text::draw(const char *text, ResourceId fontResourceId, int16 y) {
|
||||
if (text) {
|
||||
loadFont(fontResourceId);
|
||||
draw(kTextCenter, Common::Point(20, y), 16, 600, text);
|
||||
}
|
||||
}
|
||||
|
||||
int16 Text::draw(TextCentering centering, const Common::Point &point, int16 spacing, int16 width, const char *text) {
|
||||
return draw(0, 99, centering, point, spacing, width, text);
|
||||
}
|
||||
|
||||
int16 Text::draw(int16 a1, int16 a2, TextCentering centering, const Common::Point &point, int16 spacing, int16 width, const char *text) {
|
||||
if (!text || !*text)
|
||||
return 0;
|
||||
|
||||
// TODO: Make non-Chinese into Graphics::Font as well.
|
||||
if (_vm->getLanguage() == Common::Language::ZH_CHN) {
|
||||
Common::Array<Common::U32String> lines;
|
||||
Common::Point coords = point;
|
||||
int16 printed = 0;
|
||||
|
||||
loadChineseFont();
|
||||
if (!_chineseFont)
|
||||
return 0;
|
||||
char *buf = scumm_strdup(text);
|
||||
for (char *ptr = buf; *ptr; ptr++)
|
||||
if (*ptr == 1 || *ptr == 2) // Start of heading (SOH) or start of text (STX)
|
||||
*ptr = '\n';
|
||||
Common::U32String utext(buf, Common::CodePage::kGBK);
|
||||
free(buf);
|
||||
|
||||
_chineseFont->wordWrapText(utext, width, lines);
|
||||
|
||||
for (int index = a1; index <= (a1 + a2) && index < (int)lines.size(); index++) {
|
||||
switch (centering) {
|
||||
default:
|
||||
case kTextCalculate:
|
||||
break;
|
||||
|
||||
case kTextCenter:
|
||||
setPosition(coords + Common::Point((width - getChineseWidth(lines[index])) / 2, 0));
|
||||
drawChinese(lines[index]);
|
||||
break;
|
||||
|
||||
case kTextNormal:
|
||||
setPosition(coords);
|
||||
drawChinese(lines[index]);
|
||||
break;
|
||||
}
|
||||
|
||||
coords.y += spacing;
|
||||
++printed;
|
||||
}
|
||||
|
||||
return printed;
|
||||
}
|
||||
|
||||
Common::Point coords = point;
|
||||
|
||||
int16 printed = 0;
|
||||
bool drawText = false;
|
||||
int32 spaceWidth = 0;
|
||||
int32 index = 0;
|
||||
|
||||
const char *string = text;
|
||||
const char *endText = text;
|
||||
|
||||
for (;;) {
|
||||
label_start:
|
||||
|
||||
int32 charWidth = 0;
|
||||
|
||||
// Draw the text
|
||||
if (drawText) {
|
||||
char currentChar = *endText;
|
||||
|
||||
if (index >= a1 && index <= (a1 + a2)) {
|
||||
switch (centering) {
|
||||
default:
|
||||
case kTextCalculate:
|
||||
break;
|
||||
|
||||
case kTextCenter:
|
||||
drawCentered(coords, width, (int16)(endText - string), string);
|
||||
break;
|
||||
|
||||
case kTextNormal:
|
||||
setPosition(coords);
|
||||
draw(text, (int16)(endText - text));
|
||||
break;
|
||||
}
|
||||
|
||||
coords.y += spacing;
|
||||
++printed;
|
||||
}
|
||||
|
||||
++index;
|
||||
|
||||
if (!currentChar)
|
||||
break;
|
||||
|
||||
charWidth = 0;
|
||||
spaceWidth = 0;
|
||||
text = endText + 1;
|
||||
|
||||
// Skip spaces
|
||||
if (currentChar == ' ' && *text == ' ')
|
||||
do {
|
||||
++text;
|
||||
} while (*text == ' ');
|
||||
}
|
||||
|
||||
const char *txt = text;
|
||||
int32 w = 0;
|
||||
|
||||
for (;;) {
|
||||
char c = *txt;
|
||||
w += charWidth;
|
||||
charWidth = spaceWidth;
|
||||
const char *txt2 = txt;
|
||||
|
||||
if (*txt != ' ') {
|
||||
do {
|
||||
if (!c)
|
||||
break;
|
||||
|
||||
if (c == 1) // Start of heading (SOH)
|
||||
break;
|
||||
|
||||
charWidth += getWidth(c);
|
||||
txt++;
|
||||
c = txt[0];
|
||||
|
||||
} while (c != ' ');
|
||||
}
|
||||
|
||||
if ((w + charWidth) > width) {
|
||||
string = text;
|
||||
endText = txt2 - 1;
|
||||
drawText = true;
|
||||
goto label_start;
|
||||
}
|
||||
|
||||
if (!*txt)
|
||||
break;
|
||||
|
||||
if (*txt == 1 || *txt == 2) // Start of heading (SOH) or start of text (STX)
|
||||
break;
|
||||
|
||||
++txt;
|
||||
spaceWidth = getWidth(' ');
|
||||
}
|
||||
|
||||
string = text;
|
||||
endText = txt;
|
||||
drawText = true;
|
||||
}
|
||||
|
||||
return printed;
|
||||
}
|
||||
|
||||
void Text::drawCentered(const Common::Point &point, int16 width, const char *text) {
|
||||
setPosition(Common::Point(point.x + (width - getWidth(text)) / 2, point.y));
|
||||
draw(text);
|
||||
}
|
||||
|
||||
void Text::drawCentered(const Common::Point &point, int16 width, int16 length, const char *text) {
|
||||
setPosition(Common::Point(point.x + (width - getWidth(text, length)) / 2, point.y));
|
||||
draw(text, length);
|
||||
}
|
||||
|
||||
void Text::drawCentered(const Common::Point &point, int16 width, ResourceId resourceId) {
|
||||
drawCentered(point, width, get(resourceId));
|
||||
}
|
||||
|
||||
} // end of namespace Asylum
|
||||
96
engines/asylum/system/text.h
Normal file
96
engines/asylum/system/text.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ASYLUM_SYSTEM_TEXT_H
|
||||
#define ASYLUM_SYSTEM_TEXT_H
|
||||
|
||||
#include "common/ptr.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "graphics/font.h"
|
||||
|
||||
#include "asylum/shared.h"
|
||||
|
||||
namespace Asylum {
|
||||
|
||||
class AsylumEngine;
|
||||
class GraphicResource;
|
||||
class ResourcePack;
|
||||
|
||||
enum TextCentering {
|
||||
kTextNormal,
|
||||
kTextCenter,
|
||||
kTextCalculate
|
||||
};
|
||||
|
||||
class Text {
|
||||
public:
|
||||
Text(AsylumEngine *engine);
|
||||
~Text();
|
||||
|
||||
ResourceId loadFont(ResourceId resourceId);
|
||||
|
||||
void setPosition(const Common::Point &point);
|
||||
int16 getWidth(const char *text);
|
||||
int16 getWidth(const char *text, int16 length);
|
||||
int16 getWidth(ResourceId resourceId);
|
||||
char *get(ResourceId resourceId);
|
||||
|
||||
void drawASCII(char character) { drawChar(character); }
|
||||
void draw(const char *text);
|
||||
void draw(const Common::Point &point, const char *text);
|
||||
void draw(ResourceId resourceId);
|
||||
void draw(const Common::Point &point, ResourceId resourceId);
|
||||
void draw(const char *text, ResourceId fontResourceId, int16 y);
|
||||
void draw(const char *text, int16 length);
|
||||
int16 draw(TextCentering centering, const Common::Point &point, int16 spacing, int16 width, const char *text);
|
||||
void drawChinese(const Common::U32String &utext);
|
||||
int16 draw(int16 a1, int16 a2, TextCentering centering, const Common::Point &point, int16 spacing, int16 width, const char *text);
|
||||
|
||||
void drawCentered(const Common::Point &point, int16 width, const char *text);
|
||||
void drawCentered(const Common::Point &point, int16 width, ResourceId resourceId);
|
||||
void drawCentered(const Common::Point &point, int16 width, int16 length, const char *text);
|
||||
|
||||
void setTransTableNum(uint32 val) { _transTableNum = val; }
|
||||
|
||||
private:
|
||||
int16 getWidth(char c);
|
||||
void drawChar(char character);
|
||||
|
||||
int16 getChineseWidth(const Common::U32String &utext);
|
||||
void loadChineseFont();
|
||||
|
||||
AsylumEngine *_vm;
|
||||
|
||||
GraphicResource *_fontResource;
|
||||
|
||||
uint32 _transTableNum;
|
||||
|
||||
Common::Point _position;
|
||||
uint8 _curFontFlags;
|
||||
|
||||
Common::ScopedPtr<Graphics::Font> _chineseFont;
|
||||
bool _chineseFontLoadAttempted;
|
||||
};
|
||||
|
||||
} // end of namespace Asylum
|
||||
|
||||
#endif // ASYLUM_SYSTEM_TEXT_H
|
||||
Reference in New Issue
Block a user