Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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

View 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

View 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