Supports cloning battles for AI purposes.
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2021-04-11 16:27:21 +02:00
parent 14016837d9
commit a88719e2b3
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
8 changed files with 129 additions and 6 deletions

View File

@ -14,3 +14,48 @@ void PkmnLib::Battling::Battle::ClearWeather() {
_weatherScript = nullptr; _weatherScript = nullptr;
_eventHook.Trigger<WeatherChangeEvent>(""_cnc); _eventHook.Trigger<WeatherChangeEvent>(""_cnc);
} }
PkmnLib::Battling::Battle* PkmnLib::Battling::Battle::Clone() const {
auto parties = ArbUt::List<CreatureLib::Battling::BattleParty*>(_parties.Count());
for (auto* party : _parties) {
parties.Append(party->Clone());
}
auto* battle =
new Battle(_library.ForceAs<const BattleLibrary>(), parties, _canFlee, _numberOfSides, _creaturesPerSide);
for (int i = 0; i < _numberOfSides; ++i) {
battle->_sides.Set(i, _sides[i]->CloneWithoutCreatures());
// FIXME: This is horrible code to translate the creature from the old battle into the same creature in the
// new battle. This needs to be cleaned up, as it's ugly and slow.
for (int creatureIndex = 0; creatureIndex < _creaturesPerSide; ++creatureIndex) {
auto creature = _sides[i]->GetCreature(creatureIndex);
if (!creature.HasValue()) {
continue;
}
for (size_t j = 0; j < _parties.Count(); ++j) {
auto party = _parties[j];
if (!party->IsResponsibleForIndex(i, creatureIndex)) {
continue;
}
auto partyIndex = party->GetParty()->GetParty().IndexOf(creature.GetValue());
if (partyIndex != -1U) {
auto c = battle->_parties.At(j)->GetParty()->GetParty()[partyIndex];
battle->_sides.At(i)->SetCreature(c, creatureIndex);
j = _parties.Count();
break;
}
}
}
}
battle->_random = _random;
battle->_hasEnded = _hasEnded;
battle->_battleResult = _battleResult;
_historyHolder.CloneOnto(battle->_historyHolder);
battle->_currentTurn = _currentTurn;
_volatile.Clone(battle->_volatile);
if (_weatherScript != nullptr) {
battle->_weatherScript = std::unique_ptr<CreatureLib::Battling::BattleScript>(_weatherScript->Clone());
}
return battle;
}

View File

@ -36,6 +36,8 @@ namespace PkmnLib::Battling {
scripts.Append(CreatureLib::Battling::ScriptWrapper( scripts.Append(CreatureLib::Battling::ScriptWrapper(
CreatureLib::Battling::ScriptWrapper::FromScript(&_weatherScript))); CreatureLib::Battling::ScriptWrapper::FromScript(&_weatherScript)));
} }
Battle* Clone() const override;
}; };
} }

View File

@ -13,6 +13,12 @@ namespace PkmnLib::Battling {
const ArbUt::BorrowedPtr<const Library::MoveData> GetMoveData() const { const ArbUt::BorrowedPtr<const Library::MoveData> GetMoveData() const {
return GetAttack().ForceAs<const Library::MoveData>(); return GetAttack().ForceAs<const Library::MoveData>();
} }
LearnedAttack* Clone() const override {
auto move = new LearnedMove(GetAttack().ForceAs<const Library::MoveData>(), GetLearnMethod());
move->DecreaseUses(GetMaxUses() - GetRemainingUses());
return move;
}
}; };
} }

View File

@ -47,3 +47,46 @@ void PkmnLib::Battling::Pokemon::ClearStatus() {
_battle.GetValue()->TriggerEventListener<StatusChangeEvent>(this, ""_cnc); _battle.GetValue()->TriggerEventListener<StatusChangeEvent>(this, ""_cnc);
} }
} }
CreatureLib::Battling::Creature* PkmnLib::Battling::Pokemon::Clone() const {
auto moves = std::vector<CreatureLib::Battling::LearnedAttack*>(_attacks.Count());
auto i = 0;
for (auto* attack : _attacks) {
if (attack == nullptr) {
moves[i++] = nullptr;
} else {
moves[i++] = dynamic_cast<LearnedMove*>(attack->Clone());
}
}
auto* c = new Pokemon(_library.ForceAs<const BattleLibrary>(), _species.ForceAs<const Library::PokemonSpecies>(),
_variant.ForceAs<const Library::PokemonForme>(), _level, _experience, _uniqueIdentifier,
_gender, _coloring, _heldItem.ForceAs<const Library::Item>(), _nickname, _talentIndex, moves,
_individualValues, _effortValues, _nature, _allowedExperienceGain);
c->_displaySpecies = _displaySpecies;
c->_displayVariant = _displayVariant;
c->_currentHealth = _currentHealth;
c->_statBoost = _statBoost;
c->_flatStats = _flatStats;
c->_boostedStats = _boostedStats;
c->_battle = _battle;
c->_side = _side;
c->_onBattleField = _onBattleField;
if (_activeTalent != nullptr) {
c->_activeTalent = std::unique_ptr<PkmnScript::BattleScript>(_activeTalent->Clone());
}
c->_hasOverridenTalent = _hasOverridenTalent;
c->_overridenTalentName = _overridenTalentName;
if (_status != nullptr) {
c->_status = std::unique_ptr<PkmnScript::BattleScript>(_status->Clone());
}
_volatile.Clone(c->_volatile);
c->_types = std::vector<u8>(_types);
if (_statusScript != nullptr) {
c->_statusScript = std::unique_ptr<PkmnScript::BattleScript>(_statusScript->Clone());
}
c->_friendship = _friendship;
c->RecalculateFlatStats();
return c;
}

