From 2ba8f548237a482efcb036858da57898be3bce13 Mon Sep 17 00:00:00 2001 From: Aaron Date: Tue, 19 Nov 2024 22:34:41 -0800 Subject: [PATCH] Added CharacterRaceLibrary. Replaces texture filename generation etc. with library lookup. --- OpenTESArena/CMakeLists.txt | 4 ++ .../src/Entities/CharacterClassLibrary.cpp | 12 ++-- .../src/Entities/CharacterClassLibrary.h | 2 +- .../src/Entities/CharacterRaceDefinition.cpp | 29 ++++++++ .../src/Entities/CharacterRaceDefinition.h | 27 +++++++ .../src/Entities/CharacterRaceLibrary.cpp | 71 +++++++++++++++++++ .../src/Entities/CharacterRaceLibrary.h | 28 ++++++++ OpenTESArena/src/Game/Game.cpp | 2 + .../Interface/CharacterCreationUiModel.cpp | 33 +++------ .../src/Interface/CharacterCreationUiModel.h | 1 - .../src/Interface/CharacterSheetUiModel.cpp | 10 ++- .../src/Interface/CharacterSheetUiView.cpp | 32 ++++++--- .../src/Interface/GameWorldUiView.cpp | 14 +++- 13 files changed, 217 insertions(+), 48 deletions(-) create mode 100644 OpenTESArena/src/Entities/CharacterRaceDefinition.cpp create mode 100644 OpenTESArena/src/Entities/CharacterRaceDefinition.h create mode 100644 OpenTESArena/src/Entities/CharacterRaceLibrary.cpp create mode 100644 OpenTESArena/src/Entities/CharacterRaceLibrary.h diff --git a/OpenTESArena/CMakeLists.txt b/OpenTESArena/CMakeLists.txt index 7d88539ff..e7c7c55b5 100644 --- a/OpenTESArena/CMakeLists.txt +++ b/OpenTESArena/CMakeLists.txt @@ -137,6 +137,10 @@ SET(TES_ENTITIES "${SRC_ROOT}/Entities/CharacterClassDefinition.h" "${SRC_ROOT}/Entities/CharacterClassLibrary.cpp" "${SRC_ROOT}/Entities/CharacterClassLibrary.h" + "${SRC_ROOT}/Entities/CharacterRaceDefinition.cpp" + "${SRC_ROOT}/Entities/CharacterRaceDefinition.h" + "${SRC_ROOT}/Entities/CharacterRaceLibrary.cpp" + "${SRC_ROOT}/Entities/CharacterRaceLibrary.h" "${SRC_ROOT}/Entities/CitizenUtils.cpp" "${SRC_ROOT}/Entities/CitizenUtils.h" "${SRC_ROOT}/Entities/EntityAnimationDefinition.cpp" diff --git a/OpenTESArena/src/Entities/CharacterClassLibrary.cpp b/OpenTESArena/src/Entities/CharacterClassLibrary.cpp index 42d5065ad..ac11e63b6 100644 --- a/OpenTESArena/src/Entities/CharacterClassLibrary.cpp +++ b/OpenTESArena/src/Entities/CharacterClassLibrary.cpp @@ -148,6 +148,12 @@ int CharacterClassLibrary::getDefinitionCount() const return static_cast(this->defs.size()); } +const CharacterClassDefinition &CharacterClassLibrary::getDefinition(int index) const +{ + DebugAssertIndex(this->defs, index); + return this->defs[index]; +} + bool CharacterClassLibrary::findDefinitionIndexIf(const Predicate &predicate, int *outIndex) const { for (int i = 0; i < static_cast(this->defs.size()); i++) @@ -163,12 +169,6 @@ bool CharacterClassLibrary::findDefinitionIndexIf(const Predicate &predicate, in return false; } -const CharacterClassDefinition &CharacterClassLibrary::getDefinition(int index) const -{ - DebugAssertIndex(this->defs, index); - return this->defs[index]; -} - bool CharacterClassLibrary::tryGetDefinitionIndex(const CharacterClassDefinition &def, int *outIndex) const { for (int i = 0; i < static_cast(this->defs.size()); i++) diff --git a/OpenTESArena/src/Entities/CharacterClassLibrary.h b/OpenTESArena/src/Entities/CharacterClassLibrary.h index c9128a6a7..3c4cb4ff4 100644 --- a/OpenTESArena/src/Entities/CharacterClassLibrary.h +++ b/OpenTESArena/src/Entities/CharacterClassLibrary.h @@ -21,8 +21,8 @@ class CharacterClassLibrary : public Singleton void init(const ExeData &exeData); int getDefinitionCount() const; - bool findDefinitionIndexIf(const Predicate &predicate, int *outIndex) const; const CharacterClassDefinition &getDefinition(int index) const; + bool findDefinitionIndexIf(const Predicate &predicate, int *outIndex) const; bool tryGetDefinitionIndex(const CharacterClassDefinition &def, int *outIndex) const; }; diff --git a/OpenTESArena/src/Entities/CharacterRaceDefinition.cpp b/OpenTESArena/src/Entities/CharacterRaceDefinition.cpp new file mode 100644 index 000000000..24aaaf0b0 --- /dev/null +++ b/OpenTESArena/src/Entities/CharacterRaceDefinition.cpp @@ -0,0 +1,29 @@ +#include +#include + +#include "CharacterRaceDefinition.h" + +#include "components/debug/Debug.h" + +CharacterRaceDefinition::CharacterRaceDefinition() +{ + this->provinceID = -1; + std::fill(std::begin(this->singularName), std::end(this->singularName), '\0'); + std::fill(std::begin(this->pluralName), std::end(this->pluralName), '\0'); +} + +void CharacterRaceDefinition::init(int provinceID, const char *singularName, const char *pluralName, + const TextureAsset &maleCharSheetBodyTextureAsset, const std::string &maleCharSheetHeadsFilename, const std::string &maleGameUiHeadsFilename, + const TextureAsset &femaleCharSheetBodyTextureAsset, const std::string &femaleCharSheetHeadsFilename, const std::string &femaleGameUiHeadsFilename) +{ + DebugAssert(provinceID >= 0); + this->provinceID = provinceID; + std::snprintf(std::begin(this->singularName), std::size(this->singularName), "%s", singularName); + std::snprintf(std::begin(this->pluralName), std::size(this->pluralName), "%s", pluralName); + this->maleCharSheetBodyTextureAsset = maleCharSheetBodyTextureAsset; + this->maleCharSheetHeadsFilename = maleCharSheetHeadsFilename; + this->maleGameUiHeadsFilename = maleGameUiHeadsFilename; + this->femaleCharSheetBodyTextureAsset = femaleCharSheetBodyTextureAsset; + this->femaleCharSheetHeadsFilename = femaleCharSheetHeadsFilename; + this->femaleGameUiHeadsFilename = femaleGameUiHeadsFilename; +} diff --git a/OpenTESArena/src/Entities/CharacterRaceDefinition.h b/OpenTESArena/src/Entities/CharacterRaceDefinition.h new file mode 100644 index 000000000..5d49cb2ff --- /dev/null +++ b/OpenTESArena/src/Entities/CharacterRaceDefinition.h @@ -0,0 +1,27 @@ +#ifndef CHARACTER_RACE_DEFINITION_H +#define CHARACTER_RACE_DEFINITION_H + +#include + +#include "../Assets/TextureAsset.h" + +struct CharacterRaceDefinition +{ + int provinceID; + char singularName[32]; + char pluralName[32]; + TextureAsset maleCharSheetBodyTextureAsset; + std::string maleCharSheetHeadsFilename; + std::string maleGameUiHeadsFilename; + TextureAsset femaleCharSheetBodyTextureAsset; + std::string femaleCharSheetHeadsFilename; + std::string femaleGameUiHeadsFilename; + + CharacterRaceDefinition(); + + void init(int provinceID, const char *singularName, const char *pluralName, + const TextureAsset &maleCharSheetBodyTextureAsset, const std::string &maleCharSheetHeadsFilename, const std::string &maleGameUiHeadsFilename, + const TextureAsset &femaleCharSheetBodyTextureAsset, const std::string &femaleCharSheetHeadsFilename, const std::string &femaleGameUiHeadsFilename); +}; + +#endif diff --git a/OpenTESArena/src/Entities/CharacterRaceLibrary.cpp b/OpenTESArena/src/Entities/CharacterRaceLibrary.cpp new file mode 100644 index 000000000..c5f2d0a1e --- /dev/null +++ b/OpenTESArena/src/Entities/CharacterRaceLibrary.cpp @@ -0,0 +1,71 @@ +#include "../Assets/ArenaPortraitUtils.h" +#include "../Assets/CityDataFile.h" +#include "../Assets/ExeData.h" +#include "CharacterRaceLibrary.h" + +#include "components/debug/Debug.h" + +void CharacterRaceLibrary::init(const ExeData &exeData) +{ + constexpr int playableRaceCount = CityDataFile::PROVINCE_COUNT - 1; + for (int i = 0; i < playableRaceCount; i++) + { + const int raceID = i; + DebugAssertIndex(exeData.races.singularNames, raceID); + DebugAssertIndex(exeData.races.pluralNames, raceID); + const std::string &singularName = exeData.races.singularNames[raceID]; + const std::string &pluralName = exeData.races.pluralNames[raceID]; + const TextureAsset maleCharSheetBodyTextureAsset(ArenaPortraitUtils::getBody(true, raceID)); + const std::string maleCharSheetHeadsFilename = ArenaPortraitUtils::getHeads(true, raceID, false); + const std::string maleGameUiHeadsFilename = ArenaPortraitUtils::getHeads(true, raceID, true); + const TextureAsset femaleCharSheetBodyTextureAsset(ArenaPortraitUtils::getBody(false, raceID)); + const std::string femaleCharSheetHeadsFilename = ArenaPortraitUtils::getHeads(false, raceID, false); + const std::string femaleGameUiHeadsFilename = ArenaPortraitUtils::getHeads(false, raceID, true); + + CharacterRaceDefinition raceDef; + raceDef.init(raceID, singularName.c_str(), pluralName.c_str(), maleCharSheetBodyTextureAsset, maleCharSheetHeadsFilename, maleGameUiHeadsFilename, + femaleCharSheetBodyTextureAsset, femaleCharSheetHeadsFilename, femaleGameUiHeadsFilename); + this->defs.emplace_back(std::move(raceDef)); + } +} + +int CharacterRaceLibrary::getDefinitionCount() const +{ + return static_cast(this->defs.size()); +} + +const CharacterRaceDefinition &CharacterRaceLibrary::getDefinition(int index) const +{ + DebugAssertIndex(this->defs, index); + return this->defs[index]; +} + +bool CharacterRaceLibrary::findDefinitionIndexIf(const Predicate &predicate, int *outIndex) const +{ + for (int i = 0; i < static_cast(this->defs.size()); i++) + { + const CharacterRaceDefinition &def = this->defs[i]; + if (predicate(def)) + { + *outIndex = i; + return true; + } + } + + return false; +} + +bool CharacterRaceLibrary::tryGetDefinitionIndex(const CharacterRaceDefinition &def, int *outIndex) const +{ + for (int i = 0; i < static_cast(this->defs.size()); i++) + { + const CharacterRaceDefinition &charClassDef = this->defs[i]; + if (charClassDef.provinceID == def.provinceID) + { + *outIndex = i; + return true; + } + } + + return false; +} diff --git a/OpenTESArena/src/Entities/CharacterRaceLibrary.h b/OpenTESArena/src/Entities/CharacterRaceLibrary.h new file mode 100644 index 000000000..c9becf148 --- /dev/null +++ b/OpenTESArena/src/Entities/CharacterRaceLibrary.h @@ -0,0 +1,28 @@ +#ifndef CHARACTER_RACE_LIBRARY_H +#define CHARACTER_RACE_LIBRARY_H + +#include +#include + +#include "CharacterRaceDefinition.h" + +#include "components/utilities/Singleton.h" + +class ExeData; + +class CharacterRaceLibrary : public Singleton +{ +public: + using Predicate = std::function; +private: + std::vector defs; +public: + void init(const ExeData &exeData); + + int getDefinitionCount() const; + const CharacterRaceDefinition &getDefinition(int index) const; + bool findDefinitionIndexIf(const Predicate &predicate, int *outIndex) const; + bool tryGetDefinitionIndex(const CharacterRaceDefinition &def, int *outIndex) const; +}; + +#endif diff --git a/OpenTESArena/src/Game/Game.cpp b/OpenTESArena/src/Game/Game.cpp index 6d273899b..70b5ef117 100644 --- a/OpenTESArena/src/Game/Game.cpp +++ b/OpenTESArena/src/Game/Game.cpp @@ -28,6 +28,7 @@ #include "../Collision/PhysicsContactListener.h" #include "../Collision/PhysicsLayer.h" #include "../Entities/CharacterClassLibrary.h" +#include "../Entities/CharacterRaceLibrary.h" #include "../Entities/EntityDefinitionLibrary.h" #include "../GameLogic/PlayerLogicController.h" #include "../Input/InputActionName.h" @@ -371,6 +372,7 @@ bool Game::init() ItemMaterialLibrary::getInstance().init(exeData); ItemLibrary::getInstance().init(exeData); CharacterClassLibrary::getInstance().init(exeData); + CharacterRaceLibrary::getInstance().init(exeData); EntityDefinitionLibrary::getInstance().init(exeData, this->textureManager); this->sceneManager.init(this->textureManager, this->renderer); diff --git a/OpenTESArena/src/Interface/CharacterCreationUiModel.cpp b/OpenTESArena/src/Interface/CharacterCreationUiModel.cpp index 1ef4fea82..ad1e4b158 100644 --- a/OpenTESArena/src/Interface/CharacterCreationUiModel.cpp +++ b/OpenTESArena/src/Interface/CharacterCreationUiModel.cpp @@ -3,6 +3,7 @@ #include "../Assets/ArenaPaletteName.h" #include "../Assets/TextAssetLibrary.h" #include "../Entities/CharacterClassLibrary.h" +#include "../Entities/CharacterRaceLibrary.h" #include "../Game/Game.h" #include "../Stats/PrimaryAttribute.h" @@ -18,12 +19,10 @@ std::string CharacterCreationUiModel::getPlayerName(Game &game) std::string CharacterCreationUiModel::getPlayerRaceName(Game &game) { const CharacterCreationState &charCreationState = game.getCharacterCreationState(); - const ExeData &exeData = BinaryAssetLibrary::getInstance().getExeData(); - - const auto &singularRaceNames = exeData.races.singularNames; - const int raceNameIndex = charCreationState.getRaceIndex(); - DebugAssertIndex(singularRaceNames, raceNameIndex); - return singularRaceNames[raceNameIndex]; + const int raceIndex = charCreationState.getRaceIndex(); + const CharacterRaceLibrary &characterRaceLibrary = CharacterRaceLibrary::getInstance(); + const CharacterRaceDefinition &characterRaceDefinition = characterRaceLibrary.getDefinition(raceIndex); + return std::string(characterRaceDefinition.singularName); } std::string CharacterCreationUiModel::getPlayerClassName(Game &game) @@ -341,9 +340,9 @@ std::string ChooseRaceUiModel::getProvinceConfirmTitleText(Game &game) DebugAssertIndex(charCreationProvinceNames, raceIndex); const std::string &provinceName = charCreationProvinceNames[raceIndex]; - const auto &pluralRaceNames = exeData.races.pluralNames; - DebugAssertIndex(pluralRaceNames, raceIndex); - const std::string &pluralRaceName = pluralRaceNames[raceIndex]; + const CharacterRaceLibrary &characterRaceLibrary = CharacterRaceLibrary::getInstance(); + const CharacterRaceDefinition &characterRaceDefinition = characterRaceLibrary.getDefinition(raceIndex); + const std::string pluralRaceName = characterRaceDefinition.pluralName; // Replace first %s with province name. size_t index = text.find("%s"); @@ -366,16 +365,6 @@ std::string ChooseRaceUiModel::getProvinceConfirmNoText(Game &game) return "No"; // @todo: get from ExeData } -std::string ChooseRaceUiModel::getProvinceTooltipText(Game &game, int provinceID) -{ - // Get the race name associated with the province. - const auto &exeData = BinaryAssetLibrary::getInstance().getExeData(); - const auto &pluralNames = exeData.races.pluralNames; - DebugAssertIndex(pluralNames, provinceID); - const std::string &raceName = pluralNames[provinceID]; - return "Land of the " + raceName; -} - std::string ChooseRaceUiModel::getProvinceConfirmedFirstText(Game &game) { const auto &binaryAssetLibrary = BinaryAssetLibrary::getInstance(); @@ -390,9 +379,9 @@ std::string ChooseRaceUiModel::getProvinceConfirmedFirstText(Game &game) DebugAssertIndex(charCreationProvinceNames, raceIndex); const std::string &provinceName = charCreationProvinceNames[raceIndex]; - const auto &pluralRaceNames = exeData.races.pluralNames; - DebugAssertIndex(pluralRaceNames, raceIndex); - const std::string &pluralRaceName = pluralRaceNames[raceIndex]; + const CharacterRaceLibrary &characterRaceLibrary = CharacterRaceLibrary::getInstance(); + const CharacterRaceDefinition &characterRaceDefinition = characterRaceLibrary.getDefinition(raceIndex); + const std::string pluralRaceName = characterRaceDefinition.pluralName; const auto &charClassLibrary = CharacterClassLibrary::getInstance(); const int charClassDefID = charCreationState.getClassDefID(); diff --git a/OpenTESArena/src/Interface/CharacterCreationUiModel.h b/OpenTESArena/src/Interface/CharacterCreationUiModel.h index 581707f99..2cfd9e628 100644 --- a/OpenTESArena/src/Interface/CharacterCreationUiModel.h +++ b/OpenTESArena/src/Interface/CharacterCreationUiModel.h @@ -57,7 +57,6 @@ namespace ChooseRaceUiModel std::string getProvinceConfirmTitleText(Game &game); std::string getProvinceConfirmYesText(Game &game); std::string getProvinceConfirmNoText(Game &game); - std::string getProvinceTooltipText(Game &game, int provinceID); std::string getProvinceConfirmedFirstText(Game &game); std::string getProvinceConfirmedSecondText(Game &game); std::string getProvinceConfirmedThirdText(Game &game); diff --git a/OpenTESArena/src/Interface/CharacterSheetUiModel.cpp b/OpenTESArena/src/Interface/CharacterSheetUiModel.cpp index 00836d7c8..0d176d0f5 100644 --- a/OpenTESArena/src/Interface/CharacterSheetUiModel.cpp +++ b/OpenTESArena/src/Interface/CharacterSheetUiModel.cpp @@ -2,6 +2,7 @@ #include "CharacterSheetUiModel.h" #include "../Entities/CharacterClassLibrary.h" +#include "../Entities/CharacterRaceLibrary.h" #include "../Game/Game.h" #include "../Stats/PrimaryAttribute.h" @@ -16,12 +17,9 @@ std::string CharacterSheetUiModel::getPlayerName(Game &game) std::string CharacterSheetUiModel::getPlayerRaceName(Game &game) { const Player &player = game.player; - const ExeData &exeData = BinaryAssetLibrary::getInstance().getExeData(); - - const auto &singularRaceNames = exeData.races.singularNames; - const int raceNameIndex = player.raceID; - DebugAssertIndex(singularRaceNames, raceNameIndex); - return singularRaceNames[raceNameIndex]; + const CharacterRaceLibrary &characterRaceLibrary = CharacterRaceLibrary::getInstance(); + const CharacterRaceDefinition &characterRaceDefinition = characterRaceLibrary.getDefinition(player.raceID); + return characterRaceDefinition.singularName; } std::string CharacterSheetUiModel::getPlayerClassName(Game &game) diff --git a/OpenTESArena/src/Interface/CharacterSheetUiView.cpp b/OpenTESArena/src/Interface/CharacterSheetUiView.cpp index f197380d0..18451393e 100644 --- a/OpenTESArena/src/Interface/CharacterSheetUiView.cpp +++ b/OpenTESArena/src/Interface/CharacterSheetUiView.cpp @@ -7,6 +7,7 @@ #include "../Assets/ArenaPortraitUtils.h" #include "../Assets/ArenaTextureName.h" #include "../Entities/CharacterClassLibrary.h" +#include "../Entities/CharacterRaceLibrary.h" #include "../Game/Game.h" #include "../Stats/PrimaryAttribute.h" @@ -157,23 +158,34 @@ TextureAsset CharacterSheetUiView::getNextPageButtonTextureAsset() TextureAsset CharacterSheetUiView::getBodyTextureAsset(Game &game) { const Player &player = game.player; - const bool isMale = player.male; - const int raceID = player.raceID; + const CharacterRaceLibrary &characterRaceLibrary = CharacterRaceLibrary::getInstance(); + const CharacterRaceDefinition &characterRaceDefinition = characterRaceLibrary.getDefinition(player.raceID); - std::string bodyFilename = ArenaPortraitUtils::getBody(isMale, raceID); - return TextureAsset(std::move(bodyFilename)); + if (player.male) + { + return characterRaceDefinition.maleCharSheetBodyTextureAsset; + } + else + { + return characterRaceDefinition.femaleCharSheetBodyTextureAsset; + } } TextureAsset CharacterSheetUiView::getHeadTextureAsset(Game &game) { const Player &player = game.player; - const bool isMale = player.male; - const int raceID = player.raceID; - - constexpr bool trimmed = false; - std::string headsFilename = ArenaPortraitUtils::getHeads(isMale, raceID, trimmed); + const CharacterRaceLibrary &characterRaceLibrary = CharacterRaceLibrary::getInstance(); + const CharacterRaceDefinition &characterRaceDefinition = characterRaceLibrary.getDefinition(player.raceID); const int headIndex = player.portraitID; - return TextureAsset(std::move(headsFilename), headIndex); + + if (player.male) + { + return TextureAsset(std::string(characterRaceDefinition.maleCharSheetHeadsFilename), headIndex); + } + else + { + return TextureAsset(std::string(characterRaceDefinition.femaleCharSheetHeadsFilename), headIndex); + } } TextureAsset CharacterSheetUiView::getShirtTextureAsset(Game &game) diff --git a/OpenTESArena/src/Interface/GameWorldUiView.cpp b/OpenTESArena/src/Interface/GameWorldUiView.cpp index 073fc8d02..0a7f1edb2 100644 --- a/OpenTESArena/src/Interface/GameWorldUiView.cpp +++ b/OpenTESArena/src/Interface/GameWorldUiView.cpp @@ -8,6 +8,7 @@ #include "../Assets/ArenaTextureName.h" #include "../Collision/RayCastTypes.h" #include "../Entities/CharacterClassLibrary.h" +#include "../Entities/CharacterRaceLibrary.h" #include "../Entities/EntityDefinitionLibrary.h" #include "../Game/Game.h" #include "../Math/Constants.h" @@ -341,8 +342,17 @@ TextureAsset GameWorldUiView::getStatusGradientTextureAsset(StatusGradientType g TextureAsset GameWorldUiView::getPlayerPortraitTextureAsset(bool isMale, int raceID, int portraitID) { - const std::string &headsFilename = ArenaPortraitUtils::getHeads(isMale, raceID, true); - return TextureAsset(std::string(headsFilename), portraitID); + const CharacterRaceLibrary &characterRaceLibrary = CharacterRaceLibrary::getInstance(); + const CharacterRaceDefinition &characterRaceDefinition = characterRaceLibrary.getDefinition(raceID); + + if (isMale) + { + return TextureAsset(std::string(characterRaceDefinition.maleGameUiHeadsFilename), portraitID); + } + else + { + return TextureAsset(std::string(characterRaceDefinition.femaleGameUiHeadsFilename), portraitID); + } } TextureAsset GameWorldUiView::getNoMagicTextureAsset()