Exemplo n.º 1
0
        // Whenever we're in a trade, this pointer will be loaded, otherwise 0
        public async Task <bool> IsPartnerParamLoaded(CancellationToken token)
        {
            var byt = await SwitchConnection.PointerPeek(8, Offsets.LinkTradePartnerParamPointer, token).ConfigureAwait(false);

            return(BitConverter.ToUInt64(byt, 0) != 0);
        }
Exemplo n.º 2
0
 public async Task <ulong> GetTradePartnerNID(CancellationToken token) => BitConverter.ToUInt64(await SwitchConnection.PointerPeek(sizeof(ulong), Offsets.LinkTradePartnerNIDPointer, token).ConfigureAwait(false), 0);
Exemplo n.º 3
0
        // 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);
        }
Exemplo n.º 4
0
        private async Task <bool> IsSceneID(uint expected, CancellationToken token)
        {
            var byt = await SwitchConnection.PointerPeek(1, Offsets.SceneIDPointer, token).ConfigureAwait(false);

            return(byt[0] == expected);
        }
Exemplo n.º 5
0
        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));
        }
Exemplo n.º 6
0
        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);
        }
Exemplo n.º 7
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 UnSoftBan(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.Species == 0 || !offered.ChecksumValid)
            {
                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);
        }