View File

@ -87,6 +87,8 @@ namespace PkmnLib::Battling {
} }
_friendship = newValue; _friendship = newValue;
} }
Creature* Clone() const override;
}; };
} }

View File

@ -10,10 +10,23 @@ namespace PkmnLib::Battling {
: CreatureLib::Battling::CreatureParty(std::move(party)) {} : CreatureLib::Battling::CreatureParty(std::move(party)) {}
PokemonParty(std::initializer_list<CreatureLib::Battling::Creature*> party) PokemonParty(std::initializer_list<CreatureLib::Battling::Creature*> party)
: CreatureLib::Battling::CreatureParty(party) {} : CreatureLib::Battling::CreatureParty(party) {}
PokemonParty(size_t size) : CreatureLib::Battling::CreatureParty(size) {}
ArbUt::OptionalBorrowedPtr<Pokemon> GetAtIndex(int index) const { ArbUt::OptionalBorrowedPtr<Pokemon> GetAtIndex(int index) const {
return CreatureLib::Battling::CreatureParty::GetAtIndex(index).As<Pokemon>(); return CreatureLib::Battling::CreatureParty::GetAtIndex(index).As<Pokemon>();
} }
CreatureParty* Clone() const override {
auto party = new PokemonParty(GetParty().Count());
auto i = 0;
for (auto c : GetParty()) {
if (c != nullptr) {
party->SwapInto(i, c->Clone());
i++;
}
}
return party;
}
}; };
} }

View File

@ -294,9 +294,19 @@ void AngelScriptScript::PreventOpponentSwitch(const CreatureLib::Battling::Switc
void AngelScriptScript::OnEndTurn(CreatureLib::Battling::Creature* creature) { void AngelScriptScript::OnEndTurn(CreatureLib::Battling::Creature* creature) {
CALL_HOOK(OnEndTurn, { ctx->SetArgObject(0, (void*)creature); }) CALL_HOOK(OnEndTurn, { ctx->SetArgObject(0, (void*)creature); })
} }
void AngelScriptScript::ModifyNumberOfHits(CreatureLib::Battling::AttackTurnChoice* choice, u8* numberOfHits) { void AngelScriptScript::ModifyNumberOfHits(CreatureLib::Battling::AttackTurnChoice* choice,
CALL_HOOK(ModifyNumberOfHits, { u8* numberOfHits){CALL_HOOK(ModifyNumberOfHits,
ctx->SetArgObject(0, (void*)choice); {
ctx->SetArgAddress(1, numberOfHits); ctx->SetArgObject(0, (void*)choice);
}) ctx->SetArgAddress(1, numberOfHits);
})}
CreatureLib::Battling::BattleScript* AngelScriptScript::Clone() {
auto* ctx = _ctxPool->RequestContext();
auto* obj = _type->Instantiate(ctx);
if (_obj != nullptr){
obj->CopyFrom(_obj);
}
_ctxPool->ReturnContextToPool(ctx);
return new AngelScriptScript(_resolver, _type, obj, _ctxPool);
} }

View File

@ -25,6 +25,8 @@ public:
~AngelScriptScript() override { _obj->Release(); } ~AngelScriptScript() override { _obj->Release(); }
BattleScript* Clone() override;
inline asIScriptObject* GetRawAngelscriptObject() const noexcept { return _obj; } inline asIScriptObject* GetRawAngelscriptObject() const noexcept { return _obj; }
[[nodiscard]] const ArbUt::StringView& GetName() const noexcept override { return _type->GetName(); } [[nodiscard]] const ArbUt::StringView& GetName() const noexcept override { return _type->GetName(); }