Initial commit
This commit is contained in:
447
engines/ags/engine/main/config.cpp
Normal file
447
engines/ags/engine/main/config.cpp
Normal file
@@ -0,0 +1,447 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
// Game configuration
|
||||
//
|
||||
#include "ags/engine/ac/game_setup.h"
|
||||
#include "ags/shared/ac/game_setup_struct.h"
|
||||
#include "ags/engine/ac/global_translation.h"
|
||||
#include "ags/engine/ac/path_helper.h"
|
||||
#include "ags/shared/ac/sprite_cache.h"
|
||||
#include "ags/engine/ac/system.h"
|
||||
#include "ags/shared/core/platform.h"
|
||||
#include "ags/engine/debugging/debugger.h"
|
||||
#include "ags/engine/debugging/debug_log.h"
|
||||
#include "ags/engine/device/mouse_w32.h"
|
||||
#include "ags/engine/main/config.h"
|
||||
#include "ags/engine/media/audio/audio_system.h"
|
||||
#include "ags/engine/platform/base/ags_platform_driver.h"
|
||||
#include "ags/shared/util/directory.h"
|
||||
#include "ags/shared/util/ini_util.h"
|
||||
#include "ags/shared/util/text_stream_reader.h"
|
||||
#include "ags/shared/util/path.h"
|
||||
#include "ags/shared/util/string_utils.h"
|
||||
#include "ags/metaengine.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/language.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using namespace AGS::Shared;
|
||||
using namespace AGS::Engine;
|
||||
|
||||
// Filename of the default config file, the one found in the game installation
|
||||
const char *DefaultConfigFileName = "acsetup.cfg";
|
||||
|
||||
WindowSetup parse_window_mode(const String &option, bool as_windowed, WindowSetup def_value) {
|
||||
// "full_window" option means pseudo fullscreen ("borderless fullscreen window")
|
||||
if (!as_windowed && (option.CompareNoCase("full_window") == 0))
|
||||
return WindowSetup(kWnd_FullDesktop);
|
||||
// Check supported options for explicit resolution or scale factor,
|
||||
// in which case we'll use either a resizing window or a REAL fullscreen mode
|
||||
const WindowMode exp_wmode = as_windowed ? kWnd_Windowed : kWnd_Fullscreen;
|
||||
// Note that for "desktop" we return "default" for windowed, this will result
|
||||
// in referring to the desktop size but resizing in accordance to the scaling style
|
||||
if (option.CompareNoCase("desktop") == 0)
|
||||
return as_windowed ? WindowSetup(exp_wmode) : WindowSetup(get_desktop_size(), exp_wmode);
|
||||
// "Native" means using game resolution as a window size
|
||||
if (option.CompareNoCase("native") == 0)
|
||||
return WindowSetup(_GP(game).GetGameRes(), exp_wmode);
|
||||
// Try parse an explicit resolution type or game scale factor --
|
||||
size_t at = option.FindChar('x');
|
||||
if (at == 0) { // try parse as a scale (xN)
|
||||
int scale = StrUtil::StringToInt(option.Mid(1));
|
||||
if (scale > 0) return WindowSetup(scale, exp_wmode);
|
||||
} else if (at != String::NoIndex) {
|
||||
// else try parse as a "width x height"
|
||||
Size sz = Size(StrUtil::StringToInt(option.Mid(0, at)),
|
||||
StrUtil::StringToInt(option.Mid(at + 1)));
|
||||
if (!sz.IsNull()) return WindowSetup(sz, exp_wmode);
|
||||
}
|
||||
// In case of "default" option, or any format mistake, return the default
|
||||
return def_value;
|
||||
}
|
||||
|
||||
// Legacy screen size definition
|
||||
enum ScreenSizeDefinition {
|
||||
kScreenDef_Undefined = -1,
|
||||
kScreenDef_Explicit, // define by width & height
|
||||
kScreenDef_ByGameScaling, // define by game scale factor
|
||||
kScreenDef_MaxDisplay, // set to maximal supported (desktop/device screen size)
|
||||
kNumScreenDef
|
||||
};
|
||||
|
||||
static ScreenSizeDefinition parse_legacy_screendef(const String &option) {
|
||||
const char *screen_sz_def_options[kNumScreenDef] = { "explicit", "scaling", "max" };
|
||||
for (int i = 0; i < kNumScreenDef; ++i) {
|
||||
if (option.CompareNoCase(screen_sz_def_options[i]) == 0) {
|
||||
return (ScreenSizeDefinition)i;
|
||||
}
|
||||
}
|
||||
return kScreenDef_Undefined;
|
||||
}
|
||||
|
||||
FrameScaleDef parse_scaling_option(const String &option, FrameScaleDef def_value) {
|
||||
if (option.CompareNoCase("round") == 0 || option.CompareNoCase("max_round") == 0)
|
||||
return kFrame_Round;
|
||||
if (option.CompareNoCase("stretch") == 0)
|
||||
return kFrame_Stretch;
|
||||
if (option.CompareNoCase("proportional") == 0)
|
||||
return kFrame_Proportional;
|
||||
return def_value;
|
||||
}
|
||||
|
||||
static FrameScaleDef parse_legacy_scaling_option(const String &option, int &scale) {
|
||||
FrameScaleDef frame = parse_scaling_option(option, kFrame_Undefined);
|
||||
if (frame == kFrame_Undefined) {
|
||||
scale = StrUtil::StringToInt(option);
|
||||
return scale > 0 ? kFrame_Round : kFrame_Undefined;
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
// Parses legacy filter ID and converts it into current scaling options
|
||||
bool parse_legacy_frame_config(const String &scaling_option, String &filter_id,
|
||||
FrameScaleDef &frame, int &scale_factor) {
|
||||
struct {
|
||||
String LegacyName;
|
||||
String CurrentName;
|
||||
int Scaling;
|
||||
} legacy_filters[6] = { {"none", "none", -1}, {"max", "StdScale", 0}, {"StdScale", "StdScale", -1},
|
||||
{"AAx", "Linear", -1}, {"Hq2x", "Hqx", 2}, {"Hq3x", "Hqx", 3} };
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (scaling_option.CompareLeftNoCase(legacy_filters[i].LegacyName) == 0) {
|
||||
filter_id = legacy_filters[i].CurrentName;
|
||||
frame = kFrame_Round;
|
||||
scale_factor = legacy_filters[i].Scaling >= 0 ? legacy_filters[i].Scaling :
|
||||
scaling_option.Mid(legacy_filters[i].LegacyName.GetLength()).ToInt();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
String make_scaling_option(FrameScaleDef scale_def) {
|
||||
switch (scale_def) {
|
||||
case kFrame_Stretch:
|
||||
return "stretch";
|
||||
case kFrame_Proportional:
|
||||
return "proportional";
|
||||
default:
|
||||
return "round";
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t convert_scaling_to_fp(int scale_factor) {
|
||||
if (scale_factor >= 0)
|
||||
return scale_factor <<= kShift;
|
||||
else
|
||||
return kUnit / abs(scale_factor);
|
||||
}
|
||||
|
||||
int convert_fp_to_scaling(uint32_t scaling) {
|
||||
if (scaling == 0)
|
||||
return 0;
|
||||
return scaling >= kUnit ? (scaling >> kShift) : -kUnit / (int32_t)scaling;
|
||||
}
|
||||
|
||||
String find_default_cfg_file() {
|
||||
return Path::ConcatPaths(_GP(usetup).startup_dir, DefaultConfigFileName);
|
||||
}
|
||||
|
||||
String find_user_global_cfg_file() {
|
||||
return Path::ConcatPaths(GetGlobalUserConfigDir().FullDir, DefaultConfigFileName);
|
||||
}
|
||||
|
||||
String find_user_cfg_file() {
|
||||
return Path::ConcatPaths(GetGameUserConfigDir().FullDir, DefaultConfigFileName);
|
||||
}
|
||||
|
||||
void config_defaults() {
|
||||
#if AGS_PLATFORM_OS_WINDOWS
|
||||
_GP(usetup).Screen.DriverID = "D3D9";
|
||||
#else
|
||||
_GP(usetup).Screen.DriverID = "OGL";
|
||||
#endif
|
||||
// Defaults for the window style are max resizing window and "fullscreen desktop"
|
||||
_GP(usetup).Screen.FsSetup = WindowSetup(kWnd_FullDesktop);
|
||||
_GP(usetup).Screen.WinSetup = WindowSetup(kWnd_Windowed);
|
||||
}
|
||||
|
||||
static void read_legacy_graphics_config(const ConfigTree &cfg) {
|
||||
// Pre-3.* game resolution setup
|
||||
int default_res = CfgReadInt(cfg, "misc", "defaultres", kGameResolution_Default);
|
||||
int screen_res = CfgReadInt(cfg, "misc", "screenres", 0);
|
||||
if (screen_res > 0 &&
|
||||
(default_res >= kGameResolution_Default && default_res <= kGameResolution_320x240)) {
|
||||
_GP(usetup).override_upscale = true; // run low-res game in high-res mode
|
||||
}
|
||||
|
||||
_GP(usetup).Screen.Windowed = CfgReadBoolInt(cfg, "misc", "windowed");
|
||||
_GP(usetup).Screen.DriverID = CfgReadString(cfg, "misc", "gfxdriver", _GP(usetup).Screen.DriverID);
|
||||
|
||||
// Window setup: style and size definition, game frame style
|
||||
{
|
||||
String legacy_filter = CfgReadString(cfg, "misc", "gfxfilter");
|
||||
if (!legacy_filter.IsEmpty()) {
|
||||
// Legacy scaling config is applied only to windowed setting
|
||||
int scale_factor = 0;
|
||||
parse_legacy_frame_config(legacy_filter, _GP(usetup).Screen.Filter.ID, _GP(usetup).Screen.WinGameFrame,
|
||||
scale_factor);
|
||||
if (scale_factor > 0)
|
||||
_GP(usetup).Screen.WinSetup = WindowSetup(scale_factor);
|
||||
|
||||
// AGS 3.2.1 and 3.3.0 aspect ratio preferences for fullscreen
|
||||
if (!_GP(usetup).Screen.Windowed) {
|
||||
bool allow_borders =
|
||||
(CfgReadBoolInt(cfg, "misc", "sideborders") || CfgReadBoolInt(cfg, "misc", "forceletterbox") ||
|
||||
CfgReadBoolInt(cfg, "misc", "prefer_sideborders") || CfgReadBoolInt(cfg, "misc", "prefer_letterbox"));
|
||||
_GP(usetup).Screen.FsGameFrame = allow_borders ? kFrame_Proportional : kFrame_Stretch;
|
||||
}
|
||||
}
|
||||
|
||||
// AGS 3.4.0 - 3.4.1-rc uniform scaling option
|
||||
String uniform_frame_scale = CfgReadString(cfg, "graphics", "game_scale");
|
||||
if (!uniform_frame_scale.IsEmpty()) {
|
||||
int src_scale = 1;
|
||||
FrameScaleDef frame = parse_legacy_scaling_option(uniform_frame_scale, src_scale);
|
||||
_GP(usetup).Screen.FsGameFrame = frame;
|
||||
_GP(usetup).Screen.WinGameFrame = frame;
|
||||
}
|
||||
|
||||
// AGS 3.5.* gfx mode with screen definition
|
||||
const bool is_windowed = CfgReadBoolInt(cfg, "graphics", "windowed");
|
||||
WindowSetup &ws = is_windowed ? _GP(usetup).Screen.WinSetup : _GP(usetup).Screen.FsSetup;
|
||||
const WindowMode wm = is_windowed ? kWnd_Windowed : kWnd_Fullscreen;
|
||||
ScreenSizeDefinition scr_def = parse_legacy_screendef(CfgReadString(cfg, "graphics", "screen_def"));
|
||||
switch (scr_def) {
|
||||
case kScreenDef_Explicit:
|
||||
{
|
||||
Size sz(
|
||||
CfgReadInt(cfg, "graphics", "screen_width"),
|
||||
CfgReadInt(cfg, "graphics", "screen_height"));
|
||||
ws = WindowSetup(sz, wm);
|
||||
}
|
||||
break;
|
||||
case kScreenDef_ByGameScaling:
|
||||
{
|
||||
int src_scale = 0;
|
||||
is_windowed ?
|
||||
parse_legacy_scaling_option(CfgReadString(cfg, "graphics", "game_scale_win"), src_scale) :
|
||||
parse_legacy_scaling_option(CfgReadString(cfg, "graphics", "game_scale_fs"), src_scale);
|
||||
ws = WindowSetup(src_scale, wm);
|
||||
}
|
||||
break;
|
||||
case kScreenDef_MaxDisplay:
|
||||
ws = is_windowed ? WindowSetup() : WindowSetup(kWnd_FullDesktop);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_GP(usetup).Screen.Params.RefreshRate = CfgReadInt(cfg, "misc", "refresh");
|
||||
_GP(usetup).enable_antialiasing = CfgReadBoolInt(cfg, "misc", "antialias");
|
||||
}
|
||||
|
||||
static void read_legacy_config(const ConfigTree &cfg) {
|
||||
read_legacy_graphics_config(cfg);
|
||||
|
||||
_GP(usetup).SpriteCacheSize = CfgReadInt(cfg, "misc", "cachemax", _GP(usetup).SpriteCacheSize);
|
||||
}
|
||||
|
||||
void override_config_ext(ConfigTree &cfg) {
|
||||
_G(platform)->ReadConfiguration(cfg);
|
||||
}
|
||||
|
||||
void apply_config(const ConfigTree &cfg) {
|
||||
// Legacy settings have to be translated into new options;
|
||||
// they must be read first, to let newer options override them, if ones are present
|
||||
read_legacy_config(cfg);
|
||||
|
||||
{
|
||||
// Audio options
|
||||
_GP(usetup).audio_enabled = CfgReadBoolInt(cfg, "sound", "enabled", _GP(usetup).audio_enabled);
|
||||
_GP(usetup).audio_driver = CfgReadString(cfg, "sound", "driver");
|
||||
// This option is backwards (usevox is 0 if no_speech_pack)
|
||||
_GP(usetup).no_speech_pack = !CfgReadBoolInt(cfg, "sound", "usespeech", true);
|
||||
|
||||
// Graphics mode and options
|
||||
_GP(usetup).Screen.DriverID = CfgReadString(cfg, "graphics", "driver", _GP(usetup).Screen.DriverID);
|
||||
_GP(usetup).Screen.Windowed = CfgReadBoolInt(cfg, "graphics", "windowed", _GP(usetup).Screen.Windowed);
|
||||
_GP(usetup).Screen.FsSetup =
|
||||
parse_window_mode(CfgReadString(cfg, "graphics", "fullscreen", "default"), false, _GP(usetup).Screen.FsSetup);
|
||||
_GP(usetup).Screen.WinSetup =
|
||||
parse_window_mode(CfgReadString(cfg, "graphics", "window", "default"), true, _GP(usetup).Screen.WinSetup);
|
||||
|
||||
_GP(usetup).Screen.Filter.ID = CfgReadString(cfg, "graphics", "filter", "StdScale");
|
||||
_GP(usetup).Screen.FsGameFrame =
|
||||
parse_scaling_option(CfgReadString(cfg, "graphics", "game_scale_fs", "proportional"), _GP(usetup).Screen.FsGameFrame);
|
||||
_GP(usetup).Screen.WinGameFrame =
|
||||
parse_scaling_option(CfgReadString(cfg, "graphics", "game_scale_win", "round"), _GP(usetup).Screen.WinGameFrame);
|
||||
|
||||
_GP(usetup).Screen.Params.RefreshRate = CfgReadInt(cfg, "graphics", "refresh");
|
||||
|
||||
// Use ScummVM options to set the vsync flag, if available
|
||||
if (ConfMan.hasKey("vsync"))
|
||||
_GP(usetup).Screen.Params.VSync = ConfMan.getBool("vsync");
|
||||
else
|
||||
_GP(usetup).Screen.Params.VSync = CfgReadBoolInt(cfg, "graphics", "vsync");
|
||||
|
||||
_GP(usetup).RenderAtScreenRes = CfgReadBoolInt(cfg, "graphics", "render_at_screenres");
|
||||
_GP(usetup).enable_antialiasing = CfgReadBoolInt(cfg, "graphics", "antialias");
|
||||
_GP(usetup).software_render_driver = CfgReadString(cfg, "graphics", "software_driver");
|
||||
|
||||
#ifdef TODO
|
||||
_GP(usetup).rotation = (ScreenRotation)CfgReadInt(cfg, "graphics", "rotation", _GP(usetup).rotation);
|
||||
String rotation_str = CfgReadString(cfg, "graphics", "rotation", "unlocked");
|
||||
_GP(usetup).rotation = StrUtil::ParseEnum<ScreenRotation>(
|
||||
rotation_str, CstrArr<kNumScreenRotationOptions>{ "unlocked", "portrait", "landscape" },
|
||||
_GP(usetup).rotation);
|
||||
#endif
|
||||
|
||||
// Custom paths
|
||||
_GP(usetup).load_latest_save = CfgReadBoolInt(cfg, "misc", "load_latest_save", _GP(usetup).load_latest_save);
|
||||
_GP(usetup).user_data_dir = CfgReadString(cfg, "misc", "user_data_dir");
|
||||
_GP(usetup).shared_data_dir = CfgReadString(cfg, "misc", "shared_data_dir");
|
||||
_GP(usetup).show_fps = CfgReadBoolInt(cfg, "misc", "show_fps");
|
||||
|
||||
// Translation / localization
|
||||
Common::String translation;
|
||||
|
||||
if (!ConfMan.get("language").empty() && ConfMan.isKeyTemporary("language")) {
|
||||
// Map the language defined in the command-line "language" option to its description
|
||||
Common::Language lang = Common::parseLanguage(ConfMan.get("language"));
|
||||
|
||||
if (lang != Common::Language::UNK_LANG) {
|
||||
Common::String translationCode = Common::getLanguageCode(lang);
|
||||
translationCode.toLowercase();
|
||||
translation = Common::getLanguageDescription(lang);
|
||||
translation.toLowercase();
|
||||
|
||||
// Check if the game actually has such a translation, and set it if it does
|
||||
// The name of translation files can be anything, but in general they are one of:
|
||||
// - English name of the language, for example French.tra or Spanish.tra (covered)
|
||||
// - Translated name of the language, for example polsky.tra or francais.tra (not covered)
|
||||
// - The language code, for example FR.tra or DE.tra (covered)
|
||||
// - And these can be combined with a prefix or suffix, for example Nelly_Polish.tra, english2.tra (covered)
|
||||
Common::StringArray traFileNames = AGSMetaEngine::getGameTranslations(ConfMan.getActiveDomainName());
|
||||
for (Common::StringArray::iterator iter = traFileNames.begin(); iter != traFileNames.end(); ++iter) {
|
||||
Common::String traFileName = *iter;
|
||||
traFileName.toLowercase();
|
||||
if (traFileName.contains(translation) || traFileName.equals(translationCode)) {
|
||||
_GP(usetup).translation = *iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (ConfMan.getActiveDomain()->tryGetVal("translation", translation) && !translation.empty())
|
||||
_GP(usetup).translation = translation;
|
||||
else
|
||||
_GP(usetup).translation = CfgReadString(cfg, "language", "translation");
|
||||
|
||||
// Resource caches and options
|
||||
_GP(usetup).clear_cache_on_room_change = CfgReadBoolInt(cfg, "misc", "clear_cache_on_room_change", _GP(usetup).clear_cache_on_room_change);
|
||||
_GP(usetup).SpriteCacheSize = CfgReadInt(cfg, "graphics", "sprite_cache_size", _GP(usetup).SpriteCacheSize);
|
||||
_GP(usetup).TextureCacheSize = CfgReadInt(cfg, "graphics", "texture_cache_size", _GP(usetup).TextureCacheSize);
|
||||
|
||||
// Mouse options
|
||||
_GP(usetup).mouse_auto_lock = CfgReadBoolInt(cfg, "mouse", "auto_lock");
|
||||
_GP(usetup).mouse_speed = CfgReadFloat(cfg, "mouse", "speed", 1.f);
|
||||
if (_GP(usetup).mouse_speed <= 0.f)
|
||||
_GP(usetup).mouse_speed = 1.f;
|
||||
const char *mouse_ctrl_options[kNumMouseCtrlOptions] = { "never", "fullscreen", "always" };
|
||||
String mouse_str = CfgReadString(cfg, "mouse", "control_when", "fullscreen");
|
||||
for (int i = 0; i < kNumMouseCtrlOptions; ++i) {
|
||||
if (mouse_str.CompareNoCase(mouse_ctrl_options[i]) == 0) {
|
||||
_GP(usetup).mouse_ctrl_when = (MouseControlWhen)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_GP(usetup).mouse_ctrl_enabled = CfgReadBoolInt(cfg, "mouse", "control_enabled", _GP(usetup).mouse_ctrl_enabled);
|
||||
const char *mouse_speed_options[kNumMouseSpeedDefs] = { "absolute", "current_display" };
|
||||
mouse_str = CfgReadString(cfg, "mouse", "speed_def", "current_display");
|
||||
for (int i = 0; i < kNumMouseSpeedDefs; ++i) {
|
||||
if (mouse_str.CompareNoCase(mouse_speed_options[i]) == 0) {
|
||||
_GP(usetup).mouse_speed_def = (MouseSpeedDef)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Various system options
|
||||
_GP(usetup).multitasking = CfgReadInt(cfg, "misc", "background", 0) != 0;
|
||||
|
||||
// User's overrides and hacks
|
||||
_GP(usetup).override_multitasking = CfgReadInt(cfg, "override", "multitasking", -1);
|
||||
_GP(usetup).override_script_os = -1;
|
||||
// Looks for the existence of the Linux executable
|
||||
if (File::IsFile(Path::ConcatPaths(_GP(usetup).startup_dir, "ags64"))) {
|
||||
_GP(usetup).override_script_os = eOS_Linux;
|
||||
}
|
||||
String override_os = CfgReadString(cfg, "override", "os");
|
||||
if (override_os.CompareNoCase("dos") == 0) {
|
||||
_GP(usetup).override_script_os = eOS_DOS;
|
||||
} else if (override_os.CompareNoCase("win") == 0) {
|
||||
_GP(usetup).override_script_os = eOS_Win;
|
||||
} else if (override_os.CompareNoCase("linux") == 0) {
|
||||
_GP(usetup).override_script_os = eOS_Linux;
|
||||
} else if (override_os.CompareNoCase("mac") == 0) {
|
||||
_GP(usetup).override_script_os = eOS_Mac;
|
||||
}
|
||||
_GP(usetup).override_upscale = CfgReadBoolInt(cfg, "override", "upscale", _GP(usetup).override_upscale);
|
||||
_GP(usetup).legacysave_assume_dataver = static_cast<GameDataVersion>(CfgReadInt(cfg, "override", "legacysave_assume_dataver", kGameVersion_Undefined));
|
||||
_GP(usetup).legacysave_let_gui_diff = CfgReadBoolInt(cfg, "override", "legacysave_let_gui_diff");
|
||||
_GP(usetup).key_save_game = CfgReadInt(cfg, "override", "save_game_key", 0);
|
||||
_GP(usetup).key_restore_game = CfgReadInt(cfg, "override", "restore_game_key", 0);
|
||||
}
|
||||
|
||||
// Apply logging configuration
|
||||
apply_debug_config(cfg);
|
||||
}
|
||||
|
||||
void post_config() {
|
||||
if (_GP(usetup).Screen.DriverID.IsEmpty() || _GP(usetup).Screen.DriverID.CompareNoCase("DX5") == 0)
|
||||
_GP(usetup).Screen.DriverID = "Software";
|
||||
|
||||
// FIXME: this correction is needed at the moment because graphics driver
|
||||
// implementation requires some filter to be created anyway
|
||||
_GP(usetup).Screen.Filter.UserRequest = _GP(usetup).Screen.Filter.ID;
|
||||
if (_GP(usetup).Screen.Filter.ID.IsEmpty() || _GP(usetup).Screen.Filter.ID.CompareNoCase("none") == 0) {
|
||||
_GP(usetup).Screen.Filter.ID = "StdScale";
|
||||
}
|
||||
}
|
||||
|
||||
void save_config_file() {
|
||||
// Translation / localization
|
||||
if (!_GP(usetup).translation.IsEmpty()) {
|
||||
ConfMan.getActiveDomain()->setVal("translation", _GP(usetup).translation.GetCStr());
|
||||
ConfMan.flushToDisk();
|
||||
} else if (ConfMan.getActiveDomain()->contains("translation")) {
|
||||
ConfMan.getActiveDomain()->erase("translation");
|
||||
ConfMan.flushToDisk();
|
||||
}
|
||||
|
||||
// ScummVM doesn't write out other configuration changes
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
57
engines/ags/engine/main/config.h
Normal file
57
engines/ags/engine/main/config.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_ENGINE_MAIN_CONFIG_H
|
||||
#define AGS_ENGINE_MAIN_CONFIG_H
|
||||
|
||||
#include "ags/engine/main/graphics_mode.h"
|
||||
#include "ags/shared/util/ini_util.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using AGS::Shared::String;
|
||||
using AGS::Shared::ConfigTree;
|
||||
|
||||
// Set up default config settings
|
||||
void config_defaults();
|
||||
// Find and default configuration file (usually located in the game installation directory)
|
||||
String find_default_cfg_file();
|
||||
// Find all-games user configuration file
|
||||
String find_user_global_cfg_file();
|
||||
// Find and game-specific user configuration file (located into writable user directory)
|
||||
String find_user_cfg_file();
|
||||
// Apply overriding values from the external config (e.g. for mobile ports)
|
||||
void override_config_ext(ConfigTree &cfg);
|
||||
// Setup game using final config tree
|
||||
void apply_config(const ConfigTree &cfg);
|
||||
// Fixup game setup parameters
|
||||
void post_config();
|
||||
|
||||
void save_config_file();
|
||||
|
||||
FrameScaleDef parse_scaling_option(const String &option, FrameScaleDef def_value = kFrame_Undefined);
|
||||
String make_scaling_option(FrameScaleDef scale_def);
|
||||
uint32_t convert_scaling_to_fp(int scale_factor);
|
||||
int convert_fp_to_scaling(uint32_t scaling);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
1278
engines/ags/engine/main/engine.cpp
Normal file
1278
engines/ags/engine/main/engine.cpp
Normal file
File diff suppressed because it is too large
Load Diff
83
engines/ags/engine/main/engine.h
Normal file
83
engines/ags/engine/main/engine.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_ENGINE_MAIN_ENGINE_H
|
||||
#define AGS_ENGINE_MAIN_ENGINE_H
|
||||
|
||||
#include "ags/shared/util/ini_util.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
const char *get_engine_name();
|
||||
const char *get_engine_version();
|
||||
AGS::Shared::String get_engine_version_and_build();
|
||||
|
||||
void show_preload();
|
||||
void engine_init_game_settings();
|
||||
int initialize_engine(const AGS::Shared::ConfigTree &startup_opts);
|
||||
|
||||
struct DisplayModeSetup;
|
||||
// Try to set new graphics mode deduced from given configuration;
|
||||
// if requested mode fails, tries to find any compatible mode close to the
|
||||
// requested one.
|
||||
bool engine_try_set_gfxmode_any(const DisplayModeSetup &setup);
|
||||
// Tries to switch between fullscreen and windowed mode; uses previously saved
|
||||
// setup if it is available, or default settings for the new mode
|
||||
bool engine_try_switch_windowed_gfxmode();
|
||||
// Update graphic renderer and render frame when window size changes
|
||||
void engine_on_window_changed(const Size &sz);
|
||||
// Shutdown graphics mode (used before shutting down tha application)
|
||||
void engine_shutdown_gfxmode();
|
||||
|
||||
using AGS::Shared::String;
|
||||
// Defines a package file location
|
||||
struct PackLocation {
|
||||
String Name; // filename, for the reference or to use as an ID
|
||||
String Path; // full path
|
||||
};
|
||||
// Game resource paths
|
||||
// TODO: the asset path configuration should certainly be revamped at some
|
||||
// point, with uniform method of configuring auxiliary paths and packages.
|
||||
struct ResourcePaths {
|
||||
PackLocation GamePak; // main game package
|
||||
PackLocation AudioPak; // audio package
|
||||
PackLocation SpeechPak; // voice-over package
|
||||
String DataDir; // path to the data directory
|
||||
bool VoiceAvail = false; // tells whether voice files available in either location
|
||||
// NOTE: optional directories are currently only for compatibility with Editor (game test runs)
|
||||
// This is bit ugly, but remain so until more flexible configuration is designed
|
||||
String DataDir2; // optional data directory
|
||||
String AudioDir2; // optional audio directory
|
||||
String VoiceDir2; // optional voice-over directory (base)
|
||||
String VoiceDirSub;// full voice-over directory with optional sub-dir
|
||||
};
|
||||
|
||||
// (Re-)Assign all known asset search paths to the AssetManager
|
||||
void engine_assign_assetpaths();
|
||||
|
||||
// Register a callback that will be called before engine is initialised.
|
||||
// Used for apps to register their own plugins and other configuration
|
||||
typedef void (*t_engine_pre_init_callback)(void);
|
||||
extern void engine_set_pre_init_callback(t_engine_pre_init_callback callback);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
211
engines/ags/engine/main/engine_setup.cpp
Normal file
211
engines/ags/engine/main/engine_setup.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/shared/core/platform.h"
|
||||
#include "ags/shared/ac/common.h"
|
||||
#include "ags/engine/ac/display.h"
|
||||
#include "ags/engine/ac/draw.h"
|
||||
#include "ags/engine/ac/game_setup.h"
|
||||
#include "ags/engine/ac/game_state.h"
|
||||
#include "ags/engine/ac/global_game.h"
|
||||
#include "ags/engine/ac/mouse.h"
|
||||
#include "ags/engine/ac/runtime_defines.h"
|
||||
#include "ags/engine/ac/walk_behind.h"
|
||||
#include "ags/engine/ac/dynobj/script_system.h"
|
||||
#include "ags/shared/debugging/out.h"
|
||||
#include "ags/engine/device/mouse_w32.h"
|
||||
#include "ags/shared/font/fonts.h"
|
||||
#include "ags/engine/gfx/graphics_driver.h"
|
||||
#include "ags/shared/gui/gui_main.h"
|
||||
#include "ags/shared/gui/gui_inv.h"
|
||||
#include "ags/engine/main/game_run.h"
|
||||
#include "ags/engine/main/graphics_mode.h"
|
||||
#include "ags/engine/main/engine_setup.h"
|
||||
#include "ags/engine/media/video/video.h"
|
||||
#include "ags/engine/platform/base/ags_platform_driver.h"
|
||||
#include "ags/engine/platform/base/sys_main.h"
|
||||
#include "ags/globals.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using namespace AGS::Shared;
|
||||
using namespace AGS::Engine;
|
||||
|
||||
|
||||
void engine_adjust_for_rotation_settings() {
|
||||
#if 0
|
||||
switch (_GP(usetup).rotation) {
|
||||
case ScreenRotation::kScreenRotation_Portrait:
|
||||
SDL_SetHint(SDL_HINT_ORIENTATIONS, "Portrait PortraitUpsideDown");
|
||||
break;
|
||||
case ScreenRotation::kScreenRotation_Landscape:
|
||||
SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeLeft LandscapeRight");
|
||||
break;
|
||||
case kScreenRotation_Unlocked:
|
||||
// let the user rotate as wished. No adjustment needed.
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Setup gfx driver callbacks and options
|
||||
void engine_post_gfxmode_driver_setup() {
|
||||
_G(gfxDriver)->SetCallbackForPolling(update_polled_stuff);
|
||||
_G(gfxDriver)->SetCallbackToDrawScreen(draw_game_screen_callback, construct_engine_overlay);
|
||||
_G(gfxDriver)->SetCallbackOnSpriteEvt(GfxDriverSpriteEvtCallback);
|
||||
}
|
||||
|
||||
// Reset gfx driver callbacks
|
||||
void engine_pre_gfxmode_driver_cleanup() {
|
||||
_G(gfxDriver)->SetCallbackForPolling(nullptr);
|
||||
_G(gfxDriver)->SetCallbackToDrawScreen(nullptr, nullptr);
|
||||
_G(gfxDriver)->SetCallbackOnSpriteEvt(nullptr);
|
||||
_G(gfxDriver)->SetMemoryBackBuffer(nullptr);
|
||||
}
|
||||
|
||||
// Setup color conversion parameters
|
||||
void engine_setup_color_conversions(int coldepth) {
|
||||
// default shifts for how we store the sprite data
|
||||
_G(_rgb_r_shift_32) = 16;
|
||||
_G(_rgb_g_shift_32) = 8;
|
||||
_G(_rgb_b_shift_32) = 0;
|
||||
_G(_rgb_r_shift_16) = 11;
|
||||
_G(_rgb_g_shift_16) = 5;
|
||||
_G(_rgb_b_shift_16) = 0;
|
||||
_G(_rgb_r_shift_15) = 10;
|
||||
_G(_rgb_g_shift_15) = 5;
|
||||
_G(_rgb_b_shift_15) = 0;
|
||||
|
||||
// TODO: investigate if this is still necessary, and under which circumstances?
|
||||
// the color conversion should likely be done when preparing textures or
|
||||
// rendering to final output instead, not in the main engine code.
|
||||
if (coldepth < 16) {
|
||||
// ensure that any 32-bit graphics displayed are converted
|
||||
// properly to the current depth
|
||||
#if AGS_PLATFORM_OS_WINDOWS
|
||||
_G(_rgb_r_shift_32) = 16;
|
||||
_G(_rgb_g_shift_32) = 8;
|
||||
_G(_rgb_b_shift_32) = 0;
|
||||
#else
|
||||
_G(_rgb_r_shift_32) = 0;
|
||||
_G(_rgb_g_shift_32) = 8;
|
||||
_G(_rgb_b_shift_32) = 16;
|
||||
|
||||
_G(_rgb_b_shift_15) = 0;
|
||||
_G(_rgb_g_shift_15) = 5;
|
||||
_G(_rgb_r_shift_15) = 10;
|
||||
#endif
|
||||
}
|
||||
|
||||
set_color_conversion(COLORCONV_MOST | COLORCONV_EXPAND_256);
|
||||
}
|
||||
|
||||
// Setup drawing modes and color conversions;
|
||||
// they depend primarily on gfx driver capabilities and new color depth
|
||||
void engine_post_gfxmode_draw_setup(const DisplayMode &dm) {
|
||||
engine_setup_color_conversions(dm.ColorDepth);
|
||||
init_draw_method();
|
||||
}
|
||||
|
||||
// Cleanup auxiliary drawing objects
|
||||
void engine_pre_gfxmode_draw_cleanup() {
|
||||
dispose_draw_method();
|
||||
}
|
||||
|
||||
// Setup mouse control mode and graphic area
|
||||
void engine_post_gfxmode_mouse_setup(const Size &init_desktop) {
|
||||
// Assign mouse control parameters.
|
||||
//
|
||||
// NOTE that we setup speed and other related properties regardless of
|
||||
// whether mouse control was requested because it may be enabled later.
|
||||
_GP(mouse).SetSpeedUnit(1.f);
|
||||
if (_GP(usetup).mouse_speed_def == kMouseSpeed_CurrentDisplay) {
|
||||
Size cur_desktop;
|
||||
if (sys_get_desktop_resolution(cur_desktop.Width, cur_desktop.Height) == 0)
|
||||
_GP(mouse).SetSpeedUnit(MAX((float)cur_desktop.Width / (float)init_desktop.Width,
|
||||
(float)cur_desktop.Height / (float)init_desktop.Height));
|
||||
}
|
||||
|
||||
Mouse_EnableControl(_GP(usetup).mouse_ctrl_enabled);
|
||||
Debug::Printf(kDbgMsg_Info, "Mouse speed control: %s, unit: %f, user value: %f",
|
||||
_GP(usetup).mouse_ctrl_enabled ? "enabled" : "disabled", _GP(mouse).GetSpeedUnit(), _GP(mouse).GetSpeed());
|
||||
|
||||
on_coordinates_scaling_changed();
|
||||
|
||||
// If auto lock option is set, lock mouse to the game window
|
||||
if (_GP(usetup).mouse_auto_lock && _GP(scsystem).windowed != 0)
|
||||
_GP(mouse).TryLockToWindow();
|
||||
}
|
||||
|
||||
// Reset mouse controls before changing gfx mode
|
||||
void engine_pre_gfxmode_mouse_cleanup() {
|
||||
// Always disable mouse control and unlock mouse when releasing down gfx mode
|
||||
_GP(mouse).SetMovementControl(false);
|
||||
_GP(mouse).UnlockFromWindow();
|
||||
}
|
||||
|
||||
// Fill in _GP(scsystem) struct with display mode parameters
|
||||
void engine_setup_scsystem_screen(const DisplayMode &dm) {
|
||||
_GP(scsystem).windowed = dm.IsWindowed();
|
||||
_GP(scsystem).vsync = dm.Vsync;
|
||||
}
|
||||
|
||||
void engine_post_gfxmode_setup(const Size &init_desktop, const DisplayMode &old_dm) {
|
||||
DisplayMode dm = _G(gfxDriver)->GetDisplayMode();
|
||||
// If color depth has changed (or graphics mode was inited for the
|
||||
// very first time), we also need to recreate bitmaps
|
||||
bool has_driver_changed = old_dm.ColorDepth != dm.ColorDepth;
|
||||
|
||||
engine_setup_scsystem_screen(dm);
|
||||
engine_post_gfxmode_driver_setup();
|
||||
if (has_driver_changed) {
|
||||
engine_post_gfxmode_draw_setup(dm);
|
||||
}
|
||||
engine_post_gfxmode_mouse_setup(init_desktop);
|
||||
|
||||
// reset multitasking (may be overridden by the current display mode)
|
||||
SetMultitasking(_GP(usetup).multitasking);
|
||||
|
||||
invalidate_screen();
|
||||
}
|
||||
|
||||
void engine_pre_gfxmode_release() {
|
||||
engine_pre_gfxmode_mouse_cleanup();
|
||||
engine_pre_gfxmode_driver_cleanup();
|
||||
}
|
||||
|
||||
void engine_pre_gfxsystem_shutdown() {
|
||||
engine_pre_gfxmode_release();
|
||||
engine_pre_gfxmode_draw_cleanup();
|
||||
}
|
||||
|
||||
void on_coordinates_scaling_changed() {
|
||||
// Reset mouse graphic area and bounds
|
||||
_GP(mouse).UpdateGraphicArea();
|
||||
// If mouse bounds do not have valid values yet, then limit cursor to viewport
|
||||
if (_GP(play).mboundx1 == 0 && _GP(play).mboundy1 == 0 && _GP(play).mboundx2 == 0 && _GP(play).mboundy2 == 0)
|
||||
_GP(mouse).SetMoveLimit(_GP(play).GetMainViewport());
|
||||
else
|
||||
_GP(mouse).SetMoveLimit(Rect(_GP(play).mboundx1, _GP(play).mboundy1, _GP(play).mboundx2, _GP(play).mboundy2));
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
43
engines/ags/engine/main/engine_setup.h
Normal file
43
engines/ags/engine/main/engine_setup.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_ENGINE_MAIN_ENGINE_SETUP_H
|
||||
#define AGS_ENGINE_MAIN_ENGINE_SETUP_H
|
||||
|
||||
#include "ags/shared/util/geometry.h"
|
||||
#include "ags/engine/gfx/gfx_defines.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
// Setup engine after the graphics mode has changed
|
||||
void engine_post_gfxmode_setup(const Size &init_desktop, const DisplayMode &old_dm);
|
||||
// Prepare engine for graphics mode release; could be called before switching display mode too
|
||||
void engine_pre_gfxmode_release();
|
||||
// Prepare engine to the graphics mode shutdown and gfx driver destruction
|
||||
void engine_pre_gfxsystem_shutdown();
|
||||
// Applies necessary changes after screen<->virtual coordinate transformation has changed
|
||||
void on_coordinates_scaling_changed();
|
||||
// prepares game screen for rotation setting
|
||||
void engine_adjust_for_rotation_settings();
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
220
engines/ags/engine/main/game_file.cpp
Normal file
220
engines/ags/engine/main/game_file.cpp
Normal file
@@ -0,0 +1,220 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
// Game data file management
|
||||
//
|
||||
|
||||
#include "ags/shared/ac/common.h"
|
||||
#include "ags/engine/ac/character.h"
|
||||
#include "ags/shared/ac/dialog_topic.h"
|
||||
#include "ags/engine/ac/draw.h"
|
||||
#include "ags/engine/ac/game.h"
|
||||
#include "ags/engine/ac/game_setup.h"
|
||||
#include "ags/shared/ac/game_setup_struct.h"
|
||||
#include "ags/shared/ac/game_struct_defines.h"
|
||||
#include "ags/engine/ac/gui.h"
|
||||
#include "ags/engine/ac/view_frame.h"
|
||||
#include "ags/shared/core/asset_manager.h"
|
||||
#include "ags/engine/debugging/debug_log.h"
|
||||
#include "ags/shared/debugging/out.h"
|
||||
#include "ags/engine/game/game_init.h"
|
||||
#include "ags/shared/game/main_game_file.h"
|
||||
#include "ags/shared/gfx/bitmap.h"
|
||||
#include "ags/engine/gfx/blender.h"
|
||||
#include "ags/shared/gui/gui_label.h"
|
||||
#include "ags/engine/main/main.h"
|
||||
#include "ags/engine/platform/base/ags_platform_driver.h"
|
||||
#include "ags/shared/script/cc_common.h"
|
||||
#include "ags/engine/script/script.h"
|
||||
#include "ags/shared/util/stream.h"
|
||||
#include "ags/shared/util/text_stream_reader.h"
|
||||
#include "ags/globals.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using namespace AGS::Shared;
|
||||
using namespace AGS::Engine;
|
||||
|
||||
// Test if engine supports extended capabilities required to run the game
|
||||
bool test_game_caps(const std::set<String> &caps, std::set<String> &failed_caps) {
|
||||
// Currently we support nothing special
|
||||
failed_caps = caps;
|
||||
return caps.size() == 0;
|
||||
}
|
||||
|
||||
// Forms a simple list of capability names
|
||||
String get_caps_list(const std::set<String> &caps) {
|
||||
String caps_list;
|
||||
for (std::set<String>::const_iterator it = caps.begin(); it != caps.end(); ++it) {
|
||||
caps_list.Append("\n\t");
|
||||
caps_list.Append(*it);
|
||||
}
|
||||
return caps_list;
|
||||
}
|
||||
|
||||
// Called when the game file is opened for the first time (when preloading game data);
|
||||
// it logs information on data version and reports first found errors, if any.
|
||||
HGameFileError game_file_first_open(MainGameSource &src) {
|
||||
HGameFileError err = OpenMainGameFileFromDefaultAsset(src, _G(AssetMgr)->get());
|
||||
if (err ||
|
||||
err->Code() == kMGFErr_SignatureFailed ||
|
||||
err->Code() == kMGFErr_FormatVersionTooOld ||
|
||||
err->Code() == kMGFErr_FormatVersionNotSupported) {
|
||||
// Log data description for debugging
|
||||
Debug::Printf(kDbgMsg_Info, "Opened game data file: %s", src.Filename.GetCStr());
|
||||
Debug::Printf(kDbgMsg_Info, "Game data version: %d", src.DataVersion);
|
||||
Debug::Printf(kDbgMsg_Info, "Compiled with: %s", src.CompiledWith.GetCStr());
|
||||
if (src.Caps.size() > 0) {
|
||||
String caps_list = get_caps_list(src.Caps);
|
||||
Debug::Printf(kDbgMsg_Info, "Requested engine caps: %s", caps_list.GetCStr());
|
||||
}
|
||||
}
|
||||
// Quit in case of error
|
||||
if (!err)
|
||||
return err;
|
||||
|
||||
// Test the extended caps
|
||||
std::set<String> failed_caps;
|
||||
if (!test_game_caps(src.Caps, failed_caps)) {
|
||||
String caps_list = get_caps_list(failed_caps);
|
||||
return new MainGameFileError(kMGFErr_CapsNotSupported, String::FromFormat("Missing engine caps: %s", caps_list.GetCStr()));
|
||||
}
|
||||
return HGameFileError::None();
|
||||
}
|
||||
|
||||
HError preload_game_data() {
|
||||
MainGameSource src;
|
||||
HGameFileError err = game_file_first_open(src);
|
||||
if (!err)
|
||||
return (HError)err;
|
||||
// Read only the particular data we need for preliminary game analysis
|
||||
PreReadGameData(_GP(game), src.InputStream.get(), src.DataVersion);
|
||||
_GP(game).compiled_with = src.CompiledWith;
|
||||
FixupSaveDirectory(_GP(game));
|
||||
return HError::None();
|
||||
}
|
||||
|
||||
static inline HError MakeScriptLoadError(const char *name) {
|
||||
return new Error(String::FromFormat(
|
||||
"Failed to load a script module: %s", name),
|
||||
cc_get_error().ErrorString);
|
||||
}
|
||||
|
||||
// Looks up for the game scripts available as separate assets.
|
||||
// These are optional, so no error is raised if some of these are not found.
|
||||
// For those that do exist, reads them and replaces any scripts of same kind
|
||||
// in the already loaded game data.
|
||||
HError LoadGameScripts(LoadedGameEntities &ents) {
|
||||
// Global script
|
||||
std::unique_ptr<Stream> in(_GP(AssetMgr)->OpenAsset("GlobalScript.o"));
|
||||
if (in) {
|
||||
PScript script(ccScript::CreateFromStream(in.get()));
|
||||
if (!script)
|
||||
return MakeScriptLoadError("GlobalScript.o");
|
||||
ents.GlobalScript = script;
|
||||
}
|
||||
// Dialog script
|
||||
in.reset(_GP(AssetMgr)->OpenAsset("DialogScript.o"));
|
||||
if (in) {
|
||||
PScript script(ccScript::CreateFromStream(in.get()));
|
||||
if (!script)
|
||||
return MakeScriptLoadError("DialogScript.o");
|
||||
ents.DialogScript = script;
|
||||
}
|
||||
// Script modules
|
||||
// First load a modules list
|
||||
std::vector<String> modules;
|
||||
in.reset(_GP(AssetMgr)->OpenAsset("ScriptModules.lst"));
|
||||
if (in) {
|
||||
TextStreamReader reader(in.get());
|
||||
in.release(); // TextStreamReader got it
|
||||
while (!reader.EOS())
|
||||
modules.push_back(reader.ReadLine());
|
||||
}
|
||||
if (modules.size() > ents.ScriptModules.size())
|
||||
ents.ScriptModules.resize(modules.size());
|
||||
// Now run by the list and try loading everything
|
||||
for (size_t i = 0; i < modules.size(); ++i) {
|
||||
in.reset(_GP(AssetMgr)->OpenAsset(modules[i]));
|
||||
if (in) {
|
||||
PScript script(ccScript::CreateFromStream(in.get()));
|
||||
if (!script)
|
||||
return MakeScriptLoadError(modules[i].GetCStr());
|
||||
ents.ScriptModules[i] = script;
|
||||
}
|
||||
}
|
||||
return HError::None();
|
||||
}
|
||||
|
||||
HError load_game_file() {
|
||||
MainGameSource src;
|
||||
LoadedGameEntities ents(_GP(game));
|
||||
HError err = (HError)OpenMainGameFileFromDefaultAsset(src, _GP(AssetMgr).get());
|
||||
if (!err)
|
||||
return err;
|
||||
|
||||
err = (HError)ReadGameData(ents, src.InputStream.get(), src.DataVersion);
|
||||
if (!err)
|
||||
return err;
|
||||
src.InputStream.reset();
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Data overrides: for compatibility mode and custom engine support
|
||||
// NOTE: this must be done before UpdateGameData, or certain adjustments
|
||||
// won't be applied correctly.
|
||||
|
||||
// Custom engine detection (ugly hack, depends on the known game GUIDs)
|
||||
if (strcmp(_GP(game).guid, "{d6795d1c-3cfe-49ec-90a1-85c313bfccaf}" /* Kathy Rain */ ) == 0 ||
|
||||
strcmp(_GP(game).guid, "{5833654f-6f0d-40d9-99e2-65c101c8544a}" /* Whispers of a Machine */ ) == 0)
|
||||
{
|
||||
_GP(game).options[OPT_CUSTOMENGINETAG] = CUSTOMENG_CLIFFTOP;
|
||||
}
|
||||
// Upscale mode -- for old games that supported it.
|
||||
if ((_G(loaded_game_file_version) < kGameVersion_310) && _GP(usetup).override_upscale) {
|
||||
if (_GP(game).GetResolutionType() == kGameResolution_320x200 || _GP(game).GetResolutionType() == kGameResolution_Default)
|
||||
_GP(game).SetGameResolution(kGameResolution_640x400);
|
||||
else if (_GP(game).GetResolutionType() == kGameResolution_320x240)
|
||||
_GP(game).SetGameResolution(kGameResolution_640x480);
|
||||
}
|
||||
if (_GP(game).options[OPT_CUSTOMENGINETAG] == CUSTOMENG_CLIFFTOP) {
|
||||
if (_GP(game).GetResolutionType() == kGameResolution_640x400)
|
||||
_GP(game).SetGameResolution(Size(640, 360));
|
||||
}
|
||||
|
||||
err = (HError)UpdateGameData(ents, src.DataVersion);
|
||||
if (!err)
|
||||
return err;
|
||||
err = LoadGameScripts(ents);
|
||||
if (!err)
|
||||
return err;
|
||||
err = (HError)InitGameState(ents, src.DataVersion);
|
||||
if (!err)
|
||||
return err;
|
||||
return HError::None();
|
||||
}
|
||||
|
||||
void display_game_file_error(HError err) {
|
||||
_G(platform)->DisplayAlert("Loading game failed with error:\n%s.\n\nThe game files may be incomplete, corrupt or from unsupported version of AGS.",
|
||||
err->FullMessage().GetCStr());
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
40
engines/ags/engine/main/game_file.h
Normal file
40
engines/ags/engine/main/game_file.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_ENGINE_MAIN_GAME_FILE_H
|
||||
#define AGS_ENGINE_MAIN_GAME_FILE_H
|
||||
|
||||
#include "ags/shared/util/error.h"
|
||||
#include "ags/shared/util/string.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using AGS::Shared::HError;
|
||||
|
||||
// Preload particular game-describing parameters from the game data header (title, save game dir name, etc)
|
||||
HError preload_game_data();
|
||||
// Loads game data and reinitializes the game state; assigns error message in case of failure
|
||||
HError load_game_file();
|
||||
void display_game_file_error(HError err);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
1147
engines/ags/engine/main/game_run.cpp
Normal file
1147
engines/ags/engine/main/game_run.cpp
Normal file
File diff suppressed because it is too large
Load Diff
79
engines/ags/engine/main/game_run.h
Normal file
79
engines/ags/engine/main/game_run.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_ENGINE_MAIN_GAME_RUN_H
|
||||
#define AGS_ENGINE_MAIN_GAME_RUN_H
|
||||
|
||||
#include "ags/shared/ac/keycode.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
namespace AGS {
|
||||
namespace Engine {
|
||||
class IDriverDependantBitmap;
|
||||
}
|
||||
}
|
||||
using namespace AGS::Engine; // FIXME later
|
||||
|
||||
// Loops game frames until certain event takes place (for blocking actions)
|
||||
void GameLoopUntilValueIsZero(const int8 *value);
|
||||
void GameLoopUntilValueIsZero(const short *value);
|
||||
void GameLoopUntilValueIsZero(const int *value);
|
||||
void GameLoopUntilValueIsZeroOrLess(const short *move);
|
||||
void GameLoopUntilValueIsNegative(const short *value);
|
||||
void GameLoopUntilValueIsNegative(const int *value);
|
||||
void GameLoopUntilNotMoving(const short *move);
|
||||
void GameLoopUntilNoOverlay();
|
||||
void GameLoopUntilButAnimEnd(int guin, int objn);
|
||||
|
||||
// Run the actual game until it ends, or aborted by player/error; loops GameTick() internally
|
||||
void RunGameUntilAborted();
|
||||
// Update everything game related; wait for the next frame
|
||||
void UpdateGameOnce(bool checkControls = false, IDriverDependantBitmap *extraBitmap = nullptr, int extraX = 0, int extraY = 0);
|
||||
// Update minimal required game state: audio, loop counter, etc; wait for the next frame
|
||||
void UpdateGameAudioOnly();
|
||||
// Updates everything related to object views that could have changed in the midst of a
|
||||
// blocking script, cursor position and view, poll anything related to cursor position;
|
||||
// this function is useful when you don't want to update whole game, but only things
|
||||
// that are necessary for rendering the game screen.
|
||||
void UpdateCursorAndDrawables();
|
||||
// Syncs object drawable states with their logical states.
|
||||
// Useful after a major game state change, such as loading new room, in case we expect
|
||||
// that a render may occur before a normal game update is performed.
|
||||
void SyncDrawablesState();
|
||||
// Gets current logical game FPS, this is normally a fixed number set in script;
|
||||
// in case of "maxed fps" mode this function returns real measured FPS.
|
||||
float get_game_fps();
|
||||
// Gets real fps, calculated based on the game performance.
|
||||
float get_real_fps();
|
||||
// Runs service key controls, returns false if no key was pressed or key input was claimed by the engine,
|
||||
// otherwise returns true and provides a keycode.
|
||||
bool run_service_key_controls(KeyInput &kgn);
|
||||
// Runs service mouse controls, returns false if mouse input was claimed by the engine,
|
||||
// otherwise returns true and provides mouse button code.
|
||||
bool run_service_mb_controls(eAGSMouseButton &mbut, int &mwheelz);
|
||||
// Polls few things (exit flag and debugger messages)
|
||||
// TODO: refactor this
|
||||
void update_polled_stuff();
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
138
engines/ags/engine/main/game_start.cpp
Normal file
138
engines/ags/engine/main/game_start.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
// Game initialization
|
||||
//
|
||||
|
||||
#include "ags/shared/ac/common.h"
|
||||
#include "ags/shared/ac/character_info.h"
|
||||
#include "ags/engine/ac/game.h"
|
||||
#include "ags/engine/ac/game_setup.h"
|
||||
#include "ags/shared/ac/game_setup_struct.h"
|
||||
#include "ags/engine/ac/game_setup.h"
|
||||
#include "ags/engine/ac/game_state.h"
|
||||
#include "ags/engine/ac/global_game.h"
|
||||
#include "ags/engine/ac/mouse.h"
|
||||
#include "ags/engine/ac/room.h"
|
||||
#include "ags/engine/ac/screen.h"
|
||||
#include "ags/engine/ac/timer.h"
|
||||
#include "ags/engine/debugging/debug_log.h"
|
||||
#include "ags/engine/debugging/debugger.h"
|
||||
#include "ags/shared/debugging/out.h"
|
||||
#include "ags/engine/device/mouse_w32.h"
|
||||
#include "ags/engine/main/game_run.h"
|
||||
#include "ags/engine/main/game_start.h"
|
||||
#include "ags/engine/media/audio/audio_system.h"
|
||||
#include "ags/engine/script/script_runtime.h"
|
||||
#include "ags/engine/script/script.h"
|
||||
#include "ags/ags.h"
|
||||
#include "ags/globals.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using namespace AGS::Shared;
|
||||
using namespace AGS::Engine;
|
||||
|
||||
void start_game_init_editor_debugging() {
|
||||
Debug::Printf(kDbgMsg_Info, "Try connect to the external debugger");
|
||||
if (!init_editor_debugging())
|
||||
return;
|
||||
|
||||
// Debugger expects strict multitasking
|
||||
_GP(usetup).multitasking = true;
|
||||
_GP(usetup).override_multitasking = -1;
|
||||
SetMultitasking(1);
|
||||
|
||||
auto waitUntil = AGS_Clock::now() + std::chrono::milliseconds(500);
|
||||
while (waitUntil > AGS_Clock::now()) {
|
||||
// pick up any breakpoints in game_start
|
||||
check_for_messages_from_debugger();
|
||||
}
|
||||
|
||||
ccSetDebugHook(scriptDebugHook);
|
||||
}
|
||||
|
||||
static void start_game_load_savegame_on_startup(int loadSave) {
|
||||
if (loadSave != -1) {
|
||||
current_fade_out_effect();
|
||||
try_restore_save(loadSave);
|
||||
}
|
||||
}
|
||||
|
||||
void start_game() {
|
||||
set_room_placeholder();
|
||||
set_cursor_mode(MODE_WALK);
|
||||
_GP(mouse).SetPosition(Point(160, 100));
|
||||
newmusic(0);
|
||||
|
||||
set_our_eip(-42);
|
||||
|
||||
// skip ticks to account for initialisation or a restored game.
|
||||
skipMissedTicks();
|
||||
|
||||
RunScriptFunctionInModules("game_start");
|
||||
|
||||
set_our_eip(-43);
|
||||
|
||||
// Only auto-set first restart point in < 3.6.1 games,
|
||||
// since 3.6.1+ users are suggested to set one manually in script.
|
||||
if (_G(loaded_game_file_version) < kGameVersion_361_10)
|
||||
SetRestartPoint();
|
||||
|
||||
set_our_eip(-3);
|
||||
|
||||
if (_G(displayed_room) < 0) {
|
||||
current_fade_out_effect();
|
||||
load_new_room(_G(playerchar)->room, _G(playerchar));
|
||||
}
|
||||
|
||||
first_room_initialization();
|
||||
}
|
||||
|
||||
void initialize_start_and_play_game(int override_start_room, int loadSave) {
|
||||
//try { // BEGIN try for ALI3DEXception
|
||||
|
||||
set_cursor_mode(MODE_WALK);
|
||||
|
||||
if (override_start_room)
|
||||
_G(playerchar)->room = override_start_room;
|
||||
|
||||
Debug::Printf(kDbgMsg_Info, "Engine initialization complete");
|
||||
Debug::Printf(kDbgMsg_Info, "Starting game");
|
||||
|
||||
if (_G(editor_debugging_enabled))
|
||||
start_game_init_editor_debugging();
|
||||
|
||||
start_game_load_savegame_on_startup(loadSave);
|
||||
|
||||
// only start if not restored a save
|
||||
if (_G(displayed_room) < 0)
|
||||
start_game();
|
||||
|
||||
RunGameUntilAborted();
|
||||
|
||||
/*} catch (Ali3DException gfxException) {
|
||||
quit(gfxException.Message.GetCStr());
|
||||
}*/
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
32
engines/ags/engine/main/game_start.h
Normal file
32
engines/ags/engine/main/game_start.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_ENGINE_MAIN_GAME_START_H
|
||||
#define AGS_ENGINE_MAIN_GAME_START_H
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
extern void start_game();
|
||||
extern void initialize_start_and_play_game(int override_start_room, int loadSave);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
562
engines/ags/engine/main/graphics_mode.cpp
Normal file
562
engines/ags/engine/main/graphics_mode.cpp
Normal file
@@ -0,0 +1,562 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
// Graphics initialization
|
||||
//
|
||||
|
||||
#include "common/std/algorithm.h"
|
||||
#include "ags/shared/core/platform.h"
|
||||
#include "ags/engine/ac/draw.h"
|
||||
#include "ags/engine/debugging/debugger.h"
|
||||
#include "ags/shared/debugging/out.h"
|
||||
#include "ags/shared/gfx/bitmap.h"
|
||||
#include "ags/engine/gfx/gfx_driver_factory.h"
|
||||
#include "ags/engine/gfx/gfxfilter.h"
|
||||
#include "ags/engine/gfx/graphics_driver.h"
|
||||
#include "ags/engine/main/config.h"
|
||||
#include "ags/engine/main/engine_setup.h"
|
||||
#include "ags/engine/main/graphics_mode.h"
|
||||
#include "ags/engine/platform/base/ags_platform_driver.h"
|
||||
#include "ags/engine/platform/base/sys_main.h"
|
||||
#include "ags/globals.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
// Don't try to figure out the window size on the mac because the port resizes itself.
|
||||
#if AGS_PLATFORM_OS_MACOS || defined(ALLEGRO_SDL2) || AGS_PLATFORM_MOBILE
|
||||
#define USE_SIMPLE_GFX_INIT
|
||||
#endif
|
||||
|
||||
using namespace AGS::Shared;
|
||||
using namespace AGS::Engine;
|
||||
|
||||
Size get_desktop_size() {
|
||||
Size sz;
|
||||
sys_get_desktop_resolution(sz.Width, sz.Height);
|
||||
return sz;
|
||||
}
|
||||
|
||||
Size get_max_display_size(bool windowed) {
|
||||
Size device_size = get_desktop_size();
|
||||
if (windowed)
|
||||
device_size = _G(platform)->ValidateWindowSize(device_size, false);
|
||||
return device_size;
|
||||
}
|
||||
|
||||
bool create_gfx_driver(const String &gfx_driver_id) {
|
||||
_G(GfxFactory) = GetGfxDriverFactory(gfx_driver_id);
|
||||
if (!_G(GfxFactory)) {
|
||||
Debug::Printf(kDbgMsg_Error, "Failed to initialize %s graphics factory", gfx_driver_id.GetCStr());
|
||||
return false;
|
||||
}
|
||||
Debug::Printf("Using graphics factory: %s", gfx_driver_id.GetCStr());
|
||||
_G(gfxDriver) = _G(GfxFactory)->GetDriver();
|
||||
if (!_G(gfxDriver)) {
|
||||
Debug::Printf(kDbgMsg_Error, "Failed to create graphics driver");
|
||||
return false;
|
||||
}
|
||||
Debug::Printf("Created graphics driver: %s", _G(gfxDriver)->GetDriverName());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Set requested graphics filter, or default filter if the requested one failed
|
||||
bool graphics_mode_set_filter_any(const GfxFilterSetup &setup) {
|
||||
Debug::Printf("Requested gfx filter: %s", setup.UserRequest.GetCStr());
|
||||
if (!graphics_mode_set_filter(setup.ID)) {
|
||||
String def_filter = _G(GfxFactory)->GetDefaultFilterID();
|
||||
if (def_filter.CompareNoCase(setup.ID) == 0)
|
||||
return false;
|
||||
Debug::Printf(kDbgMsg_Error, "Failed to apply gfx filter: %s; will try to use factory default filter '%s' instead",
|
||||
setup.UserRequest.GetCStr(), def_filter.GetCStr());
|
||||
if (!graphics_mode_set_filter(def_filter))
|
||||
return false;
|
||||
}
|
||||
Debug::Printf("Using gfx filter: %s", _G(GfxFactory)->GetDriver()->GetGraphicsFilter()->GetInfo().Id.GetCStr());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool find_nearest_supported_mode(const IGfxModeList &modes, const Size &wanted_size, const int color_depth,
|
||||
const Size *ratio_reference, const Size *upper_bound, DisplayMode &dm, int *mode_index) {
|
||||
uint32_t wanted_ratio = 0;
|
||||
if (ratio_reference && !ratio_reference->IsNull()) {
|
||||
wanted_ratio = (ratio_reference->Height << kShift) / ratio_reference->Width;
|
||||
}
|
||||
|
||||
int nearest_width = 0;
|
||||
int nearest_height = 0;
|
||||
int nearest_width_diff = 0;
|
||||
int nearest_height_diff = 0;
|
||||
DisplayMode nearest_mode;
|
||||
int nearest_mode_index = -1;
|
||||
int mode_count = modes.GetModeCount();
|
||||
for (int i = 0; i < mode_count; ++i) {
|
||||
DisplayMode mode;
|
||||
if (!modes.GetMode(i, mode)) {
|
||||
continue;
|
||||
}
|
||||
if (wanted_ratio > 0) {
|
||||
uint32_t mode_ratio = (mode.Height << kShift) / mode.Width;
|
||||
if (mode_ratio != wanted_ratio) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (upper_bound && (mode.Width > upper_bound->Width || mode.Height > upper_bound->Height))
|
||||
continue;
|
||||
if (mode.Width == wanted_size.Width && mode.Height == wanted_size.Height) {
|
||||
nearest_width = mode.Width;
|
||||
nearest_height = mode.Height;
|
||||
nearest_mode_index = i;
|
||||
nearest_mode = mode;
|
||||
break;
|
||||
}
|
||||
|
||||
int diff_w = abs(wanted_size.Width - mode.Width);
|
||||
int diff_h = abs(wanted_size.Height - mode.Height);
|
||||
bool same_diff_w_higher = (diff_w == nearest_width_diff && nearest_width < wanted_size.Width);
|
||||
bool same_diff_h_higher = (diff_h == nearest_height_diff && nearest_height < wanted_size.Height);
|
||||
|
||||
if (nearest_width == 0 ||
|
||||
((diff_w < nearest_width_diff || same_diff_w_higher) && diff_h <= nearest_height_diff) ||
|
||||
((diff_h < nearest_height_diff || same_diff_h_higher) && diff_w <= nearest_width_diff)) {
|
||||
nearest_width = mode.Width;
|
||||
nearest_width_diff = diff_w;
|
||||
nearest_height = mode.Height;
|
||||
nearest_height_diff = diff_h;
|
||||
nearest_mode = mode;
|
||||
nearest_mode_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (nearest_width > 0 && nearest_height > 0) {
|
||||
dm = nearest_mode;
|
||||
if (mode_index)
|
||||
*mode_index = nearest_mode_index;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Size get_game_frame_from_screen_size(const Size &game_size, const Size screen_size,
|
||||
const FrameScaleDef frame, int scale = 0) {
|
||||
// Set game frame as native game resolution scaled by particular method
|
||||
switch (frame) {
|
||||
case kFrame_Stretch: return screen_size;
|
||||
case kFrame_Proportional: return ProportionalStretch(screen_size, game_size);
|
||||
case kFrame_Round: {
|
||||
int fp_scale;
|
||||
if (scale > 0)
|
||||
fp_scale = convert_scaling_to_fp(scale);
|
||||
else
|
||||
fp_scale = MAX<int32_t>(kUnit,
|
||||
MIN((screen_size.Width / game_size.Width) << kShift,
|
||||
(screen_size.Height / game_size.Height) << kShift));
|
||||
Size frame_size = Size(
|
||||
(game_size.Width * fp_scale) >> kShift,
|
||||
(game_size.Height * fp_scale) >> kShift);
|
||||
// If the scaled game size appear larger than the screen,
|
||||
// use "proportional stretch" method instead
|
||||
if (frame_size.ExceedsByAny(screen_size))
|
||||
frame_size = ProportionalStretch(screen_size, game_size);
|
||||
return frame_size;
|
||||
}
|
||||
default:
|
||||
return Size();
|
||||
}
|
||||
}
|
||||
|
||||
static Size precalc_screen_size(const Size &game_size, const WindowSetup &ws, const FrameScaleDef frame) {
|
||||
#if AGS_PLATFORM_SCUMMVM
|
||||
return game_size;
|
||||
#else
|
||||
const bool windowed = ws.Mode == kWnd_Windowed;
|
||||
// Set requested screen (window) size, depending on screen definition option
|
||||
if (!ws.Size.IsNull()) {
|
||||
// Use explicit resolution from user config
|
||||
return ws.Size;
|
||||
} else if (ws.Scale > 0) {
|
||||
return get_game_frame_from_screen_size(game_size, get_max_display_size(windowed), frame, ws.Scale);
|
||||
}
|
||||
// If nothing is set, then for the fullscreen mode set as big as current device/desktop size;
|
||||
// for the windowed mode assume maximal size inside desktop using given frame scaling
|
||||
if (windowed)
|
||||
return get_game_frame_from_screen_size(game_size, get_max_display_size(windowed), frame);
|
||||
return get_max_display_size(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Find closest possible compatible display mode and initialize it
|
||||
bool try_init_compatible_mode(const DisplayMode &dm) {
|
||||
const Size &screen_size = Size(dm.Width, dm.Height);
|
||||
// Find nearest compatible mode and init that
|
||||
Debug::Printf("Attempt to find nearest supported resolution for screen size %d x %d (%d-bit) %s, on display %d",
|
||||
dm.Width, dm.Height, dm.ColorDepth, dm.IsWindowed() ? "windowed" : "fullscreen", sys_get_window_display_index());
|
||||
const Size device_size = get_max_display_size(dm.IsWindowed());
|
||||
if (dm.IsWindowed())
|
||||
Debug::Printf("Maximal allowed window size: %d x %d", device_size.Width, device_size.Height);
|
||||
DisplayMode dm_compat = dm;
|
||||
|
||||
std::unique_ptr<IGfxModeList> modes(_G(gfxDriver)->GetSupportedModeList(dm.ColorDepth));
|
||||
|
||||
// Windowed mode
|
||||
if (dm.IsWindowed()) {
|
||||
// If windowed mode, make the resolution stay in the generally supported limits
|
||||
dm_compat.Width = MIN(dm_compat.Width, device_size.Width);
|
||||
dm_compat.Height = MIN(dm_compat.Height, device_size.Height);
|
||||
}
|
||||
// Fullscreen mode
|
||||
else {
|
||||
// Try to find any compatible mode from the list of available ones
|
||||
bool mode_found = false;
|
||||
if (modes.get())
|
||||
mode_found = find_nearest_supported_mode(*modes.get(), screen_size, dm.ColorDepth, nullptr, nullptr, dm_compat);
|
||||
if (!mode_found)
|
||||
Debug::Printf("Could not find compatible fullscreen mode. Will try to force-set mode requested by user and fallback to windowed mode if that fails.");
|
||||
dm_compat.Vsync = dm.Vsync;
|
||||
dm_compat.Mode = dm.Mode;
|
||||
}
|
||||
|
||||
bool result = graphics_mode_set_dm(dm_compat);
|
||||
if (!result && dm.IsWindowed()) {
|
||||
// When initializing windowed mode we could start with any random window size;
|
||||
// if that did not work, try to find nearest supported mode, as with fullscreen mode,
|
||||
// except referring to max window size as an upper bound
|
||||
if (find_nearest_supported_mode(*modes.get(), screen_size, dm.ColorDepth, nullptr, &device_size, dm_compat)) {
|
||||
dm_compat.Vsync = dm.Vsync;
|
||||
dm_compat.Mode = kWnd_Windowed;
|
||||
result = graphics_mode_set_dm(dm_compat);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Try to find and initialize compatible display mode as close to given setup as possible
|
||||
static bool try_init_mode_using_setup(const GraphicResolution &game_res, const WindowSetup &ws,
|
||||
const int col_depth, const FrameScaleDef frame,
|
||||
const GfxFilterSetup &filter, const DisplaySetupEx ¶ms) {
|
||||
// We determine the requested size of the screen using setup options
|
||||
const Size screen_size = precalc_screen_size(game_res, ws, frame);
|
||||
DisplayMode dm(GraphicResolution(screen_size.Width, screen_size.Height, col_depth),
|
||||
ws.Mode, params.RefreshRate, params.VSync);
|
||||
if (!try_init_compatible_mode(dm))
|
||||
return false;
|
||||
|
||||
// Set up native size and render frame
|
||||
if (!graphics_mode_set_native_res(game_res) || !graphics_mode_set_render_frame(frame))
|
||||
return false;
|
||||
|
||||
// Set up graphics filter
|
||||
if (!graphics_mode_set_filter_any(filter))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void log_out_driver_modes(const int color_depth) {
|
||||
IGfxModeList *modes = _G(gfxDriver)->GetSupportedModeList(color_depth);
|
||||
if (!modes) {
|
||||
Debug::Printf(kDbgMsg_Error, "Couldn't get a list of supported resolutions for color depth = %d", color_depth);
|
||||
return;
|
||||
}
|
||||
const int mode_count = modes->GetModeCount();
|
||||
DisplayMode mode;
|
||||
String mode_str;
|
||||
for (int i = 0, in_str = 0; i < mode_count; ++i) {
|
||||
modes->GetMode(i, mode);
|
||||
mode_str.Append(String::FromFormat("%dx%d;", mode.Width, mode.Height));
|
||||
if (++in_str % 8 == 0)
|
||||
mode_str.Append("\n\t");
|
||||
}
|
||||
delete modes;
|
||||
|
||||
String out_str = String::FromFormat("Supported gfx modes (%d-bit): ", color_depth);
|
||||
if (!mode_str.IsEmpty()) {
|
||||
out_str.Append("\n\t");
|
||||
out_str.Append(mode_str);
|
||||
} else
|
||||
out_str.Append("none");
|
||||
Debug::Printf(out_str);
|
||||
}
|
||||
|
||||
// Create requested graphics driver and try to find and initialize compatible display mode as close to user setup as possible;
|
||||
// if the given setup fails, gets default setup for the opposite type of mode (fullscreen/windowed) and tries that instead.
|
||||
bool create_gfx_driver_and_init_mode_any(const String &gfx_driver_id,
|
||||
const GraphicResolution &game_res,
|
||||
const DisplayModeSetup &setup, const ColorDepthOption &color_depth) {
|
||||
if (!graphics_mode_create_renderer(gfx_driver_id))
|
||||
return false;
|
||||
|
||||
const int use_col_depth =
|
||||
color_depth.Forced ? color_depth.Bits : _G(gfxDriver)->GetDisplayDepthForNativeDepth(color_depth.Bits);
|
||||
// Log out supported driver modes
|
||||
log_out_driver_modes(use_col_depth);
|
||||
|
||||
bool windowed = setup.Windowed;
|
||||
WindowSetup ws = windowed ? setup.WinSetup : setup.FsSetup;
|
||||
FrameScaleDef frame = windowed ? setup.WinGameFrame : setup.FsGameFrame;
|
||||
bool result = try_init_mode_using_setup(game_res, ws, use_col_depth, frame, setup.Filter, setup.Params);
|
||||
// Try windowed mode if fullscreen failed, and vice versa
|
||||
if (!result && _G(editor_debugging_enabled) == 0) {
|
||||
windowed = !windowed;
|
||||
ws = windowed ? setup.WinSetup : setup.FsSetup;
|
||||
frame = windowed ? setup.WinGameFrame : setup.FsGameFrame;
|
||||
result = try_init_mode_using_setup(game_res, ws, use_col_depth, frame, setup.Filter, setup.Params);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef USE_SIMPLE_GFX_INIT
|
||||
static bool simple_create_gfx_driver_and_init_mode(const String &gfx_driver_id,
|
||||
const GraphicResolution &game_res, const DisplayModeSetup &setup,
|
||||
const ColorDepthOption &color_depth) {
|
||||
if (!graphics_mode_create_renderer(gfx_driver_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int col_depth = _G(gfxDriver)->GetDisplayDepthForNativeDepth(color_depth.Bits);
|
||||
const WindowSetup ws = setup.Windowed ? setup.WinSetup : setup.FsSetup;
|
||||
const FrameScaleDef frame = setup.Windowed ? setup.WinGameFrame : setup.FsGameFrame;
|
||||
|
||||
DisplayMode dm(GraphicResolution(game_res.Width, game_res.Height, col_depth),
|
||||
ws.Mode, setup.Params.RefreshRate, setup.Params.VSync);
|
||||
|
||||
if (!graphics_mode_set_dm(dm)) {
|
||||
return false;
|
||||
}
|
||||
if (!graphics_mode_set_native_res(dm)) {
|
||||
return false;
|
||||
}
|
||||
if (!graphics_mode_set_render_frame(frame)) {
|
||||
return false;
|
||||
}
|
||||
if (!graphics_mode_set_filter_any(setup.Filter)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void display_gfx_mode_error(const Size &game_size, const WindowSetup &ws, const int color_depth,
|
||||
const GfxFilterSetup &filter_setup) {
|
||||
_G(proper_exit) = 1;
|
||||
|
||||
String main_error;
|
||||
PGfxFilter filter = _G(gfxDriver) ? _G(gfxDriver)->GetGraphicsFilter() : PGfxFilter();
|
||||
Size wanted_screen;
|
||||
if (!ws.Size.IsNull())
|
||||
main_error.Format("There was a problem initializing graphics mode %d x %d (%d-bit), or finding nearest compatible mode, with game size %d x %d and filter '%s'.",
|
||||
ws.Size.Width, ws.Size.Height, color_depth, game_size.Width, game_size.Height, filter ? filter->GetInfo().Id.GetCStr() : "Undefined");
|
||||
else
|
||||
main_error.Format("There was a problem finding and/or creating valid graphics mode for game size %d x %d (%d-bit) and requested filter '%s'.",
|
||||
game_size.Width, game_size.Height, color_depth, filter_setup.UserRequest.IsEmpty() ? "Undefined" : filter_setup.UserRequest.GetCStr());
|
||||
|
||||
_G(platform)->DisplayAlert("%s\n"
|
||||
"%s",
|
||||
main_error.GetCStr(), _G(platform)->GetGraphicsTroubleshootingText());
|
||||
}
|
||||
|
||||
bool graphics_mode_init_any(const GraphicResolution &game_res, const DisplayModeSetup &setup, const ColorDepthOption &color_depth) {
|
||||
// Log out display information
|
||||
Size device_size;
|
||||
if (sys_get_desktop_resolution(device_size.Width, device_size.Height) == 0)
|
||||
Debug::Printf("Device display resolution: %d x %d", device_size.Width, device_size.Height);
|
||||
else
|
||||
Debug::Printf(kDbgMsg_Error, "Unable to obtain device resolution");
|
||||
|
||||
WindowSetup ws = setup.Windowed ? setup.WinSetup : setup.FsSetup;
|
||||
FrameScaleDef gameframe = setup.Windowed ? setup.WinGameFrame : setup.FsGameFrame;
|
||||
const String scale_option = make_scaling_option(gameframe);
|
||||
Debug::Printf(kDbgMsg_Info, "Graphic settings: driver: %s, windowed: %s, screen size: %d x %d, game scale: %s",
|
||||
setup.DriverID.GetCStr(),
|
||||
setup.Windowed ? "yes" : "no",
|
||||
ws.Size.Width, ws.Size.Height,
|
||||
scale_option.GetCStr());
|
||||
Debug::Printf(kDbgMsg_Info, "Graphic settings: refresh rate (optional): %d, vsync: %d",
|
||||
setup.Params.RefreshRate, setup.Params.VSync);
|
||||
// Prepare the list of available gfx factories, having the one requested by user at first place
|
||||
// TODO: make factory & driver IDs case-insensitive!
|
||||
StringV ids;
|
||||
GetGfxDriverFactoryNames(ids);
|
||||
StringV::iterator it = ids.begin();
|
||||
for (; it != ids.end(); ++it) {
|
||||
if (it->CompareNoCase(setup.DriverID) == 0) break;
|
||||
}
|
||||
if (it != ids.end())
|
||||
ids.rotate(it);
|
||||
else
|
||||
Debug::Printf(kDbgMsg_Error, "Requested graphics driver '%s' not found, will try existing drivers instead", setup.DriverID.GetCStr());
|
||||
|
||||
// Try to create renderer and init gfx mode, choosing one factory at a time
|
||||
bool result = false;
|
||||
for (const auto &id : ids) {
|
||||
result =
|
||||
#ifdef USE_SIMPLE_GFX_INIT
|
||||
simple_create_gfx_driver_and_init_mode(id, game_res, setup, color_depth);
|
||||
#else
|
||||
create_gfx_driver_and_init_mode_any(id, game_res, setup, color_depth);
|
||||
#endif
|
||||
|
||||
if (result)
|
||||
break;
|
||||
graphics_mode_shutdown();
|
||||
}
|
||||
|
||||
// If all possibilities failed, display error message and quit
|
||||
if (!result) {
|
||||
display_gfx_mode_error(game_res, ws, color_depth.Bits, setup.Filter);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ActiveDisplaySetting graphics_mode_get_last_setting(bool windowed) {
|
||||
return windowed ? _GP(SavedWindowedSetting) : _GP(SavedFullscreenSetting);
|
||||
}
|
||||
|
||||
bool graphics_mode_create_renderer(const String &driver_id) {
|
||||
if (!create_gfx_driver(driver_id))
|
||||
return false;
|
||||
|
||||
_G(gfxDriver)->SetCallbackOnInit(GfxDriverOnInitCallback);
|
||||
// TODO: this is remains of the old code; find out if this is really
|
||||
// the best time and place to set the tint method
|
||||
_G(gfxDriver)->SetTintMethod(TintReColourise);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool graphics_mode_set_dm_any(const Size &game_size, const WindowSetup &ws,
|
||||
const ColorDepthOption &color_depth, const FrameScaleDef frame,
|
||||
const DisplaySetupEx ¶ms) {
|
||||
// We determine the requested size of the screen using setup options
|
||||
const Size screen_size = precalc_screen_size(game_size, ws, frame);
|
||||
DisplayMode dm(GraphicResolution(screen_size.Width, screen_size.Height, color_depth.Bits),
|
||||
ws.Mode, params.RefreshRate, params.VSync);
|
||||
return try_init_compatible_mode(dm);
|
||||
}
|
||||
|
||||
bool graphics_mode_set_dm(const DisplayMode &dm) {
|
||||
Debug::Printf("Attempt to switch gfx mode to %d x %d (%d-bit) %s, on display %d",
|
||||
dm.Width, dm.Height, dm.ColorDepth, dm.IsWindowed() ? "windowed" : "fullscreen", sys_get_window_display_index());
|
||||
|
||||
// Tell Allegro new default bitmap color depth (must be done before set_gfx_mode)
|
||||
// TODO: this is also done inside ALSoftwareGraphicsDriver implementation; can remove one?
|
||||
set_color_depth(dm.ColorDepth);
|
||||
|
||||
if (!_G(gfxDriver)->SetDisplayMode(dm)) {
|
||||
Debug::Printf(kDbgMsg_Error, "Failed to init gfx mode");
|
||||
return false;
|
||||
}
|
||||
|
||||
DisplayMode rdm = _G(gfxDriver)->GetDisplayMode();
|
||||
ActiveDisplaySetting &setting = rdm.IsWindowed() ? _GP(SavedWindowedSetting) : _GP(SavedFullscreenSetting);
|
||||
setting.Dm = rdm;
|
||||
setting.DisplayIndex = sys_get_window_display_index();
|
||||
Debug::Printf(kDbgMsg_Info, "Graphics driver set: %s", _G(gfxDriver)->GetDriverName());
|
||||
Debug::Printf(kDbgMsg_Info, "Graphics mode set: %d x %d (%d-bit) %s, on display %d",
|
||||
rdm.Width, rdm.Height, rdm.ColorDepth,
|
||||
rdm.IsWindowed() ? "windowed" : (rdm.IsRealFullscreen() ? "fullscreen" : "fullscreen desktop"), setting.DisplayIndex);
|
||||
Debug::Printf(kDbgMsg_Info, "Graphics mode set: refresh rate (optional): %d, vsync: %d", rdm.RefreshRate, rdm.Vsync);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool graphics_mode_update_render_frame() {
|
||||
if (!_G(gfxDriver) || !_G(gfxDriver)->IsModeSet() || !_G(gfxDriver)->IsNativeSizeValid())
|
||||
return false;
|
||||
|
||||
DisplayMode dm = _G(gfxDriver)->GetDisplayMode();
|
||||
Size screen_size = Size(dm.Width, dm.Height);
|
||||
Size native_size = _G(gfxDriver)->GetNativeSize();
|
||||
Size frame_size = get_game_frame_from_screen_size(native_size, screen_size, _G(CurFrameSetup));
|
||||
Rect render_frame = CenterInRect(RectWH(screen_size), RectWH(frame_size));
|
||||
|
||||
if (!_G(gfxDriver)->SetRenderFrame(render_frame)) {
|
||||
Debug::Printf(kDbgMsg_Error, "Failed to set render frame (%d, %d, %d, %d : %d x %d)",
|
||||
render_frame.Left, render_frame.Top, render_frame.Right, render_frame.Bottom,
|
||||
render_frame.GetWidth(), render_frame.GetHeight());
|
||||
return false;
|
||||
}
|
||||
|
||||
Rect dst_rect = _G(gfxDriver)->GetRenderDestination();
|
||||
Debug::Printf("Render frame set, render dest (%d, %d, %d, %d : %d x %d)",
|
||||
dst_rect.Left, dst_rect.Top, dst_rect.Right, dst_rect.Bottom, dst_rect.GetWidth(), dst_rect.GetHeight());
|
||||
// init game scaling transformation
|
||||
_GP(GameScaling).Init(native_size, _G(gfxDriver)->GetRenderDestination());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool graphics_mode_set_native_res(const GraphicResolution &native_res) {
|
||||
if (!_G(gfxDriver) || !native_res.IsValid())
|
||||
return false;
|
||||
if (!_G(gfxDriver)->SetNativeResolution(native_res))
|
||||
return false;
|
||||
// if render frame translation was already set, then update it with new native size
|
||||
if (_G(gfxDriver)->IsRenderFrameValid())
|
||||
graphics_mode_update_render_frame();
|
||||
return true;
|
||||
}
|
||||
|
||||
FrameScaleDef graphics_mode_get_render_frame() {
|
||||
return _G(CurFrameSetup);
|
||||
}
|
||||
|
||||
bool graphics_mode_set_render_frame(const FrameScaleDef &frame) {
|
||||
if (frame < 0 || frame >= kNumFrameScaleDef)
|
||||
return false;
|
||||
_G(CurFrameSetup) = frame;
|
||||
if (_G(gfxDriver)->GetDisplayMode().IsWindowed())
|
||||
_GP(SavedWindowedSetting).Frame = frame;
|
||||
else
|
||||
_GP(SavedFullscreenSetting).Frame = frame;
|
||||
graphics_mode_update_render_frame();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool graphics_mode_set_filter(const String &filter_id) {
|
||||
if (!_G(GfxFactory))
|
||||
return false;
|
||||
|
||||
String filter_error;
|
||||
PGfxFilter filter = _G(GfxFactory)->SetFilter(filter_id, filter_error);
|
||||
if (!filter) {
|
||||
Debug::Printf(kDbgMsg_Error, "Unable to set graphics filter '%s'. Error: %s", filter_id.GetCStr(), filter_error.GetCStr());
|
||||
return false;
|
||||
}
|
||||
Rect filter_rect = filter->GetDestination();
|
||||
Debug::Printf("Graphics filter set: '%s', filter dest (%d, %d, %d, %d : %d x %d)", filter->GetInfo().Id.GetCStr(),
|
||||
filter_rect.Left, filter_rect.Top, filter_rect.Right, filter_rect.Bottom, filter_rect.GetWidth(), filter_rect.GetHeight());
|
||||
return true;
|
||||
}
|
||||
|
||||
void graphics_mode_on_window_changed(const Size &sz) {
|
||||
if (!_G(gfxDriver))
|
||||
return; // nothing to update
|
||||
_G(gfxDriver)->UpdateDeviceScreen(sz);
|
||||
graphics_mode_update_render_frame();
|
||||
}
|
||||
|
||||
void graphics_mode_shutdown() {
|
||||
if (_G(GfxFactory))
|
||||
_G(GfxFactory)->Shutdown();
|
||||
_G(GfxFactory) = nullptr;
|
||||
_G(gfxDriver) = nullptr;
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
155
engines/ags/engine/main/graphics_mode.h
Normal file
155
engines/ags/engine/main/graphics_mode.h
Normal file
@@ -0,0 +1,155 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_ENGINE_MAIN_GRAPHICS_MODE_H
|
||||
#define AGS_ENGINE_MAIN_GRAPHICS_MODE_H
|
||||
|
||||
#include "ags/engine/gfx/gfx_defines.h"
|
||||
#include "ags/shared/util/geometry.h"
|
||||
#include "ags/shared/util/scaling.h"
|
||||
#include "ags/shared/util/string.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using AGS::Shared::String;
|
||||
using AGS::Engine::GraphicResolution;
|
||||
using AGS::Engine::DisplayMode;
|
||||
using AGS::Engine::WindowMode;
|
||||
|
||||
Size get_desktop_size();
|
||||
|
||||
namespace AGS {
|
||||
namespace Engine {
|
||||
class IGfxModeList;
|
||||
} // namespace Engine
|
||||
} // namespace AGS
|
||||
|
||||
bool find_nearest_supported_mode(const AGS::Engine::IGfxModeList &modes, const Size &wanted_size,
|
||||
const int color_depth, const Size *ratio_reference, const Size *upper_bound,
|
||||
AGS::Engine::DisplayMode &dm, int *mode_index = nullptr);
|
||||
|
||||
// Filter configuration
|
||||
struct GfxFilterSetup {
|
||||
String ID; // internal filter ID
|
||||
String UserRequest; // filter name, requested by user
|
||||
};
|
||||
|
||||
// Defines how game frame is scaled inside a larger window
|
||||
enum FrameScaleDef {
|
||||
kFrame_Undefined = -1,
|
||||
kFrame_Round, // max round (integer) scaling factor
|
||||
kFrame_Stretch, // resize to maximal possible inside the display box
|
||||
kFrame_Proportional, // same as stretch, but keep game's aspect ratio
|
||||
kNumFrameScaleDef
|
||||
};
|
||||
|
||||
// Configuration that is used to determine the size and style of the window
|
||||
struct WindowSetup
|
||||
{
|
||||
AGS3::Size Size; // explicit screen metrics
|
||||
int Scale = 0; // explicit game scale factor
|
||||
WindowMode Mode = AGS::Engine::kWnd_Windowed; // window mode
|
||||
|
||||
WindowSetup() = default;
|
||||
WindowSetup(const AGS3::Size &sz, WindowMode mode = AGS::Engine::kWnd_Windowed)
|
||||
: Size(sz), Scale(0), Mode(mode) {}
|
||||
WindowSetup(int scale, WindowMode mode = AGS::Engine::kWnd_Windowed)
|
||||
: Scale(scale), Mode(mode) {}
|
||||
WindowSetup(WindowMode mode) : Scale(0), Mode(mode) {}
|
||||
};
|
||||
|
||||
// Additional parameters for the display mode setup
|
||||
struct DisplaySetupEx {
|
||||
int RefreshRate = 0; // gfx mode refresh rate
|
||||
bool VSync = false; // vertical sync
|
||||
};
|
||||
|
||||
// Full graphics configuration, contains graphics driver selection,
|
||||
// alternate settings for windowed and fullscreen modes and gfx filter setup.
|
||||
struct DisplayModeSetup {
|
||||
String DriverID; // graphics driver ID
|
||||
|
||||
// Definitions for the fullscreen and windowed modes and scaling methods.
|
||||
// When the initial display mode is set, corresponding scaling method from this pair is used.
|
||||
// The second method is meant to be saved and used if display mode is switched at runtime.
|
||||
WindowSetup FsSetup; // definition of the fullscreen mode
|
||||
WindowSetup WinSetup; // definition of the windowed mode
|
||||
FrameScaleDef FsGameFrame = // how the game frame should be scaled/positioned in fullscreen mode
|
||||
kFrame_Undefined;
|
||||
FrameScaleDef WinGameFrame = // how the game frame should be scaled/positioned in windowed mode
|
||||
kFrame_Undefined;
|
||||
|
||||
bool Windowed = false; // initial mode
|
||||
DisplaySetupEx Params;
|
||||
|
||||
GfxFilterSetup Filter; // graphics filter definition
|
||||
};
|
||||
|
||||
// Display mode color depth variants suggested for the use
|
||||
struct ColorDepthOption {
|
||||
int Bits; // color depth value in bits
|
||||
bool Forced; // whether the depth should be forced, or driver's recommendation used
|
||||
|
||||
ColorDepthOption() : Bits(0), Forced(false) {
|
||||
}
|
||||
ColorDepthOption(int bits, bool forced = false) : Bits(bits), Forced(forced) {
|
||||
}
|
||||
};
|
||||
|
||||
// ActiveDisplaySetting struct merges DisplayMode and FrameScaleDef,
|
||||
// which is useful if you need to save active settings and reapply them later.
|
||||
struct ActiveDisplaySetting {
|
||||
DisplayMode Dm;
|
||||
FrameScaleDef Frame = kFrame_Undefined;
|
||||
int DisplayIndex = -1;
|
||||
};
|
||||
|
||||
// Initializes any possible gfx mode, using user config as a recommendation;
|
||||
// may try all available renderers and modes before succeeding (or failing)
|
||||
bool graphics_mode_init_any(const GraphicResolution &game_res, const DisplayModeSetup &setup, const ColorDepthOption &color_depth);
|
||||
// Return last saved display mode of the given kind
|
||||
ActiveDisplaySetting graphics_mode_get_last_setting(bool windowed);
|
||||
// Creates graphics driver of given id
|
||||
bool graphics_mode_create_renderer(const String &driver_id);
|
||||
// Try to find and initialize compatible display mode as close to given setup as possible
|
||||
bool graphics_mode_set_dm_any(const Size &game_size, const WindowSetup &ws,
|
||||
const ColorDepthOption &color_depth,
|
||||
const FrameScaleDef frame, const DisplaySetupEx ¶ms);
|
||||
// Set the display mode with given parameters
|
||||
bool graphics_mode_set_dm(const AGS::Engine::DisplayMode &dm);
|
||||
// Set the native image size
|
||||
bool graphics_mode_set_native_res(const GraphicResolution &native_res);
|
||||
// Get current render frame setup
|
||||
FrameScaleDef graphics_mode_get_render_frame();
|
||||
// Set the render frame position inside the window
|
||||
bool graphics_mode_set_render_frame(const FrameScaleDef &frame_setup);
|
||||
// Set requested graphics filter, or default filter if the requested one failed
|
||||
bool graphics_mode_set_filter_any(const GfxFilterSetup &setup);
|
||||
// Set the scaling filter with given ID
|
||||
bool graphics_mode_set_filter(const String &filter_id);
|
||||
// Update graphic renderer and render frame when window size changes
|
||||
void graphics_mode_on_window_changed(const Size &sz);
|
||||
// Releases current graphic mode and shuts down renderer
|
||||
void graphics_mode_shutdown();
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
312
engines/ags/engine/main/main.cpp
Normal file
312
engines/ags/engine/main/main.cpp
Normal file
@@ -0,0 +1,312 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/shared/core/platform.h"
|
||||
#include "common/std/set.h"
|
||||
#include "ags/lib/allegro.h" // allegro_exit
|
||||
#include "ags/shared/ac/common.h"
|
||||
#include "ags/engine/ac/game_setup.h"
|
||||
#include "ags/engine/ac/game_state.h"
|
||||
#include "ags/shared/core/def_version.h"
|
||||
#include "ags/engine/debugging/debugger.h"
|
||||
#include "ags/engine/debugging/debug_log.h"
|
||||
#include "ags/shared/debugging/out.h"
|
||||
#include "ags/engine/main/config.h"
|
||||
#include "ags/engine/main/engine.h"
|
||||
#include "ags/engine/main/main.h"
|
||||
#include "ags/engine/platform/base/ags_platform_driver.h"
|
||||
#include "ags/engine/platform/base/sys_main.h"
|
||||
#include "ags/engine/ac/route_finder.h"
|
||||
#include "ags/shared/core/asset_manager.h"
|
||||
#include "ags/shared/util/directory.h"
|
||||
#include "ags/shared/util/path.h"
|
||||
#include "ags/shared/util/string_compat.h"
|
||||
#include "ags/shared/util/string_utils.h"
|
||||
#include "ags/globals.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using namespace AGS::Shared;
|
||||
using namespace AGS::Engine;
|
||||
|
||||
void main_init(int argc, const char *argv[]) {
|
||||
set_our_eip(-999);
|
||||
|
||||
// Init libraries: set text encoding
|
||||
set_uformat(U_UTF8);
|
||||
set_filename_encoding(U_UNICODE);
|
||||
|
||||
_G(EngineVersion) = Version(ACI_VERSION_STR " " SPECIAL_VERSION);
|
||||
#if defined (BUILD_STR)
|
||||
_G(EngineVersion).BuildInfo = BUILD_STR;
|
||||
#endif
|
||||
|
||||
_G(platform) = AGSPlatformDriver::GetDriver();
|
||||
_G(platform)->SetCommandArgs(argv, argc);
|
||||
_G(platform)->MainInit();
|
||||
|
||||
_GP(AssetMgr).reset(new AssetManager());
|
||||
_GP(AssetMgr)->SetSearchPriority(Shared::kAssetPriorityDir);
|
||||
}
|
||||
|
||||
String get_engine_string() {
|
||||
return String::FromFormat("Adventure Game Studio v%s Interpreter\n"
|
||||
"Copyright (c) 1999-2011 Chris Jones and " ACI_COPYRIGHT_YEARS " others\n"
|
||||
"Engine version %s\n",
|
||||
_G(EngineVersion).ShortString.GetCStr(),
|
||||
get_engine_version_and_build().GetCStr());
|
||||
}
|
||||
|
||||
void main_print_help() {
|
||||
_G(platform)->WriteStdOut("%s",
|
||||
"Usage: ags [OPTIONS] [GAMEFILE or DIRECTORY]\n\n"
|
||||
//--------------------------------------------------------------------------------|
|
||||
"Options:\n"
|
||||
" --background Keeps game running in background\n"
|
||||
" (this does not work in exclusive fullscreen)\n"
|
||||
" --clear-cache-on-room-change Clears sprite cache on every room change\n"
|
||||
" --conf FILEPATH Specify explicit config file to read on startup\n"
|
||||
#if AGS_PLATFORM_OS_WINDOWS
|
||||
" --console-attach Write output to the parent process's console\n"
|
||||
#endif
|
||||
" --fps Display fps counter\n"
|
||||
" --fullscreen Force display mode to fullscreen\n"
|
||||
" --gfxdriver <id> Request graphics driver. Available options:\n"
|
||||
#if AGS_PLATFORM_OS_WINDOWS
|
||||
" d3d9, ogl, software\n"
|
||||
#else
|
||||
" ogl, software\n"
|
||||
#endif
|
||||
" --gfxfilter FILTER [SCALING]\n"
|
||||
" Request graphics filter. Available options:\n"
|
||||
" stdscale, linear\n"
|
||||
" (support may differ between graphic drivers);\n"
|
||||
" Scaling is specified as:\n"
|
||||
" proportional, round, stretch,\n"
|
||||
" or an explicit integer multiplier.\n"
|
||||
" --help Print this help message and stop\n"
|
||||
" --loadsavedgame FILEPATH Load savegame on startup\n"
|
||||
" --localuserconf Read and write user config in the game's \n"
|
||||
" directory rather than using standard system path.\n"
|
||||
" Game directory must be writeable.\n"
|
||||
" --log-OUTPUT=GROUP[:LEVEL][,GROUP[:LEVEL]][,...]\n"
|
||||
" --log-OUTPUT=+GROUPLIST[:LEVEL]\n"
|
||||
" Setup logging to the chosen OUTPUT with given\n"
|
||||
" log groups and verbosity levels. Groups may\n"
|
||||
" be also defined by a LIST of one-letter IDs,\n"
|
||||
" preceded by '+', e.g. +ABCD:LEVEL. Verbosity may\n"
|
||||
" be also defined by a numberic ID.\n"
|
||||
" OUTPUTs are\n"
|
||||
" stdout, file, console\n"
|
||||
" (where \"console\" is internal engine's console)\n"
|
||||
" GROUPs are:\n"
|
||||
" all, main (m), game (g), manobj (o),\n"
|
||||
" sprcache (c)\n"
|
||||
" LEVELs are:\n"
|
||||
" all, alert (1), fatal (2), error (3), warn (4),\n"
|
||||
" info (5), debug (6)\n"
|
||||
" Examples:\n"
|
||||
" --log-stdout=+mg:debug\n"
|
||||
" --log-file=all:warn\n"
|
||||
" --log-file-path=PATH Define custom path for the log file\n"
|
||||
//--------------------------------------------------------------------------------|
|
||||
" --no-message-box Disable alerts as modal message boxes\n"
|
||||
" --no-translation Use default game language on start\n"
|
||||
" --noiface Don't draw game GUI\n"
|
||||
" --noscript Don't run room scripts; *WARNING:* unreliable\n"
|
||||
" --nospr Don't draw room objects and characters\n"
|
||||
" --noupdate Don't run game update\n"
|
||||
" --novideo Don't play game videos\n"
|
||||
" --rotation <MODE> Screen rotation preferences. MODEs are:\n"
|
||||
" unlocked (0), portrait (1), landscape (2)\n"
|
||||
#if AGS_PLATFORM_OS_WINDOWS
|
||||
" --setup Run setup application\n"
|
||||
#endif
|
||||
" --shared-data-dir DIR Set the shared game data directory\n"
|
||||
" --startr <room_number> Start game by loading certain room.\n"
|
||||
" --tell Print various information concerning engine\n"
|
||||
" and the game; for selected output use:\n"
|
||||
" --tell-config Print contents of merged game config\n"
|
||||
" --tell-configpath Print paths to available config files\n"
|
||||
" --tell-data Print information on game data and its location\n"
|
||||
" --tell-gameproperties Print information on game general settings\n"
|
||||
" --tell-engine Print engine name and version\n"
|
||||
" --tell-filepath Print all filepaths engine uses for the game\n"
|
||||
" --tell-graphicdriver Print list of supported graphic drivers\n"
|
||||
"\n"
|
||||
" --test Run game in the test mode\n"
|
||||
" --translation <name> Select the given translation on start\n"
|
||||
" --version Print engine's version and stop\n"
|
||||
" --user-data-dir DIR Set the save game directory\n"
|
||||
" --windowed Force display mode to windowed\n"
|
||||
"\n"
|
||||
"Gamefile options:\n"
|
||||
" /dir/path/game/ Launch the game in specified directory\n"
|
||||
" /dir/path/game/penguin.exe Launch penguin.exe\n"
|
||||
" [nothing] Launch the game in the current directory\n"
|
||||
//--------------------------------------------------------------------------------|
|
||||
);
|
||||
}
|
||||
|
||||
int main_process_cmdline(ConfigTree &cfg, int argc, const char *argv[]) {
|
||||
int datafile_argv = 0;
|
||||
for (int ee = 1; ee < argc; ++ee) {
|
||||
const char *arg = argv[ee];
|
||||
//
|
||||
// Startup options
|
||||
//
|
||||
if (ags_stricmp(arg, "--help") == 0 || ags_stricmp(arg, "/?") == 0 || ags_stricmp(arg, "-?") == 0) {
|
||||
_G(justDisplayHelp) = true;
|
||||
}
|
||||
if (ags_stricmp(arg, "-v") == 0 || ags_stricmp(arg, "--version") == 0) {
|
||||
_G(justDisplayVersion) = true;
|
||||
} else if (ags_stricmp(arg, "--updatereg") == 0)
|
||||
_G(debug_flags) |= DBG_REGONLY;
|
||||
else if ((ags_stricmp(arg, "--startr") == 0) && (ee < argc - 1)) {
|
||||
_G(override_start_room) = atoi(argv[ee + 1]);
|
||||
ee++;
|
||||
} else if (ags_stricmp(arg, "--noexceptionhandler") == 0) _GP(usetup).disable_exception_handling = true;
|
||||
else if (ags_stricmp(arg, "--setup") == 0) {
|
||||
_G(justRunSetup) = true;
|
||||
} else if ((ags_stricmp(arg, "--loadsavedgame") == 0) && (argc > ee + 1)) {
|
||||
_G(loadSaveGameOnStartup) = atoi(argv[ee + 1]);
|
||||
ee++;
|
||||
} else if ((ags_stricmp(arg, "--enabledebugger") == 0) && (argc > ee + 1)) {
|
||||
snprintf(_G(editor_debugger_instance_token), sizeof(_G(editor_debugger_instance_token)), "%s", argv[ee + 1]);
|
||||
_G(editor_debugging_enabled) = 1;
|
||||
ee++;
|
||||
} else if (ags_stricmp(arg, "--conf") == 0 && (argc > ee + 1)) {
|
||||
_GP(usetup).conf_path = argv[++ee];
|
||||
} else if (ags_stricmp(arg, "--localuserconf") == 0) {
|
||||
_GP(usetup).local_user_conf = true;
|
||||
} else if (ags_stricmp(arg, "--localuserconf") == 0) {
|
||||
_GP(usetup).user_conf_dir = ".";
|
||||
} else if ((ags_stricmp(arg, "--user-conf-dir") == 0) && (argc > ee + 1)) {
|
||||
_GP(usetup).user_conf_dir = argv[++ee];
|
||||
} else if (ags_stricmp(arg, "--runfromide") == 0 && (argc > ee + 4)) {
|
||||
_GP(usetup).install_dir = argv[ee + 1];
|
||||
_GP(usetup).opt_data_dir = argv[ee + 2];
|
||||
_GP(usetup).opt_audio_dir = argv[ee + 3];
|
||||
_GP(usetup).opt_voice_dir = argv[ee + 4];
|
||||
ee += 4;
|
||||
} else if (ags_stricmp(arg, "--takeover") == 0) {
|
||||
if (argc < ee + 2)
|
||||
break;
|
||||
_GP(play).takeover_data = atoi(argv[ee + 1]);
|
||||
snprintf(_GP(play).takeover_from, sizeof(_GP(play).takeover_from), "%s", argv[ee + 2]);
|
||||
ee += 2;
|
||||
} else if (ags_stricmp(arg, "--clear-cache-on-room-change") == 0) {
|
||||
cfg["misc"]["clear_cache_on_room_change"] = "1";
|
||||
} else if (ags_strnicmp(arg, "--tell", 6) == 0) {
|
||||
if (arg[6] == 0)
|
||||
_G(tellInfoKeys).insert(String("all"));
|
||||
else if (arg[6] == '-' && arg[7] != 0)
|
||||
_G(tellInfoKeys).insert(String(arg + 7));
|
||||
}
|
||||
//
|
||||
// Config overrides
|
||||
//
|
||||
else if ((ags_stricmp(arg, "--user-data-dir") == 0) && (argc > ee + 1))
|
||||
cfg["misc"]["user_data_dir"] = argv[++ee];
|
||||
else if ((ags_stricmp(arg, "--shared-data-dir") == 0) && (argc > ee + 1))
|
||||
cfg["misc"]["shared_data_dir"] = argv[++ee];
|
||||
else if (ags_stricmp(arg, "--windowed") == 0)
|
||||
cfg["graphics"]["windowed"] = "1";
|
||||
else if (ags_stricmp(arg, "--fullscreen") == 0)
|
||||
cfg["graphics"]["windowed"] = "0";
|
||||
else if ((ags_stricmp(arg, "--gfxdriver") == 0) && (argc > ee + 1)) {
|
||||
cfg["graphics"]["driver"] = argv[++ee];
|
||||
} else if ((ags_stricmp(arg, "--gfxfilter") == 0) && (argc > ee + 1)) {
|
||||
cfg["graphics"]["filter"] = argv[++ee];
|
||||
if (argc > ee + 1 && argv[ee + 1][0] != '-') {
|
||||
// NOTE: we make an assumption here that if user provides scaling
|
||||
// multiplier, then it's meant to be applied to windowed mode only;
|
||||
// Otherwise the scaling style is applied to both.
|
||||
String scale_value = argv[++ee];
|
||||
int scale_mul = StrUtil::StringToInt(scale_value);
|
||||
if (scale_mul > 0) {
|
||||
cfg["graphics"]["window"] = String::FromFormat("x%d", scale_mul);
|
||||
cfg["graphics"]["game_scale_win"] = "round";
|
||||
} else {
|
||||
cfg["graphics"]["game_scale_fs"] = scale_value;
|
||||
cfg["graphics"]["game_scale_win"] = scale_value;
|
||||
}
|
||||
}
|
||||
} else if ((ags_stricmp(arg, "--translation") == 0) && (argc > ee + 1)) {
|
||||
cfg["language"]["translation"] = argv[++ee];
|
||||
} else if (ags_stricmp(arg, "--no-translation") == 0) {
|
||||
cfg["language"]["translation"] = "";
|
||||
} else if (ags_stricmp(arg, "--background") == 0) {
|
||||
cfg["override"]["multitasking"] = "1";
|
||||
} else if (ags_stricmp(arg, "--fps") == 0)
|
||||
cfg["misc"]["show_fps"] = "1";
|
||||
else if (ags_stricmp(arg, "--test") == 0) _G(debug_flags) |= DBG_DEBUGMODE;
|
||||
else if (ags_stricmp(arg, "--noiface") == 0) _G(debug_flags) |= DBG_NOIFACE;
|
||||
else if (ags_stricmp(arg, "--nosprdisp") == 0) _G(debug_flags) |= DBG_NODRAWSPRITES;
|
||||
else if (ags_stricmp(arg, "--nospr") == 0) _G(debug_flags) |= DBG_NOOBJECTS;
|
||||
else if (ags_stricmp(arg, "--noupdate") == 0) _G(debug_flags) |= DBG_NOUPDATE;
|
||||
else if (ags_stricmp(arg, "--nosound") == 0) _G(debug_flags) |= DBG_NOSFX;
|
||||
else if (ags_stricmp(arg, "--nomusic") == 0) _G(debug_flags) |= DBG_NOMUSIC;
|
||||
else if (ags_stricmp(arg, "--noscript") == 0) _G(debug_flags) |= DBG_NOSCRIPT;
|
||||
else if (ags_stricmp(arg, "--novideo") == 0) _G(debug_flags) |= DBG_NOVIDEO;
|
||||
else if (ags_stricmp(arg, "--rotation") == 0 && (argc > ee + 1)) {
|
||||
cfg["graphics"]["rotation"] = argv[++ee];
|
||||
} else if (ags_strnicmp(arg, "--log-", 6) == 0 && arg[6] != 0) {
|
||||
String logarg = arg + 6;
|
||||
size_t split_at = logarg.FindChar('=');
|
||||
if (split_at != String::NoIndex)
|
||||
cfg["log"][logarg.Left(split_at)] = logarg.Mid(split_at + 1);
|
||||
else
|
||||
cfg["log"][logarg] = "";
|
||||
} else if (arg[0] != '-') datafile_argv = ee;
|
||||
}
|
||||
|
||||
if (datafile_argv > 0) {
|
||||
_G(cmdGameDataPath) = _G(platform)->GetCommandArg(datafile_argv);
|
||||
}
|
||||
|
||||
if (_G(tellInfoKeys).size() > 0)
|
||||
_G(justTellInfo) = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void main_set_gamedir(int argc, const char *argv[]) {
|
||||
_G(appPath) = Path::MakeAbsolutePath(_G(platform)->GetCommandArg(0));
|
||||
_G(appDirectory) = Path::GetDirectoryPath(_G(appPath));
|
||||
|
||||
// TODO: remove following when supporting unicode paths
|
||||
{
|
||||
// It looks like Allegro library does not like ANSI (ACP) paths.
|
||||
// When *not* working in U_UNICODE filepath mode, whenever it gets
|
||||
// current directory for its own operations, it "fixes" it by
|
||||
// substituting non-ASCII symbols with '^'.
|
||||
// Here we explicitly set current directory to ASCII path.
|
||||
String cur_dir = Directory::GetCurrentDirectory();
|
||||
String path = Path::GetPathInASCII(cur_dir);
|
||||
if (!path.IsEmpty())
|
||||
Directory::SetCurrentDirectory(Path::MakeAbsolutePath(path));
|
||||
else
|
||||
Debug::Printf(kDbgMsg_Error, "Unable to determine current directory: GetPathInASCII failed.\nArg: %s", cur_dir.GetCStr());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
46
engines/ags/engine/main/main.h
Normal file
46
engines/ags/engine/main/main.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_ENGINE_MAIN_MAIN_H
|
||||
#define AGS_ENGINE_MAIN_MAIN_H
|
||||
|
||||
#include "ags/shared/core/platform.h"
|
||||
#include "ags/shared/util/version.h"
|
||||
#include "ags/shared/util/ini_util.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using AGS::Shared::ConfigTree;
|
||||
using AGS::Shared::String;
|
||||
|
||||
extern void main_init(int argc, const char *argv[]);
|
||||
|
||||
extern int main_process_cmdline(ConfigTree &cfg, int argc, const char *argv[]);
|
||||
|
||||
extern String get_engine_string();
|
||||
|
||||
extern void main_print_help();
|
||||
|
||||
extern void main_set_gamedir(int argc, const char *argv[]);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
251
engines/ags/engine/main/quit.cpp
Normal file
251
engines/ags/engine/main/quit.cpp
Normal file
@@ -0,0 +1,251 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
// Quit game procedure
|
||||
//
|
||||
|
||||
#include "ags/shared/core/platform.h"
|
||||
#include "ags/engine/ac/cd_audio.h"
|
||||
#include "ags/engine/ac/game.h"
|
||||
#include "ags/engine/ac/game_setup.h"
|
||||
#include "ags/shared/ac/game_setup_struct.h"
|
||||
#include "ags/engine/ac/game_state.h"
|
||||
#include "ags/engine/ac/room_status.h"
|
||||
#include "ags/engine/ac/route_finder.h"
|
||||
#include "ags/engine/ac/translation.h"
|
||||
#include "ags/engine/ac/dynobj/dynobj_manager.h"
|
||||
#include "ags/engine/debugging/ags_editor_debugger.h"
|
||||
#include "ags/engine/debugging/debug_log.h"
|
||||
#include "ags/engine/debugging/debugger.h"
|
||||
#include "ags/shared/debugging/out.h"
|
||||
#include "ags/shared/font/fonts.h"
|
||||
#include "ags/engine/main/config.h"
|
||||
#include "ags/engine/main/engine.h"
|
||||
#include "ags/engine/main/main.h"
|
||||
#include "ags/engine/main/quit.h"
|
||||
#include "ags/shared/ac/sprite_cache.h"
|
||||
#include "ags/engine/gfx/graphics_driver.h"
|
||||
#include "ags/shared/gfx/bitmap.h"
|
||||
#include "ags/shared/core/asset_manager.h"
|
||||
#include "ags/engine/platform/base/ags_platform_driver.h"
|
||||
#include "ags/engine/platform/base/sys_main.h"
|
||||
#include "ags/plugins/plugin_engine.h"
|
||||
#include "ags/shared/script/cc_common.h"
|
||||
#include "ags/engine/media/audio/audio_system.h"
|
||||
#include "ags/globals.h"
|
||||
#include "ags/ags.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using namespace AGS::Shared;
|
||||
using namespace AGS::Engine;
|
||||
|
||||
void quit_tell_editor_debugger(const String &qmsg, QuitReason qreason) {
|
||||
if (_G(editor_debugging_initialized)) {
|
||||
if (qreason & kQuitKind_GameException)
|
||||
_G(handledErrorInEditor) = send_exception_to_debugger(qmsg.GetCStr());
|
||||
send_state_to_debugger("EXIT");
|
||||
_G(editor_debugger)->Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void quit_stop_cd() {
|
||||
if (_G(need_to_stop_cd))
|
||||
cd_manager(3, 0);
|
||||
}
|
||||
|
||||
void quit_check_dynamic_sprites(QuitReason qreason) {
|
||||
if ((qreason & kQuitKind_NormalExit) && _G(check_dynamic_sprites_at_exit) && (_GP(game).options[OPT_DEBUGMODE] != 0)) {
|
||||
// Check that the dynamic sprites have been deleted;
|
||||
// ignore those that are owned by the game objects.
|
||||
for (size_t i = 1; i < _GP(spriteset).GetSpriteSlotCount(); i++) {
|
||||
if ((_GP(game).SpriteInfos[i].Flags & SPF_DYNAMICALLOC) &&
|
||||
((_GP(game).SpriteInfos[i].Flags & SPF_OBJECTOWNED) == 0)) {
|
||||
debug_script_warn("Dynamic sprite %d was never deleted", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void quit_shutdown_audio() {
|
||||
set_our_eip(9917);
|
||||
_GP(game).options[OPT_CROSSFADEMUSIC] = 0;
|
||||
shutdown_sound();
|
||||
}
|
||||
|
||||
// Parses the quit message; returns:
|
||||
// * QuitReason - which is a code of the reason we're quitting (game error, etc);
|
||||
// * errmsg - a pure error message (extracted from the parsed string).
|
||||
// * alertis - a complex message to post into the engine output (stdout, log);
|
||||
QuitReason quit_check_for_error_state(const char *qmsg, String &errmsg, String &alertis) {
|
||||
if (qmsg[0] == '|') {
|
||||
return kQuit_GameRequest;
|
||||
} else if (qmsg[0] == '!') {
|
||||
QuitReason qreason;
|
||||
qmsg++;
|
||||
|
||||
if (qmsg[0] == '|') {
|
||||
qreason = kQuit_UserAbort;
|
||||
alertis = "Abort key pressed.\n\n";
|
||||
} else if (qmsg[0] == '?') {
|
||||
qmsg++;
|
||||
qreason = kQuit_ScriptAbort;
|
||||
alertis = "A fatal error has been generated by the script using the AbortGame function. Please contact the game author for support.\n\n";
|
||||
} else {
|
||||
qreason = kQuit_GameError;
|
||||
alertis.Format("An error has occurred. Please contact the game author for support, as this "
|
||||
"is likely to be a scripting error and not a bug in AGS.\n"
|
||||
"(Engine version %s)\n\n", _G(EngineVersion).LongString.GetCStr());
|
||||
}
|
||||
|
||||
alertis.Append(cc_get_err_callstack());
|
||||
|
||||
if (qreason != kQuit_UserAbort) {
|
||||
alertis.AppendFmt("\nError: %s", qmsg);
|
||||
errmsg = qmsg;
|
||||
Debug::Printf(kDbgMsg_Fatal, "ERROR: %s\n%s", qmsg, cc_get_error().CallStack.GetCStr());
|
||||
}
|
||||
return qreason;
|
||||
} else if (qmsg[0] == '%') {
|
||||
qmsg++;
|
||||
alertis.Format("A warning has been generated. This is not normally fatal, but you have selected "
|
||||
"to treat warnings as errors.\n"
|
||||
"(Engine version %s)\n\n%s\n%s", _G(EngineVersion).LongString.GetCStr(), cc_get_err_callstack().GetCStr(), qmsg);
|
||||
errmsg = qmsg;
|
||||
return kQuit_GameWarning;
|
||||
} else {
|
||||
alertis.Format("An internal error has occurred. Please note down the following information.\n"
|
||||
"(Engine version %s)\n"
|
||||
"\nError: %s", _G(EngineVersion).LongString.GetCStr(), qmsg);
|
||||
return kQuit_FatalError;
|
||||
}
|
||||
}
|
||||
|
||||
void quit_delete_temp_files() {
|
||||
#ifdef TODO
|
||||
al_ffblk dfb;
|
||||
int dun = al_findfirst("~ac*.tmp", &dfb, FA_SEARCH);
|
||||
while (!dun) {
|
||||
File::DeleteFile(dfb.name);
|
||||
dun = al_findnext(&dfb);
|
||||
}
|
||||
al_findclose(&dfb);
|
||||
#endif
|
||||
}
|
||||
|
||||
// quit - exits the engine, shutting down everything gracefully
|
||||
// The parameter is the message to print. If this message begins with
|
||||
// an '!' character, then it is printed as a "contact game author" error.
|
||||
// If it begins with a '|' then it is treated as a "thanks for playing" type
|
||||
// message. If it begins with anything else, it is treated as an internal
|
||||
// error.
|
||||
// "!|" is a special code used to mean that the player has aborted (Alt+X)
|
||||
void quit(const char *quitmsg) {
|
||||
if (!_G(abort_engine)) {
|
||||
strncpy(_G(quit_message), quitmsg, sizeof(_G(quit_message)) - 1);
|
||||
_G(quit_message)[sizeof(_G(quit_message)) - 1] = '\0';
|
||||
_G(abort_engine) = true;
|
||||
}
|
||||
}
|
||||
|
||||
void quit_free() {
|
||||
if (strlen(_G(quit_message)) == 0)
|
||||
Common::strcpy_s(_G(quit_message), "|bye!");
|
||||
|
||||
const char *quitmsg = _G(quit_message);
|
||||
|
||||
Debug::Printf(kDbgMsg_Info, "Quitting the game...");
|
||||
|
||||
// NOTE: we must not use the quitmsg pointer past this step,
|
||||
// as it may be from a plugin and we're about to free plugins
|
||||
String errmsg, fullmsg;
|
||||
QuitReason qreason = quit_check_for_error_state(quitmsg, errmsg, fullmsg);
|
||||
|
||||
if (qreason & kQuitKind_NormalExit)
|
||||
save_config_file();
|
||||
|
||||
_G(handledErrorInEditor) = false;
|
||||
|
||||
quit_tell_editor_debugger(errmsg, qreason);
|
||||
|
||||
set_our_eip(9900);
|
||||
|
||||
quit_stop_cd();
|
||||
|
||||
set_our_eip(9020);
|
||||
|
||||
// Be sure to unlock mouse on exit, or users will hate us
|
||||
sys_window_lock_mouse(false);
|
||||
|
||||
set_our_eip(9016);
|
||||
|
||||
quit_check_dynamic_sprites(qreason);
|
||||
|
||||
if (_G(use_cdplayer))
|
||||
_G(platform)->ShutdownCDPlayer();
|
||||
|
||||
set_our_eip(9019);
|
||||
|
||||
quit_shutdown_audio();
|
||||
|
||||
set_our_eip(9901);
|
||||
|
||||
_GP(spriteset).Reset();
|
||||
|
||||
set_our_eip(9908);
|
||||
|
||||
shutdown_pathfinder();
|
||||
|
||||
unload_game();
|
||||
|
||||
engine_shutdown_gfxmode();
|
||||
|
||||
_G(platform)->PreBackendExit();
|
||||
|
||||
// On abnormal exit: display the message (at this point the window still exists)
|
||||
if ((qreason & kQuitKind_NormalExit) == 0 && !_G(handledErrorInEditor)) {
|
||||
_G(platform)->DisplayAlert("%s", fullmsg.GetCStr());
|
||||
}
|
||||
|
||||
// release backed library
|
||||
// WARNING: no Allegro objects should remain in memory after this,
|
||||
// if their destruction is called later, program will crash!
|
||||
shutdown_font_renderer();
|
||||
allegro_exit();
|
||||
sys_main_shutdown();
|
||||
|
||||
_G(platform)->PostAllegroExit();
|
||||
|
||||
set_our_eip(9903);
|
||||
|
||||
quit_delete_temp_files();
|
||||
|
||||
_G(proper_exit) = 1;
|
||||
|
||||
Debug::Printf(kDbgMsg_Alert, "***** ENGINE HAS SHUTDOWN");
|
||||
|
||||
shutdown_debug();
|
||||
|
||||
set_our_eip(9904);
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
60
engines/ags/engine/main/quit.h
Normal file
60
engines/ags/engine/main/quit.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_ENGINE_MAIN_QUIT_H
|
||||
#define AGS_ENGINE_MAIN_QUIT_H
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
enum QuitReason {
|
||||
// Flags defining the base reason, could be subtyped by summing
|
||||
// with the other flags:
|
||||
// - normal exit means everything is fine
|
||||
kQuitKind_NormalExit = 0x01,
|
||||
// - game was requested to abort
|
||||
kQuitKind_DeliberateAbort = 0x02,
|
||||
// - something was wrong with the game logic (script)
|
||||
kQuitKind_GameException = 0x04,
|
||||
// - something was wrong with the engine, which it could not handle
|
||||
kQuitKind_EngineException = 0x08,
|
||||
|
||||
// user closed the window or script command QuitGame was executed
|
||||
kQuit_GameRequest = kQuitKind_NormalExit | 0x10,
|
||||
|
||||
// user pressed abort game key
|
||||
kQuit_UserAbort = kQuitKind_DeliberateAbort | 0x20,
|
||||
|
||||
// script command AbortGame was executed
|
||||
kQuit_ScriptAbort = kQuitKind_GameException | 0x10,
|
||||
// game logic has generated a warning and warnings are treated as error
|
||||
kQuit_GameWarning = kQuitKind_GameException | 0x20,
|
||||
// game logic has generated an error (often script error)
|
||||
kQuit_GameError = kQuitKind_GameException | 0x30,
|
||||
|
||||
// any kind of a fatal engine error
|
||||
kQuit_FatalError = kQuitKind_EngineException
|
||||
};
|
||||
|
||||
extern void quit_free();
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
508
engines/ags/engine/main/update.cpp
Normal file
508
engines/ags/engine/main/update.cpp
Normal file
@@ -0,0 +1,508 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
// Game update procedure
|
||||
//
|
||||
|
||||
#include "ags/shared/ac/common.h"
|
||||
#include "ags/engine/ac/character.h"
|
||||
#include "ags/engine/ac/character_extras.h"
|
||||
#include "ags/engine/ac/draw.h"
|
||||
#include "ags/engine/ac/game.h"
|
||||
#include "ags/engine/ac/game_state.h"
|
||||
#include "ags/shared/ac/game_setup_struct.h"
|
||||
#include "ags/engine/ac/global_character.h"
|
||||
#include "ags/engine/ac/lip_sync.h"
|
||||
#include "ags/engine/ac/overlay.h"
|
||||
#include "ags/engine/ac/sys_events.h"
|
||||
#include "ags/engine/ac/room_object.h"
|
||||
#include "ags/engine/ac/room_status.h"
|
||||
#include "ags/engine/main/update.h"
|
||||
#include "ags/engine/ac/screen_overlay.h"
|
||||
#include "ags/shared/ac/sprite_cache.h"
|
||||
#include "ags/engine/ac/view_frame.h"
|
||||
#include "ags/engine/ac/walkable_area.h"
|
||||
#include "ags/shared/gfx/bitmap.h"
|
||||
#include "ags/engine/gfx/graphics_driver.h"
|
||||
#include "ags/engine/media/audio/audio_system.h"
|
||||
#include "ags/engine/ac/timer.h"
|
||||
#include "ags/engine/main/game_run.h"
|
||||
#include "ags/engine/ac/move_list.h"
|
||||
#include "ags/globals.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using namespace AGS::Shared;
|
||||
using namespace AGS::Engine;
|
||||
|
||||
|
||||
// Optionally fixes target position, when one axis is left to move along.
|
||||
// This is done only for backwards compatibility now.
|
||||
// Uses generic parameters.
|
||||
static void movelist_handle_targetfix(const fixed &xpermove, const fixed &ypermove, int &targety) {
|
||||
// Old comment about ancient behavior:
|
||||
// if the X-movement has finished, and the Y-per-move is < 1, finish
|
||||
// This can cause jump at the end, but without it the character will
|
||||
// walk on the spot for a while if the Y-per-move is for example 0.2
|
||||
// if ((ypermove & 0xfffff000) == 0) cmls.doneflag|=2;
|
||||
// int ypmm=(ypermove >> 16) & 0x0000ffff;
|
||||
|
||||
// NEW 2.15 SR-1 plan: if X-movement has finished, and Y-per-move is < 1,
|
||||
// allow it to finish more easily by moving target zone
|
||||
// NOTE: interesting fact: this fix was also done for the strictly vertical
|
||||
// move, probably because of the logical mistake in condition.
|
||||
|
||||
int tfix = 3;
|
||||
// 2.70: if the X permove is also <=1, don't skip as far
|
||||
if (((xpermove & 0xffff0000) == 0xffff0000) ||
|
||||
((xpermove & 0xffff0000) == 0x00000000))
|
||||
tfix = 2;
|
||||
|
||||
// 2.61 RC1: correct this to work with > -1 as well as < 1
|
||||
if (ypermove == 0) {
|
||||
}
|
||||
// Y per move is < 1, so finish the move
|
||||
else if ((ypermove & 0xffff0000) == 0)
|
||||
targety -= tfix;
|
||||
// Y per move is -1 exactly, don't snap to finish
|
||||
else if ((ypermove & 0xffffffff) == 0xffff0000) {
|
||||
}
|
||||
// Y per move is > -1, so finish the move
|
||||
else if ((ypermove & 0xffff0000) == 0xffff0000)
|
||||
targety += tfix;
|
||||
}
|
||||
|
||||
// Handle remaining move along a single axis; uses generic parameters.
|
||||
static void movelist_handle_remainer(const fixed xpermove, const fixed ypermove,
|
||||
const int xdistance, const float step_length, fixed &fin_ymove, float &fin_from_part) {
|
||||
// Walk along the remaining axis with the full walking speed
|
||||
assert(xpermove != 0 && ypermove != 0 && step_length >= 0.f);
|
||||
fin_ymove = ypermove > 0 ? ftofix(step_length) : -ftofix(step_length);
|
||||
fin_from_part = (float)xdistance / fixtof(xpermove);
|
||||
assert(fin_from_part >= 0);
|
||||
}
|
||||
|
||||
// Handle remaining move fixup, but only if necessary
|
||||
static void movelist_handle_remainer(MoveList &m) {
|
||||
assert(m.numstage > 0);
|
||||
const fixed xpermove = m.xpermove[m.onstage];
|
||||
const fixed ypermove = m.ypermove[m.onstage];
|
||||
const Point target = m.pos[m.onstage + 1];
|
||||
// Apply remainer to movelists where LONGER axis was completed, and SHORTER remains
|
||||
if ((xpermove != 0) && (ypermove != 0)) {
|
||||
if ((m.doneflag & kMoveListDone_XY) == kMoveListDone_X && (abs(ypermove) < abs(xpermove)))
|
||||
movelist_handle_remainer(xpermove, ypermove, target.X - m.from.X,
|
||||
m.GetStepLength(), m.fin_move, m.fin_from_part);
|
||||
else if ((m.doneflag & kMoveListDone_XY) == kMoveListDone_Y && (abs(xpermove) < abs(ypermove)))
|
||||
movelist_handle_remainer(ypermove, xpermove, target.Y - m.from.Y,
|
||||
m.GetStepLength(), m.fin_move, m.fin_from_part);
|
||||
}
|
||||
}
|
||||
|
||||
// Test if move completed, returns if just completed
|
||||
static bool movelist_handle_donemove(const uint8_t testflag, const fixed xpermove, const int targetx, uint8_t &doneflag, int &xps) {
|
||||
if ((doneflag & testflag) != 0)
|
||||
return false; // already done before
|
||||
|
||||
if (((xpermove > 0) && (xps >= targetx)) || ((xpermove < 0) && (xps <= targetx))) {
|
||||
doneflag |= testflag;
|
||||
xps = targetx; // snap to the target (in case run over)
|
||||
// Comment about old engine behavior:
|
||||
// if the Y is almost there too, finish it
|
||||
// this is new in v2.40
|
||||
// removed in 2.70
|
||||
/*if (abs(yps - targety) <= 2)
|
||||
yps = targety;*/
|
||||
} else if (xpermove == 0) {
|
||||
doneflag |= testflag;
|
||||
}
|
||||
return (doneflag & testflag) != 0;
|
||||
}
|
||||
|
||||
int do_movelist_move(short &mslot, int &pos_x, int &pos_y) {
|
||||
// TODO: find out why movelist 0 is not being used
|
||||
assert(mslot >= 1);
|
||||
if (mslot < 1)
|
||||
return 0;
|
||||
|
||||
int need_to_fix_sprite = 0; // TODO: find out what this value means and refactor
|
||||
MoveList &cmls = _GP(mls)[mslot];
|
||||
const fixed xpermove = cmls.xpermove[cmls.onstage];
|
||||
const fixed ypermove = cmls.ypermove[cmls.onstage];
|
||||
const fixed fin_move = cmls.fin_move;
|
||||
const float main_onpart = (cmls.fin_from_part > 0.f) ? cmls.fin_from_part : cmls.onpart;
|
||||
const float fin_onpart = cmls.onpart - main_onpart;
|
||||
Point target = cmls.pos[cmls.onstage + 1];
|
||||
int xps = pos_x, yps = pos_y;
|
||||
|
||||
// Old-style optional move target fixup
|
||||
if (_G(loaded_game_file_version) < kGameVersion_361) {
|
||||
if ((ypermove != 0) && (cmls.doneflag & kMoveListDone_X) != 0) { // X-move has finished, handle the Y-move remainer
|
||||
movelist_handle_targetfix(xpermove, ypermove, target.Y);
|
||||
} else if ((xpermove != 0) && (cmls.doneflag & kMoveListDone_Y) != 0) { // Y-move has finished, handle the X-move remainer
|
||||
movelist_handle_targetfix(xpermove, ypermove, target.Y);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate next positions, as required
|
||||
if ((cmls.doneflag & kMoveListDone_X) == 0) {
|
||||
xps = cmls.from.X + (int)(fixtof(xpermove) * main_onpart) + (int)(fixtof(fin_move) * fin_onpart);
|
||||
}
|
||||
if ((cmls.doneflag & kMoveListDone_Y) == 0) {
|
||||
yps = cmls.from.Y + (int)(fixtof(ypermove) * main_onpart) + (int)(fixtof(fin_move) * fin_onpart);
|
||||
}
|
||||
|
||||
// Check if finished either horizontal or vertical movement;
|
||||
// if any was finished just now, then also handle remainer fixup
|
||||
bool done_now = movelist_handle_donemove(kMoveListDone_X, xpermove, target.X, cmls.doneflag, xps);
|
||||
done_now |= movelist_handle_donemove(kMoveListDone_Y, ypermove, target.Y, cmls.doneflag, yps);
|
||||
if (done_now)
|
||||
movelist_handle_remainer(cmls);
|
||||
|
||||
// Handle end of move stage
|
||||
if ((cmls.doneflag & kMoveListDone_XY) == kMoveListDone_XY) {
|
||||
// this stage is done, go on to the next stage
|
||||
cmls.from = cmls.pos[cmls.onstage + 1];
|
||||
cmls.onstage++;
|
||||
cmls.onpart = -1.f;
|
||||
cmls.fin_from_part = 0.f;
|
||||
cmls.fin_move = 0;
|
||||
cmls.doneflag = 0;
|
||||
if (cmls.onstage < cmls.numstage) {
|
||||
xps = cmls.from.X;
|
||||
yps = cmls.from.Y;
|
||||
}
|
||||
|
||||
if (cmls.onstage >= cmls.numstage - 1) { // last stage is just dest pos
|
||||
cmls.numstage = 0;
|
||||
mslot = 0;
|
||||
need_to_fix_sprite = 1; // TODO: find out what this means
|
||||
} else {
|
||||
need_to_fix_sprite = 2; // TODO: find out what this means
|
||||
}
|
||||
}
|
||||
|
||||
// Make a step along the current vector and return
|
||||
cmls.onpart += 1.f;
|
||||
pos_x = xps;
|
||||
pos_y = yps;
|
||||
return need_to_fix_sprite;
|
||||
}
|
||||
|
||||
void restore_movelists() {
|
||||
// Recalculate move remainer fixups, where necessary
|
||||
for (auto &m : _GP(mls)) {
|
||||
if (m.numstage > 0)
|
||||
movelist_handle_remainer(m);
|
||||
}
|
||||
}
|
||||
|
||||
void update_script_timers() {
|
||||
if (_GP(play).gscript_timer > 0) _GP(play).gscript_timer--;
|
||||
for (int aa = 0; aa < MAX_TIMERS; aa++) {
|
||||
if (_GP(play).script_timers[aa] > 1) _GP(play).script_timers[aa]--;
|
||||
}
|
||||
}
|
||||
|
||||
void update_cycling_views() {
|
||||
// update graphics for object if cycling view
|
||||
for (uint32_t i = 0; i < _G(croom)->numobj; ++i) {
|
||||
_G(objs)[i].UpdateCyclingView(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Updates the view of the player character
|
||||
void update_player_view() {
|
||||
if (_G(playerchar)->flags & CHF_FIXVIEW)
|
||||
return; // view is locked
|
||||
|
||||
int onwalkarea = get_walkable_area_at_character(_GP(game).playercharacter);
|
||||
if (onwalkarea < 0)
|
||||
return; // error?
|
||||
|
||||
int areaview = _GP(thisroom).WalkAreas[onwalkarea].PlayerView;
|
||||
if (areaview > 0)
|
||||
_G(playerchar)->view = areaview - 1; // convert to 0-based id
|
||||
else if (_GP(thisroom).Options.PlayerView > 0)
|
||||
_G(playerchar)->view = _GP(thisroom).Options.PlayerView - 1; // convert to 0-based id
|
||||
else
|
||||
_G(playerchar)->view = _G(playerchar)->defview;
|
||||
}
|
||||
|
||||
void update_character_move_and_anim(std::vector<int> &followingAsSheep) {
|
||||
// move & animate characters
|
||||
for (int aa = 0; aa < _GP(game).numcharacters; aa++) {
|
||||
if (_GP(game).chars[aa].on != 1) continue;
|
||||
|
||||
CharacterInfo *chi = &_GP(game).chars[aa];
|
||||
CharacterExtras *chex = &_GP(charextra)[aa];
|
||||
|
||||
chi->UpdateMoveAndAnim(aa, chex, followingAsSheep);
|
||||
}
|
||||
}
|
||||
|
||||
void update_following_exactly_characters(const std::vector<int> &followingAsSheep) {
|
||||
// update location of all following_exactly characters
|
||||
for (size_t i = 0; i < followingAsSheep.size(); ++i) {
|
||||
CharacterInfo *chi = &_GP(game).chars[followingAsSheep[i]];
|
||||
|
||||
chi->UpdateFollowingExactlyCharacter();
|
||||
}
|
||||
}
|
||||
|
||||
void update_overlay_timers() {
|
||||
// update overlay timers
|
||||
auto &overs = get_overlays();
|
||||
for (auto &over : overs) {
|
||||
if (over.timeout > 0) {
|
||||
over.timeout--;
|
||||
if (over.timeout == 0) {
|
||||
remove_screen_overlay(over.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void update_speech_and_messages() {
|
||||
bool is_voice_playing = false;
|
||||
if (_GP(play).speech_has_voice) {
|
||||
auto *ch = AudioChans::GetChannel(SCHAN_SPEECH);
|
||||
is_voice_playing = ch && ch->is_playing();
|
||||
}
|
||||
// determine if speech text should be removed
|
||||
if (_GP(play).messagetime >= 0) {
|
||||
_GP(play).messagetime--;
|
||||
// extend life of text if the voice hasn't finished yet
|
||||
if (_GP(play).speech_has_voice && !_GP(play).speech_in_post_state) {
|
||||
if ((is_voice_playing) && (_GP(play).fast_forward == 0)) {
|
||||
if (_GP(play).messagetime <= 1)
|
||||
_GP(play).messagetime = 1;
|
||||
} else // if the voice has finished, remove the speech
|
||||
_GP(play).messagetime = 0;
|
||||
}
|
||||
|
||||
// Enter speech post-state: optionally increase final waiting time
|
||||
if (!_GP(play).speech_in_post_state && (_GP(play).fast_forward == 0) && (_GP(play).messagetime < 1)) {
|
||||
_GP(play).speech_in_post_state = true;
|
||||
if (_GP(play).speech_display_post_time_ms > 0) {
|
||||
_GP(play).messagetime = ::lround(_GP(play).speech_display_post_time_ms * get_game_fps() / 1000.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (_GP(play).messagetime < 1) {
|
||||
if (_GP(play).fast_forward > 0) {
|
||||
remove_screen_overlay(_GP(play).text_overlay_on);
|
||||
_GP(play).SetWaitSkipResult(SKIP_AUTOTIMER);
|
||||
} else if (_GP(play).speech_skip_style & SKIP_AUTOTIMER) {
|
||||
remove_screen_overlay(_GP(play).text_overlay_on);
|
||||
_GP(play).SetWaitSkipResult(SKIP_AUTOTIMER);
|
||||
_GP(play).SetIgnoreInput(_GP(play).ignore_user_input_after_text_timeout_ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update sierra-style speech
|
||||
void update_sierra_speech() {
|
||||
int voice_pos_ms = -1;
|
||||
if (_GP(play).speech_has_voice) {
|
||||
auto *ch = AudioChans::GetChannel(SCHAN_SPEECH);
|
||||
voice_pos_ms = ch ? ch->get_pos_ms() : -1;
|
||||
}
|
||||
if ((_G(face_talking) >= 0) && (_GP(play).fast_forward == 0)) {
|
||||
int updatedFrame = 0;
|
||||
|
||||
if ((_G(facetalkchar)->blinkview > 0) && (_G(facetalkAllowBlink))) {
|
||||
if (_G(facetalkchar)->blinktimer > 0) {
|
||||
// countdown to playing blink anim
|
||||
_G(facetalkchar)->blinktimer--;
|
||||
if (_G(facetalkchar)->blinktimer == 0) {
|
||||
_G(facetalkchar)->blinkframe = 0;
|
||||
_G(facetalkchar)->blinktimer = -1;
|
||||
updatedFrame = 2;
|
||||
}
|
||||
} else if (_G(facetalkchar)->blinktimer < 0) {
|
||||
// currently playing blink anim
|
||||
if (_G(facetalkchar)->blinktimer < ((0 - 6) - _GP(views)[_G(facetalkchar)->blinkview].loops[_G(facetalkBlinkLoop)].frames[_G(facetalkchar)->blinkframe].speed)) {
|
||||
// time to advance to next frame
|
||||
_G(facetalkchar)->blinktimer = -1;
|
||||
_G(facetalkchar)->blinkframe++;
|
||||
updatedFrame = 2;
|
||||
if (_G(facetalkchar)->blinkframe >= _GP(views)[_G(facetalkchar)->blinkview].loops[_G(facetalkBlinkLoop)].numFrames) {
|
||||
_G(facetalkchar)->blinkframe = 0;
|
||||
_G(facetalkchar)->blinktimer = _G(facetalkchar)->blinkinterval;
|
||||
}
|
||||
} else
|
||||
_G(facetalkchar)->blinktimer--;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (_G(curLipLine) >= 0) {
|
||||
// check voice lip sync
|
||||
if (_G(curLipLinePhoneme) >= _GP(splipsync)[_G(curLipLine)].numPhonemes) {
|
||||
// the lip-sync has finished, so just stay idle
|
||||
} else {
|
||||
while ((_G(curLipLinePhoneme) < _GP(splipsync)[_G(curLipLine)].numPhonemes) &&
|
||||
((_G(curLipLinePhoneme) < 0) || (voice_pos_ms >= _GP(splipsync)[_G(curLipLine)].endtimeoffs[_G(curLipLinePhoneme)]))) {
|
||||
_G(curLipLinePhoneme)++;
|
||||
if (_G(curLipLinePhoneme) >= _GP(splipsync)[_G(curLipLine)].numPhonemes)
|
||||
_G(facetalkframe) = _GP(game).default_lipsync_frame;
|
||||
else
|
||||
_G(facetalkframe) = _GP(splipsync)[_G(curLipLine)].frame[_G(curLipLinePhoneme)];
|
||||
|
||||
if (_G(facetalkframe) >= _GP(views)[_G(facetalkview)].loops[_G(facetalkloop)].numFrames)
|
||||
_G(facetalkframe) = 0;
|
||||
|
||||
updatedFrame |= 1;
|
||||
}
|
||||
}
|
||||
} else if (_G(facetalkwait) > 0) _G(facetalkwait)--;
|
||||
// don't animate if the speech has finished
|
||||
else if ((_GP(play).messagetime < 1) && (_G(facetalkframe) == 0) &&
|
||||
// if _GP(play).close_mouth_speech_time = 0, this means animation should play till
|
||||
// the speech ends; but this should not work in voice mode, and also if the
|
||||
// speech is in the "post" state
|
||||
(_GP(play).speech_has_voice || _GP(play).speech_in_post_state || _GP(play).close_mouth_speech_time > 0))
|
||||
;
|
||||
else {
|
||||
// Close mouth at end of sentence: if speech has entered the "post" state,
|
||||
// or if this is a text only mode and close_mouth_speech_time is set
|
||||
if (_GP(play).speech_in_post_state ||
|
||||
(!_GP(play).speech_has_voice &&
|
||||
(_GP(play).messagetime < _GP(play).close_mouth_speech_time) &&
|
||||
(_GP(play).close_mouth_speech_time > 0))) {
|
||||
_G(facetalkframe) = 0;
|
||||
_G(facetalkwait) = _GP(play).messagetime;
|
||||
} else if ((_GP(game).options[OPT_LIPSYNCTEXT]) && (_G(facetalkrepeat) > 0)) {
|
||||
// lip-sync speech (and not a thought)
|
||||
_G(facetalkwait) = update_lip_sync(_G(facetalkview), _G(facetalkloop), &_G(facetalkframe));
|
||||
// It is actually displayed for _G(facetalkwait)+1 loops
|
||||
// (because when it's 1, it gets --'d then wait for next time)
|
||||
_G(facetalkwait)--;
|
||||
} else {
|
||||
// normal non-lip-sync
|
||||
_G(facetalkframe)++;
|
||||
if ((_G(facetalkframe) >= _GP(views)[_G(facetalkview)].loops[_G(facetalkloop)].numFrames) ||
|
||||
(!_GP(play).speech_has_voice && (_GP(play).messagetime < 1) && (_GP(play).close_mouth_speech_time > 0))) {
|
||||
|
||||
if ((_G(facetalkframe) >= _GP(views)[_G(facetalkview)].loops[_G(facetalkloop)].numFrames) &&
|
||||
(_GP(views)[_G(facetalkview)].loops[_G(facetalkloop)].RunNextLoop())) {
|
||||
_G(facetalkloop)++;
|
||||
} else {
|
||||
_G(facetalkloop) = 0;
|
||||
}
|
||||
_G(facetalkframe) = 0;
|
||||
if (!_G(facetalkrepeat))
|
||||
_G(facetalkwait) = 999999;
|
||||
}
|
||||
if ((_G(facetalkframe) != 0) || (_G(facetalkrepeat) == 1))
|
||||
_G(facetalkwait) = _GP(views)[_G(facetalkview)].loops[_G(facetalkloop)].frames[_G(facetalkframe)].speed + GetCharacterSpeechAnimationDelay(_G(facetalkchar));
|
||||
}
|
||||
updatedFrame |= 1;
|
||||
}
|
||||
|
||||
// _G(is_text_overlay) might be 0 if it was only just destroyed this loop
|
||||
if ((updatedFrame) && (_GP(play).text_overlay_on > 0)) {
|
||||
|
||||
const auto &talking_chex = _GP(charextra)[_G(facetalkchar)->index_id];
|
||||
const int frame_vol = talking_chex.GetFrameSoundVolume(_G(facetalkchar));
|
||||
if (updatedFrame & 1)
|
||||
CheckViewFrame(_G(facetalkview), _G(facetalkloop), _G(facetalkframe), frame_vol);
|
||||
if (updatedFrame & 2)
|
||||
CheckViewFrame(_G(facetalkchar)->blinkview, _G(facetalkBlinkLoop), _G(facetalkchar)->blinkframe, frame_vol);
|
||||
|
||||
int thisPic = _GP(views)[_G(facetalkview)].loops[_G(facetalkloop)].frames[_G(facetalkframe)].pic;
|
||||
int view_frame_x = 0;
|
||||
int view_frame_y = 0;
|
||||
|
||||
auto *face_over = get_overlay(_G(face_talking));
|
||||
assert(face_over != nullptr);
|
||||
Bitmap *frame_pic = _GP(spriteset)[face_over->GetSpriteNum()];
|
||||
if (_GP(game).options[OPT_SPEECHTYPE] == 3) {
|
||||
// QFG4-style fullscreen dialog
|
||||
if (_G(facetalk_qfg4_override_placement_x)) {
|
||||
view_frame_x = _GP(play).speech_portrait_x;
|
||||
}
|
||||
if (_G(facetalk_qfg4_override_placement_y)) {
|
||||
view_frame_y = _GP(play).speech_portrait_y;
|
||||
} else {
|
||||
view_frame_y = (frame_pic->GetHeight() / 2) - (_GP(game).SpriteInfos[thisPic].Height / 2);
|
||||
}
|
||||
frame_pic->Clear(0);
|
||||
} else {
|
||||
frame_pic->ClearTransparent();
|
||||
}
|
||||
|
||||
const ViewFrame *face_vf = &_GP(views)[_G(facetalkview)].loops[_G(facetalkloop)].frames[_G(facetalkframe)];
|
||||
bool face_has_alpha = (_GP(game).SpriteInfos[face_vf->pic].Flags & SPF_ALPHACHANNEL) != 0;
|
||||
DrawViewFrame(frame_pic, face_vf, view_frame_x, view_frame_y);
|
||||
|
||||
if ((_G(facetalkchar)->blinkview > 0) && (_G(facetalkchar)->blinktimer < 0)) {
|
||||
ViewFrame *blink_vf = &_GP(views)[_G(facetalkchar)->blinkview].loops[_G(facetalkBlinkLoop)].frames[_G(facetalkchar)->blinkframe];
|
||||
face_has_alpha |= (_GP(game).SpriteInfos[blink_vf->pic].Flags & SPF_ALPHACHANNEL) != 0;
|
||||
// draw the blinking sprite on top
|
||||
DrawViewFrame(frame_pic, blink_vf, view_frame_x, view_frame_y, face_has_alpha);
|
||||
}
|
||||
|
||||
face_over->SetAlphaChannel(face_has_alpha);
|
||||
face_over->MarkChanged();
|
||||
} // end if updatedFrame
|
||||
}
|
||||
}
|
||||
|
||||
// update_stuff: moves and animates objects, executes repeat scripts, and
|
||||
// the like.
|
||||
void update_stuff() {
|
||||
|
||||
set_our_eip(20);
|
||||
|
||||
update_script_timers();
|
||||
|
||||
update_cycling_views();
|
||||
|
||||
set_our_eip(21);
|
||||
|
||||
update_player_view();
|
||||
|
||||
set_our_eip(22);
|
||||
|
||||
std::vector<int> followingAsSheep;
|
||||
|
||||
update_character_move_and_anim(followingAsSheep);
|
||||
|
||||
update_following_exactly_characters(followingAsSheep);
|
||||
|
||||
set_our_eip(23);
|
||||
|
||||
update_overlay_timers();
|
||||
|
||||
update_speech_and_messages();
|
||||
|
||||
set_our_eip(24);
|
||||
|
||||
update_sierra_speech();
|
||||
|
||||
set_our_eip(25);
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
40
engines/ags/engine/main/update.h
Normal file
40
engines/ags/engine/main/update.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_ENGINE_MAIN_UPDATE_H
|
||||
#define AGS_ENGINE_MAIN_UPDATE_H
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
// Update MoveList of certain index, save current position;
|
||||
// *resets* mslot to zero if path is complete.
|
||||
// returns "need_to_fix_sprite" value, which may be 0,1,2;
|
||||
// TODO: find out what this return value means, and refactor.
|
||||
// TODO: do not reset mslot in this function, reset externally instead.
|
||||
int do_movelist_move(short &mslot, int &pos_x, int &pos_y);
|
||||
// Recalculate derived (non-serialized) values in movelists
|
||||
void restore_movelists();
|
||||
// Update various things on the game frame (historical code mess...)
|
||||
void update_stuff();
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user