Files

431 lines
11 KiB
C++

#include "test_mock_actor.h"
#include "doctest.h"
static void nullDBEnemy(lcf::rpg::Enemy&) {}
template <typename F = decltype(&nullDBEnemy)>
static Game_Enemy& MakeEnemy(int id, int hp, int sp, int atk, int def, int spi, int agi, const F& f = &nullDBEnemy) {
auto& tp = lcf::Data::troops[0];
tp.members.resize(1);
tp.members[0].enemy_id = id;
auto* dbe = MakeDBEnemy(id, hp, sp, atk, def, spi, agi);
f(*dbe);
Main_Data::game_enemyparty->ResetBattle(1);
auto& enemy = (*Main_Data::game_enemyparty)[0];
return enemy;
}
TEST_SUITE_BEGIN("Game_Enemy");
TEST_CASE("Default") {
const MockActor m;
auto& e = MakeEnemy(1, 100, 10, 11, 12, 13, 14);
const auto& ce = e;
REQUIRE_EQ(e.GetId(), 1);
REQUIRE_EQ(e.GetType(), Game_Battler::Type_Enemy);
REQUIRE(e.GetStates().empty());
REQUIRE(ce.GetStates().empty());
REQUIRE_EQ(e.GetOriginalPosition(), Point{});
REQUIRE(e.GetName().empty());
REQUIRE(e.GetSpriteName().empty());
REQUIRE_EQ(e.GetBaseMaxHp(), 100);
REQUIRE_EQ(e.GetBaseMaxSp(), 10);
REQUIRE_EQ(e.GetHp(), 100);
REQUIRE_EQ(e.GetSp(), 10);
REQUIRE_EQ(e.GetBaseAtk(), 11);
REQUIRE_EQ(e.GetBaseDef(), 12);
REQUIRE_EQ(e.GetBaseSpi(), 13);
REQUIRE_EQ(e.GetBaseAgi(), 14);
REQUIRE_EQ(e.GetHue(), 0);
REQUIRE_EQ(e.GetBattleAnimationId(), 0);
REQUIRE_EQ(e.GetFlyingOffset(), 0);
REQUIRE_EQ(e.IsTransparent(), 0);
REQUIRE(e.IsInParty());
}
static void testLimits(int base, int battle) {
auto& enemy = MakeEnemy(1, 100, 10, 11, 12, 13, 14);
REQUIRE_EQ(enemy.MaxStatBaseValue(), base);
REQUIRE_EQ(enemy.MaxStatBattleValue(), battle);
SUBCASE("up") {
enemy.SetAtkModifier(999999);
enemy.SetDefModifier(999999);
enemy.SetSpiModifier(999999);
enemy.SetAgiModifier(999999);
REQUIRE_EQ(enemy.GetAtk(), battle);
REQUIRE_EQ(enemy.GetDef(), battle);
REQUIRE_EQ(enemy.GetSpi(), battle);
REQUIRE_EQ(enemy.GetAgi(), battle);
}
SUBCASE("down") {
enemy.SetAtkModifier(-999999);
enemy.SetDefModifier(-999999);
enemy.SetSpiModifier(-999999);
enemy.SetAgiModifier(-999999);
REQUIRE_EQ(enemy.GetAtk(), 1);
REQUIRE_EQ(enemy.GetDef(), 1);
REQUIRE_EQ(enemy.GetSpi(), 1);
REQUIRE_EQ(enemy.GetAgi(), 1);
}
}
TEST_CASE("Limits") {
SUBCASE("2k") {
const MockActor m(Player::EngineRpg2k);
testLimits(999, 9999);
}
SUBCASE("2k3") {
const MockActor m(Player::EngineRpg2k3);
testLimits(999, 9999);
}
}
static decltype(auto) MakeEnemyHit(bool miss) {
return MakeEnemy(1, 1, 1, 1, 1, 1, 1, [&](auto& e) { e.miss = miss; });
}
TEST_CASE("HitRate") {
const MockActor m;
SUBCASE("default") {
auto& e = MakeEnemyHit(false);
REQUIRE_EQ(e.GetHitChance(), 90);
}
SUBCASE("miss") {
auto& e = MakeEnemyHit(true);
REQUIRE_EQ(e.GetHitChance(), 70);
}
}
static decltype(auto) MakeEnemyCrit(bool crit, int rate) {
return MakeEnemy(1, 1, 1, 1, 1, 1, 1, [&](auto& e) { e.critical_hit = crit; e.critical_hit_chance = rate; });
}
TEST_CASE("CritRate") {
const MockActor m;
SUBCASE("disable_0") {
auto& e = MakeEnemyCrit(false, 0);
REQUIRE_EQ(e.GetCriticalHitChance(), 0.0f);
}
SUBCASE("disable_1") {
auto& e = MakeEnemyCrit(false, 1);
REQUIRE_EQ(e.GetCriticalHitChance(), 0.0f);
}
SUBCASE("disable_30") {
auto& e = MakeEnemyCrit(false, 30);
REQUIRE_EQ(e.GetCriticalHitChance(), 0.0f);
}
SUBCASE("enable_0") {
auto& e = MakeEnemyCrit(true, 0);
REQUIRE_EQ(e.GetCriticalHitChance(), std::numeric_limits<float>::infinity());
}
SUBCASE("enable_1") {
auto& e = MakeEnemyCrit(true, 1);
REQUIRE_EQ(e.GetCriticalHitChance(), 1.0f);
}
SUBCASE("enable_30") {
auto& e = MakeEnemyCrit(true, 30);
REQUIRE_EQ(e.GetCriticalHitChance(), doctest::Approx(0.03333f));
}
}
static decltype(auto) MakeEnemyReward(int exp, int gold, int drop_id, int drop_prob) {
return MakeEnemy(1, 1, 1, 1, 1, 1, 1, [&](auto& e) {
e.exp = exp;
e.gold = gold;
e.drop_id = drop_id;
e.drop_prob = drop_prob;
});
}
TEST_CASE("RewardExp") {
const MockActor m;
SUBCASE("0") {
auto& e = MakeEnemyReward(0, 0, 0, 0);
REQUIRE_EQ(e.GetExp(), 0);
}
SUBCASE("55") {
auto& e = MakeEnemyReward(55, 0, 0, 0);
REQUIRE_EQ(e.GetExp(), 55);
}
}
TEST_CASE("RewardGold") {
const MockActor m;
SUBCASE("0") {
auto& e = MakeEnemyReward(0, 0, 0, 0);
REQUIRE_EQ(e.GetMoney(), 0);
}
SUBCASE("55") {
auto& e = MakeEnemyReward(0, 55, 0, 0);
REQUIRE_EQ(e.GetMoney(), 55);
}
}
TEST_CASE("RewardItem") {
const MockActor m;
SUBCASE("0_0") {
auto& e = MakeEnemyReward(0, 0, 0, 0);
REQUIRE_EQ(e.GetDropId(), 0);
REQUIRE_EQ(e.GetDropProbability(), 0);
}
SUBCASE("0_55") {
auto& e = MakeEnemyReward(0, 0, 0, 55);
REQUIRE_EQ(e.GetDropId(), 0);
REQUIRE_EQ(e.GetDropProbability(), 55);
}
SUBCASE("1_0") {
auto& e = MakeEnemyReward(0, 0, 1, 0);
REQUIRE_EQ(e.GetDropId(), 1);
REQUIRE_EQ(e.GetDropProbability(), 0);
}
SUBCASE("1_55") {
auto& e = MakeEnemyReward(0, 0, 1, 55);
REQUIRE_EQ(e.GetDropId(), 1);
REQUIRE_EQ(e.GetDropProbability(), 55);
}
}
static Game_Enemy& MakeEnemyAttribute(int id, int attr_id, int rank) {
return MakeEnemy(id, 1, 1, 1, 1, 1, 1, [&](auto&) { SetDBEnemyAttribute(id, attr_id, rank); } );
}
TEST_CASE("Attribute") {
const MockActor m;
SUBCASE("0") {
const auto& enemy = MakeEnemyAttribute(1, 1, 0);
REQUIRE_EQ(enemy.GetBaseAttributeRate(1), 0);
REQUIRE_EQ(enemy.GetAttributeRate(1), 0);
}
SUBCASE("1") {
const auto& enemy = MakeEnemyAttribute(1, 1, 1);
REQUIRE_EQ(enemy.GetBaseAttributeRate(1), 1);
REQUIRE_EQ(enemy.GetAttributeRate(1), 1);
}
SUBCASE("2") {
const auto& enemy = MakeEnemyAttribute(1, 1, 2);
REQUIRE_EQ(enemy.GetBaseAttributeRate(1), 2);
REQUIRE_EQ(enemy.GetAttributeRate(1), 2);
}
}
TEST_CASE("BadAttribute") {
const MockActor m;
MakeDBAttribute(1, lcf::rpg::Attribute::Type_physical, -100, 200, 100, 50, 0);
SUBCASE("0") {
const auto& enemy = MakeEnemyAttribute(1, 1, 0);
REQUIRE_EQ(enemy.GetBaseAttributeRate(0), 2);
REQUIRE_EQ(enemy.GetAttributeRate(0), 2);
}
SUBCASE("INT_MAX") {
const auto& enemy = MakeEnemyAttribute(1, 1, 0);
REQUIRE_EQ(enemy.GetBaseAttributeRate(INT_MAX), 2);
REQUIRE_EQ(enemy.GetAttributeRate(INT_MAX), 2);
}
}
TEST_CASE("AttributeShift") {
const MockActor m;
SUBCASE("normal") {
auto& enemy = MakeEnemyAttribute(1, 1, 2);
REQUIRE_EQ(enemy.GetAttributeRateShift(1), 0);
REQUIRE(enemy.CanShiftAttributeRate(1, 1));
REQUIRE_EQ(1, enemy.CanShiftAttributeRate(1, 2));
REQUIRE(enemy.CanShiftAttributeRate(1, -1));
REQUIRE_EQ(-1, enemy.CanShiftAttributeRate(1, -2));
REQUIRE_EQ(enemy.GetAttributeRateShift(1), 0);
REQUIRE_EQ(enemy.GetBaseAttributeRate(1), 2);
REQUIRE_EQ(enemy.GetAttributeRate(1), 2);
enemy.ShiftAttributeRate(1, 1);
REQUIRE_EQ(enemy.GetAttributeRateShift(1), 1);
REQUIRE_EQ(enemy.GetBaseAttributeRate(1), 2);
REQUIRE_EQ(enemy.GetAttributeRate(1), 3);
enemy.ShiftAttributeRate(1, -1);
REQUIRE_EQ(enemy.GetAttributeRateShift(1), 0);
REQUIRE_EQ(enemy.GetAttributeRate(1), 2);
enemy.ShiftAttributeRate(1, -1);
REQUIRE_EQ(enemy.GetAttributeRateShift(1), -1);
REQUIRE_EQ(enemy.GetBaseAttributeRate(1), 2);
REQUIRE_EQ(enemy.GetAttributeRate(1), 1);
enemy.ShiftAttributeRate(1, 100);
REQUIRE_EQ(enemy.GetAttributeRateShift(1), 1);
REQUIRE_EQ(enemy.GetBaseAttributeRate(1), 2);
REQUIRE_EQ(enemy.GetAttributeRate(1), 3);
enemy.ShiftAttributeRate(1, -100);
REQUIRE_EQ(enemy.GetAttributeRateShift(1), -1);
REQUIRE_EQ(enemy.GetBaseAttributeRate(1), 2);
REQUIRE_EQ(enemy.GetAttributeRate(1), 1);
}
SUBCASE("overflow") {
auto& enemy = MakeEnemyAttribute(1, 1, 4);
enemy.ShiftAttributeRate(1, 1);
REQUIRE_EQ(enemy.GetAttributeRateShift(1), 1);
REQUIRE_EQ(enemy.GetBaseAttributeRate(1), 4);
REQUIRE_EQ(enemy.GetAttributeRate(1), 4);
}
SUBCASE("underflow") {
auto& enemy = MakeEnemyAttribute(1, 1, 0);
enemy.ShiftAttributeRate(1, -1);
REQUIRE_EQ(enemy.GetAttributeRateShift(1), -1);
REQUIRE_EQ(enemy.GetBaseAttributeRate(1), 0);
REQUIRE_EQ(enemy.GetAttributeRate(1), 0);
}
}
TEST_CASE("AttributeShiftInvalid") {
const MockActor m;
auto& enemy = MakeEnemyAttribute(1, 1, 100);
REQUIRE_EQ(enemy.GetAttributeRateShift(0), 0);
REQUIRE_EQ(enemy.GetAttributeRateShift(INT_MAX), 0);
REQUIRE_FALSE(enemy.CanShiftAttributeRate(0, 1));
REQUIRE_FALSE(enemy.CanShiftAttributeRate(0, -1));
REQUIRE_FALSE(enemy.CanShiftAttributeRate(INT_MAX, 1));
REQUIRE_FALSE(enemy.CanShiftAttributeRate(INT_MAX, -1));
enemy.ShiftAttributeRate(0, 1);
enemy.ShiftAttributeRate(INT_MAX, 1);
REQUIRE_EQ(enemy.GetAttributeRateShift(0), 0);
REQUIRE_EQ(enemy.GetAttributeRateShift(INT_MAX), 0);
REQUIRE_FALSE(enemy.CanShiftAttributeRate(0, 1));
REQUIRE_FALSE(enemy.CanShiftAttributeRate(0, -1));
REQUIRE_FALSE(enemy.CanShiftAttributeRate(INT_MAX, 1));
REQUIRE_FALSE(enemy.CanShiftAttributeRate(INT_MAX, -1));
}
TEST_CASE("ChangeHp") {
const MockActor m;
auto& enemy = MakeEnemy(1, 500, 500, 500, 500, 500, 500);
REQUIRE_EQ(enemy.GetHp(), 500);
SUBCASE("dmg") {
REQUIRE_EQ(enemy.ChangeHp(-9999, true), -500);
REQUIRE_EQ(enemy.GetHp(), 0);
REQUIRE(enemy.IsDead());
REQUIRE_EQ(enemy.ChangeHp(9999, true), 0);
}
SUBCASE("kill") {
enemy.Kill();
REQUIRE_EQ(enemy.GetHp(), 0);
REQUIRE(enemy.IsDead());
REQUIRE_EQ(enemy.ChangeHp(9999, true), 0);
}
SUBCASE("dmg_nokill") {
REQUIRE_EQ(enemy.ChangeHp(-9999, false), -499);
REQUIRE_EQ(enemy.GetHp(), 1);
REQUIRE_FALSE(enemy.IsDead());
REQUIRE_EQ(enemy.ChangeHp(9999, true), 499);
REQUIRE_EQ(enemy.GetHp(), 500);
REQUIRE_FALSE(enemy.IsDead());
}
}
TEST_CASE("ChangeSp") {
const MockActor m;
auto& enemy = MakeEnemy(1, 500, 500, 500, 500, 500, 500);
REQUIRE_EQ(enemy.GetSp(), 500);
REQUIRE_EQ(enemy.ChangeSp(-9999), -500);
REQUIRE_EQ(enemy.GetSp(), 0);
REQUIRE_EQ(enemy.ChangeSp(9999), 500);
}
TEST_CASE("ChangeParam") {
const MockActor m;
auto& enemy = MakeEnemy(1, 500, 500, 200, 300, 400, 500);
REQUIRE_EQ(enemy.GetAtk(), 200);
REQUIRE_EQ(enemy.GetDef(), 300);
REQUIRE_EQ(enemy.GetSpi(), 400);
REQUIRE_EQ(enemy.GetAgi(), 500);
SUBCASE("atk") {
REQUIRE_EQ(enemy.ChangeAtkModifier(-9999), -100);
REQUIRE_EQ(enemy.GetAtk(), 100);
REQUIRE_EQ(enemy.ChangeAtkModifier(9999), 300);
REQUIRE_EQ(enemy.GetAtk(), 400);
}
SUBCASE("def") {
REQUIRE_EQ(enemy.ChangeDefModifier(-9999), -150);
REQUIRE_EQ(enemy.GetDef(), 150);
REQUIRE_EQ(enemy.ChangeDefModifier(9999), 450);
REQUIRE_EQ(enemy.GetDef(), 600);
}
SUBCASE("spi") {
REQUIRE_EQ(enemy.ChangeSpiModifier(-9999), -200);
REQUIRE_EQ(enemy.GetSpi(), 200);
REQUIRE_EQ(enemy.ChangeSpiModifier(9999), 600);
REQUIRE_EQ(enemy.GetSpi(), 800);
}
SUBCASE("agi") {
REQUIRE_EQ(enemy.ChangeAgiModifier(-9999), -250);
REQUIRE_EQ(enemy.GetAgi(), 250);
REQUIRE_EQ(enemy.ChangeAgiModifier(9999), 750);
REQUIRE_EQ(enemy.GetAgi(), 1000);
}
}
TEST_SUITE_END();