Browse Source

Extract some player attributes to data files

pull/6622/head
Gleb Mazovetskiy 3 years ago
parent
commit
e090c8bf31
  1. 6
      CMake/Assets.cmake
  2. 25
      Packaging/resources/assets/txtdata/classes/README.md
  3. 18
      Packaging/resources/assets/txtdata/classes/barbarian/attributes.tsv
  4. 18
      Packaging/resources/assets/txtdata/classes/bard/attributes.tsv
  5. 18
      Packaging/resources/assets/txtdata/classes/monk/attributes.tsv
  6. 18
      Packaging/resources/assets/txtdata/classes/rogue/attributes.tsv
  7. 18
      Packaging/resources/assets/txtdata/classes/sorcerer/attributes.tsv
  8. 18
      Packaging/resources/assets/txtdata/classes/warrior/attributes.tsv
  9. 12
      Source/data/file.cpp
  10. 2
      Source/data/file.hpp
  11. 4
      Source/items.cpp
  12. 2
      Source/loadsave.cpp
  13. 4
      Source/pack.cpp
  14. 9
      Source/pfile.cpp
  15. 44
      Source/player.cpp
  16. 111
      Source/playerdat.cpp
  17. 9
      Source/playerdat.hpp

6
CMake/Assets.cmake

@ -142,6 +142,12 @@ set(devilutionx_assets
nlevels/l5data/cornerstone.dun
nlevels/l5data/uberroom.dun
txtdata/Experience.tsv
txtdata/classes/barbarian/attributes.tsv
txtdata/classes/bard/attributes.tsv
txtdata/classes/monk/attributes.tsv
txtdata/classes/rogue/attributes.tsv
txtdata/classes/sorcerer/attributes.tsv
txtdata/classes/warrior/attributes.tsv
ui_art/diablo.pal
ui_art/hellfire.pal
ui_art/creditsw.clx

25
Packaging/resources/assets/txtdata/classes/README.md

@ -0,0 +1,25 @@
# Player class data
There is one folder per class.
### attributes.tsv
Attribute | Description
-------------:|--------------------------------------
`baseStr` | Class Starting Strength Stat
`baseMag` | Class Starting Magic Stat
`baseDex` | Class Starting Dexterity Stat
`baseVit` | Class Starting Vitality Stat
`maxStr` | Class Maximum Strength Stat
`maxMag` | Class Maximum Magic Stat
`maxDex` | Class Maximum Dexterity Stat
`maxVit` | Class Maximum Vitality Stat
`blockBonus` | Class Block Bonus, %
`adjLife` | Class Life Adjustment, 1/64
`adjMana` | Class Mana Adjustment, 1/64
`lvlLife` | Life gained on level up, 1/64
`lvlMana` | Mana gained on level up, 1/64
`chrLife` | Life from base Vitality, 1/64
`chrMana` | Mana from base Magic, 1/64
`itmLife` | Life from item bonus Vitality, 1/64
`itmMana` | Mana from item bonus Magic, 1/64

18
Packaging/resources/assets/txtdata/classes/barbarian/attributes.tsv

@ -0,0 +1,18 @@
Attribute Value
baseStr 40
baseMag 0
baseDex 20
baseVit 25
maxStr 255
maxMag 0
maxDex 55
maxVit 150
blockBonus 30
adjLife 1152
adjMana 0
lvlLife 128
lvlMana 0
chrLife 128
chrMana 64
itmLife 160
itmMana 64
1 Attribute Value
2 baseStr 40
3 baseMag 0
4 baseDex 20
5 baseVit 25
6 maxStr 255
7 maxMag 0
8 maxDex 55
9 maxVit 150
10 blockBonus 30
11 adjLife 1152
12 adjMana 0
13 lvlLife 128
14 lvlMana 0
15 chrLife 128
16 chrMana 64
17 itmLife 160
18 itmMana 64

18
Packaging/resources/assets/txtdata/classes/bard/attributes.tsv

@ -0,0 +1,18 @@
Attribute Value
baseStr 20
baseMag 20
baseDex 25
baseVit 20
maxStr 120
maxMag 120
maxDex 120
maxVit 100
blockBonus 25
adjLife 1472
adjMana 192
lvlLife 128
lvlMana 128
chrLife 64
chrMana 96
itmLife 96
itmMana 112
1 Attribute Value
2 baseStr 20
3 baseMag 20
4 baseDex 25
5 baseVit 20
6 maxStr 120
7 maxMag 120
8 maxDex 120
9 maxVit 100
10 blockBonus 25
11 adjLife 1472
12 adjMana 192
13 lvlLife 128
14 lvlMana 128
15 chrLife 64
16 chrMana 96
17 itmLife 96
18 itmMana 112

18
Packaging/resources/assets/txtdata/classes/monk/attributes.tsv

@ -0,0 +1,18 @@
Attribute Value
baseStr 25
baseMag 15
baseDex 25
baseVit 20
maxStr 150
maxMag 80
maxDex 150
maxVit 80
blockBonus 25
adjLife 1472
adjMana 352
lvlLife 128
lvlMana 128
chrLife 64
chrMana 64
itmLife 96
itmMana 96
1 Attribute Value
2 baseStr 25
3 baseMag 15
4 baseDex 25
5 baseVit 20
6 maxStr 150
7 maxMag 80
8 maxDex 150
9 maxVit 80
10 blockBonus 25
11 adjLife 1472
12 adjMana 352
13 lvlLife 128
14 lvlMana 128
15 chrLife 64
16 chrMana 64
17 itmLife 96
18 itmMana 96

18
Packaging/resources/assets/txtdata/classes/rogue/attributes.tsv

@ -0,0 +1,18 @@
Attribute Value
baseStr 20
baseMag 15
baseDex 30
baseVit 20
maxStr 55
maxMag 70
maxDex 250
maxVit 80
blockBonus 20
adjLife 1472
adjMana 352
lvlLife 128
lvlMana 128
chrLife 64
chrMana 64
itmLife 96
itmMana 96
1 Attribute Value
2 baseStr 20
3 baseMag 15
4 baseDex 30
5 baseVit 20
6 maxStr 55
7 maxMag 70
8 maxDex 250
9 maxVit 80
10 blockBonus 20
11 adjLife 1472
12 adjMana 352
13 lvlLife 128
14 lvlMana 128
15 chrLife 64
16 chrMana 64
17 itmLife 96
18 itmMana 96

18
Packaging/resources/assets/txtdata/classes/sorcerer/attributes.tsv

@ -0,0 +1,18 @@
Attribute Value
baseStr 15
baseMag 35
baseDex 15
baseVit 20
maxStr 45
maxMag 250
maxDex 85
maxVit 80
blockBonus 10
adjLife 576
adjMana -128
lvlLife 64
lvlMana 128
chrLife 64
chrMana 128
itmLife 64
itmMana 128
1 Attribute Value
2 baseStr 15
3 baseMag 35
4 baseDex 15
5 baseVit 20
6 maxStr 45
7 maxMag 250
8 maxDex 85
9 maxVit 80
10 blockBonus 10
11 adjLife 576
12 adjMana -128
13 lvlLife 64
14 lvlMana 128
15 chrLife 64
16 chrMana 128
17 itmLife 64
18 itmMana 128

18
Packaging/resources/assets/txtdata/classes/warrior/attributes.tsv

@ -0,0 +1,18 @@
Attribute Value
baseStr 30
baseMag 10
baseDex 20
baseVit 25
maxStr 250
maxMag 50
maxDex 60
maxVit 100
blockBonus 30
adjLife 1152
adjMana -64
lvlLife 128
lvlMana 64
chrLife 128
chrMana 64
itmLife 128
itmMana 64
1 Attribute Value
2 baseStr 30
3 baseMag 10
4 baseDex 20
5 baseVit 25
6 maxStr 250
7 maxMag 50
8 maxDex 60
9 maxVit 100
10 blockBonus 30
11 adjLife 1152
12 adjMana -64
13 lvlLife 128
14 lvlMana 64
15 chrLife 128
16 chrMana 64
17 itmLife 128
18 itmMana 64

12
Source/data/file.cpp

@ -115,4 +115,16 @@ tl::expected<void, DataFile::Error> DataFile::parseHeader(ColumnDefinition *begi
}
return {};
}
tl::expected<void, DataFile::Error> DataFile::skipHeader()
{
RecordIterator it { data(), data() + size(), false };
++it;
if (it == this->end()) {
return tl::unexpected { Error::NoContent };
}
body_ = it.data();
return {};
}
} // namespace devilution

