Skip to content

Commit

Permalink
Fix batch trade logic (SV)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdawg1989 committed Dec 9, 2024
1 parent 8a98ba4 commit adcfc50
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 34 deletions.
2 changes: 1 addition & 1 deletion SysBot.Pokemon/Helpers/TradeBot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ public static class TradeBot

public const string ConfigPath = "config.json";

public const string Version = "v4.4";
public const string Version = "v4.5";
}
}
92 changes: 59 additions & 33 deletions SysBot.Pokemon/SV/BotTrade/PokeTradeBotSV.cs
Original file line number Diff line number Diff line change
Expand Up @@ -809,12 +809,13 @@ private async Task<PokeTradeResult> PerformBatchTrade(SAV9SV sav, PokeTradeDetai
var toSend = poke.TradeData;
if (toSend.Species != 0)
await SetBoxPokemonAbsolute(BoxStartOffset, toSend, token, sav).ConfigureAwait(false);

if (completedTrades > 0)
{
Hub.Config.Stream.StartTrade(this, poke, Hub);
Hub.Queues.StartTrade(this, poke);

await Task.Delay(10_000, token).ConfigureAwait(false); // Add delay for trade animation/pokedex register
await Task.Delay(10_000, token).ConfigureAwait(false); // Wait out trade animation/pokedex register
}

// Search for a trade partner for a Link Trade.
Expand Down Expand Up @@ -849,6 +850,8 @@ private async Task<PokeTradeResult> PerformBatchTrade(SAV9SV sav, PokeTradeDetai

poke.TradeCanceled(this, PokeTradeResult.NoTrainerFound);

CleanupAllBatchTradesFromQueue(startingDetail);

if (!await RecoverToPortal(token).ConfigureAwait(false))
{
Log("Failed to recover to portal.");
Expand Down Expand Up @@ -877,7 +880,7 @@ private async Task<PokeTradeResult> PerformBatchTrade(SAV9SV sav, PokeTradeDetai
return PokeTradeResult.RecoverOpenBox;
}
}
await Task.Delay(3_000, token).ConfigureAwait(false);
await Task.Delay(3_000 + Hub.Config.Timings.MiscellaneousSettings.ExtraTimeOpenBox, token).ConfigureAwait(false);

var tradePartnerFullInfo = await GetTradePartnerFullInfo(token).ConfigureAwait(false);
var tradePartner = new TradePartnerSV(tradePartnerFullInfo);
Expand Down Expand Up @@ -926,13 +929,18 @@ private async Task<PokeTradeResult> PerformBatchTrade(SAV9SV sav, PokeTradeDetai
return PokeTradeResult.TrainerTooSlow;
}

// Only send the "Found partner" notification on the first trade of a batch or for single trades
Log($"Found Link Trade partner: {tradePartner.TrainerName}-{tradePartner.TID7} (ID: {trainerNID})");
if (completedTrades == 0 || startingDetail.TotalBatchTrades == 1)
poke.SendNotification(this, $"Found Link Trade partner: {tradePartner.TrainerName}. **TID**: {tradePartner.TID7} **SID**: {tradePartner.SID7}. Waiting for a Pokémon...");

// Apply AutoOT after finding trade partner
if (Hub.Config.Legality.UseTradePartnerInfo && !poke.IgnoreAutoOT)
{
toSend = await ApplyAutoOT(toSend, tradePartnerFullInfo, sav, token);
toSend = await ApplyAutoOT(toSend, tradePartnerFullInfo, sav, token).ConfigureAwait(false);
poke.TradeData = toSend; // Update the actual trade data
if (toSend.Species != 0)
await SetBoxPokemonAbsolute(BoxStartOffset, toSend, token, sav).ConfigureAwait(false);
}

var offered = await ReadUntilPresent(TradePartnerOfferedOffset, 25_000, 1_000, BoxFormatSlotSize, token).ConfigureAwait(false);
Expand Down Expand Up @@ -1005,12 +1013,13 @@ private async Task<PokeTradeResult> PerformBatchTrade(SAV9SV sav, PokeTradeDetai
{
foreach (var pokemon in allReceived)
{
poke.TradeFinished(this, pokemon); // This sends each Pokemon back to the user
poke.TradeFinished(this, pokemon);
}
}

// Finally do cleanup
Hub.Queues.CompleteTrade(this, poke);
CleanupAllBatchTradesFromQueue(startingDetail);
_batchTracker.ClearReceivedPokemon(poke.Trainer.ID);
break;
}
Expand All @@ -1032,76 +1041,95 @@ private async Task<PokeTradeResult> PerformBatchTrade(SAV9SV sav, PokeTradeDetai

if (poke.TradeData.Species != 0)
{
await SetBoxPokemonAbsolute(BoxStartOffset, poke.TradeData, token, sav).ConfigureAwait(false);
if (Hub.Config.Legality.UseTradePartnerInfo && !poke.IgnoreAutoOT)
{
var nextToSend = await ApplyAutoOT(poke.TradeData, tradePartnerFullInfo, sav, token);
poke.TradeData = nextToSend;
await SetBoxPokemonAbsolute(BoxStartOffset, nextToSend, token, sav).ConfigureAwait(false);
}
else
{
await SetBoxPokemonAbsolute(BoxStartOffset, poke.TradeData, token, sav).ConfigureAwait(false);
}
}
continue;

}
else
{
poke.SendNotification(this, "All batch trades completed! Thank you for trading!");
}

poke.SendNotification(this, "Unable to find the next trade in sequence. Batch trade will be terminated.");
await ExitTradeToPortal(false, token).ConfigureAwait(false);
return PokeTradeResult.Success;
}
await ExitTradeToPortal(false, token).ConfigureAwait(false);
return PokeTradeResult.Success;
}

