feat: Load character attributes from blueprint and during chargen

This commit is contained in:
Vsevolod Kremianskii 2020-11-06 12:06:50 +07:00
parent 8801a22eec
commit f735bd673d
11 changed files with 214 additions and 33 deletions

View file

@ -384,6 +384,7 @@ set(GAME_HEADERS
src/game/player.h
src/game/portraits.h
src/game/room.h
src/game/rp/classes.h
src/game/rp/types.h
src/game/script/routines.h
src/game/script/util.h
@ -456,6 +457,7 @@ set(GAME_SOURCES
src/game/player.cpp
src/game/portraits.cpp
src/game/room.cpp
src/game/rp/classes.cpp
src/game/script/routines.cpp
src/game/script/routines_common.cpp
src/game/script/routines_kotor.cpp

View file

@ -40,7 +40,28 @@ void CreatureBlueprint::load(const GffStruct &utc) {
_appearance = utc.getInt("Appearance_Type");
_conversation = utc.getString("Conversation");
_scripts[ScriptType::Spawn] = utc.getString("ScriptSpawn");
loadAttributes(utc);
loadScripts(utc);
}
void CreatureBlueprint::loadAttributes(const GffStruct &utc) {
for (auto &classGff : utc.getList("ClassList")) {
int clazz = classGff.getInt("Class");
int level = classGff.getInt("ClassLevel");
_attributes.classLevels.push_back(make_pair(static_cast<ClassType>(clazz), level));
}
_attributes.abilities[Ability::Strength] = utc.getInt("Str");
_attributes.abilities[Ability::Dexterity] = utc.getInt("Dex");
_attributes.abilities[Ability::Constitution] = utc.getInt("Con");
_attributes.abilities[Ability::Intelligence] = utc.getInt("Int");
_attributes.abilities[Ability::Wisdom] = utc.getInt("Wis");
_attributes.abilities[Ability::Charisma] = utc.getInt("Cha");
}
void CreatureBlueprint::loadScripts(const GffStruct &utc) {
_onSpawn = utc.getString("ScriptSpawn");
_onUserDefined = utc.getString("ScriptUserDefine");
}
const string &CreatureBlueprint::tag() const {
@ -59,6 +80,18 @@ const string &CreatureBlueprint::conversation() const {
return _conversation;
}
const CreatureAttributes &CreatureBlueprint::attributes() const {
return _attributes;
}
const string &CreatureBlueprint::onSpawn() const {
return _onSpawn;
}
const string &CreatureBlueprint::onUserDefined() const {
return _onUserDefined;
}
} // namespace game
} // namespace reone

View file

@ -23,6 +23,8 @@
#include "../../resource/gfffile.h"
#include "../rp/types.h"
namespace reone {
namespace game {
@ -37,32 +39,29 @@ public:
const std::vector<std::string> &equipment() const;
int appearance() const;
const std::string &conversation() const;
const CreatureAttributes &attributes() const;
const std::string &onSpawn() const;
const std::string &onUserDefined() const;
private:
enum class ScriptType {
OnNotice,
SpellAt,
Attacked,
Damaged,
Disturbed,
EndRound,
EndDialogu,
Dialogue,
Spawn,
Rested,
Death,
UserDefine,
OnBlocked
};
std::string _tag;
std::vector<std::string> _equipment;
int _appearance { 0 };
std::string _conversation;
std::unordered_map<ScriptType, std::string> _scripts;
CreatureAttributes _attributes;
// Scripts
std::string _onSpawn;
std::string _onUserDefined;
// END Scripts
CreatureBlueprint(const CreatureBlueprint &) = delete;
CreatureBlueprint &operator=(const CreatureBlueprint &) = delete;
void loadAttributes(const resource::GffStruct &utc);
void loadScripts(const resource::GffStruct &utc);
};
} // namespace game

View file

@ -24,6 +24,7 @@
#include "../../game.h"
#include "../../portraits.h"
#include "../../rp/classes.h"
using namespace std;
using namespace std::placeholders;
@ -65,9 +66,7 @@ void CharacterGeneration::load() {
hideControl("NEW_LBL");
setControlText("LBL_NAME", "");
setControlText("LBL_CLASS", "");
setControlText("LBL_LEVEL", "");
setControlText("LBL_LEVEL_VAL", "");
setControlText("LBL_LEVEL_VAL", "1");
loadClassSelection();
loadQuickOrCustom();
@ -232,9 +231,28 @@ const CreatureConfiguration &CharacterGeneration::character() const {
void CharacterGeneration::setCharacter(const CreatureConfiguration &config) {
_character = config;
loadCharacterModel();
updateAttributes();
_portraitSelection->updatePortraits();
}
void CharacterGeneration::updateAttributes() {
setControlText("LBL_CLASS", getClassTitle(_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_VIT", to_string(vitality));
setControlText("LBL_DEF", to_string(defense));
setControlText("STR_AB_LBL", to_string(attrs.strength()));
setControlText("DEX_AB_LBL", to_string(attrs.dexterity()));
setControlText("CON_AB_LBL", to_string(attrs.constitution()));
setControlText("INT_AB_LBL", to_string(attrs.intelligence()));
setControlText("WIS_AB_LBL", to_string(attrs.wisdom()));
setControlText("CHA_AB_LBL", to_string(attrs.charisma()));
}
void CharacterGeneration::setQuickStep(int step) {
_quick->setStep(step);
}

View file

@ -83,6 +83,7 @@ private:
// END Sub GUI
void loadCharacterModel();
void updateAttributes();
gui::GUI *getSubGUI() const;
std::shared_ptr<scene::ModelSceneNode> getCharacterModel(scene::SceneGraph &sceneGraph);

View file

@ -23,6 +23,7 @@
#include "../../characters.h"
#include "../../game.h"
#include "../../object/creature.h"
#include "../../rp/classes.h"
#include "../colors.h"
@ -47,15 +48,6 @@ static map<Gender, int> g_genderStrRefs {
{ Gender::Female, 647 }
};
static map<ClassType, int> g_classStrRefs {
{ ClassType::Scout, 133 },
{ ClassType::Soldier, 134 },
{ ClassType::Scoundrel, 135 },
{ ClassType::JediGuardian, 353 },
{ ClassType::JediConsular, 354 },
{ ClassType::JediSentinel, 355 }
};
static map<ClassType, int> g_classDescStrRefs {
{ ClassType::Scoundrel, 32109 },
{ ClassType::Scout, 32110 },
@ -228,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 += " " + Resources::instance().getString(g_classStrRefs[button.config.clazz]);
classText += " " + getClassTitle(button.config.clazz);
string descText(Resources::instance().getString(g_classDescStrRefs[button.config.clazz]));

View file

@ -93,6 +93,10 @@ void Creature::load(const shared_ptr<CreatureBlueprint> &blueprint) {
}
shared_ptr<TwoDaTable> appearance(Resources::instance().get2DA("appearance"));
loadAppearance(*appearance, _blueprint->appearance());
_attributes = blueprint->attributes();
_onSpawn = blueprint->onSpawn();
_onUserDefined = blueprint->onUserDefined();
}
void Creature::loadAppearance(const TwoDaTable &table, int row) {

View file

@ -116,6 +116,13 @@ private:
float _runSpeed { 0.0f };
MovementType _movementType { MovementType::None };
bool _talking { false };
CreatureAttributes _attributes;
// Scripts
std::string _onSpawn;
// END Scripts
// Loading

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

@ -0,0 +1,82 @@
/*
* Copyright (c) 2020 Vsevolod Kremianskii
*
* 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 <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 }
};
const 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.abilities.insert(make_pair(Ability::Strength, classes->getInt(row, "str")));
attrs.abilities.insert(make_pair(Ability::Dexterity, classes->getInt(row, "dex")));
attrs.abilities.insert(make_pair(Ability::Constitution, classes->getInt(row, "con")));
attrs.abilities.insert(make_pair(Ability::Intelligence, classes->getInt(row, "int")));
attrs.abilities.insert(make_pair(Ability::Wisdom, classes->getInt(row, "wis")));
attrs.abilities.insert(make_pair(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

35
src/game/rp/classes.h Normal file
View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2020 Vsevolod Kremianskii
*
* 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 "types.h"
namespace reone {
namespace game {
const std::string &getClassTitle(ClassType clazz);
CreatureAttributes getClassAttributes(ClassType clazz);
int getClassHitPoints(ClassType clazz, int level);
int getClassDefenseBonus(ClassType clazz, int level);
} // namespace game
} // namespace reone

View file

@ -17,6 +17,7 @@
#pragma once
#include <map>
#include <utility>
#include <vector>
@ -74,8 +75,15 @@ enum class Skill {
struct CreatureAttributes {
std::vector<std::pair<ClassType, int>> classLevels;
std::vector<int> abilities;
std::vector<int> skills;
std::map<Ability, int> abilities;
std::map<Skill, int> skills;
int strength() const { return abilities.find(Ability::Strength)->second; }
int dexterity() const { return abilities.find(Ability::Dexterity)->second; }
int constitution() const { return abilities.find(Ability::Constitution)->second; }
int intelligence() const { return abilities.find(Ability::Intelligence)->second; }
int wisdom() const { return abilities.find(Ability::Wisdom)->second; }
int charisma() const { return abilities.find(Ability::Charisma)->second; }
};
} // namespace game