diff --git a/src/Battling/Battle/Battle.cpp b/src/Battling/Battle/Battle.cpp index d7da087..c5c1855 100644 --- a/src/Battling/Battle/Battle.cpp +++ b/src/Battling/Battle/Battle.cpp @@ -14,3 +14,48 @@ void PkmnLib::Battling::Battle::ClearWeather() { _weatherScript = nullptr; _eventHook.Trigger(""_cnc); } +PkmnLib::Battling::Battle* PkmnLib::Battling::Battle::Clone() const { + auto parties = ArbUt::List(_parties.Count()); + for (auto* party : _parties) { + parties.Append(party->Clone()); + } + + auto* battle = + new Battle(_library.ForceAs(), 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(_weatherScript->Clone()); + } + + return battle; +} diff --git a/src/Battling/Battle/Battle.hpp b/src/Battling/Battle/Battle.hpp index beab0f0..fc09711 100644 --- a/src/Battling/Battle/Battle.hpp +++ b/src/Battling/Battle/Battle.hpp @@ -36,6 +36,8 @@ namespace PkmnLib::Battling { scripts.Append(CreatureLib::Battling::ScriptWrapper( CreatureLib::Battling::ScriptWrapper::FromScript(&_weatherScript))); } + + Battle* Clone() const override; }; } diff --git a/src/Battling/Pokemon/LearnedMove.hpp b/src/Battling/Pokemon/LearnedMove.hpp index 53eb4a8..47aefb7 100644 --- a/src/Battling/Pokemon/LearnedMove.hpp +++ b/src/Battling/Pokemon/LearnedMove.hpp @@ -13,6 +13,12 @@ namespace PkmnLib::Battling { const ArbUt::BorrowedPtr GetMoveData() const { return GetAttack().ForceAs(); } + + LearnedAttack* Clone() const override { + auto move = new LearnedMove(GetAttack().ForceAs(), GetLearnMethod()); + move->DecreaseUses(GetMaxUses() - GetRemainingUses()); + return move; + } }; } diff --git a/src/Battling/Pokemon/Pokemon.cpp b/src/Battling/Pokemon/Pokemon.cpp index 36ee355..a94feb0 100644 --- a/src/Battling/Pokemon/Pokemon.cpp +++ b/src/Battling/Pokemon/Pokemon.cpp @@ -46,4 +46,47 @@ void PkmnLib::Battling::Pokemon::ClearStatus() { if (_battle.HasValue()) { _battle.GetValue()->TriggerEventListener(this, ""_cnc); } -} \ No newline at end of file +} + +CreatureLib::Battling::Creature* PkmnLib::Battling::Pokemon::Clone() const { + auto moves = std::vector(_attacks.Count()); + auto i = 0; + for (auto* attack : _attacks) { + if (attack == nullptr) { + moves[i++] = nullptr; + } else { + moves[i++] = dynamic_cast(attack->Clone()); + } + } + + auto* c = new Pokemon(_library.ForceAs(), _species.ForceAs(), + _variant.ForceAs(), _level, _experience, _uniqueIdentifier, + _gender, _coloring, _heldItem.ForceAs(), _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(_activeTalent->Clone()); + } + c->_hasOverridenTalent = _hasOverridenTalent; + c->_overridenTalentName = _overridenTalentName; + if (_status != nullptr) { + c->_status = std::unique_ptr(_status->Clone()); + } + _volatile.Clone(c->_volatile); + c->_types = std::vector(_types); + if (_statusScript != nullptr) { + c->_statusScript = std::unique_ptr(_statusScript->Clone()); + } + c->_friendship = _friendship; + c->RecalculateFlatStats(); + + return c; +} diff --git a/src/Battling/Pokemon/Pokemon.hpp b/src/Battling/Pokemon/Pokemon.hpp index ba81436..ac1805a 100644 --- a/src/Battling/Pokemon/Pokemon.hpp +++ b/src/Battling/Pokemon/Pokemon.hpp @@ -87,6 +87,8 @@ namespace PkmnLib::Battling { } _friendship = newValue; } + + Creature* Clone() const override; }; } diff --git a/src/Battling/Pokemon/PokemonParty.hpp b/src/Battling/Pokemon/PokemonParty.hpp index 73f0835..c795fba 100644 --- a/src/Battling/Pokemon/PokemonParty.hpp +++ b/src/Battling/Pokemon/PokemonParty.hpp @@ -10,10 +10,23 @@ namespace PkmnLib::Battling { : CreatureLib::Battling::CreatureParty(std::move(party)) {} PokemonParty(std::initializer_list party) : CreatureLib::Battling::CreatureParty(party) {} + PokemonParty(size_t size) : CreatureLib::Battling::CreatureParty(size) {} ArbUt::OptionalBorrowedPtr GetAtIndex(int index) const { return CreatureLib::Battling::CreatureParty::GetAtIndex(index).As(); } + + 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; + } }; } diff --git a/src/ScriptResolving/AngelScript/AngelScriptScript.cpp b/src/ScriptResolving/AngelScript/AngelScriptScript.cpp index 6c8217a..931db23 100644 --- a/src/ScriptResolving/AngelScript/AngelScriptScript.cpp +++ b/src/ScriptResolving/AngelScript/AngelScriptScript.cpp @@ -294,9 +294,19 @@ void AngelScriptScript::PreventOpponentSwitch(const CreatureLib::Battling::Switc void AngelScriptScript::OnEndTurn(CreatureLib::Battling::Creature* creature) { CALL_HOOK(OnEndTurn, { ctx->SetArgObject(0, (void*)creature); }) } -void AngelScriptScript::ModifyNumberOfHits(CreatureLib::Battling::AttackTurnChoice* choice, u8* numberOfHits) { - CALL_HOOK(ModifyNumberOfHits, { - ctx->SetArgObject(0, (void*)choice); - ctx->SetArgAddress(1, numberOfHits); - }) +void AngelScriptScript::ModifyNumberOfHits(CreatureLib::Battling::AttackTurnChoice* choice, + u8* numberOfHits){CALL_HOOK(ModifyNumberOfHits, + { + 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); } diff --git a/src/ScriptResolving/AngelScript/AngelScriptScript.hpp b/src/ScriptResolving/AngelScript/AngelScriptScript.hpp index 2c7950d..9cc45cf 100644 --- a/src/ScriptResolving/AngelScript/AngelScriptScript.hpp +++ b/src/ScriptResolving/AngelScript/AngelScriptScript.hpp @@ -25,6 +25,8 @@ public: ~AngelScriptScript() override { _obj->Release(); } + BattleScript* Clone() override; + inline asIScriptObject* GetRawAngelscriptObject() const noexcept { return _obj; } [[nodiscard]] const ArbUt::StringView& GetName() const noexcept override { return _type->GetName(); }