More defensive programming.
continuous-integration/drone/push Build is failing Details

Signed-off-by: Deukhoofd <Deukhoofd@gmail.com>
This commit is contained in:
Deukhoofd 2020-08-30 13:14:33 +02:00
parent 32f75f4a47
commit 3233daf9ab
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
5 changed files with 60 additions and 25 deletions

View File

@ -8,20 +8,27 @@ using namespace Battling;
class ChoiceCompare {
public:
explicit ChoiceCompare() {}
bool operator()(const std::shared_ptr<BaseTurnChoice>& a, const std::shared_ptr<BaseTurnChoice>& b) {
auto aKind = a->GetKind();
auto bKind = b->GetKind();
if (aKind != bKind)
return aKind > bKind;
if (aKind == TurnChoiceKind::Attack) {
auto aPriority = dynamic_cast<const AttackTurnChoice*>(a.get())->GetPriority();
auto bPriority = dynamic_cast<const AttackTurnChoice*>(b.get())->GetPriority();
auto aAttack = std::dynamic_pointer_cast<AttackTurnChoice>(a);
auto bAttack = std::dynamic_pointer_cast<AttackTurnChoice>(b);
AssertNotNull(aAttack);
AssertNotNull(bAttack);
auto aPriority = aAttack->GetPriority();
auto bPriority = bAttack->GetPriority();
if (aPriority != bPriority)
return aPriority > bPriority;
}
auto aSpeed = a->GetUser()->GetBoostedStat(Library::Statistic::Speed);
auto bSpeed = b->GetUser()->GetBoostedStat(Library::Statistic::Speed);
auto aUser = a->GetUser();
auto bUser = b->GetUser();
AssertNotNull(aUser);
AssertNotNull(bUser);
auto aSpeed = aUser->GetBoostedStat(Library::Statistic::Speed);
auto bSpeed = bUser->GetBoostedStat(Library::Statistic::Speed);
if (aSpeed != bSpeed)
return aSpeed > bSpeed;
@ -29,13 +36,14 @@ public:
}
};
void TurnOrdering::OrderChoices(std::vector<std::shared_ptr<BaseTurnChoice>>& vec,
[[maybe_unused]] ArbUt::Random& rand) {
for (auto item : vec) {
void TurnOrdering::OrderChoices(std::vector<std::shared_ptr<BaseTurnChoice>>& vec) {
for (const auto& item : vec) {
AssertNotNull(item);
if (item->GetKind() == TurnChoiceKind::Attack) {
auto attackChoice = static_cast<AttackTurnChoice*>(item.get());
auto attackChoice = std::dynamic_pointer_cast<AttackTurnChoice>(item);
AssertNotNull(attackChoice);
auto priority = attackChoice->GetPriority();
HOOK(ChangePriority, attackChoice, attackChoice, &priority);
HOOK(ChangePriority, attackChoice, attackChoice.get(), &priority);
attackChoice->SetPriority(priority);
}
}

View File

@ -9,7 +9,7 @@
namespace CreatureLib::Battling {
class TurnOrdering {
public:
static void OrderChoices(std::vector<std::shared_ptr<BaseTurnChoice>>& vec, ArbUt::Random& rand);
static void OrderChoices(std::vector<std::shared_ptr<BaseTurnChoice>>& vec);
};
}

View File

@ -54,12 +54,12 @@ void Battle::CheckChoicesSetAndRun() {
for (auto choice : side->GetChoices()) {
AssertNotNull(choice)
if (choice->GetKind() == TurnChoiceKind::Attack) {
auto attack = ((AttackTurnChoice*)choice.get())->GetAttack();
auto attack = std::static_pointer_cast<AttackTurnChoice>(choice);
uint8_t uses = 1;
// HOOK: change number of uses needed.
if (attack->GetRemainingUses() < uses) {
if (attack->GetAttack()->GetRemainingUses() < uses) {
choice = std::shared_ptr<BaseTurnChoice>(_library->GetMiscLibrary()->ReplacementAttack(
choice->GetUser().GetRaw(), ((AttackTurnChoice*)choice.get())->GetTarget()));
choice->GetUser().GetRaw(), attack->GetTarget()));
}
// HOOK: Check if we need to change the move
}
@ -74,7 +74,7 @@ void Battle::CheckChoicesSetAndRun() {
}
_currentTurn++;
try {
TurnOrdering::OrderChoices(choices, _random.GetRNG());
TurnOrdering::OrderChoices(choices);
} catch (const std::exception& e) {
THROW("Exception during turn ordering: '" << e.what() << "'.")
}

View File

@ -17,11 +17,11 @@ TEST_CASE("Turn ordering: Attack before pass", "[Battling]") {
auto choice2 = std::make_shared<AttackTurnChoice>(nullptr, &learnedAttack, CreatureIndex(0, 0));
auto vec = std::vector<std::shared_ptr<BaseTurnChoice>>{choice1, choice2};
auto rand = ArbUt::Random();
TurnOrdering::OrderChoices(vec, rand);
TurnOrdering::OrderChoices(vec);
CHECK(vec[0] == choice2);
CHECK(vec[1] == choice1);
vec = std::vector<std::shared_ptr<BaseTurnChoice>>{choice2, choice1};
TurnOrdering::OrderChoices(vec, rand);
TurnOrdering::OrderChoices(vec);
CHECK(vec[0] == choice2);
CHECK(vec[1] == choice1);
}
@ -34,11 +34,11 @@ TEST_CASE("Turn ordering: High priority goes before no priority", "[Battling]")
auto choice2 = std::make_shared<AttackTurnChoice>(nullptr, a2, CreatureIndex(0, 0));
auto vec = std::vector<std::shared_ptr<BaseTurnChoice>>{choice1, choice2};
auto rand = ArbUt::Random();
TurnOrdering::OrderChoices(vec, rand);
TurnOrdering::OrderChoices(vec);
CHECK(vec[0] == choice2);
CHECK(vec[1] == choice1);
vec = std::vector<std::shared_ptr<BaseTurnChoice>>{choice2, choice1};
TurnOrdering::OrderChoices(vec, rand);
TurnOrdering::OrderChoices(vec);
CHECK(vec[0] == choice2);
CHECK(vec[1] == choice1);
@ -54,11 +54,11 @@ TEST_CASE("Turn ordering: Higher priority goes before high priority", "[Battling
auto choice2 = std::make_shared<AttackTurnChoice>(nullptr, a2, CreatureIndex(0, 0));
auto vec = std::vector<std::shared_ptr<BaseTurnChoice>>{choice1, choice2};
auto rand = ArbUt::Random();
TurnOrdering::OrderChoices(vec, rand);
TurnOrdering::OrderChoices(vec);
CHECK(vec[0] == choice2);
CHECK(vec[1] == choice1);
vec = std::vector<std::shared_ptr<BaseTurnChoice>>{choice2, choice1};
TurnOrdering::OrderChoices(vec, rand);
TurnOrdering::OrderChoices(vec);
CHECK(vec[0] == choice2);
CHECK(vec[1] == choice1);
delete a1;
@ -73,11 +73,11 @@ TEST_CASE("Turn ordering: High priority goes before low priority", "[Battling]")
auto choice2 = std::make_shared<AttackTurnChoice>(nullptr, a2, CreatureIndex(0, 0));
auto vec = std::vector<std::shared_ptr<BaseTurnChoice>>{choice1, choice2};
auto rand = ArbUt::Random();
TurnOrdering::OrderChoices(vec, rand);
TurnOrdering::OrderChoices(vec);
CHECK(vec[0] == choice2);
CHECK(vec[1] == choice1);
vec = std::vector<std::shared_ptr<BaseTurnChoice>>{choice2, choice1};
TurnOrdering::OrderChoices(vec, rand);
TurnOrdering::OrderChoices(vec);
CHECK(vec[0] == choice2);
CHECK(vec[1] == choice1);
@ -93,11 +93,11 @@ TEST_CASE("Turn ordering: No priority goes before low priority", "[Battling]") {
auto choice2 = std::make_shared<AttackTurnChoice>(nullptr, a2, CreatureIndex(0, 0));
auto vec = std::vector<std::shared_ptr<BaseTurnChoice>>{choice1, choice2};
auto rand = ArbUt::Random();
TurnOrdering::OrderChoices(vec, rand);
TurnOrdering::OrderChoices(vec);
CHECK(vec[0] == choice2);
CHECK(vec[1] == choice1);
vec = std::vector<std::shared_ptr<BaseTurnChoice>>{choice2, choice1};
TurnOrdering::OrderChoices(vec, rand);
TurnOrdering::OrderChoices(vec);
CHECK(vec[0] == choice2);
CHECK(vec[1] == choice1);

View File

@ -56,6 +56,33 @@ TEST_CASE("Use damaging move", "[Integrations]") {
REQUIRE(c2->GetCurrentHealth() < c2->GetBoostedStat(Statistic::Health));
}
TEST_CASE("Run more turns", "[Integrations]") {
auto library = TestLibrary::Get();
auto c1 =
CreateCreature(library, "testSpecies1"_cnc, 50).WithAttack("standard"_cnc, AttackLearnMethod::Unknown).Create();
CreatureParty party1{c1};
auto battleParty1 = new BattleParty(&party1, {CreatureIndex(0, 0)});
auto c2 =
CreateCreature(library, "testSpecies1"_cnc, 1).WithAttack("standard"_cnc, AttackLearnMethod::Unknown).Create();
auto c3 =
CreateCreature(library, "testSpecies1"_cnc, 1).WithAttack("standard"_cnc, AttackLearnMethod::Unknown).Create();
CreatureParty party2{c2, c3};
auto battleParty2 = new BattleParty(&party2, {CreatureIndex(1, 0)});
auto battle = Battle(library, {battleParty1, battleParty2});
battle.SwitchCreature(0, 0, c1);
battle.SwitchCreature(1, 0, c2);
battle.TrySetChoice(new AttackTurnChoice(c1, c1->GetAttacks()[0], CreatureIndex(1, 0)));
battle.TrySetChoice(new PassTurnChoice(c2));
REQUIRE(c2->IsFainted());
battle.SwitchCreature(1, 0, c3);
battle.TrySetChoice(new AttackTurnChoice(c1, c1->GetAttacks()[0], CreatureIndex(1, 0)));
battle.TrySetChoice(new PassTurnChoice(c3));
}
TEST_CASE("Finish battle when all battle of one side have fainted", "[Integrations]") {
auto library = TestLibrary::Get();
auto c1 =