Support changing species for a creature.
continuous-integration/drone/push Build is passing Details

Signed-off-by: Deukhoofd <Deukhoofd@gmail.com>
This commit is contained in:
Deukhoofd 2020-08-13 10:38:56 +02:00
parent 51325943ab
commit bb35248174
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
3 changed files with 293 additions and 277 deletions

View File

@ -22,6 +22,10 @@ BORROWED_GET_FUNC(Creature, GetLibrary, const CreatureLib::Battling::BattleLibra
BORROWED_GET_FUNC(Creature, GetSpecies, const CreatureLib::Library::CreatureSpecies*); BORROWED_GET_FUNC(Creature, GetSpecies, const CreatureLib::Library::CreatureSpecies*);
BORROWED_GET_FUNC(Creature, GetVariant, const CreatureLib::Library::SpeciesVariant*); BORROWED_GET_FUNC(Creature, GetVariant, const CreatureLib::Library::SpeciesVariant*);
export uint8_t CreatureLib_Creature_ChangeSpecies(Creature* p, const CreatureLib::Library::CreatureSpecies* species,
const CreatureLib::Library::SpeciesVariant* variant) {
Try(p->ChangeSpecies(species, variant);)
}
export uint8_t CreatureLib_Creature_ChangeVariant(Creature* p, const CreatureLib::Library::SpeciesVariant* variant) { export uint8_t CreatureLib_Creature_ChangeVariant(Creature* p, const CreatureLib::Library::SpeciesVariant* variant) {
Try(p->ChangeVariant(variant);) Try(p->ChangeVariant(variant);)
} }

View File

@ -6,7 +6,8 @@
using namespace CreatureLib; using namespace CreatureLib;
Battling::Creature::Creature(ArbUt::BorrowedPtr<const BattleLibrary> library, namespace CreatureLib::Battling {
Creature::Creature(ArbUt::BorrowedPtr<const BattleLibrary> library,
const ArbUt::BorrowedPtr<const Library::CreatureSpecies>& species, const ArbUt::BorrowedPtr<const Library::CreatureSpecies>& species,
const ArbUt::BorrowedPtr<const Library::SpeciesVariant>& variant, uint8_t level, const ArbUt::BorrowedPtr<const Library::SpeciesVariant>& variant, uint8_t level,
uint32_t experience, uint32_t uid, Library::Gender gender, uint8_t coloring, uint32_t experience, uint32_t uid, Library::Gender gender, uint8_t coloring,
@ -14,8 +15,8 @@ Battling::Creature::Creature(ArbUt::BorrowedPtr<const BattleLibrary> library,
const Library::TalentIndex& talent, const std::vector<LearnedAttack*>& attacks, const Library::TalentIndex& talent, const std::vector<LearnedAttack*>& attacks,
bool allowedExperienceGain) bool allowedExperienceGain)
: _library(library), _species(species), _variant(variant), _level(level), _experience(experience), : _library(library), _species(species), _variant(variant), _level(level), _experience(experience),
_uniqueIdentifier(uid), _gender(gender), _coloring(coloring), _heldItem(heldItem), _nickname(std::move(nickname)), _uniqueIdentifier(uid), _gender(gender), _coloring(coloring), _heldItem(heldItem),
_talentIndex(talent), _hasOverridenTalent(false), _attacks(attacks), _nickname(std::move(nickname)), _talentIndex(talent), _hasOverridenTalent(false), _attacks(attacks),
_allowedExperienceGain(allowedExperienceGain) { _allowedExperienceGain(allowedExperienceGain) {
AssertNotNull(library) AssertNotNull(library)
AssertNotNull(species) AssertNotNull(species)
@ -28,9 +29,17 @@ Battling::Creature::Creature(ArbUt::BorrowedPtr<const BattleLibrary> library,
for (auto t : _variant->GetTypes()) { for (auto t : _variant->GetTypes()) {
_types.insert(t); _types.insert(t);
} }
} }
void Battling::Creature::ChangeVariant(ArbUt::BorrowedPtr<const Library::SpeciesVariant> variant) { void Creature::ChangeSpecies(const ArbUt::BorrowedPtr<const Library::CreatureSpecies>& species,
const ArbUt::BorrowedPtr<const Library::SpeciesVariant>& variant) {
AssertNotNull(species);
AssertNotNull(variant);
_species = species;
ChangeVariant(variant);
}
void Creature::ChangeVariant(const ArbUt::BorrowedPtr<const Library::SpeciesVariant>& variant) {
AssertNotNull(variant) AssertNotNull(variant)
_variant = variant; _variant = variant;
@ -41,8 +50,7 @@ void Battling::Creature::ChangeVariant(ArbUt::BorrowedPtr<const Library::Species
} }
// Grab the new active talent. // Grab the new active talent.
_activeTalent = _activeTalent = std::unique_ptr<Script>(_library->LoadScript(ScriptCategory::Talent, GetActiveTalent()));
std::unique_ptr<CreatureLib::Battling::Script>(_library->LoadScript(ScriptCategory::Talent, GetActiveTalent()));
// We modify the health of the creature by the change in its max health. // We modify the health of the creature by the change in its max health.
auto prevHealth = GetBoostedStat(CreatureLib::Library::Statistic::Health); auto prevHealth = GetBoostedStat(CreatureLib::Library::Statistic::Health);
@ -55,9 +63,9 @@ void Battling::Creature::ChangeVariant(ArbUt::BorrowedPtr<const Library::Species
} }
// TODO: consider variant specific attacks? // TODO: consider variant specific attacks?
} }
void Battling::Creature::ChangeLevelBy(int8_t amount) { void Creature::ChangeLevelBy(int8_t amount) {
auto level = _level + amount; auto level = _level + amount;
if (level > _library->GetSettings()->GetMaximalLevel()) if (level > _library->GetSettings()->GetMaximalLevel())
level = _library->GetSettings()->GetMaximalLevel(); level = _library->GetSettings()->GetMaximalLevel();
@ -66,24 +74,24 @@ void Battling::Creature::ChangeLevelBy(int8_t amount) {
_level = level; _level = level;
_experience = _library->GetGrowthRateLibrary()->CalculateExperience(_species->GetGrowthRate(), _level); _experience = _library->GetGrowthRateLibrary()->CalculateExperience(_species->GetGrowthRate(), _level);
RecalculateFlatStats(); RecalculateFlatStats();
} }
const ArbUt::StringView& Battling::Creature::GetActiveTalent() const { const ArbUt::StringView& Creature::GetActiveTalent() const {
if (_hasOverridenTalent) { if (_hasOverridenTalent) {
return _overridenTalentName; return _overridenTalentName;
} }
return _variant->GetTalent(_talentIndex); return _variant->GetTalent(_talentIndex);
} }
void Battling::Creature::SetBattleData(ArbUt::BorrowedPtr<Battle> battle, ArbUt::BorrowedPtr<BattleSide> side) { void Creature::SetBattleData(ArbUt::BorrowedPtr<Battle> battle, ArbUt::BorrowedPtr<BattleSide> side) {
_battle = battle; _battle = battle;
_side = side; _side = side;
this->ResetActiveScripts(); this->ResetActiveScripts();
} }
// region Stat APIs // region Stat APIs
bool Battling::Creature::ChangeStatBoost(Library::Statistic stat, int8_t diffAmount) { bool Creature::ChangeStatBoost(Library::Statistic stat, int8_t diffAmount) {
bool changed = false; bool changed = false;
if (diffAmount > 0) if (diffAmount > 0)
changed = this->_statBoost.IncreaseStatBy(stat, diffAmount); changed = this->_statBoost.IncreaseStatBy(stat, diffAmount);
@ -91,37 +99,37 @@ bool Battling::Creature::ChangeStatBoost(Library::Statistic stat, int8_t diffAmo
changed = this->_statBoost.DecreaseStatBy(stat, -diffAmount); changed = this->_statBoost.DecreaseStatBy(stat, -diffAmount);
this->RecalculateBoostedStat(stat); this->RecalculateBoostedStat(stat);
return changed; return changed;
} }
void Battling::Creature::RecalculateFlatStats() { void Creature::RecalculateFlatStats() {
auto& statCalc = this->_library->GetStatCalculator(); auto& statCalc = this->_library->GetStatCalculator();
this->_flatStats = statCalc->CalculateFlatStats(this); this->_flatStats = statCalc->CalculateFlatStats(this);
RecalculateBoostedStats(); RecalculateBoostedStats();
} }
void Battling::Creature::RecalculateBoostedStats() { void Creature::RecalculateBoostedStats() {
this->_boostedStats = this->_library->GetStatCalculator()->CalculateFlatStats(this); this->_boostedStats = this->_library->GetStatCalculator()->CalculateFlatStats(this);
} }
void Battling::Creature::RecalculateFlatStat(Library::Statistic stat) { void Creature::RecalculateFlatStat(Library::Statistic stat) {
auto s = this->_library->GetStatCalculator()->CalculateFlatStat(this, stat); auto s = this->_library->GetStatCalculator()->CalculateFlatStat(this, stat);
this->_flatStats.SetStat(stat, s); this->_flatStats.SetStat(stat, s);
RecalculateBoostedStat(stat); RecalculateBoostedStat(stat);
} }
void Battling::Creature::RecalculateBoostedStat(Library::Statistic stat) { void Creature::RecalculateBoostedStat(Library::Statistic stat) {
auto s = this->_library->GetStatCalculator()->CalculateBoostedStat(this, stat); auto s = this->_library->GetStatCalculator()->CalculateBoostedStat(this, stat);
this->_boostedStats.SetStat(stat, s); this->_boostedStats.SetStat(stat, s);
} }
// endregion // endregion
const ArbUt::BorrowedPtr<CreatureLib::Battling::Battle>& Battling::Creature::GetBattle() const { return _battle; } const ArbUt::BorrowedPtr<Battle>& Creature::GetBattle() const { return _battle; }
const ArbUt::BorrowedPtr<CreatureLib::Battling::BattleSide>& Battling::Creature::GetBattleSide() const { return _side; } const ArbUt::BorrowedPtr<BattleSide>& Creature::GetBattleSide() const { return _side; }
bool Battling::Creature::IsFainted() const noexcept { return this->_currentHealth == 0; } bool Creature::IsFainted() const noexcept { return this->_currentHealth == 0; }
void Battling::Creature::OnFaint() { void Creature::OnFaint() {
AssertNotNull(_battle) AssertNotNull(_battle)
AssertNotNull(_side) AssertNotNull(_side)
// HOOK: On Faint // HOOK: On Faint
@ -134,9 +142,9 @@ void Battling::Creature::OnFaint() {
_side->MarkSlotAsUnfillable(this); _side->MarkSlotAsUnfillable(this);
} }
_battle->ValidateBattleState(); _battle->ValidateBattleState();
} }
void Battling::Creature::Damage(uint32_t damage, Battling::DamageSource source) { void Creature::Damage(uint32_t damage, DamageSource source) {
if (damage > _currentHealth) { if (damage > _currentHealth) {
damage = _currentHealth; damage = _currentHealth;
} }
@ -153,9 +161,9 @@ void Battling::Creature::Damage(uint32_t damage, Battling::DamageSource source)
if (IsFainted() && damage > 0 && battle != nullptr) { if (IsFainted() && damage > 0 && battle != nullptr) {
OnFaint(); OnFaint();
} }
} }
void Battling::Creature::Heal(uint32_t amount, bool canRevive) { void Creature::Heal(uint32_t amount, bool canRevive) {
if (_currentHealth == 0 && !canRevive) { if (_currentHealth == 0 && !canRevive) {
return; return;
} }
@ -169,49 +177,49 @@ void Battling::Creature::Heal(uint32_t amount, bool canRevive) {
battle->TriggerEventListener<HealEvent>(this, _currentHealth, newHealth); battle->TriggerEventListener<HealEvent>(this, _currentHealth, newHealth);
} }
_currentHealth = newHealth; _currentHealth = newHealth;
} }
void Battling::Creature::RestoreAllAttackUses() noexcept { void Creature::RestoreAllAttackUses() noexcept {
for (auto& a : _attacks) { for (auto& a : _attacks) {
if (a != nullptr) { if (a != nullptr) {
a->RestoreAllUses(); a->RestoreAllUses();
} }
} }
} }
void Battling::Creature::OverrideActiveTalent(const ArbUt::StringView& talent) { void Creature::OverrideActiveTalent(const ArbUt::StringView& talent) {
_hasOverridenTalent = true; _hasOverridenTalent = true;
if (_activeTalent != nullptr) { if (_activeTalent != nullptr) {
_activeTalent->OnRemove(); _activeTalent->OnRemove();
_activeTalent.reset(this->_library->LoadScript(ScriptCategory::Talent, talent)); _activeTalent.reset(this->_library->LoadScript(ScriptCategory::Talent, talent));
} }
_overridenTalentName = talent; _overridenTalentName = talent;
} }
const std::unordered_set<uint8_t>& Battling::Creature::GetTypes() const noexcept { return _types; } const std::unordered_set<uint8_t>& Creature::GetTypes() const noexcept { return _types; }
bool Battling::Creature::HasType(uint8_t type) const noexcept { bool Creature::HasType(uint8_t type) const noexcept {
return std::find(_types.begin(), _types.end(), type) != _types.end(); return std::find(_types.begin(), _types.end(), type) != _types.end();
} }
size_t Battling::Creature::ScriptCount() const { size_t Creature::ScriptCount() const {
auto c = 3; auto c = 3;
if (_side != nullptr) { if (_side != nullptr) {
c += _side->ScriptCount(); c += _side->ScriptCount();
} }
return c; return c;
} }
void Battling::Creature::GetActiveScripts(ArbUt::List<ScriptWrapper>& scripts) { void Creature::GetActiveScripts(ArbUt::List<ScriptWrapper>& scripts) {
scripts.Append(ScriptWrapper::FromScript(&_activeTalent)); scripts.Append(ScriptWrapper::FromScript(&_activeTalent));
scripts.Append(ScriptWrapper::FromScript(&_status)); scripts.Append(ScriptWrapper::FromScript(&_status));
scripts.Append(ScriptWrapper::FromSet(&_volatile)); scripts.Append(ScriptWrapper::FromSet(&_volatile));
if (_side != nullptr) { if (_side != nullptr) {
_side->GetActiveScripts(scripts); _side->GetActiveScripts(scripts);
} }
} }
void Battling::Creature::ClearVolatileScripts() { _volatile.Clear(); } void Creature::ClearVolatileScripts() { _volatile.Clear(); }
void Battling::Creature::AddExperience(uint32_t amount) { void Creature::AddExperience(uint32_t amount) {
auto maxLevel = _library->GetSettings()->GetMaximalLevel(); auto maxLevel = _library->GetSettings()->GetMaximalLevel();
if (_level >= maxLevel) { if (_level >= maxLevel) {
return; return;
@ -226,35 +234,35 @@ void Battling::Creature::AddExperience(uint32_t amount) {
} }
_experience = exp; _experience = exp;
_level = level; _level = level;
} }
ArbUt::BorrowedPtr<const Library::CreatureSpecies> Battling::Creature::GetDisplaySpecies() const noexcept { ArbUt::BorrowedPtr<const Library::CreatureSpecies> Creature::GetDisplaySpecies() const noexcept {
auto species = _displaySpecies; auto species = _displaySpecies;
if (species == nullptr) if (species == nullptr)
species = _species; species = _species;
return species; return species;
} }
ArbUt::BorrowedPtr<const Library::SpeciesVariant> Battling::Creature::GetDisplayVariant() const noexcept { ArbUt::BorrowedPtr<const Library::SpeciesVariant> Creature::GetDisplayVariant() const noexcept {
auto variant = _displayVariant; auto variant = _displayVariant;
if (variant == nullptr) if (variant == nullptr)
variant = _variant; variant = _variant;
return variant; return variant;
} }
void Battling::Creature::SetHeldItem(const ArbUt::BasicStringView& itemName) { void Creature::SetHeldItem(const ArbUt::BasicStringView& itemName) {
ArbUt::BorrowedPtr<const Library::Item> item; ArbUt::BorrowedPtr<const Library::Item> item;
if (!_library->GetItemLibrary()->TryGet(itemName.GetHash(), item)) { if (!_library->GetItemLibrary()->TryGet(itemName.GetHash(), item)) {
THROW_CREATURE("Item not found '" << itemName.c_str() << "'."); THROW_CREATURE("Item not found '" << itemName.c_str() << "'.");
} }
_heldItem = item; _heldItem = item;
} }
void Battling::Creature::SetHeldItem(uint32_t itemNameHash) { void Creature::SetHeldItem(uint32_t itemNameHash) {
ArbUt::BorrowedPtr<const Library::Item> item; ArbUt::BorrowedPtr<const Library::Item> item;
if (!_library->GetItemLibrary()->TryGet(itemNameHash, item)) { if (!_library->GetItemLibrary()->TryGet(itemNameHash, item)) {
THROW_CREATURE("Item not found."); THROW_CREATURE("Item not found.");
} }
_heldItem = item; _heldItem = item;
} }
void Battling::Creature::AddVolatileScript(const ArbUt::StringView& name) { void Creature::AddVolatileScript(const ArbUt::StringView& name) {
auto script = _volatile.Get(name); auto script = _volatile.Get(name);
if (script != nullptr) { if (script != nullptr) {
script->Stack(); script->Stack();
@ -265,13 +273,13 @@ void Battling::Creature::AddVolatileScript(const ArbUt::StringView& name) {
THROW_CREATURE("Invalid volatile script requested for creature: '" << name.c_str() << "'."); THROW_CREATURE("Invalid volatile script requested for creature: '" << name.c_str() << "'.");
} }
_volatile.Add(script.GetRaw()); _volatile.Add(script.GetRaw());
} }
void Battling::Creature::AddVolatileScript(Script* script) { _volatile.Add(script); } void Creature::AddVolatileScript(Script* script) { _volatile.Add(script); }
void Battling::Creature::RemoveVolatileScript(const ArbUt::BasicStringView& name) { _volatile.Remove(name); } void Creature::RemoveVolatileScript(const ArbUt::BasicStringView& name) { _volatile.Remove(name); }
void Battling::Creature::RemoveVolatileScript(Battling::Script* script) { _volatile.Remove(script->GetName()); } void Creature::RemoveVolatileScript(Script* script) { _volatile.Remove(script->GetName()); }
bool Battling::Creature::HasVolatileScript(const ArbUt::BasicStringView& name) const { return _volatile.Has(name); } bool Creature::HasVolatileScript(const ArbUt::BasicStringView& name) const { return _volatile.Has(name); }
void Battling::Creature::AddAttack(Battling::LearnedAttack* attack) { void Creature::AddAttack(LearnedAttack* attack) {
for (size_t i = 0; i < _attacks.Count(); i++) { for (size_t i = 0; i < _attacks.Count(); i++) {
if (_attacks[i] == nullptr) { if (_attacks[i] == nullptr) {
_attacks.Set(i, attack); _attacks.Set(i, attack);
@ -282,8 +290,8 @@ void Battling::Creature::AddAttack(Battling::LearnedAttack* attack) {
_attacks.Append(attack); _attacks.Append(attack);
} }
THROW_CREATURE("Can't add attack. The creature already has the maximum amount of attacks."); THROW_CREATURE("Can't add attack. The creature already has the maximum amount of attacks.");
} }
uint8_t Battling::Creature::GetAvailableAttackSlot() const noexcept { uint8_t Creature::GetAvailableAttackSlot() const noexcept {
for (uint8_t i = 0; i < (uint8_t)_attacks.Count(); i++) { for (uint8_t i = 0; i < (uint8_t)_attacks.Count(); i++) {
if (_attacks[i] == nullptr) { if (_attacks[i] == nullptr) {
return i; return i;
@ -293,8 +301,8 @@ uint8_t Battling::Creature::GetAvailableAttackSlot() const noexcept {
return _attacks.Count(); return _attacks.Count();
} }
return -1; return -1;
} }
void Battling::Creature::ReplaceAttack(size_t index, Battling::LearnedAttack* attack) { void Creature::ReplaceAttack(size_t index, LearnedAttack* attack) {
if (_attacks.Count() <= index) { if (_attacks.Count() <= index) {
if (_attacks.Count() < _library->GetStaticLib()->GetSettings()->GetMaximalAttacks()) { if (_attacks.Count() < _library->GetStaticLib()->GetSettings()->GetMaximalAttacks()) {
_attacks.Append(attack); _attacks.Append(attack);
@ -303,4 +311,6 @@ void Battling::Creature::ReplaceAttack(size_t index, Battling::LearnedAttack* at
<< "."); << ".");
} }
_attacks.Set(index, attack); _attacks.Set(index, attack);
}
} }

View File

@ -85,7 +85,9 @@ namespace CreatureLib::Battling {
return _species; return _species;
} }
inline const ArbUt::BorrowedPtr<const Library::SpeciesVariant>& GetVariant() const noexcept { return _variant; } inline const ArbUt::BorrowedPtr<const Library::SpeciesVariant>& GetVariant() const noexcept { return _variant; }
virtual void ChangeVariant(ArbUt::BorrowedPtr<const Library::SpeciesVariant> variant); virtual void ChangeSpecies(const ArbUt::BorrowedPtr<const Library::CreatureSpecies>& species,
const ArbUt::BorrowedPtr<const Library::SpeciesVariant>& variant);
virtual void ChangeVariant(const ArbUt::BorrowedPtr<const Library::SpeciesVariant>& variant);
inline uint8_t GetLevel() const noexcept { return _level; } inline uint8_t GetLevel() const noexcept { return _level; }
inline uint32_t GetExperience() const noexcept { return _experience; } inline uint32_t GetExperience() const noexcept { return _experience; }
inline uint32_t GetUniqueIdentifier() const noexcept { return _uniqueIdentifier; } inline uint32_t GetUniqueIdentifier() const noexcept { return _uniqueIdentifier; }