/* 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 . * */ #include "ags/shared/ac/character_info.h" #include "ags/shared/ac/game_setup_struct_base.h" #include "ags/shared/ac/game_setup_struct.h" #include "ags/shared/ac/game_version.h" #include "ags/shared/ac/words_dictionary.h" #include "ags/shared/script/cc_script.h" #include "ags/shared/util/stream.h" #include "ags/shared/util/string_utils.h" namespace AGS3 { using namespace AGS::Shared; GameSetupStructBase::GameSetupStructBase() : numviews(0) , numcharacters(0) , playercharacter(-1) , totalscore(0) , numinvitems(0) , numdialog(0) , numdlgmessage(0) , numfonts(0) , color_depth(0) , target_win(0) , dialog_bullet(0) , hotdot(0) , hotdotouter(0) , uniqueid(0) , numgui(0) , numcursors(0) , default_lipsync_frame(0) , invhotdotsprite(0) , dict(nullptr) , _resolutionType(kGameResolution_Undefined) , _dataUpscaleMult(1) , _screenUpscaleMult(1) { memset(options, 0, sizeof(options)); memset(paluses, 0, sizeof(paluses)); memset(defpal, 0, sizeof(defpal)); memset(reserved, 0, sizeof(reserved)); } GameSetupStructBase::~GameSetupStructBase() { Free(); } void GameSetupStructBase::Free() { for (int i = 0; i < MAXGLOBALMES; ++i) { messages[i].Free(); } dict.reset(); chars.clear(); numcharacters = 0; } void GameSetupStructBase::SetDefaultResolution(GameResolutionType type) { SetDefaultResolution(type, Size()); } void GameSetupStructBase::SetDefaultResolution(Size size) { SetDefaultResolution(kGameResolution_Custom, size); } void GameSetupStructBase::SetDefaultResolution(GameResolutionType type, Size size) { // Calculate native res first then remember it SetNativeResolution(type, size); _defGameResolution = _gameResolution; // Setup data resolution according to legacy settings (if set) _dataResolution = _defGameResolution; if (IsLegacyHiRes() && options[OPT_NATIVECOORDINATES] == 0) { _dataResolution = _defGameResolution / HIRES_COORD_MULTIPLIER; } OnResolutionSet(); } void GameSetupStructBase::SetNativeResolution(GameResolutionType type, Size game_res) { if (type == kGameResolution_Custom) { _resolutionType = kGameResolution_Custom; _gameResolution = game_res; _letterboxSize = _gameResolution; } else { _resolutionType = type; _gameResolution = ResolutionTypeToSize(_resolutionType, IsLegacyLetterbox()); _letterboxSize = ResolutionTypeToSize(_resolutionType, false); } } void GameSetupStructBase::SetGameResolution(GameResolutionType type) { SetNativeResolution(type, Size()); OnResolutionSet(); } void GameSetupStructBase::SetGameResolution(Size game_res) { SetNativeResolution(kGameResolution_Custom, game_res); OnResolutionSet(); } void GameSetupStructBase::OnResolutionSet() { // The final data-to-game multiplier is always set after actual game resolution (not default one) if (!_dataResolution.IsNull()) _dataUpscaleMult = _gameResolution.Width / _dataResolution.Width; else _dataUpscaleMult = 1; if (!_defGameResolution.IsNull()) _screenUpscaleMult = _gameResolution.Width / _defGameResolution.Width; else _screenUpscaleMult = 1; _relativeUIMult = IsLegacyHiRes() ? HIRES_COORD_MULTIPLIER : 1; } void GameSetupStructBase::ReadFromFile(Stream *in, GameDataVersion game_ver, SerializeInfo &info) { // NOTE: historically the struct was saved by dumping whole memory // into the file stream, which added padding from memory alignment; // here we mark the padding bytes, as they do not belong to actual data. gamename.ReadCount(in, LEGACY_GAME_NAME_LENGTH); in->ReadInt16(); // alignment padding to int32 (gamename: 50 -> 52 bytes) in->ReadArrayOfInt32(options, MAX_OPTIONS); if (game_ver < kGameVersion_340_4) { // TODO: this should probably be possible to deduce script API level // using game data version and other options like OPT_STRICTSCRIPTING options[OPT_BASESCRIPTAPI] = kScriptAPI_Undefined; options[OPT_SCRIPTCOMPATLEV] = kScriptAPI_Undefined; } in->Read(&paluses[0], sizeof(paluses)); // colors are an array of chars in->Read(&defpal[0], sizeof(defpal)); numviews = in->ReadInt32(); numcharacters = in->ReadInt32(); playercharacter = in->ReadInt32(); totalscore = in->ReadInt32(); numinvitems = in->ReadInt16(); in->ReadInt16(); // alignment padding to int32 numdialog = in->ReadInt32(); numdlgmessage = in->ReadInt32(); numfonts = in->ReadInt32(); color_depth = in->ReadInt32(); target_win = in->ReadInt32(); dialog_bullet = in->ReadInt32(); hotdot = static_cast(in->ReadInt16()); hotdotouter = static_cast(in->ReadInt16()); uniqueid = in->ReadInt32(); numgui = in->ReadInt32(); numcursors = in->ReadInt32(); GameResolutionType resolution_type = (GameResolutionType)in->ReadInt32(); Size game_size; if (resolution_type == kGameResolution_Custom && game_ver >= kGameVersion_330) { game_size.Width = in->ReadInt32(); game_size.Height = in->ReadInt32(); } SetDefaultResolution(resolution_type, game_size); default_lipsync_frame = in->ReadInt32(); invhotdotsprite = in->ReadInt32(); in->ReadArrayOfInt32(reserved, NUM_INTS_RESERVED); info.ExtensionOffset = static_cast(in->ReadInt32()); in->ReadArrayOfInt32(&info.HasMessages.front(), MAXGLOBALMES); info.HasWordsDict = in->ReadInt32() != 0; in->ReadInt32(); // globalscript (dummy 32-bit pointer value) in->ReadInt32(); // chars (dummy 32-bit pointer value) info.HasCCScript = in->ReadInt32() != 0; } void GameSetupStructBase::WriteToFile(Stream *out, const SerializeInfo &info) const { // NOTE: historically the struct was saved by dumping whole memory // into the file stream, which added padding from memory alignment; // here we mark the padding bytes, as they do not belong to actual data. gamename.WriteCount(out, LEGACY_GAME_NAME_LENGTH); out->WriteInt16(0); // alignment padding to int32 out->WriteArrayOfInt32(options, MAX_OPTIONS); out->Write(&paluses[0], sizeof(paluses)); // colors are an array of chars out->Write(&defpal[0], sizeof(defpal)); out->WriteInt32(numviews); out->WriteInt32(numcharacters); out->WriteInt32(playercharacter); out->WriteInt32(totalscore); out->WriteInt16(numinvitems); out->WriteInt16(0); // alignment padding to int32 out->WriteInt32(numdialog); out->WriteInt32(numdlgmessage); out->WriteInt32(numfonts); out->WriteInt32(color_depth); out->WriteInt32(target_win); out->WriteInt32(dialog_bullet); out->WriteInt16(static_cast(hotdot)); out->WriteInt16(static_cast(hotdotouter)); out->WriteInt32(uniqueid); out->WriteInt32(numgui); out->WriteInt32(numcursors); out->WriteInt32(_resolutionType); if (_resolutionType == kGameResolution_Custom) { out->WriteInt32(_defGameResolution.Width); out->WriteInt32(_defGameResolution.Height); } out->WriteInt32(default_lipsync_frame); out->WriteInt32(invhotdotsprite); out->WriteArrayOfInt32(reserved, 17); for (int i = 0; i < MAXGLOBALMES; ++i) { out->WriteInt32(!messages[i].IsEmpty() ? 1 : 0); } out->WriteInt32(dict ? 1 : 0); out->WriteInt32(0); // globalscript (dummy 32-bit pointer value) out->WriteInt32(0); // chars (dummy 32-bit pointer value) out->WriteInt32(info.HasCCScript ? 1 : 0); } Size ResolutionTypeToSize(GameResolutionType resolution, bool letterbox) { switch (resolution) { case kGameResolution_Default: case kGameResolution_320x200: return letterbox ? Size(320, 240) : Size(320, 200); case kGameResolution_320x240: return Size(320, 240); case kGameResolution_640x400: return letterbox ? Size(640, 480) : Size(640, 400); case kGameResolution_640x480: return Size(640, 480); case kGameResolution_800x600: return Size(800, 600); case kGameResolution_1024x768: return Size(1024, 768); case kGameResolution_1280x720: return Size(1280, 720); default: return Size(); } } const char *GetScriptAPIName(ScriptAPIVersion v) { switch (v) { case kScriptAPI_v321: return "v3.2.1"; case kScriptAPI_v330: return "v3.3.0"; case kScriptAPI_v334: return "v3.3.4"; case kScriptAPI_v335: return "v3.3.5"; case kScriptAPI_v340: return "v3.4.0"; case kScriptAPI_v341: return "v3.4.1"; case kScriptAPI_v350: return "v3.5.0-alpha"; case kScriptAPI_v3507: return "v3.5.0-final"; case kScriptAPI_v351: return "v3.5.1"; case kScriptAPI_v360: return "v3.6.0-alpha"; case kScriptAPI_v36026: return "v3.6.0-final"; case kScriptAPI_v361: return "v3.6.1"; default: return "unknown"; } } } // namespace AGS3