Added lots of security using asserts.
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is failing
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	continuous-integration/drone/push Build is failing
				
			This commit is contained in:
		@@ -116,6 +116,8 @@ Standard:        Cpp11
 | 
			
		||||
StatementMacros:
 | 
			
		||||
  - Q_UNUSED
 | 
			
		||||
  - QT_REQUIRE_VERSION
 | 
			
		||||
  - Assert
 | 
			
		||||
  - AssertNotNull
 | 
			
		||||
TabWidth:        8
 | 
			
		||||
UseTab:          Never
 | 
			
		||||
...
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
#include "EventHook.hpp"
 | 
			
		||||
@@ -16,6 +16,7 @@ namespace CreatureLib::Battling {
 | 
			
		||||
        void RegisterListener(EVENT_HOOK_FUNC(func)) { _listeners.push_back(func); }
 | 
			
		||||
 | 
			
		||||
        void TriggerEvent(EventData* eventData) const {
 | 
			
		||||
            AssertNotNull(eventData)
 | 
			
		||||
            for (auto listener : _listeners) {
 | 
			
		||||
                listener(eventData);
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,8 @@
 | 
			
		||||
#include "ChoiceQueue.hpp"
 | 
			
		||||
#include <Arbutils/Assert.hpp>
 | 
			
		||||
 | 
			
		||||
bool CreatureLib::Battling::ChoiceQueue::MoveCreatureChoiceNext(CreatureLib::Battling::Creature* creature) {
 | 
			
		||||
    AssertNotNull(creature)
 | 
			
		||||
    // Find which index the creature choice is at.
 | 
			
		||||
    size_t choiceIndex = SIZE_MAX;
 | 
			
		||||
    for (size_t index = _current; index < _queue.size(); index++) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,12 @@
 | 
			
		||||
#include "TurnHandler.hpp"
 | 
			
		||||
#include <Arbutils/Assert.hpp>
 | 
			
		||||
#include "../../Library/Exceptions/NotImplementedException.hpp"
 | 
			
		||||
#include "../Models/Battle.hpp"
 | 
			
		||||
#include "../ScriptHandling/ScriptMacros.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace CreatureLib::Battling;
 | 
			
		||||
 | 
			
		||||
void TurnHandler::RunTurn(Battle* battle, ChoiceQueue* queue) {
 | 
			
		||||
void TurnHandler::RunTurn(ChoiceQueue* queue) {
 | 
			
		||||
    AssertNotNull(queue)
 | 
			
		||||
    for (auto choice : queue->GetInnerQueue()) {
 | 
			
		||||
        HOOK(OnBeforeTurn, choice, choice);
 | 
			
		||||
    }
 | 
			
		||||
@@ -31,6 +32,7 @@ void TurnHandler::ExecuteChoice(BaseTurnChoice* choice) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    auto battle = user->GetBattle();
 | 
			
		||||
    AssertNotNull(battle)
 | 
			
		||||
    // If the user is not in the field, we don't want to execute its choice.
 | 
			
		||||
    if (!battle->CreatureInField(user)) {
 | 
			
		||||
        return;
 | 
			
		||||
@@ -51,6 +53,7 @@ void TurnHandler::ExecuteChoice(BaseTurnChoice* choice) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TurnHandler::ExecuteAttackChoice(AttackTurnChoice* choice) {
 | 
			
		||||
    AssertNotNull(choice)
 | 
			
		||||
    auto attackName = choice->GetAttack()->GetAttack()->GetName();
 | 
			
		||||
    HOOK(ChangeAttack, choice, choice, &attackName);
 | 
			
		||||
    if (attackName != choice->GetAttack()->GetAttack()->GetName()) {
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@ namespace CreatureLib::Battling {
 | 
			
		||||
        static void ExecuteFleeChoice(FleeTurnChoice* choice);
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        static void RunTurn(Battle* battle, ChoiceQueue* queue);
 | 
			
		||||
        static void RunTurn(ChoiceQueue* queue);
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,4 @@
 | 
			
		||||
#include "BattleLibrary.hpp"
 | 
			
		||||
#include <cassert>
 | 
			
		||||
 | 
			
		||||
using namespace CreatureLib::Battling;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
#include "BattleStatCalculator.hpp"
 | 
			
		||||
#include <Arbutils/Assert.hpp>
 | 
			
		||||
#include "../../Library/Exceptions/NotImplementedException.hpp"
 | 
			
		||||
#include "../Models/Creature.hpp"
 | 
			
		||||
 | 
			
		||||
@@ -24,12 +25,14 @@ Battling::BattleStatCalculator::CalculateBoostedStats(Battling::Creature* creatu
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t CalculateHealthStat(Battling::Creature* creature) {
 | 
			
		||||
    AssertNotNull(creature)
 | 
			
		||||
    auto level = creature->GetLevel();
 | 
			
		||||
    auto a = (creature->GetBaseStat(Library::Statistic::Health)) * 2 * level;
 | 
			
		||||
    return floor(a / 100) + level + 10;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t CalculateOtherStat(Battling::Creature* creature, Library::Statistic stat) {
 | 
			
		||||
    AssertNotNull(creature)
 | 
			
		||||
    auto level = creature->GetLevel();
 | 
			
		||||
    auto a = (creature->GetBaseStat(stat)) * 2 * level;
 | 
			
		||||
    return floor(a / 100) + 10;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,11 @@
 | 
			
		||||
#include "DamageLibrary.hpp"
 | 
			
		||||
#include <Arbutils/Assert.hpp>
 | 
			
		||||
#include "../ScriptHandling/ScriptMacros.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace CreatureLib::Battling;
 | 
			
		||||
uint32_t DamageLibrary::GetDamage(ExecutingAttack* attack, Creature* target, uint8_t hitIndex) const {
 | 
			
		||||
    AssertNotNull(attack)
 | 
			
		||||
    AssertNotNull(target)
 | 
			
		||||
    auto levelMod = static_cast<float>(2 * attack->GetUser()->GetLevel());
 | 
			
		||||
    auto hit = attack->GetAttackDataForTarget(target)->GetHit(hitIndex);
 | 
			
		||||
    auto bp = hit->GetBasePower();
 | 
			
		||||
@@ -15,13 +18,18 @@ uint32_t DamageLibrary::GetDamage(ExecutingAttack* attack, Creature* target, uin
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t DamageLibrary::GetBasePower(ExecutingAttack* attack, Creature* target, uint8_t hitIndex) const {
 | 
			
		||||
    AssertNotNull(attack)
 | 
			
		||||
    AssertNotNull(target)
 | 
			
		||||
    auto bp = attack->GetAttack()->GetAttack()->GetBasePower();
 | 
			
		||||
    HOOK(OverrideBasePower, attack, attack, target, hitIndex, &bp);
 | 
			
		||||
    return bp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float DamageLibrary::GetStatModifier(ExecutingAttack* attack, Creature* target, uint8_t hitIndex) const {
 | 
			
		||||
    AssertNotNull(attack)
 | 
			
		||||
    AssertNotNull(target)
 | 
			
		||||
    auto user = attack->GetUser();
 | 
			
		||||
    AssertNotNull(user)
 | 
			
		||||
    HOOK(ChangeDamageStatsUser, attack, attack, target, hitIndex, &user);
 | 
			
		||||
    auto hit = attack->GetAttackDataForTarget(target)->GetHit(hitIndex);
 | 
			
		||||
    Library::Statistic offensiveStat;
 | 
			
		||||
@@ -57,8 +65,11 @@ float DamageLibrary::GetStatModifier(ExecutingAttack* attack, Creature* target,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float DamageLibrary::GetDamageModifier(ExecutingAttack* attack, Creature* target, uint8_t hitIndex) const {
 | 
			
		||||
    AssertNotNull(attack)
 | 
			
		||||
    AssertNotNull(target)
 | 
			
		||||
    float mod = 1;
 | 
			
		||||
    auto hit = attack->GetAttackDataForTarget(target)->GetHit(hitIndex);
 | 
			
		||||
    AssertNotNull(hit)
 | 
			
		||||
    mod *= hit->GetEffectiveness();
 | 
			
		||||
    HOOK(ModifyDamageModifier, attack, attack, target, hitIndex, &mod);
 | 
			
		||||
    return mod;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,8 @@
 | 
			
		||||
void CreatureLib::Battling::ExperienceLibrary::HandleExperienceGain(
 | 
			
		||||
    CreatureLib::Battling::Creature* faintedMon, const std::unordered_set<Creature*>& opponents) const {
 | 
			
		||||
    for (auto opponent : opponents) {
 | 
			
		||||
        if (opponent == nullptr)
 | 
			
		||||
            continue;
 | 
			
		||||
        auto levelDiff = faintedMon->GetLevel() - opponent->GetLevel() + 10;
 | 
			
		||||
        if (levelDiff <= 0)
 | 
			
		||||
            continue;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,11 @@
 | 
			
		||||
#include "MiscLibrary.hpp"
 | 
			
		||||
#include <Arbutils/Assert.hpp>
 | 
			
		||||
#include "../Models/Battle.hpp"
 | 
			
		||||
#include "../TurnChoices/AttackTurnChoice.hpp"
 | 
			
		||||
 | 
			
		||||
bool CreatureLib::Battling::MiscLibrary::IsCritical(CreatureLib::Battling::ExecutingAttack* attack,
 | 
			
		||||
                                                    CreatureLib::Battling::Creature* target, uint8_t hit) const {
 | 
			
		||||
    AssertNotNull(target)
 | 
			
		||||
    auto rand = target->GetBattle()->GetRandom();
 | 
			
		||||
    return rand->Get(10) <= 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -31,6 +33,7 @@ static CreatureLib::Battling::LearnedAttack* GetReplacementAttack() {
 | 
			
		||||
bool CreatureLib::Battling::MiscLibrary::CanFlee(FleeTurnChoice* switchChoice) const { return true; }
 | 
			
		||||
CreatureLib::Battling::BaseTurnChoice*
 | 
			
		||||
CreatureLib::Battling::MiscLibrary::ReplacementAttack(Creature* user, CreatureIndex target) const {
 | 
			
		||||
    AssertNotNull(user)
 | 
			
		||||
    auto sideTarget = 0;
 | 
			
		||||
    if (user->GetBattleSide()->GetSideIndex() == 0)
 | 
			
		||||
        sideTarget = 1;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
#include "Battle.hpp"
 | 
			
		||||
#include <Arbutils/Assert.hpp>
 | 
			
		||||
#include "../../Library/Exceptions/NotImplementedException.hpp"
 | 
			
		||||
#include "../Flow/TurnHandler.hpp"
 | 
			
		||||
#include "../Flow/TurnOrdering.hpp"
 | 
			
		||||
@@ -9,6 +10,7 @@ using namespace CreatureLib::Battling;
 | 
			
		||||
const BattleLibrary* Battle::GetLibrary() const { return _library; }
 | 
			
		||||
 | 
			
		||||
bool Battle::CanUse(const BaseTurnChoice* choice) {
 | 
			
		||||
    AssertNotNull(choice)
 | 
			
		||||
    if (choice->GetKind() == TurnChoiceKind::Attack) {
 | 
			
		||||
        // HOOK: change number of uses needed.
 | 
			
		||||
        return dynamic_cast<const AttackTurnChoice*>(choice)->GetAttack()->GetRemainingUses() > 1;
 | 
			
		||||
@@ -17,6 +19,7 @@ bool Battle::CanUse(const BaseTurnChoice* choice) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Battle::TrySetChoice(BaseTurnChoice* choice) {
 | 
			
		||||
    AssertNotNull(choice)
 | 
			
		||||
    if (!CanUse(choice))
 | 
			
		||||
        return false;
 | 
			
		||||
    choice->GetUser()->GetBattleSide()->SetChoice(choice);
 | 
			
		||||
@@ -40,9 +43,7 @@ void Battle::CheckChoicesSetAndRun() {
 | 
			
		||||
    auto i = 0;
 | 
			
		||||
    for (auto side : _sides) {
 | 
			
		||||
        for (BaseTurnChoice* choice : side->GetChoices()) {
 | 
			
		||||
            if (choice == nullptr) {
 | 
			
		||||
                throw CreatureException("Choice was null");
 | 
			
		||||
            }
 | 
			
		||||
            AssertNotNull(choice)
 | 
			
		||||
            if (choice->GetKind() == TurnChoiceKind::Attack) {
 | 
			
		||||
                auto attack = (dynamic_cast<AttackTurnChoice*>((choice)))->GetAttack();
 | 
			
		||||
                uint8_t uses = 1;
 | 
			
		||||
@@ -60,7 +61,7 @@ void Battle::CheckChoicesSetAndRun() {
 | 
			
		||||
    }
 | 
			
		||||
    TurnOrdering::OrderChoices(choices, _random.GetRNG());
 | 
			
		||||
    this->_currentTurnQueue = new ChoiceQueue(choices);
 | 
			
		||||
    TurnHandler::RunTurn(this, this->_currentTurnQueue);
 | 
			
		||||
    TurnHandler::RunTurn(this->_currentTurnQueue);
 | 
			
		||||
    if (this->_currentTurnQueue->HasCompletedQueue) {
 | 
			
		||||
        delete this->_currentTurnQueue;
 | 
			
		||||
        this->_currentTurnQueue = nullptr;
 | 
			
		||||
@@ -72,6 +73,7 @@ ChoiceQueue* Battle::GetCurrentTurnQueue() const { return _currentTurnQueue; }
 | 
			
		||||
BattleRandom* Battle::GetRandom() { return &_random; }
 | 
			
		||||
 | 
			
		||||
bool Battle::CreatureInField(const Creature* creature) const {
 | 
			
		||||
    AssertNotNull(creature)
 | 
			
		||||
    for (auto s : _sides) {
 | 
			
		||||
        if (s->CreatureOnSide(creature))
 | 
			
		||||
            return true;
 | 
			
		||||
@@ -84,6 +86,7 @@ void Battle::ForceRecall(uint8_t side, uint8_t index) { _sides[side]->SetCreatur
 | 
			
		||||
void Battle::GetActiveScripts(std::vector<ScriptWrapper>& scripts) { scripts.emplace_back(&_volatile); }
 | 
			
		||||
 | 
			
		||||
void Battle::SwitchCreature(uint8_t sideIndex, uint8_t index, Creature* c) {
 | 
			
		||||
    AssertNotNull(c)
 | 
			
		||||
    auto side = this->_sides[sideIndex];
 | 
			
		||||
    side->SetCreature(c, index);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
#ifndef CREATURELIB_BATTLE_HPP
 | 
			
		||||
#define CREATURELIB_BATTLE_HPP
 | 
			
		||||
 | 
			
		||||
#include <Arbutils/Assert.hpp>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "../EventHooks/EventHook.hpp"
 | 
			
		||||
#include "../Flow/ChoiceQueue.hpp"
 | 
			
		||||
@@ -33,6 +34,10 @@ namespace CreatureLib::Battling {
 | 
			
		||||
               uint8_t numberOfSides = 2, uint8_t creaturesPerSide = 1)
 | 
			
		||||
            : _library(library), _parties(std::move(parties)), _canFlee(canFlee), _numberOfSides(numberOfSides),
 | 
			
		||||
              _creaturesPerSide(creaturesPerSide) {
 | 
			
		||||
            AssertNotNull(_library)
 | 
			
		||||
            for (auto p : parties)
 | 
			
		||||
                AssertNotNull(p)
 | 
			
		||||
 | 
			
		||||
            _sides = std::vector<BattleSide*>(numberOfSides);
 | 
			
		||||
            for (size_t i = 0; i < numberOfSides; i++) {
 | 
			
		||||
                _sides[i] = new BattleSide(i, this, creaturesPerSide);
 | 
			
		||||
@@ -64,6 +69,7 @@ namespace CreatureLib::Battling {
 | 
			
		||||
        bool CreatureInField(const Creature* creature) const;
 | 
			
		||||
 | 
			
		||||
        Creature* GetCreature(const CreatureIndex& target) const {
 | 
			
		||||
            Assert(target.GetSideIndex() < _sides.size())
 | 
			
		||||
            return _sides[target.GetSideIndex()]->GetCreature(target.GetCreatureIndex());
 | 
			
		||||
        }
 | 
			
		||||
        Creature* GetCreature(uint8_t side, uint8_t target) const { return _sides[side]->GetCreature(target); }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
#ifndef CREATURELIB_BATTLEPARTY_HPP
 | 
			
		||||
#define CREATURELIB_BATTLEPARTY_HPP
 | 
			
		||||
 | 
			
		||||
#include <Arbutils/Assert.hpp>
 | 
			
		||||
#include "CreatureIndex.hpp"
 | 
			
		||||
#include "CreatureParty.hpp"
 | 
			
		||||
 | 
			
		||||
namespace CreatureLib::Battling {
 | 
			
		||||
    class BattleParty {
 | 
			
		||||
        CreatureParty* _party;
 | 
			
		||||
@@ -11,7 +11,9 @@ namespace CreatureLib::Battling {
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        BattleParty(CreatureParty* party, std::vector<CreatureIndex> responsibleIndices)
 | 
			
		||||
            : _party(party), _responsibleIndices(responsibleIndices) {}
 | 
			
		||||
            : _party(party), _responsibleIndices(responsibleIndices) {
 | 
			
		||||
            AssertNotNull(_party)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline CreatureParty* GetParty() const { return _party; }
 | 
			
		||||
        inline const std::vector<CreatureIndex>& GetResponsibleIndices() const { return _responsibleIndices; }
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ using namespace CreatureLib::Battling;
 | 
			
		||||
bool BattleSide::AllChoicesSet() const { return _choicesSet == _creaturesPerSide; }
 | 
			
		||||
 | 
			
		||||
bool BattleSide::AllPossibleSlotsFilled() const {
 | 
			
		||||
    AssertNotNull(_battle)
 | 
			
		||||
    for (size_t i = 0; i < _creatures.size(); i++) {
 | 
			
		||||
        auto c = _creatures[i];
 | 
			
		||||
        if (c == nullptr || c->IsFainted()) {
 | 
			
		||||
@@ -28,6 +29,7 @@ void BattleSide::ResetChoices() {
 | 
			
		||||
const std::vector<BaseTurnChoice*>& BattleSide::GetChoices() const { return _choices; }
 | 
			
		||||
 | 
			
		||||
void BattleSide::SetChoice(BaseTurnChoice* choice) {
 | 
			
		||||
    AssertNotNull(choice)
 | 
			
		||||
    auto find = std::find(_creatures.begin(), _creatures.end(), choice->GetUser());
 | 
			
		||||
    if (find == _creatures.end())
 | 
			
		||||
        throw CreatureException("User not found");
 | 
			
		||||
@@ -37,6 +39,7 @@ void BattleSide::SetChoice(BaseTurnChoice* choice) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BattleSide::SetCreature(Creature* creature, uint8_t index) {
 | 
			
		||||
    AssertNotNull(creature)
 | 
			
		||||
    auto old = _creatures[index];
 | 
			
		||||
    if (old != nullptr) {
 | 
			
		||||
        old->SetOnBattleField(false);
 | 
			
		||||
@@ -59,6 +62,7 @@ void BattleSide::SetCreature(Creature* creature, uint8_t index) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool BattleSide::CreatureOnSide(const Creature* creature) const {
 | 
			
		||||
    AssertNotNull(creature)
 | 
			
		||||
    return std::find(_creatures.begin(), _creatures.end(), creature) != _creatures.end();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -70,5 +74,6 @@ void BattleSide::GetActiveScripts(std::vector<ScriptWrapper>& scripts) {
 | 
			
		||||
}
 | 
			
		||||
uint8_t BattleSide::GetRandomCreatureIndex() {
 | 
			
		||||
    // TODO: Consider adding parameter to only get index for available creatures.
 | 
			
		||||
    AssertNotNull(_battle)
 | 
			
		||||
    return _battle->GetRandom()->Get(_creaturesPerSide);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
#ifndef CREATURELIB_BATTLESIDE_HPP
 | 
			
		||||
#define CREATURELIB_BATTLESIDE_HPP
 | 
			
		||||
 | 
			
		||||
#include <Arbutils/Assert.hpp>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "../TurnChoices/BaseTurnChoice.hpp"
 | 
			
		||||
#include "Creature.hpp"
 | 
			
		||||
@@ -19,10 +20,8 @@ namespace CreatureLib::Battling {
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        explicit BattleSide(uint8_t index, Battle* battle, uint8_t creaturesPerSide)
 | 
			
		||||
            : _index(index), _creaturesPerSide(creaturesPerSide), _battle(battle) {
 | 
			
		||||
            _creatures = std::vector<Creature*>(creaturesPerSide);
 | 
			
		||||
            _choices = std::vector<BaseTurnChoice*>(creaturesPerSide);
 | 
			
		||||
            _fillableSlots = std::vector<bool>(creaturesPerSide);
 | 
			
		||||
            : _index(index), _creaturesPerSide(creaturesPerSide), _creatures(creaturesPerSide),
 | 
			
		||||
              _choices(creaturesPerSide), _fillableSlots(creaturesPerSide), _battle(battle) {
 | 
			
		||||
            for (size_t i = 0; i < creaturesPerSide; i++) {
 | 
			
		||||
                _creatures[i] = nullptr;
 | 
			
		||||
                _choices[i] = nullptr;
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,9 @@ Battling::Creature::Creature(const BattleLibrary* library, const Library::Creatu
 | 
			
		||||
    : _library(library), _species(species), _variant(variant), _level(level), _experience(experience),
 | 
			
		||||
      _uniqueIdentifier(uid), _gender(gender), _coloring(coloring), _heldItem(heldItem), _nickname(std::move(nickname)),
 | 
			
		||||
      _talentIndex(talent), _hasOverridenTalent(false), _attacks(std::move(attacks)) {
 | 
			
		||||
    AssertNotNull(library)
 | 
			
		||||
    AssertNotNull(species)
 | 
			
		||||
    AssertNotNull(variant)
 | 
			
		||||
 | 
			
		||||
    _activeTalent = _library->LoadScript(ScriptCategory::Talent, GetActiveTalent());
 | 
			
		||||
    if (_nickname.empty()) {
 | 
			
		||||
@@ -84,7 +87,7 @@ Battling::Battle* Battling::Creature::GetBattle() const { return _battle; }
 | 
			
		||||
 | 
			
		||||
Battling::BattleSide* Battling::Creature::GetBattleSide() const { return _side; }
 | 
			
		||||
 | 
			
		||||
bool Battling::Creature::IsFainted() const { return this->_currentHealth <= 0; }
 | 
			
		||||
bool Battling::Creature::IsFainted() const noexcept { return this->_currentHealth <= 0; }
 | 
			
		||||
 | 
			
		||||
void Battling::Creature::OnFaint() {
 | 
			
		||||
    // HOOK: On Faint
 | 
			
		||||
@@ -140,12 +143,12 @@ void Battling::Creature::OverrideActiveTalent(const ConstString& talent) {
 | 
			
		||||
    _activeTalent = this->_library->LoadScript(ScriptCategory::Talent, talent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const std::vector<uint8_t>& Battling::Creature::GetTypes() const {
 | 
			
		||||
const std::vector<uint8_t>& Battling::Creature::GetTypes() const noexcept {
 | 
			
		||||
    // HOOK: override types.
 | 
			
		||||
    return this->_variant->GetTypes();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Battling::Creature::HasType(uint8_t type) const {
 | 
			
		||||
bool Battling::Creature::HasType(uint8_t type) const noexcept {
 | 
			
		||||
    auto t = GetTypes();
 | 
			
		||||
    return std::find(t.begin(), t.end(), type) != t.end();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -76,24 +76,24 @@ namespace CreatureLib::Battling {
 | 
			
		||||
            _currentHealth = GetBoostedStat(Library::Statistic::Health);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline const Library::CreatureSpecies* GetSpecies() const { return _species; }
 | 
			
		||||
        inline const Library::SpeciesVariant* GetVariant() const { return _variant; }
 | 
			
		||||
        inline uint8_t GetLevel() const { return _level; }
 | 
			
		||||
        inline uint32_t GetExperience() const { return _experience; }
 | 
			
		||||
        inline Library::Gender GetGender() const { return _gender; }
 | 
			
		||||
        inline uint8_t GetColoring() const { return _coloring; }
 | 
			
		||||
        inline bool HasHeldItem(const ConstString& name) const {
 | 
			
		||||
        inline const Library::CreatureSpecies* GetSpecies() const noexcept { return _species; }
 | 
			
		||||
        inline const Library::SpeciesVariant* GetVariant() const noexcept { return _variant; }
 | 
			
		||||
        inline uint8_t GetLevel() const noexcept { return _level; }
 | 
			
		||||
        inline uint32_t GetExperience() const noexcept { return _experience; }
 | 
			
		||||
        inline Library::Gender GetGender() const noexcept { return _gender; }
 | 
			
		||||
        inline uint8_t GetColoring() const noexcept { return _coloring; }
 | 
			
		||||
        inline bool HasHeldItem(const ConstString& name) const noexcept {
 | 
			
		||||
            return _heldItem != nullptr && _heldItem->GetName() == name;
 | 
			
		||||
        }
 | 
			
		||||
        inline bool HasHeldItem(uint32_t nameHash) const {
 | 
			
		||||
        inline bool HasHeldItem(uint32_t nameHash) const noexcept {
 | 
			
		||||
            return _heldItem != nullptr && _heldItem->GetName() == nameHash;
 | 
			
		||||
        }
 | 
			
		||||
        inline const Library::Item* GetHeldItem() const { return _heldItem; }
 | 
			
		||||
        inline const Library::Item* GetHeldItem() const noexcept { return _heldItem; }
 | 
			
		||||
        void SetHeldItem(const ConstString& itemName);
 | 
			
		||||
        void SetHeldItem(uint32_t itemNameHash);
 | 
			
		||||
        inline void SetHeldItem(const Library::Item* item) { _heldItem = item; };
 | 
			
		||||
        inline void SetHeldItem(const Library::Item* item) noexcept { _heldItem = item; };
 | 
			
		||||
 | 
			
		||||
        inline uint32_t GetCurrentHealth() const { return _currentHealth; }
 | 
			
		||||
        inline uint32_t GetCurrentHealth() const noexcept { return _currentHealth; }
 | 
			
		||||
 | 
			
		||||
        void SetBattleData(Battle* battle, BattleSide* side);
 | 
			
		||||
        Battle* GetBattle() const;
 | 
			
		||||
@@ -101,14 +101,14 @@ namespace CreatureLib::Battling {
 | 
			
		||||
        void SetOnBattleField(bool value) { _onBattleField = value; }
 | 
			
		||||
        bool IsOnBattleField() const { return _onBattleField; }
 | 
			
		||||
 | 
			
		||||
        const std::string& GetNickname() const { return _nickname; }
 | 
			
		||||
        const std::string& GetNickname() const noexcept { return _nickname; }
 | 
			
		||||
        const ConstString& GetActiveTalent() const;
 | 
			
		||||
 | 
			
		||||
        [[nodiscard]] bool IsFainted() const;
 | 
			
		||||
        [[nodiscard]] const std::vector<uint8_t>& GetTypes() const;
 | 
			
		||||
        [[nodiscard]] bool HasType(uint8_t type) const;
 | 
			
		||||
        [[nodiscard]] bool IsFainted() const noexcept;
 | 
			
		||||
        [[nodiscard]] const std::vector<uint8_t>& GetTypes() const noexcept;
 | 
			
		||||
        [[nodiscard]] bool HasType(uint8_t type) const noexcept;
 | 
			
		||||
 | 
			
		||||
        uint32_t GetMaxHealth() const { return _boostedStats.GetHealth(); }
 | 
			
		||||
        uint32_t GetMaxHealth() const noexcept { return _boostedStats.GetHealth(); }
 | 
			
		||||
        void ChangeLevelBy(int8_t amount);
 | 
			
		||||
        void Damage(uint32_t damage, DamageSource source);
 | 
			
		||||
        void Heal(uint32_t amount, bool canRevive = false);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
#ifndef CREATURELIB_EXECUTINGATTACK_HPP
 | 
			
		||||
#define CREATURELIB_EXECUTINGATTACK_HPP
 | 
			
		||||
 | 
			
		||||
#include <Arbutils/Assert.hpp>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <vector>
 | 
			
		||||
@@ -61,6 +62,8 @@ namespace CreatureLib::Battling {
 | 
			
		||||
        ExecutingAttack(const std::vector<Creature*>& targets, uint8_t numberHits, Creature* user,
 | 
			
		||||
                        LearnedAttack* attack, Script* script)
 | 
			
		||||
            : _user(user), _attack(attack), _script(script) {
 | 
			
		||||
            AssertNotNull(user)
 | 
			
		||||
            AssertNotNull(attack)
 | 
			
		||||
            _targets.reserve(targets.size());
 | 
			
		||||
            for (auto target : targets) {
 | 
			
		||||
                _targets.insert({target, TargetData(numberHits)});
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,10 @@
 | 
			
		||||
#include "LearnedAttack.hpp"
 | 
			
		||||
 | 
			
		||||
#include <Arbutils/Assert.hpp>
 | 
			
		||||
CreatureLib::Battling::LearnedAttack::LearnedAttack(CreatureLib::Library::AttackData* attack, uint8_t maxUses,
 | 
			
		||||
                                                    AttackLearnMethod learnMethod)
 | 
			
		||||
    : _attack(attack), _maxUses(maxUses), _remainingUses(maxUses), _learnMethod(learnMethod) {}
 | 
			
		||||
    : _attack(attack), _maxUses(maxUses), _remainingUses(maxUses), _learnMethod(learnMethod) {
 | 
			
		||||
    AssertNotNull(_attack)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CreatureLib::Battling::LearnedAttack::LearnedAttack(const CreatureLib::Library::AttackData* attack,
 | 
			
		||||
                                                    AttackLearnMethod learnMethod)
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
#include "ScriptWrapper.hpp"
 | 
			
		||||
@@ -29,6 +29,7 @@ namespace CreatureLib::Battling {
 | 
			
		||||
    public:
 | 
			
		||||
        AttackTurnChoice(Creature* user, LearnedAttack* attack, const CreatureIndex& target)
 | 
			
		||||
            : BaseTurnChoice(user), _attack(attack), _target(target) {
 | 
			
		||||
            AssertNotNull(attack)
 | 
			
		||||
            ResolveScript();
 | 
			
		||||
        }
 | 
			
		||||
        AttackTurnChoice(Creature* user, LearnedAttack* attack, const CreatureIndex& target, Script* script)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
#ifndef CREATURELIB_BASETURNCHOICE_HPP
 | 
			
		||||
#define CREATURELIB_BASETURNCHOICE_HPP
 | 
			
		||||
 | 
			
		||||
#include <Arbutils/Assert.hpp>
 | 
			
		||||
#include "../ScriptHandling/ScriptSource.hpp"
 | 
			
		||||
#include "TurnChoiceKind.hpp"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,9 @@ namespace CreatureLib::Battling {
 | 
			
		||||
        Creature* _newCreature;
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        SwitchTurnChoice(Creature* user, Creature* newCreature) : BaseTurnChoice(user), _newCreature(newCreature) {}
 | 
			
		||||
        SwitchTurnChoice(Creature* user, Creature* newCreature) : BaseTurnChoice(user), _newCreature(newCreature) {
 | 
			
		||||
            AssertNotNull(_newCreature)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        TurnChoiceKind GetKind() const final { return TurnChoiceKind::Switch; }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
#ifndef CREATURELIB_BASELIBRARY_HPP
 | 
			
		||||
#define CREATURELIB_BASELIBRARY_HPP
 | 
			
		||||
 | 
			
		||||
#include <Arbutils/Assert.hpp>
 | 
			
		||||
#include <Arbutils/ConstString.hpp>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <string>
 | 
			
		||||
@@ -21,21 +22,19 @@ namespace CreatureLib::Library {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline void Insert(const Arbutils::CaseInsensitiveConstString& key, const T* value) {
 | 
			
		||||
            AssertNotNull(value)
 | 
			
		||||
            _values.insert({key.GetHash(), value});
 | 
			
		||||
        }
 | 
			
		||||
        inline void Insert(uint32_t hashedKey, const T* value) { _values.insert({hashedKey, value}); }
 | 
			
		||||
        inline void Insert(uint32_t hashedKey, const T* value) {
 | 
			
		||||
            AssertNotNull(value)
 | 
			
		||||
            _values.insert({hashedKey, value});
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inline void Delete(const Arbutils::CaseInsensitiveConstString& key) { _values.erase(key.GetHash()); }
 | 
			
		||||
        inline void Delete(uint32_t hashedKey) { _values.erase({hashedKey}); }
 | 
			
		||||
 | 
			
		||||
        bool TryGet(const Arbutils::CaseInsensitiveConstString& name, const T*& out) const {
 | 
			
		||||
            auto find = this->_values.find(name.GetHash());
 | 
			
		||||
            if (find == this->_values.end()) {
 | 
			
		||||
                out = nullptr;
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            out = find->second;
 | 
			
		||||
            return true;
 | 
			
		||||
            return TryGet(name.GetHash(), out);
 | 
			
		||||
        }
 | 
			
		||||
        bool TryGet(uint32_t hashedKey, const T*& out) const {
 | 
			
		||||
            auto find = this->_values.find(hashedKey);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,14 @@
 | 
			
		||||
#include "CreatureSpecies.hpp"
 | 
			
		||||
#include <Arbutils/Assert.hpp>
 | 
			
		||||
 | 
			
		||||
using namespace CreatureLib::Library;
 | 
			
		||||
 | 
			
		||||
CreatureSpecies::CreatureSpecies(uint16_t id, const ConstString& name, const SpeciesVariant* defaultVariant,
 | 
			
		||||
                                 float genderRatio, const ConstString& growthRate, uint8_t captureRate)
 | 
			
		||||
    : _name(name), _id(id), _genderRate(genderRatio), _growthRate(growthRate), _captureRate(captureRate),
 | 
			
		||||
      _variants({{"default"_cnc, defaultVariant}}) {}
 | 
			
		||||
      _variants({{"default"_cnc, defaultVariant}}) {
 | 
			
		||||
    AssertNotNull(defaultVariant)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CreatureSpecies::HasVariant(const ConstString& name) const { return _variants.find(name) != _variants.end(); }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
#ifndef CREATURELIB_LEARNABLEATTACKS_HPP
 | 
			
		||||
#define CREATURELIB_LEARNABLEATTACKS_HPP
 | 
			
		||||
 | 
			
		||||
#include <Arbutils/Assert.hpp>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "../Attacks/AttackData.hpp"
 | 
			
		||||
@@ -11,7 +12,12 @@ namespace CreatureLib::Library {
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        LearnableAttacks(size_t levelAttackCapacity)
 | 
			
		||||
            : _learnedByLevel(std::unordered_map<uint8_t, std::vector<const AttackData*>>(levelAttackCapacity)) {}
 | 
			
		||||
            : _learnedByLevel(std::unordered_map<uint8_t, std::vector<const AttackData*>>(levelAttackCapacity)) {
 | 
			
		||||
            for (auto kv : _learnedByLevel) {
 | 
			
		||||
                for (auto attack : kv.second)
 | 
			
		||||
                    AssertNotNull(attack)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void AddLevelMove(uint8_t level, const AttackData* attack);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -37,7 +37,7 @@ const CreatureLib::Library::LearnableAttacks* CreatureLib::Library::SpeciesVaria
 | 
			
		||||
 | 
			
		||||
CreatureLib::Library::SpeciesVariant::SpeciesVariant(ConstString name, float height, float weight,
 | 
			
		||||
                                                     uint32_t baseExperience, std::vector<uint8_t> types,
 | 
			
		||||
                                                     CreatureLib::Library::StatisticSet<uint16_t> baseStats,
 | 
			
		||||
                                                     const CreatureLib::Library::StatisticSet<uint16_t>& baseStats,
 | 
			
		||||
                                                     std::vector<ConstString> talents,
 | 
			
		||||
                                                     std::vector<ConstString> secretTalents,
 | 
			
		||||
                                                     const LearnableAttacks* attacks)
 | 
			
		||||
 
 | 
			
		||||
@@ -23,14 +23,14 @@ namespace CreatureLib::Library {
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        std::vector<uint8_t> _types;
 | 
			
		||||
        const Library::StatisticSet<uint16_t> _baseStatistics;
 | 
			
		||||
        const Library::StatisticSet<uint16_t>& _baseStatistics;
 | 
			
		||||
        std::vector<ConstString> _talents;
 | 
			
		||||
        std::vector<ConstString> _secretTalents;
 | 
			
		||||
        const LearnableAttacks* _attacks;
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        SpeciesVariant(ConstString name, float height, float weight, uint32_t baseExperience,
 | 
			
		||||
                       std::vector<uint8_t> types, Library::StatisticSet<uint16_t> baseStats,
 | 
			
		||||
                       std::vector<uint8_t> types, const Library::StatisticSet<uint16_t>& baseStats,
 | 
			
		||||
                       std::vector<ConstString> talents, std::vector<ConstString> secretTalents,
 | 
			
		||||
                       const LearnableAttacks* attacks);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,14 @@ CreatureLib::Library::DataLibrary::DataLibrary(LibrarySettings* settings, Creatu
 | 
			
		||||
                                               CreatureLib::Library::GrowthRateLibrary* growthRates,
 | 
			
		||||
                                               TypeLibrary* typeLibrary)
 | 
			
		||||
    : _settings(settings), _species(species), _attacks(attacks), _items(items), _growthRates(growthRates),
 | 
			
		||||
      _typeLibrary(typeLibrary) {}
 | 
			
		||||
      _typeLibrary(typeLibrary) {
 | 
			
		||||
    AssertNotNull(_settings)
 | 
			
		||||
    AssertNotNull(_species)
 | 
			
		||||
    AssertNotNull(_attacks)
 | 
			
		||||
    AssertNotNull(_items)
 | 
			
		||||
    AssertNotNull(_growthRates)
 | 
			
		||||
    AssertNotNull(_typeLibrary)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const CreatureLib::Library::LibrarySettings* CreatureLib::Library::DataLibrary::GetSettings() const {
 | 
			
		||||
    return _settings;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
#ifndef CREATURELIB_EXTERNGROWTHRATE_HPP
 | 
			
		||||
#define CREATURELIB_EXTERNGROWTHRATE_HPP
 | 
			
		||||
 | 
			
		||||
#include <Arbutils/Assert.hpp>
 | 
			
		||||
#include "GrowthRate.hpp"
 | 
			
		||||
namespace CreatureLib::Library {
 | 
			
		||||
    class ExternGrowthRate : public GrowthRate {
 | 
			
		||||
@@ -9,7 +10,10 @@ namespace CreatureLib::Library {
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        ExternGrowthRate(uint8_t (*calcLevel)(uint32_t), uint32_t (*calcExperience)(uint8_t level))
 | 
			
		||||
            : _calcLevel(calcLevel), _calcExperience(calcExperience) {}
 | 
			
		||||
            : _calcLevel(calcLevel), _calcExperience(calcExperience) {
 | 
			
		||||
            AssertNotNull(calcLevel)
 | 
			
		||||
            AssertNotNull(calcExperience)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        uint8_t CalculateLevel(uint32_t experience) const override { return _calcLevel(experience); }
 | 
			
		||||
        uint32_t CalculateExperience(uint8_t level) const override { return _calcExperience(level); }
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,10 @@ namespace CreatureLib::Library {
 | 
			
		||||
            return _experience[_experience.size() - 1];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        uint32_t CalculateExperience(uint8_t level) const override { return _experience[level - 1]; }
 | 
			
		||||
        uint32_t CalculateExperience(uint8_t level) const override {
 | 
			
		||||
            Assert(level <= _experience.size())
 | 
			
		||||
            return _experience[level - 1];
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,9 @@ namespace CreatureLib::Library {
 | 
			
		||||
        T _magicalDefense;
 | 
			
		||||
        T _speed;
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        StatisticSet<T>(const StatisticSet<T>& v) = delete;
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        StatisticSet(T health, T physicalAttack, T physicalDefense, T magicalAttack, T magicalDefense, T speed)
 | 
			
		||||
            : _health(health), _physicalAttack(physicalAttack), _physicalDefense(physicalDefense),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
#include "TypeLibrary.hpp"
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <Arbutils/Assert.hpp>
 | 
			
		||||
 | 
			
		||||
using namespace CreatureLib::Library;
 | 
			
		||||
 | 
			
		||||
@@ -12,6 +12,8 @@ float TypeLibrary::GetEffectiveness(uint8_t attacking, const std::vector<uint8_t
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float TypeLibrary::GetSingleEffectiveness(uint8_t attacking, uint8_t defensive) const {
 | 
			
		||||
    Assert(attacking < _effectiveness.size())
 | 
			
		||||
    Assert(defensive < _effectiveness.size())
 | 
			
		||||
    return _effectiveness[attacking][defensive];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -36,5 +38,7 @@ uint8_t TypeLibrary::RegisterType(uint32_t key) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TypeLibrary::SetEffectiveness(uint8_t attacking, uint8_t defensive, float effectiveness) {
 | 
			
		||||
    Assert(attacking < _effectiveness.size())
 | 
			
		||||
    Assert(defensive < _effectiveness.size())
 | 
			
		||||
    _effectiveness[attacking][defensive] = effectiveness;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,8 +10,10 @@ using namespace CreatureLib;
 | 
			
		||||
using namespace CreatureLib::Battling;
 | 
			
		||||
 | 
			
		||||
TEST_CASE("Turn ordering: Attack before pass", "[Battling]") {
 | 
			
		||||
    auto lib = TestLibrary::Get();
 | 
			
		||||
    auto learnedAttack = LearnedAttack(lib->GetAttackLibrary()->Get("standard"_cnc), AttackLearnMethod::Unknown);
 | 
			
		||||
    auto choice1 = new PassTurnChoice(nullptr);
 | 
			
		||||
    auto choice2 = new AttackTurnChoice(nullptr, nullptr, CreatureIndex(0, 0));
 | 
			
		||||
    auto choice2 = new AttackTurnChoice(nullptr, &learnedAttack, CreatureIndex(0, 0));
 | 
			
		||||
    auto vec = std::vector<BaseTurnChoice*>{choice1, choice2};
 | 
			
		||||
    auto rand = Arbutils::Random();
 | 
			
		||||
    TurnOrdering::OrderChoices(vec, rand);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user