2
Source/data/file.hpp

@ -107,6 +107,8 @@ public:
return parseHeader(begin, end, [typedMapper](std::string_view label) { return typedMapper(label).transform([](T value) { return static_cast<uint8_t>(value); }); });
}
[[nodiscard]] tl::expected<void, DataFile::Error> skipHeader();
[[nodiscard]] RecordIterator begin() const
{
return { body_, data() + size(), body_ != data() };

4
Source/items.cpp

@ -2748,10 +2748,10 @@ void CalcPlrItemVals(Player &player, bool loadgfx)
player._pFireResist = std::clamp(fr, 0, MaxResistance);
player._pLghtResist = std::clamp(lr, 0, MaxResistance);
vadd = (vadd * PlayersData[static_cast<size_t>(player._pClass)].itmLife) >> 6;
vadd = (vadd * GetClassAttributes(player._pClass).itmLife) >> 6;
ihp += (vadd << 6); // BUGFIX: blood boil can cause negative shifts here (see line 757)
madd = (madd * PlayersData[static_cast<size_t>(player._pClass)].itmMana) >> 6;
madd = (madd * GetClassAttributes(player._pClass).itmMana) >> 6;
imana += (madd << 6);
player._pMaxHP = ihp + player._pMaxHPBase;

2
Source/loadsave.cpp

@ -414,7 +414,7 @@ void LoadPlayer(LoadHelper &file, Player &player)
player._pDamageMod = file.NextLE<int32_t>();
player._pBaseToBlk = file.NextLE<int32_t>();
if (player._pBaseToBlk == 0)
player._pBaseToBlk = PlayersData[static_cast<std::size_t>(player._pClass)].blockBonus;
player._pBaseToBlk = GetClassAttributes(player._pClass).blockBonus;
player._pHPBase = file.NextLE<int32_t>();
player._pMaxHPBase = file.NextLE<int32_t>();
player._pHitPoints = file.NextLE<int32_t>();

4
Source/pack.cpp

@ -453,7 +453,7 @@ void UnPackPlayer(const PlayerPack &packed, Player &player)
player._pExperience = SDL_SwapLE32(packed.pExperience);
player._pGold = SDL_SwapLE32(packed.pGold);
player._pBaseToBlk = PlayersData[static_cast<std::size_t>(player._pClass)].blockBonus;
player._pBaseToBlk = GetClassAttributes(player._pClass).blockBonus;
if ((int)(player._pHPBase & 0xFFFFFFC0) < 64)
player._pHPBase = 64;
@ -542,7 +542,7 @@ bool UnPackNetPlayer(const PlayerNetPack &packed, Player &player)
player._pStatPts = packed.pStatPts;
player._pExperience = SDL_SwapLE32(packed.pExperience);
player._pBaseToBlk = PlayersData[static_cast<std::size_t>(player._pClass)].blockBonus;
player._pBaseToBlk = GetClassAttributes(player._pClass).blockBonus;
player._pMaxManaBase = baseManaMax;
player._pManaBase = baseMana;
player._pMemSpells = SDL_SwapLE64(packed.pMemSpells);

9
Source/pfile.cpp

@ -678,10 +678,11 @@ bool pfile_ui_set_hero_infos(bool (*uiAddHeroInfo)(_uiheroinfo *))
void pfile_ui_set_class_stats(unsigned int playerClass, _uidefaultstats *classStats)
{
classStats->strength = PlayersData[playerClass].baseStr;
classStats->magic = PlayersData[playerClass].baseMag;
classStats->dexterity = PlayersData[playerClass].baseDex;
classStats->vitality = PlayersData[playerClass].baseVit;
const ClassAttributes &classAttributes = GetClassAttributes(static_cast<HeroClass>(playerClass));
classStats->strength = classAttributes.baseStr;
classStats->magic = classAttributes.baseMag;
classStats->dexterity = classAttributes.baseDex;
classStats->vitality = classAttributes.baseVit;
}
uint32_t pfile_ui_get_first_unused_save_num()

44
Source/player.cpp

@ -1703,16 +1703,16 @@ int Player::GetCurrentAttributeValue(CharacterAttribute attribute) const
int Player::GetMaximumAttributeValue(CharacterAttribute attribute) const
{
PlayerData plrData = PlayersData[static_cast<std::size_t>(_pClass)];
const ClassAttributes &attr = GetClassAttributes(_pClass);
switch (attribute) {
case CharacterAttribute::Strength:
return plrData.maxStr;
return attr.maxStr;
case CharacterAttribute::Magic:
return plrData.maxMag;
return attr.maxMag;
case CharacterAttribute::Dexterity:
return plrData.maxDex;
return attr.maxDex;
case CharacterAttribute::Vitality:
return plrData.maxVit;
return attr.maxVit;
}
app_fatal("Unsupported attribute");
}
@ -2062,14 +2062,14 @@ uint32_t Player::getNextExperienceThreshold() const
int32_t Player::calculateBaseLife() const
{
const PlayerData &playerData = PlayersData[static_cast<size_t>(_pClass)];
return playerData.adjLife + (playerData.lvlLife * getCharacterLevel()) + (playerData.chrLife * _pBaseVit);
const ClassAttributes &attr = GetClassAttributes(_pClass);
return attr.adjLife + (attr.lvlLife * getCharacterLevel()) + (attr.chrLife * _pBaseVit);
}
int32_t Player::calculateBaseMana() const
{
const PlayerData &playerData = PlayersData[static_cast<size_t>(_pClass)];
return playerData.adjMana + (playerData.lvlMana * getCharacterLevel()) + (playerData.chrMana * _pBaseMag);
const ClassAttributes &attr = GetClassAttributes(_pClass);
return attr.adjMana + (attr.lvlMana * getCharacterLevel()) + (attr.chrMana * _pBaseMag);
}
Player *PlayerAtPosition(Point position)
@ -2279,24 +2279,24 @@ void CreatePlayer(Player &player, HeroClass c)
player = {};
SetRndSeed(SDL_GetTicks());
const PlayerData &playerData = PlayersData[static_cast<size_t>(c)];
const ClassAttributes &attr = GetClassAttributes(c);
player.setCharacterLevel(1);
player._pClass = c;
player._pBaseStr = playerData.baseStr;
player._pBaseStr = attr.baseStr;
player._pStrength = player._pBaseStr;
player._pBaseMag = playerData.baseMag;
player._pBaseMag = attr.baseMag;
player._pMagic = player._pBaseMag;
player._pBaseDex = playerData.baseDex;
player._pBaseDex = attr.baseDex;
player._pDexterity = player._pBaseDex;
player._pBaseVit = playerData.baseVit;
player._pBaseVit = attr.baseVit;
player._pVitality = player._pBaseVit;
player._pBaseToBlk = playerData.blockBonus;
player._pBaseToBlk = attr.blockBonus;
player._pHitPoints = player.calculateBaseLife();
player._pMaxHP = player._pHitPoints;
@ -2314,7 +2314,7 @@ void CreatePlayer(Player &player, HeroClass c)
player._pInfraFlag = false;
player._pRSplType = SpellType::Skill;
SpellID s = playerData.skill;
SpellID s = PlayersData[static_cast<size_t>(c)].skill;
player._pAblSpells = GetSpellBitmask(s);
player._pRSpell = s;
@ -2397,7 +2397,7 @@ void NextPlrLevel(Player &player)
} else {
player._pStatPts += 5;
}
int hp = PlayersData[static_cast<size_t>(player._pClass)].lvlLife;
int hp = GetClassAttributes(player._pClass).lvlLife;
player._pMaxHP += hp;
player._pHitPoints = player._pMaxHP;
@ -2408,7 +2408,7 @@ void NextPlrLevel(Player &player)
RedrawComponent(PanelDrawComponent::Health);
}
int mana = PlayersData[static_cast<size_t>(player._pClass)].lvlMana;
int mana = GetClassAttributes(player._pClass).lvlMana;
player._pMaxMana += mana;
player._pMaxManaBase += mana;
@ -3329,7 +3329,7 @@ void ModifyPlrMag(Player &player, int l)
player._pBaseMag += l;
int ms = l;
ms *= PlayersData[static_cast<size_t>(player._pClass)].chrMana;
ms *= GetClassAttributes(player._pClass).chrMana;
player._pMaxManaBase += ms;
player._pMaxMana += ms;
@ -3366,7 +3366,7 @@ void ModifyPlrVit(Player &player, int l)
player._pBaseVit += l;
int ms = l;
ms *= PlayersData[static_cast<size_t>(player._pClass)].chrLife;
ms *= GetClassAttributes(player._pClass).chrLife;
player._pHPBase += ms;
player._pMaxHPBase += ms;
@ -3401,7 +3401,7 @@ void SetPlrMag(Player &player, int v)
player._pBaseMag = v;
int m = v;
m *= PlayersData[static_cast<size_t>(player._pClass)].chrMana;
m *= GetClassAttributes(player._pClass).chrMana;
player._pMaxManaBase = m;
player._pMaxMana = m;
@ -3419,7 +3419,7 @@ void SetPlrVit(Player &player, int v)
player._pBaseVit = v;
int hp = v;
hp *= PlayersData[static_cast<size_t>(player._pClass)].chrLife;
hp *= GetClassAttributes(player._pClass).chrLife;
player._pHPBase = hp;
player._pMaxHPBase = hp;

