Beispiel #1
0
        private async Task <PokeTradeResult> ProcessDumpTradeAsync(PokeTradeDetail <PB8> detail, CancellationToken token)
        {
            int ctr   = 0;
            var time  = TimeSpan.FromSeconds(Hub.Config.Trade.MaxDumpTradeTime);
            var start = DateTime.Now;

            while (ctr < Hub.Config.Trade.MaxDumpsPerTrade && DateTime.Now - start < time)
            {
                // Wait for user input... Needs to be different from the previously offered Pokémon.
                var tradeOffered = await ReadUntilChanged(LinkTradePokemonOffset, lastOffered, 3_000, 1_000, false, true, token).ConfigureAwait(false);

                if (!tradeOffered)
                {
                    continue;
                }

                // If we detected a change, they offered something.
                var pk = await ReadPokemon(LinkTradePokemonOffset, BoxFormatSlotSize, token).ConfigureAwait(false);

                var newEC = await SwitchConnection.ReadBytesAbsoluteAsync(LinkTradePokemonOffset, 8, token).ConfigureAwait(false);

                if (pk == null || pk.Species < 1 || !pk.ChecksumValid || lastOffered == newEC)
                {
                    continue;
                }
                lastOffered = newEC;

                // Send results from separate thread; the bot doesn't need to wait for things to be calculated.
                if (DumpSetting.Dump)
                {
                    var subfolder = detail.Type.ToString().ToLower();
                    DumpPokemon(DumpSetting.DumpFolder, subfolder, pk); // received
                }

                var la      = new LegalityAnalysis(pk);
                var verbose = la.Report(true);
                Log($"Shown Pokémon is: {(la.Valid ? "Valid" : "Invalid")}.");

                detail.SendNotification(this, pk, verbose);
                ctr++;
            }

            Log($"Ended Dump loop after processing {ctr} Pokémon.");
            if (ctr == 0)
            {
                return(PokeTradeResult.TrainerTooSlow);
            }

            TradeSettings.AddCompletedDumps();
            detail.Notifier.SendNotification(this, detail, $"Dumped {ctr} Pokémon.");
            detail.Notifier.TradeFinished(this, detail, detail.TradeData); // blank pk8
            return(PokeTradeResult.Success);
        }
Beispiel #2
0
        private async Task GetCoordinatesForSpin(string name, CancellationToken token)
        {
            if (TradeExtensions <PK8> .Coordinates.TryGetValue(name, out _))
            {
                return;
            }

            TradeExtensions <PK8> .CoordinatesOffset = await ParsePointer("[[[[[[main+26365B8]+88]+1F8]+E0]+10]+E0]+60", token).ConfigureAwait(false); // Thank you for the pointer, Zyro <3

            TradeExtensions <PK8> .Coordinates.Add(name,
                                                   (
                                                       await SwitchConnection.ReadBytesAbsoluteAsync(TradeExtensions <PK8> .CoordinatesOffset, 4, token).ConfigureAwait(false),
                                                       await SwitchConnection.ReadBytesAbsoluteAsync(TradeExtensions <PK8> .CoordinatesOffset + 0x4, 4, token).ConfigureAwait(false),
                                                       await SwitchConnection.ReadBytesAbsoluteAsync(TradeExtensions <PK8> .CoordinatesOffset + 0x8, 4, token).ConfigureAwait(false)
                                                   ));
        }
