aboutsummaryrefslogtreecommitdiff
path: root/libs/game_bethesda/src/games/fallout3
diff options
context:
space:
mode:
authorSulfurNitride <SulfurNitride@users.noreply.github.com>2026-02-11 02:37:39 -0600
committerSulfurNitride <SulfurNitride@users.noreply.github.com>2026-02-11 02:37:39 -0600
commit7ee008e150bc5bcf76082d726f719ee0fdfda982 (patch)
tree27fb39be241fdb5ac2734c574de678977d1856d0 /libs/game_bethesda/src/games/fallout3
Fluorine Manager: full Linux port of Mod Organizer 2
Complete native Linux port with FUSE-based virtual filesystem, Proton/umu-run integration, and Flatpak packaging. Key features: - FUSE VFS replacing Windows USVFS (in-process + standalone helper for Flatpak) - Proton/GE-Proton/umu-run launcher with env var forwarding - Flatpak support (sandbox-aware VFS, NXM handler, umu-run) - Wine prefix management UI - Case-insensitive path resolution for Linux filesystems - QSettings-safe INI handling (avoids Bethesda INI corruption) - Portable instance support with auto-generated launcher scripts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'libs/game_bethesda/src/games/fallout3')
-rw-r--r--libs/game_bethesda/src/games/fallout3/CMakeLists.txt20
-rw-r--r--libs/game_bethesda/src/games/fallout3/fallout3bsainvalidation.cpp16
-rw-r--r--libs/game_bethesda/src/games/fallout3/fallout3bsainvalidation.h20
-rw-r--r--libs/game_bethesda/src/games/fallout3/fallout3dataarchives.cpp33
-rw-r--r--libs/game_bethesda/src/games/fallout3/fallout3dataarchives.h20
-rw-r--r--libs/game_bethesda/src/games/fallout3/fallout3moddatachecker.h31
-rw-r--r--libs/game_bethesda/src/games/fallout3/fallout3moddatacontent.h22
-rw-r--r--libs/game_bethesda/src/games/fallout3/fallout3savegame.cpp72
-rw-r--r--libs/game_bethesda/src/games/fallout3/fallout3savegame.h23
-rw-r--r--libs/game_bethesda/src/games/fallout3/fallout3scriptextender.cpp18
-rw-r--r--libs/game_bethesda/src/games/fallout3/fallout3scriptextender.h17
-rw-r--r--libs/game_bethesda/src/games/fallout3/game_fallout3_en.ts17
-rw-r--r--libs/game_bethesda/src/games/fallout3/gamefallout3.cpp279
-rw-r--r--libs/game_bethesda/src/games/fallout3/gamefallout3.h58
-rw-r--r--libs/game_bethesda/src/games/fallout3/gamefallout3.json1
15 files changed, 647 insertions, 0 deletions
diff --git a/libs/game_bethesda/src/games/fallout3/CMakeLists.txt b/libs/game_bethesda/src/games/fallout3/CMakeLists.txt
new file mode 100644
index 0000000..3db9758
--- /dev/null
+++ b/libs/game_bethesda/src/games/fallout3/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.16)
+
+add_library(game_fallout3 SHARED
+ fallout3bsainvalidation.cpp
+ fallout3bsainvalidation.h
+ fallout3dataarchives.cpp
+ fallout3dataarchives.h
+ fallout3moddatachecker.h
+ fallout3moddatacontent.h
+ fallout3savegame.cpp
+ fallout3savegame.h
+ fallout3scriptextender.cpp
+ fallout3scriptextender.h
+ gamefallout3.cpp
+ gamefallout3.h
+)
+mo2_configure_plugin(game_fallout3 NO_SOURCES WARNINGS 4)
+mo2_default_source_group()
+target_link_libraries(game_fallout3 PRIVATE game_gamebryo)
+mo2_install_plugin(game_fallout3)
diff --git a/libs/game_bethesda/src/games/fallout3/fallout3bsainvalidation.cpp b/libs/game_bethesda/src/games/fallout3/fallout3bsainvalidation.cpp
new file mode 100644
index 0000000..ce981fb
--- /dev/null
+++ b/libs/game_bethesda/src/games/fallout3/fallout3bsainvalidation.cpp
@@ -0,0 +1,16 @@
+#include "fallout3bsainvalidation.h"
+
+Fallout3BSAInvalidation::Fallout3BSAInvalidation(MOBase::DataArchives* dataArchives,
+ MOBase::IPluginGame const* game)
+ : GamebryoBSAInvalidation(dataArchives, "fallout.ini", game)
+{}
+
+QString Fallout3BSAInvalidation::invalidationBSAName() const
+{
+ return "Fallout - Invalidation.bsa";
+}
+
+unsigned long Fallout3BSAInvalidation::bsaVersion() const
+{
+ return 0x68;
+}
diff --git a/libs/game_bethesda/src/games/fallout3/fallout3bsainvalidation.h b/libs/game_bethesda/src/games/fallout3/fallout3bsainvalidation.h
new file mode 100644
index 0000000..f836073
--- /dev/null
+++ b/libs/game_bethesda/src/games/fallout3/fallout3bsainvalidation.h
@@ -0,0 +1,20 @@
+#ifndef FALLOUT3BSAINVALIDATION_H
+#define FALLOUT3BSAINVALIDATION_H
+
+#include "fallout3dataarchives.h"
+#include "gamebryobsainvalidation.h"
+
+#include <memory>
+
+class Fallout3BSAInvalidation : public GamebryoBSAInvalidation
+{
+public:
+ Fallout3BSAInvalidation(MOBase::DataArchives* dataArchives,
+ MOBase::IPluginGame const* game);
+
+private:
+ virtual QString invalidationBSAName() const override;
+ virtual unsigned long bsaVersion() const override;
+};
+
+#endif // FALLOUT3BSAINVALIDATION_H
diff --git a/libs/game_bethesda/src/games/fallout3/fallout3dataarchives.cpp b/libs/game_bethesda/src/games/fallout3/fallout3dataarchives.cpp
new file mode 100644
index 0000000..ed6627b
--- /dev/null
+++ b/libs/game_bethesda/src/games/fallout3/fallout3dataarchives.cpp
@@ -0,0 +1,33 @@
+#include "fallout3dataarchives.h"
+
+#include "iprofile.h"
+#include <utility.h>
+
+QStringList Fallout3DataArchives::vanillaArchives() const
+{
+ return {"Fallout - Textures.bsa", "Fallout - Meshes.bsa", "Fallout - Voices.bsa",
+ "Fallout - Sound.bsa", "Fallout - MenuVoices.bsa", "Fallout - Misc.bsa"};
+}
+
+QStringList Fallout3DataArchives::archives(const MOBase::IProfile* profile) const
+{
+ QStringList result;
+
+ QString iniFile = profile->localSettingsEnabled()
+ ? QDir(profile->absolutePath()).absoluteFilePath("fallout.ini")
+ : localGameDirectory().absoluteFilePath("fallout.ini");
+ result.append(getArchivesFromKey(iniFile, "SArchiveList"));
+
+ return result;
+}
+
+void Fallout3DataArchives::writeArchiveList(MOBase::IProfile* profile,
+ const QStringList& before)
+{
+ QString list = before.join(", ");
+
+ QString iniFile = profile->localSettingsEnabled()
+ ? QDir(profile->absolutePath()).absoluteFilePath("fallout.ini")
+ : localGameDirectory().absoluteFilePath("fallout.ini");
+ setArchivesToKey(iniFile, "SArchiveList", list);
+}
diff --git a/libs/game_bethesda/src/games/fallout3/fallout3dataarchives.h b/libs/game_bethesda/src/games/fallout3/fallout3dataarchives.h
new file mode 100644
index 0000000..8ba4561
--- /dev/null
+++ b/libs/game_bethesda/src/games/fallout3/fallout3dataarchives.h
@@ -0,0 +1,20 @@
+#ifndef FALLOUT3DATAARCHIVES_H
+#define FALLOUT3DATAARCHIVES_H
+
+#include "gamebryodataarchives.h"
+#include <QDir>
+
+class Fallout3DataArchives : public GamebryoDataArchives
+{
+public:
+ using GamebryoDataArchives::GamebryoDataArchives;
+
+ virtual QStringList vanillaArchives() const override;
+ virtual QStringList archives(const MOBase::IProfile* profile) const override;
+
+private:
+ virtual void writeArchiveList(MOBase::IProfile* profile,
+ const QStringList& before) override;
+};
+
+#endif // FALLOUT3DATAARCHIVES_H
diff --git a/libs/game_bethesda/src/games/fallout3/fallout3moddatachecker.h b/libs/game_bethesda/src/games/fallout3/fallout3moddatachecker.h
new file mode 100644
index 0000000..0051137
--- /dev/null
+++ b/libs/game_bethesda/src/games/fallout3/fallout3moddatachecker.h
@@ -0,0 +1,31 @@
+#ifndef FALLOUT3_MODATACHECKER_H
+#define FALLOUT3_MODATACHECKER_H
+
+#include <gamebryomoddatachecker.h>
+
+class Fallout3ModDataChecker : public GamebryoModDataChecker
+{
+public:
+ using GamebryoModDataChecker::GamebryoModDataChecker;
+
+protected:
+ virtual const FileNameSet& possibleFolderNames() const override
+ {
+ static FileNameSet result{
+ "fonts", "interface", "menus", "meshes",
+ "music", "scripts", "shaders", "sound",
+ "strings", "textures", "trees", "video",
+ "facegen", "materials", "fose", "distantlod",
+ "asi", "Tools", "MCM", "distantland",
+ "mits", "dllplugins", "CalienteTools", "NetScriptFramework",
+ "shadersfx"};
+ return result;
+ }
+ virtual const FileNameSet& possibleFileExtensions() const override
+ {
+ static FileNameSet result{"esp", "esm", "bsa", "modgroups", "ini"};
+ return result;
+ }
+};
+
+#endif // FALLOUT3_MODATACHECKER_H
diff --git a/libs/game_bethesda/src/games/fallout3/fallout3moddatacontent.h b/libs/game_bethesda/src/games/fallout3/fallout3moddatacontent.h
new file mode 100644
index 0000000..bc314a9
--- /dev/null
+++ b/libs/game_bethesda/src/games/fallout3/fallout3moddatacontent.h
@@ -0,0 +1,22 @@
+#ifndef FALLOUT3_MODDATACONTENT_H
+#define FALLOUT3_MODDATACONTENT_H
+
+#include <gamebryomoddatacontent.h>
+#include <ifiletree.h>
+
+class Fallout3ModDataContent : public GamebryoModDataContent
+{
+public:
+ /**
+ *
+ */
+ Fallout3ModDataContent(MOBase::IGameFeatures const* gameFeatures)
+ : GamebryoModDataContent(gameFeatures)
+ {
+ // Just need to disable some contents:
+ m_Enabled[CONTENT_MCM] = false;
+ m_Enabled[CONTENT_SKYPROC] = false;
+ }
+};
+
+#endif // FALLOUT3_MODDATACONTENT_H
diff --git a/libs/game_bethesda/src/games/fallout3/fallout3savegame.cpp b/libs/game_bethesda/src/games/fallout3/fallout3savegame.cpp
new file mode 100644
index 0000000..aa9bcde
--- /dev/null
+++ b/libs/game_bethesda/src/games/fallout3/fallout3savegame.cpp
@@ -0,0 +1,72 @@
+#include "fallout3savegame.h"
+
+#include "gamefallout3.h"
+
+Fallout3SaveGame::Fallout3SaveGame(QString const& fileName, GameFallout3 const* game)
+ : GamebryoSaveGame(fileName, game)
+{
+ FileWrapper file(getFilepath(), "FO3SAVEGAME");
+
+ uint32_t width, height;
+ fetchInformationFields(file, width, height, m_SaveNumber, m_PCName, m_PCLevel,
+ m_PCLocation);
+}
+
+void Fallout3SaveGame::fetchInformationFields(FileWrapper& file, uint32_t& width,
+ uint32_t& height,
+ uint32_t& saveNumber,
+ QString& playerName,
+ unsigned short& playerLevel,
+ QString& playerLocation) const
+{
+ file.skip<uint32_t>(); // Save header size
+
+ file.setHasFieldMarkers(true);
+ file.setPluginString(GamebryoSaveGame::StringType::TYPE_BZSTRING);
+
+ file.skip<uint32_t>(); // File version ?
+ file.skip<unsigned char>(); // delimiter
+
+ file.read(width);
+ file.read(height);
+ file.read(saveNumber);
+ file.read(playerName);
+
+ QString whatthis;
+ file.read(whatthis);
+
+ long level;
+ file.read(level);
+ playerLevel = level;
+
+ file.read(playerLocation);
+}
+
+std::unique_ptr<GamebryoSaveGame::DataFields> Fallout3SaveGame::fetchDataFields() const
+{
+ FileWrapper file(getFilepath(), "FO3SAVEGAME");
+
+ std::unique_ptr<DataFields> fields = std::make_unique<DataFields>();
+
+ uint32_t width, height;
+ {
+ QString dummyName, dummyLocation;
+ unsigned short dummyLevel;
+ uint32_t dummySaveNumber;
+
+ fetchInformationFields(file, width, height, dummySaveNumber, dummyName, dummyLevel,
+ dummyLocation);
+ }
+
+ QString playtime;
+ file.read(playtime);
+
+ fields->Screenshot = file.readImage(width, height, 256);
+
+ file.skip<char>(5); // unknown (1 byte), plugin size (4 bytes)
+
+ file.setPluginString(GamebryoSaveGame::StringType::TYPE_BSTRING);
+ fields->Plugins = file.readPlugins();
+
+ return fields;
+}
diff --git a/libs/game_bethesda/src/games/fallout3/fallout3savegame.h b/libs/game_bethesda/src/games/fallout3/fallout3savegame.h
new file mode 100644
index 0000000..2a33037
--- /dev/null
+++ b/libs/game_bethesda/src/games/fallout3/fallout3savegame.h
@@ -0,0 +1,23 @@
+#ifndef FALLOUT3SAVEGAME_H
+#define FALLOUT3SAVEGAME_H
+
+#include "gamebryosavegame.h"
+
+class GameFallout3;
+
+class Fallout3SaveGame : public GamebryoSaveGame
+{
+public:
+ Fallout3SaveGame(QString const& fileName, GameFallout3 const* game);
+
+protected:
+ // Fetch easy-to-access information.
+ void fetchInformationFields(FileWrapper& wrapper, uint32_t& width,
+ uint32_t& height, uint32_t& saveNumber,
+ QString& playerName, unsigned short& playerLevel,
+ QString& playerLocation) const;
+
+ std::unique_ptr<DataFields> fetchDataFields() const override;
+};
+
+#endif // FALLOUT3SAVEGAME_H
diff --git a/libs/game_bethesda/src/games/fallout3/fallout3scriptextender.cpp b/libs/game_bethesda/src/games/fallout3/fallout3scriptextender.cpp
new file mode 100644
index 0000000..608a305
--- /dev/null
+++ b/libs/game_bethesda/src/games/fallout3/fallout3scriptextender.cpp
@@ -0,0 +1,18 @@
+#include "fallout3scriptextender.h"
+
+#include <QString>
+#include <QStringList>
+
+Fallout3ScriptExtender::Fallout3ScriptExtender(GameGamebryo const* game)
+ : GamebryoScriptExtender(game)
+{}
+
+QString Fallout3ScriptExtender::BinaryName() const
+{
+ return "fose_loader.exe";
+}
+
+QString Fallout3ScriptExtender::PluginPath() const
+{
+ return "fose/plugins";
+}
diff --git a/libs/game_bethesda/src/games/fallout3/fallout3scriptextender.h b/libs/game_bethesda/src/games/fallout3/fallout3scriptextender.h
new file mode 100644
index 0000000..1769d6b
--- /dev/null
+++ b/libs/game_bethesda/src/games/fallout3/fallout3scriptextender.h
@@ -0,0 +1,17 @@
+#ifndef FALLOUT3SCRIPTEXTENDER_H
+#define FALLOUT3SCRIPTEXTENDER_H
+
+#include "gamebryoscriptextender.h"
+
+class GameGamebryo;
+
+class Fallout3ScriptExtender : public GamebryoScriptExtender
+{
+public:
+ Fallout3ScriptExtender(GameGamebryo const* game);
+
+ virtual QString BinaryName() const override;
+ virtual QString PluginPath() const override;
+};
+
+#endif // FALLOUT3SCRIPTEXTENDER_H
diff --git a/libs/game_bethesda/src/games/fallout3/game_fallout3_en.ts b/libs/game_bethesda/src/games/fallout3/game_fallout3_en.ts
new file mode 100644
index 0000000..5b90534
--- /dev/null
+++ b/libs/game_bethesda/src/games/fallout3/game_fallout3_en.ts
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="en_US">
+<context>
+ <name>GameFallout3</name>
+ <message>
+ <location filename="gamefallout3.cpp" line="138"/>
+ <source>Fallout 3 Support Plugin</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="gamefallout3.cpp" line="148"/>
+ <source>Adds support for the game Fallout 3.</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+</TS>
diff --git a/libs/game_bethesda/src/games/fallout3/gamefallout3.cpp b/libs/game_bethesda/src/games/fallout3/gamefallout3.cpp
new file mode 100644
index 0000000..f2f4562
--- /dev/null
+++ b/libs/game_bethesda/src/games/fallout3/gamefallout3.cpp
@@ -0,0 +1,279 @@
+#include "gamefallout3.h"
+
+#include "fallout3bsainvalidation.h"
+#include "fallout3dataarchives.h"
+#include "fallout3moddatachecker.h"
+#include "fallout3moddatacontent.h"
+#include "fallout3savegame.h"
+#include "fallout3scriptextender.h"
+
+#include "executableinfo.h"
+#include "pluginsetting.h"
+#include "versioninfo.h"
+#include <gamebryogameplugins.h>
+#include <gamebryolocalsavegames.h>
+#include <gamebryosavegameinfo.h>
+#include <gamebryounmanagedmods.h>
+
+#include <QCoreApplication>
+#include <QDir>
+#include <QFileInfo>
+#include <QList>
+#include <QObject>
+#include <QString>
+#include <QStringList>
+
+#include <memory>
+
+using namespace MOBase;
+
+GameFallout3::GameFallout3() {}
+
+bool GameFallout3::init(IOrganizer* moInfo)
+{
+ if (!GameGamebryo::init(moInfo)) {
+ return false;
+ }
+
+ auto dataArchives = std::make_shared<Fallout3DataArchives>(this);
+ registerFeature(std::make_shared<Fallout3ScriptExtender>(this));
+ registerFeature(dataArchives);
+ registerFeature(std::make_shared<Fallout3BSAInvalidation>(dataArchives.get(), this));
+ registerFeature(std::make_shared<GamebryoSaveGameInfo>(this));
+ registerFeature(std::make_shared<GamebryoLocalSavegames>(this, "fallout.ini"));
+ registerFeature(std::make_shared<Fallout3ModDataChecker>(this));
+ registerFeature(
+ std::make_shared<Fallout3ModDataContent>(m_Organizer->gameFeatures()));
+ registerFeature(std::make_shared<GamebryoGamePlugins>(moInfo));
+ registerFeature(std::make_shared<GamebryoUnmangedMods>(this));
+ return true;
+}
+
+QString GameFallout3::identifyVariant() const
+{
+ if (QFile::exists(m_GamePath + "/Fallout3ng.exe")) {
+ return "Low Violence";
+ } else if (QFile::exists(m_GamePath + "/Galaxy.dll")) {
+ return "GOG";
+ } else if (QFile::exists(m_GamePath + "/FalloutLauncherEpic.exe")) {
+ return "Epic Games";
+ } else if (m_GamePath.endsWith("Fallout 3 goty")) {
+ return "Steam (Game of the Year)";
+ } else {
+ return "Steam (Regular)";
+ }
+}
+
+QString GameFallout3::identifyGamePath() const
+{
+ // Steam (Regular)
+ auto result = parseSteamLocation("22300", "Fallout 3");
+
+ // Steam (Game of the Year)
+ if (result.isEmpty()) {
+ result = parseSteamLocation("22370", "Fallout 3 goty");
+ }
+
+ // Epic Games
+ if (result.isEmpty()) {
+ // Fallout 3: Game of the Year Edition: adeae8bbfc94427db57c7dfecce3f1d4
+ result = parseEpicGamesLocation({"adeae8bbfc94427db57c7dfecce3f1d4"});
+ if (QFileInfo(result).isDir()) {
+ QDir startPath = QDir(result);
+ auto subDirs =
+ startPath.entryList({"Fallout 3 GOTY*"}, QDir::Dirs | QDir::NoDotAndDotDot);
+ if (!subDirs.isEmpty())
+ result = startPath.absoluteFilePath(subDirs.first());
+ }
+ }
+
+ // GOG (and Steam)
+ if (result.isEmpty()) {
+ result = GameGamebryo::identifyGamePath();
+ }
+
+ return result;
+}
+
+QString GameFallout3::gameName() const
+{
+ return "Fallout 3";
+}
+
+void GameFallout3::detectGame()
+{
+ m_GamePath = identifyGamePath();
+ setGameVariant(identifyVariant());
+ m_MyGamesPath = determineMyGamesPath("Fallout3");
+}
+
+QList<ExecutableInfo> GameFallout3::executables() const
+{
+ return QList<ExecutableInfo>()
+ << ExecutableInfo("FOSE",
+ findInGameFolder(m_Organizer->gameFeatures()
+ ->gameFeature<MOBase::ScriptExtender>()
+ ->loaderName()))
+ << ExecutableInfo("Fallout 3", findInGameFolder(binaryName()))
+ << ExecutableInfo("Fallout Mod Manager", findInGameFolder("fomm/fomm.exe"))
+ << ExecutableInfo("Construction Kit", findInGameFolder("geck.exe"))
+ << ExecutableInfo("Fallout Launcher", findInGameFolder(getLauncherName()))
+ << ExecutableInfo("BOSS", findInGameFolder("BOSS/BOSS.exe"))
+ << ExecutableInfo("LOOT", QFileInfo(getLootPath()))
+ .withArgument("--game=\"Fallout3\"");
+}
+
+QList<ExecutableForcedLoadSetting> GameFallout3::executableForcedLoads() const
+{
+ return QList<ExecutableForcedLoadSetting>();
+}
+
+QString GameFallout3::name() const
+{
+ return "Fallout 3 Support Plugin";
+}
+
+QString GameFallout3::localizedName() const
+{
+ return tr("Fallout 3 Support Plugin");
+}
+
+QString GameFallout3::author() const
+{
+ return "Tannin";
+}
+
+QString GameFallout3::description() const
+{
+ return tr("Adds support for the game Fallout 3.");
+}
+
+MOBase::VersionInfo GameFallout3::version() const
+{
+ return VersionInfo(1, 4, 1, VersionInfo::RELEASE_FINAL);
+}
+
+QList<PluginSetting> GameFallout3::settings() const
+{
+ return QList<PluginSetting>();
+}
+
+void GameFallout3::initializeProfile(const QDir& path, ProfileSettings settings) const
+{
+ if (settings.testFlag(IPluginGame::MODS)) {
+ copyToProfile(localAppFolder() + "/Fallout3", path, "plugins.txt");
+ copyToProfile(localAppFolder() + "/Fallout3", path, "loadorder.txt");
+ }
+
+ if (settings.testFlag(IPluginGame::CONFIGURATION)) {
+ if (settings.testFlag(IPluginGame::PREFER_DEFAULTS) ||
+ !QFileInfo(myGamesPath(), "fallout.ini").exists()) {
+ copyToProfile(gameDirectory().absolutePath(), path, "fallout_default.ini",
+ "fallout.ini");
+ } else {
+ copyToProfile(myGamesPath(), path, "fallout.ini");
+ }
+
+ copyToProfile(myGamesPath(), path, "falloutprefs.ini");
+ copyToProfile(myGamesPath(), path, "FalloutCustom.ini");
+ copyToProfile(myGamesPath(), path, "custom.ini");
+ copyToProfile(myGamesPath(), path, "GECKCustom.ini");
+ copyToProfile(myGamesPath(), path, "GECKPrefs.ini");
+ }
+}
+
+QString GameFallout3::savegameExtension() const
+{
+ return "fos";
+}
+
+QString GameFallout3::savegameSEExtension() const
+{
+ return "";
+}
+
+std::shared_ptr<const GamebryoSaveGame>
+GameFallout3::makeSaveGame(QString filePath) const
+{
+ return std::make_shared<const Fallout3SaveGame>(filePath, this);
+}
+
+QString GameFallout3::steamAPPId() const
+{
+ if (selectedVariant() == "Steam (Game Of The Year)") {
+ return "22370";
+ } else if (selectedVariant() == "Steam (Regular)") {
+ return "22300";
+ } else {
+ return "";
+ }
+}
+
+QStringList GameFallout3::primaryPlugins() const
+{
+ return {"fallout3.esm"};
+}
+
+QStringList GameFallout3::gameVariants() const
+{
+ return {"Steam (Regular)", "Steam (Game Of The Year)", "Epic Games", "GOG",
+ "Low Violence"};
+}
+
+QString GameFallout3::binaryName() const
+{
+ if (selectedVariant() == "Low Violence") {
+ return "Fallout3ng.exe";
+ } else {
+ return GameGamebryo::binaryName();
+ }
+}
+
+QString GameFallout3::gameShortName() const
+{
+ return "Fallout3";
+}
+
+QStringList GameFallout3::validShortNames() const
+{
+ return {"FalloutNV"};
+}
+
+QString GameFallout3::gameNexusName() const
+{
+ return "fallout3";
+}
+
+QStringList GameFallout3::iniFiles() const
+{
+ return {"fallout.ini", "falloutprefs.ini", "FalloutCustom.ini", "GECKCustom.ini",
+ "GECKPrefs.ini"};
+}
+
+QStringList GameFallout3::DLCPlugins() const
+{
+ return {"ThePitt.esm", "Anchorage.esm", "BrokenSteel.esm", "PointLookout.esm",
+ "Zeta.esm"};
+}
+
+int GameFallout3::nexusModOrganizerID() const
+{
+ return 16348;
+}
+
+int GameFallout3::nexusGameID() const
+{
+ return 120;
+}
+
+QString GameFallout3::getLauncherName() const
+{
+ const QMap<QString, QString> names = {
+ {"Steam (Regular)", "Fallout3Launcher.exe"},
+ {"Steam (Game of the Year)", "Fallout3Launcher.exe"},
+ {"Epic Games", "FalloutLauncherEpic.exe"},
+ {"GOG", "FalloutLauncher.exe"},
+ {"Low Violence", "Fallout3Launcher.exe"}};
+
+ return names.value(selectedVariant());
+}
diff --git a/libs/game_bethesda/src/games/fallout3/gamefallout3.h b/libs/game_bethesda/src/games/fallout3/gamefallout3.h
new file mode 100644
index 0000000..a6dce27
--- /dev/null
+++ b/libs/game_bethesda/src/games/fallout3/gamefallout3.h
@@ -0,0 +1,58 @@
+#ifndef GAMEFALLOUT3_H
+#define GAMEFALLOUT3_H
+
+#include "gamegamebryo.h"
+
+#include <QObject>
+#include <QtGlobal>
+
+class GameFallout3 : public GameGamebryo
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.tannin.GameFallout3" FILE "gamefallout3.json")
+
+public:
+ GameFallout3();
+
+ virtual bool init(MOBase::IOrganizer* moInfo) override;
+
+public: // IPluginGame interface
+ virtual QString gameName() const override;
+ virtual void detectGame() override;
+ virtual QList<MOBase::ExecutableInfo> executables() const override;
+ virtual QList<MOBase::ExecutableForcedLoadSetting>
+ executableForcedLoads() const override;
+ virtual void initializeProfile(const QDir& path,
+ ProfileSettings settings) const override;
+ virtual QString steamAPPId() const override;
+ virtual QStringList primaryPlugins() const override;
+ virtual QStringList gameVariants() const;
+ QString binaryName() const override;
+ virtual QString gameShortName() const override;
+ virtual QStringList validShortNames() const override;
+ virtual QString gameNexusName() const override;
+ virtual QString getLauncherName() const override;
+ virtual QStringList iniFiles() const override;
+ virtual QStringList DLCPlugins() const override;
+ virtual int nexusModOrganizerID() const override;
+ virtual int nexusGameID() const override;
+
+public: // IPlugin interface
+ virtual QString name() const override;
+ virtual QString localizedName() const override;
+ virtual QString author() const override;
+ virtual QString description() const override;
+ virtual MOBase::VersionInfo version() const override;
+ virtual QList<MOBase::PluginSetting> settings() const override;
+
+protected:
+ virtual QString identifyGamePath() const override;
+ virtual QString savegameExtension() const override;
+ virtual QString savegameSEExtension() const override;
+ std::shared_ptr<const GamebryoSaveGame> makeSaveGame(QString filePath) const override;
+
+private:
+ QString identifyVariant() const;
+};
+
+#endif // GAMEFALLOUT3_H
diff --git a/libs/game_bethesda/src/games/fallout3/gamefallout3.json b/libs/game_bethesda/src/games/fallout3/gamefallout3.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/libs/game_bethesda/src/games/fallout3/gamefallout3.json
@@ -0,0 +1 @@
+{}