111
Source/playerdat.cpp

@ -11,6 +11,8 @@
#include <bitset>
#include <charconv>
#include <cstdint>
#include <unordered_map>
#include <variant>
#include <vector>
#include <expected.hpp>
@ -22,6 +24,7 @@
#include "textdat.h"
#include "utils/language.h"
#include "utils/static_vector.hpp"
#include "utils/str_cat.hpp"
namespace devilution {
@ -152,11 +155,104 @@ void ReloadExperienceData()
}
}
void LoadClassAttributes(std::string_view classPath, ClassAttributes &out)
{
const std::string filename = StrCat("txtdata\\classes\\", classPath, "\\attributes.tsv");
tl::expected<DataFile, DataFile::Error> dataFileResult = DataFile::load(filename);
if (!dataFileResult.has_value()) {
DataFile::reportFatalError(dataFileResult.error(), filename);
}
DataFile &dataFile = dataFileResult.value();
if (tl::expected<void, DataFile::Error> result = dataFile.skipHeader();
!result.has_value()) {
DataFile::reportFatalError(result.error(), filename);
}
struct KeyInfo {
std::variant<uint8_t *, int16_t *> out;
bool found = false;
};
std::unordered_map<std::string_view, KeyInfo> keyToField {
{ "baseStr", KeyInfo { &out.baseStr } },
{ "baseMag", KeyInfo { &out.baseMag } },
{ "baseDex", KeyInfo { &out.baseDex } },
{ "baseVit", KeyInfo { &out.baseVit } },
{ "maxStr", KeyInfo { &out.maxStr } },
{ "maxMag", KeyInfo { &out.maxMag } },
{ "maxDex", KeyInfo { &out.maxDex } },
{ "maxVit", KeyInfo { &out.maxVit } },
{ "blockBonus", KeyInfo { &out.blockBonus } },
{ "adjLife", KeyInfo { &out.adjLife } },
{ "adjMana", KeyInfo { &out.adjMana } },
{ "lvlLife", KeyInfo { &out.lvlLife } },
{ "lvlMana", KeyInfo { &out.lvlMana } },
{ "chrLife", KeyInfo { &out.chrLife } },
{ "chrMana", KeyInfo { &out.chrMana } },
{ "itmLife", KeyInfo { &out.itmLife } },
{ "itmMana", KeyInfo { &out.itmMana } },
};
for (DataFileRecord record : dataFile) {
FieldIterator fieldIt = record.begin();
const FieldIterator endField = record.end();
const std::string_view key = (*fieldIt).value();
++fieldIt;
if (fieldIt == endField) {
DataFile::reportFatalError(DataFile::Error::NotEnoughColumns, filename);
}
DataFileField valueField = *fieldIt;
auto mappingIt = keyToField.find(key);
if (mappingIt == keyToField.end()) {
app_fatal(fmt::format("Unknown field {} in {}", key, filename));
}
KeyInfo &keyInfo = mappingIt->second;
if (keyInfo.found) {
app_fatal(fmt::format("Duplicate field {} in {}", key, filename));
}
std::visit([&](auto *outField) {
auto parseIntResult = valueField.parseInt(*outField);
if (parseIntResult != std::errc()) {
DataFile::reportFatalFieldError(parseIntResult, filename, "Value", valueField);
}
},
keyInfo.out);
keyInfo.found = true;
++fieldIt;
}
for (const auto &[key, keyInfo] : keyToField) {
if (!keyInfo.found) {
app_fatal(fmt::format("Missing field {} in {}", key, filename));
}
}
}
std::vector<ClassAttributes> ClassAttributesPerClass;
void LoadClassesAttributes()
{
const std::array classPaths { "warrior", "rogue", "sorcerer", "monk", "bard", "barbarian" };
ClassAttributesPerClass.clear();
ClassAttributesPerClass.reserve(classPaths.size());
for (std::string_view path : classPaths) {
LoadClassAttributes(path, ClassAttributesPerClass.emplace_back());
}
}
} // namespace
const ClassAttributes &GetClassAttributes(HeroClass playerClass)
{
return ClassAttributesPerClass[static_cast<size_t>(playerClass)];
}
void LoadPlayerDataFiles()
{
ReloadExperienceData();
LoadClassesAttributes();
}
uint32_t GetNextExperienceThresholdForLevel(unsigned level)
@ -183,15 +279,14 @@ const _sfx_id herosounds[enum_size<HeroClass>::value][enum_size<HeroSpeech>::val
/** Contains the data related to each player class. */
const PlayerData PlayersData[] = {
// clang-format off
// HeroClass className, classPath, baseStr, baseMag, baseDex, baseVit, maxStr, maxMag, maxDex, maxVit, blockBonus, adjLife, adjMana, lvlLife, lvlMana, chrLife, chrMana, itmLife, itmMana, skill,
// HeroClass className, classPath, skill
// TRANSLATORS: Player Block start
/* HeroClass::Warrior */ { N_("Warrior"), "warrior", 30, 10, 20, 25, 250, 50, 60, 100, 30, (18 << 6), -(1 << 6), (2 << 6), (1 << 6), (2 << 6), (1 << 6), (2 << 6), (1 << 6), SpellID::ItemRepair },
/* HeroClass::Rogue */ { N_("Rogue"), "rogue", 20, 15, 30, 20, 55, 70, 250, 80, 20, (23 << 6), static_cast<int>(5.5F * 64), (2 << 6), (2 << 6), (1 << 6), (1 << 6), static_cast<int>(1.5F * 64), static_cast<int>(1.5F * 64), SpellID::TrapDisarm },
/* HeroClass::Sorcerer */ { N_("Sorcerer"), "sorceror", 15, 35, 15, 20, 45, 250, 85, 80, 10, (9 << 6), -(2 << 6), (1 << 6), (2 << 6), (1 << 6), (2 << 6), (1 << 6), (2 << 6), SpellID::StaffRecharge },
/* HeroClass::Monk */ { N_("Monk"), "monk", 25, 15, 25, 20, 150, 80, 150, 80, 25, (23 << 6), static_cast<int>(5.5F * 64), (2 << 6), (2 << 6), (1 << 6), (1 << 6), static_cast<int>(1.5F * 64), static_cast<int>(1.5F * 64), SpellID::Search, },
/* HeroClass::Bard */ { N_("Bard"), "rogue", 20, 20, 25, 20, 120, 120, 120, 100, 25, (23 << 6), (3 << 6), (2 << 6), (2 << 6), (1 << 6), static_cast<int>(1.5F * 64), static_cast<int>(1.5F * 64), static_cast<int>(1.75F * 64), SpellID::Identify },
/* HeroClass::Barbarian */ { N_("Barbarian"), "warrior", 40, 0, 20, 25, 255, 0, 55, 150, 30, (18 << 6), (0 << 6), (2 << 6), (0 << 6), (2 << 6), (1 << 6), static_cast<int>(2.5F * 64), (1 << 6), SpellID::Rage },
/* HeroClass::Warrior */ { N_("Warrior"), "warrior", SpellID::ItemRepair },
/* HeroClass::Rogue */ { N_("Rogue"), "rogue", SpellID::TrapDisarm },
/* HeroClass::Sorcerer */ { N_("Sorcerer"), "sorceror", SpellID::StaffRecharge },
/* HeroClass::Monk */ { N_("Monk"), "monk", SpellID::Search },
/* HeroClass::Bard */ { N_("Bard"), "rogue", SpellID::Identify },
/* HeroClass::Barbarian */ { N_("Barbarian"), "warrior", SpellID::Rage },
// clang-format on
};

9
Source/playerdat.hpp

@ -17,6 +17,11 @@ struct PlayerData {
const char *className;
/* Class Directory Path */
const char *classPath;
/* Class Skill */
SpellID skill;
};
struct ClassAttributes {
/* Class Starting Strength Stat */
uint8_t baseStr;
/* Class Starting Magic Stat */
@ -51,10 +56,10 @@ struct PlayerData {
int16_t itmLife;
/* Mana from item bonus Magic */
int16_t itmMana;
/* Class Skill */
SpellID skill;
};
const ClassAttributes &GetClassAttributes(HeroClass playerClass);
struct PlayerSpriteData {
/* Sprite width: Stand */
uint8_t stand;

Loading…
Cancel
Save