5991 lines
174 KiB
C++
5991 lines
174 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/>.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* This file is based on WME Lite.
|
|
* http://dead-code.org/redir.php?target=wmelite
|
|
* Copyright (c) 2011 Jan Nedoma
|
|
*/
|
|
|
|
#include "engines/wintermute/dcgf.h"
|
|
#include "engines/wintermute/base/base_engine.h"
|
|
#include "engines/wintermute/base/base_game.h"
|
|
#include "engines/wintermute/base/base_fader.h"
|
|
#include "engines/wintermute/base/base_file_manager.h"
|
|
#include "engines/wintermute/base/font/base_font.h"
|
|
#include "engines/wintermute/base/font/base_font_storage.h"
|
|
#include "engines/wintermute/base/gfx/base_renderer.h"
|
|
#ifdef ENABLE_WME3D
|
|
#include "engines/wintermute/base/gfx/base_renderer3d.h"
|
|
#endif
|
|
#include "engines/wintermute/base/gfx/base_image.h"
|
|
#include "engines/wintermute/base/gfx/base_surface.h"
|
|
#include "engines/wintermute/base/base_keyboard_state.h"
|
|
#include "engines/wintermute/base/base_parser.h"
|
|
#include "engines/wintermute/base/base_quick_msg.h"
|
|
#include "engines/wintermute/base/sound/base_sound_manager.h"
|
|
#include "engines/wintermute/base/base_sprite.h"
|
|
#include "engines/wintermute/base/base_sub_frame.h"
|
|
#include "engines/wintermute/base/base_transition_manager.h"
|
|
#include "engines/wintermute/base/base_viewport.h"
|
|
#include "engines/wintermute/base/base_region.h"
|
|
#include "engines/wintermute/base/base_surface_storage.h"
|
|
#include "engines/wintermute/base/save_thumb_helper.h"
|
|
#include "engines/wintermute/base/scriptables/script_ext_array.h"
|
|
#include "engines/wintermute/base/scriptables/script_value.h"
|
|
#include "engines/wintermute/base/scriptables/script_engine.h"
|
|
#include "engines/wintermute/base/scriptables/script_stack.h"
|
|
#include "engines/wintermute/base/scriptables/script.h"
|
|
#include "engines/wintermute/base/sound/base_sound.h"
|
|
#include "engines/wintermute/base/file/base_savefile_manager_file.h"
|
|
#include "engines/wintermute/base/base_access_mgr.h"
|
|
#include "engines/wintermute/ext/plugins.h"
|
|
#include "engines/wintermute/video/video_player.h"
|
|
#include "engines/wintermute/video/video_theora_player.h"
|
|
#include "engines/wintermute/utils/utils.h"
|
|
#include "engines/wintermute/utils/crc.h"
|
|
#include "engines/wintermute/utils/path_util.h"
|
|
#include "engines/wintermute/utils/string_util.h"
|
|
#include "engines/wintermute/ui/ui_window.h"
|
|
#include "engines/wintermute/ui/ui_text.h"
|
|
#include "engines/wintermute/wintermute.h"
|
|
#include "engines/wintermute/platform_osystem.h"
|
|
#include "engines/wintermute/ad/ad_scene.h"
|
|
|
|
#include "base/version.h"
|
|
#include "common/config-manager.h"
|
|
#include "common/savefile.h"
|
|
#include "common/textconsole.h"
|
|
#include "common/util.h"
|
|
#include "common/keyboard.h"
|
|
#include "common/system.h"
|
|
#include "common/file.h"
|
|
#include "graphics/scaler.h"
|
|
|
|
#if EXTENDED_DEBUGGER_ENABLED
|
|
#include "engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.h"
|
|
#endif
|
|
|
|
#ifdef ENABLE_WME3D
|
|
#include "graphics/renderer.h"
|
|
#include "engines/util.h"
|
|
#include "engines/wintermute/base/gfx/xmodel.h"
|
|
#if defined(USE_OPENGL_GAME) || defined(USE_OPENGL_SHADERS)
|
|
#include "graphics/opengl/context.h"
|
|
#endif
|
|
#endif
|
|
|
|
namespace Wintermute {
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
IMPLEMENT_PERSISTENT(BaseGame, true)
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
BaseGame::BaseGame(const Common::String &targetName) : BaseObject(this), _targetName(targetName) {
|
|
_shuttingDown = false;
|
|
|
|
_state = GAME_RUNNING;
|
|
_origState = GAME_RUNNING;
|
|
_freezeLevel = 0;
|
|
|
|
_interactive = true;
|
|
_origInteractive = false;
|
|
|
|
_surfaceStorage = nullptr;
|
|
_fontStorage = nullptr;
|
|
_renderer = nullptr;
|
|
#ifdef ENABLE_WME3D
|
|
_renderer3D = nullptr;
|
|
#endif
|
|
_soundMgr = nullptr;
|
|
_videoPlayer = nullptr;
|
|
_fileManager = nullptr;
|
|
_transMgr = nullptr;
|
|
_scEngine = nullptr;
|
|
_keyboardState = nullptr;
|
|
|
|
_mathClass = nullptr;
|
|
_directoryClass = nullptr;
|
|
|
|
_debugLogFile = nullptr;
|
|
_debugMode = false;
|
|
_debugShowFPS = false;
|
|
|
|
_systemFont = nullptr;
|
|
_videoFont = nullptr;
|
|
|
|
_theoraPlayer = nullptr;
|
|
|
|
_mainObject = nullptr;
|
|
_activeObject = nullptr;
|
|
|
|
_fader = nullptr;
|
|
|
|
_offsetX = _offsetY = 0;
|
|
_offsetPercentX = _offsetPercentY = 0.0f;
|
|
|
|
_subtitles = true;
|
|
_videoSubtitles = true;
|
|
|
|
_timer = 0;
|
|
_timerDelta = 0;
|
|
_timerLast = 0;
|
|
|
|
_liveTimer = 0;
|
|
_liveTimerDelta = 0;
|
|
_liveTimerLast = 0;
|
|
|
|
_sequence = 0;
|
|
|
|
_mousePos.x = _mousePos.y = 0;
|
|
_mouseLeftDown = _mouseRightDown = _mouseMidlleDown = false;
|
|
_capturedObject = nullptr;
|
|
|
|
// FPS counters
|
|
_lastTime = _fpsTime = _deltaTime = _framesRendered = _fps = 0;
|
|
|
|
_cursorNoninteractive = nullptr;
|
|
|
|
#ifdef ENABLE_WME3D
|
|
_useD3D = true;
|
|
_playing3DGame = false;
|
|
#else
|
|
_useD3D = false;
|
|
#endif
|
|
|
|
_stringTable = new BaseStringTable(this);
|
|
|
|
for (int i = 0; i < NUM_MUSIC_CHANNELS; i++) {
|
|
_music[i] = nullptr;
|
|
_musicStartTime[i] = 0;
|
|
}
|
|
|
|
_settingsResWidth = 800;
|
|
_settingsResHeight = 600;
|
|
_settingsRequireAcceleration = false;
|
|
_settingsRequireSound = false;
|
|
_settingsTLMode = 0;
|
|
_settingsAllowWindowed = true;
|
|
_settingsGameFile = nullptr;
|
|
_settingsAllowAdvanced = false;
|
|
_settingsAllowAccessTab = true;
|
|
_settingsAllowAboutTab = true;
|
|
_settingsAllowDesktopRes = false;
|
|
|
|
_editorForceScripts = false;
|
|
_editorAlwaysRegister = false;
|
|
|
|
_focusedWindow = nullptr;
|
|
|
|
_loadInProgress = false;
|
|
|
|
_quitting = false;
|
|
_loading = false;
|
|
_scheduledLoadSlot = -1;
|
|
|
|
_personalizedSave = false;
|
|
_compressedSavegames = true;
|
|
|
|
_editorMode = false;
|
|
|
|
_engineLogCallback = nullptr;
|
|
_engineLogCallbackData = nullptr;
|
|
|
|
_smartCache = false;
|
|
_surfaceGCCycleTime = 10000;
|
|
|
|
_reportTextureFormat = false;
|
|
|
|
_viewportSP = -1;
|
|
|
|
_subtitlesSpeed = 70;
|
|
|
|
_forceNonStreamedSounds = false;
|
|
|
|
// These are NOT the actual engine defaults (they are 0, 0),
|
|
// but we have a use for thumbnails even for games that don't
|
|
// use them in-game, hence we set a default that is suitably
|
|
// sized for the GMM (expecting 4:3 ratio)
|
|
_thumbnailWidth = kThumbnailWidth;
|
|
_thumbnailHeight = kThumbnailHeight2;
|
|
|
|
_indicatorDisplay = false;
|
|
_indicatorColor = BYTETORGBA(255, 0, 0, 128);
|
|
_indicatorProgress = 0;
|
|
_indicatorX = -1;
|
|
_indicatorY = -1;
|
|
_indicatorWidth = -1;
|
|
_indicatorHeight = 8;
|
|
_richSavedGames = false;
|
|
_savedGameExt = nullptr;
|
|
BaseUtils::setString(&_savedGameExt, "dsv");
|
|
|
|
_musicCrossfadeRunning = false;
|
|
_musicCrossfadeStartTime = 0;
|
|
_musicCrossfadeLength = 0;
|
|
_musicCrossfadeChannel1 = -1;
|
|
_musicCrossfadeChannel2 = -1;
|
|
_musicCrossfadeSwap = false;
|
|
_musicCrossfadeVolume1 = 0;
|
|
_musicCrossfadeVolume2 = 100;
|
|
|
|
_loadImageName = nullptr;
|
|
_saveImageName = nullptr;
|
|
_saveLoadImage = nullptr;
|
|
|
|
_saveImageX = _saveImageY = 0;
|
|
_loadImageX = _loadImageY = 0;
|
|
|
|
_hasDrawnSaveLoadImage = false;
|
|
|
|
#ifdef ENABLE_WME3D
|
|
_maxShadowType = SHADOW_STENCIL;
|
|
_supportsRealTimeShadows = false;
|
|
#endif
|
|
|
|
_editorResolutionWidth = 0;
|
|
_editorResolutionHeight = 0;
|
|
|
|
_localSaveDir = nullptr;
|
|
BaseUtils::setString(&_localSaveDir, "saves");
|
|
|
|
_saveDirChecked = false;
|
|
|
|
_loadingIcon = nullptr;
|
|
_loadingIconX = _loadingIconY = 0;
|
|
_loadingIconPersistent = false;
|
|
|
|
_textEncoding = TEXT_ANSI;
|
|
_textRTL = false;
|
|
|
|
_soundBufferSizeSec = 3;
|
|
_suspendedRendering = false;
|
|
|
|
_lastCursor = nullptr;
|
|
|
|
// accessibility flags
|
|
_accessTTSEnabled = false;
|
|
_accessTTSTalk = true;
|
|
_accessTTSCaptions = true;
|
|
_accessTTSKeypress = true;
|
|
_accessKeyboardEnabled = true;//false;
|
|
_accessKeyboardCursorSkip = true;
|
|
_accessKeyboardPause = false;
|
|
|
|
_accessGlobalPaused = false;
|
|
_accessShieldWin = nullptr;
|
|
|
|
BasePlatform::setRectEmpty(&_mouseLockRect);
|
|
|
|
_suppressScriptErrors = false;
|
|
_lastMiniUpdate = 0;
|
|
_miniUpdateEnabled = false;
|
|
|
|
_cachedThumbnail = nullptr;
|
|
|
|
_autorunDisabled = false;
|
|
|
|
// compatibility bits
|
|
_compatKillMethodThreads = false;
|
|
|
|
_usedMem = 0;
|
|
|
|
|
|
_autoSaveOnExit = true;
|
|
_autoSaveSlot = 999;
|
|
_cursorHidden = false;
|
|
|
|
#ifdef ENABLE_HEROCRAFT
|
|
_rndHc = new Common::RandomSource("HeroCraft");
|
|
#endif
|
|
|
|
_touchInterface = false;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
BaseGame::~BaseGame() {
|
|
_shuttingDown = true;
|
|
|
|
LOG(0, "");
|
|
LOG(0, "Shutting down...");
|
|
|
|
ConfMan.setBool("last_run", true);
|
|
ConfMan.flushToDisk();
|
|
|
|
cleanup();
|
|
|
|
SAFE_DELETE_ARRAY(_localSaveDir);
|
|
SAFE_DELETE_ARRAY(_settingsGameFile);
|
|
SAFE_DELETE_ARRAY(_savedGameExt);
|
|
SAFE_DELETE(_cachedThumbnail);
|
|
|
|
SAFE_DELETE(_saveLoadImage);
|
|
SAFE_DELETE(_mathClass);
|
|
SAFE_DELETE(_directoryClass);
|
|
|
|
SAFE_DELETE(_transMgr);
|
|
SAFE_DELETE(_scEngine);
|
|
SAFE_DELETE(_fontStorage);
|
|
SAFE_DELETE(_surfaceStorage);
|
|
SAFE_DELETE(_theoraPlayer);
|
|
SAFE_DELETE(_videoPlayer);
|
|
SAFE_DELETE(_soundMgr);
|
|
//SAFE_DELETE(_keyboardState);
|
|
|
|
SAFE_DELETE(_renderer);
|
|
_fileManager = nullptr;
|
|
SAFE_DELETE(_accessMgr);
|
|
|
|
SAFE_DELETE(_stringTable);
|
|
|
|
#ifdef ENABLE_HEROCRAFT
|
|
SAFE_DELETE(_rndHc);
|
|
#endif
|
|
|
|
debugDisable();
|
|
debugC(kWintermuteDebugLog, "--- shutting down normally ---\n");
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::cleanup() {
|
|
SAFE_DELETE(_loadingIcon);
|
|
|
|
_engineLogCallback = nullptr;
|
|
_engineLogCallbackData = nullptr;
|
|
|
|
for (int i = 0; i < NUM_MUSIC_CHANNELS; i++) {
|
|
SAFE_DELETE(_music[i]);
|
|
_musicStartTime[i] = 0;
|
|
}
|
|
|
|
unregisterObject(_fader);
|
|
_fader = nullptr;
|
|
|
|
for (int32 i = 0; i < _regObjects.getSize(); i++) {
|
|
SAFE_DELETE(_regObjects[i]);
|
|
}
|
|
_regObjects.removeAll();
|
|
|
|
_windows.removeAll(); // refs only
|
|
_focusedWindow = nullptr; // ref only
|
|
_accessShieldWin = nullptr;
|
|
|
|
SAFE_DELETE_ARRAY(_saveImageName);
|
|
SAFE_DELETE_ARRAY(_loadImageName);
|
|
|
|
SAFE_DELETE(_cursorNoninteractive);
|
|
SAFE_DELETE(_cursor);
|
|
SAFE_DELETE(_activeCursor);
|
|
|
|
SAFE_DELETE(_scValue);
|
|
SAFE_DELETE(_sFX);
|
|
|
|
for (int32 i = 0; i < _scripts.getSize(); i++) {
|
|
_scripts[i]->_owner = nullptr;
|
|
_scripts[i]->finish();
|
|
}
|
|
_scripts.removeAll();
|
|
|
|
_fontStorage->removeFont(_systemFont);
|
|
_systemFont = nullptr;
|
|
|
|
_fontStorage->removeFont(_videoFont);
|
|
_videoFont = nullptr;
|
|
|
|
#ifdef ENABLE_WME3D
|
|
if (_shadowImage) {
|
|
_surfaceStorage->removeSurface(_shadowImage);
|
|
_shadowImage = nullptr;
|
|
}
|
|
#endif
|
|
|
|
for (int32 i = 0; i < _quickMessages.getSize(); i++) {
|
|
delete _quickMessages[i];
|
|
}
|
|
_quickMessages.removeAll();
|
|
|
|
_viewportStack.removeAll();
|
|
_viewportSP = -1;
|
|
|
|
SAFE_DELETE_ARRAY(_name);
|
|
SAFE_DELETE_ARRAY(_filename);
|
|
for (int i = 0; i < 7; i++) {
|
|
SAFE_DELETE_ARRAY(_caption[i]);
|
|
}
|
|
|
|
_lastCursor = nullptr;
|
|
|
|
SAFE_DELETE(_keyboardState);
|
|
|
|
if (_accessMgr) {
|
|
_accessMgr->setActiveObject(nullptr);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::initConfManSettings() {
|
|
if (ConfMan.hasKey("debug_mode")) {
|
|
if (ConfMan.getBool("debug_mode")) {
|
|
debugEnable("./wme.log");
|
|
}
|
|
}
|
|
|
|
if (ConfMan.hasKey("show_fps")) {
|
|
_debugShowFPS = ConfMan.getBool("show_fps");
|
|
} else {
|
|
_debugShowFPS = false;
|
|
}
|
|
|
|
if (ConfMan.hasKey("bilinear_filtering")) {
|
|
_bilinearFiltering = ConfMan.getBool("bilinear_filtering");
|
|
} else {
|
|
_bilinearFiltering = false;
|
|
}
|
|
|
|
if (ConfMan.hasKey("disable_smartcache")) {
|
|
_smartCache = ConfMan.getBool("disable_smartcache");
|
|
} else {
|
|
_smartCache = true;
|
|
}
|
|
|
|
#ifdef ENABLE_WME3D
|
|
if (ConfMan.hasKey("force_2d_renderer")) {
|
|
_force2dRenderer = ConfMan.getBool("force_2d_renderer");
|
|
} else {
|
|
_force2dRenderer = false;
|
|
}
|
|
#endif
|
|
|
|
if (!_smartCache) {
|
|
LOG(0, "Smart cache is DISABLED");
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::initRenderer() {
|
|
bool windowedMode = !ConfMan.getBool("fullscreen");
|
|
return _renderer->initRenderer(_settingsResWidth, _settingsResHeight, windowedMode);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::initialize1() {
|
|
bool loaded = false; // Not really a loop, but a goto-replacement.
|
|
while (!loaded) {
|
|
_surfaceStorage = new BaseSurfaceStorage(this);
|
|
if (_surfaceStorage == nullptr) {
|
|
break;
|
|
}
|
|
|
|
_fontStorage = new BaseFontStorage(this);
|
|
if (_fontStorage == nullptr) {
|
|
break;
|
|
}
|
|
|
|
_fileManager = BaseFileManager::getEngineInstance();
|
|
if (_fileManager == nullptr) {
|
|
break;
|
|
}
|
|
|
|
_accessMgr = new BaseAccessMgr(this);
|
|
if (_accessMgr == nullptr) {
|
|
break;
|
|
}
|
|
|
|
_soundMgr = new BaseSoundMgr(this);
|
|
if (_soundMgr == nullptr) {
|
|
break;
|
|
}
|
|
|
|
_videoPlayer = new VideoPlayer(this);
|
|
if (_videoPlayer == nullptr) {
|
|
break;
|
|
}
|
|
|
|
_mathClass = makeSXMath(this);
|
|
if (_mathClass == nullptr) {
|
|
break;
|
|
}
|
|
|
|
_directoryClass = makeSXDirectory(this);
|
|
if (_directoryClass == nullptr) {
|
|
break;
|
|
}
|
|
|
|
#if EXTENDED_DEBUGGER_ENABLED
|
|
_scEngine = new DebuggableScEngine(this);
|
|
#else
|
|
_scEngine = new ScEngine(this);
|
|
#endif
|
|
if (_scEngine == nullptr) {
|
|
break;
|
|
}
|
|
|
|
_transMgr = new BaseTransitionMgr(this);
|
|
if (_transMgr == nullptr) {
|
|
break;
|
|
}
|
|
|
|
_keyboardState = new BaseKeyboardState(this);
|
|
if (_keyboardState == nullptr) {
|
|
break;
|
|
}
|
|
|
|
_fader = new BaseFader(this);
|
|
if (_fader == nullptr) {
|
|
break;
|
|
}
|
|
registerObject(_fader);
|
|
|
|
_pluginEvents.clearEvents();
|
|
|
|
loaded = true;
|
|
}
|
|
if (loaded == true) {
|
|
return STATUS_OK;
|
|
} else {
|
|
delete _directoryClass;
|
|
delete _mathClass;
|
|
delete _keyboardState;
|
|
delete _transMgr;
|
|
delete _surfaceStorage;
|
|
delete _fontStorage;
|
|
delete _videoPlayer;
|
|
delete _soundMgr;
|
|
delete _accessMgr;
|
|
_fileManager = nullptr;
|
|
delete _scEngine;
|
|
return STATUS_FAILED;
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::initialize2() { // we know whether we are going to be accelerated
|
|
#ifdef ENABLE_WME3D
|
|
Common::String rendererConfig = ConfMan.get("renderer");
|
|
Graphics::RendererType desiredRendererType = Graphics::Renderer::parseTypeCode(rendererConfig);
|
|
uint32 availableRendererTypes = Graphics::Renderer::getAvailableTypes();
|
|
|
|
availableRendererTypes &=
|
|
#if defined(USE_OPENGL_GAME)
|
|
Graphics::kRendererTypeOpenGL |
|
|
#endif
|
|
#if defined(USE_OPENGL_SHADERS)
|
|
Graphics::kRendererTypeOpenGLShaders |
|
|
#endif
|
|
#if defined(USE_TINYGL)
|
|
Graphics::kRendererTypeTinyGL |
|
|
#endif
|
|
0;
|
|
|
|
#if defined(USE_TINYGL)
|
|
// When playing 2D, TinyGL is not really TinyGL but software and is always available
|
|
if (!_playing3DGame) {
|
|
availableRendererTypes |= Graphics::kRendererTypeTinyGL;
|
|
}
|
|
#endif
|
|
|
|
Graphics::RendererType matchingRendererType = Graphics::Renderer::getBestMatchingType(desiredRendererType, availableRendererTypes);
|
|
|
|
bool force2dRenderer = _force2dRenderer && !_playing3DGame;
|
|
#if defined(USE_OPENGL_SHADERS)
|
|
if (!force2dRenderer && matchingRendererType == Graphics::kRendererTypeOpenGLShaders) {
|
|
initGraphics3d(_settingsResWidth, _settingsResHeight);
|
|
_renderer3D = makeOpenGL3DShaderRenderer(this);
|
|
}
|
|
#endif // defined(USE_OPENGL_SHADERS)
|
|
#if defined(USE_OPENGL_GAME)
|
|
if (!force2dRenderer && matchingRendererType == Graphics::kRendererTypeOpenGL) {
|
|
initGraphics3d(_settingsResWidth, _settingsResHeight);
|
|
_renderer3D = makeOpenGL3DRenderer(this);
|
|
}
|
|
#endif // defined(USE_OPENGL_GAME)
|
|
#if defined(USE_TINYGL)
|
|
if (!force2dRenderer && matchingRendererType == Graphics::kRendererTypeTinyGL) {
|
|
if (_playing3DGame) {
|
|
warning("3D software renderer is not supported yet");
|
|
_renderer3D = nullptr;//makeTinyGL3DRenderer(this);
|
|
}
|
|
}
|
|
#endif // defined(USE_TINYGL)
|
|
_useD3D = _renderer3D != nullptr;
|
|
_renderer = _renderer3D;
|
|
|
|
if (!_renderer && !_playing3DGame) {
|
|
_renderer = makeOSystemRenderer(this);
|
|
}
|
|
#else
|
|
_renderer = makeOSystemRenderer(this);
|
|
#endif
|
|
|
|
if (_renderer == nullptr) {
|
|
return STATUS_FAILED;
|
|
} else {
|
|
return STATUS_OK;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::initialize3() { // renderer is initialized
|
|
_posX = _renderer->getWidth() / 2;
|
|
_posY = _renderer->getHeight() / 2;
|
|
|
|
if (_indicatorY == -1)
|
|
_indicatorY = _renderer->getHeight() - _indicatorHeight;
|
|
if (_indicatorX == -1) {
|
|
_indicatorX = 0;
|
|
}
|
|
if (_indicatorWidth == -1) {
|
|
_indicatorWidth = _renderer->getWidth();
|
|
}
|
|
|
|
if (_accessMgr) {
|
|
_game->_accessMgr->initialize();
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
void BaseGame::debugEnable(const char *filename) {
|
|
_debugMode = true;
|
|
|
|
int secs = BasePlatform::getTime() / 1000;
|
|
int hours = secs / 3600;
|
|
secs = secs % 3600;
|
|
int mins = secs / 60;
|
|
secs = secs % 60;
|
|
|
|
#ifdef _DEBUG
|
|
LOG(0, "********** DEBUG LOG OPENED %02d-%02d-%02d (Debug Build) *******************", hours, mins, secs);
|
|
#else
|
|
LOG(0, "********** DEBUG LOG OPENED %02d-%02d-%02d (Release Build) *****************", hours, mins, secs);
|
|
#endif
|
|
|
|
LOG(0, "%s - %s ver %d.%d.%d%s ", gScummVMFullVersion, DCGF_NAME, DCGF_VER_MAJOR, DCGF_VER_MINOR, DCGF_VER_BUILD, DCGF_VER_SUFFIX);
|
|
|
|
AnsiString platform = BasePlatform::getPlatformName();
|
|
LOG(0, "Platform: %s", platform.c_str());
|
|
LOG(0, "");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
void BaseGame::debugDisable() {
|
|
if (_debugLogFile != nullptr) {
|
|
LOG(0, "********** DEBUG LOG CLOSED ********************************************");
|
|
//fclose((FILE *)_debugLogFile);
|
|
_debugLogFile = nullptr;
|
|
}
|
|
_debugMode = false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
void BaseGame::LOG(bool res, const char *fmt, ...) {
|
|
uint32 secs = BasePlatform::getTime() / 1000;
|
|
uint32 hours = secs / 3600;
|
|
secs = secs % 3600;
|
|
uint32 mins = secs / 60;
|
|
secs = secs % 60;
|
|
|
|
char buff[512];
|
|
va_list va;
|
|
|
|
va_start(va, fmt);
|
|
Common::vsprintf_s(buff, fmt, va);
|
|
va_end(va);
|
|
|
|
// redirect to an engine's own callback
|
|
if (_engineLogCallback) {
|
|
_engineLogCallback(buff, res, _engineLogCallbackData);
|
|
}
|
|
|
|
debugCN(kWintermuteDebugLog, "%02d:%02d:%02d: %s\n", hours, mins, secs, buff);
|
|
|
|
//fprintf((FILE *)_debugLogFile, "%02d:%02d:%02d: %s\n", hours, mins, secs, buff);
|
|
//fflush((FILE *)_debugLogFile);
|
|
|
|
//quickMessage(buff);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::setEngineLogCallback(ENGINE_LOG_CALLBACK callback, void *data) {
|
|
_engineLogCallback = callback;
|
|
_engineLogCallbackData = data;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::initLoop() {
|
|
_viewportSP = -1;
|
|
|
|
_currentTime = BasePlatform::getTime();
|
|
|
|
_renderer->initLoop();
|
|
_soundMgr->initLoop();
|
|
updateMusicCrossfade();
|
|
|
|
_surfaceStorage->initLoop();
|
|
|
|
if (_accessMgr) {
|
|
_accessMgr->initLoop();
|
|
}
|
|
|
|
_fontStorage->initLoop();
|
|
|
|
|
|
//_activeObject = nullptr;
|
|
|
|
// count FPS
|
|
_deltaTime = _currentTime - _lastTime;
|
|
_lastTime = _currentTime;
|
|
_fpsTime += _deltaTime;
|
|
|
|
_liveTimerDelta = _liveTimer - _liveTimerLast;
|
|
_liveTimerLast = _liveTimer;
|
|
_liveTimer += MIN((uint32)1000, _deltaTime);
|
|
|
|
if (_state != GAME_FROZEN) {
|
|
_timerDelta = _timer - _timerLast;
|
|
_timerLast = _timer;
|
|
_timer += MIN((uint32)1000, _deltaTime);
|
|
} else {
|
|
_timerDelta = 0;
|
|
}
|
|
|
|
_framesRendered++;
|
|
if (_fpsTime > 1000) {
|
|
_fps = _framesRendered;
|
|
_framesRendered = 0;
|
|
_fpsTime = 0;
|
|
}
|
|
//_game->LOG(0, "%d", _fps);
|
|
|
|
getMousePos(&_mousePos);
|
|
|
|
_focusedWindow = nullptr;
|
|
for (int32 i = _windows.getSize() - 1; i >= 0; i--) {
|
|
if (_windows[i]->_visible) {
|
|
_focusedWindow = _windows[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
updateSounds();
|
|
|
|
if (_fader) {
|
|
_fader->update();
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::initInput() {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int BaseGame::getSequence() {
|
|
return ++_sequence;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::setOffset(int32 offsetX, int32 offsetY) {
|
|
_offsetX = offsetX;
|
|
_offsetY = offsetY;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::getOffset(int *offsetX, int *offsetY) const {
|
|
if (offsetX != nullptr) {
|
|
*offsetX = _offsetX;
|
|
}
|
|
if (offsetY != nullptr) {
|
|
*offsetY = _offsetY;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::loadFile(const char *filename) {
|
|
char *buffer = (char *)_game->_fileManager->readWholeFile(filename);
|
|
if (buffer == nullptr) {
|
|
_game->LOG(0, "BaseGame::loadFile failed for file '%s'", filename);
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
bool ret;
|
|
|
|
setFilename(filename);
|
|
|
|
if (DID_FAIL(ret = loadBuffer(buffer, true))) {
|
|
_game->LOG(0, "Error parsing GAME file '%s'", filename);
|
|
}
|
|
|
|
delete[] buffer;
|
|
|
|
return ret;
|
|
}
|
|
|
|
TOKEN_DEF_START
|
|
TOKEN_DEF(GAME)
|
|
TOKEN_DEF(TEMPLATE)
|
|
TOKEN_DEF(NAME)
|
|
TOKEN_DEF(SYSTEM_FONT)
|
|
TOKEN_DEF(VIDEO_FONT)
|
|
TOKEN_DEF(EVENTS)
|
|
TOKEN_DEF(CURSOR)
|
|
TOKEN_DEF(ACTIVE_CURSOR)
|
|
TOKEN_DEF(NONINTERACTIVE_CURSOR)
|
|
TOKEN_DEF(STRING_TABLE)
|
|
TOKEN_DEF(RESOLUTION)
|
|
TOKEN_DEF(SETTINGS)
|
|
TOKEN_DEF(REQUIRE_3D_ACCELERATION)
|
|
TOKEN_DEF(REQUIRE_SOUND)
|
|
TOKEN_DEF(HWTL_MODE)
|
|
TOKEN_DEF(ALLOW_WINDOWED_MODE)
|
|
TOKEN_DEF(ALLOW_ACCESSIBILITY_TAB)
|
|
TOKEN_DEF(ALLOW_ABOUT_TAB)
|
|
TOKEN_DEF(ALLOW_ADVANCED)
|
|
TOKEN_DEF(ALLOW_DESKTOP_RES)
|
|
TOKEN_DEF(REGISTRY_PATH)
|
|
TOKEN_DEF(PERSONAL_SAVEGAMES)
|
|
TOKEN_DEF(SCRIPT)
|
|
TOKEN_DEF(CAPTION)
|
|
TOKEN_DEF(PROPERTY)
|
|
TOKEN_DEF(SUBTITLES_SPEED)
|
|
TOKEN_DEF(SUBTITLES)
|
|
TOKEN_DEF(VIDEO_SUBTITLES)
|
|
TOKEN_DEF(EDITOR_PROPERTY)
|
|
TOKEN_DEF(THUMBNAIL_WIDTH)
|
|
TOKEN_DEF(THUMBNAIL_HEIGHT)
|
|
TOKEN_DEF(INDICATOR_X)
|
|
TOKEN_DEF(INDICATOR_Y)
|
|
TOKEN_DEF(INDICATOR_WIDTH)
|
|
TOKEN_DEF(INDICATOR_HEIGHT)
|
|
TOKEN_DEF(INDICATOR_COLOR)
|
|
TOKEN_DEF(SAVE_IMAGE_X)
|
|
TOKEN_DEF(SAVE_IMAGE_Y)
|
|
TOKEN_DEF(SAVE_IMAGE)
|
|
TOKEN_DEF(LOAD_IMAGE_X)
|
|
TOKEN_DEF(LOAD_IMAGE_Y)
|
|
TOKEN_DEF(LOAD_IMAGE)
|
|
#ifdef ENABLE_WME3D
|
|
TOKEN_DEF(SHADOW_IMAGE)
|
|
#endif
|
|
TOKEN_DEF(LOCAL_SAVE_DIR)
|
|
TOKEN_DEF(RICH_SAVED_GAMES)
|
|
TOKEN_DEF(SAVED_GAME_EXT)
|
|
TOKEN_DEF(GUID)
|
|
TOKEN_DEF(COMPAT_KILL_METHOD_THREADS)
|
|
TOKEN_DEF_END
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::loadBuffer(char *buffer, bool complete) {
|
|
TOKEN_TABLE_START(commands)
|
|
TOKEN_TABLE(GAME)
|
|
TOKEN_TABLE(TEMPLATE)
|
|
TOKEN_TABLE(NAME)
|
|
TOKEN_TABLE(SYSTEM_FONT)
|
|
TOKEN_TABLE(VIDEO_FONT)
|
|
TOKEN_TABLE(EVENTS)
|
|
TOKEN_TABLE(CURSOR)
|
|
TOKEN_TABLE(ACTIVE_CURSOR)
|
|
TOKEN_TABLE(NONINTERACTIVE_CURSOR)
|
|
TOKEN_TABLE(PERSONAL_SAVEGAMES)
|
|
TOKEN_TABLE(SCRIPT)
|
|
TOKEN_TABLE(CAPTION)
|
|
TOKEN_TABLE(PROPERTY)
|
|
TOKEN_TABLE(SUBTITLES_SPEED)
|
|
TOKEN_TABLE(SUBTITLES)
|
|
TOKEN_TABLE(VIDEO_SUBTITLES)
|
|
TOKEN_TABLE(EDITOR_PROPERTY)
|
|
TOKEN_TABLE(THUMBNAIL_WIDTH)
|
|
TOKEN_TABLE(THUMBNAIL_HEIGHT)
|
|
TOKEN_TABLE(INDICATOR_X)
|
|
TOKEN_TABLE(INDICATOR_Y)
|
|
TOKEN_TABLE(INDICATOR_WIDTH)
|
|
TOKEN_TABLE(INDICATOR_HEIGHT)
|
|
TOKEN_TABLE(INDICATOR_COLOR)
|
|
TOKEN_TABLE(SAVE_IMAGE_X)
|
|
TOKEN_TABLE(SAVE_IMAGE_Y)
|
|
TOKEN_TABLE(SAVE_IMAGE)
|
|
TOKEN_TABLE(LOAD_IMAGE_X)
|
|
TOKEN_TABLE(LOAD_IMAGE_Y)
|
|
TOKEN_TABLE(LOAD_IMAGE)
|
|
#ifdef ENABLE_WME3D
|
|
TOKEN_TABLE(SHADOW_IMAGE)
|
|
#endif
|
|
TOKEN_TABLE(LOCAL_SAVE_DIR)
|
|
TOKEN_TABLE(COMPAT_KILL_METHOD_THREADS)
|
|
TOKEN_TABLE_END
|
|
|
|
char *params;
|
|
int cmd;
|
|
BaseParser parser(_game);
|
|
|
|
if (complete) {
|
|
if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_GAME) {
|
|
_game->LOG(0, "'GAME' keyword expected.");
|
|
return STATUS_FAILED;
|
|
}
|
|
buffer = params;
|
|
}
|
|
|
|
while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) {
|
|
switch (cmd) {
|
|
case TOKEN_TEMPLATE:
|
|
if (DID_FAIL(loadFile(params))) {
|
|
cmd = PARSERR_GENERIC;
|
|
}
|
|
break;
|
|
|
|
case TOKEN_NAME:
|
|
setName(params);
|
|
break;
|
|
|
|
case TOKEN_CAPTION:
|
|
setCaption(params);
|
|
break;
|
|
|
|
case TOKEN_SYSTEM_FONT:
|
|
if (_systemFont) {
|
|
_fontStorage->removeFont(_systemFont);
|
|
}
|
|
_systemFont = nullptr;
|
|
|
|
_systemFont = _game->_fontStorage->addFont(params);
|
|
break;
|
|
|
|
case TOKEN_VIDEO_FONT:
|
|
if (_videoFont) {
|
|
_fontStorage->removeFont(_videoFont);
|
|
}
|
|
_videoFont = nullptr;
|
|
|
|
_videoFont = _game->_fontStorage->addFont(params);
|
|
break;
|
|
|
|
#ifdef ENABLE_WME3D
|
|
case TOKEN_SHADOW_IMAGE:
|
|
if (_shadowImage) {
|
|
_surfaceStorage->removeSurface(_shadowImage);
|
|
}
|
|
_shadowImage = nullptr;
|
|
|
|
_shadowImage = _game->_surfaceStorage->addSurface(params, false);
|
|
break;
|
|
#endif
|
|
|
|
case TOKEN_CURSOR:
|
|
SAFE_DELETE(_cursor);
|
|
_cursor = new BaseSprite(_game);
|
|
if (!_cursor || DID_FAIL(_cursor->loadFile(params))) {
|
|
SAFE_DELETE(_cursor);
|
|
cmd = PARSERR_GENERIC;
|
|
}
|
|
break;
|
|
|
|
case TOKEN_ACTIVE_CURSOR:
|
|
SAFE_DELETE(_activeCursor);
|
|
_activeCursor = new BaseSprite(_game);
|
|
if (!_activeCursor || DID_FAIL(_activeCursor->loadFile(params))) {
|
|
SAFE_DELETE(_activeCursor);
|
|
cmd = PARSERR_GENERIC;
|
|
}
|
|
break;
|
|
|
|
case TOKEN_NONINTERACTIVE_CURSOR:
|
|
SAFE_DELETE(_cursorNoninteractive);
|
|
_cursorNoninteractive = new BaseSprite(_game);
|
|
if (!_cursorNoninteractive || DID_FAIL(_cursorNoninteractive->loadFile(params))) {
|
|
SAFE_DELETE(_cursorNoninteractive);
|
|
cmd = PARSERR_GENERIC;
|
|
}
|
|
break;
|
|
|
|
case TOKEN_SCRIPT:
|
|
addScript(params);
|
|
break;
|
|
|
|
case TOKEN_PERSONAL_SAVEGAMES:
|
|
parser.scanStr(params, "%b", &_personalizedSave);
|
|
break;
|
|
|
|
case TOKEN_SUBTITLES:
|
|
parser.scanStr(params, "%b", &_subtitles);
|
|
break;
|
|
|
|
case TOKEN_SUBTITLES_SPEED:
|
|
parser.scanStr(params, "%d", &_subtitlesSpeed);
|
|
break;
|
|
|
|
case TOKEN_VIDEO_SUBTITLES:
|
|
parser.scanStr(params, "%b", &_videoSubtitles);
|
|
break;
|
|
|
|
case TOKEN_PROPERTY:
|
|
parseProperty(params, false);
|
|
break;
|
|
|
|
case TOKEN_EDITOR_PROPERTY:
|
|
parseEditorProperty(params, false);
|
|
break;
|
|
|
|
case TOKEN_THUMBNAIL_WIDTH:
|
|
parser.scanStr(params, "%d", &_thumbnailWidth);
|
|
break;
|
|
|
|
case TOKEN_THUMBNAIL_HEIGHT:
|
|
parser.scanStr(params, "%d", &_thumbnailHeight);
|
|
break;
|
|
|
|
case TOKEN_INDICATOR_X:
|
|
parser.scanStr(params, "%d", &_indicatorX);
|
|
break;
|
|
|
|
case TOKEN_INDICATOR_Y:
|
|
parser.scanStr(params, "%d", &_indicatorY);
|
|
break;
|
|
|
|
case TOKEN_INDICATOR_COLOR: {
|
|
int r, g, b, a;
|
|
parser.scanStr(params, "%d,%d,%d,%d", &r, &g, &b, &a);
|
|
_indicatorColor = BYTETORGBA(r, g, b, a);
|
|
}
|
|
break;
|
|
|
|
case TOKEN_INDICATOR_WIDTH:
|
|
parser.scanStr(params, "%d", &_indicatorWidth);
|
|
break;
|
|
|
|
case TOKEN_INDICATOR_HEIGHT:
|
|
parser.scanStr(params, "%d", &_indicatorHeight);
|
|
break;
|
|
|
|
case TOKEN_SAVE_IMAGE:
|
|
BaseUtils::setString(&_saveImageName, (char *)params);
|
|
break;
|
|
|
|
case TOKEN_SAVE_IMAGE_X:
|
|
parser.scanStr(params, "%d", &_saveImageX);
|
|
break;
|
|
|
|
case TOKEN_SAVE_IMAGE_Y:
|
|
parser.scanStr(params, "%d", &_saveImageY);
|
|
break;
|
|
|
|
case TOKEN_LOAD_IMAGE:
|
|
BaseUtils::setString(&_loadImageName, (char *)params);
|
|
break;
|
|
|
|
case TOKEN_LOAD_IMAGE_X:
|
|
parser.scanStr(params, "%d", &_loadImageX);
|
|
break;
|
|
|
|
case TOKEN_LOAD_IMAGE_Y:
|
|
parser.scanStr(params, "%d", &_loadImageY);
|
|
break;
|
|
|
|
case TOKEN_LOCAL_SAVE_DIR:
|
|
BaseUtils::setString(&_localSaveDir, (char *)params);
|
|
break;
|
|
|
|
case TOKEN_COMPAT_KILL_METHOD_THREADS:
|
|
parser.scanStr(params, "%b", &_compatKillMethodThreads);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!_systemFont) {
|
|
_systemFont = _game->_fontStorage->addFont("system_font.fnt");
|
|
}
|
|
#ifdef ENABLE_WME3D
|
|
if (!_shadowImage) {
|
|
_shadowImage = _game->_surfaceStorage->addSurface("shadow.png", false);
|
|
}
|
|
#endif
|
|
|
|
if (cmd == PARSERR_TOKENNOTFOUND) {
|
|
_game->LOG(0, "Syntax error in GAME definition");
|
|
return STATUS_FAILED;
|
|
}
|
|
if (cmd == PARSERR_GENERIC) {
|
|
_game->LOG(0, "Error loading GAME definition");
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// high level scripting interface
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// LOG
|
|
//////////////////////////////////////////////////////////////////////////
|
|
if (strcmp(name, "LOG") == 0) {
|
|
stack->correctParams(1);
|
|
LOG(0, stack->pop()->getString());
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Caption
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Caption") == 0) {
|
|
bool res = BaseObject::scCallMethod(script, stack, thisStack, name);
|
|
setWindowTitle();
|
|
return res;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Msg
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Msg") == 0) {
|
|
stack->correctParams(1);
|
|
quickMessage(stack->pop()->getString());
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// RunScript
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "RunScript") == 0) {
|
|
_game->LOG(0, "**Warning** The 'RunScript' method is now obsolete. Use 'AttachScript' instead (same syntax)");
|
|
stack->correctParams(1);
|
|
if (DID_FAIL(addScript(stack->pop()->getString()))) {
|
|
stack->pushBool(false);
|
|
} else {
|
|
stack->pushBool(true);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// LoadStringTable
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "LoadStringTable") == 0) {
|
|
stack->correctParams(2);
|
|
const char *filename = stack->pop()->getString();
|
|
ScValue *val = stack->pop();
|
|
|
|
bool clearOld;
|
|
if (val->isNULL()) {
|
|
clearOld = true;
|
|
} else {
|
|
clearOld = val->getBool();
|
|
}
|
|
|
|
if (DID_FAIL(_stringTable->loadFile(filename, clearOld))) {
|
|
stack->pushBool(false);
|
|
} else {
|
|
stack->pushBool(true);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// ValidObject
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "ValidObject") == 0) {
|
|
stack->correctParams(1);
|
|
BaseScriptable *obj = stack->pop()->getNative();
|
|
if (validObject((BaseObject *)obj)) {
|
|
stack->pushBool(true);
|
|
} else {
|
|
stack->pushBool(false);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Reset
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Reset") == 0) {
|
|
stack->correctParams(0);
|
|
resetContent();
|
|
stack->pushNULL();
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// UnloadObject
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "UnloadObject") == 0) {
|
|
stack->correctParams(1);
|
|
ScValue *val = stack->pop();
|
|
BaseObject *obj = (BaseObject *)val->getNative();
|
|
unregisterObject(obj);
|
|
if (val->getType() == VAL_VARIABLE_REF) {
|
|
val->setNULL();
|
|
}
|
|
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// LoadWindow
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "LoadWindow") == 0) {
|
|
stack->correctParams(1);
|
|
UIWindow *win = new UIWindow(_game);
|
|
if (win && DID_SUCCEED(win->loadFile(stack->pop()->getString()))) {
|
|
_windows.add(win);
|
|
registerObject(win);
|
|
stack->pushNative(win, true);
|
|
} else {
|
|
SAFE_DELETE(win);
|
|
stack->pushNULL();
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// ExpandString
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "ExpandString") == 0) {
|
|
stack->correctParams(1);
|
|
ScValue *val = stack->pop();
|
|
size_t strSize = strlen(val->getString()) + 1;
|
|
char *str = new char[strSize];
|
|
Common::strcpy_s(str, strSize, val->getString());
|
|
_stringTable->expand(&str);
|
|
stack->pushString(str);
|
|
delete[] str;
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// PlayMusic / PlayMusicChannel
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "PlayMusic") == 0 || strcmp(name, "PlayMusicChannel") == 0) {
|
|
int channel = 0;
|
|
if (strcmp(name, "PlayMusic") == 0) {
|
|
stack->correctParams(4);
|
|
} else {
|
|
stack->correctParams(5);
|
|
channel = stack->pop()->getInt();
|
|
}
|
|
|
|
const char *filename = stack->pop()->getString();
|
|
ScValue *valLooping = stack->pop();
|
|
bool looping = valLooping->isNULL() ? true : valLooping->getBool();
|
|
|
|
ScValue *valLoopStart = stack->pop();
|
|
uint32 loopStart = (uint32)(valLoopStart->isNULL() ? 0 : valLoopStart->getInt());
|
|
|
|
ScValue *valPrivVolume = stack->pop();
|
|
uint32 privVolume = (uint32)(valPrivVolume->isNULL() ? 100 : valPrivVolume->getInt());
|
|
|
|
if (DID_FAIL(playMusic(channel, filename, looping, loopStart, privVolume))) {
|
|
stack->pushBool(false);
|
|
} else {
|
|
stack->pushBool(true);
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// StopMusic / StopMusicChannel
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "StopMusic") == 0 || strcmp(name, "StopMusicChannel") == 0) {
|
|
int channel = 0;
|
|
|
|
if (strcmp(name, "StopMusic") == 0) {
|
|
stack->correctParams(0);
|
|
} else {
|
|
stack->correctParams(1);
|
|
channel = stack->pop()->getInt();
|
|
}
|
|
|
|
if (DID_FAIL(stopMusic(channel))) {
|
|
stack->pushBool(false);
|
|
} else {
|
|
stack->pushBool(true);
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// PauseMusic / PauseMusicChannel
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "PauseMusic") == 0 || strcmp(name, "PauseMusicChannel") == 0) {
|
|
int channel = 0;
|
|
|
|
if (strcmp(name, "PauseMusic") == 0) {
|
|
stack->correctParams(0);
|
|
} else {
|
|
stack->correctParams(1);
|
|
channel = stack->pop()->getInt();
|
|
}
|
|
|
|
if (DID_FAIL(pauseMusic(channel))) {
|
|
stack->pushBool(false);
|
|
} else {
|
|
stack->pushBool(true);
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// ResumeMusic / ResumeMusicChannel
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "ResumeMusic") == 0 || strcmp(name, "ResumeMusicChannel") == 0) {
|
|
int channel = 0;
|
|
if (strcmp(name, "ResumeMusic") == 0) {
|
|
stack->correctParams(0);
|
|
} else {
|
|
stack->correctParams(1);
|
|
channel = stack->pop()->getInt();
|
|
}
|
|
|
|
if (DID_FAIL(resumeMusic(channel))) {
|
|
stack->pushBool(false);
|
|
} else {
|
|
stack->pushBool(true);
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetMusic / GetMusicChannel
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetMusic") == 0 || strcmp(name, "GetMusicChannel") == 0) {
|
|
int channel = 0;
|
|
if (strcmp(name, "GetMusic") == 0) {
|
|
stack->correctParams(0);
|
|
} else {
|
|
stack->correctParams(1);
|
|
channel = stack->pop()->getInt();
|
|
}
|
|
if (channel < 0 || channel >= NUM_MUSIC_CHANNELS) {
|
|
stack->pushNULL();
|
|
} else {
|
|
if (!_music[channel] || !_music[channel]->_soundFilename || !_music[channel]->_soundFilename[0]) {
|
|
stack->pushNULL();
|
|
} else {
|
|
stack->pushString(_music[channel]->_soundFilename);
|
|
}
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SetMusicPosition / SetMusicChannelPosition
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SetMusicPosition") == 0 || strcmp(name, "SetMusicChannelPosition") == 0 || strcmp(name, "SetMusicPositionChannel") == 0) {
|
|
int channel = 0;
|
|
if (strcmp(name, "SetMusicPosition") == 0) {
|
|
stack->correctParams(1);
|
|
} else {
|
|
stack->correctParams(2);
|
|
channel = stack->pop()->getInt();
|
|
}
|
|
|
|
uint32 time = stack->pop()->getInt();
|
|
|
|
if (DID_FAIL(setMusicStartTime(channel, time))) {
|
|
stack->pushBool(false);
|
|
} else {
|
|
stack->pushBool(true);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetMusicPosition / GetMusicChannelPosition
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetMusicPosition") == 0 || strcmp(name, "GetMusicChannelPosition") == 0) {
|
|
int channel = 0;
|
|
if (strcmp(name, "GetMusicPosition") == 0) {
|
|
stack->correctParams(0);
|
|
} else {
|
|
stack->correctParams(1);
|
|
channel = stack->pop()->getInt();
|
|
}
|
|
|
|
if (channel < 0 || channel >= NUM_MUSIC_CHANNELS || !_music[channel]) {
|
|
stack->pushInt(0);
|
|
} else {
|
|
stack->pushInt(_music[channel]->getPositionTime());
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// IsMusicPlaying / IsMusicChannelPlaying
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "IsMusicPlaying") == 0 || strcmp(name, "IsMusicChannelPlaying") == 0) {
|
|
int channel = 0;
|
|
if (strcmp(name, "IsMusicPlaying") == 0) {
|
|
stack->correctParams(0);
|
|
} else {
|
|
stack->correctParams(1);
|
|
channel = stack->pop()->getInt();
|
|
}
|
|
|
|
if (channel < 0 || channel >= NUM_MUSIC_CHANNELS || !_music[channel]) {
|
|
stack->pushBool(false);
|
|
} else {
|
|
stack->pushBool(_music[channel]->isPlaying());
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SetMusicVolume / SetMusicChannelVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SetMusicVolume") == 0 || strcmp(name, "SetMusicChannelVolume") == 0) {
|
|
int channel = 0;
|
|
if (strcmp(name, "SetMusicVolume") == 0) {
|
|
stack->correctParams(1);
|
|
} else {
|
|
stack->correctParams(2);
|
|
channel = stack->pop()->getInt();
|
|
}
|
|
|
|
int volume = stack->pop()->getInt();
|
|
if (channel < 0 || channel >= NUM_MUSIC_CHANNELS || !_music[channel]) {
|
|
stack->pushBool(false);
|
|
} else {
|
|
if (DID_FAIL(_music[channel]->setVolume(volume))) {
|
|
stack->pushBool(false);
|
|
} else {
|
|
stack->pushBool(true);
|
|
}
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetMusicVolume / GetMusicChannelVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetMusicVolume") == 0 || strcmp(name, "GetMusicChannelVolume") == 0) {
|
|
int channel = 0;
|
|
if (strcmp(name, "GetMusicVolume") == 0) {
|
|
stack->correctParams(0);
|
|
} else {
|
|
stack->correctParams(1);
|
|
channel = stack->pop()->getInt();
|
|
}
|
|
|
|
if (channel < 0 || channel >= NUM_MUSIC_CHANNELS || !_music[channel]) {
|
|
stack->pushInt(0);
|
|
} else {
|
|
stack->pushInt(_music[channel]->getVolume());
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// MusicCrossfade
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "MusicCrossfade") == 0) {
|
|
stack->correctParams(4);
|
|
int channel1 = stack->pop()->getInt(0);
|
|
int channel2 = stack->pop()->getInt(0);
|
|
uint32 fadeLength = (uint32)stack->pop()->getInt(0);
|
|
bool swap = stack->pop()->getBool(true);
|
|
|
|
if (_musicCrossfadeRunning) {
|
|
script->runtimeError("Game.MusicCrossfade: Music crossfade is already in progress.");
|
|
stack->pushBool(false);
|
|
return STATUS_OK;
|
|
}
|
|
|
|
_musicCrossfadeStartTime = _liveTimer;
|
|
_musicCrossfadeChannel1 = channel1;
|
|
_musicCrossfadeChannel2 = channel2;
|
|
_musicCrossfadeLength = fadeLength;
|
|
_musicCrossfadeSwap = swap;
|
|
|
|
_musicCrossfadeRunning = true;
|
|
|
|
_musicCrossfadeVolume1 = 0;
|
|
_musicCrossfadeVolume2 = 100;
|
|
|
|
stack->pushBool(true);
|
|
return STATUS_OK;
|
|
}
|
|
|
|
#ifdef ENABLE_FOXTAIL
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [FoxTail] MusicCrossfadeVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "MusicCrossfadeVolume") == 0) {
|
|
stack->correctParams(4);
|
|
int channel = stack->pop()->getInt(0);
|
|
int volume1 = stack->pop()->getInt(0);
|
|
int volume2 = stack->pop()->getInt(0);
|
|
uint32 fadeLength = (uint32)stack->pop()->getInt(0);
|
|
|
|
if (_musicCrossfadeRunning) {
|
|
script->runtimeError("Game.MusicCrossfade: Music crossfade is already in progress.");
|
|
stack->pushBool(false);
|
|
return STATUS_OK;
|
|
}
|
|
|
|
_musicCrossfadeStartTime = _game->_liveTimer;
|
|
_musicCrossfadeChannel1 = channel;
|
|
_musicCrossfadeChannel2 = channel;
|
|
_musicCrossfadeLength = fadeLength;
|
|
_musicCrossfadeSwap = false;
|
|
|
|
_musicCrossfadeRunning = true;
|
|
|
|
_musicCrossfadeVolume1 = volume1;
|
|
_musicCrossfadeVolume2 = volume2;
|
|
|
|
stack->pushBool(true);
|
|
return STATUS_OK;
|
|
}
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetSoundLength
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetSoundLength") == 0) {
|
|
stack->correctParams(1);
|
|
|
|
int length = 0;
|
|
const char *filename = stack->pop()->getString();
|
|
|
|
BaseSound *sound = new BaseSound(_game);
|
|
if (sound && DID_SUCCEED(sound->setSound(filename, TSoundType::SOUND_MUSIC, true))) {
|
|
length = sound->getLength();
|
|
SAFE_DELETE(sound);
|
|
}
|
|
stack->pushInt(length);
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SetMousePos
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SetMousePos") == 0) {
|
|
stack->correctParams(2);
|
|
int32 x = stack->pop()->getInt();
|
|
int32 y = stack->pop()->getInt();
|
|
x = MAX<int32>(x, 0);
|
|
x = MIN(x, _renderer->getWidth());
|
|
y = MAX<int32>(y, 0);
|
|
y = MIN(y, _renderer->getHeight());
|
|
Common::Point32 p;
|
|
p.x = x + _renderer->_drawOffsetX;
|
|
p.y = y + _renderer->_drawOffsetY;
|
|
|
|
//CBPlatform::ClientToScreen(m_Renderer->m_Window, &p);
|
|
BasePlatform::setCursorPos(p.x, p.y);
|
|
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// LockMouseRect
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "LockMouseRect") == 0) {
|
|
stack->correctParams(4);
|
|
int left = stack->pop()->getInt();
|
|
int top = stack->pop()->getInt();
|
|
int right = stack->pop()->getInt();
|
|
int bottom = stack->pop()->getInt();
|
|
|
|
if (right < left) {
|
|
BaseUtils::swap(&left, &right);
|
|
}
|
|
if (bottom < top) {
|
|
BaseUtils::swap(&top, &bottom);
|
|
}
|
|
|
|
BasePlatform::setRect(&_mouseLockRect, left, top, right, bottom);
|
|
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// PlayVideo
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "PlayVideo") == 0) {
|
|
//Game->LOG(0, "Warning: Game.PlayVideo() is now deprecated. Use Game.PlayTheora() instead.");
|
|
|
|
stack->correctParams(6);
|
|
const char *filename = stack->pop()->getString();
|
|
ScValue *valType = stack->pop();
|
|
int type;
|
|
if (valType->isNULL()) {
|
|
type = (int)VID_PLAY_STRETCH;
|
|
} else {
|
|
type = valType->getInt();
|
|
}
|
|
|
|
int xVal = stack->pop()->getInt();
|
|
int yVal = stack->pop()->getInt();
|
|
bool freezeMusic = stack->pop()->getBool(true);
|
|
|
|
ScValue *valSub = stack->pop();
|
|
const char *subtitleFile = valSub->isNULL() ? nullptr : valSub->getString();
|
|
|
|
if (type < (int)VID_PLAY_POS || type > (int)VID_PLAY_CENTER) {
|
|
type = (int)VID_PLAY_STRETCH;
|
|
}
|
|
|
|
if (DID_SUCCEED(_game->_videoPlayer->initialize(filename, subtitleFile))) {
|
|
if (DID_SUCCEED(_game->_videoPlayer->play((TVideoPlayback)type, xVal, yVal, freezeMusic))) {
|
|
stack->pushBool(true);
|
|
script->sleep(0);
|
|
} else {
|
|
stack->pushBool(false);
|
|
}
|
|
} else {
|
|
stack->pushBool(false);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// PlayTheora
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "PlayTheora") == 0) {
|
|
stack->correctParams(7);
|
|
const char *filename = stack->pop()->getString();
|
|
ScValue *valType = stack->pop();
|
|
int type;
|
|
if (valType->isNULL()) {
|
|
type = (int)VID_PLAY_STRETCH;
|
|
} else {
|
|
type = valType->getInt();
|
|
}
|
|
|
|
int xVal = stack->pop()->getInt();
|
|
int yVal = stack->pop()->getInt();
|
|
bool freezeMusic = stack->pop()->getBool(true);
|
|
bool dropFrames = stack->pop()->getBool(true);
|
|
|
|
ScValue *valSub = stack->pop();
|
|
const char *subtitleFile = valSub->isNULL() ? nullptr : valSub->getString();
|
|
|
|
if (type < (int)VID_PLAY_POS || type > (int)VID_PLAY_CENTER) {
|
|
type = (int)VID_PLAY_STRETCH;
|
|
}
|
|
|
|
bool videoLoaded = false;
|
|
SAFE_DELETE(_theoraPlayer);
|
|
_theoraPlayer = new VideoTheoraPlayer(this);
|
|
if (_theoraPlayer && DID_SUCCEED(_theoraPlayer->initialize(filename, subtitleFile))) {
|
|
_theoraPlayer->_dontDropFrames = !dropFrames;
|
|
if (DID_SUCCEED(_theoraPlayer->play((TVideoPlayback)type, xVal, yVal, true, freezeMusic))) {
|
|
stack->pushBool(true);
|
|
script->sleep(0);
|
|
videoLoaded = true;
|
|
} else {
|
|
stack->pushBool(false);
|
|
}
|
|
} else {
|
|
stack->pushBool(false);
|
|
}
|
|
|
|
if (!videoLoaded) {
|
|
SAFE_DELETE(_theoraPlayer);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// QuitGame
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "QuitGame") == 0) {
|
|
stack->correctParams(0);
|
|
stack->pushNULL();
|
|
_quitting = true;
|
|
return STATUS_OK;
|
|
}
|
|
|
|
#ifdef ENABLE_FOXTAIL
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [FoxTail] RegistryFlush
|
|
// Return value is never used
|
|
// Used at SaveGameSettings() and Game.RegistryFlush()
|
|
// Called after a series of RegWriteNumber calls
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "RegistryFlush") == 0) {
|
|
stack->correctParams(0);
|
|
ConfMan.flushToDisk();
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [FoxTail] GetSaveSlotDescriptionTimestamp
|
|
// Return struct with "Description" and "Timestamp" fields in 1.2.362-
|
|
// Return array with "Description" and "Timestamp" items in 1.2.527+
|
|
// Timestamps should be comparable types
|
|
// Used to sort saved games by timestamps at save.script & load.script
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetSaveSlotDescriptionTimestamp") == 0) {
|
|
stack->correctParams(1);
|
|
int slot = stack->pop()->getInt();
|
|
|
|
TimeDate time;
|
|
getSaveSlotTimestamp(slot, &time);
|
|
stack->pushInt(time.tm_sec);
|
|
stack->pushInt(time.tm_min);
|
|
stack->pushInt(time.tm_hour);
|
|
stack->pushInt(time.tm_mday);
|
|
stack->pushInt(time.tm_mon + 1);
|
|
stack->pushInt(time.tm_year + 1900);
|
|
stack->pushInt(6);
|
|
BaseScriptable *date = makeSXDate(_game, stack);
|
|
stack->pushNative(date, false);
|
|
|
|
Common::String desc;
|
|
getSaveSlotDescription(slot, desc);
|
|
stack->pushString(desc.c_str());
|
|
|
|
BaseScriptable *obj;
|
|
if (BaseEngine::instance().isFoxTail(FOXTAIL_1_2_527, FOXTAIL_LATEST_VERSION)) {
|
|
stack->pushInt(2);
|
|
obj = makeSXArray(_game, stack);
|
|
} else {
|
|
stack->pushInt(0);
|
|
obj = makeSXObject(_game, stack);
|
|
obj->scSetProperty("Description", stack->pop());
|
|
obj->scSetProperty("Timestamp", stack->pop());
|
|
}
|
|
stack->pushNative(obj, false);
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [FoxTail] ValidSaveSlotVersion
|
|
// Checks if given slot stores game state of compatible game version
|
|
// This version always returs true
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "ValidSaveSlotVersion") == 0) {
|
|
stack->correctParams(1);
|
|
/* int slot = */ stack->pop()->getInt();
|
|
// do nothing
|
|
stack->pushBool(true);
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [FoxTail] GetScreenType
|
|
// Returns 0 on fullscreen and 1 on window
|
|
// Used to init and update controls at options.script and methods.script
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetScreenType") == 0) {
|
|
stack->correctParams(0);
|
|
int type = _renderer->isWindowed() ? 1 : 0;
|
|
stack->pushInt(type);
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [FoxTail] GetScreenMode
|
|
// Returns integer to be used as a pixelization mode multiplier
|
|
// (e.g. it returns 2 for 640x360, 3 for 960x540, etc...)
|
|
// Used to init and update controls at options.script and methods.script
|
|
// This implementation always return 2 to fake window size of 2*320 x 2*180
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetScreenMode") == 0) {
|
|
stack->correctParams(0);
|
|
stack->pushInt(2);
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [FoxTail] GetDesktopDisplayMode
|
|
// Return struct with "w" and "h" fields in 1.2.362-
|
|
// Return array with "w" and "h" items in 1.2.527+
|
|
// Used to init and update controls at options.script and methods.script
|
|
// w,h of actual desktop size expected to calcucate maximum available size
|
|
// Available screen modes are calcucated as 2...N, N*320<w and N*180<h
|
|
// This implementation fakes available size as 2*320 x 2*180 only
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetDesktopDisplayMode") == 0) {
|
|
stack->correctParams(0);
|
|
stack->pushInt(2 * 180 + 1);
|
|
stack->pushInt(2 * 320 + 1);
|
|
|
|
BaseScriptable *obj;
|
|
if (BaseEngine::instance().isFoxTail(FOXTAIL_1_2_527, FOXTAIL_LATEST_VERSION)) {
|
|
stack->pushInt(2);
|
|
obj = makeSXArray(_game, stack);
|
|
} else {
|
|
stack->pushInt(0);
|
|
obj = makeSXObject(_game, stack);
|
|
obj->scSetProperty("w", stack->pop());
|
|
obj->scSetProperty("h", stack->pop());
|
|
}
|
|
stack->pushNative(obj, false);
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [FoxTail] SetScreenTypeMode
|
|
// This implementation ignores mode, toggles screen type only
|
|
// Used to change screen type&mode at options.script and methods.script
|
|
// Return value is never used
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SetScreenTypeMode") == 0) {
|
|
stack->correctParams(2);
|
|
int type = stack->pop()->getInt();
|
|
stack->pop()->getInt(); // mode is unused
|
|
|
|
_renderer->setWindowed(type);
|
|
stack->pushNULL();
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [FoxTail] ChangeWindowGrab
|
|
// Used at game.script on "Keypress" event on F11
|
|
// Readme of FoxTail says: "F11 - free the mouse pointer from the window"
|
|
// This implementation does nothing
|
|
// Return value is never used
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "ChangeWindowGrab") == 0) {
|
|
stack->correctParams(0);
|
|
stack->pushNULL();
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [FoxTail] GetFiles
|
|
// Used at kalimba.script on F9 keypress to reload list of available music
|
|
// Known params: "*.mb"
|
|
// Original implementation does not seem to look up at DCP packages
|
|
// This implementation looks up at savegame storage and for actual files
|
|
// Return value expected to be an Array of Strings
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetFiles") == 0) {
|
|
stack->correctParams(1);
|
|
const char *pattern = stack->pop()->getString();
|
|
|
|
Common::StringArray fnames;
|
|
BaseFileManager::getEngineInstance()->listMatchingFiles(fnames, pattern);
|
|
|
|
stack->pushInt(0);
|
|
BaseScriptable *arr = makeSXArray(_game, stack);
|
|
for (uint32 i = 0; i < fnames.size(); i++) {
|
|
stack->pushString(fnames[i].c_str());
|
|
((SXArray *)arr)->push(stack->pop());
|
|
}
|
|
|
|
stack->pushNative(arr, false);
|
|
return STATUS_OK;
|
|
}
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// RegWriteNumber
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "RegWriteNumber") == 0) {
|
|
stack->correctParams(2);
|
|
const char *key = stack->pop()->getString();
|
|
int val = stack->pop()->getInt();
|
|
Common::String privKey = "priv_" + StringUtil::encodeSetting(key);
|
|
ConfMan.setInt(privKey, val);
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// RegReadNumber
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "RegReadNumber") == 0) {
|
|
stack->correctParams(2);
|
|
const char *key = stack->pop()->getString();
|
|
int initVal = stack->pop()->getInt();
|
|
Common::String privKey = "priv_" + StringUtil::encodeSetting(key);
|
|
int result = initVal;
|
|
if (ConfMan.hasKey(privKey)) {
|
|
result = ConfMan.getInt(privKey);
|
|
}
|
|
stack->pushInt(result);
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// RegWriteString
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "RegWriteString") == 0) {
|
|
stack->correctParams(2);
|
|
const char *key = stack->pop()->getString();
|
|
const char *val = stack->pop()->getString();
|
|
Common::String privKey = "wme_" + StringUtil::encodeSetting(key);
|
|
Common::String privVal = StringUtil::encodeSetting(val);
|
|
ConfMan.set(privKey, privVal);
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// RegReadString
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "RegReadString") == 0) {
|
|
stack->correctParams(2);
|
|
const char *key = stack->pop()->getString();
|
|
const char *initVal = stack->pop()->getString();
|
|
Common::String result = readRegistryString(key, initVal);
|
|
stack->pushString(result.c_str());
|
|
return STATUS_OK;
|
|
}
|
|
|
|
#ifdef ENABLE_HEROCRAFT
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [HeroCraft] GetSpriteControl
|
|
// Returns some internal state
|
|
// Known return values are:
|
|
// * 44332211: MUST be returned at "game.script" to allow game start
|
|
// * 77885566: may be returned at "mainMenu.script" to force open registration window
|
|
// * 90123679: may be returned at "mainMenu.script" to make "Buy Game" button visible
|
|
// Used at "Pole Chudes" only
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetSpriteControl") == 0) {
|
|
stack->correctParams(0);
|
|
stack->pushInt(44332211L);
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [HeroCraft] RandomInitSeed
|
|
// Additional method to be called before RandomSeed()
|
|
// Used at "Pole Chudes" only
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "RandomInitSeed") == 0) {
|
|
stack->correctParams(1);
|
|
int seed = stack->pop()->getInt();
|
|
|
|
_rndHc->setSeed(seed);
|
|
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [HeroCraft] RandomSeed
|
|
// Similar to usual Random() function, but using seed provided earlier
|
|
// Used at "Pole Chudes" only
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "RandomSeed") == 0) {
|
|
stack->correctParams(2);
|
|
|
|
int from = stack->pop()->getInt();
|
|
int to = stack->pop()->getInt();
|
|
int rnd = _rndHc->getRandomNumberRng(from, to);
|
|
|
|
stack->pushInt(rnd);
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [HeroCraft] GetImageInfo
|
|
// Returns image size in "<width>;<height>" format, e.g. "800;600"
|
|
// Known params: "fsdata\\splash1.jpg"
|
|
// Game script turn off scaling if returned value is "1024;768"
|
|
// Used at "Papa's Daughters 1" only
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetImageInfo") == 0) {
|
|
stack->correctParams(1);
|
|
/*const char *filename =*/ stack->pop()->getString();
|
|
stack->pushString("1024;768");
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [HeroCraft] A lot of functions used for self-check
|
|
// Used at "Papa's Daughters 2" only
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "DeleteItems") == 0 || strcmp(name, "CreateActorItems") == 0 || strcmp(name, "DeleteActorItems") == 0 || strcmp(name, "PrepareItems") == 0 || strcmp(name, "CreateEntityItems") == 0 || strcmp(name, "DeleteEntityItems") == 0 || strcmp(name, "PrepareItemsWin") == 0 || strcmp(name, "CreateItems") == 0) {
|
|
stack->correctParams(3);
|
|
uint32 a = (uint32)stack->pop()->getInt();
|
|
uint32 b = (uint32)stack->pop()->getInt();
|
|
uint32 c = (uint32)stack->pop()->getInt();
|
|
|
|
uint32 result = 0;
|
|
const char* fname = "PapasDaughters2.wrp.exe";
|
|
if (strcmp(name, "PrepareItems") == 0 || strcmp(name, "CreateEntityItems") == 0 || strcmp(name, "DeleteEntityItems") == 0) {
|
|
result = getFilePartChecksumHc(fname, b, a);
|
|
} else if (strcmp(name, "PrepareItemsWin") == 0) {
|
|
result = getFilePartChecksumHc(fname, b, c);
|
|
} else if (strcmp(name, "CreateItems") == 0) {
|
|
result = getFilePartChecksumHc(fname, a, c);
|
|
} else {
|
|
result = getFilePartChecksumHc(fname, a, b);
|
|
}
|
|
|
|
stack->pushInt(result);
|
|
return STATUS_OK;
|
|
}
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SaveGame
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SaveGame") == 0) {
|
|
stack->correctParams(3);
|
|
int slot = stack->pop()->getInt();
|
|
const char *xdesc = stack->pop()->getString();
|
|
size_t descSize = strlen(xdesc) + 1;
|
|
char *desc = new char[descSize];
|
|
Common::strcpy_s(desc, descSize, xdesc);
|
|
bool quick = stack->pop()->getBool(false);
|
|
|
|
stack->pushBool(true);
|
|
if (DID_FAIL(saveGame(slot, desc, quick))) {
|
|
stack->pop();
|
|
stack->pushBool(false);
|
|
}
|
|
delete[] desc;
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// LoadGame
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "LoadGame") == 0) {
|
|
stack->correctParams(1);
|
|
_scheduledLoadSlot = stack->pop()->getInt();
|
|
_loading = true;
|
|
stack->pushBool(false);
|
|
script->sleep(0);
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// IsSaveSlotUsed
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "IsSaveSlotUsed") == 0) {
|
|
stack->correctParams(1);
|
|
int slot = stack->pop()->getInt();
|
|
stack->pushBool(isSaveSlotUsed(slot));
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetSaveSlotDescription
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetSaveSlotDescription") == 0) {
|
|
stack->correctParams(1);
|
|
int slot = stack->pop()->getInt();
|
|
Common::String desc;
|
|
getSaveSlotDescription(slot, desc);
|
|
stack->pushString(desc.c_str());
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// EmptySaveSlot
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "EmptySaveSlot") == 0) {
|
|
stack->correctParams(1);
|
|
int slot = stack->pop()->getInt();
|
|
emptySaveSlot(slot);
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SetGlobalSFXVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SetGlobalSFXVolume") == 0) {
|
|
stack->correctParams(1);
|
|
_game->_soundMgr->setVolumePercent(TSoundType::SOUND_SFX, (byte)stack->pop()->getInt());
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SetGlobalSpeechVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SetGlobalSpeechVolume") == 0) {
|
|
stack->correctParams(1);
|
|
_game->_soundMgr->setVolumePercent(TSoundType::SOUND_SPEECH, (byte)stack->pop()->getInt());
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SetGlobalMusicVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SetGlobalMusicVolume") == 0) {
|
|
stack->correctParams(1);
|
|
_game->_soundMgr->setVolumePercent(TSoundType::SOUND_MUSIC, (byte)stack->pop()->getInt());
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SetGlobalMasterVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SetGlobalMasterVolume") == 0) {
|
|
stack->correctParams(1);
|
|
_game->_soundMgr->setMasterVolumePercent((byte)stack->pop()->getInt());
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetGlobalSFXVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetGlobalSFXVolume") == 0) {
|
|
stack->correctParams(0);
|
|
stack->pushInt(_soundMgr->getVolumePercent(TSoundType::SOUND_SFX));
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetGlobalSpeechVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetGlobalSpeechVolume") == 0) {
|
|
stack->correctParams(0);
|
|
stack->pushInt(_soundMgr->getVolumePercent(TSoundType::SOUND_SPEECH));
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetGlobalMusicVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetGlobalMusicVolume") == 0) {
|
|
stack->correctParams(0);
|
|
stack->pushInt(_soundMgr->getVolumePercent(TSoundType::SOUND_MUSIC));
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetGlobalMasterVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetGlobalMasterVolume") == 0) {
|
|
stack->correctParams(0);
|
|
stack->pushInt(_soundMgr->getMasterVolumePercent());
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SetActiveCursor
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SetActiveCursor") == 0) {
|
|
stack->correctParams(1);
|
|
if (DID_SUCCEED(setActiveCursor(stack->pop()->getString()))) {
|
|
stack->pushBool(true);
|
|
} else {
|
|
stack->pushBool(false);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetActiveCursor
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetActiveCursor") == 0) {
|
|
stack->correctParams(0);
|
|
if (!_activeCursor || !_activeCursor->_filename || !_activeCursor->_filename[0]) {
|
|
stack->pushNULL();
|
|
} else {
|
|
stack->pushString(_activeCursor->_filename);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetActiveCursorObject
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetActiveCursorObject") == 0) {
|
|
stack->correctParams(0);
|
|
if (!_activeCursor) {
|
|
stack->pushNULL();
|
|
} else {
|
|
stack->pushNative(_activeCursor, true);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// RemoveActiveCursor
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "RemoveActiveCursor") == 0) {
|
|
stack->correctParams(0);
|
|
SAFE_DELETE(_activeCursor);
|
|
stack->pushNULL();
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// HasActiveCursor
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "HasActiveCursor") == 0) {
|
|
stack->correctParams(0);
|
|
|
|
if (_activeCursor) {
|
|
stack->pushBool(true);
|
|
} else {
|
|
stack->pushBool(false);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// FileExists
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "FileExists") == 0) {
|
|
stack->correctParams(1);
|
|
const char *filename = stack->pop()->getString();
|
|
|
|
bool exists = _fileManager->hasFile(filename); // Had absPathWarning = false
|
|
|
|
// Used for screenshot files in "Stroke of Fate" duology
|
|
if (!exists)
|
|
exists = sfmFileExists(filename);
|
|
|
|
stack->pushBool(exists);
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// FadeOut / FadeOutAsync / SystemFadeOut / SystemFadeOutAsync
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "FadeOut") == 0 || strcmp(name, "FadeOutAsync") == 0 || strcmp(name, "SystemFadeOut") == 0 || strcmp(name, "SystemFadeOutAsync") == 0) {
|
|
stack->correctParams(5);
|
|
uint32 duration = stack->pop()->getInt(500);
|
|
byte red = stack->pop()->getInt(0);
|
|
byte green = stack->pop()->getInt(0);
|
|
byte blue = stack->pop()->getInt(0);
|
|
byte alpha = stack->pop()->getInt(0xFF);
|
|
|
|
// HACK: Corrosion fades screen to black while opening main menu
|
|
// Thus, we get black screenshots when saving game from in-game menus
|
|
// Let's take & keep screenshot before entering main menu
|
|
if (duration == 750 && BaseEngine::instance().getGameId() == "corrosion") {
|
|
SAFE_DELETE(_cachedThumbnail);
|
|
_cachedThumbnail = new SaveThumbHelper(this);
|
|
if (DID_FAIL(_cachedThumbnail->storeThumbnail())) {
|
|
SAFE_DELETE(_cachedThumbnail);
|
|
}
|
|
}
|
|
|
|
bool system = (strcmp(name, "SystemFadeOut") == 0 || strcmp(name, "SystemFadeOutAsync") == 0);
|
|
|
|
_fader->fadeOut(BYTETORGBA(red, green, blue, alpha), duration, system);
|
|
if (strcmp(name, "FadeOutAsync") != 0 && strcmp(name, "SystemFadeOutAsync") != 0) {
|
|
script->waitFor(_fader);
|
|
}
|
|
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// FadeIn / FadeInAsync / SystemFadeIn / SystemFadeInAsync
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "FadeIn") == 0 || strcmp(name, "FadeInAsync") == 0 || strcmp(name, "SystemFadeIn") == 0 || strcmp(name, "SystemFadeInAsync") == 0) {
|
|
stack->correctParams(5);
|
|
uint32 duration = stack->pop()->getInt(500);
|
|
byte red = stack->pop()->getInt(0);
|
|
byte green = stack->pop()->getInt(0);
|
|
byte blue = stack->pop()->getInt(0);
|
|
byte alpha = stack->pop()->getInt(0xFF);
|
|
|
|
bool system = (strcmp(name, "SystemFadeIn") == 0 || strcmp(name, "SystemFadeInAsync") == 0);
|
|
|
|
_fader->fadeIn(BYTETORGBA(red, green, blue, alpha), duration, system);
|
|
if (strcmp(name, "FadeInAsync") != 0 && strcmp(name, "SystemFadeInAsync") != 0) {
|
|
script->waitFor(_fader);
|
|
}
|
|
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetFadeColor
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetFadeColor") == 0) {
|
|
stack->correctParams(0);
|
|
stack->pushInt(_fader->getCurrentColor());
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Screenshot
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Screenshot") == 0) {
|
|
stack->correctParams(1);
|
|
char filename[MAX_PATH_LENGTH];
|
|
|
|
ScValue *val = stack->pop();
|
|
|
|
int fileNum = 0;
|
|
while (true) {
|
|
Common::sprintf_s(filename, "%s%03d.bmp", val->isNULL() ? _name : val->getString(), fileNum);
|
|
if (!sfmFileExists(filename)) {
|
|
break;
|
|
}
|
|
fileNum++;
|
|
}
|
|
|
|
// redraw before taking screenshot
|
|
_game->displayContent(false);
|
|
|
|
bool ret = false;
|
|
BaseImage *image = _game->_renderer->takeScreenshot();
|
|
if (image) {
|
|
ret = DID_SUCCEED(image->saveBMPFile(filename));
|
|
delete image;
|
|
} else {
|
|
ret = false;
|
|
}
|
|
|
|
stack->pushBool(ret);
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// ScreenshotEx
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "ScreenshotEx") == 0) {
|
|
stack->correctParams(3);
|
|
const char *filename = stack->pop()->getString();
|
|
int sizeX = stack->pop()->getInt(_renderer->getWidth());
|
|
int sizeY = stack->pop()->getInt(_renderer->getHeight());
|
|
|
|
// redraw before taking screenshot
|
|
_game->displayContent(false);
|
|
|
|
bool ret = false;
|
|
BaseImage *image = _game->_renderer->takeScreenshot(sizeX, sizeY);
|
|
if (image) {
|
|
ret = DID_SUCCEED(image->saveBMPFile(filename));
|
|
delete image;
|
|
} else {
|
|
ret = false;
|
|
}
|
|
|
|
stack->pushBool(ret);
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CreateWindow
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "CreateWindow") == 0) {
|
|
stack->correctParams(1);
|
|
ScValue *val = stack->pop();
|
|
|
|
UIWindow *win = new UIWindow(_game);
|
|
_windows.add(win);
|
|
registerObject(win);
|
|
if (!val->isNULL()) {
|
|
win->setName(val->getString());
|
|
}
|
|
stack->pushNative(win, true);
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// DeleteWindow
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "DeleteWindow") == 0) {
|
|
stack->correctParams(1);
|
|
BaseObject *obj = (BaseObject *)stack->pop()->getNative();
|
|
for (int32 i = 0; i < _windows.getSize(); i++) {
|
|
if (_windows[i] == obj) {
|
|
unregisterObject(_windows[i]);
|
|
stack->pushBool(true);
|
|
return STATUS_OK;
|
|
}
|
|
}
|
|
stack->pushBool(false);
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// OpenDocument
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "OpenDocument") == 0) {
|
|
stack->correctParams(1);
|
|
g_system->openUrl(stack->pop()->getString());
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// DEBUG_DumpClassRegistry
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "DEBUG_DumpClassRegistry") == 0) {
|
|
stack->correctParams(0);
|
|
DEBUG_DumpClassRegistry();
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SetLoadingScreen
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SetLoadingScreen") == 0) {
|
|
stack->correctParams(3);
|
|
ScValue *val = stack->pop();
|
|
_loadImageX = stack->pop()->getInt();
|
|
_loadImageY = stack->pop()->getInt();
|
|
|
|
if (val->isNULL()) {
|
|
SAFE_DELETE_ARRAY(_loadImageName);
|
|
} else {
|
|
BaseUtils::setString(&_loadImageName, val->getString());
|
|
}
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SetSavingScreen
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SetSavingScreen") == 0) {
|
|
stack->correctParams(3);
|
|
ScValue *val = stack->pop();
|
|
_saveImageX = stack->pop()->getInt();
|
|
_saveImageY = stack->pop()->getInt();
|
|
|
|
if (val->isNULL()) {
|
|
SAFE_DELETE_ARRAY(_saveImageName);
|
|
} else {
|
|
BaseUtils::setString(&_saveImageName, val->getString());
|
|
}
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SetWaitCursor
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SetWaitCursor") == 0) {
|
|
stack->correctParams(1);
|
|
if (DID_SUCCEED(setWaitCursor(stack->pop()->getString()))) {
|
|
stack->pushBool(true);
|
|
} else {
|
|
stack->pushBool(false);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// RemoveWaitCursor
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "RemoveWaitCursor") == 0) {
|
|
stack->correctParams(0);
|
|
SAFE_DELETE(_cursorNoninteractive);
|
|
stack->pushNULL();
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetWaitCursor
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetWaitCursor") == 0) {
|
|
stack->correctParams(0);
|
|
if (!_cursorNoninteractive || !_cursorNoninteractive->_filename) {
|
|
stack->pushNULL();
|
|
} else {
|
|
stack->pushString(_cursorNoninteractive->_filename);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetWaitCursorObject
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetWaitCursorObject") == 0) {
|
|
stack->correctParams(0);
|
|
if (!_cursorNoninteractive) {
|
|
stack->pushNULL();
|
|
} else {
|
|
stack->pushNative(_cursorNoninteractive, true);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// ClearScriptCache
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "ClearScriptCache") == 0) {
|
|
stack->correctParams(0);
|
|
stack->pushBool(DID_SUCCEED(_scEngine->emptyScriptCache()));
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// DisplayLoadingIcon
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "DisplayLoadingIcon") == 0) {
|
|
stack->correctParams(4);
|
|
|
|
const char *filename = stack->pop()->getString();
|
|
_loadingIconX = stack->pop()->getInt();
|
|
_loadingIconY = stack->pop()->getInt();
|
|
_loadingIconPersistent = stack->pop()->getBool();
|
|
|
|
SAFE_DELETE(_loadingIcon);
|
|
_loadingIcon = new BaseSprite(this);
|
|
if (!_loadingIcon || DID_FAIL(_loadingIcon->loadFile(filename))) {
|
|
SAFE_DELETE(_loadingIcon);
|
|
} else {
|
|
displayContent(false, true);
|
|
_game->_renderer->flip();
|
|
_game->_renderer->initLoop();
|
|
}
|
|
stack->pushNULL();
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// HideLoadingIcon
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "HideLoadingIcon") == 0) {
|
|
stack->correctParams(0);
|
|
SAFE_DELETE(_loadingIcon);
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// DumpTextureStats
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "DumpTextureStats") == 0) {
|
|
stack->correctParams(1);
|
|
const char *filename = stack->pop()->getString();
|
|
|
|
_renderer->dumpData(filename);
|
|
|
|
stack->pushNULL();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// AccOutputText
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "AccOutputText") == 0) {
|
|
stack->correctParams(2);
|
|
/* const char *str = */stack->pop()->getString();
|
|
/* int type = */stack->pop()->getInt();
|
|
//m_AccessMgr->Speak(Str, (TTTSType)Type);
|
|
stack->pushNULL();
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
#ifdef ENABLE_WME3D
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// IsShadowTypeSupported
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "IsShadowTypeSupported") == 0) {
|
|
stack->correctParams(1);
|
|
TShadowType type = static_cast<TShadowType>(stack->pop()->getInt());
|
|
|
|
switch (type) {
|
|
case SHADOW_NONE:
|
|
case SHADOW_SIMPLE:
|
|
stack->pushBool(true);
|
|
break;
|
|
|
|
case SHADOW_FLAT:
|
|
_renderer3D->enableShadows();
|
|
stack->pushBool(_supportsRealTimeShadows);
|
|
break;
|
|
|
|
case SHADOW_STENCIL:
|
|
stack->pushBool(_renderer3D->shadowVolumeSupported());
|
|
break;
|
|
|
|
default:
|
|
stack->pushBool(false);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// StoreSaveThumbnail
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "StoreSaveThumbnail") == 0) {
|
|
stack->correctParams(0);
|
|
SAFE_DELETE(_cachedThumbnail);
|
|
_cachedThumbnail = new SaveThumbHelper(this);
|
|
if (DID_FAIL(_cachedThumbnail->storeThumbnail())) {
|
|
SAFE_DELETE(_cachedThumbnail);
|
|
stack->pushBool(false);
|
|
} else {
|
|
stack->pushBool(true);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// DeleteSaveThumbnail
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "DeleteSaveThumbnail") == 0) {
|
|
stack->correctParams(0);
|
|
SAFE_DELETE(_cachedThumbnail);
|
|
stack->pushNULL();
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetFileChecksum
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetFileChecksum") == 0) {
|
|
stack->correctParams(2);
|
|
const char *filename = stack->pop()->getString();
|
|
bool asHex = stack->pop()->getBool(false);
|
|
|
|
Common::SeekableReadStream *file = _fileManager->openFile(filename, false);
|
|
if (file) {
|
|
crc remainder = crc_initialize();
|
|
byte buf[1024];
|
|
int32 bytesRead = 0;
|
|
|
|
while (bytesRead < file->size()) {
|
|
int32 bufSize = MIN<int32>(1024, (int32)file->size() - bytesRead);
|
|
bytesRead += file->read(buf, bufSize);
|
|
|
|
for (int32 i = 0; i < bufSize; i++) {
|
|
remainder = crc_process_byte(buf[i], remainder);
|
|
}
|
|
}
|
|
crc checksum = crc_finalize(remainder);
|
|
|
|
if (asHex) {
|
|
char hex[100];
|
|
Common::sprintf_s(hex, "%x", checksum);
|
|
stack->pushString(hex);
|
|
} else {
|
|
stack->pushInt(checksum);
|
|
}
|
|
|
|
_fileManager->closeFile(file);
|
|
file = nullptr;
|
|
} else {
|
|
stack->pushNULL();
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// EnableScriptProfiling
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "EnableScriptProfiling") == 0) {
|
|
stack->correctParams(0);
|
|
_scEngine->enableProfiling();
|
|
stack->pushNULL();
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// DisableScriptProfiling
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "DisableScriptProfiling") == 0) {
|
|
stack->correctParams(0);
|
|
_scEngine->disableProfiling();
|
|
stack->pushNULL();
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// ShowStatusLine
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "ShowStatusLine") == 0) {
|
|
stack->correctParams(0);
|
|
stack->pushNULL();
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// HideStatusLine
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "HideStatusLine") == 0) {
|
|
stack->correctParams(0);
|
|
stack->pushNULL();
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// ShowURLInBrowser
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "ShowURLInBrowser") == 0) {
|
|
stack->correctParams(1);
|
|
|
|
/*const char *URLToShow = */stack->pop()->getString();
|
|
stack->pushNULL();
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// advertisementPrepare
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "advertisementPrepare") == 0) {
|
|
stack->correctParams(2);
|
|
|
|
/*const char *key = */stack->pop()->getString();
|
|
/*int32 number = */stack->pop()->getInt();
|
|
int32 ret = 0;
|
|
stack->pushInt(ret);
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// advertisementShow
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "advertisementShow") == 0) {
|
|
stack->correctParams(2);
|
|
|
|
/*const char *key = */stack->pop()->getString();
|
|
/*int32 number = */stack->pop()->getInt();
|
|
int32 ret = 0;
|
|
stack->pushInt(ret);
|
|
|
|
return STATUS_OK;
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SetWindowedMode
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SetWindowedMode") == 0) {
|
|
stack->correctParams(1);
|
|
|
|
/*bool mode = */stack->pop()->getBool(false);
|
|
|
|
// Disable controlling fullscreen mode from scripts.
|
|
// Better handing by backend.
|
|
//_renderer->setWindowed(mode);
|
|
|
|
stack->pushNULL();
|
|
|
|
return STATUS_OK;
|
|
} else {
|
|
return BaseObject::scCallMethod(script, stack, thisStack, name);
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
ScValue *BaseGame::scGetProperty(const char *name) {
|
|
_scValue->setNULL();
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Type
|
|
//////////////////////////////////////////////////////////////////////////
|
|
if (strcmp(name, "Type") == 0) {
|
|
_scValue->setString("game");
|
|
return _scValue;
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Name
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Name") == 0) {
|
|
_scValue->setString(_name);
|
|
return _scValue;
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Hwnd (RO)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Hwnd") == 0) {
|
|
_scValue->setInt((int)_renderer->_window);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CurrentTime (RO)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "CurrentTime") == 0) {
|
|
_scValue->setInt((int)_timer);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// WindowsTime (RO)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "WindowsTime") == 0) {
|
|
_scValue->setInt((int)BasePlatform::getTime());
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// WindowedMode (RO)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "WindowedMode") == 0) {
|
|
_scValue->setBool(_renderer->isWindowed());
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// MouseX
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "MouseX") == 0) {
|
|
_scValue->setInt(_mousePos.x);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// MouseY
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "MouseY") == 0) {
|
|
_scValue->setInt(_mousePos.y);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// MainObject
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "MainObject") == 0) {
|
|
_scValue->setNative(_mainObject, true);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// ActiveObject (RO)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "ActiveObject") == 0) {
|
|
_scValue->setNative(_activeObject, true);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// ScreenWidth (RO)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "ScreenWidth") == 0) {
|
|
_scValue->setInt(_renderer->getWidth());
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// ScreenHeight (RO)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "ScreenHeight") == 0) {
|
|
_scValue->setInt(_renderer->getHeight());
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Interactive
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Interactive") == 0) {
|
|
_scValue->setBool(_interactive);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// DebugMode (RO)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "DebugMode") == 0) {
|
|
_scValue->setBool(_debugMode);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SoundAvailable (RO)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SoundAvailable") == 0) {
|
|
_scValue->setBool(_soundMgr->_soundAvailable);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SFXVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SFXVolume") == 0) {
|
|
//_game->LOG(0, "**Warning** The SFXVolume attribute is obsolete");
|
|
_scValue->setInt(_soundMgr->getVolumePercent(TSoundType::SOUND_SFX));
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SpeechVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SpeechVolume") == 0) {
|
|
//_game->LOG(0, "**Warning** The SpeechVolume attribute is obsolete");
|
|
_scValue->setInt(_soundMgr->getVolumePercent(TSoundType::SOUND_SPEECH));
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// MusicVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "MusicVolume") == 0) {
|
|
//_game->LOG(0, "**Warning** The MusicVolume attribute is obsolete");
|
|
_scValue->setInt(_soundMgr->getVolumePercent(TSoundType::SOUND_MUSIC));
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// MasterVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "MasterVolume") == 0) {
|
|
//_game->LOG(0, "**Warning** The MasterVolume attribute is obsolete");
|
|
_scValue->setInt(_soundMgr->getMasterVolumePercent());
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Keyboard (RO)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Keyboard") == 0) {
|
|
if (_keyboardState) {
|
|
_scValue->setNative(_keyboardState, true);
|
|
} else {
|
|
_scValue->setNULL();
|
|
}
|
|
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Subtitles
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Subtitles") == 0) {
|
|
_scValue->setBool(_subtitles);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SubtitlesSpeed
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SubtitlesSpeed") == 0) {
|
|
_scValue->setInt(_subtitlesSpeed);
|
|
return _scValue;
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// VideoSubtitles
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "VideoSubtitles") == 0) {
|
|
_scValue->setBool(_videoSubtitles);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// FPS (RO)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "FPS") == 0) {
|
|
_scValue->setInt(_fps);
|
|
return _scValue;
|
|
}
|
|
|
|
#ifdef ENABLE_WME3D
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Shadows (obsolete)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Shadows") == 0) {
|
|
_scValue->setBool(_maxShadowType > SHADOW_NONE);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SimpleShadows (obsolete)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SimpleShadows") == 0) {
|
|
_scValue->setBool(_maxShadowType == SHADOW_SIMPLE);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SupportsRealTimeShadows (obsolete)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SupportsRealTimeShadows") == 0) {
|
|
_renderer3D->enableShadows();
|
|
_scValue->setBool(_supportsRealTimeShadows);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// MaxShadowType
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "MaxShadowType") == 0) {
|
|
_scValue->setInt(_maxShadowType);
|
|
return _scValue;
|
|
}
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// AcceleratedMode / Accelerated (RO)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "AcceleratedMode") == 0 || strcmp(name, "Accelerated") == 0) {
|
|
_scValue->setBool(_useD3D);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// TextEncoding
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "TextEncoding") == 0) {
|
|
_scValue->setInt(_textEncoding);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// TextRTL
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "TextRTL") == 0) {
|
|
_scValue->setBool(_textRTL);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SoundBufferSize
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SoundBufferSize") == 0) {
|
|
_scValue->setInt(_soundBufferSizeSec);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SuspendedRendering
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SuspendedRendering") == 0) {
|
|
_scValue->setBool(_suspendedRendering);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SuppressScriptErrors
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SuppressScriptErrors") == 0) {
|
|
_scValue->setBool(_suppressScriptErrors);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Frozen
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Frozen") == 0) {
|
|
_scValue->setBool(_state == GAME_FROZEN);
|
|
return _scValue;
|
|
}
|
|
|
|
#ifdef ENABLE_WME3D
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Direct3DDevice
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Direct3DDevice") == 0) {
|
|
if (_game->_useD3D)
|
|
_scValue->setInt((int)('D3DH'));
|
|
else
|
|
_scValue->setNULL();
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// DirectDrawInterface
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "DirectDrawInterface") == 0) {
|
|
if (!_game->_useD3D)
|
|
_scValue->setInt((int)('DDIH'));
|
|
else
|
|
_scValue->setNULL();
|
|
return _scValue;
|
|
}
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// AccTTSEnabled
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "AccTTSEnabled") == 0) {
|
|
_scValue->setBool(_accessTTSEnabled);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// AccTTSTalk
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "AccTTSTalk") == 0) {
|
|
_scValue->setBool(_accessTTSTalk);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// AccTTSCaptions
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "AccTTSCaptions") == 0) {
|
|
_scValue->setBool(_accessTTSCaptions);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// AccTTSKeypress
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "AccTTSKeypress") == 0) {
|
|
_scValue->setBool(_accessTTSKeypress);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// AccKeyboardEnabled
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "AccKeyboardEnabled") == 0) {
|
|
_scValue->setBool(_accessKeyboardEnabled);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// AccKeyboardCursorSkip
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "AccKeyboardCursorSkip") == 0) {
|
|
_scValue->setBool(_accessKeyboardCursorSkip);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// AccKeyboardPause
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "AccKeyboardPause") == 0) {
|
|
_scValue->setBool(_accessKeyboardPause);
|
|
return _scValue;
|
|
}
|
|
|
|
#ifdef ENABLE_WME3D
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// UsedMemory
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "UsedMemory") == 0) {
|
|
// wme only returns a non-zero value in debug mode
|
|
_scValue->setInt(0);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// MaxActiveLights
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "MaxActiveLights") == 0) {
|
|
if (_useD3D) {
|
|
BaseRenderer3D *renderer = _game->_renderer3D;
|
|
_scValue->setInt(renderer->getMaxActiveLights());
|
|
} else {
|
|
_scValue->setInt(0);
|
|
}
|
|
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// HardwareTL
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "HardwareTL") == 0) {
|
|
// always support hardware transformations and lights
|
|
_scValue->setBool(true);
|
|
return _scValue;
|
|
}
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// AutorunDisabled
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "AutorunDisabled") == 0) {
|
|
_scValue->setBool(_autorunDisabled);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SaveDirectory (RO)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SaveDirectory") == 0) {
|
|
AnsiString dataDir = "saves"; // See also: SXDirectory::scGetProperty("TempDirectory")
|
|
_scValue->setString(dataDir.c_str());
|
|
return _scValue;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// AutoSaveOnExit
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "AutoSaveOnExit") == 0) {
|
|
_scValue->setBool(_autoSaveOnExit);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// AutoSaveSlot
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "AutoSaveSlot") == 0) {
|
|
_scValue->setInt(_autoSaveSlot);
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CursorHidden
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "CursorHidden") == 0) {
|
|
_scValue->setBool(_cursorHidden);
|
|
return _scValue;
|
|
}
|
|
|
|
#ifdef ENABLE_FOXTAIL
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [FoxTail] SystemLanguage (RO)
|
|
// Returns Steam API language name string
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SystemLanguage") == 0) {
|
|
switch (Common::parseLanguage(ConfMan.get("language"))) {
|
|
case Common::CS_CZE:
|
|
_scValue->setString("czech");
|
|
break;
|
|
case Common::DA_DNK:
|
|
_scValue->setString("danish");
|
|
break;
|
|
case Common::DE_DEU:
|
|
_scValue->setString("german");
|
|
break;
|
|
case Common::ES_ESP:
|
|
_scValue->setString("spanish");
|
|
break;
|
|
case Common::FI_FIN:
|
|
_scValue->setString("finnish");
|
|
break;
|
|
case Common::FR_FRA:
|
|
_scValue->setString("french");
|
|
break;
|
|
case Common::EL_GRC:
|
|
_scValue->setString("greek");
|
|
break;
|
|
case Common::HU_HUN:
|
|
_scValue->setString("hungarian");
|
|
break;
|
|
case Common::IT_ITA:
|
|
_scValue->setString("italian");
|
|
break;
|
|
case Common::JA_JPN:
|
|
_scValue->setString("japanese");
|
|
break;
|
|
case Common::KO_KOR:
|
|
_scValue->setString("koreana");
|
|
break;
|
|
case Common::NB_NOR:
|
|
_scValue->setString("norwegian");
|
|
break;
|
|
case Common::NL_NLD:
|
|
_scValue->setString("dutch");
|
|
break;
|
|
case Common::PT_BRA:
|
|
_scValue->setString("brazilian");
|
|
break;
|
|
case Common::PT_PRT:
|
|
_scValue->setString("portuguese");
|
|
break;
|
|
case Common::PL_POL:
|
|
_scValue->setString("polish");
|
|
break;
|
|
case Common::RU_RUS:
|
|
_scValue->setString("russian");
|
|
break;
|
|
case Common::SV_SWE:
|
|
_scValue->setString("swedish");
|
|
break;
|
|
case Common::UA_UKR:
|
|
_scValue->setString("ukrainian");
|
|
break;
|
|
case Common::ZH_CHN:
|
|
_scValue->setString("schinese");
|
|
break;
|
|
case Common::ZH_TWN:
|
|
_scValue->setString("tchinese");
|
|
break;
|
|
default:
|
|
_scValue->setString("english");
|
|
break;
|
|
}
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [FoxTail] BuildVersion (RO)
|
|
// Used to display full game version at options.script in UpdateControls()
|
|
// Returns FoxTail engine version number as a dotted string
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "BuildVersion") == 0) {
|
|
if (BaseEngine::instance().getTargetExecutable() == FOXTAIL_1_2_227) {
|
|
_scValue->setString("1.2.227");
|
|
} else if (BaseEngine::instance().getTargetExecutable() == FOXTAIL_1_2_230) {
|
|
_scValue->setString("1.2.230");
|
|
} else if (BaseEngine::instance().getTargetExecutable() == FOXTAIL_1_2_304) {
|
|
_scValue->setString("1.2.304");
|
|
} else if (BaseEngine::instance().getTargetExecutable() == FOXTAIL_1_2_362) {
|
|
_scValue->setString("1.2.362");
|
|
} else if (BaseEngine::instance().getTargetExecutable() == FOXTAIL_1_2_527) {
|
|
_scValue->setString("1.2.527");
|
|
} else if (BaseEngine::instance().getTargetExecutable() == FOXTAIL_1_2_896) {
|
|
_scValue->setString("1.2.896");
|
|
} else if (BaseEngine::instance().getTargetExecutable() == FOXTAIL_1_2_902) {
|
|
_scValue->setString("1.2.902");
|
|
} else {
|
|
_scValue->setString("UNKNOWN");
|
|
}
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [FoxTail] GameVersion (RO)
|
|
// Used to display full game version at options.script in UpdateControls()
|
|
// Returns FoxTail version number as a string
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GameVersion") == 0) {
|
|
uint32 gameVersion = 0;
|
|
BaseFileManager *fileManager = BaseEngine::instance().getFileManager();
|
|
if (fileManager) {
|
|
gameVersion = fileManager->getPackageVersion("data.dcp");
|
|
}
|
|
char tmp[16];
|
|
Common::sprintf_s(tmp,"%u",gameVersion);
|
|
_scValue->setString(tmp);
|
|
return _scValue;
|
|
}
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Platform (RO)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Platform") == 0 &&
|
|
BaseEngine::instance().getGameId() != "royalmahjong") { // avoid clashing
|
|
_scValue->setString(BasePlatform::getPlatformName().c_str());
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// DeviceType (RO)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "DeviceType") == 0) {
|
|
_scValue->setString(getDeviceType().c_str());
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// MostRecentSaveSlot (RO)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "MostRecentSaveSlot") == 0) {
|
|
if (!ConfMan.hasKey("most_recent_saveslot")) {
|
|
_scValue->setInt(-1);
|
|
} else {
|
|
_scValue->setInt(ConfMan.getInt("most_recent_saveslot"));
|
|
}
|
|
return _scValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Store (RO)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Store") == 0) {
|
|
_scValue->setNULL();
|
|
error("Request for a SXStore-object, which is not supported by ScummVM");
|
|
|
|
return _scValue;
|
|
} else {
|
|
return BaseObject::scGetProperty(name);
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::scSetProperty(const char *name, ScValue *value) {
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Name
|
|
//////////////////////////////////////////////////////////////////////////
|
|
if (strcmp(name, "Name") == 0) {
|
|
setName(value->getString());
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// MouseX
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "MouseX") == 0) {
|
|
_mousePos.x = value->getInt();
|
|
resetMousePos();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// MouseY
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "MouseY") == 0) {
|
|
_mousePos.y = value->getInt();
|
|
resetMousePos();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Caption
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Name") == 0) {
|
|
bool res = BaseObject::scSetProperty(name, value);
|
|
setWindowTitle();
|
|
return res;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// MainObject
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "MainObject") == 0) {
|
|
BaseScriptable *obj = value->getNative();
|
|
if (obj == nullptr || validObject((BaseObject *)obj)) {
|
|
_mainObject = (BaseObject *)obj;
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Interactive
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Interactive") == 0) {
|
|
setInteractive(value->getBool());
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SFXVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SFXVolume") == 0) {
|
|
//_game->LOG(0, "**Warning** The SFXVolume attribute is obsolete");
|
|
_game->_soundMgr->setVolumePercent(TSoundType::SOUND_SFX, (byte)value->getInt());
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SpeechVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SpeechVolume") == 0) {
|
|
//_game->LOG(0, "**Warning** The SpeechVolume attribute is obsolete");
|
|
_game->_soundMgr->setVolumePercent(TSoundType::SOUND_SPEECH, (byte)value->getInt());
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// MusicVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "MusicVolume") == 0) {
|
|
//_game->LOG(0, "**Warning** The MusicVolume attribute is obsolete");
|
|
_game->_soundMgr->setVolumePercent(TSoundType::SOUND_MUSIC, (byte)value->getInt());
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// MasterVolume
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "MasterVolume") == 0) {
|
|
//_game->LOG(0, "**Warning** The MasterVolume attribute is obsolete");
|
|
_game->_soundMgr->setMasterVolumePercent((byte)value->getInt());
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Subtitles
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Subtitles") == 0) {
|
|
_subtitles = value->getBool();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SubtitlesSpeed
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SubtitlesSpeed") == 0) {
|
|
_subtitlesSpeed = value->getInt();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// VideoSubtitles
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "VideoSubtitles") == 0) {
|
|
_videoSubtitles = value->getBool();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
#ifdef ENABLE_WME3D
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Shadows (obsolete)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Shadows") == 0) {
|
|
if (value->getBool()) {
|
|
setMaxShadowType(SHADOW_STENCIL);
|
|
} else {
|
|
setMaxShadowType(SHADOW_NONE);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SimpleShadows (obsolete)
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SimpleShadows") == 0) {
|
|
if (value->getBool()) {
|
|
setMaxShadowType(SHADOW_SIMPLE);
|
|
} else {
|
|
setMaxShadowType(SHADOW_STENCIL);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// MaxShadowType
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "MaxShadowType") == 0) {
|
|
setMaxShadowType(static_cast<TShadowType>(value->getInt()));
|
|
return STATUS_OK;
|
|
}
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// TextEncoding
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "TextEncoding") == 0) {
|
|
int enc = value->getInt();
|
|
if (enc < 0) {
|
|
enc = 0;
|
|
}
|
|
if (enc >= NUM_TEXT_ENCODINGS) {
|
|
enc = NUM_TEXT_ENCODINGS - 1;
|
|
}
|
|
_textEncoding = (TTextEncoding)enc;
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// TextRTL
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "TextRTL") == 0) {
|
|
_textRTL = value->getBool();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SoundBufferSize
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SoundBufferSize") == 0) {
|
|
_soundBufferSizeSec = value->getInt();
|
|
_soundBufferSizeSec = MAX<int32>(3, _soundBufferSizeSec);
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SuspendedRendering
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SuspendedRendering") == 0) {
|
|
_suspendedRendering = value->getBool();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SuppressScriptErrors
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SuppressScriptErrors") == 0) {
|
|
_suppressScriptErrors = value->getBool();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// AutorunDisabled
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "AutorunDisabled") == 0) {
|
|
_autorunDisabled = value->getBool();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// AutoSaveOnExit
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "AutoSaveOnExit") == 0) {
|
|
_autoSaveOnExit = value->getBool();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// AutoSaveSlot
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "AutoSaveSlot") == 0) {
|
|
_autoSaveSlot = value->getInt();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CursorHidden
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "CursorHidden") == 0) {
|
|
_cursorHidden = value->getBool();
|
|
return STATUS_OK;
|
|
} else {
|
|
return BaseObject::scSetProperty(name, value);
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
const char *BaseGame::scToString() {
|
|
return "[game object]";
|
|
}
|
|
|
|
#define QUICK_MSG_DURATION 3000
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::displayQuickMsg() {
|
|
if (_quickMessages.getSize() == 0 || !_systemFont) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
// update
|
|
for (int32 i = 0; i < _quickMessages.getSize(); i++) {
|
|
if (_currentTime - _quickMessages[i]->_startTime>= QUICK_MSG_DURATION) {
|
|
delete _quickMessages[i];
|
|
_quickMessages.removeAt(i);
|
|
i--;
|
|
}
|
|
}
|
|
|
|
int posY = 20;
|
|
|
|
// display
|
|
for (int32 i = 0; i < _quickMessages.getSize(); i++) {
|
|
_systemFont->drawText((const byte *)_quickMessages[i]->getText(), 0, posY, _renderer->getWidth());
|
|
posY += _systemFont->getTextHeight((const byte *)_quickMessages[i]->getText(), _renderer->getWidth());
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
#define MAX_QUICK_MSG 5
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::quickMessage(const char *text) {
|
|
if (_quickMessages.getSize() >= MAX_QUICK_MSG) {
|
|
delete _quickMessages[0];
|
|
_quickMessages.removeAt(0);
|
|
}
|
|
_quickMessages.add(new BaseQuickMsg(_game, text));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::quickMessageForm(char *fmt, ...) {
|
|
char buff[256];
|
|
va_list va;
|
|
|
|
va_start(va, fmt);
|
|
Common::vsprintf_s(buff, fmt, va);
|
|
va_end(va);
|
|
|
|
quickMessage(buff);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::registerObject(BaseObject *object) {
|
|
_regObjects.add(object);
|
|
return STATUS_OK;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::unregisterObject(BaseObject *object) {
|
|
if (!object) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
// is it a window?
|
|
for (int32 i = 0; i < _windows.getSize(); i++) {
|
|
if ((BaseObject *)_windows[i] == object) {
|
|
_windows.removeAt(i);
|
|
|
|
// get new focused window
|
|
if (_focusedWindow == object) {
|
|
_focusedWindow = nullptr;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
// is it active object?
|
|
if (_activeObject == object) {
|
|
_activeObject = nullptr;
|
|
}
|
|
|
|
// is it main object?
|
|
if (_mainObject == object) {
|
|
_mainObject = nullptr;
|
|
}
|
|
|
|
// is it active accessibility object?
|
|
if (_accessMgr && _accessMgr->getActiveObject() == object) {
|
|
_accessMgr->setActiveObject(nullptr);
|
|
}
|
|
|
|
// destroy object
|
|
for (int32 i = 0; i < _regObjects.getSize(); i++) {
|
|
if (_regObjects[i] == object) {
|
|
_regObjects.removeAt(i);
|
|
if (!_loadInProgress) {
|
|
SystemClassRegistry::getInstance()->enumInstances(invalidateValues, "ScValue", (void *)object);
|
|
}
|
|
delete object;
|
|
return STATUS_OK;
|
|
}
|
|
}
|
|
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::invalidateValues(void *value, void *data) {
|
|
ScValue *val = (ScValue *)value;
|
|
if (val->isNative() && val->getNative() == data) {
|
|
if (!val->_persistent && ((BaseScriptable *)data)->_refCount == 1) {
|
|
((BaseScriptable *)data)->_refCount++;
|
|
}
|
|
val->setNative(nullptr);
|
|
val->setNULL();
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::validObject(BaseObject *object) {
|
|
if (!object) {
|
|
return false;
|
|
}
|
|
if (object == this) {
|
|
return true;
|
|
}
|
|
|
|
for (int32 i = 0; i < _regObjects.getSize(); i++) {
|
|
if (_regObjects[i] == object) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::externalCall(ScScript *script, ScStack *stack, ScStack *thisStack, char *name) {
|
|
ScValue *thisObj;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// LOG
|
|
//////////////////////////////////////////////////////////////////////////
|
|
if (strcmp(name, "LOG") == 0) {
|
|
stack->correctParams(1);
|
|
_game->LOG(0, "sc: %s", stack->pop()->getString());
|
|
stack->pushNULL();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// String
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "String") == 0) {
|
|
thisObj = thisStack->getTop();
|
|
|
|
thisObj->setNative(makeSXString(_game, stack));
|
|
stack->pushNULL();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// MemBuffer
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "MemBuffer") == 0) {
|
|
thisObj = thisStack->getTop();
|
|
|
|
thisObj->setNative(makeSXMemBuffer(_game, stack));
|
|
stack->pushNULL();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// File
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "File") == 0) {
|
|
thisObj = thisStack->getTop();
|
|
|
|
thisObj->setNative(makeSXFile(_game, stack));
|
|
stack->pushNULL();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Date
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Date") == 0) {
|
|
thisObj = thisStack->getTop();
|
|
|
|
thisObj->setNative(makeSXDate(_game, stack));
|
|
stack->pushNULL();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Array
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Array") == 0) {
|
|
thisObj = thisStack->getTop();
|
|
|
|
thisObj->setNative(makeSXArray(_game, stack));
|
|
stack->pushNULL();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Directory
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Directory") == 0) {
|
|
thisObj = thisStack->getTop();
|
|
|
|
thisObj->setNative(makeSXDirectory(_game));
|
|
stack->pushNULL();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Object
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Object") == 0) {
|
|
thisObj = thisStack->getTop();
|
|
|
|
thisObj->setNative(makeSXObject(_game, stack));
|
|
stack->pushNULL();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Sleep
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Sleep") == 0) {
|
|
stack->correctParams(1);
|
|
|
|
script->sleep((uint32)stack->pop()->getInt());
|
|
stack->pushNULL();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// WaitFor
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "WaitFor") == 0) {
|
|
stack->correctParams(1);
|
|
|
|
BaseScriptable *obj = stack->pop()->getNative();
|
|
if (validObject((BaseObject *)obj)) {
|
|
script->waitForExclusive((BaseObject *)obj);
|
|
}
|
|
stack->pushNULL();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Random
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Random") == 0) {
|
|
stack->correctParams(2);
|
|
|
|
int from = stack->pop()->getInt();
|
|
int to = stack->pop()->getInt();
|
|
|
|
stack->pushInt(BaseUtils::randomInt(from, to));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SetScriptTimeSlice
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "SetScriptTimeSlice") == 0) {
|
|
stack->correctParams(1);
|
|
|
|
script->_timeSlice = (uint32)stack->pop()->getInt();
|
|
stack->pushNULL();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// MakeRGBA / MakeRGB / RGB
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "MakeRGBA") == 0 || strcmp(name, "MakeRGB") == 0 || strcmp(name, "RGB") == 0) {
|
|
stack->correctParams(4);
|
|
int r = stack->pop()->getInt();
|
|
int g = stack->pop()->getInt();
|
|
int b = stack->pop()->getInt();
|
|
int a;
|
|
ScValue *val = stack->pop();
|
|
if (val->isNULL()) {
|
|
a = 255;
|
|
} else {
|
|
a = val->getInt();
|
|
}
|
|
|
|
stack->pushInt(BYTETORGBA(r, g, b, a));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// MakeHSL
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "MakeHSL") == 0) {
|
|
stack->correctParams(3);
|
|
int h = stack->pop()->getInt();
|
|
int s = stack->pop()->getInt();
|
|
int l = stack->pop()->getInt();
|
|
|
|
stack->pushInt(BaseUtils::HSLtoRGB(h, s, l));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetRValue
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetRValue") == 0) {
|
|
stack->correctParams(1);
|
|
|
|
uint32 rgba = (uint32)stack->pop()->getInt();
|
|
stack->pushInt(RGBCOLGetR(rgba));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetGValue
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetGValue") == 0) {
|
|
stack->correctParams(1);
|
|
|
|
uint32 rgba = (uint32)stack->pop()->getInt();
|
|
stack->pushInt(RGBCOLGetG(rgba));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetBValue
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetBValue") == 0) {
|
|
stack->correctParams(1);
|
|
|
|
uint32 rgba = (uint32)stack->pop()->getInt();
|
|
stack->pushInt(RGBCOLGetB(rgba));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetAValue
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetAValue") == 0) {
|
|
stack->correctParams(1);
|
|
|
|
uint32 rgba = (uint32)stack->pop()->getInt();
|
|
stack->pushInt(RGBCOLGetA(rgba));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetHValue
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetHValue") == 0) {
|
|
stack->correctParams(1);
|
|
uint32 rgb = (uint32)stack->pop()->getInt();
|
|
|
|
byte H, S, L;
|
|
BaseUtils::RGBtoHSL(rgb, &H, &S, &L);
|
|
stack->pushInt(H);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetSValue
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetSValue") == 0) {
|
|
stack->correctParams(1);
|
|
uint32 rgb = (uint32)stack->pop()->getInt();
|
|
|
|
byte H, S, L;
|
|
BaseUtils::RGBtoHSL(rgb, &H, &S, &L);
|
|
stack->pushInt(S);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetLValue
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "GetLValue") == 0) {
|
|
stack->correctParams(1);
|
|
uint32 rgb = (uint32)stack->pop()->getInt();
|
|
|
|
byte H, S, L;
|
|
BaseUtils::RGBtoHSL(rgb, &H, &S, &L);
|
|
stack->pushInt(L);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Debug
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Debug") == 0) {
|
|
stack->correctParams(0);
|
|
stack->pushNULL();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// ToString
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "ToString") == 0) {
|
|
stack->correctParams(1);
|
|
const char *str = stack->pop()->getString();
|
|
size_t strSize = strlen(str) + 1;
|
|
char *str2 = new char[strSize];
|
|
Common::strcpy_s(str2, strSize, str);
|
|
stack->pushString(str2);
|
|
delete[] str2;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// ToInt
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "ToInt") == 0) {
|
|
stack->correctParams(1);
|
|
int val = stack->pop()->getInt();
|
|
stack->pushInt(val);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// ToFloat
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "ToFloat") == 0) {
|
|
stack->correctParams(1);
|
|
double val = stack->pop()->getFloat();
|
|
stack->pushFloat(val);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// ToBool
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "ToBool") == 0) {
|
|
stack->correctParams(1);
|
|
bool val = stack->pop()->getBool();
|
|
stack->pushBool(val);
|
|
}
|
|
|
|
#ifdef ENABLE_FOXTAIL
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [FoxTail] IsNumber
|
|
// Used at kalimba.script to check if string token is a number
|
|
// If true is returned, then ToInt() is called for same parameter
|
|
// ToInt(string) implementation is using atoi(), so let's use it here too
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "IsNumber") == 0) {
|
|
stack->correctParams(1);
|
|
ScValue *val = stack->pop();
|
|
|
|
bool result = false;
|
|
if (val->isInt() || val->isFloat()) {
|
|
result = true;
|
|
} else if (val->isString()) {
|
|
const char *str = val->getString();
|
|
result = (atoi(str) != 0) || (strcmp(str, "0") == 0);
|
|
}
|
|
|
|
stack->pushBool(result);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [FoxTail] Split
|
|
// Returns array of words of a string, using another as a delimeter
|
|
// Used to split strings by 1-2 characters delimeter in various scripts
|
|
// All the delimeters ever used in FoxTail are:
|
|
// " ", "@", "#", "$", "&", ",", "\\", "@h", "@i", "@p", "@s"
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Split") == 0) {
|
|
stack->correctParams(2);
|
|
const char *str = stack->pop()->getString();
|
|
Common::String sep = stack->pop()->getString();
|
|
uint32 size = strlen(str) + 1;
|
|
|
|
// Let's make copies before modifying stack
|
|
char *copy = new char[size];
|
|
Common::strcpy_s(copy, size, str);
|
|
|
|
// There is no way to makeSXArray() with exactly 1 given element
|
|
// That's why we are creating empty Array and SXArray::push() later
|
|
stack->pushInt(0);
|
|
BaseScriptable *arr = makeSXArray(_game, stack);
|
|
|
|
// Iterating string copy, replacing delimeter with '\0' and pushing matches
|
|
// Only non-empty matches should be pushed
|
|
char *begin = copy;
|
|
for (char *it = copy; it < copy + size; it++) {
|
|
if (strncmp(it, sep.c_str(), sep.size()) == 0 || *it == '\0') {
|
|
*it = '\0';
|
|
if (it != begin) {
|
|
stack->pushString(begin);
|
|
((SXArray *)arr)->push(stack->pop());
|
|
}
|
|
begin = it + sep.size();
|
|
it = begin - 1;
|
|
}
|
|
}
|
|
|
|
stack->pushNative(arr, false);
|
|
|
|
delete[] copy;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// [FoxTail] Trim / lTrim / rTrim
|
|
// Removes whitespaces from a string from the left & right
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if (strcmp(name, "Trim") == 0 || strcmp(name, "lTrim") == 0 || strcmp(name, "rTrim") == 0) {
|
|
stack->correctParams(1);
|
|
const char *str = stack->pop()->getString();
|
|
size_t copySize = strlen(str) + 1;
|
|
char *copy = new char[copySize];
|
|
Common::strcpy_s(copy, copySize, str);
|
|
|
|
char *ptr = copy;
|
|
if (strcmp(name, "rTrim") != 0) {
|
|
ptr = Common::ltrim(ptr);
|
|
}
|
|
if (strcmp(name, "lTrim") != 0) {
|
|
ptr = Common::rtrim(ptr);
|
|
}
|
|
|
|
stack->pushString(ptr);
|
|
|
|
delete[] copy;
|
|
}
|
|
#endif
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Plugins: emulate object constructors from known "wme_*.dll" plugins
|
|
//////////////////////////////////////////////////////////////////////////
|
|
else if(!DID_FAIL(EmulatePluginCall(_game, stack, thisStack, name))) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// failure
|
|
else {
|
|
script->runtimeError("Call to undefined function '%s'. Ignored.", name);
|
|
stack->correctParams(0);
|
|
stack->pushNULL();
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::showCursor() {
|
|
if (_cursorHidden) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
if (!_interactive && _game->_state == GAME_RUNNING) {
|
|
if (_cursorNoninteractive) {
|
|
return drawCursor(_cursorNoninteractive);
|
|
}
|
|
} else {
|
|
if (_activeObject && !DID_FAIL(_activeObject->showCursor())) {
|
|
return STATUS_OK;
|
|
} else {
|
|
if (_activeObject && _activeCursor && _activeObject->getExtendedFlag("usable")) {
|
|
return drawCursor(_activeCursor);
|
|
} else if (_cursor) {
|
|
return drawCursor(_cursor);
|
|
}
|
|
}
|
|
}
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::saveGame(int32 slot, const char *desc, bool quickSave) {
|
|
Common::String filename;
|
|
getSaveSlotFilename(slot, filename);
|
|
|
|
LOG(0, "Saving game '%s'...", filename.c_str());
|
|
|
|
pluginEvents().applyEvent(WME_EVENT_GAME_BEFORE_SAVE, nullptr);
|
|
applyEvent("BeforeSave", true);
|
|
|
|
bool ret;
|
|
|
|
_indicatorDisplay = true;
|
|
_indicatorProgress = 0;
|
|
_hasDrawnSaveLoadImage = false;
|
|
|
|
BasePersistenceManager *pm = new BasePersistenceManager();
|
|
if (DID_SUCCEED(ret = pm->initSave(desc))) {
|
|
if (!quickSave) {
|
|
SAFE_DELETE(_saveLoadImage);
|
|
if (_saveImageName && _saveImageName[0] != '\0') {
|
|
_saveLoadImage = _game->_renderer->createSurface();
|
|
if (!_saveLoadImage || DID_FAIL(_saveLoadImage->create(_saveImageName, true, true, 0, 0, 0))) {
|
|
SAFE_DELETE(_saveLoadImage);
|
|
}
|
|
}
|
|
}
|
|
if (DID_SUCCEED(ret = SystemClassRegistry::getInstance()->saveTable(_game, pm, quickSave))) {
|
|
if (DID_SUCCEED(ret = SystemClassRegistry::getInstance()->saveInstances(_game, pm, quickSave))) {
|
|
pm->putDWORD(BaseEngine::instance().getRandomSource()->getSeed());
|
|
if (DID_SUCCEED(ret = pm->saveFile(filename))) {
|
|
ConfMan.setInt("most_recent_saveslot", slot);
|
|
ConfMan.flushToDisk();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
delete pm;
|
|
_indicatorDisplay = false;
|
|
|
|
// added render step after saving game
|
|
_renderer->endSaveLoad();
|
|
|
|
SAFE_DELETE(_saveLoadImage);
|
|
|
|
return ret;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::loadGame(uint32 slot) {
|
|
//_game->LOG(0, "Load start %d", BaseUtils::GetUsedMemMB());
|
|
|
|
_loading = false;
|
|
_scheduledLoadSlot = -1;
|
|
|
|
Common::String filename;
|
|
getSaveSlotFilename(slot, filename);
|
|
|
|
return loadGame(filename.c_str());
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::loadGame(const char *filename) {
|
|
LOG(0, "Loading game '%s'...", filename);
|
|
|
|
bool ret;
|
|
|
|
// added stopping video before load save
|
|
stopVideo();
|
|
|
|
SAFE_DELETE(_saveLoadImage);
|
|
if (_loadImageName && _loadImageName[0] != '\0') {
|
|
_saveLoadImage = _game->_renderer->createSurface();
|
|
|
|
if (!_saveLoadImage || DID_FAIL(_saveLoadImage->create(_loadImageName, true, true, 0, 0, 0))) {
|
|
SAFE_DELETE(_saveLoadImage);
|
|
}
|
|
}
|
|
|
|
_loadInProgress = true;
|
|
_indicatorDisplay = true;
|
|
_indicatorProgress = 0;
|
|
_hasDrawnSaveLoadImage = false;
|
|
|
|
pluginEvents().clearEvents();
|
|
|
|
BasePersistenceManager *pm = new BasePersistenceManager();
|
|
if (DID_SUCCEED(ret = pm->initLoad(filename))) {
|
|
//if (DID_SUCCEED(ret = cleanup())) {
|
|
if (DID_SUCCEED(ret = SystemClassRegistry::getInstance()->loadTable(_game, pm))) {
|
|
if (DID_SUCCEED(ret = SystemClassRegistry::getInstance()->loadInstances(_game, pm))) {
|
|
// Restore random-seed:
|
|
BaseEngine::instance().getRandomSource()->setSeed(pm->getDWORD());
|
|
|
|
// data initialization after load
|
|
initAfterLoad();
|
|
|
|
pluginEvents().applyEvent(WME_EVENT_GAME_AFTER_LOAD, nullptr);
|
|
applyEvent("AfterLoad", true);
|
|
|
|
displayContent(true, false);
|
|
//_renderer->flip();
|
|
|
|
accessUnpause();
|
|
}
|
|
}
|
|
}
|
|
|
|
_indicatorDisplay = false;
|
|
delete pm;
|
|
_loadInProgress = false;
|
|
|
|
// added render step after loadng game
|
|
_renderer->endSaveLoad();
|
|
|
|
SAFE_DELETE(_saveLoadImage);
|
|
|
|
//BaseEngine::LOG(0, "Load end %d", BaseUtils::GetUsedMemMB());
|
|
|
|
// AdGame:
|
|
if (DID_SUCCEED(ret)) {
|
|
SystemClassRegistry::getInstance()->enumInstances(afterLoadRegion, "AdRegion", nullptr);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::initAfterLoad() {
|
|
SystemClassRegistry::getInstance()->enumInstances(afterLoadRegion, "BaseRegion", nullptr);
|
|
SystemClassRegistry::getInstance()->enumInstances(afterLoadSubFrame, "BaseSubFrame", nullptr);
|
|
SystemClassRegistry::getInstance()->enumInstances(afterLoadSound, "BaseSound", nullptr);
|
|
SystemClassRegistry::getInstance()->enumInstances(afterLoadFont, "BaseFontTT", nullptr);
|
|
#ifdef ENABLE_WME3D
|
|
SystemClassRegistry::getInstance()->enumInstances(afterLoadXModel, "XModel", nullptr);
|
|
#endif
|
|
SystemClassRegistry::getInstance()->enumInstances(afterLoadScript, "ScScript", nullptr);
|
|
// AdGame:
|
|
SystemClassRegistry::getInstance()->enumInstances(afterLoadScene, "AdScene", nullptr);
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::afterLoadScene(void *scene, void *data) {
|
|
((AdScene *)scene)->afterLoad();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::afterLoadRegion(void *region, void *data) {
|
|
((BaseRegion *)region)->createRegion();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::afterLoadSubFrame(void *subframe, void *data) {
|
|
((BaseSubFrame *)subframe)->setSurfaceSimple();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::afterLoadSound(void *sound, void *data) {
|
|
((BaseSound *)sound)->setSoundSimple();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::afterLoadFont(void *font, void *data) {
|
|
((BaseFont *)font)->afterLoad();
|
|
}
|
|
|
|
#ifdef ENABLE_WME3D
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::afterLoadXModel(void *model, void *data) {
|
|
((XModel *)model)->initializeSimple();
|
|
}
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::afterLoadScript(void *script, void *data) {
|
|
((ScScript *)script)->afterLoad();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::displayWindows(bool inGame) {
|
|
bool res;
|
|
|
|
// did we lose focus? focus topmost window
|
|
if (_focusedWindow == nullptr || !_focusedWindow->_visible || _focusedWindow->_disable) {
|
|
_focusedWindow = nullptr;
|
|
for (int32 i = _windows.getSize() - 1; i >= 0; i--) {
|
|
if (_windows[i]->_visible && !_windows[i]->_disable) {
|
|
_focusedWindow = _windows[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// display all windows
|
|
for (int32 i = 0; i < _windows.getSize(); i++) {
|
|
if (_windows[i]->_visible && _windows[i]->_inGame == inGame) {
|
|
|
|
res = _windows[i]->display();
|
|
if (DID_FAIL(res)) {
|
|
return res;
|
|
}
|
|
}
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::playMusic(int channel, const char *filename, bool looping, uint32 loopStart, uint32 privVolume) {
|
|
if (channel >= NUM_MUSIC_CHANNELS) {
|
|
_game->LOG(0, "**Error** Attempting to use music channel %d (max num channels: %d)", channel, NUM_MUSIC_CHANNELS);
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
SAFE_DELETE(_music[channel]);
|
|
|
|
_music[channel] = new BaseSound(_game);
|
|
if (_music[channel] && DID_SUCCEED(_music[channel]->setSound(filename, TSoundType::SOUND_MUSIC, true, privVolume))) {
|
|
if (_musicStartTime[channel]) {
|
|
_music[channel]->setPositionTime(_musicStartTime[channel]);
|
|
_musicStartTime[channel] = 0;
|
|
}
|
|
if (loopStart) {
|
|
_music[channel]->setLoopStart(loopStart);
|
|
}
|
|
return _music[channel]->play(looping);
|
|
} else {
|
|
SAFE_DELETE(_music[channel]);
|
|
return STATUS_FAILED;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::stopMusic(int channel) {
|
|
if (channel >= NUM_MUSIC_CHANNELS) {
|
|
_game->LOG(0, "**Error** Attempting to use music channel %d (max num channels: %d)", channel, NUM_MUSIC_CHANNELS);
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
if (_music[channel]) {
|
|
_music[channel]->stop();
|
|
SAFE_DELETE(_music[channel]);
|
|
return STATUS_OK;
|
|
} else {
|
|
return STATUS_FAILED;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::pauseMusic(int channel) {
|
|
if (channel >= NUM_MUSIC_CHANNELS) {
|
|
_game->LOG(0, "**Error** Attempting to use music channel %d (max num channels: %d)", channel, NUM_MUSIC_CHANNELS);
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
if (_music[channel]) {
|
|
return _music[channel]->pause();
|
|
} else {
|
|
return STATUS_FAILED;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::resumeMusic(int channel) {
|
|
if (channel >= NUM_MUSIC_CHANNELS) {
|
|
_game->LOG(0, "**Error** Attempting to use music channel %d (max num channels: %d)", channel, NUM_MUSIC_CHANNELS);
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
if (_music[channel]) {
|
|
return _music[channel]->resume();
|
|
} else {
|
|
return STATUS_FAILED;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::setMusicStartTime(int channel, uint32 time) {
|
|
if (channel >= NUM_MUSIC_CHANNELS) {
|
|
_game->LOG(0, "**Error** Attempting to use music channel %d (max num channels: %d)", channel, NUM_MUSIC_CHANNELS);
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
_musicStartTime[channel] = time;
|
|
if (_music[channel] && _music[channel]->isPlaying()) {
|
|
return _music[channel]->setPositionTime(time);
|
|
} else {
|
|
return STATUS_OK;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::loadSettings(const char *filename) {
|
|
TOKEN_TABLE_START(commands)
|
|
TOKEN_TABLE(SETTINGS)
|
|
TOKEN_TABLE(GAME)
|
|
TOKEN_TABLE(STRING_TABLE)
|
|
TOKEN_TABLE(RESOLUTION)
|
|
TOKEN_TABLE(REQUIRE_3D_ACCELERATION)
|
|
TOKEN_TABLE(REQUIRE_SOUND)
|
|
TOKEN_TABLE(HWTL_MODE)
|
|
TOKEN_TABLE(ALLOW_WINDOWED_MODE)
|
|
TOKEN_TABLE(ALLOW_ACCESSIBILITY_TAB)
|
|
TOKEN_TABLE(ALLOW_ABOUT_TAB)
|
|
TOKEN_TABLE(ALLOW_ADVANCED)
|
|
TOKEN_TABLE(ALLOW_DESKTOP_RES)
|
|
TOKEN_TABLE(REGISTRY_PATH)
|
|
TOKEN_TABLE(RICH_SAVED_GAMES)
|
|
TOKEN_TABLE(SAVED_GAME_EXT)
|
|
TOKEN_TABLE(GUID)
|
|
TOKEN_TABLE_END
|
|
|
|
char *origBuffer = (char *)_game->_fileManager->readWholeFile(filename);
|
|
if (origBuffer == nullptr) {
|
|
_game->LOG(0, "BaseGame::loadSettings failed for file '%s'", filename);
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
bool ret = STATUS_OK;
|
|
|
|
char *buffer = origBuffer;
|
|
char *params;
|
|
int cmd;
|
|
BaseParser parser(_game);
|
|
|
|
if (parser.getCommand(&buffer, commands, ¶ms) != TOKEN_SETTINGS) {
|
|
_game->LOG(0, "'SETTINGS' keyword expected in game settings file.");
|
|
return STATUS_FAILED;
|
|
}
|
|
buffer = params;
|
|
while ((cmd = parser.getCommand(&buffer, commands, ¶ms)) > 0) {
|
|
switch (cmd) {
|
|
case TOKEN_GAME: {
|
|
SAFE_DELETE_ARRAY(_settingsGameFile);
|
|
size_t gameFileSize = strlen(params) + 1;
|
|
_settingsGameFile = new char[gameFileSize];
|
|
Common::strcpy_s(_settingsGameFile, gameFileSize, params);
|
|
break;
|
|
}
|
|
|
|
case TOKEN_STRING_TABLE:
|
|
if (DID_FAIL(_stringTable->loadFile(params))) {
|
|
cmd = PARSERR_GENERIC;
|
|
}
|
|
break;
|
|
|
|
case TOKEN_RESOLUTION:
|
|
parser.scanStr(params, "%d,%d", &_settingsResWidth, &_settingsResHeight);
|
|
break;
|
|
|
|
case TOKEN_REQUIRE_3D_ACCELERATION:
|
|
parser.scanStr(params, "%b", &_settingsRequireAcceleration);
|
|
break;
|
|
|
|
case TOKEN_REQUIRE_SOUND:
|
|
parser.scanStr(params, "%b", &_settingsRequireSound);
|
|
break;
|
|
|
|
case TOKEN_HWTL_MODE:
|
|
parser.scanStr(params, "%d", &_settingsTLMode);
|
|
break;
|
|
|
|
case TOKEN_ALLOW_WINDOWED_MODE:
|
|
parser.scanStr(params, "%b", &_settingsAllowWindowed);
|
|
break;
|
|
|
|
case TOKEN_ALLOW_DESKTOP_RES:
|
|
parser.scanStr(params, "%b", &_settingsAllowDesktopRes);
|
|
break;
|
|
|
|
case TOKEN_ALLOW_ADVANCED:
|
|
parser.scanStr(params, "%b", &_settingsAllowAdvanced);
|
|
break;
|
|
|
|
case TOKEN_ALLOW_ACCESSIBILITY_TAB:
|
|
parser.scanStr(params, "%b", &_settingsAllowAccessTab);
|
|
break;
|
|
|
|
case TOKEN_ALLOW_ABOUT_TAB:
|
|
parser.scanStr(params, "%b", &_settingsAllowAboutTab);
|
|
break;
|
|
|
|
case TOKEN_REGISTRY_PATH:
|
|
//BaseEngine::instance().getRegistry()->setBasePath(params);
|
|
break;
|
|
|
|
case TOKEN_RICH_SAVED_GAMES:
|
|
parser.scanStr(params, "%b", &_richSavedGames);
|
|
break;
|
|
|
|
case TOKEN_SAVED_GAME_EXT:
|
|
BaseUtils::setString(&_savedGameExt, (char *)params);
|
|
break;
|
|
|
|
case TOKEN_GUID:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (cmd == PARSERR_TOKENNOTFOUND) {
|
|
_game->LOG(0, "Syntax error in game settings '%s'", filename);
|
|
ret = STATUS_FAILED;
|
|
}
|
|
if (cmd == PARSERR_GENERIC) {
|
|
_game->LOG(0, "Error loading game settings '%s'", filename);
|
|
ret = STATUS_FAILED;
|
|
}
|
|
|
|
_settingsAllowWindowed = true;
|
|
_compressedSavegames = true;
|
|
|
|
delete[] origBuffer;
|
|
|
|
return ret;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::persist(BasePersistenceManager *persistMgr) {
|
|
if (!persistMgr->getIsSaving()) {
|
|
cleanup();
|
|
}
|
|
|
|
BaseObject::persist(persistMgr);
|
|
|
|
persistMgr->transferPtr(TMEMBER_PTR(_activeObject));
|
|
persistMgr->transferPtr(TMEMBER_PTR(_capturedObject));
|
|
persistMgr->transferPtr(TMEMBER_PTR(_cursorNoninteractive));
|
|
persistMgr->transferBool(TMEMBER(_editorMode));
|
|
persistMgr->transferPtr(TMEMBER_PTR(_fader));
|
|
persistMgr->transferSint32(TMEMBER(_freezeLevel));
|
|
persistMgr->transferPtr(TMEMBER_PTR(_focusedWindow));
|
|
persistMgr->transferPtr(TMEMBER_PTR(_fontStorage));
|
|
persistMgr->transferBool(TMEMBER(_interactive));
|
|
persistMgr->transferPtr(TMEMBER_PTR(_keyboardState));
|
|
persistMgr->transferUint32(TMEMBER(_lastTime));
|
|
persistMgr->transferPtr(TMEMBER_PTR(_mainObject));
|
|
for (int i = 0; i < NUM_MUSIC_CHANNELS; i++) {
|
|
persistMgr->transferPtr(TMEMBER_PTR(_music[i]));
|
|
persistMgr->transferUint32(TMEMBER(_musicStartTime[i]));
|
|
}
|
|
persistMgr->transferBool(TMEMBER(_musicCrossfadeRunning));
|
|
persistMgr->transferUint32(TMEMBER(_musicCrossfadeStartTime));
|
|
persistMgr->transferUint32(TMEMBER(_musicCrossfadeLength));
|
|
persistMgr->transferSint32(TMEMBER(_musicCrossfadeChannel1));
|
|
persistMgr->transferSint32(TMEMBER(_musicCrossfadeChannel2));
|
|
persistMgr->transferBool(TMEMBER(_musicCrossfadeSwap));
|
|
// let's keep savegame compatibility for the price of small possibility of wrong volume at game load
|
|
if (!persistMgr->getIsSaving()) {
|
|
_musicCrossfadeVolume1 = 0;
|
|
_musicCrossfadeVolume2 = 100;
|
|
}
|
|
|
|
persistMgr->transferSint32(TMEMBER(_offsetX));
|
|
persistMgr->transferSint32(TMEMBER(_offsetY));
|
|
persistMgr->transferFloat(TMEMBER(_offsetPercentX));
|
|
persistMgr->transferFloat(TMEMBER(_offsetPercentY));
|
|
|
|
persistMgr->transferBool(TMEMBER(_origInteractive));
|
|
persistMgr->transferSint32(TMEMBER_INT(_origState));
|
|
persistMgr->transferBool(TMEMBER(_personalizedSave));
|
|
persistMgr->transferBool(TMEMBER(_quitting));
|
|
|
|
_regObjects.persist(persistMgr);
|
|
|
|
persistMgr->transferPtr(TMEMBER_PTR(_scEngine));
|
|
//persistMgr->transfer(TMEMBER(_soundMgr));
|
|
persistMgr->transferSint32(TMEMBER_INT(_state));
|
|
//persistMgr->transfer(TMEMBER(_surfaceStorage));
|
|
persistMgr->transferBool(TMEMBER(_subtitles));
|
|
persistMgr->transferSint32(TMEMBER(_subtitlesSpeed));
|
|
persistMgr->transferPtr(TMEMBER_PTR(_systemFont));
|
|
persistMgr->transferPtr(TMEMBER_PTR(_videoFont));
|
|
persistMgr->transferBool(TMEMBER(_videoSubtitles));
|
|
|
|
persistMgr->transferUint32(TMEMBER(_timer));
|
|
persistMgr->transferUint32(TMEMBER(_timerDelta));
|
|
persistMgr->transferUint32(TMEMBER(_timerLast));
|
|
|
|
persistMgr->transferUint32(TMEMBER(_liveTimer));
|
|
persistMgr->transferUint32(TMEMBER(_liveTimerDelta));
|
|
persistMgr->transferUint32(TMEMBER(_liveTimerLast));
|
|
|
|
persistMgr->transferCharPtr(TMEMBER(_loadImageName));
|
|
persistMgr->transferCharPtr(TMEMBER(_saveImageName));
|
|
persistMgr->transferSint32(TMEMBER(_saveImageX));
|
|
persistMgr->transferSint32(TMEMBER(_saveImageY));
|
|
persistMgr->transferSint32(TMEMBER(_loadImageX));
|
|
persistMgr->transferSint32(TMEMBER(_loadImageY));
|
|
|
|
#ifdef ENABLE_WME3D
|
|
if (BaseEngine::instance().getFlags() & GF_3D) {
|
|
persistMgr->transferSint32(TMEMBER_INT(_maxShadowType));
|
|
persistMgr->transferSint32(TMEMBER(_editorResolutionWidth));
|
|
persistMgr->transferSint32(TMEMBER(_editorResolutionHeight));
|
|
} else {
|
|
_editorResolutionWidth = _editorResolutionHeight = 0;
|
|
}
|
|
#else
|
|
_editorResolutionWidth = _editorResolutionHeight = 0;
|
|
#endif
|
|
|
|
persistMgr->transferSint32(TMEMBER_INT(_textEncoding));
|
|
persistMgr->transferBool(TMEMBER(_textRTL));
|
|
|
|
persistMgr->transferSint32(TMEMBER(_soundBufferSizeSec));
|
|
persistMgr->transferBool(TMEMBER(_suspendedRendering));
|
|
|
|
persistMgr->transferRect32(TMEMBER(_mouseLockRect));
|
|
|
|
_windows.persist(persistMgr);
|
|
|
|
persistMgr->transferBool(TMEMBER(_suppressScriptErrors));
|
|
persistMgr->transferBool(TMEMBER(_autorunDisabled));
|
|
|
|
persistMgr->transferBool(TMEMBER(_autoSaveOnExit));
|
|
persistMgr->transferUint32(TMEMBER(_autoSaveSlot));
|
|
persistMgr->transferBool(TMEMBER(_cursorHidden));
|
|
|
|
if (persistMgr->checkVersion(1, 3, 1)) {
|
|
_stringTable->persist(persistMgr);
|
|
}
|
|
|
|
if (persistMgr->checkVersion(1, 10, 1)) {
|
|
persistMgr->transferPtr(TMEMBER(_accessShieldWin));
|
|
} else {
|
|
if (!persistMgr->getIsSaving()) {
|
|
_accessShieldWin = nullptr;
|
|
}
|
|
}
|
|
|
|
// initialise to defaults
|
|
if (!persistMgr->getIsSaving()) {
|
|
_quitting = false;
|
|
_accessTTSEnabled = false;
|
|
_accessTTSTalk = true;
|
|
_accessTTSCaptions = true;
|
|
_accessTTSKeypress = true;
|
|
_accessKeyboardEnabled = false;
|
|
_accessKeyboardCursorSkip = true;
|
|
_accessKeyboardPause = false;
|
|
_accessGlobalPaused = false;
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::focusWindow(UIWindow *window) {
|
|
UIWindow *prev = _focusedWindow;
|
|
|
|
for (int32 i = 0; i < _windows.getSize(); i++) {
|
|
if (_windows[i] == window) {
|
|
if (i < _windows.getSize() - 1) {
|
|
_windows.removeAt(i);
|
|
_windows.add(window);
|
|
|
|
_game->_focusedWindow = window;
|
|
}
|
|
|
|
if (window->_mode == WINDOW_NORMAL && prev != window && _game->validObject(prev) && (prev->_mode == WINDOW_EXCLUSIVE || prev->_mode == WINDOW_SYSTEM_EXCLUSIVE)) {
|
|
return focusWindow(prev);
|
|
} else {
|
|
return STATUS_OK;
|
|
}
|
|
}
|
|
}
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::freeze(bool includingMusic) {
|
|
if (_freezeLevel == 0) {
|
|
_scEngine->pauseAll();
|
|
_soundMgr->pauseAll(includingMusic);
|
|
_origState = _state;
|
|
_origInteractive = _interactive;
|
|
_interactive = true;
|
|
}
|
|
_state = GAME_FROZEN;
|
|
_freezeLevel++;
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::unfreeze() {
|
|
if (_freezeLevel == 0) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
_freezeLevel--;
|
|
if (_freezeLevel == 0) {
|
|
_state = _origState;
|
|
_interactive = _origInteractive;
|
|
_scEngine->resumeAll();
|
|
_soundMgr->resumeAll();
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::handleKeypress(Common::Event *event, bool printable) {
|
|
if (isVideoPlaying()) {
|
|
if (event->kbd.keycode == Common::KEYCODE_ESCAPE) {
|
|
stopVideo();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (event->type == Common::EVENT_QUIT) {
|
|
onWindowClose();
|
|
return true;
|
|
}
|
|
|
|
if (handleAccessKey(event, printable)) {
|
|
return true;
|
|
}
|
|
|
|
_keyboardState->handleKeyPress(event);
|
|
_keyboardState->readKey(event);
|
|
|
|
if (_focusedWindow) {
|
|
if (!_game->_focusedWindow->handleKeypress(event, _keyboardState->isCurrentPrintable())) {
|
|
/*if (event->type != SDL_TEXTINPUT) {*/
|
|
if (_game->_focusedWindow->canHandleEvent("Keypress")) {
|
|
_game->_focusedWindow->applyEvent("Keypress");
|
|
} else {
|
|
applyEvent("Keypress");
|
|
}
|
|
/*}*/
|
|
}
|
|
return true;
|
|
} else { /*if (event->type != SDL_TEXTINPUT)*/
|
|
applyEvent("Keypress");
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void BaseGame::handleKeyRelease(Common::Event *event) {
|
|
_keyboardState->handleKeyRelease(event);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::handleAccessKey(Common::Event *event, bool printable) {
|
|
if (event->kbd.flags & Common::KBD_CTRL) {
|
|
_accessMgr->_ctrlPressed = event->type == Common::EVENT_KEYDOWN;
|
|
}
|
|
|
|
if (_accessKeyboardEnabled) {
|
|
if (event->kbd.keycode == Common::KEYCODE_TAB &&
|
|
(event->kbd.flags & Common::KBD_CTRL)) {
|
|
//BaseObject *obj = nullptr;
|
|
if (event->kbd.flags & Common::KBD_SHIFT) {
|
|
/*obj = */_accessMgr->getPrevObject();
|
|
} else {
|
|
/*obj = */_accessMgr->getNextObject();
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
if (printable && _accessKeyboardPause) {
|
|
if (event->kbd.keycode == Common::KEYCODE_SPACE &&
|
|
(event->kbd.flags & Common::KBD_CTRL)) {
|
|
_accessGlobalPaused = !_accessGlobalPaused;
|
|
if (_accessGlobalPaused) {
|
|
accessPause();
|
|
} else {
|
|
accessUnpause();
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::accessPause() {
|
|
_accessGlobalPaused = true;
|
|
|
|
if (_accessShieldWin)
|
|
unregisterObject(_accessShieldWin);
|
|
|
|
_accessShieldWin = new UIWindow(this);
|
|
_windows.add(_accessShieldWin);
|
|
registerObject(_accessShieldWin);
|
|
|
|
_accessShieldWin->_posX = _accessShieldWin->_posY = 0;
|
|
_accessShieldWin->_width = _renderer->_width;
|
|
_accessShieldWin->_height = _renderer->_height;
|
|
|
|
UIText *sta = new UIText(_game);
|
|
sta->_parent = _accessShieldWin;
|
|
_accessShieldWin->_widgets.add(sta);
|
|
sta->setText(_stringTable->expandStatic("/SYSENG0040/Game paused. Press Ctrl+Space to resume."));
|
|
sta->_sharedFonts = true;
|
|
sta->_font = _systemFont;
|
|
sta->sizeToFit();
|
|
sta->_posY = _accessShieldWin->_height - sta->_height;
|
|
sta->_posX = (_accessShieldWin->_width - sta->_width) / 2;
|
|
|
|
_accessShieldWin->_visible = true;
|
|
_accessShieldWin->goSystemExclusive();
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::accessUnpause() {
|
|
_accessGlobalPaused = false;
|
|
if (_accessShieldWin) {
|
|
_accessShieldWin->close();
|
|
unregisterObject(_accessShieldWin);
|
|
_accessShieldWin = nullptr;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::handleMouseWheel(int32 delta) {
|
|
bool handled = false;
|
|
if (_focusedWindow) {
|
|
handled = _game->_focusedWindow->handleMouseWheel(delta);
|
|
|
|
if (!handled) {
|
|
if (delta < 0 && _game->_focusedWindow->canHandleEvent("MouseWheelDown")) {
|
|
_game->_focusedWindow->applyEvent("MouseWheelDown");
|
|
handled = true;
|
|
} else if (_game->_focusedWindow->canHandleEvent("MouseWheelUp")) {
|
|
_game->_focusedWindow->applyEvent("MouseWheelUp");
|
|
handled = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!handled) {
|
|
if (delta < 0) {
|
|
applyEvent("MouseWheelDown");
|
|
} else {
|
|
applyEvent("MouseWheelUp");
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::getVersion(byte *verMajor, byte *verMinor, byte *extMajor, byte *extMinor) {
|
|
if (verMajor) {
|
|
*verMajor = DCGF_VER_MAJOR;
|
|
}
|
|
if (verMinor) {
|
|
*verMinor = DCGF_VER_MINOR;
|
|
}
|
|
|
|
if (extMajor) {
|
|
*extMajor = 0;
|
|
}
|
|
if (extMinor) {
|
|
*extMinor = 0;
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::setWindowTitle() {
|
|
if (_renderer) {
|
|
char title[512];
|
|
Common::strlcpy(title, _caption[0], 512);
|
|
if (title[0] != '\0') {
|
|
Common::strlcat(title, " - ", 512);
|
|
}
|
|
Common::strlcat(title, "Wintermute Engine", 512);
|
|
|
|
// ignoring setting window title
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::getSaveSlotFilename(int slot, Common::String &filename) {
|
|
BasePersistenceManager *pm = new BasePersistenceManager();
|
|
if (pm) {
|
|
filename = pm->getFilenameForSlot(slot);
|
|
delete pm;
|
|
debugC(kWintermuteDebugSaveGame, "getSaveSlotFileName(%d) = %s", slot, filename.c_str());
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::getSaveDir(char *buffer) {
|
|
// this should not be used
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::getSaveSlotDescription(int slot, Common::String &description) {
|
|
Common::String filename;
|
|
getSaveSlotFilename(slot, filename);
|
|
BasePersistenceManager *pm = new BasePersistenceManager();
|
|
if (!pm) {
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
if (DID_FAIL(pm->initLoad(filename))) {
|
|
delete pm;
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
description = pm->_savedDescription;
|
|
delete pm;
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::isSaveSlotUsed(int slot) {
|
|
Common::String filename;
|
|
getSaveSlotFilename(slot, filename);
|
|
BasePersistenceManager *pm = new BasePersistenceManager();
|
|
bool ret = pm->getSaveExists(slot);
|
|
delete pm;
|
|
|
|
return ret;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::emptySaveSlot(int slot) {
|
|
Common::String filename;
|
|
getSaveSlotFilename(slot, filename);
|
|
BasePersistenceManager *pm = new BasePersistenceManager();
|
|
|
|
((WintermuteEngine *)g_engine)->getSaveFileMan()->removeSavefile(pm->getFilenameForSlot(slot));
|
|
delete pm;
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::setActiveObject(BaseObject *obj) {
|
|
// not-active when game is frozen
|
|
if (obj && !_game->_interactive && !obj->_nonIntMouseEvents) {
|
|
obj = nullptr;
|
|
}
|
|
|
|
if (obj == _activeObject) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
if (_activeObject) {
|
|
_activeObject->applyEvent("MouseLeave");
|
|
}
|
|
// if (validObject(_activeObject)) _activeObject->applyEvent("MouseLeave");
|
|
_activeObject = obj;
|
|
if (_activeObject) {
|
|
_accessMgr->speak(_activeObject->getAccessCaption(), TTS_CAPTION);
|
|
_activeObject->applyEvent("MouseEntry");
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::pushViewport(BaseViewport *viewport) {
|
|
_viewportSP++;
|
|
if (_viewportSP >= _viewportStack.getSize()) {
|
|
_viewportStack.add(viewport);
|
|
} else {
|
|
_viewportStack[_viewportSP] = viewport;
|
|
}
|
|
|
|
_renderer->setViewport(viewport->getRect());
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::popViewport() {
|
|
_viewportSP--;
|
|
if (_viewportSP < -1) {
|
|
_game->LOG(0, "Fatal: Viewport stack underflow!");
|
|
}
|
|
|
|
if (_viewportSP >= 0 && _viewportSP < _viewportStack.getSize())
|
|
_renderer->setViewport(_viewportStack[_viewportSP]->getRect());
|
|
else
|
|
_renderer->setViewport(_renderer->_drawOffsetX,
|
|
_renderer->_drawOffsetY,
|
|
_renderer->getWidth() + _renderer->_drawOffsetX,
|
|
_renderer->getHeight() + _renderer->_drawOffsetY);
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::getCurrentViewportRect(Common::Rect32 *rect, bool *custom) {
|
|
if (rect == nullptr) {
|
|
return STATUS_FAILED;
|
|
} else {
|
|
if (_viewportSP >= 0) {
|
|
BasePlatform::copyRect(rect, _viewportStack[_viewportSP]->getRect());
|
|
if (custom) {
|
|
*custom = true;
|
|
}
|
|
} else {
|
|
// SetRect(Rect, 0, 0, m_Renderer->m_Width, m_Renderer->m_Height);
|
|
BasePlatform::setRect(rect, _renderer->_drawOffsetX,
|
|
_renderer->_drawOffsetY,
|
|
_renderer->getWidth() + _renderer->_drawOffsetX,
|
|
_renderer->getHeight() + _renderer->_drawOffsetY);
|
|
if (custom) {
|
|
*custom = false;
|
|
}
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::getCurrentViewportOffset(int *offsetX, int *offsetY) {
|
|
if (_viewportSP >= 0) {
|
|
if (offsetX)
|
|
*offsetX = _viewportStack[_viewportSP]->_offsetX;
|
|
if (offsetY)
|
|
*offsetY = _viewportStack[_viewportSP]->_offsetY;
|
|
} else {
|
|
if (offsetX) {
|
|
*offsetX = 0;
|
|
}
|
|
if (offsetY) {
|
|
*offsetY = 0;
|
|
}
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::windowLoadHook(UIWindow *win, char **buf, char **params) {
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::windowScriptMethodHook(UIWindow *win, ScScript *script, ScStack *stack, const char *name) {
|
|
return STATUS_FAILED;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::setInteractive(bool state) {
|
|
_interactive = state;
|
|
if (_transMgr) {
|
|
_transMgr->_origInteractive = state;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::resetMousePos() {
|
|
Common::Point p;
|
|
p.x = _mousePos.x + _renderer->_drawOffsetX;
|
|
p.y = _mousePos.y + _renderer->_drawOffsetY;
|
|
|
|
//CBPlatform::ClientToScreen(Game->m_Renderer->m_Window, &p);
|
|
BasePlatform::setCursorPos(p.x, p.y);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::displayContent(bool doUpdate, bool displayAll) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::displayContentSimple() {
|
|
// clear screen
|
|
_renderer->clear();
|
|
if (_indicatorDisplay) {
|
|
#ifdef ENABLE_FOXTAIL
|
|
if (BaseEngine::instance().isFoxTail())
|
|
displayIndicatorFoxTail();
|
|
else
|
|
#endif
|
|
displayIndicator();
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::displayIndicator() {
|
|
if (_saveLoadImage && !_hasDrawnSaveLoadImage) {
|
|
Common::Rect32 rc;
|
|
BasePlatform::setRect(&rc, 0, 0, _saveLoadImage->getWidth(), _saveLoadImage->getHeight());
|
|
if (_loadInProgress) {
|
|
_saveLoadImage->displayTrans(_loadImageX, _loadImageY, rc);
|
|
} else {
|
|
_saveLoadImage->displayTrans(_saveImageX, _saveImageY, rc);
|
|
}
|
|
_renderer->flip();
|
|
_hasDrawnSaveLoadImage = true;
|
|
}
|
|
|
|
// Original whole condition seems has typo with '&&' instead '||' for first part.
|
|
// Added _indicatorProgress to avoid draw on 0 progress
|
|
if (!_indicatorDisplay || !_indicatorProgress || _indicatorWidth <= 0 || _indicatorHeight <= 0)
|
|
return STATUS_OK;
|
|
int curWidth = (int)(_indicatorWidth * (float)((float)_indicatorProgress / 100.0f));
|
|
_renderer->fillRect(_indicatorX, _indicatorY, curWidth, _indicatorHeight, _indicatorColor);
|
|
_renderer->indicatorFlip(_indicatorX, _indicatorY, curWidth, _indicatorHeight);
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::updateMusicCrossfade() {
|
|
if (!_musicCrossfadeRunning) {
|
|
return STATUS_OK;
|
|
}
|
|
if (_state == GAME_FROZEN) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
if (_musicCrossfadeChannel1 < 0 || _musicCrossfadeChannel1 >= NUM_MUSIC_CHANNELS || !_music[_musicCrossfadeChannel1]) {
|
|
_musicCrossfadeRunning = false;
|
|
return STATUS_OK;
|
|
}
|
|
if (_musicCrossfadeChannel2 < 0 || _musicCrossfadeChannel2 >= NUM_MUSIC_CHANNELS || !_music[_musicCrossfadeChannel2]) {
|
|
_musicCrossfadeRunning = false;
|
|
return STATUS_OK;
|
|
}
|
|
|
|
if (!_music[_musicCrossfadeChannel1]->isPlaying()) {
|
|
_music[_musicCrossfadeChannel1]->play();
|
|
}
|
|
if (!_music[_musicCrossfadeChannel2]->isPlaying()) {
|
|
_music[_musicCrossfadeChannel2]->play();
|
|
}
|
|
|
|
uint32 currentTime = _game->_liveTimer - _musicCrossfadeStartTime;
|
|
|
|
if (currentTime >= _musicCrossfadeLength) {
|
|
_musicCrossfadeRunning = false;
|
|
|
|
if (_musicCrossfadeVolume2 == 0) {
|
|
_music[_musicCrossfadeChannel2]->stop();
|
|
_music[_musicCrossfadeChannel2]->setVolume(100);
|
|
} else {
|
|
_music[_musicCrossfadeChannel2]->setVolume(_musicCrossfadeVolume2);
|
|
}
|
|
|
|
if (_musicCrossfadeChannel1 != _musicCrossfadeChannel2) {
|
|
if (_musicCrossfadeVolume1 == 0) {
|
|
_music[_musicCrossfadeChannel1]->stop();
|
|
_music[_musicCrossfadeChannel1]->setVolume(100);
|
|
} else {
|
|
_music[_musicCrossfadeChannel1]->setVolume(_musicCrossfadeVolume1);
|
|
}
|
|
}
|
|
|
|
if (_musicCrossfadeSwap) {
|
|
// Swap channels
|
|
BaseSound *dummy = _music[_musicCrossfadeChannel1];
|
|
int dummyInt = _musicStartTime[_musicCrossfadeChannel1];
|
|
|
|
_music[_musicCrossfadeChannel1] = _music[_musicCrossfadeChannel2];
|
|
_musicStartTime[_musicCrossfadeChannel1] = _musicStartTime[_musicCrossfadeChannel2];
|
|
|
|
_music[_musicCrossfadeChannel2] = dummy;
|
|
_musicStartTime[_musicCrossfadeChannel2] = dummyInt;
|
|
}
|
|
} else {
|
|
float progress = (float)currentTime / (float)_musicCrossfadeLength;
|
|
int volumeDelta = (int)((_musicCrossfadeVolume1 - _musicCrossfadeVolume2)*progress);
|
|
_music[_musicCrossfadeChannel2]->setVolume(_musicCrossfadeVolume1 - volumeDelta);
|
|
BaseEngine::LOG(0, "Setting music channel %d volume to %d", _musicCrossfadeChannel2, _musicCrossfadeVolume1 - volumeDelta);
|
|
|
|
if (_musicCrossfadeChannel1 != _musicCrossfadeChannel2) {
|
|
_music[_musicCrossfadeChannel1]->setVolume(_musicCrossfadeVolume2 + volumeDelta);
|
|
BaseEngine::LOG(0, "Setting music channel %d volume to %d", _musicCrossfadeChannel1, _musicCrossfadeVolume2 + volumeDelta);
|
|
}
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::resetContent() {
|
|
_scEngine->clearGlobals();
|
|
//_timer = 0;
|
|
//_liveTimer = 0;
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::DEBUG_DumpClassRegistry() {
|
|
warning("DEBUG_DumpClassRegistry - untested");
|
|
Common::DumpFile *f = new Common::DumpFile;
|
|
f->open("zz_class_reg_dump.log");
|
|
SystemClassRegistry::getInstance()->dumpClasses(f);
|
|
f->close();
|
|
delete f;
|
|
_game->quickMessage("Classes dump completed.");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::invalidateDeviceObjects() {
|
|
for (int32 i = 0; i < _regObjects.getSize(); i++) {
|
|
_regObjects[i]->invalidateDeviceObjects();
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::restoreDeviceObjects() {
|
|
for (int32 i = 0; i < _regObjects.getSize(); i++) {
|
|
_regObjects[i]->restoreDeviceObjects();
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::setWaitCursor(const char *filename) {
|
|
SAFE_DELETE(_cursorNoninteractive);
|
|
|
|
_cursorNoninteractive = new BaseSprite(_game);
|
|
if (!_cursorNoninteractive || DID_FAIL(_cursorNoninteractive->loadFile(filename))) {
|
|
SAFE_DELETE(_cursorNoninteractive);
|
|
return STATUS_FAILED;
|
|
} else {
|
|
return STATUS_OK;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::isVideoPlaying() {
|
|
if (_videoPlayer->isPlaying()) {
|
|
return true;
|
|
}
|
|
if (_theoraPlayer && _theoraPlayer->isPlaying()) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::stopVideo() {
|
|
if (_videoPlayer->isPlaying()) {
|
|
_videoPlayer->stop();
|
|
}
|
|
if (_theoraPlayer && _theoraPlayer->isPlaying()) {
|
|
_theoraPlayer->stop();
|
|
SAFE_DELETE(_theoraPlayer);
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::drawCursor(BaseSprite *cursor) {
|
|
if (!cursor) {
|
|
return STATUS_FAILED;
|
|
}
|
|
if (cursor != _lastCursor) {
|
|
cursor->reset();
|
|
_lastCursor = cursor;
|
|
}
|
|
return cursor->draw(_mousePos.x, _mousePos.y);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::renderShadowGeometry() {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::onActivate(bool activate, bool refreshMouse) {
|
|
if (_shuttingDown || !_renderer) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
_renderer->_active = activate;
|
|
|
|
if (refreshMouse) {
|
|
Common::Point32 p;
|
|
getMousePos(&p);
|
|
setActiveObject(_renderer->getObjectAt(p.x, p.y));
|
|
}
|
|
|
|
if (activate) {
|
|
_soundMgr->resumeAll();
|
|
} else {
|
|
_soundMgr->pauseAll();
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
BaseObject *BaseGame::getNextAccessObject(BaseObject *currObject) {
|
|
if (_focusedWindow) {
|
|
return _focusedWindow->getNextAccessObject(currObject);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
BaseObject* BaseGame::getPrevAccessObject(BaseObject *currObject) {
|
|
if(_focusedWindow) {
|
|
return _focusedWindow->getPrevAccessObject(currObject);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::onMouseLeftDown() {
|
|
if (isVideoPlaying()) {
|
|
stopVideo();
|
|
return STATUS_OK;
|
|
}
|
|
|
|
if (_activeObject) {
|
|
_activeObject->handleMouse(MOUSE_CLICK, MOUSE_BUTTON_LEFT);
|
|
}
|
|
|
|
bool handled = _state == GAME_RUNNING && DID_SUCCEED(applyEvent("LeftClick"));
|
|
if (!handled) {
|
|
if (_activeObject != nullptr) {
|
|
_activeObject->applyEvent("LeftClick");
|
|
}
|
|
}
|
|
|
|
if (_activeObject != nullptr) {
|
|
_capturedObject = _activeObject;
|
|
}
|
|
_mouseLeftDown = true;
|
|
//BasePlatform::setCapture(_renderer->_window);
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::onMouseLeftUp() {
|
|
if (isVideoPlaying()) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
if (_activeObject) {
|
|
_activeObject->handleMouse(MOUSE_RELEASE, MOUSE_BUTTON_LEFT);
|
|
}
|
|
|
|
//BasePlatform::releaseCapture();
|
|
_capturedObject = nullptr;
|
|
_mouseLeftDown = false;
|
|
|
|
bool handled = _state == GAME_RUNNING && DID_SUCCEED(applyEvent("LeftRelease"));
|
|
if (!handled) {
|
|
if (_activeObject != nullptr) {
|
|
_activeObject->applyEvent("LeftRelease");
|
|
}
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::onMouseLeftDblClick() {
|
|
if (isVideoPlaying()) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
if (_state == GAME_RUNNING && !_interactive) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
if (_activeObject) {
|
|
_activeObject->handleMouse(MOUSE_DBLCLICK, MOUSE_BUTTON_LEFT);
|
|
}
|
|
|
|
bool handled = _state == GAME_RUNNING && DID_SUCCEED(applyEvent("LeftDoubleClick"));
|
|
if (!handled) {
|
|
if (_activeObject != nullptr) {
|
|
_activeObject->applyEvent("LeftDoubleClick");
|
|
}
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::onMouseRightDblClick() {
|
|
if (isVideoPlaying()) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
if (_state == GAME_RUNNING && !_interactive) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
if (_activeObject) {
|
|
_activeObject->handleMouse(MOUSE_DBLCLICK, MOUSE_BUTTON_RIGHT);
|
|
}
|
|
|
|
bool handled = _state == GAME_RUNNING && DID_SUCCEED(applyEvent("RightDoubleClick"));
|
|
if (!handled) {
|
|
if (_activeObject != nullptr) {
|
|
_activeObject->applyEvent("RightDoubleClick");
|
|
}
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::onMouseRightDown() {
|
|
if (isVideoPlaying()) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
if (_activeObject) {
|
|
_activeObject->handleMouse(MOUSE_CLICK, MOUSE_BUTTON_RIGHT);
|
|
}
|
|
|
|
bool handled = _state == GAME_RUNNING && DID_SUCCEED(applyEvent("RightClick"));
|
|
if (!handled) {
|
|
if (_activeObject != nullptr) {
|
|
_activeObject->applyEvent("RightClick");
|
|
}
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::onMouseRightUp() {
|
|
if (isVideoPlaying()) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
if (_activeObject) {
|
|
_activeObject->handleMouse(MOUSE_RELEASE, MOUSE_BUTTON_RIGHT);
|
|
}
|
|
|
|
bool handled = _state == GAME_RUNNING && DID_SUCCEED(applyEvent("RightRelease"));
|
|
if (!handled) {
|
|
if (_activeObject != nullptr) {
|
|
_activeObject->applyEvent("RightRelease");
|
|
}
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::onMouseMiddleDown() {
|
|
if (isVideoPlaying()) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
if (_state == GAME_RUNNING && !_interactive) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
if (_activeObject) {
|
|
_activeObject->handleMouse(MOUSE_CLICK, MOUSE_BUTTON_MIDDLE);
|
|
}
|
|
|
|
bool handled = _state == GAME_RUNNING && DID_SUCCEED(applyEvent("MiddleClick"));
|
|
if (!handled) {
|
|
if (_activeObject != nullptr) {
|
|
_activeObject->applyEvent("MiddleClick");
|
|
}
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::onMouseMiddleUp() {
|
|
if (isVideoPlaying()) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
if (_activeObject) {
|
|
_activeObject->handleMouse(MOUSE_RELEASE, MOUSE_BUTTON_MIDDLE);
|
|
}
|
|
|
|
bool handled = _state == GAME_RUNNING && DID_SUCCEED(applyEvent("MiddleRelease"));
|
|
if (!handled) {
|
|
if (_activeObject != nullptr) {
|
|
_activeObject->applyEvent("MiddleRelease");
|
|
}
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::onPaint() {
|
|
if (_renderer && _renderer->isWindowed() && _renderer->isReady()) {
|
|
_renderer->initLoop();
|
|
displayContent(false, true);
|
|
displayDebugInfo();
|
|
_renderer->windowedBlt();
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::onWindowClose() {
|
|
if (canHandleEvent("QuitGame")) {
|
|
if (_state != GAME_FROZEN) {
|
|
_game->applyEvent("QuitGame");
|
|
}
|
|
return STATUS_OK;
|
|
} else {
|
|
return STATUS_FAILED;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::displayDebugInfo() {
|
|
const uint32 strLength = 100;
|
|
char str[strLength];
|
|
|
|
if (_debugShowFPS) {
|
|
Common::sprintf_s(str, "FPS: %d", _game->_fps);
|
|
_systemFont->drawText((byte *)str, 0, 0, 100, TAL_LEFT);
|
|
}
|
|
|
|
if (_game->_debugMode) {
|
|
if (!_game->_renderer->isWindowed()) {
|
|
Common::sprintf_s(str, "Mode: %dx%dx%d", _renderer->getWidth(), _renderer->getHeight(), _renderer->getBPP());
|
|
} else {
|
|
Common::sprintf_s(str, "Mode: %dx%d windowed", _renderer->getWidth(), _renderer->getHeight());
|
|
}
|
|
|
|
Common::strlcat(str, " (", strLength);
|
|
Common::strlcat(str, _renderer->getName().c_str(), strLength);
|
|
Common::strlcat(str, ")", strLength);
|
|
_systemFont->drawText((byte *)str, 0, 0, _renderer->getWidth(), TAL_RIGHT);
|
|
|
|
_renderer->displayDebugInfo();
|
|
|
|
int scrTotal, scrRunning, scrWaiting, scrPersistent;
|
|
scrTotal = _scEngine->getNumScripts(&scrRunning, &scrWaiting, &scrPersistent);
|
|
Common::sprintf_s(str, "Running scripts: %d (r:%d w:%d p:%d)", scrTotal, scrRunning, scrWaiting, scrPersistent);
|
|
_systemFont->drawText((byte *)str, 0, 70, _renderer->getWidth(), TAL_RIGHT);
|
|
|
|
Common::sprintf_s(str, "Timer: %d", _timer);
|
|
_game->_systemFont->drawText((byte *)str, 0, 130, _renderer->getWidth(), TAL_RIGHT);
|
|
|
|
if (_activeObject != nullptr) {
|
|
_systemFont->drawText((const byte *)_activeObject->_name, 0, 150, _renderer->getWidth(), TAL_RIGHT);
|
|
}
|
|
|
|
// Display used memory
|
|
Common::sprintf_s(str, "GfxMem: %dMB", _usedMem / (1024 * 1024));
|
|
_systemFont->drawText((byte *)str, 0, 170, _renderer->getWidth(), TAL_RIGHT);
|
|
}
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
#ifdef ENABLE_WME3D
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::setMaxShadowType(TShadowType maxShadowType) {
|
|
if (maxShadowType > SHADOW_STENCIL) {
|
|
maxShadowType = SHADOW_STENCIL;
|
|
}
|
|
if (maxShadowType < 0) {
|
|
maxShadowType = SHADOW_NONE;
|
|
}
|
|
|
|
if (maxShadowType == SHADOW_FLAT && !_supportsRealTimeShadows) {
|
|
maxShadowType = SHADOW_SIMPLE;
|
|
}
|
|
_maxShadowType = maxShadowType;
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
TShadowType BaseGame::getMaxShadowType(BaseObject *object) {
|
|
if (!object)
|
|
return _maxShadowType;
|
|
else
|
|
return MIN(_maxShadowType, object->_shadowType);
|
|
}
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::getLayerSize(int *layerWidth, int *layerHeight, Common::Rect32 *viewport, bool *customViewport) {
|
|
if (_renderer) {
|
|
*layerWidth = _renderer->getWidth();
|
|
*layerHeight = _renderer->getHeight();
|
|
*customViewport = false;
|
|
BasePlatform::setRect(viewport, 0, 0, _renderer->getWidth(), _renderer->getHeight());
|
|
return true;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
#ifdef ENABLE_WME3D
|
|
//////////////////////////////////////////////////////////////////////////
|
|
uint32 BaseGame::getAmbientLightColor() {
|
|
return 0x00000000;
|
|
}
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::getMousePos(Common::Point32 *pos) {
|
|
BasePlatform::getCursorPos(pos);
|
|
|
|
pos->x -= _renderer->_drawOffsetX;
|
|
pos->y -= _renderer->_drawOffsetY;
|
|
|
|
/*
|
|
// Windows can squish maximized window if it's larger than desktop
|
|
// so we need to modify mouse position appropriately (tnx mRax)
|
|
if (_renderer->_windowed && ::IsZoomed(_renderer->_window)) {
|
|
Common::Rect rc;
|
|
::GetClientRect(_renderer->_window, &rc);
|
|
Pos->x *= _game->_renderer->_realWidth;
|
|
Pos->x /= (rc.right - rc.left);
|
|
Pos->y *= _game->_renderer->_realHeight;
|
|
Pos->y /= (rc.bottom - rc.top);
|
|
}
|
|
*/
|
|
|
|
if (_mouseLockRect.left != 0 && _mouseLockRect.right != 0 && _mouseLockRect.top != 0 && _mouseLockRect.bottom != 0) {
|
|
if (!BasePlatform::ptInRect(&_mouseLockRect, *pos)) {
|
|
pos->x = MAX(_mouseLockRect.left, pos->x);
|
|
pos->y = MAX(_mouseLockRect.top, pos->y);
|
|
|
|
pos->x = MIN(_mouseLockRect.right, pos->x);
|
|
pos->y = MIN(_mouseLockRect.bottom, pos->y);
|
|
|
|
Common::Point32 newPos = *pos;
|
|
|
|
newPos.x += _renderer->_drawOffsetX;
|
|
newPos.y += _renderer->_drawOffsetY;
|
|
|
|
//CBPlatform::ClientToScreen(Game->m_Renderer->m_Window, &NewPos);
|
|
BasePlatform::setCursorPos(newPos.x, newPos.y);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef ENABLE_WME3D
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::getFogParams(bool *fogEnabled, uint32 *, float *, float *) {
|
|
*fogEnabled = false;
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::miniUpdate() {
|
|
if (!_miniUpdateEnabled) {
|
|
return true;
|
|
}
|
|
|
|
if (BasePlatform::getTime() - _lastMiniUpdate > 200) {
|
|
if (_soundMgr) {
|
|
_soundMgr->initLoop();
|
|
}
|
|
_lastMiniUpdate = BasePlatform::getTime();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::onScriptShutdown(ScScript *script) {
|
|
return STATUS_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::setIndicatorVal(int value) {
|
|
bool redisplay = (_indicatorProgress != value);
|
|
_indicatorProgress = value;
|
|
if (redisplay)
|
|
displayIndicator();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::isLeftDoubleClick() {
|
|
return isDoubleClick(0);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::isRightDoubleClick() {
|
|
return isDoubleClick(1);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::isDoubleClick(int32 buttonIndex) {
|
|
uint32 maxDoubleCLickTime = 500;
|
|
int maxMoveX = 4;
|
|
int maxMoveY = 4;
|
|
|
|
Common::Point32 pos;
|
|
BasePlatform::getCursorPos(&pos);
|
|
|
|
int moveX = ABS(pos.x - _lastClick[buttonIndex].posX);
|
|
int moveY = ABS(pos.y - _lastClick[buttonIndex].posY);
|
|
|
|
if (_lastClick[buttonIndex].time == 0 || BasePlatform::getTime() - _lastClick[buttonIndex].time > maxDoubleCLickTime || moveX > maxMoveX || moveY > maxMoveY) {
|
|
_lastClick[buttonIndex].time = BasePlatform::getTime();
|
|
_lastClick[buttonIndex].posX = pos.x;
|
|
_lastClick[buttonIndex].posY = pos.y;
|
|
return false;
|
|
} else {
|
|
_lastClick[buttonIndex].time = 0;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::handleCustomActionStart(BaseGameCustomAction action) {
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::handleCustomActionEnd(BaseGameCustomAction action) {
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::autoSaveOnExit() {
|
|
_soundMgr->saveSettings();
|
|
|
|
if (!_autoSaveOnExit) {
|
|
return;
|
|
}
|
|
if (_state == GAME_FROZEN) {
|
|
return;
|
|
}
|
|
|
|
saveGame(_autoSaveSlot, "autosave", true);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void BaseGame::addMem(int32 bytes) {
|
|
_usedMem += bytes;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
AnsiString BaseGame::getDeviceType() const {
|
|
return "computer";
|
|
}
|
|
|
|
#ifdef ENABLE_HEROCRAFT
|
|
uint8 BaseGame::getFilePartChecksumHc(const char *filename, uint32 begin, uint32 end) {
|
|
if (begin >= end) {
|
|
warning("Wrong limits for checksum check");
|
|
return 0;
|
|
}
|
|
|
|
uint32 size;
|
|
char *buffer = (char *)BaseFileManager::getEngineInstance()->readWholeFile(filename, &size);
|
|
if (buffer == nullptr) {
|
|
warning("Failed to open '%s' for checksum check", filename);
|
|
return 0;
|
|
}
|
|
|
|
if (size < end) {
|
|
warning("File '%s' is too small for checksum check", filename);
|
|
delete[] buffer;
|
|
return 0;
|
|
}
|
|
|
|
uint8 result = 0;
|
|
for (uint32 i = begin; i < end; i++) {
|
|
uint8 tmp = buffer[i];
|
|
result += tmp;
|
|
if (result < tmp) {
|
|
result++;
|
|
}
|
|
}
|
|
|
|
delete[] buffer;
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
#ifdef ENABLE_FOXTAIL
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool BaseGame::displayIndicatorFoxTail() {
|
|
_renderer->clear();
|
|
|
|
// Original whole condition seems has typo with '&&' instead '||' for first part.
|
|
// Added _indicatorProgress to avoid draw on 0 progress
|
|
if (!_indicatorDisplay || !_indicatorProgress || _indicatorWidth <= 0 || _indicatorHeight <= 0)
|
|
return STATUS_OK;
|
|
int curWidth = (int)(_indicatorWidth * (float)((float)_indicatorProgress / 100.0f));
|
|
_renderer->fillRect(_indicatorX, _indicatorY, curWidth, _indicatorHeight, _indicatorColor);
|
|
|
|
if (_saveLoadImage) {
|
|
Common::Rect32 rc;
|
|
BasePlatform::setRect(&rc, 0, 0, _saveLoadImage->getWidth(), _saveLoadImage->getHeight());
|
|
if (_loadInProgress)
|
|
_saveLoadImage->displayTrans(_loadImageX, _loadImageY, rc);
|
|
else
|
|
_saveLoadImage->displayTrans(_saveImageX, _saveImageY, rc);
|
|
_renderer->flip();
|
|
}
|
|
_renderer->forcedFlip();
|
|
|
|
return STATUS_OK;
|
|
}
|
|
#endif
|
|
|
|
void BaseGame::getSaveSlotTimestamp(int slot, TimeDate *time) {
|
|
memset(time, 0, sizeof(TimeDate));
|
|
Common::String filename;
|
|
getSaveSlotFilename(slot, filename);
|
|
BasePersistenceManager *pm = new BasePersistenceManager();
|
|
if ((pm->initLoad(filename))) {
|
|
*time = pm->getSavedTimestamp();
|
|
}
|
|
delete pm;
|
|
}
|
|
|
|
Common::String BaseGame::readRegistryString(const Common::String &key, const Common::String &initValue) const {
|
|
// Game specific hacks:
|
|
Common::String result = initValue;
|
|
// James Peris:
|
|
if (BaseEngine::instance().getGameId() == "jamesperis" && key == "Language") {
|
|
Common::Language language = BaseEngine::instance().getLanguage();
|
|
if (language == Common::EN_ANY) {
|
|
result = "english";
|
|
} else if (language == Common::ES_ESP) {
|
|
result = "spanish";
|
|
} else {
|
|
error("Invalid language set for James Peris");
|
|
}
|
|
} else { // Just fallback to using ConfMan for now
|
|
Common::String privKey = "wme_" + StringUtil::encodeSetting(key);
|
|
if (ConfMan.hasKey(privKey)) {
|
|
result = StringUtil::decodeSetting(ConfMan.get(privKey));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
} // End of namespace Wintermute
|