diff --git a/include/loot/api.h b/include/loot/api.h index 10b0f6d7..7af09d88 100644 --- a/include/loot/api.h +++ b/include/loot/api.h @@ -246,6 +246,7 @@ extern "C" LOOT_API extern const unsigned int loot_game_tes5; /**< Game code for The Elder Scrolls V: Skyrim. */ LOOT_API extern const unsigned int loot_game_fo3; /**< Game code for Fallout 3. */ LOOT_API extern const unsigned int loot_game_fonv; /**< Game code for Fallout: New Vegas. */ + LOOT_API extern const unsigned int loot_game_fo4; /**< Game code for Fallout: New Vegas. */ /**@}*/ /**********************************************************************//** diff --git a/src/api/api.cpp b/src/api/api.cpp index 002eb6d3..47563d9c 100644 --- a/src/api/api.cpp +++ b/src/api/api.cpp @@ -63,6 +63,7 @@ const unsigned int loot_game_tes4 = loot::Game::tes4; const unsigned int loot_game_tes5 = loot::Game::tes5; const unsigned int loot_game_fo3 = loot::Game::fo3; const unsigned int loot_game_fonv = loot::Game::fonv; +const unsigned int loot_game_fo4 = loot::Game::fo4; // LOOT message types. const unsigned int loot_message_say = loot::Message::say; @@ -243,7 +244,12 @@ LOOT_API unsigned int loot_create_db(loot_db * const db, const unsigned int clientGame, const char * const gamePath, const char * const gameLocalPath) { - if (db == nullptr || (clientGame != loot_game_tes4 && clientGame != loot_game_tes5 && clientGame != loot_game_fo3 && clientGame != loot_game_fonv)) + if (db == nullptr + || (clientGame != loot_game_tes4 + && clientGame != loot_game_tes5 + && clientGame != loot_game_fo3 + && clientGame != loot_game_fonv + && clientGame != loot_game_fo4)) return c_error(loot_error_invalid_args, "Null pointer passed."); //Set the locale to get encoding conversions working correctly. diff --git a/src/backend/game/game.cpp b/src/backend/game/game.cpp index 13bfe6a6..230369e9 100644 --- a/src/backend/game/game.cpp +++ b/src/backend/game/game.cpp @@ -54,7 +54,7 @@ namespace loot { Game::Game(const unsigned int gameCode, const std::string& folder) : GameSettings(gameCode, folder), _pluginsFullyLoaded(false) {} void Game::Init(bool createFolder, const boost::filesystem::path& gameLocalAppData) { - if (Id() != Game::tes4 && Id() != Game::tes5 && Id() != Game::fo3 && Id() != Game::fonv) { + if (Id() != Game::tes4 && Id() != Game::tes5 && Id() != Game::fo3 && Id() != Game::fonv && Id() != Game::fo4) { throw error(error::invalid_args, lc::translate("Invalid game ID supplied.").str()); } diff --git a/src/backend/game/game_settings.cpp b/src/backend/game/game_settings.cpp index fce082a1..3682e9c8 100644 --- a/src/backend/game/game_settings.cpp +++ b/src/backend/game/game_settings.cpp @@ -42,6 +42,7 @@ namespace loot { const unsigned int GameSettings::tes5 = 2; const unsigned int GameSettings::fo3 = 3; const unsigned int GameSettings::fonv = 4; + const unsigned int GameSettings::fo4 = 5; GameSettings::GameSettings() : _id(GameSettings::autodetect) {} @@ -78,6 +79,14 @@ namespace loot { _repositoryURL = "https://github.com/loot/falloutnv.git"; _repositoryBranch = "v0.8"; } + else if (Id() == GameSettings::fo4) { + _name = "Fallout 4"; + _registryKey = "Software\\Bethesda Softworks\\Fallout4\\Installed Path"; + _lootFolderName = "Fallout4"; + _masterFile = "Fallout4.esm"; + _repositoryURL = "https://github.com/loot/fallout4.git"; + _repositoryBranch = "v0.8"; + } if (!folder.empty()) _lootFolderName = folder; @@ -127,8 +136,10 @@ namespace loot { return libespm::GameId::SKYRIM; else if (_id == GameSettings::fo3) return libespm::GameId::FALLOUT3; - else + else if (_id == GameSettings::fonv) return libespm::GameId::FALLOUTNV; + else + return libespm::GameId::FALLOUT4; } string GameSettings::Name() const { @@ -234,6 +245,9 @@ namespace loot { if (find(games.begin(), games.end(), GameSettings(GameSettings::fonv)) == games.end()) games.push_back(GameSettings(GameSettings::fonv)); + if (find(games.begin(), games.end(), GameSettings(GameSettings::fo4)) == games.end()) + games.push_back(GameSettings(GameSettings::fo4)); + // If there were any missing defaults, make sure they're in settings now. settings["games"] = games; diff --git a/src/backend/game/game_settings.h b/src/backend/game/game_settings.h index 635f71fa..a85e8d80 100644 --- a/src/backend/game/game_settings.h +++ b/src/backend/game/game_settings.h @@ -71,6 +71,7 @@ namespace loot { static const unsigned int tes5; static const unsigned int fo3; static const unsigned int fonv; + static const unsigned int fo4; private: unsigned int _id; std::string _name; @@ -122,6 +123,8 @@ namespace YAML { rhs = loot::GameSettings(loot::GameSettings::fo3, node["folder"].as()); else if (node["type"].as() == loot::GameSettings(loot::GameSettings::fonv).FolderName()) rhs = loot::GameSettings(loot::GameSettings::fonv, node["folder"].as()); + else if (node["type"].as() == loot::GameSettings(loot::GameSettings::fo4).FolderName()) + rhs = loot::GameSettings(loot::GameSettings::fo4, node["folder"].as()); else throw RepresentationException(node.Mark(), "bad conversion: invalid value for 'type' key in 'game settings' object"); diff --git a/src/backend/game/load_order_handler.cpp b/src/backend/game/load_order_handler.cpp index 26950603..a5f3528b 100644 --- a/src/backend/game/load_order_handler.cpp +++ b/src/backend/game/load_order_handler.cpp @@ -45,7 +45,8 @@ namespace loot { if (game.Id() != GameSettings::tes4 && game.Id() != GameSettings::tes5 && game.Id() != GameSettings::fo3 - && game.Id() != GameSettings::fonv) { + && game.Id() != GameSettings::fonv + && game.Id() != GameSettings::fo4) { throw error(error::invalid_args, lc::translate("Unsupported game ID supplied.").str()); } @@ -74,6 +75,8 @@ namespace loot { ret = lo_create_handle(&_gh, LIBLO_GAME_FO3, game.GamePath().string().c_str(), gameLocalDataPath); else if (game.Id() == GameSettings::fonv) ret = lo_create_handle(&_gh, LIBLO_GAME_FNV, game.GamePath().string().c_str(), gameLocalDataPath); + else if (game.Id() == GameSettings::fo4) + ret = lo_create_handle(&_gh, LIBLO_GAME_FO4, game.GamePath().string().c_str(), gameLocalDataPath); else ret = LIBLO_ERROR_INVALID_ARGS; diff --git a/src/backend/plugin/plugin.cpp b/src/backend/plugin/plugin.cpp index 6a9ac204..9c7db7e6 100644 --- a/src/backend/plugin/plugin.cpp +++ b/src/backend/plugin/plugin.cpp @@ -296,7 +296,7 @@ namespace loot { bool Plugin::LoadsBSA(const Game& game) const { if (IsRegexPlugin()) return false; - if (game.Id() == Game::tes5) { + if (game.Id() == Game::tes5 || game.Id() == Game::fo4) { // Skyrim plugins only load BSAs that exactly match their basename. return boost::filesystem::exists(game.DataPath() / (name.substr(0, name.length() - 3) + "bsa")); } diff --git a/src/gui/handler.cpp b/src/gui/handler.cpp index 3d3510f9..6e136107 100644 --- a/src/gui/handler.cpp +++ b/src/gui/handler.cpp @@ -612,6 +612,7 @@ namespace loot { temp.push_back(Game(Game::tes5).FolderName()); temp.push_back(Game(Game::fo3).FolderName()); temp.push_back(Game(Game::fonv).FolderName()); + temp.push_back(Game(Game::fo4).FolderName()); return JSON::stringify(temp); } diff --git a/src/tests/backend/game/test_game_settings.h b/src/tests/backend/game/test_game_settings.h index 79b80623..651cb785 100644 --- a/src/tests/backend/game/test_game_settings.h +++ b/src/tests/backend/game/test_game_settings.h @@ -259,7 +259,8 @@ TEST(GetGameSettings, AllMissing) { loot::GameSettings(loot::GameSettings::tes4), loot::GameSettings(loot::GameSettings::tes5), loot::GameSettings(loot::GameSettings::fo3), - loot::GameSettings(loot::GameSettings::fonv) + loot::GameSettings(loot::GameSettings::fonv), + loot::GameSettings(loot::GameSettings::fo4) }; EXPECT_FALSE(settings["games"]); @@ -271,7 +272,8 @@ TEST(GetGameSettings, MissingFallout3) { std::list initial({ loot::GameSettings(loot::GameSettings::tes4, "folder1"), loot::GameSettings(loot::GameSettings::tes5, "folder2"), - loot::GameSettings(loot::GameSettings::fonv, "folder3") + loot::GameSettings(loot::GameSettings::fonv, "folder3"), + loot::GameSettings(loot::GameSettings::fo4, "folder4") }); YAML::Node settings; @@ -281,6 +283,7 @@ TEST(GetGameSettings, MissingFallout3) { loot::GameSettings(loot::GameSettings::tes4, "folder1"), loot::GameSettings(loot::GameSettings::tes5, "folder2"), loot::GameSettings(loot::GameSettings::fonv, "folder3"), + loot::GameSettings(loot::GameSettings::fo4, "folder4"), loot::GameSettings(loot::GameSettings::fo3) };