private async Task<PokeTradeResult> PerformLinkCodeTrade(SAV9SV sav, PokeTradeDetail<PK9> poke, CancellationToken token)
{
// Update Barrier Settings
UpdateBarrier(poke.IsSynchronized);

poke.TradeInitialize(this);

Hub.Config.Stream.EndEnterCode(this);

// Handle connection and portal entry
if (!await EnsureConnectedAndInPortal(token).ConfigureAwait(false))
{
return PokeTradeResult.RecoverStart;
}

// Enter Link Trade and code
if (!await EnterLinkTradeAndCode(poke.Code, token).ConfigureAwait(false))
{
return PokeTradeResult.RecoverStart;
}

StartFromOverworld = false;

// Route to appropriate trade handling based on trade type
if (poke.Type == PokeTradeType.Batch)
return await PerformBatchTrade(sav, poke, token).ConfigureAwait(false);

return await PerformNonBatchTrade(sav, poke, token).ConfigureAwait(false);
}

private async Task<bool> EnsureConnectedAndInPortal(CancellationToken token)
{
// StartFromOverworld can be true on first pass or if something went wrong last trade.
if (StartFromOverworld && !await IsOnOverworld(OverworldOffset, token).ConfigureAwait(false))
await RecoverToOverworld(token).ConfigureAwait(false);

// Handles getting into the portal. Will retry this until successful.
// if we're not starting from overworld, then ensure we're online before opening link trade -- will break the bot otherwise.
// If we're starting from overworld, then ensure we're online before opening the portal.
if (!StartFromOverworld && !await IsConnectedOnline(ConnectedOffset, token).ConfigureAwait(false))
{
await RecoverToOverworld(token).ConfigureAwait(false);
if (!await ConnectAndEnterPortal(token).ConfigureAwait(false))
{
await RecoverToOverworld(token).ConfigureAwait(false);
return PokeTradeResult.RecoverStart;
return false;
}
}
else if (StartFromOverworld && !await ConnectAndEnterPortal(token).ConfigureAwait(false))
{
await RecoverToOverworld(token).ConfigureAwait(false);
return PokeTradeResult.RecoverStart;
return false;
}
return true;
}

private async Task<bool> EnterLinkTradeAndCode(int code, CancellationToken token)
{
// Assumes we're freshly in the Portal and the cursor is over Link Trade.
Log("Selecting Link Trade.");
await Click(A, 1_500, token).ConfigureAwait(false);

// Always clear Link Codes and enter a new one based on the current trade type
await Click(X, 1_000, token).ConfigureAwait(false);
await Click(PLUS, 1_000, token).ConfigureAwait(false);
await Task.Delay(500, token).ConfigureAwait(false);
await Task.Delay(Hub.Config.Timings.MiscellaneousSettings.ExtraTimeOpenCodeEntry, token).ConfigureAwait(false);

var code = poke.Code;
Log($"Entering Link Trade code: {code:0000 0000}...");
await EnterLinkCode(code, Hub.Config, token).ConfigureAwait(false);
await Click(PLUS, 3_000, token).ConfigureAwait(false);

StartFromOverworld = false;

if (poke.Type == PokeTradeType.Batch)
{
return await PerformBatchTrade(sav, poke, token).ConfigureAwait(false);
}
else
{
return await PerformNonBatchTrade(sav, poke, token).ConfigureAwait(false);
}
return true;
}

private async Task<PokeTradeResult> PerformNonBatchTrade(SAV9SV sav, PokeTradeDetail<PK9> poke, CancellationToken token)
Expand Down Expand Up @@ -1334,10 +1362,8 @@ private async Task PerformTrade(SAV9SV sav, PokeTradeDetail<PK9> detail, PokeRou
PokeTradeResult result;
try
{
if (detail.Type == PokeTradeType.Batch)
result = await PerformBatchTrade(sav, detail, token).ConfigureAwait(false);
else
result = await PerformLinkCodeTrade(sav, detail, token).ConfigureAwait(false);
// All trades go through PerformLinkCodeTrade which will handle both regular and batch trades
result = await PerformLinkCodeTrade(sav, detail, token).ConfigureAwait(false);

if (result != PokeTradeResult.Success)
{
Expand Down

0 comments on commit adcfc50

Please sign in to comment.