refactor: Refactor creature class management

Replace classutil with Classes and CreatureClass.
This commit is contained in:
Vsevolod Kremianskii 2021-01-03 12:09:30 +07:00
parent 956bca3d64
commit bd4cee6bde
9 changed files with 234 additions and 99 deletions

View file

@ -436,7 +436,8 @@ set(GAME_HEADERS
src/game/portraitutil.h
src/game/room.h
src/game/rp/attributes.h
src/game/rp/classutil.h
src/game/rp/class.h
src/game/rp/classes.h
src/game/rp/damageresolver.h
src/game/rp/factionutil.h
src/game/rp/types.h
@ -529,7 +530,8 @@ set(GAME_SOURCES
src/game/portraitutil.cpp
src/game/room.cpp
src/game/rp/attributes.cpp
src/game/rp/classutil.cpp
src/game/rp/class.cpp
src/game/rp/classes.cpp
src/game/rp/damageresolver.cpp
src/game/rp/factionutil.cpp
src/game/savedgame.cpp

View file

@ -24,7 +24,7 @@
#include "../../game.h"
#include "../../portraitutil.h"
#include "../../rp/classutil.h"
#include "../../rp/classes.h"
#include "../colorutil.h"
@ -323,11 +323,13 @@ shared_ptr<ModelSceneNode> CharacterGeneration::getCharacterModel(SceneGraph &sc
}
void CharacterGeneration::updateAttributes() {
setControlText("LBL_CLASS", getClassTitle(_character.clazz));
shared_ptr<CreatureClass> clazz(Classes::instance().get(_character.clazz));
CreatureAttributes attrs(getClassAttributes(_character.clazz));
int vitality = getClassHitPoints(_character.clazz, 1) + (attrs.constitution() - 10) / 2;
int defense = 10 + getClassDefenseBonus(_character.clazz, 1) + (attrs.dexterity() - 10) / 2;
setControlText("LBL_CLASS", clazz->name());
CreatureAttributes attrs(clazz->defaultAttributes());
int vitality = clazz->getHitPoints(1) + (attrs.constitution() - 10) / 2;
int defense = 10 + clazz->getDefenseBonus(1) + (attrs.dexterity() - 10) / 2;
setControlText("LBL_VIT", to_string(vitality));
setControlText("LBL_DEF", to_string(defense));

View file

@ -23,7 +23,7 @@
#include "../../characterutil.h"
#include "../../game.h"
#include "../../object/creature.h"
#include "../../rp/classutil.h"
#include "../../rp/classes.h"
#include "../colorutil.h"
@ -220,7 +220,7 @@ void ClassSelection::onFocusChanged(const string &control, bool focus) {
ClassButton &button = _classButtons[idx];
string classText(Resources::instance().getString(g_genderStrRefs[button.config.gender]));
classText += " " + getClassTitle(button.config.clazz);
classText += " " + Classes::instance().get(button.config.clazz)->name();
string descText(Resources::instance().getString(g_classDescStrRefs[button.config.clazz]));

View file

@ -33,7 +33,7 @@
#include "../action/attack.h"
#include "../blueprint/blueprints.h"
#include "../rp/classutil.h"
#include "../rp/classes.h"
#include "../portraitutil.h"
#include "objectfactory.h"
@ -156,7 +156,7 @@ void Creature::load(const CreatureConfiguration &config) {
loadAppearance(*appearance, config.appearance);
loadPortrait(config.appearance);
_attributes.addClassLevels(config.clazz, 1);
_currentHitPoints = _hitPoints = _maxHitPoints = getClassHitPoints(config.clazz, 1);
_currentHitPoints = _hitPoints = _maxHitPoints = Classes::instance().get(config.clazz)->getHitPoints(1);
}
for (auto &item : config.equipment) {
equip(item);

76
src/game/rp/class.cpp Normal file
View file

@ -0,0 +1,76 @@
/*
* Copyright (c) 2020-2021 The reone project contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "class.h"
#include "../../resource/resources.h"
using namespace std;
using namespace reone::resource;
namespace reone {
namespace game {
CreatureClass::CreatureClass(ClassType type) : _type(type) {
}
void CreatureClass::load(const TwoDaRow &row) {
_name = Resources::instance().getString(row.getInt("name"));
_description = Resources::instance().getString(row.getInt("description"));
_hitdie = row.getInt("hitdie");
_defaultAttributes.setAbilityScore(Ability::Strength, row.getInt("str"));
_defaultAttributes.setAbilityScore(Ability::Dexterity, row.getInt("dex"));
_defaultAttributes.setAbilityScore(Ability::Constitution, row.getInt("con"));
_defaultAttributes.setAbilityScore(Ability::Intelligence, row.getInt("int"));
_defaultAttributes.setAbilityScore(Ability::Wisdom, row.getInt("wis"));
_defaultAttributes.setAbilityScore(Ability::Charisma, row.getInt("cha"));
}
int CreatureClass::getHitPoints(int level) {
return level * _hitdie;
}
int CreatureClass::getDefenseBonus(int level) {
switch (_type) {
case ClassType::JediConsular:
case ClassType::JediGuardian:
case ClassType::JediSentinel:
case ClassType::Scoundrel:
return 2 + (2 * (level / 6));
default:
return 0;
}
}
const string &CreatureClass::name() const {
return _name;
}
const string &CreatureClass::description() const {
return _description;
}
const CreatureAttributes &CreatureClass::defaultAttributes() const {
return _defaultAttributes;
}
} // namespace game
} // namespace reone

66
src/game/rp/class.h Normal file
View file

@ -0,0 +1,66 @@
/*
* Copyright (c) 2020-2021 The reone project contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
#include "../../resource/2dafile.h"
#include "attributes.h"
#include "types.h"
namespace reone {
namespace game {
/**
* Represents a creature class.
*/
class CreatureClass {
public:
CreatureClass(ClassType type);
void load(const resource::TwoDaRow &row);
/**
* Compute a number of hit points that creature of this class and the
* specified level would have.
*/
int getHitPoints(int level);
/**
* Compute a defense bonus that creature of this class and the specified
* level would have.
*/
int getDefenseBonus(int level);
const std::string &name() const;
const std::string &description() const;
const CreatureAttributes &defaultAttributes() const;
private:
ClassType _type;
std::string _name;
std::string _description;
int _hitdie { 0 };
CreatureAttributes _defaultAttributes;
};
} // namespace game
} // namespace reone

58
src/game/rp/classes.cpp Normal file
View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2020-2021 The reone project contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "classes.h"
#include "../../resource/resources.h"
using namespace std;
using namespace reone::resource;
namespace reone {
namespace game {
static const char kClassesTableResRef[] = "classes";
Classes &Classes::instance() {
static Classes classes;
return classes;
}
shared_ptr<CreatureClass> Classes::get(ClassType type) {
auto maybeClass = _classes.find(type);
if (maybeClass != _classes.end()) return maybeClass->second;
auto inserted = _classes.insert(make_pair(type, doGet(type)));
return inserted.first->second;
}
shared_ptr<CreatureClass> Classes::doGet(ClassType type) {
shared_ptr<TwoDaTable> table(Resources::instance().get2DA(kClassesTableResRef));
const TwoDaRow &row = table->rows()[static_cast<int>(type)];
auto clazz = make_shared<CreatureClass>(type);
clazz->load(row);
return move(clazz);
}
} // namespace game
} // namespace reone

View file

@ -17,19 +17,32 @@
#pragma once
#include <string>
#include <memory>
#include <unordered_map>
#include "attributes.h"
#include "class.h"
#include "types.h"
namespace reone {
namespace game {
std::string getClassTitle(ClassType clazz);
CreatureAttributes getClassAttributes(ClassType clazz);
int getClassHitPoints(ClassType clazz, int level);
int getClassDefenseBonus(ClassType clazz, int level);
class Classes {
public:
static Classes &instance();
std::shared_ptr<CreatureClass> get(ClassType type);
private:
std::unordered_map<ClassType, std::shared_ptr<CreatureClass>> _classes;
Classes() = default;
Classes(const Classes &) = delete;
Classes &operator=(const Classes &) = delete;
std::shared_ptr<CreatureClass> doGet(ClassType type);
};
} // namespace game

View file

@ -1,82 +0,0 @@
/*
* Copyright (c) 2020-2021 The reone project contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "classutil.h"
#include <map>
#include "../../resource/resources.h"
using namespace std;
using namespace reone::resource;
namespace reone {
namespace game {
static map<ClassType, int> g_classStrRefs {
{ ClassType::Scout, 133 },
{ ClassType::Soldier, 134 },
{ ClassType::Scoundrel, 135 },
{ ClassType::JediGuardian, 353 },
{ ClassType::JediConsular, 354 },
{ ClassType::JediSentinel, 355 }
};
string getClassTitle(ClassType clazz) {
int strRef = g_classStrRefs.find(clazz)->second;
return Resources::instance().getString(strRef);
}
CreatureAttributes getClassAttributes(ClassType clazz) {
shared_ptr<TwoDaTable> classes(Resources::instance().get2DA("classes"));
int row = static_cast<int>(clazz);
CreatureAttributes attrs;
attrs.setAbilityScore(Ability::Strength, classes->getInt(row, "str"));
attrs.setAbilityScore(Ability::Dexterity, classes->getInt(row, "dex"));
attrs.setAbilityScore(Ability::Constitution, classes->getInt(row, "con"));
attrs.setAbilityScore(Ability::Intelligence, classes->getInt(row, "int"));
attrs.setAbilityScore(Ability::Wisdom, classes->getInt(row, "wis"));
attrs.setAbilityScore(Ability::Charisma, classes->getInt(row, "cha"));
return move(attrs);
}
int getClassHitPoints(ClassType clazz, int level) {
shared_ptr<TwoDaTable> classes(Resources::instance().get2DA("classes"));
int row = static_cast<int>(clazz);
return level * classes->getInt(row, "hitdie");
}
int getClassDefenseBonus(ClassType clazz, int level) {
switch (clazz) {
case ClassType::JediConsular:
case ClassType::JediGuardian:
case ClassType::JediSentinel:
case ClassType::Scoundrel:
return 2 + (2 * (level / 6));
default:
return 0;
}
}
} // namespace game
} // namespace reone