Skip to content

Commit

Permalink
Added CharacterRaceLibrary.
Browse files Browse the repository at this point in the history
Replaces texture filename generation etc. with library lookup.
  • Loading branch information
afritz1 committed Nov 20, 2024
1 parent 90cd9e3 commit 2ba8f54
Show file tree
Hide file tree
Showing 13 changed files with 217 additions and 48 deletions.
4 changes: 4 additions & 0 deletions OpenTESArena/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
12 changes: 6 additions & 6 deletions OpenTESArena/src/Entities/CharacterClassLibrary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,12 @@ int CharacterClassLibrary::getDefinitionCount() const
return static_cast<int>(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<int>(this->defs.size()); i++)
Expand All @@ -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<int>(this->defs.size()); i++)
Expand Down
2 changes: 1 addition & 1 deletion OpenTESArena/src/Entities/CharacterClassLibrary.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ class CharacterClassLibrary : public Singleton<CharacterClassLibrary>
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;
};

Expand Down
29 changes: 29 additions & 0 deletions OpenTESArena/src/Entities/CharacterRaceDefinition.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <algorithm>
#include <cstring>

#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;
}
27 changes: 27 additions & 0 deletions OpenTESArena/src/Entities/CharacterRaceDefinition.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef CHARACTER_RACE_DEFINITION_H
#define CHARACTER_RACE_DEFINITION_H

#include <string>

#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
71 changes: 71 additions & 0 deletions OpenTESArena/src/Entities/CharacterRaceLibrary.cpp
Original file line number Diff line number Diff line change
@@ -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<int>(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<int>(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<int>(this->defs.size()); i++)
{
const CharacterRaceDefinition &charClassDef = this->defs[i];
if (charClassDef.provinceID == def.provinceID)
{
*outIndex = i;
return true;
}
}

return false;
}
28 changes: 28 additions & 0 deletions OpenTESArena/src/Entities/CharacterRaceLibrary.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#ifndef CHARACTER_RACE_LIBRARY_H
#define CHARACTER_RACE_LIBRARY_H

#include <functional>
#include <vector>

#include "CharacterRaceDefinition.h"

#include "components/utilities/Singleton.h"

class ExeData;

class CharacterRaceLibrary : public Singleton<CharacterRaceLibrary>
{
public:
using Predicate = std::function<bool(const CharacterRaceDefinition&)>;
private:
std::vector<CharacterRaceDefinition> 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
2 changes: 2 additions & 0 deletions OpenTESArena/src/Game/Game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
Expand Down
33 changes: 11 additions & 22 deletions OpenTESArena/src/Interface/CharacterCreationUiModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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)
Expand Down Expand Up @@ -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");
Expand All @@ -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();
Expand All @@ -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();
Expand Down
1 change: 0 additions & 1 deletion OpenTESArena/src/Interface/CharacterCreationUiModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 4 additions & 6 deletions OpenTESArena/src/Interface/CharacterSheetUiModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "CharacterSheetUiModel.h"
#include "../Entities/CharacterClassLibrary.h"
#include "../Entities/CharacterRaceLibrary.h"
#include "../Game/Game.h"
#include "../Stats/PrimaryAttribute.h"

Expand All @@ -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)
Expand Down
32 changes: 22 additions & 10 deletions OpenTESArena/src/Interface/CharacterSheetUiView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 2ba8f54

Please sign in to comment.