Beispiel #3
0
        private async Task <PokeTradeResult> ConfirmAndStartTrading(PokeTradeDetail <PB8> detail, CancellationToken token)
        {
            // We'll keep watching B1S1 for a change to indicate a trade started -> should try quitting at that point.
            var oldEC = await SwitchConnection.ReadBytesAbsoluteAsync(BoxStartOffset, 8, token).ConfigureAwait(false);

            await Click(A, 3_000, token).ConfigureAwait(false);

            for (int i = 0; i < 10; i++)
            {
                if (await IsUserBeingShifty(detail, token).ConfigureAwait(false))
                {
                    return(PokeTradeResult.SuspiciousActivity);
                }
                await Click(A, 1_500, token).ConfigureAwait(false);
            }

            var tradeCounter = 0;

            while (await IsUnionWork(UnionTalkingOffset, token).ConfigureAwait(false))
            {
                await Click(A, 1_000, token).ConfigureAwait(false);

                tradeCounter++;

                var newEC = await SwitchConnection.ReadBytesAbsoluteAsync(BoxStartOffset, 8, token).ConfigureAwait(false);

                if (!newEC.SequenceEqual(oldEC))
                {
                    await Task.Delay(5_000, token).ConfigureAwait(false);

                    return(PokeTradeResult.Success);
                }

                // We've somehow failed out of the Union Room -- can happen with connection error.
                if (!await IsUnionWork(UnionGamingOffset, token).ConfigureAwait(false))
                {
                    return(PokeTradeResult.TrainerTooSlow);
                }
                if (tradeCounter >= Hub.Config.Trade.TradeAnimationMaxDelaySeconds)
                {
                    break;
                }
            }

            // If we don't detect a B1S1 change, the trade didn't go through in that time.
            return(PokeTradeResult.TrainerTooSlow);
        }
Beispiel #4
0
        public async Task <PK8?> ReadUntilPresentAbsolute(ulong offset, int waitms, int waitInterval, CancellationToken token, int size = BoxFormatSlotSize) // Need to eliminate duplicate code, currently a hack
        {
            int msWaited = 0;

            while (msWaited < waitms)
            {
                var data = await SwitchConnection.ReadBytesAbsoluteAsync(offset, size, token).ConfigureAwait(false);

                var pk = new PK8(data);
                if (pk.Species != 0 && pk.ChecksumValid)
                {
                    return(pk);
                }

                await Task.Delay(waitInterval, token).ConfigureAwait(false);

                msWaited += waitInterval;
            }
            return(null);
        }
        //Pointer parser, code from ALM
        public async Task <ulong> ParsePointer(String pointer, CancellationToken token)
        {
            var  ptr    = pointer;
            uint finadd = 0;

            if (!ptr.EndsWith("]"))
            {
                finadd = Util.GetHexValue(ptr.Split('+').Last());
            }
            var jumps = ptr.Replace("main", "").Replace("[", "").Replace("]", "").Split(new[] { "+" }, StringSplitOptions.RemoveEmptyEntries);

            if (jumps.Length == 0)
            {
                Log("Invalid Pointer");
                return(0);
            }

            var   initaddress = Util.GetHexValue(jumps[0].Trim());
            ulong address     = BitConverter.ToUInt64(await SwitchConnection.ReadBytesMainAsync(initaddress, 0x8, token).ConfigureAwait(false), 0);

            foreach (var j in jumps)
            {
                var val = Util.GetHexValue(j.Trim());
                if (val == initaddress)
                {
                    continue;
                }
                if (val == finadd)
                {
                    address += val;
                    break;
                }
                address = BitConverter.ToUInt64(await SwitchConnection.ReadBytesAbsoluteAsync(address + val, 0x8, token).ConfigureAwait(false), 0);
            }
            return(address);
        }
