Better handling of filling empty slots.
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
345af31464
commit
57f16bc420
|
@ -10,9 +10,6 @@ void TurnHandler::RunTurn(Battle* battle, ChoiceQueue* queue) {
|
||||||
HOOK(OnBeforeTurn, choice, choice);
|
HOOK(OnBeforeTurn, choice, choice);
|
||||||
}
|
}
|
||||||
while (queue->HasNext()) {
|
while (queue->HasNext()) {
|
||||||
if (battle->HasRecalledSlots()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto item = queue->Dequeue();
|
auto item = queue->Dequeue();
|
||||||
ExecuteChoice(item);
|
ExecuteChoice(item);
|
||||||
delete item;
|
delete item;
|
||||||
|
|
|
@ -26,6 +26,9 @@ bool Battle::TrySetChoice(BaseTurnChoice* choice) {
|
||||||
|
|
||||||
void Battle::CheckChoicesSetAndRun() {
|
void Battle::CheckChoicesSetAndRun() {
|
||||||
for (auto side : _sides) {
|
for (auto side : _sides) {
|
||||||
|
if (!side->AllPossibleSlotsFilled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!side->AllChoicesSet()) {
|
if (!side->AllChoicesSet()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -34,8 +37,11 @@ void Battle::CheckChoicesSetAndRun() {
|
||||||
auto i = 0;
|
auto i = 0;
|
||||||
for (auto side : _sides) {
|
for (auto side : _sides) {
|
||||||
for (BaseTurnChoice* choice : side->GetChoices()) {
|
for (BaseTurnChoice* choice : side->GetChoices()) {
|
||||||
|
if (choice == nullptr) {
|
||||||
|
throw CreatureException("Choice was null");
|
||||||
|
}
|
||||||
if (choice->GetKind() == TurnChoiceKind::Attack) {
|
if (choice->GetKind() == TurnChoiceKind::Attack) {
|
||||||
auto attack = dynamic_cast<const AttackTurnChoice*>(choice)->GetAttack();
|
auto attack = (dynamic_cast<AttackTurnChoice*>((choice)))->GetAttack();
|
||||||
uint8_t uses = 1;
|
uint8_t uses = 1;
|
||||||
// HOOK: change number of uses needed.
|
// HOOK: change number of uses needed.
|
||||||
if (attack->GetRemainingUses() < uses) {
|
if (attack->GetRemainingUses() < uses) {
|
||||||
|
@ -70,23 +76,21 @@ bool Battle::CreatureInField(const Creature* creature) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Battle::HasRecalledSlots() const { return _numberOfRecalledSlots > 0; }
|
void Battle::ForceRecall(uint8_t side, uint8_t index) { _sides[side]->SetCreature(nullptr, index); }
|
||||||
|
|
||||||
void Battle::ForceRecall(uint8_t side, uint8_t index) {
|
void Battle::FillEmptySlot(uint8_t side, uint8_t index, Creature* c) { _sides[side]->SetCreature(c, index); }
|
||||||
_numberOfRecalledSlots++;
|
|
||||||
// TODO: Switch out.
|
|
||||||
}
|
|
||||||
|
|
||||||
void Battle::FillRecall(uint8_t side, uint8_t, Creature* c) {
|
|
||||||
_numberOfRecalledSlots--;
|
|
||||||
// TODO: switch in.
|
|
||||||
if (_numberOfRecalledSlots == 0 && _currentTurnQueue != nullptr) {
|
|
||||||
TurnHandler::RunTurn(this, _currentTurnQueue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Battle::GetActiveScripts(std::vector<ScriptWrapper>& scripts) { scripts.emplace_back(&_volatile); }
|
void Battle::GetActiveScripts(std::vector<ScriptWrapper>& scripts) { scripts.emplace_back(&_volatile); }
|
||||||
void Battle::SwitchCreature(uint8_t sideIndex, uint8_t index, Creature* c) {
|
void Battle::SwitchCreature(uint8_t sideIndex, uint8_t index, Creature* c) {
|
||||||
auto side = this->_sides[sideIndex];
|
auto side = this->_sides[sideIndex];
|
||||||
side->SetCreature(c, index);
|
side->SetCreature(c, index);
|
||||||
}
|
}
|
||||||
|
bool Battle::CanSlotBeFilled(uint8_t side, uint8_t index) const {
|
||||||
|
for (const auto& party : _parties) {
|
||||||
|
if (party.IsResponsibleForIndex(side, index)) {
|
||||||
|
if (party.HasCreaturesNotInField())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@ namespace CreatureLib::Battling {
|
||||||
Core::Random _random;
|
Core::Random _random;
|
||||||
ChoiceQueue* _currentTurnQueue = nullptr;
|
ChoiceQueue* _currentTurnQueue = nullptr;
|
||||||
|
|
||||||
uint8_t _numberOfRecalledSlots = 0;
|
|
||||||
ScriptSet _volatile;
|
ScriptSet _volatile;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -28,7 +27,7 @@ namespace CreatureLib::Battling {
|
||||||
: _library(library), _parties(parties), _numberOfSides(numberOfSides), _creaturesPerSide(creaturesPerSide) {
|
: _library(library), _parties(parties), _numberOfSides(numberOfSides), _creaturesPerSide(creaturesPerSide) {
|
||||||
_sides = std::vector<BattleSide*>(numberOfSides);
|
_sides = std::vector<BattleSide*>(numberOfSides);
|
||||||
for (size_t i = 0; i < numberOfSides; i++) {
|
for (size_t i = 0; i < numberOfSides; i++) {
|
||||||
_sides[i] = new BattleSide(this, creaturesPerSide);
|
_sides[i] = new BattleSide(i, this, creaturesPerSide);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,11 +53,10 @@ namespace CreatureLib::Battling {
|
||||||
return _sides[target.GetSideIndex()]->GetCreature(target.GetCreatureIndex());
|
return _sides[target.GetSideIndex()]->GetCreature(target.GetCreatureIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool HasRecalledSlots() const;
|
|
||||||
|
|
||||||
void ForceRecall(uint8_t side, uint8_t index);
|
void ForceRecall(uint8_t side, uint8_t index);
|
||||||
void FillRecall(uint8_t side, uint8_t, Creature* c);
|
void FillEmptySlot(uint8_t side, uint8_t index, Creature* c);
|
||||||
void SwitchCreature(uint8_t side, uint8_t index, Creature* c);
|
void SwitchCreature(uint8_t side, uint8_t index, Creature* c);
|
||||||
|
bool CanSlotBeFilled(uint8_t side, uint8_t index) const;
|
||||||
|
|
||||||
void GetActiveScripts(std::vector<ScriptWrapper>& scripts) override;
|
void GetActiveScripts(std::vector<ScriptWrapper>& scripts) override;
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,7 +14,37 @@ namespace CreatureLib::Battling {
|
||||||
: _party(party), _responsibleIndices(responsibleIndices) {}
|
: _party(party), _responsibleIndices(responsibleIndices) {}
|
||||||
|
|
||||||
CreatureParty* GetParty() { return _party; }
|
CreatureParty* GetParty() { return _party; }
|
||||||
std::vector<CreatureIndex>& GetResponsibleIndices() { return _responsibleIndices; }
|
const std::vector<CreatureIndex>& GetResponsibleIndices() const { return _responsibleIndices; }
|
||||||
|
|
||||||
|
bool IsResponsibleForIndex(const CreatureIndex& index) const {
|
||||||
|
for (const auto& i : _responsibleIndices) {
|
||||||
|
if (i == index)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsResponsibleForIndex(uint8_t side, uint8_t index) const {
|
||||||
|
for (const auto& i : _responsibleIndices) {
|
||||||
|
if (i.GetSideIndex() == side && i.GetCreatureIndex() == index)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasCreaturesNotInField() const {
|
||||||
|
auto p = _party->GetParty();
|
||||||
|
for (const auto& creature : p) {
|
||||||
|
if (creature == nullptr)
|
||||||
|
continue;
|
||||||
|
if (creature->IsFainted())
|
||||||
|
continue;
|
||||||
|
if (creature->IsOnBattleField())
|
||||||
|
continue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,17 @@ using namespace CreatureLib::Battling;
|
||||||
|
|
||||||
bool BattleSide::AllChoicesSet() const { return _choicesSet == _creaturesPerSide; }
|
bool BattleSide::AllChoicesSet() const { return _choicesSet == _creaturesPerSide; }
|
||||||
|
|
||||||
|
bool BattleSide::AllPossibleSlotsFilled() const {
|
||||||
|
for (size_t i = 0; i < _creatures.size(); i++) {
|
||||||
|
auto c = _creatures[i];
|
||||||
|
if (c == nullptr || c->IsFainted()) {
|
||||||
|
if (_battle->CanSlotBeFilled(_index, i))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void BattleSide::ResetChoices() {
|
void BattleSide::ResetChoices() {
|
||||||
_choicesSet = 0;
|
_choicesSet = 0;
|
||||||
for (uint8_t i = 0; i < _creaturesPerSide; i++) {
|
for (uint8_t i = 0; i < _creaturesPerSide; i++) {
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
namespace CreatureLib::Battling {
|
namespace CreatureLib::Battling {
|
||||||
class BattleSide : public ScriptSource {
|
class BattleSide : public ScriptSource {
|
||||||
|
uint8_t _index;
|
||||||
uint8_t _creaturesPerSide;
|
uint8_t _creaturesPerSide;
|
||||||
std::vector<Creature*> _creatures;
|
std::vector<Creature*> _creatures;
|
||||||
std::vector<BaseTurnChoice*> _choices;
|
std::vector<BaseTurnChoice*> _choices;
|
||||||
|
@ -15,8 +16,8 @@ namespace CreatureLib::Battling {
|
||||||
Battle* _battle;
|
Battle* _battle;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit BattleSide(Battle* battle, uint8_t creaturesPerSide)
|
explicit BattleSide(uint8_t index, Battle* battle, uint8_t creaturesPerSide)
|
||||||
: _creaturesPerSide(creaturesPerSide), _battle(battle) {
|
: _index(index), _creaturesPerSide(creaturesPerSide), _battle(battle) {
|
||||||
_creatures = std::vector<Creature*>(creaturesPerSide);
|
_creatures = std::vector<Creature*>(creaturesPerSide);
|
||||||
_choices = std::vector<BaseTurnChoice*>(creaturesPerSide);
|
_choices = std::vector<BaseTurnChoice*>(creaturesPerSide);
|
||||||
for (size_t i = 0; i < creaturesPerSide; i++) {
|
for (size_t i = 0; i < creaturesPerSide; i++) {
|
||||||
|
@ -31,6 +32,8 @@ namespace CreatureLib::Battling {
|
||||||
[[nodiscard]] bool AllChoicesSet() const;
|
[[nodiscard]] bool AllChoicesSet() const;
|
||||||
[[nodiscard]] const std::vector<BaseTurnChoice*>& GetChoices() const;
|
[[nodiscard]] const std::vector<BaseTurnChoice*>& GetChoices() const;
|
||||||
|
|
||||||
|
[[nodiscard]] bool AllPossibleSlotsFilled() const;
|
||||||
|
|
||||||
void SetChoice(BaseTurnChoice* choice);
|
void SetChoice(BaseTurnChoice* choice);
|
||||||
void ResetChoices();
|
void ResetChoices();
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ namespace CreatureLib::Battling {
|
||||||
|
|
||||||
Battle* _battle;
|
Battle* _battle;
|
||||||
BattleSide* _side;
|
BattleSide* _side;
|
||||||
|
bool _onBattleField;
|
||||||
|
|
||||||
std::string _nickname = "";
|
std::string _nickname = "";
|
||||||
int8_t _talentIndex;
|
int8_t _talentIndex;
|
||||||
|
@ -68,6 +69,7 @@ namespace CreatureLib::Battling {
|
||||||
void SetBattleData(Battle* battle, BattleSide* side);
|
void SetBattleData(Battle* battle, BattleSide* side);
|
||||||
Battle* GetBattle() const;
|
Battle* GetBattle() const;
|
||||||
BattleSide* GetBattleSide() const;
|
BattleSide* GetBattleSide() const;
|
||||||
|
bool IsOnBattleField() const { return _onBattleField; }
|
||||||
|
|
||||||
const std::string& GetNickname() const;
|
const std::string& GetNickname() const;
|
||||||
const std::string& GetActiveTalent() const;
|
const std::string& GetActiveTalent() const;
|
||||||
|
|
|
@ -15,6 +15,10 @@ namespace CreatureLib::Battling {
|
||||||
uint8_t GetSideIndex() const { return _side; }
|
uint8_t GetSideIndex() const { return _side; }
|
||||||
|
|
||||||
uint8_t GetCreatureIndex() const { return _creature; }
|
uint8_t GetCreatureIndex() const { return _creature; }
|
||||||
|
|
||||||
|
bool operator==(const CreatureIndex& rhs) const { return (_side == rhs._side) && (_creature == rhs._creature); }
|
||||||
|
|
||||||
|
bool operator!=(const CreatureIndex& rhs) const { return !operator==(rhs); }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
using namespace CreatureLib::Battling;
|
using namespace CreatureLib::Battling;
|
||||||
|
|
||||||
TEST_CASE("Set Choice one-sized side", "[Battling]") {
|
TEST_CASE("Set Choice one-sized side", "[Battling]") {
|
||||||
auto side = BattleSide(nullptr, 1);
|
auto side = BattleSide(0, nullptr, 1);
|
||||||
auto c = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
|
auto c = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
|
||||||
side.SetCreature(c, 0);
|
side.SetCreature(c, 0);
|
||||||
auto choice = new PassTurnChoice(c);
|
auto choice = new PassTurnChoice(c);
|
||||||
|
@ -18,7 +18,7 @@ TEST_CASE("Set Choice one-sized side", "[Battling]") {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Set Choice one-sized side, validate all choices set", "[Battling]") {
|
TEST_CASE("Set Choice one-sized side, validate all choices set", "[Battling]") {
|
||||||
auto side = BattleSide(nullptr, 1);
|
auto side = BattleSide(0, nullptr, 1);
|
||||||
auto c = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
|
auto c = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
|
||||||
side.SetCreature(c, 0);
|
side.SetCreature(c, 0);
|
||||||
auto choice = new PassTurnChoice(c);
|
auto choice = new PassTurnChoice(c);
|
||||||
|
@ -30,7 +30,7 @@ TEST_CASE("Set Choice one-sized side, validate all choices set", "[Battling]") {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Set Choice two-sized side", "[Battling]") {
|
TEST_CASE("Set Choice two-sized side", "[Battling]") {
|
||||||
auto side = BattleSide(nullptr, 2);
|
auto side = BattleSide(0, nullptr, 2);
|
||||||
auto c1 = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
|
auto c1 = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
|
||||||
auto c2 = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
|
auto c2 = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
|
||||||
side.SetCreature(c1, 0);
|
side.SetCreature(c1, 0);
|
||||||
|
@ -46,7 +46,7 @@ TEST_CASE("Set Choice two-sized side", "[Battling]") {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Set Choice two-sized side, validate all choices set", "[Battling]") {
|
TEST_CASE("Set Choice two-sized side, validate all choices set", "[Battling]") {
|
||||||
auto side = BattleSide(nullptr, 2);
|
auto side = BattleSide(0, nullptr, 2);
|
||||||
auto c1 = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
|
auto c1 = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
|
||||||
auto c2 = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
|
auto c2 = CreateCreature(GetLibrary(), "testSpecies1", 5).Create();
|
||||||
side.SetCreature(c1, 0);
|
side.SetCreature(c1, 0);
|
||||||
|
|
|
@ -41,8 +41,8 @@ TEST_CASE("Use damaging move", "[Integrations]") {
|
||||||
|
|
||||||
auto battle = Battle(library, {battleParty1, battleParty2});
|
auto battle = Battle(library, {battleParty1, battleParty2});
|
||||||
|
|
||||||
battle.SwitchCreature(0, 0, c1);
|
battle.FillEmptySlot(0, 0, c1);
|
||||||
battle.SwitchCreature(1, 0, c2);
|
battle.FillEmptySlot(1, 0, c2);
|
||||||
|
|
||||||
battle.TrySetChoice(new AttackTurnChoice(c1, c1->GetAttacks()[0], CreatureIndex(1, 0)));
|
battle.TrySetChoice(new AttackTurnChoice(c1, c1->GetAttacks()[0], CreatureIndex(1, 0)));
|
||||||
battle.TrySetChoice(new PassTurnChoice(c2));
|
battle.TrySetChoice(new PassTurnChoice(c2));
|
||||||
|
|
Loading…
Reference in New Issue