|
|
|
|
@ -0,0 +1,638 @@
|
|
|
|
|
#pragma region License
|
|
|
|
|
/*
|
|
|
|
|
License (OLC-3)
|
|
|
|
|
~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
Copyright 2026 Amy 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 © 2024 The FreeType
|
|
|
|
|
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
|
|
|
|
|
All rights reserved.
|
|
|
|
|
*/
|
|
|
|
|
#pragma endregion
|
|
|
|
|
#include"AdventuresInLestoria.h"
|
|
|
|
|
#include"config.h"
|
|
|
|
|
#include"ItemDrop.h"
|
|
|
|
|
#include"Tutorial.h"
|
|
|
|
|
#include"DamageNumber.h"
|
|
|
|
|
#include"GameHelper.h"
|
|
|
|
|
#include"SoundEffect.h"
|
|
|
|
|
#include"Monster.h"
|
|
|
|
|
|
|
|
|
|
using namespace olc::utils;
|
|
|
|
|
|
|
|
|
|
INCLUDE_MONSTER_DATA
|
|
|
|
|
INCLUDE_game
|
|
|
|
|
INCLUDE_GFX
|
|
|
|
|
INCLUDE_DAMAGENUMBER_LIST
|
|
|
|
|
INCLUDE_MONSTER_LIST
|
|
|
|
|
INCLUDE_INITIALIZEGAMECONFIGURATIONS
|
|
|
|
|
|
|
|
|
|
class MonsterTests{
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<AiL>testGame;
|
|
|
|
|
|
|
|
|
|
MonsterTests(){
|
|
|
|
|
SetupTestMonster();
|
|
|
|
|
SetupMockMap();
|
|
|
|
|
}
|
|
|
|
|
~MonsterTests(){
|
|
|
|
|
testGame->EndGame();
|
|
|
|
|
testGame->OnUserUpdate(0.f);
|
|
|
|
|
testGame.reset();
|
|
|
|
|
}
|
|
|
|
|
#pragma region Setup Functions
|
|
|
|
|
//Makes MONSTER_DATA["TestName"] available.
|
|
|
|
|
void SetupTestMonster(){
|
|
|
|
|
InitializeGameConfigurations();
|
|
|
|
|
testGame.reset(new AiL(true));
|
|
|
|
|
ItemAttribute::Initialize();
|
|
|
|
|
ItemInfo::InitializeItems();
|
|
|
|
|
testGame->InitializeGraphics();
|
|
|
|
|
testGame->InitializeClasses();
|
|
|
|
|
sig::Animation::InitializeAnimations();
|
|
|
|
|
Monster::InitializeStrategies();
|
|
|
|
|
MonsterData::InitializeMonsterData();
|
|
|
|
|
testGame->InitializeDefaultKeybinds();
|
|
|
|
|
testGame->InitializePlayer();
|
|
|
|
|
sig::Animation::SetupPlayerAnimations();
|
|
|
|
|
Menu::InitializeMenus();
|
|
|
|
|
Tutorial::Initialize();
|
|
|
|
|
Stats::InitializeDamageReductionTable();
|
|
|
|
|
SoundEffect::Initialize();
|
|
|
|
|
|
|
|
|
|
GameState::Initialize();
|
|
|
|
|
GameState::STATE=GameState::states.at(States::State::GAME_RUN);
|
|
|
|
|
testGame->ResetLevelStates();
|
|
|
|
|
|
|
|
|
|
#pragma region Setup a fake test map
|
|
|
|
|
game->MAP_DATA.Unlock();
|
|
|
|
|
game->MAP_DATA["CAMPAIGN_1_1"];
|
|
|
|
|
Game::_SetCurrentLevel("CAMPAIGN_1_1");
|
|
|
|
|
ItemDrop::ClearDrops();
|
|
|
|
|
game->MAP_DATA.SetInitialized();
|
|
|
|
|
#pragma endregion
|
|
|
|
|
|
|
|
|
|
MonsterData testMonsterData{"TestName","Test Monster",30,10,5,{MonsterDropData{"Health Potion",100.f,1,1}},200.f};
|
|
|
|
|
testMonsterData.hurtSound="Monster Hurt";
|
|
|
|
|
MONSTER_DATA["TestName"]=testMonsterData;
|
|
|
|
|
|
|
|
|
|
Menu::themes.SetInitialized();
|
|
|
|
|
GFX.SetInitialized();
|
|
|
|
|
DAMAGENUMBER_LIST.clear();
|
|
|
|
|
game->MAP_DATA.SetInitialized();
|
|
|
|
|
}
|
|
|
|
|
void SetupMockMap(){
|
|
|
|
|
game->MAP_DATA.at("CAMPAIGN_1_1")=Map{};
|
|
|
|
|
ItemDrop::ClearDrops();
|
|
|
|
|
}
|
|
|
|
|
#pragma endregion
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TEST(MonsterTests,"DisplayNameCheck"){
|
|
|
|
|
REQUIRE("Test Monster"==MONSTER_DATA["TestName"].GetDisplayName());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"InternalNameCheck"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
REQUIRE("TestName"==testMonster.GetName());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"HealthCheck"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
REQUIRE(testMonster.GetHealth()==testMonster.GetMaxHealth());
|
|
|
|
|
REQUIRE(testMonster.GetHealth()==30);
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"Deal5DamageAndNoDamageFlagWork"){
|
|
|
|
|
Monster&testMonster{game->SpawnMonster({},MONSTER_DATA["TestName"])};
|
|
|
|
|
Game::Update(0.f);
|
|
|
|
|
testMonster.Hurt(5,testMonster.OnUpperLevel(),testMonster.GetZ());
|
|
|
|
|
REQUIRE(testMonster.GetHealth()==testMonster.GetMaxHealth()-5);
|
|
|
|
|
REQUIRE(false==testMonster.HasIframes());
|
|
|
|
|
Game::Update(0.1f); //Prevent stacking up damage all on one damage number.
|
|
|
|
|
testMonster.Hurt(0,testMonster.OnUpperLevel(),testMonster.GetZ());
|
|
|
|
|
REQUIRE(size_t(2)==DAMAGENUMBER_LIST.size());
|
|
|
|
|
Game::Update(0.1f); //Prevent stacking up damage all on one damage number.
|
|
|
|
|
testMonster.Hurt(0,testMonster.OnUpperLevel(),testMonster.GetZ(),HurtFlag::NO_DAMAGE_NUMBER);
|
|
|
|
|
REQUIRE(size_t(2)==DAMAGENUMBER_LIST.size());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"Deal5DamageAndDamageSoundEffectsPlay"){
|
|
|
|
|
Monster&testMonster{game->SpawnMonster({},MONSTER_DATA["TestName"])};
|
|
|
|
|
testMonster.Hurt(5,testMonster.OnUpperLevel(),testMonster.GetZ());
|
|
|
|
|
REQUIRE(1==SoundEffect::soundsPlayedLog["Monster Hurt"]);
|
|
|
|
|
Game::Update(0.1f); //Prevent stacking up damage all on one damage number.
|
|
|
|
|
testMonster.Hurt(5,testMonster.OnUpperLevel(),testMonster.GetZ(),HurtFlag::NO_DAMAGE_NUMBER);
|
|
|
|
|
REQUIRE(1==SoundEffect::soundsPlayedLog["Monster Hurt"]);
|
|
|
|
|
Game::Update(0.1f); //Prevent stacking up damage all on one damage number.
|
|
|
|
|
testMonster.Hurt(5,testMonster.OnUpperLevel(),testMonster.GetZ(),HurtFlag::DOT);
|
|
|
|
|
REQUIRE(1==SoundEffect::soundsPlayedLog["Monster Hurt"]);
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"ZeroDamageResultsInTrue"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
const bool result{testMonster.Hurt(0,testMonster.OnUpperLevel(),testMonster.GetZ())};
|
|
|
|
|
REQUIRE(true==result);
|
|
|
|
|
REQUIRE(false==testMonster.HasIframes());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"IFrameShouldResultInNoDamage"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.ApplyIframes(0.5f);
|
|
|
|
|
testMonster.Hurt(5,testMonster.OnUpperLevel(),testMonster.GetZ());
|
|
|
|
|
REQUIRE(testMonster.GetHealth()==testMonster.GetMaxHealth());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"BeingInTheAirShouldAvoidAttacksFromTheGround"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.SetZ(2.f);
|
|
|
|
|
testMonster.Hurt(5,testMonster.OnUpperLevel(),0.f);
|
|
|
|
|
REQUIRE(testMonster.GetHealth()==testMonster.GetMaxHealth());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"MonstersDeal10Damage_NoDamageReduction"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
Monster testMonster2{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
game->GetPlayer()->Hurt(testMonster.GetAttack(),testMonster.OnUpperLevel(),testMonster.GetZ());
|
|
|
|
|
testMonster2.Hurt(testMonster.GetAttack(),testMonster.OnUpperLevel(),testMonster.GetZ());
|
|
|
|
|
REQUIRE(game->GetPlayer()->GetMaxHealth()-10==game->GetPlayer()->GetHealth());
|
|
|
|
|
REQUIRE(testMonster2.GetMaxHealth()-10==testMonster2.GetHealth());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"DoubleAttackPctModifierWorks"){
|
|
|
|
|
Monster buffMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
buffMonster.AddBuff(BuffType::STAT_UP,5,100._Pct,{ItemAttribute::Get("Attack %")});
|
|
|
|
|
|
|
|
|
|
Monster testMonster2{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
game->GetPlayer()->Hurt(buffMonster.GetAttack(),buffMonster.OnUpperLevel(),buffMonster.GetZ());
|
|
|
|
|
testMonster2.Hurt(buffMonster.GetAttack(),buffMonster.OnUpperLevel(),buffMonster.GetZ());
|
|
|
|
|
REQUIRE(game->GetPlayer()->GetMaxHealth()-20==game->GetPlayer()->GetHealth());
|
|
|
|
|
REQUIRE(testMonster2.GetMaxHealth()-20==testMonster2.GetHealth());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"AttackUpModifierWorks"){
|
|
|
|
|
Monster buffMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
buffMonster.AddBuff(BuffType::STAT_UP,5,5.f,{"Attack"});
|
|
|
|
|
|
|
|
|
|
Monster testMonster2{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
game->GetPlayer()->Hurt(buffMonster.GetAttack(),buffMonster.OnUpperLevel(),buffMonster.GetZ());
|
|
|
|
|
testMonster2.Hurt(buffMonster.GetAttack(),buffMonster.OnUpperLevel(),buffMonster.GetZ());
|
|
|
|
|
REQUIRE(game->GetPlayer()->GetMaxHealth()-15==game->GetPlayer()->GetHealth());
|
|
|
|
|
REQUIRE(testMonster2.GetMaxHealth()-15==testMonster2.GetHealth());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"HealthUpModifierWorks"){
|
|
|
|
|
Monster buffMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
buffMonster.AddBuff(BuffType::STAT_UP,5,5.f,{"Health"});
|
|
|
|
|
|
|
|
|
|
REQUIRE(35==buffMonster.GetMaxHealth());
|
|
|
|
|
REQUIRE(30==buffMonster.GetHealth());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"AttackUpPctModifierWorks"){
|
|
|
|
|
Monster buffMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
buffMonster.AddBuff(BuffType::STAT_UP,5,100.0_Pct,{"Attack %"});
|
|
|
|
|
|
|
|
|
|
Monster testMonster2{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
game->GetPlayer()->Hurt(buffMonster.GetAttack(),buffMonster.OnUpperLevel(),buffMonster.GetZ());
|
|
|
|
|
testMonster2.Hurt(buffMonster.GetAttack(),buffMonster.OnUpperLevel(),buffMonster.GetZ());
|
|
|
|
|
REQUIRE(game->GetPlayer()->GetMaxHealth()-20==game->GetPlayer()->GetHealth());
|
|
|
|
|
REQUIRE(testMonster2.GetMaxHealth()-20==testMonster2.GetHealth());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"MonsterIsConsideredDeadAt0Health"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.Hurt(testMonster.GetMaxHealth(),testMonster.OnUpperLevel(),testMonster.GetZ());
|
|
|
|
|
REQUIRE(true==testMonster.IsDead());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"ItemDropSpawnsWhenMonsterIsKilled"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.Hurt(testMonster.GetMaxHealth(),testMonster.OnUpperLevel(),testMonster.GetZ());
|
|
|
|
|
REQUIRE(size_t(1)==ItemDrop::GetDrops().size());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"MoveSpdSetCorrectly"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
REQUIRE(2.f==testMonster.GetMoveSpdMult());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"SlowdownBuffTest"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::SLOWDOWN,5.f,0.5f);
|
|
|
|
|
REQUIRE(1.f==testMonster.GetMoveSpdMult());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"SelfInflictedSlowdownTest"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::SELF_INFLICTED_SLOWDOWN,5.f,0.5f);
|
|
|
|
|
REQUIRE(1.f==testMonster.GetMoveSpdMult());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"SpeedBoostTest"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::SPEEDBOOST,5.f,0.5f);
|
|
|
|
|
REQUIRE(3.f==testMonster.GetMoveSpdMult());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"LockOnSpeedBoostTest"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::LOCKON_SPEEDBOOST,5.f,0.5f);
|
|
|
|
|
REQUIRE(3.f==testMonster.GetMoveSpdMult());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"AdditiveMoveSpdBuffsTest"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::SLOWDOWN,5.f,0.5f);
|
|
|
|
|
testMonster.AddBuff(BuffType::SPEEDBOOST,5.f,0.75f);
|
|
|
|
|
REQUIRE(2.5f==testMonster.GetMoveSpdMult());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"DamageReductionBuffTest"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::DAMAGE_REDUCTION,5.f,0.25f);
|
|
|
|
|
|
|
|
|
|
testMonster.Hurt(testMonster.GetAttack(),testMonster.OnUpperLevel(),testMonster.GetZ());
|
|
|
|
|
//25% damage reduction should result in 7.5 health taken, When ceiling'd results in 8 health taken.
|
|
|
|
|
REQUIRE(22==testMonster.GetHealth());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"BarrierBuffTest"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::BARRIER_DAMAGE_REDUCTION,5.f,0.5f);
|
|
|
|
|
|
|
|
|
|
testMonster.Hurt(testMonster.GetAttack(),testMonster.OnUpperLevel(),testMonster.GetZ());
|
|
|
|
|
//50% damage reduction should result in 5 health taken
|
|
|
|
|
REQUIRE(25==testMonster.GetHealth());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"AdditiveDamageReductionTest"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::DAMAGE_REDUCTION,5.f,0.25f);
|
|
|
|
|
testMonster.AddBuff(BuffType::BARRIER_DAMAGE_REDUCTION,5.f,0.5f);
|
|
|
|
|
|
|
|
|
|
testMonster.Hurt(testMonster.GetAttack(),testMonster.OnUpperLevel(),testMonster.GetZ());
|
|
|
|
|
//25+50% damage reduction should result in 2.5 health taken. When ceiling'd, results in 3 health taken.
|
|
|
|
|
REQUIRE(27==testMonster.GetHealth());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"MaximumDamageReductionTest"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::DAMAGE_REDUCTION,5.f,INFINITY);
|
|
|
|
|
|
|
|
|
|
testMonster.Hurt(testMonster.GetAttack(),testMonster.OnUpperLevel(),testMonster.GetZ());
|
|
|
|
|
//At 100% or more damage reduction, the monster should take 0 damage.
|
|
|
|
|
REQUIRE(30==testMonster.GetHealth());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"TrueDamageTest"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
|
|
|
|
|
testMonster._DealTrueDamage(testMonster.GetAttack()*3);
|
|
|
|
|
REQUIRE(0==testMonster.GetHealth());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"TrueDamageTestWith100PctDamageReduction"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::DAMAGE_REDUCTION,5.f,INFINITY);
|
|
|
|
|
|
|
|
|
|
testMonster._DealTrueDamage(testMonster.GetAttack()*3);
|
|
|
|
|
//Damage reduction should not affect true damage at all.
|
|
|
|
|
REQUIRE(0==testMonster.GetHealth());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"CriticalRateTest"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
|
|
|
|
|
game->GetPlayer()->SetBaseStat(ItemAttribute::Get("Crit Rate"),100.f);
|
|
|
|
|
|
|
|
|
|
testMonster.Hurt(5,testMonster.OnUpperLevel(),testMonster.GetZ());
|
|
|
|
|
//If crit rate works 100% of the time, getting hurt should deal crit dmg % more damage (which defaults to 50%). Ceiling 7.5 damage to 8.
|
|
|
|
|
REQUIRE(22==testMonster.GetHealth());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"CriticalDamageTest"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
|
|
|
|
|
game->GetPlayer()->SetBaseStat(ItemAttribute::Get("Crit Rate"),100.f);
|
|
|
|
|
game->GetPlayer()->SetBaseStat(ItemAttribute::Get("Crit Dmg"),150.f);
|
|
|
|
|
|
|
|
|
|
testMonster.Hurt(5,testMonster.OnUpperLevel(),testMonster.GetZ());
|
|
|
|
|
//If crit rate works 100% of the time, getting hurt will deal 150% more damage. Ceiling 12.5 damage to 13.
|
|
|
|
|
REQUIRE(17==testMonster.GetHealth());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"ShouldNotDieNormallyTest"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.diesNormally=false;
|
|
|
|
|
|
|
|
|
|
testMonster.Hurt(1000,testMonster.OnUpperLevel(),testMonster.GetZ());
|
|
|
|
|
testMonster.Hurt(1000,testMonster.OnUpperLevel(),testMonster.GetZ());
|
|
|
|
|
testMonster.Hurt(1000,testMonster.OnUpperLevel(),testMonster.GetZ());
|
|
|
|
|
//Health should continue to remain at 1 and the monster should remain alive if the dies normally flag is false.
|
|
|
|
|
REQUIRE(1==testMonster.GetHealth());
|
|
|
|
|
REQUIRE(testMonster.IsAlive());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"IllegalDefenseStatUpBuffCheck"){
|
|
|
|
|
try{
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::STAT_UP,5.f,5.f,{"Defense"});
|
|
|
|
|
FAIL("Adding a Defense buff succeeded! This should NOT be allowed!");
|
|
|
|
|
}catch(std::exception&e){}
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"IllegalMoveSpdStatUpBuffCheck"){
|
|
|
|
|
try{
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::STAT_UP,5.f,5.f,{"Move Spd %"});
|
|
|
|
|
FAIL("Adding a Move Spd % buff succeeded! This should NOT be allowed!");
|
|
|
|
|
}catch(std::exception&e){}
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"IllegalDefensePctStatUpBuffCheck"){
|
|
|
|
|
try{
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::STAT_UP,5.f,5.f,{"Defense %"});
|
|
|
|
|
FAIL("Adding a Defense % buff succeeded! This should NOT be allowed!");
|
|
|
|
|
}catch(std::exception&e){}
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"IllegalCDRStatUpBuffCheck"){
|
|
|
|
|
try{
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::STAT_UP,5.f,5.f,{"CDR"});
|
|
|
|
|
FAIL("Adding a CDR buff succeeded! This should NOT be allowed!");
|
|
|
|
|
}catch(std::exception&e){}
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"IllegalCritRateStatUpBuffCheck"){
|
|
|
|
|
try{
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::STAT_UP,5.f,5.f,{"Crit Rate"});
|
|
|
|
|
FAIL("Adding a Crit Rate buff succeeded! This should NOT be allowed!");
|
|
|
|
|
}catch(std::exception&e){}
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"IllegalCritDmgStatUpBuffCheck"){
|
|
|
|
|
try{
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::STAT_UP,5.f,5.f,{"Crit Damage"});
|
|
|
|
|
FAIL("Adding a Crit Damage buff succeeded! This should NOT be allowed!");
|
|
|
|
|
}catch(std::exception&e){}
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"IllegalHPRecoveryPctStatUpBuffCheck"){
|
|
|
|
|
try{
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::STAT_UP,5.f,5.f,{"HP Recovery %"});
|
|
|
|
|
FAIL("Adding a HP Recovery % buff succeeded! This should NOT be allowed!");
|
|
|
|
|
}catch(std::exception&e){}
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"IllegalHP6RecoveryPctStatUpBuffCheck"){
|
|
|
|
|
try{
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::STAT_UP,5.f,5.f,{"HP6 Recovery %"});
|
|
|
|
|
FAIL("Adding a HP6 Recovery % buff succeeded! This should NOT be allowed!");
|
|
|
|
|
}catch(std::exception&e){}
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"IllegalHP4RecoveryPctStatUpBuffCheck"){
|
|
|
|
|
try{
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::STAT_UP,5.f,5.f,{"HP4 Recovery %"});
|
|
|
|
|
FAIL("Adding a HP4 Recovery % buff succeeded! This should NOT be allowed!");
|
|
|
|
|
}catch(std::exception&e){}
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"IllegalDamageReductionStatUpBuffCheck"){
|
|
|
|
|
try{
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::STAT_UP,5.f,5.f,{"Damage Reduction"});
|
|
|
|
|
FAIL("Adding a Damage Reduction buff succeeded! This should NOT be allowed!");
|
|
|
|
|
}catch(std::exception&e){}
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"IllegalAttackSpdStatUpBuffCheck"){
|
|
|
|
|
try{
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::STAT_UP,5.f,5.f,{"Attack Spd"});
|
|
|
|
|
FAIL("Adding a Attack Spd buff succeeded! This should NOT be allowed!");
|
|
|
|
|
}catch(std::exception&e){};
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"IllegalManaStatUpBuffCheck"){
|
|
|
|
|
try{
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::STAT_UP,5.f,5.f,{"Mana"});
|
|
|
|
|
FAIL("Adding a Mana buff succeeded! This should NOT be allowed!");
|
|
|
|
|
}catch(std::exception&e){}
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"DOTTest"){
|
|
|
|
|
Monster testMonster{{},MONSTER_DATA["TestName"]};
|
|
|
|
|
testMonster.AddBuff(BuffType::DAMAGE_REDUCTION,10.f,100._Pct);
|
|
|
|
|
testMonster.Hurt(10,testMonster.OnUpperLevel(),testMonster.GetZ(),HurtFlag::DOT);
|
|
|
|
|
REQUIRE(20==testMonster.GetHealth());
|
|
|
|
|
testMonster.Update(1.f); //Let time pass so two DOT numbers don't stack up.
|
|
|
|
|
testMonster.ApplyIframes(0.5f);
|
|
|
|
|
testMonster.Hurt(10,testMonster.OnUpperLevel(),testMonster.GetZ(),HurtFlag::DOT);
|
|
|
|
|
REQUIRE(10==testMonster.GetHealth());
|
|
|
|
|
REQUIRE(2==std::accumulate(DAMAGENUMBER_LIST.begin(),DAMAGENUMBER_LIST.end(),0,[](int count,const std::shared_ptr<DamageNumber>&damageNumber){
|
|
|
|
|
if(damageNumber->GetType()==DamageNumberType::DOT)return count+1;
|
|
|
|
|
else return count;
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"TrapperMarkTest"){
|
|
|
|
|
MonsterData testMonsterData{"TestName","Test Monster",30,10,5,{MonsterDropData{"Health Potion",100.f,1,1}},200.f};
|
|
|
|
|
game->SpawnMonster({},testMonsterData);
|
|
|
|
|
Game::Update(0.1f); //A monster that is spawned needs to be added to the monster list in the next tick.
|
|
|
|
|
std::weak_ptr<Monster>testMonster{MONSTER_LIST.front()};
|
|
|
|
|
|
|
|
|
|
REQUIRE(uint8_t(0)==testMonster.lock()->GetMarkStacks());
|
|
|
|
|
|
|
|
|
|
testMonster.lock()->ApplyMark(7.f,5U);
|
|
|
|
|
|
|
|
|
|
game->SetElapsedTime(0.3f);
|
|
|
|
|
game->OnUserUpdate(0.3f); //A monster that had a mark applied needs to be added as a lock on target in the next tick.
|
|
|
|
|
|
|
|
|
|
REQUIRE(uint8_t(5)==testMonster.lock()->GetMarkStacks());
|
|
|
|
|
|
|
|
|
|
testMonster.lock()->Hurt(1,testMonster.lock()->OnUpperLevel(),testMonster.lock()->GetZ());
|
|
|
|
|
|
|
|
|
|
REQUIRE(uint8_t(5)==testMonster.lock()->GetMarkStacks());
|
|
|
|
|
|
|
|
|
|
testMonster.lock()->Hurt(1,testMonster.lock()->OnUpperLevel(),testMonster.lock()->GetZ(),HurtFlag::PLAYER_ABILITY);
|
|
|
|
|
|
|
|
|
|
REQUIRE(uint8_t(4)==testMonster.lock()->GetMarkStacks());
|
|
|
|
|
REQUIRE(22==testMonster.lock()->GetHealth());
|
|
|
|
|
|
|
|
|
|
testMonster.lock()->Hurt(1,testMonster.lock()->OnUpperLevel(),testMonster.lock()->GetZ(),HurtFlag::DOT);
|
|
|
|
|
|
|
|
|
|
REQUIRE(uint8_t(4)==testMonster.lock()->GetMarkStacks());
|
|
|
|
|
|
|
|
|
|
testMonster.lock()->_DealTrueDamage(1);
|
|
|
|
|
|
|
|
|
|
REQUIRE(uint8_t(4)==testMonster.lock()->GetMarkStacks());
|
|
|
|
|
|
|
|
|
|
testMonster.lock()->Heal(testMonster.lock()->GetMaxHealth()); //Heal the monster so it doesn't die.
|
|
|
|
|
|
|
|
|
|
testMonster.lock()->_DealTrueDamage(1,HurtFlag::PLAYER_ABILITY);
|
|
|
|
|
|
|
|
|
|
REQUIRE(uint8_t(3)==testMonster.lock()->GetMarkStacks());
|
|
|
|
|
|
|
|
|
|
testMonster.lock()->_DealTrueDamage(10,HurtFlag::DOT|HurtFlag::PLAYER_ABILITY);
|
|
|
|
|
|
|
|
|
|
REQUIRE(uint8_t(2)==testMonster.lock()->GetMarkStacks());
|
|
|
|
|
|
|
|
|
|
testMonster.lock()->Heal(testMonster.lock()->GetMaxHealth());
|
|
|
|
|
|
|
|
|
|
testMonster.lock()->TriggerMark();
|
|
|
|
|
|
|
|
|
|
REQUIRE(uint8_t(1)==testMonster.lock()->GetMarkStacks());
|
|
|
|
|
REQUIRE(24==testMonster.lock()->GetHealth());
|
|
|
|
|
|
|
|
|
|
game->SetElapsedTime(10.f);
|
|
|
|
|
testMonster.lock()->Update(10.f);
|
|
|
|
|
|
|
|
|
|
REQUIRE(uint8_t(0)==testMonster.lock()->GetMarkStacks());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"HurtFailsWhenDead"){
|
|
|
|
|
MonsterData testMonsterData{"TestName","Test Monster",30,10,5,{MonsterDropData{"Health Potion",100.f,1,1}},200.f};
|
|
|
|
|
Monster&m{game->SpawnMonster({},testMonsterData)};
|
|
|
|
|
m.Hurt(50,m.OnUpperLevel(),m.GetZ());
|
|
|
|
|
REQUIRE(m.IsDead());
|
|
|
|
|
REQUIRE(!m.IsAlive());
|
|
|
|
|
|
|
|
|
|
REQUIRE(!m.Hurt(50,m.OnUpperLevel(),m.GetZ()));
|
|
|
|
|
REQUIRE(!m.Hurt(50,m.OnUpperLevel(),m.GetZ(),HurtFlag::DOT));
|
|
|
|
|
REQUIRE(!m.Hurt(50,m.OnUpperLevel(),m.GetZ(),HurtFlag::PLAYER_ABILITY));
|
|
|
|
|
REQUIRE(!m._DealTrueDamage(50));
|
|
|
|
|
REQUIRE(!m._DealTrueDamage(50==HurtFlag::DOT));
|
|
|
|
|
REQUIRE(!m._DealTrueDamage(50==HurtFlag::PLAYER_ABILITY));
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"HurtSucceedsWhenAlive"){
|
|
|
|
|
MonsterData testMonsterData{"TestName","Test Monster",3000,10,5,{MonsterDropData{"Health Potion",100.f,1,1}},200.f};
|
|
|
|
|
Monster&m{game->SpawnMonster({},testMonsterData)};
|
|
|
|
|
m.Hurt(50,m.OnUpperLevel(),m.GetZ());
|
|
|
|
|
REQUIRE(!m.IsDead());
|
|
|
|
|
REQUIRE(m.IsAlive());
|
|
|
|
|
|
|
|
|
|
REQUIRE(m.Hurt(50,m.OnUpperLevel(),m.GetZ()));
|
|
|
|
|
REQUIRE(m.Hurt(50,m.OnUpperLevel(),m.GetZ(),HurtFlag::DOT));
|
|
|
|
|
REQUIRE(m.Hurt(50,m.OnUpperLevel(),m.GetZ(),HurtFlag::PLAYER_ABILITY));
|
|
|
|
|
REQUIRE(m._DealTrueDamage(50));
|
|
|
|
|
REQUIRE(m._DealTrueDamage(50==HurtFlag::DOT));
|
|
|
|
|
REQUIRE(m._DealTrueDamage(50==HurtFlag::PLAYER_ABILITY));
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"HurtSucceedsWhenDyingWithExactHealth"){
|
|
|
|
|
MonsterData testMonsterData{"TestName","Test Monster",50,10,5,{MonsterDropData{"Health Potion",100.f,1,1}},200.f};
|
|
|
|
|
Monster&m{game->SpawnMonster({},testMonsterData)};
|
|
|
|
|
m.Hurt(50,m.OnUpperLevel(),m.GetZ());
|
|
|
|
|
REQUIRE(m.IsDead());
|
|
|
|
|
REQUIRE(!m.IsAlive());
|
|
|
|
|
m.Heal(50);
|
|
|
|
|
REQUIRE(m.Hurt(50,m.OnUpperLevel(),m.GetZ()));
|
|
|
|
|
m.Heal(50);
|
|
|
|
|
REQUIRE(m.Hurt(50,m.OnUpperLevel(),m.GetZ(),HurtFlag::DOT));
|
|
|
|
|
m.Heal(50);
|
|
|
|
|
REQUIRE(m.Hurt(50,m.OnUpperLevel(),m.GetZ(),HurtFlag::PLAYER_ABILITY));
|
|
|
|
|
m.Heal(50);
|
|
|
|
|
REQUIRE(m._DealTrueDamage(50));
|
|
|
|
|
m.Heal(50);
|
|
|
|
|
REQUIRE(m._DealTrueDamage(50==HurtFlag::DOT));
|
|
|
|
|
m.Heal(50);
|
|
|
|
|
REQUIRE(m._DealTrueDamage(50==HurtFlag::PLAYER_ABILITY));
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"UnconsciousMonsterTest"){
|
|
|
|
|
Monster&parrot{game->SpawnMonster({},MONSTER_DATA.at("Parrot"))};
|
|
|
|
|
Game::Update(1.f);
|
|
|
|
|
REQUIRE(!parrot.IsUnconscious());
|
|
|
|
|
parrot.Hurt(1,parrot.OnUpperLevel(),parrot.GetZ());
|
|
|
|
|
REQUIRE(!parrot.IsUnconscious());
|
|
|
|
|
parrot.Hurt(parrot.GetMaxHealth(),parrot.OnUpperLevel(),parrot.GetZ());
|
|
|
|
|
REQUIRE(parrot.IsUnconscious());
|
|
|
|
|
REQUIRE(parrot.IsDead());
|
|
|
|
|
REQUIRE(parrot.InUndamageableState(parrot.OnUpperLevel(),parrot.GetZ()));
|
|
|
|
|
Game::Update(MONSTER_DATA.at("Parrot").UnconsciousTime()/2);
|
|
|
|
|
REQUIRE(parrot.IsUnconscious());
|
|
|
|
|
REQUIRE(parrot.IsDead());
|
|
|
|
|
REQUIRE(parrot.InUndamageableState(parrot.OnUpperLevel(),parrot.GetZ()));
|
|
|
|
|
Game::Update(MONSTER_DATA.at("Parrot").UnconsciousTime()/2);
|
|
|
|
|
REQUIRE(!parrot.IsUnconscious());
|
|
|
|
|
REQUIRE(parrot.IsAlive());
|
|
|
|
|
REQUIRE(!parrot.InUndamageableState(parrot.OnUpperLevel(),parrot.GetZ()));
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"UnconsciousMonsterHurtTest"){
|
|
|
|
|
Monster&parrot{game->SpawnMonster({},MONSTER_DATA.at("Parrot"))};
|
|
|
|
|
Game::Update(1.f);
|
|
|
|
|
parrot.Hurt(parrot.GetMaxHealth(),parrot.OnUpperLevel(),parrot.GetZ());
|
|
|
|
|
REQUIRE(parrot.IsUnconscious());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"MonsterCollisionRadiusTest"){
|
|
|
|
|
Monster&parrot{game->SpawnMonster({},MONSTER_DATA.at("Parrot"))};
|
|
|
|
|
parrot.strategy="[TEST]Run Right"; //Disable default AI for testing collisions
|
|
|
|
|
Game::Update(1.f);
|
|
|
|
|
Game::Update(1.f);
|
|
|
|
|
REQUIRE(parrot.GetOriginalCollisionRadius()==parrot.GetCollisionRadius());
|
|
|
|
|
|
|
|
|
|
REQUIRE(int(game->GetPlayer()->GetMaxHealth()-parrot.GetCollisionDamage())==game->GetPlayer()->GetHealth());
|
|
|
|
|
parrot.SetCollisionRadius(0.f);
|
|
|
|
|
REQUIRE(0.f==parrot.GetCollisionRadius());
|
|
|
|
|
game->GetPlayer()->Heal(game->GetPlayer()->GetMaxHealth());
|
|
|
|
|
game->GetPlayer()->_SetIframes(0.f);
|
|
|
|
|
parrot.SetPos({});
|
|
|
|
|
game->GetPlayer()->ForceSetPos({});
|
|
|
|
|
Game::Update(1.f);
|
|
|
|
|
REQUIRE(game->GetPlayer()->GetMaxHealth()==game->GetPlayer()->GetHealth());
|
|
|
|
|
parrot.SetCollisionRadius(parrot.GetOriginalCollisionRadius());
|
|
|
|
|
Game::Update(1.f);
|
|
|
|
|
REQUIRE(int(game->GetPlayer()->GetMaxHealth()-parrot.GetCollisionDamage())==game->GetPlayer()->GetHealth());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"MonsterCollisionRadiusSizeTest"){
|
|
|
|
|
Monster&parrot{game->SpawnMonster({},MONSTER_DATA.at("Parrot"))};
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"MonsterRunRightTest"){
|
|
|
|
|
Game::LoadLevelWithTMX("TEST_MAP",testGame.get());
|
|
|
|
|
testGame->GetPlayer()->ForceSetPos({100,100});
|
|
|
|
|
Monster&boar{game->SpawnMonster({24,24},MONSTER_DATA.at("Boar"))};
|
|
|
|
|
Game::Update(0.f); // Make sure monster spawns first.
|
|
|
|
|
boar.strategy="[TEST]Run Right";
|
|
|
|
|
const vf2d originalBoarPos{boar.GetPos()};
|
|
|
|
|
Game::Update(0.5f);
|
|
|
|
|
REQUIRE(originalBoarPos+vf2d{50.f*boar.GetMoveSpdMult(),0.f}==boar.GetPos());
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"MonsterHasteMoveTest"){
|
|
|
|
|
Game::LoadLevelWithTMX("TEST_MAP",testGame.get());
|
|
|
|
|
Monster&parrot{game->SpawnMonster({24,24},MONSTER_DATA.at("Parrot"))};
|
|
|
|
|
Game::Update(0.f); // Make sure monster spawns first.
|
|
|
|
|
parrot.strategy="[TEST]Run Right";
|
|
|
|
|
{
|
|
|
|
|
const vf2d originalParrotPos{parrot.GetPos()};
|
|
|
|
|
Game::Update(0.5f);
|
|
|
|
|
REQUIRE(originalParrotPos+vf2d{50.f*parrot.GetMoveSpdMult(),0.f}==parrot.GetPos());
|
|
|
|
|
}
|
|
|
|
|
parrot.AddBuff(BuffType::HASTEN,INFINITE,0.3f);
|
|
|
|
|
{
|
|
|
|
|
const vf2d originalParrotPos{parrot.GetPos()};
|
|
|
|
|
Game::Update(0.5f);
|
|
|
|
|
REQUIRE(originalParrotPos+vf2d{65.f*parrot.GetMoveSpdMult(),0.f}==parrot.GetPos());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
TEST(MonsterTests,"MonsterManaRecoveryTest"){
|
|
|
|
|
Monster&fireMage{game->SpawnMonster({24,24},MONSTER_DATA.at("Skeleton Fire Mage"))};
|
|
|
|
|
std::for_each(MONSTER_DATA["Skeleton Fire Mage"].abilities.begin(),MONSTER_DATA["Skeleton Fire Mage"].abilities.end(),[](MonsterAbilityData&data){
|
|
|
|
|
data.pctCastChance=0.f; //While testing and running game updates we do not want this ability to go off, so we set the cast percent chance to zero percent.
|
|
|
|
|
});
|
|
|
|
|
Game::Update(0.f); // Make sure monster spawns first.
|
|
|
|
|
const int initialMonsterMP{DATA.GetProperty("Monsters.Skeleton Fire Mage.MP").GetInt()};
|
|
|
|
|
REQUIRE(fireMage.mp==initialMonsterMP);
|
|
|
|
|
const float mpRecovery{float(DATA.GetProperty("Monsters.Skeleton Fire Mage.MP Recovery").GetReal())};
|
|
|
|
|
REQUIRE(fireMage.GetMPRecovery()==mpRecovery);
|
|
|
|
|
Game::Update(0.f);
|
|
|
|
|
int newMonsterMP{initialMonsterMP+int(mpRecovery)};
|
|
|
|
|
REQUIRE(fireMage.mp==newMonsterMP);
|
|
|
|
|
Game::Update(0.f);
|
|
|
|
|
REQUIRE(fireMage.mp==newMonsterMP);
|
|
|
|
|
Game::Update(1.f);
|
|
|
|
|
newMonsterMP+=int(mpRecovery);
|
|
|
|
|
REQUIRE(fireMage.mp==newMonsterMP);
|
|
|
|
|
MONSTER_DATA["TestName"].mpRecovery=0.5f;
|
|
|
|
|
MONSTER_DATA["TestName"].abilities.emplace_back("Meteor",50,0.0f);
|
|
|
|
|
Monster&testMonster{game->SpawnMonster({24,24},MONSTER_DATA.at("TestName"))};
|
|
|
|
|
Game::Update(0.f); // Make sure monster spawns first.
|
|
|
|
|
REQUIRE(testMonster.mp==0);
|
|
|
|
|
Game::Update(1.f);
|
|
|
|
|
REQUIRE(testMonster.mp==0);
|
|
|
|
|
REQUIRE(testMonster.mpRemainder==0.5f);
|
|
|
|
|
Game::Update(1.f);
|
|
|
|
|
REQUIRE(testMonster.mp==1);
|
|
|
|
|
REQUIRE(testMonster.mpRemainder==0.f);
|
|
|
|
|
}
|