Beispiel #6
0
        private async Task <PokeTradeResult> PerformLinkCodeTrade(SAV8BS sav, PokeTradeDetail <PB8> poke, CancellationToken token)
        {
            sessionTradeCount++;
            Log($"Starting trade #{sessionTradeCount} for this session.");
            // Update Barrier Settings
            UpdateBarrier(poke.IsSynchronized);
            poke.TradeInitialize(this);
            await RestartGameIfCantLeaveUnionRoom(token).ConfigureAwait(false);

            Hub.Config.Stream.EndEnterCode(this);

            if (await CheckIfSoftBanned(SoftBanOffset, token).ConfigureAwait(false))
            {
                await Unban(token).ConfigureAwait(false);
            }

            var toSend = poke.TradeData;

            if (toSend.Species != 0)
            {
                await SetBoxPokemonAbsolute(BoxStartOffset, toSend, token, sav).ConfigureAwait(false);
            }

            // Enter Union Room and set ourselves up as Trading.
            if (!await EnterUnionRoomWithCode(poke.Type, poke.Code, token).ConfigureAwait(false))
            {
                // We don't know how far we made it in, so restart the game to be safe.
                await RestartGameBDSP(token).ConfigureAwait(false);

                return(PokeTradeResult.RecoverEnterUnionRoom);
            }

            poke.TradeSearching(this);
            var waitPartner = Hub.Config.Trade.TradeWaitTime;

            // Keep pressing A until we detect someone talking to us.
            while (!await IsUnionWork(UnionTalkingOffset, token).ConfigureAwait(false) && waitPartner > 0)
            {
                for (int i = 0; i < 2; ++i)
                {
                    await Click(A, 0_450, token).ConfigureAwait(false);
                }

                if (--waitPartner <= 0)
                {
                    return(PokeTradeResult.NoTrainerFound);
                }
            }

            // Keep pressing A until TargetTranerParam is loaded (when we hit the box).
            while (!await IsPartnerParamLoaded(token).ConfigureAwait(false) && waitPartner > 0)
            {
                for (int i = 0; i < 2; ++i)
                {
                    await Click(A, 0_450, token).ConfigureAwait(false);
                }

                // Can be false if they talked and quit.
                if (!await IsUnionWork(UnionTalkingOffset, token).ConfigureAwait(false))
                {
                    break;
                }
                if (--waitPartner <= 0)
                {
                    return(PokeTradeResult.TrainerTooSlow);
                }
            }

            // Still going through dialog and box opening.
            await Task.Delay(3_000, token).ConfigureAwait(false);

            // Can happen if they quit out of talking to us.
            if (!await IsPartnerParamLoaded(token).ConfigureAwait(false))
            {
                return(PokeTradeResult.TrainerTooSlow);
            }

            var tradePartner = await GetTradePartnerInfo(token).ConfigureAwait(false);

            //var trainerNID = await GetTradePartnerNID(token).ConfigureAwait(false);
            Log($"Found Link Trade partner: {tradePartner.TrainerName}-{tradePartner.TID7}");

            await Task.Delay(2_000, token).ConfigureAwait(false);

            // Confirm Box 1 Slot 1
            if (poke.Type == PokeTradeType.Specific)
            {
                for (int i = 0; i < 5; i++)
                {
                    await Click(A, 0_500, token).ConfigureAwait(false);
                }
            }

            poke.SendNotification(this, $"Found Link Trade partner: {tradePartner.TrainerName}. Waiting for a Pokémon...");

            // Requires at least one trade for this pointer to make sense, so cache it here.
            LinkTradePokemonOffset = await SwitchConnection.PointerAll(Offsets.LinkTradePartnerPokemonPointer, token).ConfigureAwait(false);

            if (poke.Type == PokeTradeType.Dump)
            {
                return(await ProcessDumpTradeAsync(poke, token).ConfigureAwait(false));
            }

            // Wait for user input... Needs to be different from the previously offered Pokémon.
            var tradeOffered = await ReadUntilChanged(LinkTradePokemonOffset, lastOffered, 25_000, 1_000, false, true, token).ConfigureAwait(false);

            if (!tradeOffered)
            {
                return(PokeTradeResult.TrainerTooSlow);
            }

            // If we detected a change, they offered something.
            var offered = await ReadPokemon(LinkTradePokemonOffset, BoxFormatSlotSize, token).ConfigureAwait(false);

            if (offered is null)
            {
                return(PokeTradeResult.TrainerTooSlow);
            }
            lastOffered = await SwitchConnection.ReadBytesAbsoluteAsync(LinkTradePokemonOffset, 8, token).ConfigureAwait(false);

            PokeTradeResult update;
            var             trainer = new PartnerDataHolder(0, tradePartner.TrainerName, tradePartner.TID7);

            (toSend, update) = await GetEntityToSend(sav, poke, offered, toSend, trainer, token).ConfigureAwait(false);

            if (update != PokeTradeResult.Success)
            {
                return(update);
            }

            var tradeResult = await ConfirmAndStartTrading(poke, token).ConfigureAwait(false);

            if (tradeResult != PokeTradeResult.Success)
            {
                return(tradeResult);
            }

            if (token.IsCancellationRequested)
            {
                return(PokeTradeResult.RoutineCancel);
            }

            // Trade was Successful!
            var received = await ReadPokemon(BoxStartOffset, BoxFormatSlotSize, token).ConfigureAwait(false);

            // Pokémon in b1s1 is same as the one they were supposed to receive (was never sent).
            if (SearchUtil.HashByDetails(received) == SearchUtil.HashByDetails(toSend) && received.Checksum == toSend.Checksum)
            {
                Log("User did not complete the trade.");
                return(PokeTradeResult.TrainerTooSlow);
            }

            // As long as we got rid of our inject in b1s1, assume the trade went through.
            Log("User completed the trade.");
            poke.TradeFinished(this, received);

            // Only log if we completed the trade.
            UpdateCountsAndExport(poke, received, toSend);

            // Still need to wait out the trade animation.
            for (var i = 0; i < 30; i++)
            {
                await Click(A, 0_500, token).ConfigureAwait(false);
            }

            Log("Trying to get out of the Union Room.");
            // Now get out of the Union Room.
            if (!await EnsureOutsideOfUnionRoom(token).ConfigureAwait(false))
            {
                return(PokeTradeResult.RecoverReturnOverworld);
            }

            // Sometimes they offered another mon, so store that immediately upon leaving Union Room.
            lastOffered = await SwitchConnection.ReadBytesAbsoluteAsync(LinkTradePokemonOffset, 8, token).ConfigureAwait(false);

            return(PokeTradeResult.Success);
        }
        public async Task <PB7> LGReadPokemon(ulong offset, CancellationToken token, int size = EncryptedSize)
        {
            var data = await SwitchConnection.ReadBytesAbsoluteAsync(offset, size, token).ConfigureAwait(false);

            return(new PB7(data));
        }
 public async Task <uint> LGReadComboCount(CancellationToken token) =>
 BitConverter.ToUInt16(await SwitchConnection.ReadBytesAbsoluteAsync(await ParsePointer(CatchComboPointer, token).ConfigureAwait(false), 2, token).ConfigureAwait(false), 0);
        public async Task <PK8> ReadPokemon(ulong offset, CancellationToken token, int size = BoxFormatSlotSize)
        {
            var data = await SwitchConnection.ReadBytesAbsoluteAsync(offset, size, token).ConfigureAwait(false);

            return(new PK8(data));
        }
