# pragma region License
/*
License ( OLC - 3 )
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
Copyright 2024 Joshua Sigona < sigonasr2 @ gmail . com >
Redistribution and use in source and binary forms , with or without modification ,
are permitted provided that the following conditions are met :
1. Redistributions or derivations of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2. Redistributions or derivative works in binary form must reproduce the above
copyright notice . This list of conditions and the following disclaimer must be
reproduced in the documentation and / or other materials provided with the distribution .
3. Neither the name of the copyright holder nor the names of its contributors may
be used to endorse or promote products derived from this software without specific
prior written permission .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS " AND ANY
EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT ,
INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED
TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR
BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN
CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE .
Portions of this software are copyright <EFBFBD> 2024 The FreeType
Project ( www . freetype . org ) . Please see LICENSE_FT . txt for more information .
All rights reserved .
*/
# pragma endregion
# include "CppUnitTest.h"
# include "AdventuresInLestoria.h"
# include "Tutorial.h"
# include <random>
# include <format>
# include "ItemDrop.h"
# include "DamageNumber.h"
# include <ranges>
using namespace Microsoft : : VisualStudio : : CppUnitTestFramework ;
using namespace olc : : utils ;
INCLUDE_GFX
INCLUDE_ITEM_DATA
INCLUDE_DAMAGENUMBER_LIST
INCLUDE_INITIALIZEGAMECONFIGURATIONS
extern std : : mt19937 rng ;
namespace Test
{
template < class T >
inline static void InRange ( T initialVal , std : : pair < T , T > range , std : : wstring_view assertMessage ) {
Assert : : IsTrue ( initialVal > = range . first & & initialVal < = range . second , std : : format ( L " Expected: {}~{} Actual: {} - {} " , range . first , range . second , initialVal , assertMessage ) . c_str ( ) ) ;
}
}
namespace EnchantTests
{
TEST_CLASS ( EnchantTest )
{
public :
std : : unique_ptr < AiL > testGame ;
InputGroup testKeyboardInput ;
Player * player ;
HWButton * testKey ;
TEST_METHOD_INITIALIZE ( PlayerInitialize ) {
InitializeGameConfigurations ( ) ;
rng = std : : mt19937 { 57189U } ; //Establish a fixed random seed on setup so the exact same results are generated every test run.
testGame . reset ( new AiL ( true ) ) ;
ItemAttribute : : Initialize ( ) ;
ItemInfo : : InitializeItems ( ) ;
testGame - > InitializeGraphics ( ) ;
testGame - > InitializeClasses ( ) ;
sig : : Animation : : InitializeAnimations ( ) ;
testGame - > InitializeDefaultKeybinds ( ) ;
testGame - > InitializePlayer ( ) ;
sig : : Animation : : SetupPlayerAnimations ( ) ;
Menu : : InitializeMenus ( ) ;
Tutorial : : Initialize ( ) ;
Stats : : InitializeDamageReductionTable ( ) ;
GameState : : Initialize ( ) ;
GameState : : STATE = GameState : : states . at ( States : : State : : GAME_RUN ) ;
# pragma region Setup a fake test map and test monster
game - > MAP_DATA [ " CAMPAIGN_1_1 " ] ;
ItemDrop : : ClearDrops ( ) ;
MonsterData testMonsterData { " TestName " , " Test Monster " , 1000 , 10 , 5 , { MonsterDropData { " Health Potion " , 100.f , 1 , 1 } } , 200.f } ;
MONSTER_DATA [ " TestName " ] = testMonsterData ;
# pragma endregion
player = testGame - > GetPlayer ( ) ;
//Setup key "0" as a test input
testKeyboardInput . AddKeybind ( Input { InputType : : KEY , 0 } ) ;
testKey = testGame - > GetKeyboardState ( 0 ) ;
testGame - > olc_UpdateKeyFocus ( true ) ; //Force the game to be "focused" for tests. Required if we want keyboard inputs to work.
Menu : : themes . SetInitialized ( ) ;
GFX . SetInitialized ( ) ;
DAMAGENUMBER_LIST . clear ( ) ;
}
TEST_METHOD ( HealthBoostCheck ) {
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
std : : weak_ptr < Item > nullRing2 { Inventory : : AddItem ( " Null Ring " s ) } ;
Assert : : AreEqual ( 100 , player - > GetMaxHealth ( ) , L " Player starts with 100 health. " ) ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
std : : unordered_map < int , uint32_t > statDistribution ;
for ( int i : std : : ranges : : iota_view ( 0 , 1000 ) ) {
nullRing . lock ( ) - > EnchantItem ( " Health Boost " ) ;
statDistribution [ player - > GetMaxHealth ( ) ] + + ;
}
Assert : : AreEqual ( size_t ( 3 ) , statDistribution . size ( ) , L " There should be three entries generated. If not, then the RNG picking is likely not working! " ) ;
Inventory : : EquipItem ( nullRing2 , EquipSlot : : RING2 ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 1000 ) ) {
nullRing2 . lock ( ) - > EnchantItem ( " Health Boost " ) ;
Test : : InRange ( player - > GetMaxHealth ( ) , { 106 , 110 } , L " Max Health not in expected range with two rings equipped. " ) ;
}
}
TEST_METHOD ( AttackBoostCheck ) {
player - > SetBaseStat ( " Attack " , 100.f ) ;
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
std : : weak_ptr < Item > nullRing2 { Inventory : : AddItem ( " Null Ring " s ) } ;
Assert : : AreEqual ( 100 , player - > GetAttack ( ) , L " Player starts with 100 attack. " ) ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 1000 ) ) {
nullRing . lock ( ) - > EnchantItem ( " Attack Boost " ) ;
Test : : InRange ( player - > GetAttack ( ) , { 103 , 105 } , L " Attack not in expected range. " ) ;
}
Inventory : : EquipItem ( nullRing2 , EquipSlot : : RING2 ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 1000 ) ) {
nullRing2 . lock ( ) - > EnchantItem ( " Attack Boost " ) ;
Test : : InRange ( player - > GetAttack ( ) , { 106 , 110 } , L " Attack not in expected range with two rings equipped. " ) ;
}
}
TEST_METHOD ( MovementBoostCheck ) {
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
std : : weak_ptr < Item > nullRing2 { Inventory : : AddItem ( " Null Ring " s ) } ;
Assert : : AreEqual ( 100.0 _Pct , player - > GetMoveSpdMult ( ) , L " Player starts with 100% Movespd. " ) ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 1000 ) ) {
nullRing . lock ( ) - > EnchantItem ( " Movement Boost " ) ;
Test : : InRange ( player - > GetMoveSpdMult ( ) , { 103.0 _Pct , 105.0 _Pct } , L " Move Speed not in expected range. " ) ;
}
Inventory : : EquipItem ( nullRing2 , EquipSlot : : RING2 ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 1000 ) ) {
nullRing2 . lock ( ) - > EnchantItem ( " Movement Boost " ) ;
Test : : InRange ( player - > GetMoveSpdMult ( ) , { 106.0 _Pct , 110.0 _Pct } , L " Move Speed not in expected range with two rings equipped. " ) ;
}
}
TEST_METHOD ( AbilityHasteCheck ) {
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
std : : weak_ptr < Item > nullRing2 { Inventory : : AddItem ( " Null Ring " s ) } ;
Assert : : AreEqual ( 0.0 _Pct , player - > GetCooldownReductionPct ( ) , L " Player starts with 0% CDR. " ) ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 1000 ) ) {
nullRing . lock ( ) - > EnchantItem ( " Ability Haste " ) ;
Test : : InRange ( player - > GetCooldownReductionPct ( ) , { 3.0 _Pct , 5.0 _Pct } , L " CDR not in expected range. " ) ;
}
Inventory : : EquipItem ( nullRing2 , EquipSlot : : RING2 ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 1000 ) ) {
nullRing2 . lock ( ) - > EnchantItem ( " Ability Haste " ) ;
Test : : InRange ( player - > GetCooldownReductionPct ( ) , { 6.0 _Pct , 10.0 _Pct } , L " CDR not in expected range with two rings. " ) ;
}
}
TEST_METHOD ( CritRateCheck ) {
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
std : : weak_ptr < Item > nullRing2 { Inventory : : AddItem ( " Null Ring " s ) } ;
Assert : : AreEqual ( 0.0 _Pct , player - > GetCritRatePct ( ) , L " Player starts with 0% Crit Rate. " ) ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 1000 ) ) {
nullRing . lock ( ) - > EnchantItem ( " Crit Rate " ) ;
Test : : InRange ( player - > GetCritRatePct ( ) , { 3.0 _Pct , 5.0 _Pct } , L " Crit Rate not in expected range. " ) ;
}
Inventory : : EquipItem ( nullRing2 , EquipSlot : : RING2 ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 1000 ) ) {
nullRing2 . lock ( ) - > EnchantItem ( " Crit Rate " ) ;
Test : : InRange ( player - > GetCritRatePct ( ) , { 6.0 _Pct , 10.0 _Pct } , L " Crit Rate not in expected range with two rings. " ) ;
}
}
TEST_METHOD ( CritDamageCheck ) {
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
std : : weak_ptr < Item > nullRing2 { Inventory : : AddItem ( " Null Ring " s ) } ;
Assert : : AreEqual ( 50.0 _Pct , player - > GetCritDmgPct ( ) , L " Player starts with 50% Crit Damage. " ) ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 1000 ) ) {
nullRing . lock ( ) - > EnchantItem ( " Crit Damage " ) ;
Test : : InRange ( player - > GetCritDmgPct ( ) , { 57.0 _Pct , 60.0 _Pct } , L " Crit Damage not in expected range. " ) ;
}
Inventory : : EquipItem ( nullRing2 , EquipSlot : : RING2 ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 1000 ) ) {
nullRing2 . lock ( ) - > EnchantItem ( " Crit Damage " ) ;
Test : : InRange ( player - > GetCritDmgPct ( ) , { 64.0 _Pct , 70.0 _Pct } , L " Crit Damage not in expected range with two rings. " ) ;
}
}
TEST_METHOD ( StoneskinCheck ) {
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
std : : weak_ptr < Item > nullRing2 { Inventory : : AddItem ( " Null Ring " s ) } ;
Assert : : AreEqual ( 0.0 _Pct , player - > GetDamageReductionPct ( ) , L " Player starts with 0% Damage Reduction. " ) ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 1000 ) ) {
nullRing . lock ( ) - > EnchantItem ( " Stoneskin " ) ;
Test : : InRange ( player - > GetDamageReductionPct ( ) , { 3.0 _Pct , 5.0 _Pct } , L " Damage Reduction not in expected range. " ) ;
}
Inventory : : EquipItem ( nullRing2 , EquipSlot : : RING2 ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 1000 ) ) {
nullRing2 . lock ( ) - > EnchantItem ( " Stoneskin " ) ;
Test : : InRange ( player - > GetDamageReductionPct ( ) , { 6.0 _Pct , 10.0 _Pct } , L " Damage Reduction not in expected range with two rings. " ) ;
}
}
TEST_METHOD ( ManaPoolCheck ) {
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
std : : weak_ptr < Item > nullRing2 { Inventory : : AddItem ( " Null Ring " s ) } ;
Assert : : AreEqual ( 100 , player - > GetMaxMana ( ) , L " Player starts with 100 mana. " ) ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 1000 ) ) {
nullRing . lock ( ) - > EnchantItem ( " Mana Pool " ) ;
Test : : InRange ( player - > GetMaxMana ( ) , { 107 , 112 } , L " Mana Pool not in expected range. " ) ;
}
Inventory : : EquipItem ( nullRing2 , EquipSlot : : RING2 ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 1000 ) ) {
nullRing2 . lock ( ) - > EnchantItem ( " Mana Pool " ) ;
Test : : InRange ( player - > GetMaxMana ( ) , { 114 , 124 } , L " Mana Pool not in expected range with two rings. " ) ;
}
}
TEST_METHOD ( MagicalProtectionCheck ) {
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
std : : weak_ptr < Item > nullRing2 { Inventory : : AddItem ( " Null Ring " s ) } ;
Assert : : AreEqual ( 100 , player - > GetMaxHealth ( ) , L " Player starts with 100 health. " ) ;
Assert : : AreEqual ( 0.0 _Pct , player - > GetDamageReductionPct ( ) , L " Player starts with 0% damage reduction. " ) ;
Assert : : AreEqual ( 100.0 _Pct , player - > GetMoveSpdMult ( ) , L " Player starts with 100% move speed. " ) ;
Assert : : AreEqual ( 0.0 _Pct , player - > GetHP6RecoveryPct ( ) , L " Player starts with 0% HP/6 recovery. " ) ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 1000 ) ) {
nullRing . lock ( ) - > EnchantItem ( " Magical Protection " ) ;
Test : : InRange ( player - > GetMaxHealth ( ) , { 102 , 103 } , L " Max Health not in expected range. " ) ;
Test : : InRange ( player - > GetDamageReductionPct ( ) , { 2.0 _Pct , 3.0 _Pct } , L " Damage Reduction not in expected range. " ) ;
Test : : InRange ( player - > GetMoveSpdMult ( ) , { 102.0 _Pct , 103.0 _Pct } , L " Move Speed % not in expected range. " ) ;
Test : : InRange ( player - > GetHP6RecoveryPct ( ) , { 1.0 _Pct , 1.0 _Pct } , L " HP/6 Recovery not in expected range. " ) ;
}
Inventory : : EquipItem ( nullRing2 , EquipSlot : : RING2 ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 1000 ) ) {
nullRing2 . lock ( ) - > EnchantItem ( " Magical Protection " ) ;
Test : : InRange ( player - > GetMaxHealth ( ) , { 102 , 103 } , L " Max Health not in expected range with two rings. " ) ;
Test : : InRange ( player - > GetDamageReductionPct ( ) , { 2.0 _Pct , 3.0 _Pct } , L " Damage Reduction not in expected range with two rings. " ) ;
Test : : InRange ( player - > GetMoveSpdMult ( ) , { 102.0 _Pct , 103.0 _Pct } , L " Move Speed % not in expected range with two rings. " ) ;
Test : : InRange ( player - > GetHP6RecoveryPct ( ) , { 1.0 _Pct , 1.0 _Pct } , L " HP/6 Recovery not in expected range with two rings. " ) ;
}
}
TEST_METHOD ( AuraOfTheBeastCheck ) {
player - > SetBaseStat ( " Attack " , 100.f ) ;
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
std : : weak_ptr < Item > nullRing2 { Inventory : : AddItem ( " Null Ring " s ) } ;
Assert : : AreEqual ( 100 , player - > GetAttack ( ) , L " Player starts with 100 attack. " ) ;
Assert : : AreEqual ( 0.0 _Pct , player - > GetCritRatePct ( ) , L " Player starts with 0% crit rate. " ) ;
Assert : : AreEqual ( 0.0 _Pct , player - > GetCooldownReductionPct ( ) , L " Player starts with 0% cooldown reduction. " ) ;
Assert : : AreEqual ( 50.0 _Pct , player - > GetCritDmgPct ( ) , L " Player starts with 50% crit rate. " ) ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 1000 ) ) {
nullRing . lock ( ) - > EnchantItem ( " Aura of the Beast " ) ;
Test : : InRange ( player - > GetAttack ( ) , { 102 , 103 } , L " Attack not in expected range. " ) ;
Test : : InRange ( player - > GetCritRatePct ( ) , { 2.0 _Pct , 3.0 _Pct } , L " Crit Rate not in expected range. " ) ;
Test : : InRange ( player - > GetCooldownReductionPct ( ) , { 2.0 _Pct , 3.0 _Pct } , L " Cooldown Reduction % not in expected range. " ) ;
Test : : InRange ( player - > GetCritDmgPct ( ) , { 53.0 _Pct , 57.0 _Pct } , L " Crit Damage not in expected range. " ) ;
}
Inventory : : EquipItem ( nullRing2 , EquipSlot : : RING2 ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 1000 ) ) {
nullRing2 . lock ( ) - > EnchantItem ( " Aura of the Beast " ) ;
Test : : InRange ( player - > GetAttack ( ) , { 102 , 103 } , L " Attack not in expected range with two rings. " ) ;
Test : : InRange ( player - > GetCritRatePct ( ) , { 2.0 _Pct , 3.0 _Pct } , L " Crit Rate not in expected range with two rings. " ) ;
Test : : InRange ( player - > GetCooldownReductionPct ( ) , { 2.0 _Pct , 3.0 _Pct } , L " Cooldown Reduction % not in expected range with two rings. " ) ;
Test : : InRange ( player - > GetCritDmgPct ( ) , { 53.0 _Pct , 57.0 _Pct } , L " Crit Damage not in expected range with two rings. " ) ;
}
}
TEST_METHOD ( LethalTempoCheck ) {
MonsterData testMonsterData { " TestName " , " Test Monster " , 30 , 10 , 5 , { MonsterDropData { " Health Potion " , 100.f , 1 , 1 } } , 200.f } ;
MONSTER_DATA [ " TestName " ] = testMonsterData ;
Monster testMonster { { } , MONSTER_DATA [ " TestName " ] } ;
testMonster . Hurt ( 0 , testMonster . OnUpperLevel ( ) , testMonster . GetZ ( ) ) ;
Assert : : AreEqual ( size_t ( 0 ) , player - > GetBuffs ( BuffType : : LETHAL_TEMPO ) . size ( ) , L " Lethal Tempo does not stack up without the enchant. " ) ;
testMonster . Hurt ( 0 , testMonster . OnUpperLevel ( ) , testMonster . GetZ ( ) , HurtFlag : : PLAYER_ABILITY ) ;
Assert : : AreEqual ( size_t ( 0 ) , player - > GetBuffs ( BuffType : : LETHAL_TEMPO ) . size ( ) , L " Lethal Tempo does not stack up without the enchant. " ) ;
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
nullRing . lock ( ) - > EnchantItem ( " Lethal Tempo " ) ;
testMonster . Hurt ( 0 , testMonster . OnUpperLevel ( ) , testMonster . GetZ ( ) , HurtFlag : : PLAYER_ABILITY ) ;
Assert : : AreEqual ( size_t ( 1 ) , player - > GetBuffs ( BuffType : : LETHAL_TEMPO ) . size ( ) , L " Lethal Tempo buff is active after attacking with the enchant.. " ) ;
Assert : : AreEqual ( 0.0175f , player - > GetAttackRecoveryRateReduction ( ) , L " Lethal Tempo buff reduced attack Recovery Rate by 0.0175 (5% of 0.35). " ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 10 ) ) {
testMonster . Hurt ( 0 , testMonster . OnUpperLevel ( ) , testMonster . GetZ ( ) , HurtFlag : : PLAYER_ABILITY ) ;
}
Assert : : AreEqual ( 0.0875f , player - > GetAttackRecoveryRateReduction ( ) , L " Lethal Tempo buff should cap at 5 stacks. " ) ;
Assert : : AreEqual ( size_t ( 1 ) , player - > GetBuffs ( BuffType : : LETHAL_TEMPO ) . size ( ) , L " Lethal Tempo buff is active. " ) ;
}
TEST_METHOD ( SecondWindCheck ) {
Assert : : AreEqual ( 0.0 _Pct , player - > GetHPRecoveryPct ( ) , L " HP Recovery Pct is 0% at the start. " ) ;
player - > Hurt ( 90 , player - > OnUpperLevel ( ) , player - > GetZ ( ) ) ;
Assert : : AreEqual ( 0.0 _Pct , player - > GetHPRecoveryPct ( ) , L " HP Recovery Pct is still 0% without Second Wind. " ) ;
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
nullRing . lock ( ) - > EnchantItem ( " Second Wind " ) ;
Assert : : AreEqual ( 1.0 _Pct , player - > GetHPRecoveryPct ( ) , L " HP Recovery Pct is now 1% with low health with Second Wind. " ) ;
player - > Heal ( 11 ) ;
Assert : : AreEqual ( 0.0 _Pct , player - > GetHPRecoveryPct ( ) , L " HP Recovery Pct is now 0% since Second Wind should no longer activate above 20% health. " ) ;
}
TEST_METHOD ( EmergencyRecoveryCheck ) {
Assert : : AreEqual ( 0.0 _Pct , player - > GetHP6RecoveryPct ( ) , 0.1 _Pct , L " HP Recovery/6 Pct is 0% at the start. " ) ;
Assert : : AreEqual ( 0.0 _Pct , player - > GetHP4RecoveryPct ( ) , 0.1 _Pct , L " HP Recovery/4 Pct is 0% at the start. " ) ;
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
nullRing . lock ( ) - > EnchantItem ( " Emergency Recovery " ) ;
Assert : : AreEqual ( 1.0 _Pct , player - > GetHP6RecoveryPct ( ) , 0.1 _Pct , L " HP Recovery/6 Pct is base 1% even with full HP. " ) ;
Assert : : AreEqual ( 0.0 _Pct , player - > GetHP4RecoveryPct ( ) , 0.1 _Pct , L " HP Recovery/4 Pct is still 0% since the player is not lower than 30% health. " ) ;
for ( int i : std : : ranges : : iota_view ( 1 , 7 ) ) {
player - > Hurt ( 10 , player - > OnUpperLevel ( ) , player - > GetZ ( ) ) ;
Assert : : AreEqual ( 1.0 _Pct + 0.5 _Pct * i , player - > GetHP6RecoveryPct ( ) , 0.1 _Pct , L " HP Recovery/6 Pct is increasing by 0.5% per 10% missing health. " ) ;
}
player - > Hurt ( 10 , player - > OnUpperLevel ( ) , player - > GetZ ( ) ) ;
Assert : : AreEqual ( 0.0 _Pct , player - > GetHP6RecoveryPct ( ) , 0.1 _Pct , L " HP Recovery/6 Pct is now 0% as the HP Recovery/4 sec version should have activated. " ) ;
Assert : : AreEqual ( 4.5 _Pct , player - > GetHP4RecoveryPct ( ) , 0.1 _Pct , L " HP Recovery/4 Pct is now 4.5% " ) ;
for ( int i : std : : ranges : : iota_view ( 1 , 3 ) ) {
player - > Hurt ( 10 , player - > OnUpperLevel ( ) , player - > GetZ ( ) ) ;
Assert : : AreEqual ( 4.5 _Pct + 0.5 _Pct * i , player - > GetHP4RecoveryPct ( ) , 0.1 _Pct , L " HP Recovery/4 Pct is increasing by 0.5% per 10% missing health. " ) ;
}
}
TEST_METHOD ( DeathDefianceCheck ) {
for ( int i : std : : ranges : : iota_view ( 0 , 10 ) ) {
player - > Heal ( 100 ) ;
player - > Hurt ( 1000 , player - > OnUpperLevel ( ) , player - > GetZ ( ) ) ;
if ( player - > IsAlive ( ) ) { Assert : : Fail ( L " Player survived while not having the Death Defiance Enchant! THIS SHOULD NOT BE HAPPENING! " ) ; }
player - > _SetIframes ( 0.f ) ;
}
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
nullRing . lock ( ) - > EnchantItem ( " Death Defiance " ) ;
player - > Heal ( 100 ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 10 ) ) {
const int prevPlayerHP { player - > GetHealth ( ) } ;
player - > Hurt ( 1 , player - > OnUpperLevel ( ) , player - > GetZ ( ) ) ;
Assert : : AreNotEqual ( prevPlayerHP , player - > GetHealth ( ) , L " Death Defiance triggered even though the player did not take lethal damage! " ) ;
player - > _SetIframes ( 0.f ) ;
}
bool survivedAtLeastOnce { false } ;
for ( int i : std : : ranges : : iota_view ( 0 , 10 ) ) {
player - > Heal ( 100 ) ;
player - > Hurt ( 1000 , player - > OnUpperLevel ( ) , player - > GetZ ( ) ) ;
if ( player - > IsAlive ( ) ) {
survivedAtLeastOnce = true ;
break ;
}
player - > _SetIframes ( 0.f ) ;
}
Assert : : AreEqual ( true , survivedAtLeastOnce , L " Player should have survived at least one time with Death Defiance. " ) ;
}
TEST_METHOD ( ReaperOfSoulsCheck ) {
MonsterData testMonsterData { " TestName " , " Test Monster " , 30 , 10 , 5 , { MonsterDropData { " Health Potion " , 100.f , 1 , 1 } } , 200.f } ;
MONSTER_DATA [ " TestName " ] = testMonsterData ;
Monster testMonster { { } , MONSTER_DATA [ " TestName " ] } ;
Monster testMonster2 { { } , MONSTER_DATA [ " TestName " ] } ;
testMonster . Hurt ( 1000 , testMonster . OnUpperLevel ( ) , testMonster . GetZ ( ) ) ;
testGame - > SetElapsedTime ( 0.5f ) ;
testGame - > OnUserUpdate ( 0.5f ) ;
for ( Effect * eff : game - > GetAllEffects ( ) | std : : views : : filter ( [ ] ( Effect * eff ) { return eff - > GetType ( ) = = EffectType : : MONSTER_SOUL ; } ) ) {
Assert : : Fail ( L " A Monster Soul should not be generated " ) ;
}
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
nullRing . lock ( ) - > EnchantItem ( " Reaper of Souls " ) ;
testMonster2 . Hurt ( 1000 , testMonster2 . OnUpperLevel ( ) , testMonster2 . GetZ ( ) ) ;
testGame - > SetElapsedTime ( 0.5f ) ;
testGame - > OnUserUpdate ( 0.5f ) ;
bool foundSoul { false } ;
for ( const Effect * eff : game - > GetAllEffects ( ) | std : : views : : filter ( [ ] ( const Effect * eff ) { return eff - > GetType ( ) = = EffectType : : MONSTER_SOUL ; } ) ) {
foundSoul = true ;
break ;
}
if ( ! foundSoul ) Assert : : Fail ( L " A soul was not generated from a kill with the Reaper of Souls enchant. " ) ;
testGame - > SetElapsedTime ( 3.5f ) ;
testGame - > OnUserUpdate ( 3.5f ) ;
player - > Hurt ( 5 , player - > OnUpperLevel ( ) , player - > GetZ ( ) ) ;
player - > ConsumeMana ( 10 ) ;
player - > GetRightClickAbility ( ) . cooldown = player - > GetAbility1 ( ) . cooldown = player - > GetAbility2 ( ) . cooldown = player - > GetAbility3 ( ) . cooldown = player - > GetAbility4 ( ) . cooldown = 0.4f ;
for ( int i : std : : ranges : : iota_view ( 0 , 2 ) ) {
testGame - > SetElapsedTime ( 0.001f ) ;
testGame - > OnUserUpdate ( 0.001f ) ;
}
Assert : : AreEqual ( 98 , player - > GetHealth ( ) , L " Player should have healed for 3 health from contacting the soul. " ) ;
Assert : : AreEqual ( 92 , player - > GetMana ( ) , L " Player should have gained 2 mana from contacting the soul. " ) ;
Assert : : AreEqual ( 0.f , player - > GetRightClickAbility ( ) . cooldown , L " Player's ability cooldowns should reduce from contacting the soul. " ) ;
Assert : : AreEqual ( 0.f , player - > GetAbility1 ( ) . cooldown , L " Player's ability cooldowns should reduce from contacting the soul. " ) ;
Assert : : AreEqual ( 0.f , player - > GetAbility2 ( ) . cooldown , L " Player's ability cooldowns should reduce from contacting the soul. " ) ;
Assert : : AreEqual ( 0.f , player - > GetAbility3 ( ) . cooldown , L " Player's ability cooldowns should reduce from contacting the soul. " ) ;
Assert : : AreEqual ( 0.f , player - > GetAbility4 ( ) . cooldown , L " Player's ability cooldowns should reduce from contacting the soul. " ) ;
//This should be the moment the wisp is fading out.
testGame - > SetElapsedTime ( 0.5f ) ;
testGame - > OnUserUpdate ( 0.5f ) ;
for ( Effect * eff : game - > GetAllEffects ( ) | std : : views : : filter ( [ ] ( Effect * eff ) { return eff - > GetType ( ) = = EffectType : : MONSTER_SOUL ; } ) ) {
Assert : : Fail ( L " A Monster Soul has not disappeared after colliding with a player. " ) ;
}
}
TEST_METHOD ( WizardsSoulCheck ) {
testKey - > bHeld = true ; //Force the key to be held down for testing purposes.
player - > CheckAndPerformAbility ( player - > GetRightClickAbility ( ) , testKeyboardInput ) ;
player - > SetState ( State : : NORMAL ) ;
player - > RestoreMana ( 100 ) ;
player - > CheckAndPerformAbility ( player - > GetAbility1 ( ) , testKeyboardInput ) ;
player - > SetState ( State : : NORMAL ) ;
player - > RestoreMana ( 100 ) ;
player - > CheckAndPerformAbility ( player - > GetAbility2 ( ) , testKeyboardInput ) ;
player - > SetState ( State : : NORMAL ) ;
player - > RestoreMana ( 100 ) ;
player - > CheckAndPerformAbility ( player - > GetAbility3 ( ) , testKeyboardInput ) ;
player - > SetState ( State : : NORMAL ) ;
player - > RestoreMana ( 100 ) ;
player - > CheckAndPerformAbility ( player - > GetAbility4 ( ) , testKeyboardInput ) ;
Assert : : AreEqual ( player - > GetRightClickAbility ( ) . GetCooldownTime ( ) , player - > GetRightClickAbility ( ) . cooldown , L " By default the player cooldowns are unaffected without the Wizard's Soul enchant. " ) ;
Assert : : AreEqual ( player - > GetAbility1 ( ) . GetCooldownTime ( ) , player - > GetAbility1 ( ) . cooldown , L " By default the player cooldowns are unaffected without the Wizard's Soul enchant. " ) ;
Assert : : AreEqual ( player - > GetAbility2 ( ) . GetCooldownTime ( ) , player - > GetAbility2 ( ) . cooldown , L " By default the player cooldowns are unaffected without the Wizard's Soul enchant. " ) ;
Assert : : AreEqual ( player - > GetAbility3 ( ) . GetCooldownTime ( ) , player - > GetAbility3 ( ) . cooldown , L " By default the player cooldowns are unaffected without the Wizard's Soul enchant. " ) ;
Assert : : AreEqual ( player - > GetAbility4 ( ) . GetCooldownTime ( ) , player - > GetAbility4 ( ) . cooldown , L " By default the player cooldowns are unaffected without the Wizard's Soul enchant. " ) ;
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
nullRing . lock ( ) - > EnchantItem ( " Wizard's Soul " ) ;
player - > SetState ( State : : NORMAL ) ;
player - > RestoreMana ( 100 ) ;
player - > GetRightClickAbility ( ) . charges = 1 ; //Reset the cooldown so it can be used.
player - > GetRightClickAbility ( ) . cooldown = 0.f ; //Reset the cooldown so it can be used.
player - > CheckAndPerformAbility ( player - > GetRightClickAbility ( ) , testKeyboardInput ) ;
Assert : : AreEqual ( player - > GetRightClickAbility ( ) . GetCooldownTime ( ) , player - > GetRightClickAbility ( ) . cooldown , L " Right-click ability goes on cooldown like normal. " ) ;
Assert : : AreEqual ( player - > GetAbility1 ( ) . GetCooldownTime ( ) , player - > GetAbility1 ( ) . cooldown , L " All other abilities are unaffected by Right-click ability being used. " ) ;
Assert : : AreEqual ( player - > GetAbility2 ( ) . GetCooldownTime ( ) , player - > GetAbility2 ( ) . cooldown , L " All other abilities are unaffected by Right-click ability being used. " ) ;
Assert : : AreEqual ( player - > GetAbility3 ( ) . GetCooldownTime ( ) , player - > GetAbility3 ( ) . cooldown , L " All other abilities are unaffected by Right-click ability being used. " ) ;
Assert : : AreEqual ( player - > GetAbility4 ( ) . GetCooldownTime ( ) , player - > GetAbility4 ( ) . cooldown , L " All other abilities are unaffected by Right-click ability being used. " ) ;
player - > SetState ( State : : NORMAL ) ;
player - > RestoreMana ( 100 ) ;
player - > GetAbility1 ( ) . charges = 1 ; //Reset the cooldown so it can be used.
player - > GetAbility1 ( ) . cooldown = 0.f ; //Reset the cooldown so it can be used.
player - > CheckAndPerformAbility ( player - > GetAbility1 ( ) , testKeyboardInput ) ;
Assert : : AreEqual ( player - > GetRightClickAbility ( ) . GetCooldownTime ( ) , player - > GetRightClickAbility ( ) . cooldown , L " Right-click ability remains unaffected by other abilities. " ) ;
Assert : : AreEqual ( player - > GetAbility1 ( ) . GetCooldownTime ( ) , player - > GetAbility1 ( ) . cooldown , L " Same ability used should not be affected. " ) ;
Assert : : AreEqual ( player - > GetAbility2 ( ) . GetCooldownTime ( ) - 1.5f , player - > GetAbility2 ( ) . cooldown , L " All other abilities have cooldowns reduced by 1.5 seconds. " ) ;
Assert : : AreEqual ( player - > GetAbility3 ( ) . GetCooldownTime ( ) - 1.5f , player - > GetAbility3 ( ) . cooldown , L " All other abilities have cooldowns reduced by 1.5 seconds. " ) ;
Assert : : AreEqual ( player - > GetAbility4 ( ) . GetCooldownTime ( ) - 1.5f , player - > GetAbility4 ( ) . cooldown , L " All other abilities have cooldowns reduced by 1.5 seconds. " ) ;
player - > SetState ( State : : NORMAL ) ;
player - > RestoreMana ( 100 ) ;
player - > GetAbility2 ( ) . charges = 1 ; //Reset the cooldown so it can be used.
player - > GetAbility2 ( ) . cooldown = 0.f ; //Reset the cooldown so it can be used.
player - > CheckAndPerformAbility ( player - > GetAbility2 ( ) , testKeyboardInput ) ;
Assert : : AreEqual ( player - > GetRightClickAbility ( ) . GetCooldownTime ( ) , player - > GetRightClickAbility ( ) . cooldown , L " Right-click ability remains unaffected by other abilities. " ) ;
Assert : : AreEqual ( player - > GetAbility1 ( ) . GetCooldownTime ( ) - 1.5f , player - > GetAbility1 ( ) . cooldown , L " All other abilities have cooldowns reduced by 1.5 seconds. " ) ;
Assert : : AreEqual ( player - > GetAbility2 ( ) . GetCooldownTime ( ) , player - > GetAbility2 ( ) . cooldown , L " Same ability used should not be affected. " ) ;
Assert : : AreEqual ( player - > GetAbility3 ( ) . GetCooldownTime ( ) - 3.f , player - > GetAbility3 ( ) . cooldown , L " All other abilities have cooldowns reduced by 1.5 seconds. " ) ;
Assert : : AreEqual ( player - > GetAbility4 ( ) . GetCooldownTime ( ) - 3.f , player - > GetAbility4 ( ) . cooldown , L " All other abilities have cooldowns reduced by 1.5 seconds. " ) ;
player - > SetState ( State : : NORMAL ) ;
player - > RestoreMana ( 100 ) ;
player - > GetAbility3 ( ) . charges = 1 ; //Reset the cooldown so it can be used.
player - > GetAbility3 ( ) . cooldown = 0.f ; //Reset the cooldown so it can be used.
player - > CheckAndPerformAbility ( player - > GetAbility3 ( ) , testKeyboardInput ) ;
game - > SetElapsedTime ( 1.f ) ;
game - > OnUserUpdate ( 1.f ) ; //It's a cast, so wait one second as the ability gets used. This also reduces cooldowns by a second...
Assert : : AreEqual ( player - > GetRightClickAbility ( ) . GetCooldownTime ( ) - 1.f , player - > GetRightClickAbility ( ) . cooldown , L " Right-click ability remains unaffected by other abilities. " ) ;
Assert : : AreEqual ( player - > GetAbility1 ( ) . GetCooldownTime ( ) - 4.f , player - > GetAbility1 ( ) . cooldown , L " All other abilities have cooldowns reduced by 1.5 seconds. " ) ;
Assert : : AreEqual ( player - > GetAbility2 ( ) . GetCooldownTime ( ) - 2.5f , player - > GetAbility2 ( ) . cooldown , L " All other abilities have cooldowns reduced by 1.5 seconds. " ) ;
Assert : : AreEqual ( player - > GetAbility3 ( ) . GetCooldownTime ( ) - 1.f , player - > GetAbility3 ( ) . cooldown , L " Same ability used should not be affected. " ) ;
Assert : : AreEqual ( player - > GetAbility4 ( ) . GetCooldownTime ( ) , player - > GetAbility4 ( ) . cooldown , L " All other abilities have cooldowns reduced by 1.5 seconds. " ) ;
player - > SetState ( State : : NORMAL ) ;
player - > RestoreMana ( 100 ) ;
player - > GetAbility4 ( ) . charges = 1 ; //Reset the cooldown so it can be used.
player - > GetAbility4 ( ) . cooldown = 0.f ; //Reset the cooldown so it can be used.
player - > CheckAndPerformAbility ( player - > GetAbility4 ( ) , testKeyboardInput ) ;
Assert : : AreEqual ( player - > GetRightClickAbility ( ) . GetCooldownTime ( ) - 1.f , player - > GetRightClickAbility ( ) . cooldown , L " Right-click ability remains unaffected by other abilities. " ) ;
Assert : : AreEqual ( player - > GetAbility1 ( ) . GetCooldownTime ( ) - 4.f , player - > GetAbility1 ( ) . cooldown , L " Ability 4 isn't setup for anything and returns as unused, causing cooldowns to remain the same. " ) ;
Assert : : AreEqual ( player - > GetAbility2 ( ) . GetCooldownTime ( ) - 2.5f , player - > GetAbility2 ( ) . cooldown , L " Ability 4 isn't setup for anything and returns as unused, causing cooldowns to remain the same. " ) ;
Assert : : AreEqual ( player - > GetAbility3 ( ) . GetCooldownTime ( ) - 1.f , player - > GetAbility3 ( ) . cooldown , L " Ability 4 isn't setup for anything and returns as unused, causing cooldowns to remain the same. " ) ;
Assert : : AreEqual ( player - > GetAbility4 ( ) . GetCooldownTime ( ) , player - > GetAbility4 ( ) . cooldown , L " Ability 4 isn't setup for anything and returns as unused, causing cooldowns to remain the same. " ) ;
}
TEST_METHOD ( LastReserveCheck ) {
player - > SetBaseStat ( " Attack " , 100.f ) ;
Assert : : AreEqual ( 0.0 _Pct , player - > GetDamageReductionPct ( ) , L " Damage reduction starts at 0% " ) ;
Assert : : AreEqual ( 100 , player - > GetAttack ( ) , L " Attack damage starts at 100. " ) ;
Assert : : AreEqual ( 0.0 _Pct , player - > GetCooldownReductionPct ( ) , L " Cooldown reduction starts at 0% " ) ;
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
nullRing . lock ( ) - > EnchantItem ( " Last Reserve " ) ;
Assert : : AreEqual ( 0.0 _Pct , player - > GetDamageReductionPct ( ) , L " Damage reduction is still 0% " ) ;
Assert : : AreEqual ( 100 , player - > GetAttack ( ) , L " Attack damage still 100. " ) ;
Assert : : AreEqual ( 0.0 _Pct , player - > GetCooldownReductionPct ( ) , L " Cooldown reduction is still 0% " ) ;
player - > Hurt ( 80 , player - > OnUpperLevel ( ) , player - > GetZ ( ) ) ;
Assert : : AreEqual ( 30.0 _Pct , player - > GetDamageReductionPct ( ) , L " Damage reduction increased to 30% " ) ;
Assert : : AreEqual ( 110 , player - > GetAttack ( ) , L " Attack damage is now 110. " ) ;
Assert : : AreEqual ( 10.0 _Pct , player - > GetCooldownReductionPct ( ) , L " Cooldown reduction increased to 10% " ) ;
}
TEST_METHOD ( QuickdrawCheck ) {
MonsterData testMonsterData { " TestName " , " Test Monster " , 30 , 10 , 5 , { MonsterDropData { " Health Potion " , 100.f , 1 , 1 } } , 200.f } ;
MONSTER_DATA [ " TestName " ] = testMonsterData ;
Monster testMonster { { } , MONSTER_DATA [ " TestName " ] } ;
player - > AutoAttack ( ) ; //Put auto attack on cooldown.
for ( int i : std : : ranges : : iota_view ( 0 , 20 ) ) {
testMonster . Hurt ( 0 , testMonster . OnUpperLevel ( ) , testMonster . GetZ ( ) ) ;
Assert : : AreEqual ( " Warrior.Auto Attack.Cooldown " _F , player - > GetAutoAttackTimer ( ) , L " The auto attack timer should not be reduced: No enchant + wasn't hit by a player ability. " ) ;
}
for ( int i : std : : ranges : : iota_view ( 0 , 20 ) ) {
testMonster . Hurt ( 0 , testMonster . OnUpperLevel ( ) , testMonster . GetZ ( ) , HurtFlag : : PLAYER_ABILITY ) ;
Assert : : AreEqual ( " Warrior.Auto Attack.Cooldown " _F , player - > GetAutoAttackTimer ( ) , L " The auto attack timer should not be reduced: No enchant. " ) ;
}
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
nullRing . lock ( ) - > EnchantItem ( " Quickdraw " ) ;
for ( int i : std : : ranges : : iota_view ( 0 , 20 ) ) {
testMonster . Hurt ( 0 , testMonster . OnUpperLevel ( ) , testMonster . GetZ ( ) ) ;
Assert : : AreEqual ( " Warrior.Auto Attack.Cooldown " _F , player - > GetAutoAttackTimer ( ) , L " The auto attack timer should not be reduced: Wasn't hit by a player ability. " ) ;
}
for ( int i : std : : ranges : : iota_view ( 0 , 20 ) ) {
testMonster . Hurt ( 0 , testMonster . OnUpperLevel ( ) , testMonster . GetZ ( ) , HurtFlag : : PLAYER_ABILITY ) ;
}
Assert : : AreEqual ( 0.f , player - > GetAutoAttackTimer ( ) , L " The auto attack timer should have been reset at some point. " ) ;
}
TEST_METHOD ( StealthyRetreatCheck ) {
game - > ChangePlayerClass ( RANGER ) ;
player = game - > GetPlayer ( ) ;
testKey - > bHeld = true ; //Force the key to be held down for testing purposes.
player - > CheckAndPerformAbility ( player - > GetRightClickAbility ( ) , testKeyboardInput ) ;
Assert : : AreEqual ( " Ranger.Right Click Ability.RetreatTime " _F , player - > GetIframeTime ( ) , L " Ranger's retreat iframe time is normal. " ) ;
player - > _SetIframes ( 0.f ) ;
player - > GetRightClickAbility ( ) . charges = 1 ;
player - > SetState ( State : : NORMAL ) ;
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
nullRing . lock ( ) - > EnchantItem ( " Stealthy Retreat " ) ;
player - > CheckAndPerformAbility ( player - > GetRightClickAbility ( ) , testKeyboardInput ) ;
Assert : : AreEqual ( " Ranger.Right Click Ability.RetreatTime " _F + " Stealthy Retreat " _ENC [ " INVULNERABILITY INCREASE " ] , player - > GetIframeTime ( ) , L " Ranger's retreat iframe time is much greater. " ) ;
}
TEST_METHOD ( PoisonousArrowCheck ) {
game - > ChangePlayerClass ( RANGER ) ;
player = game - > GetPlayer ( ) ;
Assert : : AreEqual ( false , player - > PoisonArrowAutoAttackReady ( ) , L " Poison arrow auto attack should not be ready immediately. " ) ;
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
nullRing . lock ( ) - > EnchantItem ( " Poisonous Arrow " ) ;
Assert : : AreEqual ( true , player - > PoisonArrowAutoAttackReady ( ) , L " Poison arrow auto attack should now be ready. " ) ;
player - > AutoAttack ( ) ;
Assert : : AreEqual ( false , player - > PoisonArrowAutoAttackReady ( ) , L " Poison arrow auto attack should now be on cooldown. " ) ;
game - > SetElapsedTime ( " Poisonous Arrow " _ENC [ " POISON ARROW RESET FREQUENCY " ] ) ;
game - > OnUserUpdate ( " Poisonous Arrow " _ENC [ " POISON ARROW RESET FREQUENCY " ] ) ;
Assert : : AreEqual ( true , player - > PoisonArrowAutoAttackReady ( ) , L " Poison arrow auto attack should be ready again. " ) ;
}
TEST_METHOD ( ExtremeRapidFireCheck ) {
game - > ChangePlayerClass ( RANGER ) ;
player = game - > GetPlayer ( ) ;
Assert : : AreEqual ( 0 , player - > RemainingRapidFireShots ( ) , L " Player starts off with no Rapid Fire shots available. " ) ;
testKey - > bHeld = true ; //Force the key to be held down for testing purposes.
player - > CheckAndPerformAbility ( player - > GetAbility1 ( ) , testKeyboardInput ) ;
Assert : : AreEqual ( " Ranger.Ability 1.ArrowCount " _I , player - > RemainingRapidFireShots ( ) , L " Player now has normal Rapid Fire shot count. " ) ;
for ( int i : std : : ranges : : iota_view ( 0 , " Ranger.Ability 1.ArrowCount " _I ) ) {
game - > SetElapsedTime ( 1.f ) ;
game - > OnUserUpdate ( 1.f ) ;
}
player - > SetState ( State : : NORMAL ) ;
player - > GetAbility1 ( ) . charges = 1 ;
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
nullRing . lock ( ) - > EnchantItem ( " Extreme Rapid Fire " ) ;
player - > CheckAndPerformAbility ( player - > GetAbility1 ( ) , testKeyboardInput ) ;
Assert : : AreEqual ( " Ranger.Ability 1.ArrowCount " _I + int ( " Extreme Rapid Fire " _ENC [ " ARROW COUNT INCREASE " ] ) , player - > RemainingRapidFireShots ( ) , L " Player now has even more Rapid Fire shots. " ) ;
}
TEST_METHOD ( MegaChargedShotCheck ) {
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
nullRing . lock ( ) - > EnchantItem ( " Mega Charged Shot " ) ;
Assert : : AreEqual ( " Warrior.Ability 2.Precast Time " _F , player - > GetAbility2 ( ) . precastInfo . castTime , L " Non-Ranger class' precast times should be unaffected with the item. " ) ;
game - > ChangePlayerClass ( RANGER ) ;
player = game - > GetPlayer ( ) ;
Assert : : AreEqual ( " Ranger.Ability 2.Precast Time " _F + " Mega Charged Shot " _ENC [ " CAST TIME INCREASE " ] , player - > GetAbility2 ( ) . precastInfo . castTime , L " Ranger class' precast time should be affected with the item. " ) ;
Inventory : : UnequipItem ( EquipSlot : : RING1 ) ;
Assert : : AreEqual ( " Ranger.Ability 2.Precast Time " _F , player - > GetAbility2 ( ) . precastInfo . castTime , L " Ranger class' precast time should be back to normal. " ) ;
}
TEST_METHOD ( MultiMultiShotCheck ) {
game - > ChangePlayerClass ( RANGER ) ;
player = game - > GetPlayer ( ) ;
Assert : : AreEqual ( uint8_t ( 1 ) , player - > GetAbility3 ( ) . MAX_CHARGES , L " Player starts with 1 max charge of Multishot. " ) ;
const float multishotCooldownTime { " Ranger.Ability 3.Cooldown " _F } ;
Assert : : AreEqual ( " Ranger.Ability 3.Cooldown " _F , player - > GetAbility3 ( ) . GetCooldownTime ( ) , util : : wformat ( " Player starts with {} seconds of cooldown on Multishot. " , multishotCooldownTime ) . c_str ( ) ) ;
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
nullRing . lock ( ) - > EnchantItem ( " Multi-Multishot " ) ;
Assert : : AreEqual ( uint8_t ( 3 ) , player - > GetAbility3 ( ) . MAX_CHARGES , L " Player now has 3 max charges of Multishot. " ) ;
const float newMultishotCooldownTime { multishotCooldownTime - multishotCooldownTime * " Multi-Multishot " _ENC [ " COOLDOWN REDUCTION PCT " ] / 100.f } ;
Assert : : AreEqual ( newMultishotCooldownTime , player - > GetAbility3 ( ) . GetCooldownTime ( ) , util : : wformat ( " Player starts with {} seconds of cooldown on Multishot. " , newMultishotCooldownTime ) . c_str ( ) ) ;
}
TEST_METHOD ( BackstabberCheck ) {
MonsterData testMonsterData { " TestName " , " Test Monster " , 30 , 10 , 5 , { MonsterDropData { " Health Potion " , 100.f , 1 , 1 } } , 200.f } ;
MONSTER_DATA [ " TestName " ] = testMonsterData ;
Monster testMonster { { } , MONSTER_DATA [ " TestName " ] } ;
testMonster . Hurt ( 10 , testMonster . OnUpperLevel ( ) , testMonster . GetZ ( ) ) ;
Assert : : AreEqual ( 20 , testMonster . GetHealth ( ) , L " Monster should have taken 10 hitpoints of damage. " ) ;
testMonster . Heal ( 10 ) ;
game - > GetPlayer ( ) - > ForceSetPos ( { 4 , 0 } ) ;
testMonster . Hurt ( 10 , testMonster . OnUpperLevel ( ) , testMonster . GetZ ( ) , HurtFlag : : PLAYER_ABILITY ) ;
Assert : : AreEqual ( 20 , testMonster . GetHealth ( ) , L " Monster should have taken 10 hitpoints of damage even if the attack was a valid backstab (no enchantment). " ) ;
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
nullRing . lock ( ) - > EnchantItem ( " Backstabber " ) ;
game - > GetPlayer ( ) - > ForceSetPos ( { 0 , 0 } ) ;
testMonster . Hurt ( 10 , testMonster . OnUpperLevel ( ) , testMonster . GetZ ( ) ) ;
Assert : : AreEqual ( 10 , testMonster . GetHealth ( ) , L " Monster should have taken 10 hitpoints of damage still since it wasn't flagged as a player ability. " ) ;
testMonster . Heal ( 30 ) ;
testMonster . Hurt ( 10 , testMonster . OnUpperLevel ( ) , testMonster . GetZ ( ) , HurtFlag : : PLAYER_ABILITY ) ;
Assert : : AreEqual ( 20 , testMonster . GetHealth ( ) , L " Monster should have taken 10 hitpoints of damage with the backstab bonus because the player is not behind the target. " ) ;
game - > GetPlayer ( ) - > ForceSetPos ( { 4 , 0 } ) ;
testMonster . Hurt ( 10 , testMonster . OnUpperLevel ( ) , testMonster . GetZ ( ) , HurtFlag : : PLAYER_ABILITY ) ;
Assert : : AreEqual ( 6 , testMonster . GetHealth ( ) , L " Monster should have taken 14 hitpoints of damage with the backstab bonus successfully applied. " ) ;
}
TEST_METHOD ( TumbleCheck ) {
testKey - > bHeld = true ; //Force the key to be held down for testing purposes.
game - > ChangePlayerClass ( THIEF ) ;
player = game - > GetPlayer ( ) ;
player - > CheckAndPerformAbility ( player - > GetRightClickAbility ( ) , testKeyboardInput ) ;
const float originalIframeTime { " Thief.Right Click Ability.Iframe Time " _F } ;
Assert : : AreEqual ( originalIframeTime , player - > GetIframeTime ( ) , L " Iframe time should be normal. " ) ;
const float originalMovespdIntensity { " Thief.Right Click Ability.Movespeed Buff " _f [ 0 ] / 100.f } ;
Assert : : AreEqual ( originalMovespdIntensity , player - > GetBuffs ( BuffType : : SPEEDBOOST ) [ 0 ] . intensity , L " Player should have a movespeed buff of the regular intensity. " ) ;
player - > RemoveAllBuffs ( ) ;
player - > GetRightClickAbility ( ) . charges = 1 ;
std : : weak_ptr < Item > nullRing { Inventory : : AddItem ( " Null Ring " s ) } ;
Inventory : : EquipItem ( nullRing , EquipSlot : : RING1 ) ;
nullRing . lock ( ) - > EnchantItem ( " Tumble " ) ;
player - > CheckAndPerformAbility ( player - > GetRightClickAbility ( ) , testKeyboardInput ) ;
Assert : : AreEqual ( originalIframeTime + " Thief.Right Click Ability.Iframe Time " _F * " Tumble " _ENC [ " BOOST PERCENTAGE " ] / 100.f , player - > GetIframeTime ( ) , L " Iframe time should be longer. " ) ;
Assert : : AreEqual ( originalMovespdIntensity + originalMovespdIntensity * " Tumble " _ENC [ " BOOST PERCENTAGE " ] / 100.f , player - > GetBuffs ( BuffType : : SPEEDBOOST ) [ 0 ] . intensity , L " Player should have a movespeed buff with greater intensity. " ) ;
}
} ;
}