diff --git a/CMakeLists.txt b/CMakeLists.txt index e89b8f28..bddf2075 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -238,7 +238,6 @@ if(ENABLE_TESTING) tests/Moves/FuryAttack.cpp tests/Moves/KnockOff.cpp tests/PokedexTest.cpp - tests/RegistryContainerTests.cpp tests/SimulateTurnsTest.cpp tests/SimulationSetupTest.cpp tests/Tests.cpp diff --git a/CMakePresets.json b/CMakePresets.json index e070bbb6..168e51c5 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -80,9 +80,22 @@ { "name": "benchmark-release-with-checks", "inherits": [ - "test", "benchmark-release" - ] + ], + "cacheVariables": { + "CMAKE_BUILD_TYPE": "RelWithDebInfo", + "ENABLE_TESTING": "ON" + } + }, + { + "name": "profile", + "inherits": [ + "benchmark", + "default" + ], + "cacheVariables": { + "CMAKE_BUILD_TYPE": "RelWithDebInfo" + } } ], "buildPresets": [ @@ -127,6 +140,11 @@ "name": "benchmark-release-with-checks", "inherits": "benchmark", "configurePreset": "benchmark-release-with-checks" + }, + { + "name": "profile", + "inherits": "benchmark", + "configurePreset": "profile" } ] } diff --git a/extras/PokeSim.cpp b/extras/PokeSim.cpp index c2f00292..b970eda8 100644 --- a/extras/PokeSim.cpp +++ b/extras/PokeSim.cpp @@ -209,12 +209,20 @@ void checkStat(types::stat stat, bool hp = false) { } } -void checkEffectiveStat(types::stat stat, bool hp = false) { - if (hp) { - checkBounds(stat); - } - else { - checkBounds(stat); +void checkEffectiveStat(types::stat stat, dex::Stat name = dex::Stat::NONE) { + switch (name) { + case dex::Stat::HP: { + checkBounds(stat); + break; + } + case dex::Stat::SPE: { + checkBounds(stat); + break; + } + default: { + checkBounds(stat); + break; + } } } @@ -1259,32 +1267,32 @@ void check(const stat::Spe& spe) { template <> void check(const stat::CurrentHp& hp) { - checkBounds(hp.val); + checkEffectiveStat(hp.val, dex::Stat::HP); } template <> void check(const stat::EffectiveAtk& atk) { - checkEffectiveStat(atk.val); + checkEffectiveStat(atk.val, dex::Stat::ATK); } template <> void check(const stat::EffectiveDef& def) { - checkEffectiveStat(def.val); + checkEffectiveStat(def.val, dex::Stat::DEF); } template <> void check(const stat::EffectiveSpa& spa) { - checkEffectiveStat(spa.val); + checkEffectiveStat(spa.val, dex::Stat::SPA); } template <> void check(const stat::EffectiveSpd& spd) { - checkEffectiveStat(spd.val); + checkEffectiveStat(spd.val, dex::Stat::SPD); } template <> void check(const stat::EffectiveSpe& spe) { - checkEffectiveStat(spe.val); + checkEffectiveStat(spe.val, dex::Stat::SPE); } template <> @@ -1587,10 +1595,10 @@ types::sides Simulation::createInitialBattle( if (battleInfo.runWithSimulateTurn) { battleStateSetup.setProperty(); } - if (battleInfo.runWithCalculateDamage || !battleInfo.damageCalculations.empty()) { + if (battleInfo.runWithCalculateDamage) { battleStateSetup.setProperty(); } - if (battleInfo.runWithAnalyzeEffect || !battleInfo.effectsToAnalyze.empty()) { + if (battleInfo.runWithAnalyzeEffect) { battleStateSetup.setProperty(); } @@ -1901,32 +1909,17 @@ void Simulation::run() { analyzeEffect(); } -types::entityVector Simulation::selectedBattleEntities() const { - if (hasActiveSelection()) { - auto view = registry.view(); - return {view.begin(), view.end()}; - } - +types::entityVector Simulation::battleEntities() const { auto view = registry.view(); return {view.begin(), view.end()}; } -types::entityVector Simulation::selectedMoveEntities() const { - if (hasActiveSelection()) { - auto view = registry.view(); - return {view.begin(), view.end()}; - } - +types::entityVector Simulation::moveEntities() const { auto view = registry.view(); return {view.begin(), view.end()}; } -types::entityVector Simulation::selectedPokemonEntities() const { - if (hasActiveSelection()) { - auto view = registry.view(); - return {view.begin(), view.end()}; - } - +types::entityVector Simulation::pokemonEntities() const { auto view = registry.view(); return {view.begin(), view.end()}; } @@ -1936,8 +1929,6 @@ types::entityVector Simulation::selectedPokemonEntities() const { ///////////////////// START OF src/Simulation/RunEvent.cpp ///////////////////// -#include - // TODO(aed3) Autogenerate? namespace pokesim { @@ -1947,37 +1938,6 @@ void applyEventModifier(ModifiedComponent& component, EventModifier eventModifie component.val = applyChainedModifier(component.val, eventModifier.val); } -template -internal::RegistryContainer::SelectionFunction getMoveEventPokemonSelector() { - static const size_t SelectAnyPokemon = sizeof...(PokemonSpecifiers) == 0U; - return internal::RegistryContainer::SelectionFunction{ - [](const void*, const types::registry& registry) -> types::entityVector { - entt::dense_set entities; - auto selectedMoveView = registry.view(); - auto begin = selectedMoveView.begin(); - auto end = selectedMoveView.end(); - if (selectedMoveView.empty()) { - auto anyMoveView = registry.view(); - begin = anyMoveView.begin(); - end = anyMoveView.end(); - } - - std::for_each(begin, end, [®istry, &entities](types::entity entity) { - if constexpr ( - SelectAnyPokemon || std::disjunction_v...>) { - entities.insert(registry.get(entity).val); - } - - if constexpr ( - SelectAnyPokemon || std::disjunction_v...>) { - entities.insert(registry.get(entity).val); - } - }); - - return {entities.begin(), entities.end()}; - }}; -} - void applyBasePowerEventModifier(types::handle moveHandle, BasePower basePower, EventModifier eventModifier) { calc_damage::Power& power = moveHandle.emplace(basePower.val); power.val = applyChainedModifier(power.val, eventModifier.val); @@ -1990,32 +1950,28 @@ void runBeforeMove(Simulation& simulation) { } void runResidual(Simulation& simulation) { - pokesim::internal::SelectForPokemonView selectedPokemon{simulation}; - if (selectedPokemon.hasNoneSelected()) { - return; - } dex::Burn::onResidual(simulation); } void runAccuracyEvent(Simulation&) {} void runModifyAccuracyEvent(Simulation& simulation) { - simulation.addToEntities(); + simulation.addToEntities(); dex::BrightPowder::onModifyAccuracy(simulation); - simulation.viewForSelectedMoves>(); + simulation.view>(); simulation.registry.clear(); } void runModifyCritBoostEvent(Simulation&) {} void runBasePowerEvent(Simulation& simulation) { - simulation.addToEntities(); + simulation.addToEntities(); dex::KnockOff::onBasePower(simulation); - simulation.viewForSelectedMoves(); + simulation.view(); simulation.registry.clear(); } @@ -2075,10 +2031,6 @@ template void runAfterEachBoostEvent(Simulation&); void runAfterBoostEvent(Simulation&) {} void runModifyMove(Simulation& simulation) { - // internal::SelectForPokemonView<> selectedPokemon{ - // simulation, - // getMoveEventPokemonSelector()}; - dex::ChoiceScarf::onSourceModifyMove(simulation); dex::ChoiceSpecs::onSourceModifyMove(simulation); } @@ -2092,7 +2044,7 @@ void runModifyAtk(Simulation&) {} void runModifyDef(Simulation&) {} void runModifySpa(Simulation& simulation) { - simulation.addToEntities(); + simulation.addToEntities(); // Priority 1 dex::ChoiceSpecs::onModifySpa(simulation); @@ -2100,25 +2052,25 @@ void runModifySpa(Simulation& simulation) { // Priority 5 dex::Plus::onModifySpA(simulation); - simulation.viewForSelectedPokemon>(); + simulation.view>(); simulation.registry.clear(); } void runModifySpd(Simulation& simulation) { - simulation.addToEntities(); + simulation.addToEntities(); dex::AssaultVest::onModifySpd(simulation); - simulation.viewForSelectedPokemon>(); + simulation.view>(); simulation.registry.clear(); } void runModifySpe(Simulation& simulation) { - simulation.addToEntities(); + simulation.addToEntities(); dex::ChoiceScarf::onModifySpe(simulation); - simulation.viewForSelectedPokemon>(); + simulation.view>(); simulation.registry.clear(); dex::Paralysis::onModifySpe(simulation); @@ -2165,15 +2117,13 @@ void removeHitCountFromFaintedTargets(types::handle moveHandle, CurrentActionTar template void runMoveHitCheck(Simulation& simulation) { - simulation.addToEntities(); - - internal::SelectForCurrentActionMoveView selectedMoves{simulation}; - if (selectedMoves.hasNoneSelected()) { + if (simulation.registry.view().empty()) { return; } + simulation.addToEntities(); + Function(simulation); - selectedMoves.deselect(); simulation.view>(); simulation.registry.clear(); @@ -2199,14 +2149,14 @@ void setEffectTarget(types::handle handle, TargetEntityHolder target) { } void runMoveEffects(Simulation& simulation) { - internal::SelectForCurrentActionMoveView selectedMoves{simulation}; - if (selectedMoves.hasNoneSelected()) { + internal::EntityFilter moveFilter{simulation}; + if (moveFilter.hasNoneSelected()) { return; } - simulation.viewForSelectedMoves(); - simulation.viewForSelectedMoves, Tags>(); - simulation.viewForSelectedMoves, Tags>(); + moveFilter.view(); + moveFilter.view, Tags>(); + moveFilter.view, Tags>(); tryBoost(simulation); trySetStatus(simulation); @@ -2245,17 +2195,15 @@ void removeFaintedSecondaryEffectTarget( // exists that has a random chance to add a side or field affect regardless of the target's HP, then this function will // need to be reworked. void removeFaintedSecondaryEffectTargets(Simulation& simulation) { - internal::SelectForCurrentActionMoveView selectedMoves{simulation}; - if (selectedMoves.hasNoneSelected()) { + internal::EntityFilter moveFilter{simulation}; + if (moveFilter.hasNoneSelected()) { return; } - simulation.viewForSelectedMoves< - removeFaintedSecondaryEffectTarget, - Tags>(simulation.simulateTurnOptions); - simulation.viewForSelectedMoves< - removeFaintedSecondaryEffectTarget, - Tags>(simulation.simulateTurnOptions); + moveFilter.view, Tags>( + simulation.simulateTurnOptions); + moveFilter.view, Tags>( + simulation.simulateTurnOptions); } // TODO(aed3): When adding damage source, change this to accept the move's handle and CurrentActionSource to pass to @@ -2281,7 +2229,7 @@ void setMoveHitCount(Simulation& simulation) { } void applyDamage(Simulation& simulation) { - simulation.viewForSelectedMoves(); + simulation.view(); auto view = simulation.registry.view(entt::exclude); simulation.registry.insert(view.begin(), view.end()); @@ -2326,11 +2274,6 @@ void moveHitLoop(Simulation& simulation) { while (!simulation.registry.view().empty()) { POKESIM_REQUIRE(iterations <= MoveHitLimits::MAX, "More hits were ran more than possible."); - internal::SelectForCurrentActionMoveView selectedMoves{simulation}; - POKESIM_REQUIRE( - !selectedMoves.hasNoneSelected(), - "HitCount should only be present on active moves, meaning this loop should only be entered if there are moves to " - "select."); calc_damage::run(simulation); // 1. call to this.battle.getDamage runDamageEvent(simulation); @@ -2368,6 +2311,10 @@ void runMoveHitChecks(Simulation& simulation) { namespace pokesim::simulate_turn { namespace { +auto getBattleFilter(Simulation& simulation) { + return pokesim::internal::EntityFilter{simulation}; +} + void addTargetAllyToTargets(types::registry& registry, const Battle& battle) { const Sides& sides = registry.get(battle.val); const TargetSlotName& targetSlotName = registry.get(registry.get(battle.val).val); @@ -2419,6 +2366,7 @@ void getMoveTargets(Simulation& simulation) { simulation .view>(); } + simulation.view, entt::exclude_t>(); simulation.view< createActionMoveForTargets, @@ -2445,7 +2393,7 @@ void removeActionBySource(types::handle sourceHandle, Battle battle) { } void runMoveAction(Simulation& simulation) { - simulation.viewForSelectedBattles>(); + getBattleFilter(simulation).view>(); simulation.view< removeActionBySource, @@ -2455,11 +2403,13 @@ void runMoveAction(Simulation& simulation) { Tags, entt::exclude_t>(); - pokesim::internal::SelectForBattleView selectedBattle{simulation}; - if (selectedBattle.hasNoneSelected()) return; + pokesim::internal::EntityFilter battleFilter{simulation}; + if (battleFilter.hasNoneSelected()) { + return; + } - simulation.viewForSelectedBattles(simulation); - simulation.viewForSelectedBattles(simulation.pokedex()); + battleFilter.view(simulation); + battleFilter.view(simulation.pokedex()); runBeforeMove(simulation); @@ -2470,10 +2420,12 @@ void runMoveAction(Simulation& simulation) { } void runResidualAction(Simulation& simulation) { - pokesim::internal::SelectForBattleView selectedBattle{simulation}; - if (selectedBattle.hasNoneSelected()) return; + pokesim::internal::EntityFilter battleFilter{simulation}; + if (battleFilter.hasNoneSelected()) { + return; + } - simulation.viewForSelectedBattles>(); + battleFilter.view>(); simulation.registry.clear(); runResidual(simulation); @@ -2509,6 +2461,11 @@ void checkWin(types::handle battleHandle, const Sides& sides) { } void faintPokemon(Simulation& simulation) { + auto battleFilter = getBattleFilter(simulation); + if (battleFilter.hasNoneSelected()) { + return; + } + using LoopLimits = Constants::ActivePokemon; types::activePokemonIndex iterations = LoopLimits::MIN; while (!simulation.registry.view().empty()) { @@ -2516,27 +2473,31 @@ void faintPokemon(Simulation& simulation) { iterations <= LoopLimits::MAX, "More Pokemon were queued to faint in at least one battle than possible."); - simulation.viewForSelectedBattles(); + battleFilter.view(); - pokesim::internal::SelectForPokemonView selectedPokemon{simulation}; + pokesim::internal::EntityFilter pokemonFilter{simulation}; POKESIM_REQUIRE( - !selectedPokemon.hasNoneSelected(), + !pokemonFilter.hasNoneSelected(), "This loop should only be run if setFainting had Pokemon to set as fainting."); runFaintEvent(simulation); runEndAbilityEvent(simulation); + + pokemonFilter.addToSelected(); runEndItemEvent(simulation); - simulation.viewForSelectedPokemon(); + simulation.registry.clear(); + + pokemonFilter.view(); simulation.addToEntities(); simulation.removeFromEntities(); simulation.removeFromEntities(); - simulation.viewForSelectedBattles(); + battleFilter.view(); iterations++; } - simulation.viewForSelectedBattles, entt::exclude_t>(); + battleFilter.view, entt::exclude_t>(); runAfterFaintEvent(simulation); } @@ -2552,7 +2513,7 @@ void runCurrentAction(Simulation& simulation) { // Switch requests updateAllStats(simulation); - simulation.viewForSelectedBattles>(); + getBattleFilter(simulation).view>(); simulation.registry.clear(); } @@ -2565,13 +2526,15 @@ void updateActivePokemonPostTurn(types::registry& registry, const pokesim::MoveS } void nextTurn(Simulation& simulation) { - simulation.viewForSelectedBattles(); + getBattleFilter(simulation).view(); - pokesim::internal::SelectForPokemonView selectedPokemon{ - simulation}; - if (!selectedPokemon.hasNoneSelected()) { - simulation.viewForSelectedPokemon(); + pokesim::internal::EntityFilter pokemonFilter{simulation}; + if (!pokemonFilter.hasNoneSelected()) { + pokemonFilter.view(); + + pokemonFilter.addToSelected(); runDisableMove(simulation); + simulation.registry.clear(); } } @@ -2586,35 +2549,33 @@ void simulateTurn(Simulation& simulation) { "Rebuild PokeSim with the flag POKESIM_ALL_DAMAGE_ALL_BRANCHES to enable this option combination."); #endif + auto battleFilter = getBattleFilter(simulation); + if (battleFilter.hasNoneSelected()) { + return; + } + if (!options.getApplyChangesToInputBattle()) { - simulation.addToEntities(); + simulation.addToEntities(); const auto entityMap = clone(simulation.registry, 1U); for (const auto& inputBattleMapping : entityMap) { simulation.registry.emplace(inputBattleMapping.first); + simulation.registry.remove(inputBattleMapping.first); } } - pokesim::internal::SelectForBattleView selectedBattles{ - simulation, - entt::exclude}; - pokesim::internal::SelectForSideView selectedSides{ - simulation, - entt::exclude}; - if (selectedBattles.hasNoneSelected() || selectedSides.hasNoneSelected()) return; - - simulation.viewForSelectedBattles(); + battleFilter.view(); updateAllStats(simulation); - simulation.viewForSelectedSides(); - simulation.removeFromEntities(); + simulation.view>(); + simulation.removeFromEntities(); - // simulation.viewForSelectedBattles, entt::exclude_t>(); - simulation.viewForSelectedBattles(); - simulation.viewForSelectedBattles, entt::exclude_t>(); + // battleFilter.view, entt::exclude_t>(); + battleFilter.view(); + battleFilter.view, entt::exclude_t>(); - simulation.addToEntities(); + simulation.addToEntities(); - simulation.viewForSelectedBattles(); + battleFilter.view(); using ActionsLimit = Constants::ActionQueueLength; types::actionQueueIndex actionsTaken = ActionsLimit::MIN; while (!simulation.registry.view().empty()) { @@ -2623,14 +2584,17 @@ void simulateTurn(Simulation& simulation) { "More actions in a turn were queued to be taken than in at least one battle than are possible."); runCurrentAction(simulation); - simulation.viewForSelectedBattles, entt::exclude_t>(); + battleFilter.view, entt::exclude_t>(); actionsTaken++; } nextTurn(simulation); - simulation.removeFromEntities(); - simulation.viewForSelectedBattles(); + simulation + .removeFromEntities(); + battleFilter.view(); + + simulation.addToEntities(); simulation.registry.clear(); } } // namespace @@ -2650,6 +2614,7 @@ void run(Simulation& simulation) { ////////////////// START OF src/SimulateTurn/RandomChance.cpp ////////////////// #include +#include namespace pokesim::internal { namespace { @@ -3269,6 +3234,7 @@ void resolveTeamDecision(types::registry& registry, const types::teamOrder& team battleActionQueue.val.push_back(actionHandle.entity()); } } // namespace + void resolveDecision(types::handle sideHandle, const SideDecision& sideDecision) { POKESIM_REQUIRE(sideDecision.sideId != PlayerSideId::NONE, "Decisions must be assigned to a player."); POKESIM_REQUIRE(!sideDecision.decisions.valueless_by_exception(), "Decisions must be non-empty."); @@ -3332,7 +3298,7 @@ void speedSort(types::handle handle, ActionQueue& actionQueue) { speedSortList.push_back({registry->get(entity), entity}); } - // TODO (aed3): Test how different sorting algorithms affect speed + // TODO(aed3): Test how different sorting algorithms affect speed std::sort(speedSortList.begin(), speedSortList.end(), [](const auto& pairA, const auto& pairB) { if (pairA.first.order != pairB.first.order) { return pairA.first.order < pairB.first.order; @@ -3496,44 +3462,39 @@ types::eventPossibilities countUniqueDamageRolls(types::handle moveHandle) { } void updateAllDamageRollProbabilities(Simulation& simulation) { - simulation.viewForSelectedMoves(); + simulation.view(); } void updatePartialProbabilities(Simulation& simulation) { - simulation.viewForSelectedMoves(); + simulation.view(); } } // namespace void cloneFromDamageRolls(Simulation& simulation, DamageRollKind damageRollKind) { - pokesim::internal::SelectForCurrentActionMoveView selectedMoves{simulation}; - if (selectedMoves.hasNoneSelected()) return; + pokesim::internal::EntityFilter moveFilter{simulation}; + moveFilter.applySelectionTags(); + if (moveFilter.hasNoneSelected()) return; bool forAllDamageRolls = damageRollKind & DamageRollKind::ALL_DAMAGE_ROLLS; bool forRequiredDamageRolls = simulation.simulateTurnOptions.getMakeBranchesOnRandomEvents() || forAllDamageRolls; - auto applyChoices = [](Simulation& sim) { sim.viewForSelectedMoves(); }; + auto applyChoices = [](Simulation& sim) { sim.view(); }; auto updateProbabilities = forAllDamageRolls ? updateAllDamageRollProbabilities : updatePartialProbabilities; - runRandomEventCount( + runRandomEventCount( simulation, countUniqueDamageRolls, applyChoices, updateProbabilities, forRequiredDamageRolls); - simulation.removeFromEntities(); + simulation.removeFromEntities(); + moveFilter.clearSelectionTags(); } void setIfMoveCrits(Simulation& simulation) { - pokesim::internal::SelectForCurrentActionMoveView selectedMoves{simulation}; - if (selectedMoves.hasNoneSelected()) return; - - runReciprocalRandomBinaryChance( - simulation, - [](Simulation& sim) { - sim.addToEntities(); - }); - - simulation.registry.clear(); + runReciprocalRandomBinaryChance(simulation, [](Simulation& sim) { + sim.addToEntities(); + }); } } // namespace pokesim::simulate_turn @@ -4243,7 +4204,7 @@ void Pokedex::loadForBattleInfo(const std::vector& battleInf namespace pokesim::dex { namespace { void knockOffOnBasePowerCheckRemovableItem( - types::registry& registry, CurrentActionSource source, CurrentActionTarget target) { + types::registry& registry, CurrentActionSource source, CurrentActionTarget target, EventModifier&) { if (registry.get(source.val).val > Constants::PokemonCurrentHpStat::MIN) { registry.emplace_or_replace(target.val); } @@ -4267,15 +4228,15 @@ void knockOffOnBasePower( void KnockOff::onBasePower(Simulation& simulation) { const auto modifier = simulation.pokedex().getStaticValue(); - simulation.viewForSelectedMoves>(); + simulation.view>(); checkIfCanRemoveItem(simulation); - simulation.viewForSelectedMoves>(modifier); + simulation.view>(modifier); simulation.registry.clear(); } void KnockOff::onAfterHit(Simulation& simulation) { - simulation.viewForSelectedMoves>(); + simulation.view>(); tryRemoveItem(simulation); simulation.registry.clear(); } @@ -4321,8 +4282,7 @@ void sourceModifyDamage( template struct FocusSashOnAfterModifyDamage { static void run(Simulation& simulation, types::damage hpToKeep) { - simulation.viewForSelectedPokemon>( - hpToKeep); + simulation.view>(hpToKeep); } static void modifyDamage( @@ -4334,6 +4294,10 @@ struct FocusSashOnAfterModifyDamage { types::registry& registry = *pokemonHandle.registry(); for (types::entity move : moves.val) { + if (!registry.all_of(move)) { + continue; + } + if constexpr (std::is_same_v) { Damage& damage = registry.get(move); if (damage.val < hp.val) { @@ -4362,7 +4326,9 @@ void lifeOrbOnAfterMove( bool onlyStatusMoves = true; types::registry& registry = *pokemonHandle.registry(); for (types::entity move : moves.val) { - onlyStatusMoves &= registry.all_of(move); + if (registry.all_of(move)) { + onlyStatusMoves &= registry.all_of(move); + } } if (!onlyStatusMoves) { @@ -4373,28 +4339,25 @@ void lifeOrbOnAfterMove( void AssaultVest::onModifySpd(Simulation& simulation) { const auto modifier = simulation.pokedex().getStaticValue(); - simulation.viewForSelectedPokemon, Tags>( - modifier, - 1U); + + simulation.view, Tags>(modifier, 1U); } void AssaultVest::onEnd(Simulation& simulation) { - simulation.addToEntities(); + simulation.addToEntities(); } void BrightPowder::onModifyAccuracy(Simulation& simulation) { const auto numerator = simulation.pokedex().getStaticValue(); const auto denominator = simulation.pokedex().getStaticValue(); - simulation.viewForSelectedPokemon, Tags>( - numerator, - denominator); + + simulation.view, Tags>(numerator, denominator); } void ChoiceScarf::onModifySpe(Simulation& simulation) { const auto modifier = simulation.pokedex().getStaticValue(); - simulation.viewForSelectedPokemon, Tags>( - modifier, - 1U); + + simulation.view, Tags>(modifier, 1U); } void ChoiceScarf::onSourceModifyMove(Simulation& simulation) { @@ -4403,14 +4366,13 @@ void ChoiceScarf::onSourceModifyMove(Simulation& simulation) { } void ChoiceScarf::onEnd(Simulation& simulation) { - simulation.addToEntities(); + simulation.addToEntities(); } void ChoiceSpecs::onModifySpa(Simulation& simulation) { const auto modifier = simulation.pokedex().getStaticValue(); - simulation.viewForSelectedPokemon, Tags>( - modifier, - 1U); + + simulation.view, Tags>(modifier, 1U); } void ChoiceSpecs::onSourceModifyMove(Simulation& simulation) { @@ -4419,11 +4381,12 @@ void ChoiceSpecs::onSourceModifyMove(Simulation& simulation) { } void ChoiceSpecs::onEnd(Simulation& simulation) { - simulation.addToEntities(); + simulation.addToEntities(); } void FocusSash::onAfterModifyDamage(Simulation& simulation) { const auto hpToKeep = simulation.pokedex().getStaticValue(); + simulation.addToEntities(); checkIfCanUseItem(simulation); @@ -4440,14 +4403,14 @@ void FocusSash::onDamage(Simulation& simulation) { void LifeOrb::onModifyDamage(Simulation& simulation) { const auto numerator = simulation.pokedex().getStaticValue(); const auto denominator = simulation.pokedex().getStaticValue(); - simulation.viewForSelectedPokemon, Tags>( - numerator, - denominator); + + simulation.view, Tags>(numerator, denominator); } void LifeOrb::onAfterMoveUsed(Simulation& simulation) { const auto divisor = simulation.pokedex().getStaticValue(); - simulation.viewForSelectedPokemon>(divisor); + + simulation.view>(divisor); } } // namespace pokesim::dex @@ -4506,21 +4469,24 @@ void choiceLockOnDisableMove( } // namespace void Burn::onSetDamageRollModifiers(Simulation& simulation) { - simulation - .viewForSelectedPokemon /*, entt::exclude */>(); + simulation.view /*, entt::exclude */>(); } void Burn::onResidual(Simulation& simulation) { const auto divisor = simulation.pokedex().getStaticValue(); - simulation.viewForSelectedPokemon>(divisor); + + simulation.view>(divisor); } void Paralysis::onModifySpe(Simulation& simulation) { const auto speedDivisor = simulation.pokedex().getStaticValue(); const auto speedDividend = simulation.pokedex().getStaticValue(); - simulation.viewForSelectedPokemon< + + simulation.view< paralysisOnModifySpeed, - Tags /*, entt::exclude_t*/>(speedDivisor, speedDividend); + Tags /*, entt::exclude_t*/>( + speedDivisor, + speedDividend); } void Paralysis::onBeforeMove(Simulation& simulation) { @@ -4532,23 +4498,26 @@ void Paralysis::onBeforeMove(Simulation& simulation) { pokesim::internal::randomBinaryChance( simulation, - [](Simulation& sim) { - sim.viewForSelectedPokemon>(); - }, + [](Simulation& sim) { sim.view>(); }, std::nullopt); simulation.view>(); - simulation.registry.clear(); + simulation.registry.clear(); } void ChoiceLock::onBeforeMove(Simulation& simulation) { - simulation.viewForSelectedPokemon, entt::exclude_t>(); - simulation.viewForSelectedPokemon(simulation.pokedex()); + simulation.view, entt::exclude_t>(); + simulation.view(simulation.pokedex()); } void ChoiceLock::onDisableMove(Simulation& simulation) { - simulation.viewForSelectedPokemon, entt::exclude_t>(); - simulation.viewForSelectedPokemon(simulation.pokedex()); - simulation.viewForSelectedPokemon(); + pokesim::internal::EntityFilter filter{simulation}; + if (filter.hasNoneSelected()) { + return; + } + + filter.view, entt::exclude_t>(); + filter.view(simulation.pokedex()); + filter.view(); } } // namespace pokesim::dex @@ -4596,13 +4565,13 @@ void Plus::onModifySpA(Simulation& simulation) { if (simulation.isBattleFormat(BattleFormat::SINGLES)) { return; } - simulation.viewForSelectedPokemon>(); + simulation.view>(); } void Static::onDamagingHit(Simulation& simulation) { const auto chanceOfStatic = simulation.pokedex().getStaticValue(); - simulation.viewForSelectedPokemon>(chanceOfStatic, simulation); + simulation.view>(chanceOfStatic, simulation); // TODO(aed3): This is now inefficient since the random chance will happen for move sources that cannot have their // status changed. @@ -4650,6 +4619,10 @@ types::entity InputSetup::entity() const { namespace pokesim::calc_damage { namespace { +auto getMoveFilter(Simulation& simulation) { + return pokesim::internal::EntityFilter{simulation}; +} + void clearRunVariables(Simulation& simulation) { simulation.registry.clear< tags::Crit, @@ -4696,10 +4669,6 @@ void setDefendingSide(types::handle moveHandle, Defender defender) { types::registry& registry = *moveHandle.registry(); PlayerSideId playerSide = registry.get(registry.get(defender.val).val).val; switch (playerSide) { - case PlayerSideId::NONE: { - POKESIM_REQUIRE_FAIL("Player side wasn't set properly."); - break; - } case PlayerSideId::P1: { moveHandle.emplace(); break; @@ -4708,6 +4677,10 @@ void setDefendingSide(types::handle moveHandle, Defender defender) { moveHandle.emplace(); break; } + default: { + POKESIM_REQUIRE_FAIL("Player side wasn't set properly."); + break; + } } } @@ -4728,6 +4701,7 @@ void modifyDamage(Damage& damage, const DamageRollModifiers& modifiers, const Po if (modifiers.burn) { const auto multiplier = pokedex.getStaticValue(); + damage.val = (types::damage)fixedPointMultiply(damage.val, multiplier); } @@ -4830,7 +4804,7 @@ void setIgnoreDefendingBoostIfPositive(types::handle moveHandle, Defender defend void calculateBaseDamage( types::handle moveHandle, Power power, AttackingLevel level, AttackingStat attack, DefendingStat defense) { types::damage damage = computeBaseDamage(power.val, level.val, attack.val, defense.val); - moveHandle.emplace_or_replace(damage); + moveHandle.emplace(damage); } void applyUsesUntilKo(types::handle moveHandle, const DamageRolls& damageRolls, Defender defender) { @@ -4861,8 +4835,8 @@ void applySideDamageRollOptions(Simulation& simulation) { isSimulateTurn || isCalculateDamage || isAnalyzeEffect, "Using a type that isn't a valid simulation tag."); - pokesim::internal::SelectForCurrentActionMoveView selectedMoves{simulation}; - if (selectedMoves.hasNoneSelected()) { + pokesim::internal::EntityFilter moveFilter{simulation}; + if (moveFilter.hasNoneSelected()) { return; } @@ -4887,55 +4861,57 @@ void applySideDamageRollOptions(Simulation& simulation) { } if (damageRollOptions.sidesMatch()) { + moveFilter.template addToSelected(); + simulation.removeFromEntities(); if constexpr (onlyPassDamageRoll) { ApplyDamageRollKind(simulation, damageRollOptions.getP1()); } else { ApplyDamageRollKind(simulation, damageRollOptions.getP1(), calculateUpToFoeHp, noKoChanceCalculation); } + simulation.registry.clear(); } else { - simulation.viewForSelectedMoves(); - pokesim::internal::SelectForCurrentActionMoveView p1DefendingMoves{simulation}; - if (!p1DefendingMoves.hasNoneSelected()) { - if constexpr (onlyPassDamageRoll) { - ApplyDamageRollKind(simulation, damageRollOptions.getP1()); - } - else { - ApplyDamageRollKind(simulation, damageRollOptions.getP1(), calculateUpToFoeHp, noKoChanceCalculation); - } - } - p1DefendingMoves.deselect(); + moveFilter.template view(); - pokesim::internal::SelectForCurrentActionMoveView p2DefendingMoves{simulation}; - if (!p2DefendingMoves.hasNoneSelected()) { - if constexpr (onlyPassDamageRoll) { - ApplyDamageRollKind(simulation, damageRollOptions.getP2()); - } - else { - ApplyDamageRollKind(simulation, damageRollOptions.getP2(), calculateUpToFoeHp, noKoChanceCalculation); - } + simulation.addToEntities(); + simulation.removeFromEntities(); + if constexpr (onlyPassDamageRoll) { + ApplyDamageRollKind(simulation, damageRollOptions.getP1()); + } + else { + ApplyDamageRollKind(simulation, damageRollOptions.getP1(), calculateUpToFoeHp, noKoChanceCalculation); } + simulation.registry.clear(); - simulation.registry.clear(); + simulation.addToEntities(); + simulation.removeFromEntities(); + if constexpr (onlyPassDamageRoll) { + ApplyDamageRollKind(simulation, damageRollOptions.getP2()); + } + else { + ApplyDamageRollKind(simulation, damageRollOptions.getP2(), calculateUpToFoeHp, noKoChanceCalculation); + } + simulation.registry.clear(); } } template void setIfMoveCrits(Simulation& simulation, DamageRollKind damageRollKind) { if (damageRollKind & DamageRollKind::GUARANTEED_CRIT_CHANCE) { - simulation.addToEntities(); + simulation.addToEntities(); return; } if constexpr (std::is_same_v) { - simulation.addToEntities(); + simulation.addToEntities(); runModifyCritBoostEvent(simulation); - simulation.viewForSelectedMoves( + simulation.view( simulation.pokedex().getStaticValue()); simulation.registry.clear(); simulate_turn::setIfMoveCrits(simulation); + simulation.registry.clear(); } } @@ -4949,37 +4925,42 @@ void applyDamageRollsAndModifiers( damageRollKind != DamageRollKind::GUARANTEED_CRIT_CHANCE, "Must pick a damage roll kind to go along with crits."); - simulation.addToEntities(); + pokesim::internal::EntityFilter moveFilter{simulation}; + if (moveFilter.hasNoneSelected()) { + return; + } + + simulation.addToEntities(); if (damageRollKind & DamageRollKind::ALL_DAMAGE_ROLLS) { - simulation.viewForSelectedMoves(simulation.pokedex()); + moveFilter.view(simulation.pokedex()); } else { if (damageRollKind & DamageRollKind::MAX_DAMAGE) { - simulation.viewForSelectedMoves(simulation.pokedex()); + moveFilter.view(simulation.pokedex()); } if (damageRollKind & DamageRollKind::AVERAGE_DAMAGE) { - simulation.viewForSelectedMoves(simulation.pokedex()); + moveFilter.view(simulation.pokedex()); } if (damageRollKind & DamageRollKind::MIN_DAMAGE) { - simulation.viewForSelectedMoves(simulation.pokedex()); + moveFilter.view(simulation.pokedex()); } } if constexpr (std::is_same_v) { if (calculateUpToFoeHp) { - simulation.viewForSelectedMoves(); + moveFilter.view(); } simulate_turn::cloneFromDamageRolls(simulation, damageRollKind); } else { - simulation.viewForSelectedMoves(simulation.pokedex()); + moveFilter.view(simulation.pokedex()); if (calculateUpToFoeHp) { - simulation.viewForSelectedMoves(); + moveFilter.view(); } if (!noKoChanceCalculation && damageRollKind & DamageRollKind::ALL_DAMAGE_ROLLS) { - simulation.viewForSelectedMoves>(); + moveFilter.view>(); } } } @@ -5013,68 +4994,66 @@ void resetEffectiveAndDefendingStat(types::registry& registry, Defender defender template void setUnboostedStat(Simulation& simulation) { static constexpr bool forAttacker = std::is_same_v; + auto moveFilter = getMoveFilter(simulation); + if constexpr (forAttacker) { - simulation.viewForSelectedMoves, Tags>(); + moveFilter.view, Tags>(); } else { - simulation.viewForSelectedMoves, Tags>(); + moveFilter.view, Tags>(); } - internal::SelectForPokemonView selectedPokemon{simulation}; - if (selectedPokemon.hasNoneSelected()) { + if (simulation.registry.view().empty()) { return; } if constexpr (std::is_same_v) { - simulation.viewForSelectedPokemon(); - runModifyAtk(simulation); + simulation.addToEntities(); + updateAtk(simulation, true); } else if constexpr ( std::is_same_v || std::is_same_v) { - simulation.viewForSelectedPokemon(); - runModifyDef(simulation); + simulation.addToEntities(); + updateDef(simulation, true); } else if constexpr (std::is_same_v) { - simulation.viewForSelectedPokemon(); - runModifySpa(simulation); + simulation.addToEntities(); + updateSpa(simulation, true); } else if constexpr (std::is_same_v) { - simulation.viewForSelectedPokemon(); - runModifySpd(simulation); + simulation.addToEntities(); + updateSpd(simulation, true); } else { static_assert("No other stat is used as the attacking or defending stat."); } if constexpr (forAttacker) { - simulation - .viewForSelectedMoves, Tags>(); + moveFilter.view, Tags>(); } else { - simulation - .viewForSelectedMoves, Tags>(); + moveFilter.view, Tags>(); } simulation.registry.clear(); } void setDamageFormulaVariables(Simulation& simulation) { - simulation.viewForSelectedMoves(); + auto moveFilter = getMoveFilter(simulation); + moveFilter.view(); - simulation.viewForSelectedMoves, Tags>(); - simulation.viewForSelectedMoves, Tags>(); - simulation.viewForSelectedMoves, Tags>(); - simulation.viewForSelectedMoves, Tags>(); + moveFilter.view, Tags>(); + moveFilter.view, Tags>(); + moveFilter.view, Tags>(); + moveFilter.view, Tags>(); - simulation.viewForSelectedMoves, Tags>(); - simulation.viewForSelectedMoves, Tags>(); - simulation.viewForSelectedMoves, Tags>(); - simulation.viewForSelectedMoves, Tags>(); - // simulation.viewForSelectedMoves, Tags>(); + moveFilter.view, Tags>(); + moveFilter.view, Tags>(); + moveFilter.view, Tags>(); + moveFilter.view, Tags>(); + // moveFilter.view, Tags>(); - // simulation.viewForSelectedPokemon>(); + // moveFilter.view>(); setUnboostedStat(simulation); setUnboostedStat(simulation); @@ -5084,15 +5063,16 @@ void setDamageFormulaVariables(Simulation& simulation) { } void setDamageRollModifiers(Simulation& simulation) { - simulation.viewForSelectedMoves(); - simulation.viewForSelectedMoves(simulation.pokedex()); + auto moveFilter = getMoveFilter(simulation); + moveFilter.view(); + moveFilter.view(simulation.pokedex()); dex::Burn::onSetDamageRollModifiers(simulation); runModifyDamageEvent(simulation); } void calcDamage(Simulation& simulation) { - pokesim::internal::SelectForCurrentActionMoveView<> selectedMoves{simulation, entt::exclude}; - if (selectedMoves.hasNoneSelected()) { + auto moveFilter = getMoveFilter(simulation); + if (moveFilter.hasNoneSelected()) { return; } @@ -5107,11 +5087,11 @@ void calcDamage(Simulation& simulation) { runBasePowerEvent(simulation); setDamageFormulaVariables(simulation); - simulation.viewForSelectedMoves(); - simulation.viewForSelectedMoves>( + moveFilter.view(); + moveFilter.view>( simulation.pokedex().getStaticValue()); - simulation.addToEntities(); + simulation.addToEntities(); setDamageRollModifiers(simulation); applySideDamageRollOptions>(simulation); @@ -5476,7 +5456,7 @@ void removeItemTags(types::handle handle, ItemName item) { template void removeItemComponents(Simulation& simulation) { - simulation.viewForSelectedPokemon(); + simulation.view>(); simulation.removeFromEntities(); simulation.registry.clear(); } @@ -5588,11 +5568,6 @@ void checkIfCanUseItem(Simulation& simulation) { } void useItem(Simulation& simulation) { - pokesim::internal::SelectForPokemonView selectedPokemon{simulation}; - if (selectedPokemon.hasNoneSelected()) { - return; - } - runAfterUseItemEvent(simulation); removeItemComponents(simulation); } @@ -5608,12 +5583,10 @@ void checkIfCanRemoveItem(Simulation& simulation) { } void removeItem(Simulation& simulation) { - pokesim::internal::SelectForPokemonView selectedPokemon{simulation}; - if (selectedPokemon.hasNoneSelected()) { - return; - } - + simulation.addToEntities(); runEndItemEvent(simulation); + simulation.registry.clear(); + removeItemComponents(simulation); } @@ -5741,73 +5714,83 @@ void tryBoost(Simulation& simulation) { } void updateAllStats(Simulation& simulation) { - updateAtk(simulation); - updateDef(simulation); - updateSpa(simulation); - updateSpd(simulation); - updateSpe(simulation); + updateAtk(simulation, false); + updateDef(simulation, false); + updateSpa(simulation, false); + updateSpd(simulation, false); + updateSpe(simulation, false); } -void updateAtk(Simulation& simulation) { - internal::SelectForPokemonView selectedAtkUpdateRequired{simulation}; - if (selectedAtkUpdateRequired.hasNoneSelected()) return; +void updateAtk(Simulation& simulation, bool ignoreBoosts) { + internal::EntityFilter filter{simulation}; + if (filter.hasNoneSelected()) return; - simulation.viewForSelectedPokemon(); + filter.view(); - simulation.viewForSelectedPokemon>(); + if (!ignoreBoosts) { + filter.view>(); + } runModifyAtk(simulation); - simulation.registry.clear(); + filter.clearSelectionTags(); } -void updateDef(Simulation& simulation) { - internal::SelectForPokemonView selectedDefUpdateRequired{simulation}; - if (selectedDefUpdateRequired.hasNoneSelected()) return; +void updateDef(Simulation& simulation, bool ignoreBoosts) { + internal::EntityFilter filter{simulation}; + if (filter.hasNoneSelected()) return; - simulation.viewForSelectedPokemon(); + filter.view(); - simulation.viewForSelectedPokemon>(); + if (!ignoreBoosts) { + filter.view>(); + } runModifyDef(simulation); - simulation.registry.clear(); + filter.clearSelectionTags(); } -void updateSpa(Simulation& simulation) { - internal::SelectForPokemonView selectedSpaUpdateRequired{simulation}; - if (selectedSpaUpdateRequired.hasNoneSelected()) return; +void updateSpa(Simulation& simulation, bool ignoreBoosts) { + internal::EntityFilter filter{simulation}; + if (filter.hasNoneSelected()) return; - simulation.viewForSelectedPokemon(); + filter.view(); - simulation.viewForSelectedPokemon>(); + if (!ignoreBoosts) { + filter.view>(); + } runModifySpa(simulation); - simulation.registry.clear(); + filter.clearSelectionTags(); } -void updateSpd(Simulation& simulation) { - internal::SelectForPokemonView selectedSpdUpdateRequired{simulation}; - if (selectedSpdUpdateRequired.hasNoneSelected()) return; +void updateSpd(Simulation& simulation, bool ignoreBoosts) { + internal::EntityFilter filter{simulation}; + if (filter.hasNoneSelected()) return; - simulation.viewForSelectedPokemon(); + filter.view(); - simulation.viewForSelectedPokemon>(); + if (!ignoreBoosts) { + filter.view>(); + } runModifySpd(simulation); - simulation.registry.clear(); + filter.clearSelectionTags(); } -void updateSpe(Simulation& simulation) { - internal::SelectForPokemonView selectedSpeUpdateRequired{simulation}; - if (selectedSpeUpdateRequired.hasNoneSelected()) return; +void updateSpe(Simulation& simulation, bool ignoreBoosts) { + internal::EntityFilter filter{simulation}; + if (filter.hasNoneSelected()) return; - simulation.viewForSelectedPokemon(); + filter.view(); - simulation.viewForSelectedPokemon>(); + if (!ignoreBoosts) { + filter.view>(); + } runModifySpe(simulation); // trick room - simulation.viewForSelectedPokemon>(); - simulation.registry.clear(); + filter.view>(); + filter.clearSelectionTags(); } } // namespace pokesim @@ -5969,7 +5952,7 @@ void clearCurrentAction(Simulation& simulation) { registry.destroy(failedActionMoves.begin(), failedActionMoves.end()); registry.destroy(currentActions.begin(), currentActions.end()); - auto battles = simulation.selectedBattleEntities(); + auto battles = simulation.battleEntities(); registry.remove< action::tags::Item, ItemName, @@ -7046,15 +7029,14 @@ void clearRunVariables(Simulation& simulation) { } void analyzeEffect(Simulation& simulation) { - pokesim::internal::SelectForPokemonView selectedPokemon(simulation); - pokesim::internal::SelectForBattleView selectedBattle(simulation); + pokesim::internal::EntityFilter battleFilter(simulation); - if (selectedPokemon.hasNoneSelected() || selectedBattle.hasNoneSelected()) { + if (battleFilter.hasNoneSelected()) { return; } simulation.view(simulation.pokedex()); - simulation.viewForSelectedBattles(); + battleFilter.view(); if (!simulation.analyzeEffectOptions.getReconsiderActiveEffects()) { ignoreBattlesWithEffectActive(simulation); diff --git a/extras/PokeSim.hpp b/extras/PokeSim.hpp index 7267240f..de47dd94 100644 --- a/extras/PokeSim.hpp +++ b/extras/PokeSim.hpp @@ -166,6 +166,7 @@ * src/Components/Tags/MoveTags.hpp * src/Components/Tags/NatureTags.hpp * src/Components/Tags/PokemonTags.hpp + * src/Components/Tags/RunEventTags.hpp * src/Components/Tags/Selection.hpp * src/Components/Tags/SimulationTags.hpp * src/Components/Tags/StatusTags.hpp @@ -197,7 +198,6 @@ * src/Simulation/Formulas.hpp * src/Utilities/Tags.hpp * src/Utilities/RegistryLoop.hpp - * src/Simulation/RegistryContainer.hpp * src/Simulation/Simulation.hpp * src/Utilities/DebugChecks.hpp * src/Simulation/SimulationSetupDebugChecks.hpp @@ -236,10 +236,10 @@ * src/Pokedex/Moves/Thunderbolt.hpp * src/Pokedex/Moves/WillOWisp.hpp * src/Simulation/RunEvent.hpp - * src/Utilities/SelectForView.hpp * src/Battle/ManageBattleState.hpp * src/SimulateTurn/RandomChance.hpp * src/Simulation/MoveHitSteps.hpp + * src/Utilities/EntityFilter.hpp * src/Battle/Side/ManageSideState.hpp * src/SimulateTurn/ManageActionQueue.hpp * src/SimulateTurn/SimulateTurnDebugChecks.hpp @@ -17219,6 +17219,14 @@ struct Constants { static constexpr std::uint16_t DEFAULT = 1U; }; + struct PokemonEffectiveSpeStat { + static constexpr std::uint16_t MAX = 65535U; + // A Pokemon with a speed stat of 7 or less (i.e. level 1 Shuckle) that is paralyzed with -6 speed boosts can have + // no speed. + static constexpr std::uint16_t MIN = 0U; + static constexpr std::uint16_t DEFAULT = 1U; + }; + struct PokemonEv { static constexpr std::uint8_t MAX = 255U; static constexpr std::uint8_t MIN = 0U; @@ -18442,7 +18450,7 @@ struct MovePair { }; struct SkippedInputCount { - types::eventPossibilities val = 0U; + types::entityIndex val = 0U; }; namespace tags { @@ -19839,15 +19847,22 @@ struct CanSetStatus {}; ////////////////// END OF src/Components/Tags/PokemonTags.hpp ////////////////// -////////////////// START OF src/Components/Tags/Selection.hpp ////////////////// +//////////////// START OF src/Components/Tags/RunEventTags.hpp ///////////////// namespace pokesim::tags { -struct SelectedForViewBattle {}; -struct SelectedForViewSide {}; -struct SelectedForViewPokemon {}; -struct SelectedForViewMove {}; +struct DisableMove {}; +struct EndItem {}; } // namespace pokesim::tags +///////////////// END OF src/Components/Tags/RunEventTags.hpp ////////////////// + +////////////////// START OF src/Components/Tags/Selection.hpp ////////////////// + +namespace pokesim::internal::tags { +struct CloneFromDamageRolls {}; +struct ApplySideDamageRollOptions {}; +} // namespace pokesim::internal::tags + /////////////////// END OF src/Components/Tags/Selection.hpp /////////////////// /////////////// START OF src/Components/Tags/SimulationTags.hpp //////////////// @@ -22410,336 +22425,6 @@ struct RegistryLoop< //////////////////// END OF src/Utilities/RegistryLoop.hpp ///////////////////// -//////////////// START OF src/Simulation/RegistryContainer.hpp ///////////////// - -namespace pokesim::internal { -class RegistryContainer { - public: - using SelectionFunction = entt::delegate; - - private: - template - friend struct SelectForView; - - using SelectionFunctionList = internal::maxSizedVector; - SelectionFunctionList battleSelection{}; - SelectionFunctionList sideSelection{}; - SelectionFunctionList pokemonSelection{}; - SelectionFunctionList moveSelection{}; - - template - SelectionFunctionList& selectedFunctions() { - if constexpr (std::is_same_v) { - return battleSelection; - } - else if constexpr (std::is_same_v) { - return sideSelection; - } - else if constexpr (std::is_same_v) { - return pokemonSelection; - } - else { - return moveSelection; - } - } - - template - const SelectionFunctionList& selectedFunctions() const { - if constexpr (std::is_same_v) { - return battleSelection; - } - else if constexpr (std::is_same_v) { - return sideSelection; - } - else if constexpr (std::is_same_v) { - return pokemonSelection; - } - else { - return moveSelection; - } - } - - template - std::size_t select( - GetNewSelection getNewSelection, GetUnmatchedSelection getUnmatchedSelection, SelectionFunction selectionFunction, - bool isEmptySelection = false) { - auto list = getNewSelection(registry); - if (list.empty()) { - return 0U; - } - - bool narrowSelection = hasActiveSelection(); - std::size_t finalSelectionSize = 0U; - - if (narrowSelection && isEmptySelection) { - selectedFunctions().push_back(selectionFunction); - return registry.view().size(); - } - if (narrowSelection) { - auto unmatchedSelections = getUnmatchedSelection(registry); - std::size_t totalSelected = registry.view().size(); - std::size_t unmatchedSelectionSize = unmatchedSelections.size(); - if (unmatchedSelectionSize == totalSelected) { - return 0U; - } - - registry.remove(unmatchedSelections.begin(), unmatchedSelections.end()); - - POKESIM_REQUIRE( - unmatchedSelectionSize < totalSelected, - "The number of elements removed from the active selection must be less than the number of elements selected."); - finalSelectionSize = totalSelected - unmatchedSelectionSize; - } - else { - registry.clear(); - registry.insert(list.begin(), list.end()); - finalSelectionSize = list.size(); - } - - selectedFunctions().push_back(selectionFunction); - - return finalSelectionSize; - } - - template - std::size_t select(entt::exclude_t exclude) { - auto getNewSelection = [&exclude](types::registry& reg) { - auto view = reg.view(exclude); - return types::entityVector{view.begin(), view.end()}; - }; - auto getUnmatchedSelection = [](types::registry& reg) { - auto view = reg.view(entt::exclude); - return types::entityVector{view.begin(), view.end()}; - }; - SelectionFunction selectionFunction{[](const void*, const types::registry& reg) { - auto view = reg.view(entt::exclude); - return types::entityVector{view.begin(), view.end()}; - }}; - - return select( - getNewSelection, - getUnmatchedSelection, - selectionFunction, - sizeof...(ComponentsToSelect) == 0U); - } - - template - std::size_t select(SelectionFunction selectionFunction) { - auto getUnmatchedSelections = [&selectionFunction](const types::registry& reg) -> types::entityVector { - auto upcomingSelection = selectionFunction(reg); - auto currentSelection = reg.view(); - auto end = - std::remove_if(upcomingSelection.begin(), upcomingSelection.end(), [¤tSelection](types::entity entity) { - return !currentSelection.contains(entity); - }); - return {upcomingSelection.begin(), end}; - }; - - return select(selectionFunction, getUnmatchedSelections, selectionFunction); - } - - template - void deselect() { - POKESIM_REQUIRE(hasActiveSelection(), "Selections must be present to deselect."); - - registry.clear(); - SelectionFunctionList& functions = selectedFunctions(); - functions.pop_back(); - - if (functions.empty()) { - return; - } - - types::entityVector filteredEntityList = functions[0](registry); - auto end = filteredEntityList.end(); - for (std::size_t i = 1U; i < functions.size(); i++) { - types::entityVector previouslySelected = functions[i](registry); - end = std::remove_if(filteredEntityList.begin(), end, [&previouslySelected](types::entity entity) { - return std::find(previouslySelected.begin(), previouslySelected.end(), entity) == previouslySelected.end(); - }); - } - - registry.insert(filteredEntityList.begin(), end); - } - - protected: - template - bool hasActiveSelection() const { - return !selectedFunctions().empty(); - } - - private: - template - struct ForSelected; - - template < - typename Selected, typename Required, auto Function, typename ExcludeContainer, typename IncludeContainer, - typename... ExtraTags> - struct ForSelected, ExcludeContainer, IncludeContainer> { - template - static void view(RegistryContainer* container, const PassedInArgs&... passedInArgs) { - if (container->hasActiveSelection()) { - container->view, ExcludeContainer, IncludeContainer>( - passedInArgs...); - } - else { - container->view, ExcludeContainer, IncludeContainer>(passedInArgs...); - } - } - - template - static void group(RegistryContainer* container, const PassedInArgs&... passedInArgs) { - if (container->hasActiveSelection()) { - container->view, ExcludeContainer, IncludeContainer>(passedInArgs...); - } - else { - container->group, ExcludeContainer, IncludeContainer>(passedInArgs...); - } - } - }; - - public: - template < - auto Function, typename TagContainer = Tags<>, typename ExcludeContainer = entt::exclude_t<>, - typename IncludeContainer = entt::get_t<>, typename... PassedInArgs> - void viewForSelectedBattles(const PassedInArgs&... passedInArgs) { - ForSelected< - pokesim::tags::SelectedForViewBattle, - pokesim::tags::Battle, - Function, - TagContainer, - ExcludeContainer, - IncludeContainer>::view(this, passedInArgs...); - } - - template < - auto Function, typename TagContainer = Tags<>, typename ExcludeContainer = entt::exclude_t<>, - typename IncludeContainer = entt::get_t<>, typename... PassedInArgs> - void groupForSelectedBattles(const PassedInArgs&... passedInArgs) { - ForSelected< - pokesim::tags::SelectedForViewBattle, - pokesim::tags::Battle, - Function, - TagContainer, - ExcludeContainer, - IncludeContainer>::group(this, passedInArgs...); - } - - template < - auto Function, typename TagContainer = Tags<>, typename ExcludeContainer = entt::exclude_t<>, - typename IncludeContainer = entt::get_t<>, typename... PassedInArgs> - void viewForSelectedSides(const PassedInArgs&... passedInArgs) { - ForSelected< - pokesim::tags::SelectedForViewSide, - pokesim::tags::Side, - Function, - TagContainer, - ExcludeContainer, - IncludeContainer>::view(this, passedInArgs...); - } - - template < - auto Function, typename TagContainer = Tags<>, typename ExcludeContainer = entt::exclude_t<>, - typename IncludeContainer = entt::get_t<>, typename... PassedInArgs> - void groupForSelectedSides(const PassedInArgs&... passedInArgs) { - ForSelected< - pokesim::tags::SelectedForViewSide, - pokesim::tags::Side, - Function, - TagContainer, - ExcludeContainer, - IncludeContainer>::group(this, passedInArgs...); - } - - template < - auto Function, typename TagContainer = Tags<>, typename ExcludeContainer = entt::exclude_t<>, - typename IncludeContainer = entt::get_t<>, typename... PassedInArgs> - void viewForSelectedPokemon(const PassedInArgs&... passedInArgs) { - ForSelected< - pokesim::tags::SelectedForViewPokemon, - pokesim::tags::Pokemon, - Function, - TagContainer, - ExcludeContainer, - IncludeContainer>::view(this, passedInArgs...); - } - - template < - auto Function, typename TagContainer = Tags<>, typename ExcludeContainer = entt::exclude_t<>, - typename IncludeContainer = entt::get_t<>, typename... PassedInArgs> - void groupForSelectedPokemon(const PassedInArgs&... passedInArgs) { - ForSelected< - pokesim::tags::SelectedForViewPokemon, - pokesim::tags::Pokemon, - Function, - TagContainer, - ExcludeContainer, - IncludeContainer>::group(this, passedInArgs...); - } - - template < - auto Function, typename TagContainer = Tags<>, typename ExcludeContainer = entt::exclude_t<>, - typename IncludeContainer = entt::get_t<>, typename... PassedInArgs> - void viewForSelectedMoves(const PassedInArgs&... passedInArgs) { - ForSelected< - pokesim::tags::SelectedForViewMove, - pokesim::tags::CurrentActionMove, - Function, - TagContainer, - ExcludeContainer, - IncludeContainer>::view(this, passedInArgs...); - } - - template < - auto Function, typename TagContainer = Tags<>, typename ExcludeContainer = entt::exclude_t<>, - typename IncludeContainer = entt::get_t<>, typename... PassedInArgs> - void groupForSelectedMoves(const PassedInArgs&... passedInArgs) { - ForSelected< - pokesim::tags::SelectedForViewMove, - pokesim::tags::CurrentActionMove, - Function, - TagContainer, - ExcludeContainer, - IncludeContainer>::group(this, passedInArgs...); - } - - template < - auto Function, typename TagContainer = Tags<>, typename ExcludeContainer = entt::exclude_t<>, - typename IncludeContainer = entt::get_t<>, typename... PassedInArgs> - auto view(const PassedInArgs&... passedInArgs) { - return internal::RegistryLoop::view( - registry, - passedInArgs...); - } - - template < - auto Function, typename TagContainer = Tags<>, typename ExcludeContainer = entt::exclude_t<>, - typename IncludeContainer = entt::get_t<>, typename... PassedInArgs> - auto group(const PassedInArgs&... passedInArgs) { - return internal::RegistryLoop::group( - registry, - passedInArgs...); - } - - public: - types::registry registry{}; - - template - void addToEntities(const Args&... args) { - auto view = registry.view(); - registry.insert(view.begin(), view.end(), args...); - } - - template - void removeFromEntities(entt::exclude_t exclude = entt::exclude_t{}) { - auto view = registry.view(exclude); - registry.remove(view.begin(), view.end()); - } -}; -} // namespace pokesim::internal - -///////////////// END OF src/Simulation/RegistryContainer.hpp ////////////////// - //////////////////// START OF src/Simulation/Simulation.hpp //////////////////// namespace pokesim { @@ -22767,7 +22452,7 @@ struct SimulationSetupChecks; * @details Each `Simulation` instance will only simulate for either single or double battles. This class is optimized * for running multiple simulations of the same battle, where each battle state has completed the same number of turns. */ -class Simulation : public internal::RegistryContainer { +class Simulation { private: types::entityVector createInitialMoves(const std::vector& moveInfoList); PokemonStateSetup createInitialPokemon(const PokemonCreationInfo& pokemonInfo); @@ -22838,9 +22523,9 @@ class Simulation : public internal::RegistryContainer { void clearCalculateDamageResults(); void clearAnalyzeEffectResults(); - types::entityVector selectedBattleEntities() const; - types::entityVector selectedMoveEntities() const; - types::entityVector selectedPokemonEntities() const; + types::entityVector battleEntities() const; + types::entityVector moveEntities() const; + types::entityVector pokemonEntities() const; template