Files
azerothcore-wotlk/src/test/mocks/UnitStub.h
blinkysc 4599f26ae9 refactor(Core/Spells): QAston proc system (#24233)
Co-authored-by: blinkysc <blinkysc@users.noreply.github.com>
Co-authored-by: QAston <qaston@gmail.com>
Co-authored-by: joschiwald <joschiwald@online.de>
Co-authored-by: ariel- <ariel-@users.noreply.github.com>
Co-authored-by: Kitzunu <24550914+Kitzunu@users.noreply.github.com>
Co-authored-by: blinkysc <your-github-email@example.com>
Co-authored-by: Tereneckla <Tereneckla@users.noreply.github.com>
Co-authored-by: Andrew <47818697+Nyeriah@users.noreply.github.com>
2026-02-18 08:31:53 -03:00

245 lines
7.2 KiB
C++

/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* 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 2 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 <http://www.gnu.org/licenses/>.
*/
#ifndef AZEROTHCORE_UNIT_STUB_H
#define AZEROTHCORE_UNIT_STUB_H
#include "gmock/gmock.h"
#include <cstdint>
#include <functional>
#include <map>
#include <vector>
class SpellInfo;
class Aura;
class AuraEffect;
class Item;
/**
* @brief Lightweight stub for Unit proc-related functionality
*
* This stub provides controlled behavior for testing proc scripts
* without requiring the full Unit hierarchy.
*/
class UnitStub
{
public:
UnitStub() = default;
virtual ~UnitStub() = default;
// Identity
virtual bool IsPlayer() const { return _isPlayer; }
virtual bool IsAlive() const { return _isAlive; }
virtual bool IsFriendlyTo(UnitStub const* unit) const { return _isFriendly; }
void SetIsPlayer(bool isPlayer) { _isPlayer = isPlayer; }
void SetIsAlive(bool isAlive) { _isAlive = isAlive; }
void SetIsFriendly(bool isFriendly) { _isFriendly = isFriendly; }
// Aura management
virtual bool HasAura(uint32_t spellId) const
{
return _auras.find(spellId) != _auras.end();
}
virtual void AddAuraStub(uint32_t spellId)
{
_auras[spellId] = true;
}
virtual void RemoveAuraStub(uint32_t spellId)
{
_auras.erase(spellId);
}
// Spell casting tracking
struct CastRecord
{
uint32_t spellId;
bool triggered;
int32_t bp0;
int32_t bp1;
int32_t bp2;
};
virtual void RecordCast(uint32_t spellId, bool triggered = true,
int32_t bp0 = 0, int32_t bp1 = 0, int32_t bp2 = 0)
{
_castHistory.push_back({spellId, triggered, bp0, bp1, bp2});
}
[[nodiscard]] std::vector<CastRecord> const& GetCastHistory() const { return _castHistory; }
[[nodiscard]] bool WasCast(uint32_t spellId) const
{
for (auto const& record : _castHistory)
{
if (record.spellId == spellId)
return true;
}
return false;
}
[[nodiscard]] size_t CountCasts(uint32_t spellId) const
{
size_t count = 0;
for (auto const& record : _castHistory)
{
if (record.spellId == spellId)
++count;
}
return count;
}
void ClearCastHistory() { _castHistory.clear(); }
// Health/Power
virtual uint32_t GetMaxHealth() const { return _maxHealth; }
virtual uint32_t GetHealth() const { return _health; }
virtual uint32_t CountPctFromMaxHealth(int32_t pct) const
{
return (_maxHealth * static_cast<uint32_t>(pct)) / 100;
}
void SetMaxHealth(uint32_t maxHealth) { _maxHealth = maxHealth; }
void SetHealth(uint32_t health) { _health = health; }
// Weapon speed for PPM calculations
virtual uint32_t GetAttackTime(uint8_t attType) const
{
return _attackTimes.count(attType) ? _attackTimes.at(attType) : 2000;
}
void SetAttackTime(uint8_t attType, uint32_t time)
{
_attackTimes[attType] = time;
}
// PPM modifier tracking for proc tests
// Simulates Player::ApplySpellMod(spellId, SPELLMOD_PROC_PER_MINUTE, ppm)
void SetPPMModifier(uint32_t spellId, float modifier)
{
_ppmModifiers[spellId] = modifier;
}
void ClearPPMModifiers()
{
_ppmModifiers.clear();
}
/**
* @brief Calculate PPM proc chance with modifiers
* Mimics Unit::GetPPMProcChance() formula: (WeaponSpeed * PPM) / 600.0f
*/
virtual float GetPPMProcChance(uint32_t weaponSpeed, float ppm, uint32_t spellId = 0) const
{
if (ppm <= 0.0f)
return 0.0f;
// Apply PPM modifier if set for this spell
float modifiedPPM = ppm;
if (spellId > 0 && _ppmModifiers.count(spellId))
modifiedPPM += _ppmModifiers.at(spellId);
return (static_cast<float>(weaponSpeed) * modifiedPPM) / 600.0f;
}
// Chance modifier tracking for proc tests
// Simulates Player::ApplySpellMod(spellId, SPELLMOD_CHANCE_OF_SUCCESS, chance)
void SetChanceModifier(uint32_t spellId, float modifier)
{
_chanceModifiers[spellId] = modifier;
}
void ClearChanceModifiers()
{
_chanceModifiers.clear();
}
/**
* @brief Apply chance modifier for a spell
*/
float ApplyChanceModifier(uint32_t spellId, float baseChance) const
{
if (spellId > 0 && _chanceModifiers.count(spellId))
return baseChance + _chanceModifiers.at(spellId);
return baseChance;
}
// Cooldowns
virtual bool HasSpellCooldown(uint32_t spellId) const
{
return _cooldowns.find(spellId) != _cooldowns.end();
}
virtual void AddSpellCooldown(uint32_t spellId)
{
_cooldowns[spellId] = true;
}
virtual void RemoveSpellCooldown(uint32_t spellId)
{
_cooldowns.erase(spellId);
}
// Class/Level
virtual uint8_t GetClass() const { return _class; }
virtual uint8_t GetLevel() const { return _level; }
void SetClass(uint8_t unitClass) { _class = unitClass; }
void SetLevel(uint8_t level) { _level = level; }
private:
bool _isPlayer = false;
bool _isAlive = true;
bool _isFriendly = false;
std::map<uint32_t, bool> _auras;
std::vector<CastRecord> _castHistory;
std::map<uint32_t, bool> _cooldowns;
std::map<uint8_t, uint32_t> _attackTimes;
std::map<uint32_t, float> _ppmModifiers; // PPM modifiers by spell ID
std::map<uint32_t, float> _chanceModifiers; // Chance modifiers by spell ID
uint32_t _maxHealth = 10000;
uint32_t _health = 10000;
uint8_t _class = 1; // Warrior by default
uint8_t _level = 80;
};
/**
* @brief GMock-enabled Unit stub for verification
*/
class MockUnitStub : public UnitStub
{
public:
MOCK_METHOD(bool, IsPlayer, (), (const, override));
MOCK_METHOD(bool, IsAlive, (), (const, override));
MOCK_METHOD(bool, IsFriendlyTo, (UnitStub const* unit), (const, override));
MOCK_METHOD(bool, HasAura, (uint32_t spellId), (const, override));
MOCK_METHOD(uint32_t, GetMaxHealth, (), (const, override));
MOCK_METHOD(uint32_t, GetHealth, (), (const, override));
MOCK_METHOD(uint32_t, CountPctFromMaxHealth, (int32_t pct), (const, override));
MOCK_METHOD(uint32_t, GetAttackTime, (uint8_t attType), (const, override));
MOCK_METHOD(bool, HasSpellCooldown, (uint32_t spellId), (const, override));
MOCK_METHOD(uint8_t, GetClass, (), (const, override));
MOCK_METHOD(uint8_t, GetLevel, (), (const, override));
MOCK_METHOD(float, GetPPMProcChance, (uint32_t weaponSpeed, float ppm, uint32_t spellId), (const, override));
};
#endif //AZEROTHCORE_UNIT_STUB_H