2019-10-17 12:33:25 +00:00
|
|
|
#include "BattleSide.hpp"
|
2020-08-14 11:52:22 +00:00
|
|
|
#include "../EventHooks/EventDataClasses.hpp"
|
2021-11-19 12:49:19 +00:00
|
|
|
#include "../ScriptHandling/ScriptMacros.hpp"
|
2021-11-19 14:36:48 +00:00
|
|
|
#include "Battle.hpp"
|
2019-10-29 10:19:25 +00:00
|
|
|
|
|
|
|
using namespace CreatureLib::Battling;
|
|
|
|
|
2020-04-04 15:03:06 +00:00
|
|
|
bool BattleSide::AllChoicesSet() const noexcept { return _choicesSet == _creaturesPerSide; }
|
2019-10-29 10:19:25 +00:00
|
|
|
|
2019-12-07 11:13:12 +00:00
|
|
|
bool BattleSide::AllPossibleSlotsFilled() const {
|
2020-07-28 15:22:43 +00:00
|
|
|
try {
|
|
|
|
for (size_t i = 0; i < _creatures.Count(); i++) {
|
|
|
|
auto c = _creatures[i];
|
2021-06-19 10:33:31 +00:00
|
|
|
if (!c.HasValue() || !c.GetValue()->IsUsable()) {
|
2021-01-15 14:46:48 +00:00
|
|
|
if (_battle->CanSlotBeFilled(_index, i)) {
|
2020-07-28 15:22:43 +00:00
|
|
|
return false;
|
2021-01-15 14:46:48 +00:00
|
|
|
}
|
2020-07-28 15:22:43 +00:00
|
|
|
}
|
2019-12-07 11:13:12 +00:00
|
|
|
}
|
2020-07-28 15:22:43 +00:00
|
|
|
} catch (const std::exception& e) {
|
2021-11-21 11:39:07 +00:00
|
|
|
THROW("Exception during AllPossibleSlotsFilled check: '", e.what(), "'.");
|
2019-12-07 11:13:12 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-04-04 15:03:06 +00:00
|
|
|
void BattleSide::ResetChoices() noexcept {
|
2019-11-06 17:08:21 +00:00
|
|
|
_choicesSet = 0;
|
2022-03-23 12:56:45 +00:00
|
|
|
for (u8 i = 0; i < _creaturesPerSide; i++) {
|
2019-10-29 10:19:25 +00:00
|
|
|
_choices[i] = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-28 11:55:22 +00:00
|
|
|
void BattleSide::SetChoice(BaseTurnChoice* choice) {
|
2020-12-13 11:15:40 +00:00
|
|
|
EnsureNotNull(choice)
|
2020-07-28 15:22:43 +00:00
|
|
|
try {
|
|
|
|
for (size_t i = 0; i < _creatures.Count(); i++) {
|
|
|
|
auto& c = _creatures[i];
|
2020-12-12 11:22:48 +00:00
|
|
|
if (!c.HasValue()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (c.GetValue() == choice->GetUser()) {
|
2020-07-28 15:22:43 +00:00
|
|
|
_choices[i] = std::shared_ptr<BaseTurnChoice>(choice);
|
|
|
|
_choicesSet++;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (const std::exception& e) {
|
2021-11-21 11:39:07 +00:00
|
|
|
THROW("Error during setting choice: '", e.what(), "'.");
|
2020-07-28 15:22:43 +00:00
|
|
|
}
|
2020-08-17 10:18:01 +00:00
|
|
|
THROW("User not found");
|
2019-10-29 10:19:25 +00:00
|
|
|
}
|
|
|
|
|
2022-03-23 12:56:45 +00:00
|
|
|
void BattleSide::SetCreature(ArbUt::OptionalBorrowedPtr<Creature> creature, u8 index) {
|
2019-12-07 20:56:29 +00:00
|
|
|
auto old = _creatures[index];
|
2020-12-12 11:22:48 +00:00
|
|
|
if (old.HasValue()) {
|
2021-11-19 14:36:48 +00:00
|
|
|
HOOK(OnRemove, old.GetValue());
|
2020-12-12 11:22:48 +00:00
|
|
|
old.GetValue()->SetOnBattleField(false);
|
2019-12-07 20:56:29 +00:00
|
|
|
}
|
2021-08-28 17:05:52 +00:00
|
|
|
_creatures[index] = creature;
|
2020-12-12 11:22:48 +00:00
|
|
|
if (!creature.HasValue()) {
|
|
|
|
return;
|
2020-03-25 18:07:36 +00:00
|
|
|
}
|
2020-12-12 11:22:48 +00:00
|
|
|
creature.GetValue()->SetBattleData(_battle, this);
|
|
|
|
creature.GetValue()->SetOnBattleField(true);
|
2021-05-08 09:53:32 +00:00
|
|
|
creature.GetValue()->SetBattleIndex(CreatureIndex(_index, index));
|
2020-12-12 11:22:48 +00:00
|
|
|
for (auto* side : _battle->GetSides()) {
|
|
|
|
if (side == this) {
|
2019-12-14 11:40:50 +00:00
|
|
|
continue;
|
2020-12-12 11:22:48 +00:00
|
|
|
}
|
2020-08-07 08:38:35 +00:00
|
|
|
for (const auto& c : side->GetCreatures()) {
|
2020-12-12 11:22:48 +00:00
|
|
|
if (c.HasValue()) {
|
|
|
|
c.GetValue()->MarkOpponentAsSeen(creature.GetValue());
|
|
|
|
creature.GetValue()->MarkOpponentAsSeen(c.GetValue());
|
2019-12-14 11:40:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-12-12 11:22:48 +00:00
|
|
|
_battle->TriggerEventListener<SwitchEvent>(CreatureIndex(this->_index, index), creature.GetValue());
|
2021-11-19 14:36:48 +00:00
|
|
|
HOOK(OnSwitchIn, creature.GetValue(), creature.GetValue());
|
2019-12-05 11:56:41 +00:00
|
|
|
}
|
2019-11-02 12:57:43 +00:00
|
|
|
|
2020-06-02 11:06:24 +00:00
|
|
|
bool BattleSide::CreatureOnSide(const ArbUt::BorrowedPtr<Creature>& creature) const {
|
2020-12-12 11:22:48 +00:00
|
|
|
return std::find(_creatures.begin(), _creatures.end(), creature.GetRaw()) != _creatures.end();
|
2019-11-02 12:57:43 +00:00
|
|
|
}
|
|
|
|
|
2022-03-23 12:56:45 +00:00
|
|
|
const ArbUt::OptionalBorrowedPtr<Creature>& BattleSide::GetCreature(u8 index) const { return _creatures[index]; }
|
2019-11-10 13:32:05 +00:00
|
|
|
|
2020-05-26 16:31:06 +00:00
|
|
|
void BattleSide::GetActiveScripts(ArbUt::List<ScriptWrapper>& scripts) {
|
2021-10-29 17:31:08 +00:00
|
|
|
GetOwnScripts(scripts);
|
2019-11-10 16:08:42 +00:00
|
|
|
_battle->GetActiveScripts(scripts);
|
2019-11-10 13:32:05 +00:00
|
|
|
}
|
2021-10-29 17:31:08 +00:00
|
|
|
void BattleSide::GetOwnScripts(ArbUt::List<ScriptWrapper>& scripts) {
|
|
|
|
scripts.Append(ScriptWrapper::FromSet(&_volatile));
|
|
|
|
}
|
2020-04-25 09:33:25 +00:00
|
|
|
size_t BattleSide::ScriptCount() const { return _battle->ScriptCount() + 1; }
|
|
|
|
|
2022-03-23 12:56:45 +00:00
|
|
|
u8 BattleSide::GetRandomCreatureIndex() {
|
2020-03-22 09:30:45 +00:00
|
|
|
// TODO: Consider adding parameter to only get index for available creatures.
|
|
|
|
return _battle->GetRandom()->Get(_creaturesPerSide);
|
|
|
|
}
|
2021-03-26 11:01:18 +00:00
|
|
|
bool BattleSide::SwapPositions(u8 a, u8 b) {
|
|
|
|
// If out of range, don't allow swapping.
|
|
|
|
if (a >= _creaturesPerSide || b >= _creaturesPerSide) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the two indices are the same, don't allow swapping.
|
|
|
|
if (a == b) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fetch parties for the two indices.
|
|
|
|
BattleParty* partyA = nullptr;
|
|
|
|
BattleParty* partyB = nullptr;
|
|
|
|
for (auto* party : this->_battle->GetParties()) {
|
|
|
|
if (party->IsResponsibleForIndex(_index, a)) {
|
|
|
|
partyA = party;
|
|
|
|
}
|
|
|
|
if (party->IsResponsibleForIndex(_index, b)) {
|
|
|
|
partyB = party;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Don't allow swapping if different parties are responsible for the indices.
|
|
|
|
if (partyA != partyB) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto creatureA = _creatures[a];
|
|
|
|
_creatures[a] = _creatures[b];
|
|
|
|
_creatures[b] = creatureA;
|
2021-03-28 09:58:26 +00:00
|
|
|
_battle->TriggerEventListener<SwapEvent>(_index, a, b);
|
2021-03-26 11:01:18 +00:00
|
|
|
return true;
|
|
|
|
}
|
2021-04-13 20:45:48 +00:00
|
|
|
|
2021-05-08 09:53:32 +00:00
|
|
|
BattleSide* BattleSide::CloneWithoutCreatures(ArbUt::BorrowedPtr<Battle> battle) const {
|
|
|
|
auto* side = new BattleSide(_index, battle, _creaturesPerSide);
|
2021-04-11 13:20:50 +00:00
|
|
|
side->_choicesSet = _choicesSet;
|
2021-10-29 19:55:49 +00:00
|
|
|
_volatile.Clone(side, side->_volatile);
|
2021-04-11 13:20:50 +00:00
|
|
|
side->_hasFled = _hasFled;
|
|
|
|
return side;
|
|
|
|
}
|
2021-10-28 12:49:24 +00:00
|
|
|
|
|
|
|
BattleScript* BattleSide::AddVolatileScript(const ArbUt::StringView& key) {
|
|
|
|
auto script = _volatile.Get(key);
|
|
|
|
if (script.HasValue()) {
|
|
|
|
script.GetValue()->Stack();
|
|
|
|
return script.GetValue();
|
|
|
|
}
|
2021-10-29 19:40:10 +00:00
|
|
|
script = _battle->GetLibrary()->LoadScript(this, ScriptCategory::Side, key);
|
2021-10-28 12:49:24 +00:00
|
|
|
if (!script.HasValue()) {
|
2021-11-21 11:39:07 +00:00
|
|
|
THROW("Invalid volatile script requested for battleside: '", key.c_str(), "'.");
|
2021-10-28 12:49:24 +00:00
|
|
|
}
|
|
|
|
return _volatile.Add(script.GetValue());
|
|
|
|
}
|
|
|
|
BattleScript* BattleSide::AddVolatileScript(BattleScript* script) { return _volatile.Add(script); }
|
|
|
|
void BattleSide::RemoveVolatileScript(BattleScript* script) { _volatile.Remove(script->GetName()); }
|