CreatureLib/src/Battling/Models/Creature.hpp

239 lines
11 KiB
C++

#ifndef CREATURELIB_BATTLECREATURE_HPP
#define CREATURELIB_BATTLECREATURE_HPP
#include "../../Defines.hpp"
#include "../../Library/ClampedStatisticSet.hpp"
#include "../../Library/CreatureData/CreatureSpecies.hpp"
#include "../../Library/Items/Item.hpp"
#include "../ScriptHandling/ScriptAggregator.hpp"
#include "../ScriptHandling/ScriptSet.hpp"
#include "../ScriptHandling/ScriptSource.hpp"
#include "CreatureIndex.hpp"
#include "DamageSource.hpp"
#include "LearnedAttack.hpp"
namespace CreatureLib::Battling {
// Forward declare battle class
class Battle;
class BattleSide;
class BattleLibrary;
class Creature : public ScriptSource {
protected:
ArbUt::BorrowedPtr<const BattleLibrary> _library;
ArbUt::BorrowedPtr<const Library::CreatureSpecies> _species;
ArbUt::BorrowedPtr<const Library::SpeciesVariant> _variant;
ArbUt::OptionalBorrowedPtr<const Library::CreatureSpecies> _displaySpecies = nullptr;
ArbUt::OptionalBorrowedPtr<const Library::SpeciesVariant> _displayVariant = nullptr;
level_int_t _level;
u32 _experience;
u32 _uniqueIdentifier;
Library::Gender _gender;
u8 _coloring;
u32 _currentHealth = 0;
f32 _weight;
f32 _height;
Library::ClampedStatisticSet<i8, -6, 6> _statBoost;
Library::StatisticSet<u32> _flatStats;
Library::StatisticSet<u32> _boostedStats;
struct BattleData {
bool OnBattleField = false;
ArbUt::OptionalBorrowedPtr<Battle> Battle = nullptr;
ArbUt::OptionalBorrowedPtr<BattleSide> Side = nullptr;
CreatureIndex Index = {};
std::unordered_set<ArbUt::BorrowedPtr<Creature>> SeenOpponents;
} _battleData = {};
std::optional<std::string> _nickname = {};
CreatureLib::Library::TalentIndex _talentIndex = {};
ArbUt::OptionalUniquePtr<BattleScript> _activeTalent = {};
bool _hasOverridenTalent = false;
ArbUt::OptionalBorrowedPtr<const Library::Talent> _overridenTalent = {};
ArbUt::OptionalUniquePtrList<LearnedAttack> _attacks = {};
bool _allowedExperienceGain = {};
ArbUt::OptionalUniquePtr<BattleScript> _status = nullptr;
ScriptSet _volatile = {};
std::vector<u8> _types = {};
ArbUt::OptionalBorrowedPtr<const Library::Item> _heldItem;
ArbUt::OptionalUniquePtr<BattleScript> _heldItemTriggerScript = nullptr;
private:
void OnFaint(DamageSource damageSource);
public:
Creature(const ArbUt::BorrowedPtr<const BattleLibrary>& library,
const ArbUt::BorrowedPtr<const Library::CreatureSpecies>& species,
const ArbUt::BorrowedPtr<const Library::SpeciesVariant>& variant, level_int_t level, u32 experience,
u32 uid, Library::Gender gender, u8 coloring, ArbUt::OptionalBorrowedPtr<const Library::Item> heldItem,
std::optional<std::string> nickname, const Library::TalentIndex& talent,
const std::vector<LearnedAttack*>& attacks, bool allowedExperienceGain = true);
virtual ~Creature();
virtual void Initialize() {
RecalculateFlatStats();
_currentHealth = GetBoostedStat(Library::Statistic::Health);
}
inline const ArbUt::BorrowedPtr<const BattleLibrary>& GetLibrary() const noexcept { return _library; }
inline const ArbUt::BorrowedPtr<const Library::CreatureSpecies>& GetSpecies() const noexcept {
return _species;
}
inline const ArbUt::BorrowedPtr<const Library::SpeciesVariant>& GetVariant() const noexcept { return _variant; }
virtual void ChangeSpecies(const ArbUt::BorrowedPtr<const Library::CreatureSpecies>& species,
const ArbUt::BorrowedPtr<const Library::SpeciesVariant>& variant);
virtual void ChangeVariant(const ArbUt::StringView& variantName);
virtual void ChangeVariant(const ArbUt::BorrowedPtr<const Library::SpeciesVariant>& variant);
inline level_int_t GetLevel() const noexcept { return _level; }
inline u32 GetExperience() const noexcept { return _experience; }
inline u32 GetUniqueIdentifier() const noexcept { return _uniqueIdentifier; }
inline Library::Gender GetGender() const noexcept { return _gender; }
inline u8 GetColoring() const noexcept { return _coloring; }
inline bool HasHeldItem(const ArbUt::BasicStringView& name) const noexcept {
return _heldItem.HasValue() && _heldItem.GetValue()->GetName() == name;
}
inline bool HasHeldItem(u32 nameHash) const noexcept {
return _heldItem.HasValue() && _heldItem.GetValue()->GetName() == nameHash;
}
inline const ArbUt::OptionalBorrowedPtr<const Library::Item>& GetHeldItem() const noexcept { return _heldItem; }
void SetHeldItem(const ArbUt::StringView& itemName);
void SetHeldItemByHash(u32 itemNameHash);
inline void SetHeldItem(const ArbUt::BorrowedPtr<const Library::Item>& item) noexcept { _heldItem = item; };
bool ConsumeHeldItem();
inline u32 GetCurrentHealth() const noexcept { return _currentHealth; }
inline f32 GetWeight() const noexcept { return _weight; }
inline void SetWeight(f32 weight) noexcept {
if (weight < 0.1f) {
weight = 0.1f;
}
_weight = weight;
}
inline f32 GetHeight() const noexcept { return _height; }
inline void SetHeight(f32 height) noexcept {
if (height < 0.1f) {
height = 0.1f;
}
_height = height;
}
void SetBattleData(const ArbUt::BorrowedPtr<Battle>& battle, const ArbUt::BorrowedPtr<BattleSide>& side);
virtual void ClearBattleData() noexcept;
inline const ArbUt::OptionalBorrowedPtr<Battle>& GetBattle() const { return _battleData.Battle; }
inline const ArbUt::OptionalBorrowedPtr<BattleSide>& GetBattleSide() const { return _battleData.Side; }
void SetOnBattleField(bool value);
inline void SetBattleIndex(const CreatureIndex& index) { _battleData.Index = index; }
inline const CreatureIndex& GetBattleIndex() const noexcept { return _battleData.Index; }
inline bool IsOnBattleField() const { return _battleData.OnBattleField; }
inline std::optional<std::string_view> GetNickname() const noexcept {
if (_nickname.has_value()) {
return _nickname.value();
}
return {};
}
inline void SetNickname(std::string nickname) noexcept { _nickname = nickname; }
const CreatureLib::Library::TalentIndex& GetRealTalent() const noexcept { return _talentIndex; }
ArbUt::BorrowedPtr<const Library::Talent> GetActiveTalent() const;
/// Are we allowed to use this creature in a battle?
[[nodiscard]] virtual bool IsUsable() const noexcept;
[[nodiscard]] bool IsFainted() const noexcept;
[[nodiscard]] const std::vector<u8>& GetTypes() const noexcept;
[[nodiscard]] bool HasType(u8 type) const noexcept;
void SetType(u8 index, u8 type) noexcept;
u32 GetMaxHealth() const noexcept { return _boostedStats.GetHealth(); }
void ChangeLevelBy(i8 amount);
void Damage(u32 damage, DamageSource source);
void Heal(u32 amount, bool canRevive = false);
void RestoreAllAttackUses() noexcept;
void OverrideActiveTalent(const ArbUt::StringView& talent);
void AddExperience(u32 amount);
void MarkOpponentAsSeen(ArbUt::BorrowedPtr<Creature> creature) { _battleData.SeenOpponents.insert(creature); }
const std::unordered_set<ArbUt::BorrowedPtr<Creature>>& GetSeenOpponents() const {
return _battleData.SeenOpponents;
}
size_t ScriptCount() const override;
void GetActiveScripts(ArbUt::List<ScriptWrapper>& scripts) override;
void GetOwnScripts(ArbUt::List<ScriptWrapper>& scripts) override;
void ClearVolatileScripts();
BattleScript* non_null AddVolatileScript(const ArbUt::StringView& name);
BattleScript* non_null AddVolatileScript(BattleScript* non_null script);
void RemoveVolatileScript(const ArbUt::BasicStringView& name);
void RemoveVolatileScript(BattleScript* non_null script);
bool HasVolatileScript(const ArbUt::BasicStringView& name) const;
const ArbUt::OptionalUniquePtrList<LearnedAttack>& GetAttacks() noexcept { return _attacks; }
bool HasAttack(const ArbUt::StringView& name) {
for (auto& a : _attacks) {
if (a == nullptr)
continue;
if (a->GetAttack()->GetName() == name)
return true;
}
return false;
}
ArbUt::OptionalBorrowedPtr<const Library::CreatureSpecies> GetDisplaySpecies() const noexcept;
ArbUt::OptionalBorrowedPtr<const Library::SpeciesVariant> GetDisplayVariant() const noexcept;
void SetDisplaySpecies(const ArbUt::BorrowedPtr<const Library::CreatureSpecies>& species) noexcept {
_displaySpecies = species.GetRaw();
}
void SetDisplayVariant(ArbUt::BorrowedPtr<const Library::SpeciesVariant> variant) noexcept {
_displayVariant = variant.GetRaw();
};
inline bool AllowedExperienceGain() const noexcept { return _allowedExperienceGain; }
inline void SetAllowedExperienceGain(bool allowed) noexcept { _allowedExperienceGain = allowed; }
u8 GetAvailableAttackSlot() const noexcept;
void AddAttack(LearnedAttack* non_null attack);
void ReplaceAttack(size_t index, LearnedAttack* non_null attack);
void SwapAttacks(size_t a, size_t b) { _attacks.Swap(a, b); }
void SetStatus(const ArbUt::StringView& name);
void ClearStatus();
const ArbUt::StringView& GetStatusName() const noexcept {
if (!_status.HasValue())
return ArbUt::StringView::EmptyString();
return _status.GetValue()->GetName();
}
// region Stat APIs
bool ChangeStatBoost(Library::Statistic stat, i8 diffAmount, bool selfInflicted = false);
[[nodiscard]] inline u32 GetFlatStat(Library::Statistic stat) const { return _flatStats.GetStat(stat); }
[[nodiscard]] inline u32 GetBoostedStat(Library::Statistic stat) const { return _boostedStats.GetStat(stat); }
[[nodiscard]] inline u32 GetBaseStat(Library::Statistic stat) const { return _variant->GetStatistic(stat); }
[[nodiscard]] inline i8 GetStatBoost(Library::Statistic stat) const { return _statBoost.GetStat(stat); }
void RecalculateFlatStats();
void RecalculateBoostedStats();
void RecalculateFlatStat(Library::Statistic);
void RecalculateBoostedStat(Library::Statistic);
// endregion
virtual Creature* non_null Clone() const;
};
}
#endif // CREATURELIB_CREATURE_HPP