Beispiel #10
0
 public async Task <bool> LairStatusCheckMain(ushort val, ulong ofs, CancellationToken token) => BitConverter.GetBytes(val).SequenceEqual(await SwitchConnection.ReadBytesAbsoluteAsync(ofs, 2, token).ConfigureAwait(false));
        // Uses absolute offset which is set each session. Checks for IsGaming or IsTalking.
        public async Task <bool> IsUnionWork(ulong offset, CancellationToken token)
        {
            var data = await SwitchConnection.ReadBytesAbsoluteAsync(offset, 1, token).ConfigureAwait(false);

            return(data[0] == 1);
        }
        public override async Task <PB8> ReadPokemon(ulong offset, int size, CancellationToken token)
        {
            var data = await SwitchConnection.ReadBytesAbsoluteAsync(offset, size, token).ConfigureAwait(false);

            return(new PB8(data));
        }
        public async Task <bool> CheckIfSoftBanned(ulong offset, CancellationToken token)
        {
            var data = await SwitchConnection.ReadBytesAbsoluteAsync(offset, 4, token).ConfigureAwait(false);

            return(BitConverter.ToUInt32(data, 0) != 0);
        }
        private async Task Overworld(CancellationToken token, bool birds = false)
        {
            GameVersion version = await LGWhichGameVersion(token).ConfigureAwait(false);

            List <int[]> movementslist = ParseMovements();
            bool         firstrun      = movementslist.Count > 0;
            Stopwatch    stopwatch     = new Stopwatch();
            uint         prev          = 0;
            uint         newspawn;
            uint         catchcombo;
            uint         speciescombo;
            int          i              = 0;
            int          j              = 0;
            bool         freeze         = false;
            bool         searchforshiny = Hub.Config.LGPE_OverworldScan.OnlyShiny;
            bool         found          = false;

            if (movementslist.Count > 0)
            {
                Log($"ATTENTION!{Environment.NewLine}Any wild encounter will broke the movement routine, resulting in the pg moving to unwanted places!{Environment.NewLine}" +
                    $"----------------------------------------{Environment.NewLine}" +
                    $"ATTENTION!\nUnexpected behaviour can occur if a shiny is detected while changing area. It his higlhy recommended to avoid that.{Environment.NewLine}" +
                    $"-----------------------------------------{Environment.NewLine}");
            }

            //Catch combo to increment spawn quality and shiny rate (Thanks to Lincoln-LM for the offsets)
            if ((int)Hub.Config.LGPE_OverworldScan.ChainSpecies > 0)
            {
                speciescombo = BitConverter.ToUInt16(await SwitchConnection.ReadBytesAbsoluteAsync(await ParsePointer(SpeciesComboPointer, token).ConfigureAwait(false), 2, token).ConfigureAwait(false), 0);
                if ((speciescombo != (uint)Hub.Config.LGPE_OverworldScan.ChainSpecies) && (Hub.Config.LGPE_OverworldScan.ChainSpecies != 0))
                {
                    Log($"Current catch combo being on {(speciescombo == 0 ? "None" : SpeciesName.GetSpeciesName((int)speciescombo, 2))}, changing to {Hub.Config.LGPE_OverworldScan.ChainSpecies}.");
                    await SwitchConnection.WriteBytesAbsoluteAsync(BitConverter.GetBytes((uint)Hub.Config.LGPE_OverworldScan.ChainSpecies), await ParsePointer(SpeciesComboPointer, token).ConfigureAwait(false), token).ConfigureAwait(false);

                    speciescombo = BitConverter.ToUInt16(await SwitchConnection.ReadBytesAbsoluteAsync(await ParsePointer(SpeciesComboPointer, token).ConfigureAwait(false), 2, token).ConfigureAwait(false), 0);
                    Log($"Current catch combo being now on {(speciescombo == 0 ? "None" : SpeciesName.GetSpeciesName((int)speciescombo, 2))}.");
                }
            }
            if (Hub.Config.LGPE_OverworldScan.ChainCount > 0)
            {
                catchcombo = BitConverter.ToUInt16(await SwitchConnection.ReadBytesAbsoluteAsync(await ParsePointer(CatchComboPointer, token).ConfigureAwait(false), 2, token).ConfigureAwait(false), 0);
                if (catchcombo < (uint)Hub.Config.LGPE_OverworldScan.ChainCount)
                {
                    Log($"Current catch combo being {catchcombo}, incrementing to {Hub.Config.LGPE_OverworldScan.ChainCount}.");
                    await SwitchConnection.WriteBytesAbsoluteAsync(BitConverter.GetBytes((uint)Hub.Config.LGPE_OverworldScan.ChainCount), await ParsePointer(CatchComboPointer, token).ConfigureAwait(false), token).ConfigureAwait(false);

                    catchcombo = BitConverter.ToUInt16(await SwitchConnection.ReadBytesAbsoluteAsync(await ParsePointer(CatchComboPointer, token).ConfigureAwait(false), 2, token).ConfigureAwait(false), 0);
                    Log($"Current catch combo being now {catchcombo}.");
                }
            }

            while (!token.IsCancellationRequested)
            {
                if (searchforshiny)
                {
                    await LGZaksabeast(token, version).ConfigureAwait(false);
                }
                while (freeze == false && !token.IsCancellationRequested && !found)
                {
                    if (await LGCountMilliseconds(Hub.Config, token).ConfigureAwait(false) > 0 || !searchforshiny)
                    {
                        //The routine need to continue and check the overworld spawns, cannot be stuck at changing stick position.
                        if (movementslist.Count > 0)
                        {
                            if (stopwatch.ElapsedMilliseconds >= movementslist.ElementAt(j)[2] || firstrun)
                            {
                                if (firstrun)
                                {
                                    firstrun = false;
                                }
                                //Log($"Moved for {stopwatch.ElapsedMilliseconds}ms.");
                                await ResetStick(token).ConfigureAwait(false);
                                await SetStick(RIGHT, (short)(movementslist.ElementAt(j)[0]), (short)(movementslist.ElementAt(j)[1]), 0_001, token).ConfigureAwait(false);

                                j++;
                                if (j == movementslist.Count)
                                {
                                    j = 0;
                                }
                                stopwatch.Restart();
                            }
                        }

                        //Check is inside an unwanted encounter
                        if (await LGIsInCatchScreen(token).ConfigureAwait(false))
                        {
                            await ResetStick(token).ConfigureAwait(false);

                            Log($"Unwanted encounter detected!");
                            int y = 0;
                            while (await LGIsInCatchScreen(token).ConfigureAwait(false) && !token.IsCancellationRequested)
                            {
                                y++;
                                await Task.Delay(8_000, token).ConfigureAwait(false);

                                if (y > 2)
                                {
                                    await Click(B, 1_200, token).ConfigureAwait(false);
                                }
                                await Click(B, 1_200, token).ConfigureAwait(false);
                                await Click(A, 1_000, token).ConfigureAwait(false);

                                await Task.Delay(6_500, token).ConfigureAwait(false);
                            }
                            Log($"Exited wild encounter.");
                        }

                        //Check new spawns
                        newspawn = BitConverter.ToUInt16(await Connection.ReadBytesAsync(LastSpawn1, 2, token).ConfigureAwait(false), 0);
                        if (newspawn != prev)
                        {
                            if (newspawn != 0)
                            {
                                i++;
                                if (IsPKLegendary((int)newspawn))
                                {
                                    Counts.AddCompletedLegends();
                                }
                                else
                                {
                                    Counts.AddCompletedEncounters();
                                }
                                Log($"New spawn ({i}): {newspawn} {SpeciesName.GetSpeciesName((int)newspawn, 4)}");
                            }
                            prev = newspawn;
                            if (!searchforshiny &&
                                ((!birds && (int)newspawn == (int)Hub.Config.LGPE_OverworldScan.StopOnSpecies) ||
                                 (!birds && (int)Hub.Config.LGPE_OverworldScan.StopOnSpecies == 0) ||
                                 (birds && ((int)newspawn == 144 || (int)newspawn == 145 || (int)newspawn == 146))))
                            {
                                await Click(X, 1_000, token).ConfigureAwait(false);
                                await Click(HOME, 1_000, token).ConfigureAwait(false);

                                if (!String.IsNullOrEmpty(Hub.Config.Discord.UserTag))
                                {
                                    Log($"<@{Hub.Config.Discord.UserTag}> stop conditions met, restart the bot(s) to search again.");
                                }
                                else
                                {
                                    Log("Stop conditions met, restart the bot(s) to search again.");
                                }
                                return;
                            }
                        }
                    }
                    else if (searchforshiny)
                    {
                        freeze = true;
                    }
                }

                if (searchforshiny && !token.IsCancellationRequested)
                {
                    Log("A Shiny has been detected.");
                }

                //Unfreeze to restart the routine, or log the Shiny species.
                await LGUnfreeze(token, version).ConfigureAwait(false);

                newspawn = BitConverter.ToUInt16(await Connection.ReadBytesAsync(LastSpawn1, 2, token).ConfigureAwait(false), 0);

                //Stop Conditions logic
                if (birds && ((int)newspawn == 144 || (int)newspawn == 145 || (int)newspawn == 146) && !token.IsCancellationRequested)
                {
                    found = true;
                }
                else if ((!birds && (int)Hub.Config.LGPE_OverworldScan.StopOnSpecies > 0 && (int)newspawn == (int)Hub.Config.LGPE_OverworldScan.StopOnSpecies) ||
                         (!birds && (int)Hub.Config.LGPE_OverworldScan.StopOnSpecies == 0))
                {
                    found = true;
                }
                else
                {
                    found = false;
                }

                if (!found && !token.IsCancellationRequested)
                {
                    freeze = false;
                    Log($"Shiny {SpeciesName.GetSpeciesName((int)newspawn, 4)} is not the target, the routine will continue.");
                }
                else if (!token.IsCancellationRequested)
                {
                    await ResetStick(token).ConfigureAwait(false);

                    if (!String.IsNullOrEmpty(Hub.Config.Discord.UserTag))
                    {
                        Log($"<@{Hub.Config.Discord.UserTag}> Shiny {SpeciesName.GetSpeciesName((int)newspawn, 4)} found!");
                    }
                    else
                    {
                        Log($"Shiny {SpeciesName.GetSpeciesName((int)newspawn, 4)} found!");
                    }
                    await Click(X, 1_000, token).ConfigureAwait(false);
                    await Click(HOME, 1_000, token).ConfigureAwait(false);

                    return;
                }
            }
            await ResetStick(token).ConfigureAwait(false);

            if (searchforshiny)
            {
                await LGUnfreeze(token, version).ConfigureAwait(false);
            }
        }