mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-13 21:31:53 +00:00
662 lines
20 KiB
C++
662 lines
20 KiB
C++
/* 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 "audio/audiostream.h"
|
|
#include "audio/decoders/raw.h"
|
|
#include "common/archive.h"
|
|
#include "common/config-manager.h"
|
|
#include "common/debug-channels.h"
|
|
#include "common/debug.h"
|
|
#include "common/error.h"
|
|
#include "common/events.h"
|
|
#include "common/file.h"
|
|
#include "common/memstream.h"
|
|
#include "common/savefile.h"
|
|
#include "common/str.h"
|
|
#include "common/system.h"
|
|
#include "common/substream.h"
|
|
#include "common/timer.h"
|
|
#include "engines/advancedDetector.h"
|
|
#include "engines/util.h"
|
|
#include "graphics/paletteman.h"
|
|
#include "image/bmp.h"
|
|
|
|
#include "hypno/grammar.h"
|
|
#include "hypno/hypno.h"
|
|
|
|
namespace Hypno {
|
|
|
|
Hotspots *g_parsedHots;
|
|
ArcadeShooting *g_parsedArc;
|
|
HypnoEngine *g_hypno;
|
|
|
|
HypnoEngine::HypnoEngine(OSystem *syst, const ADGameDescription *gd)
|
|
: Engine(syst), _gameDescription(gd), _image(nullptr),
|
|
_compositeSurface(nullptr), _transparentColor(0),
|
|
_nextHotsToAdd(nullptr), _nextHotsToRemove(nullptr),
|
|
_levelId(0), _skipLevel(false), _health(0), _maxHealth(0),
|
|
_playerFrameIdx(0), _playerFrameSep(0), _refreshConversation(false),
|
|
_countdown(0), _timerStarted(false), _score(0), _bonus(0), _lives(0),
|
|
_defaultCursor(""), _defaultCursorIdx(0), _skipDefeatVideo(false),
|
|
_background(nullptr), _masks(nullptr), _musicRate(0), _musicStereo(false),
|
|
_additionalVideo(nullptr), _ammo(0), _maxAmmo(0), _skipNextVideo(false),
|
|
_doNotStopSounds(false), _screenW(0), _screenH(0), // Every games initializes its own resolution
|
|
_keepTimerDuringScenes(false) {
|
|
_rnd = new Common::RandomSource("hypno");
|
|
_checkpoint = "";
|
|
|
|
if (gd->extra)
|
|
_variant = gd->extra;
|
|
else
|
|
_variant = "FullGame";
|
|
g_hypno = this;
|
|
g_parsedArc = new ArcadeShooting();
|
|
_language = Common::parseLanguage(ConfMan.get("language"));
|
|
_platform = Common::parsePlatform(ConfMan.get("platform"));
|
|
if (!Common::parseBool(ConfMan.get("cheats"), _cheatsEnabled))
|
|
error("Failed to parse bool from cheats options");
|
|
|
|
if (!Common::parseBool(ConfMan.get("infiniteHealth"), _infiniteHealthCheat))
|
|
error("Failed to parse bool from cheats options");
|
|
|
|
if (!Common::parseBool(ConfMan.get("infiniteAmmo"), _infiniteAmmoCheat))
|
|
error("Failed to parse bool from cheats options");
|
|
|
|
if (!Common::parseBool(ConfMan.get("unlockAllLevels"), _unlockAllLevels))
|
|
error("Failed to parse bool from cheats options");
|
|
|
|
if (!Common::parseBool(ConfMan.get("restored"), _restoredContentEnabled))
|
|
error("Failed to parse bool from restored options");
|
|
// Add quit level
|
|
Hotspot q(MakeMenu);
|
|
Action *a = new Quit();
|
|
q.actions.push_back(a);
|
|
Scene *quit = new Scene();
|
|
Hotspots hs;
|
|
hs.push_back(q);
|
|
quit->hots = hs;
|
|
_levels["<quit>"] = quit;
|
|
resetStatistics();
|
|
}
|
|
|
|
HypnoEngine::~HypnoEngine() {
|
|
// Deallocate actions
|
|
// for (Levels::iterator it = _levels.begin(); it != _levels.end(); ++it) {
|
|
// Level level = (*it)._value;
|
|
// for (Hotspots::iterator itt = level.scene.hots.begin(); itt != level.scene.hots.end(); ++itt) {
|
|
// Hotspot hot = *itt;
|
|
// for (Actions::iterator ittt = hot.actions.begin(); ittt != hot.actions.end(); ++ittt)
|
|
// delete (*ittt);
|
|
// }
|
|
// }
|
|
|
|
delete _rnd;
|
|
_compositeSurface->free();
|
|
delete _compositeSurface;
|
|
|
|
delete g_parsedArc;
|
|
}
|
|
|
|
void HypnoEngine::initializePath(const Common::FSNode &gamePath) {
|
|
SearchMan.addDirectory(gamePath, 0, 10);
|
|
}
|
|
|
|
LibFile *HypnoEngine::loadLib(const Common::Path &prefix, const Common::Path &filename, bool encrypted) {
|
|
LibFile *lib = new LibFile();
|
|
SearchMan.add(filename.toString(), (Common::Archive *)lib, 0, true);
|
|
if (!lib->open(prefix, filename, encrypted)) {
|
|
return nullptr;
|
|
}
|
|
_archive.push_back(lib);
|
|
return lib;
|
|
}
|
|
|
|
void HypnoEngine::loadAssets() { error("Function \"%s\" not implemented", __FUNCTION__); }
|
|
Common::String HypnoEngine::findNextLevel(const Common::String &level) { error("Function \"%s\" not implemented", __FUNCTION__); }
|
|
|
|
Common::Error HypnoEngine::run() {
|
|
Graphics::ModeList modes;
|
|
modes.push_back(Graphics::Mode(640, 480));
|
|
modes.push_back(Graphics::Mode(320, 200));
|
|
initGraphicsModes(modes);
|
|
|
|
// Initialize graphics
|
|
_pixelFormat = Graphics::PixelFormat::createFormatCLUT8();
|
|
initGraphics(_screenW, _screenH, &_pixelFormat);
|
|
|
|
_compositeSurface = new Graphics::Surface();
|
|
_compositeSurface->create(_screenW, _screenH, _pixelFormat);
|
|
|
|
// Main event loop
|
|
loadAssets();
|
|
|
|
int saveSlot = ConfMan.getInt("save_slot");
|
|
if (saveSlot >= 0) { // load the savegame
|
|
loadGameState(saveSlot);
|
|
}
|
|
|
|
assert(!_nextLevel.empty());
|
|
while (!shouldQuit()) {
|
|
debug("nextLevel: %s", _nextLevel.c_str());
|
|
_prefixDir = "";
|
|
_videosPlaying.clear();
|
|
_videosLooping.clear();
|
|
if (!_nextLevel.empty()) {
|
|
_currentLevel = findNextLevel(_nextLevel);
|
|
_nextLevel = "";
|
|
_arcadeMode = "";
|
|
runLevel(_currentLevel);
|
|
} else
|
|
g_system->delayMillis(300);
|
|
}
|
|
return Common::kNoError;
|
|
}
|
|
|
|
void HypnoEngine::runLevel(Common::String &name) {
|
|
if (!_levels.contains(name))
|
|
error("Level %s cannot be found", name.c_str());
|
|
|
|
_prefixDir = _levels[name]->prefix;
|
|
stopSound();
|
|
_music.clear();
|
|
|
|
// Play intros
|
|
disableCursor();
|
|
|
|
if (_levels[name]->playMusicDuringIntro && !_levels[name]->music.empty()) {
|
|
playSound(_levels[name]->music, 0, _levels[name]->musicRate);
|
|
_doNotStopSounds = true;
|
|
}
|
|
|
|
debug("Number of videos to play: %d", _levels[name]->intros.size());
|
|
for (Filenames::iterator it = _levels[name]->intros.begin(); it != _levels[name]->intros.end(); ++it) {
|
|
MVideo v(*it, Common::Point(0, 0), false, true, false);
|
|
runIntro(v);
|
|
}
|
|
|
|
_doNotStopSounds = false;
|
|
|
|
if (_levels[name]->type == TransitionLevel) {
|
|
debugC(1, kHypnoDebugScene, "Executing transition level %s", name.c_str());
|
|
runTransition((Transition *)_levels[name]);
|
|
} else if (_levels[name]->type == ArcadeLevel) {
|
|
debugC(1, kHypnoDebugArcade, "Executing arcade level %s", name.c_str());
|
|
changeScreenMode("320x200");
|
|
ArcadeShooting *arc = (ArcadeShooting *)_levels[name];
|
|
runBeforeArcade(arc);
|
|
runArcade(arc);
|
|
runAfterArcade(arc);
|
|
} else if (_levels[name]->type == CodeLevel) {
|
|
debugC(1, kHypnoDebugScene, "Executing hardcoded level %s", name.c_str());
|
|
// Resolution depends on the game
|
|
runCode((Code *)_levels[name]);
|
|
} else if (_levels[name]->type == SceneLevel) {
|
|
debugC(1, kHypnoDebugScene, "Executing scene level %s with next level: %s", name.c_str(), _levels[name]->levelIfWin.c_str());
|
|
runScene((Scene *)_levels[name]);
|
|
} else {
|
|
error("Invalid level %s", name.c_str());
|
|
}
|
|
}
|
|
|
|
void HypnoEngine::runIntros(Videos &videos) {
|
|
debugC(1, kHypnoDebugScene, "Starting run intros with %d videos!", videos.size());
|
|
Common::Event event;
|
|
if (!_doNotStopSounds)
|
|
stopSound();
|
|
bool skip = false;
|
|
int clicked[3] = {-1, -1, -1};
|
|
int clicks = 0;
|
|
|
|
for (Videos::iterator it = videos.begin(); it != videos.end(); ++it) {
|
|
playVideo(*it);
|
|
}
|
|
|
|
while (!shouldQuit()) {
|
|
while (g_system->getEventManager()->pollEvent(event)) {
|
|
// Events
|
|
switch (event.type) {
|
|
case Common::EVENT_KEYDOWN:
|
|
if (event.kbd.keycode == Common::KEYCODE_ESCAPE)
|
|
skip = true;
|
|
break;
|
|
case Common::EVENT_LBUTTONDOWN:
|
|
if (videos.size() == 1) {
|
|
int first = (clicks - 2) % 3;
|
|
int last = clicks % 3;
|
|
clicked[last] = videos[0].decoder->getCurFrame();
|
|
if (clicks >= 2 && clicked[last] - clicked[first] <= 10)
|
|
skip = true;
|
|
clicks++;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (skip) {
|
|
for (Videos::iterator it = videos.begin(); it != videos.end(); ++it) {
|
|
if (it->decoder)
|
|
skipVideo(*it);
|
|
}
|
|
videos.clear();
|
|
}
|
|
|
|
bool playing = false;
|
|
for (Videos::iterator it = videos.begin(); it != videos.end(); ++it) {
|
|
assert(!it->loop);
|
|
if (it->decoder) {
|
|
if (it->decoder->endOfVideo()) {
|
|
it->decoder->close();
|
|
delete it->decoder;
|
|
it->decoder = nullptr;
|
|
} else {
|
|
playing = true;
|
|
if (it->decoder->needsUpdate()) {
|
|
updateScreen(*it);
|
|
drawScreen();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!playing) {
|
|
debugC(1, kHypnoDebugScene, "Not playing anymore!");
|
|
break;
|
|
}
|
|
g_system->updateScreen();
|
|
g_system->delayMillis(10);
|
|
}
|
|
}
|
|
|
|
void HypnoEngine::runIntro(MVideo &video) {
|
|
Videos tmp;
|
|
tmp.push_back(video);
|
|
runIntros(tmp);
|
|
}
|
|
|
|
void HypnoEngine::runCode(Code *code) { error("Function \"%s\" not implemented", __FUNCTION__); }
|
|
void HypnoEngine::showCredits() { error("Function \"%s\" not implemented", __FUNCTION__); }
|
|
void HypnoEngine::loadGame(const Common::String &nextLevel, int score, int puzzleDifficulty, int combatDifficulty) {
|
|
error("Function \"%s\" not implemented", __FUNCTION__);
|
|
}
|
|
|
|
void HypnoEngine::loadFonts(const Common::String prefix) {
|
|
Common::File file;
|
|
Common::Path path = Common::Path(prefix).append("block05.fgx");
|
|
|
|
if (!file.open(path))
|
|
error("Cannot open font %s", path.toString().c_str());
|
|
|
|
byte *font = (byte *)malloc(file.size());
|
|
file.read(font, file.size());
|
|
|
|
_font05.set_size(file.size()*8);
|
|
_font05.set_bits((byte *)font);
|
|
|
|
file.close();
|
|
free(font);
|
|
path = Common::Path(prefix).append("scifi08.fgx");
|
|
|
|
if (!file.open(path))
|
|
error("Cannot open font %s", path.toString().c_str());
|
|
|
|
font = (byte *)malloc(file.size());
|
|
file.read(font, file.size());
|
|
|
|
_font08.set_size(file.size()*8);
|
|
_font08.set_bits((byte *)font);
|
|
|
|
file.close();
|
|
free(font);
|
|
}
|
|
|
|
void HypnoEngine::drawString(const Filename &name, const Common::String &str, int x, int y, int w, uint32 c) {
|
|
error("Function \"%s\" not implemented", __FUNCTION__);
|
|
}
|
|
|
|
void HypnoEngine::loadImage(const Common::String &name, int x, int y, bool transparent, bool palette, int frameNumber) {
|
|
|
|
debugC(1, kHypnoDebugMedia, "%s(%s, %d, %d, %d)", __FUNCTION__, name.c_str(), x, y, transparent);
|
|
Graphics::Surface *surf;
|
|
if (palette) {
|
|
byte *array;
|
|
surf = decodeFrame(name, frameNumber, &array);
|
|
loadPalette(array, 0, 256);
|
|
free(array);
|
|
} else
|
|
surf = decodeFrame(name, frameNumber);
|
|
|
|
drawImage(*surf, x, y, transparent);
|
|
|
|
surf->free();
|
|
delete surf;
|
|
}
|
|
|
|
void HypnoEngine::drawImage(Graphics::Surface &surf, int x, int y, bool transparent) {
|
|
Common::Rect srcRect(surf.w, surf.h);
|
|
Common::Rect dstRect = srcRect;
|
|
|
|
dstRect.moveTo(x, y);
|
|
_compositeSurface->clip(srcRect, dstRect);
|
|
|
|
if (transparent) {
|
|
_compositeSurface->copyRectToSurfaceWithKey(surf, dstRect.left, dstRect.top, srcRect, _transparentColor);
|
|
} else
|
|
_compositeSurface->copyRectToSurface(surf, dstRect.left, dstRect.top, srcRect);
|
|
}
|
|
|
|
Graphics::Surface *HypnoEngine::decodeFrame(const Common::String &name, int n, byte **palette) {
|
|
Common::File *file = new Common::File();
|
|
Common::Path path = convertPath(name);
|
|
if (!_prefixDir.empty())
|
|
path = _prefixDir.join(path);
|
|
|
|
if (!file->open(path))
|
|
error("unable to find video file %s", path.toString().c_str());
|
|
|
|
HypnoSmackerDecoder vd;
|
|
if (!vd.loadStream(file))
|
|
error("unable to load video %s", path.toString().c_str());
|
|
|
|
for (int f = 0; f < n; f++)
|
|
vd.decodeNextFrame();
|
|
|
|
const Graphics::Surface *frame = vd.decodeNextFrame();
|
|
Graphics::Surface *rframe = frame->convertTo(frame->format, vd.getPalette());
|
|
if (palette != nullptr) {
|
|
byte *newPalette = (byte *)malloc(3 * 256);
|
|
memcpy(newPalette, vd.getPalette(), 3 * 256);
|
|
*palette = newPalette;
|
|
}
|
|
|
|
return rframe;
|
|
}
|
|
|
|
Frames HypnoEngine::decodeFrames(const Common::String &name) {
|
|
Frames frames;
|
|
Common::File *file = new Common::File();
|
|
Common::Path path = convertPath(name);
|
|
if (!_prefixDir.empty())
|
|
path = _prefixDir.join(path);
|
|
|
|
if (!file->open(path))
|
|
error("unable to find video file %s", path.toString().c_str());
|
|
|
|
HypnoSmackerDecoder vd;
|
|
if (!vd.loadStream(file))
|
|
error("unable to load video %s", path.toString().c_str());
|
|
|
|
const Graphics::Surface *frame = nullptr;
|
|
Graphics::Surface *rframe = nullptr;
|
|
|
|
while (!vd.endOfVideo()) {
|
|
frame = vd.decodeNextFrame();
|
|
rframe = frame->convertTo(_pixelFormat, vd.getPalette());
|
|
frames.push_back(rframe);
|
|
}
|
|
return frames;
|
|
}
|
|
|
|
void HypnoEngine::changeScreenMode(const Common::String &mode) {
|
|
debugC(1, kHypnoDebugMedia, "%s(%s)", __FUNCTION__, mode.c_str());
|
|
if (mode == "640x480") {
|
|
if (_screenW == 640 && _screenH == 480)
|
|
return;
|
|
|
|
_screenW = 640;
|
|
_screenH = 480;
|
|
|
|
initGraphics(_screenW, _screenH, &_pixelFormat);
|
|
|
|
_compositeSurface->free();
|
|
delete _compositeSurface;
|
|
|
|
_compositeSurface = new Graphics::Surface();
|
|
_compositeSurface->create(_screenW, _screenH, _pixelFormat);
|
|
} else if (mode == "320x200") {
|
|
if (_screenW == 320 && _screenH == 200)
|
|
return;
|
|
|
|
_screenW = 320;
|
|
_screenH = 200;
|
|
|
|
initGraphics(_screenW, _screenH, &_pixelFormat);
|
|
|
|
_compositeSurface->free();
|
|
delete _compositeSurface;
|
|
|
|
_compositeSurface = new Graphics::Surface();
|
|
_compositeSurface->create(_screenW, _screenH, _pixelFormat);
|
|
} else
|
|
error("Unknown screen mode %s", mode.c_str());
|
|
}
|
|
|
|
void HypnoEngine::loadPalette(const Common::String &fname) {
|
|
Common::File file;
|
|
Common::Path path = convertPath(fname);
|
|
if (!_prefixDir.empty())
|
|
path = _prefixDir.join(path);
|
|
|
|
if (!file.open(path))
|
|
error("unable to find palette file %s", path.toString().c_str());
|
|
|
|
debugC(1, kHypnoDebugMedia, "Loading palette from %s", path.toString().c_str());
|
|
byte *videoPalette = (byte *)malloc(file.size());
|
|
file.read(videoPalette, file.size());
|
|
g_system->getPaletteManager()->setPalette(videoPalette + 8, 0, 256);
|
|
}
|
|
|
|
void HypnoEngine::loadPalette(const byte *palette, uint32 offset, uint32 size) {
|
|
debugC(1, kHypnoDebugMedia, "Loading palette from byte array with offset %d and size %d", offset, size);
|
|
g_system->getPaletteManager()->setPalette(palette, offset, size);
|
|
}
|
|
|
|
|
|
byte *HypnoEngine::getPalette(uint32 idx) {
|
|
byte *videoPalette = (byte *)malloc(3);
|
|
g_system->getPaletteManager()->grabPalette(videoPalette, idx, 1);
|
|
return videoPalette;
|
|
}
|
|
|
|
void HypnoEngine::updateVideo(MVideo &video) {
|
|
video.decoder->decodeNextFrame();
|
|
}
|
|
|
|
void HypnoEngine::updateScreen(MVideo &video) {
|
|
const Graphics::Surface *frame = video.decoder->decodeNextFrame();
|
|
bool dirtyPalette = video.decoder->hasDirtyPalette();
|
|
bool isFullscreen = (frame->w == _screenW && frame->h == _screenH);
|
|
|
|
if (frame->h == 0 || frame->w == 0 || video.decoder->getPalette() == nullptr)
|
|
return;
|
|
|
|
const byte *videoPalette = nullptr;
|
|
if (video.scaled && dirtyPalette) {
|
|
debugC(1, kHypnoDebugMedia, "Updating palette at frame %d", video.decoder->getCurFrame());
|
|
videoPalette = video.decoder->getPalette();
|
|
g_system->getPaletteManager()->setPalette(videoPalette, 0, 256);
|
|
}
|
|
|
|
if (video.scaled && !isFullscreen) {
|
|
Graphics::Surface *sframe = frame->scale(_screenW, _screenH);
|
|
Common::Rect srcRect(sframe->w, sframe->h);
|
|
Common::Rect dstRect = srcRect;
|
|
|
|
dstRect.moveTo(video.position);
|
|
_compositeSurface->clip(srcRect, dstRect);
|
|
|
|
if (video.transparent) {
|
|
_compositeSurface->copyRectToSurfaceWithKey(*sframe, dstRect.left, dstRect.top, srcRect, _transparentColor);
|
|
} else {
|
|
_compositeSurface->copyRectToSurface(*sframe, dstRect.left, dstRect.top, srcRect);
|
|
}
|
|
|
|
sframe->free();
|
|
delete sframe;
|
|
} else {
|
|
Common::Rect srcRect(frame->w, frame->h);
|
|
Common::Rect dstRect = srcRect;
|
|
|
|
dstRect.moveTo(video.position);
|
|
_compositeSurface->clip(srcRect, dstRect);
|
|
|
|
if (video.transparent) {
|
|
_compositeSurface->copyRectToSurfaceWithKey(*frame, dstRect.left, dstRect.top, srcRect, _transparentColor);
|
|
} else {
|
|
_compositeSurface->copyRectToSurface(*frame, dstRect.left, dstRect.top, srcRect);
|
|
}
|
|
}
|
|
}
|
|
|
|
void HypnoEngine::drawScreen() {
|
|
g_system->copyRectToScreen(_compositeSurface->getPixels(), _compositeSurface->pitch, 0, 0, _screenW, _screenH);
|
|
g_system->updateScreen();
|
|
g_system->delayMillis(10);
|
|
}
|
|
|
|
// Video handling
|
|
|
|
void HypnoEngine::playVideo(MVideo &video) {
|
|
debugC(1, kHypnoDebugMedia, "%s(%s)", __FUNCTION__, video.path.c_str());
|
|
Common::File *file = new Common::File();
|
|
Common::Path path = convertPath(video.path);
|
|
if (!_prefixDir.empty())
|
|
path = _prefixDir.join(path);
|
|
|
|
if (!file->open(path))
|
|
error("unable to find video file %s", path.toString().c_str());
|
|
|
|
if (video.decoder != nullptr) {
|
|
debugC(1, kHypnoDebugMedia, "Restarting %s!!!!", video.path.c_str());
|
|
delete video.decoder;
|
|
}
|
|
// error("Video %s was not previously closed and deallocated", video.path.c_str());
|
|
|
|
video.decoder = new HypnoSmackerDecoder();
|
|
|
|
if (!video.decoder->loadStream(file))
|
|
error("unable to load video %s", path.toString().c_str());
|
|
|
|
debugC(1, kHypnoDebugMedia, "audio track count: %d", video.decoder->getAudioTrackCount());
|
|
video.decoder->start();
|
|
}
|
|
|
|
void HypnoEngine::skipVideo(MVideo &video) {
|
|
if (!video.decoder)
|
|
return;
|
|
debugC(1, kHypnoDebugMedia, "%s()", __FUNCTION__);
|
|
video.decoder->close();
|
|
delete video.decoder;
|
|
video.decoder = nullptr;
|
|
}
|
|
|
|
// Sound handling
|
|
|
|
void HypnoEngine::playSound(const Common::String &filename, uint32 loops, uint32 sampleRate, bool stereo) {
|
|
debugC(1, kHypnoDebugMedia, "%s(%s, %d, %d)", __FUNCTION__, filename.c_str(), loops, sampleRate);
|
|
Common::Path name = convertPath(filename);
|
|
|
|
Audio::LoopingAudioStream *stream = nullptr;
|
|
Common::File *file = new Common::File();
|
|
if (file->open(name)) {
|
|
uint32 flags = Audio::FLAG_UNSIGNED;
|
|
|
|
Common::SeekableSubReadStream *sub;
|
|
if (stereo) {
|
|
sub = new Common::SeekableSubReadStream(file, 0, file->size() - (file->size() % 2), DisposeAfterUse::YES);
|
|
flags = flags | Audio::FLAG_STEREO;
|
|
} else {
|
|
sub = new Common::SeekableSubReadStream(file, 0, file->size(), DisposeAfterUse::YES);
|
|
}
|
|
|
|
stream = new Audio::LoopingAudioStream(Audio::makeRawStream(sub, sampleRate, flags, DisposeAfterUse::YES), loops);
|
|
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, stream, -1, Audio::Mixer::kMaxChannelVolume);
|
|
} else {
|
|
if (!_prefixDir.empty())
|
|
name = _prefixDir.join(name);
|
|
if (file->open(name)) {
|
|
stream = new Audio::LoopingAudioStream(Audio::makeRawStream(file, sampleRate, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES), loops);
|
|
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, stream, -1, Audio::Mixer::kMaxChannelVolume);
|
|
} else {
|
|
debugC(1, kHypnoDebugMedia, "%s not found!", name.toString().c_str());
|
|
delete file;
|
|
}
|
|
}
|
|
}
|
|
|
|
void HypnoEngine::stopSound() {
|
|
debugC(1, kHypnoDebugMedia, "%s()", __FUNCTION__);
|
|
_mixer->stopAll();
|
|
//_mixer->stopHandle(_soundHandle);
|
|
}
|
|
|
|
// Path handling
|
|
|
|
Common::Path HypnoEngine::convertPath(const Common::String &name) {
|
|
Common::String path(name);
|
|
Common::String s1("\\");
|
|
Common::String s2("/");
|
|
|
|
while (path.contains(s1))
|
|
Common::replace(path, s1, s2);
|
|
|
|
s1 = Common::String("\"");
|
|
s2 = Common::String("");
|
|
|
|
Common::replace(path, s1, s2);
|
|
Common::replace(path, s1, s2);
|
|
|
|
path.toLowercase();
|
|
return Common::Path(path);
|
|
}
|
|
|
|
// Timers
|
|
static void alarmCallback(void *refCon) {
|
|
g_system->getTimerManager()->removeTimerProc(&alarmCallback);
|
|
Common::String *level = (Common::String *)refCon;
|
|
g_hypno->_nextLevel = *level;
|
|
delete level;
|
|
}
|
|
|
|
static void countdownCallback(void *refCon) {
|
|
g_hypno->_countdown = g_hypno->_countdown - 1;
|
|
}
|
|
|
|
bool HypnoEngine::startAlarm(uint32 delay, Common::String *ns) {
|
|
return g_system->getTimerManager()->installTimerProc(&alarmCallback, delay, (void *)ns, "alarm");
|
|
}
|
|
|
|
bool HypnoEngine::startCountdown(uint32 delay) {
|
|
_countdown = delay;
|
|
_timerStarted = true;
|
|
uint32 oneSecond = 1000000;
|
|
return g_system->getTimerManager()->installTimerProc(&countdownCallback, oneSecond, 0x0, "countdown");
|
|
}
|
|
|
|
void HypnoEngine::removeTimers() {
|
|
_timerStarted = false;
|
|
_keepTimerDuringScenes = false;
|
|
g_system->getTimerManager()->removeTimerProc(&alarmCallback);
|
|
g_system->getTimerManager()->removeTimerProc(&countdownCallback);
|
|
}
|
|
|
|
} // End of namespace Hypno
|