/// <summary>
 /// PlayCryInternal has a switch-statement at the end that limits the number of pokemon to 512 (128*4).
 /// We can rewrite that function to remove the limit and simplify the code.
 /// </summary>
 private void UpdatePlayCryInternal(IEditableViewPort viewPort, ModelDelta token)
 {
     var scriptStart       = 0x0720C2;
     var scriptLength      = 35 * 2;
     var gMPlay_PokemonCry = 0x02037ECC;
     var SpeciesToCryId    = 0x043304;
     var SetPokemonCryTone = 0x1DE638;
     var script            = @$ "
     sound_PlayCryInternal_After_SetPokemonCryPriority:
        mov   r0, r7
        bl    <{SpeciesToCryId:X6}>
        private int AddPokemonThumbConstantCode(IEditableViewPort viewPort, ModelDelta token, int pokecount, int freespace)
        {
            var model = viewPort.Model;

            var newCode = viewPort.Tools.CodeTool.Parser.Compile(token, model, freespace,
                                                                 "ldr r0, [pc, <pokecount>]",                        // 0
                                                                 "bx  lr",
                                                                 "ldr r1, [pc, <pokecount>]",                        // 4
                                                                 "bx  lr",
                                                                 "ldr r2, [pc, <pokecount>]",                        // 8
                                                                 "bx  lr",
                                                                 "ldr r3, [pc, <pokecount>]",                        // 12
                                                                 "bx  lr",
                                                                 "ldr r4, [pc, <pokecount>]",                        // 16
                                                                 "bx  lr",
                                                                 "ldr r5, [pc, <pokecount>]",                        // 20
                                                                 "bx  lr",
                                                                 "ldr r6, [pc, <pokecount>]",                        // 24
                                                                 "bx  lr",
                                                                 "ldr r7, [pc, <pokecount>]",                        // 28
                                                                 "bx  lr",
                                                                 "ldr r0, [pc, <pokecountMinusTwo>]",                // 32
                                                                 "bx  lr",
                                                                 "ldr r1, [pc, <pokecountMinusTwoShiftToHighBits>]", // 36
                                                                 "bx  lr",
                                                                 "ldr r4, [pc, <pokecount>]",                        // 40: r4=pokecount + r0 - 161 : see Menu2_GetMonSpriteAnchorCoord, species = SPECIES_OLD_UNOWN_B + unownLetter - 1
                                                                 "add r4, r4, r0",
                                                                 "sub r4, 161",
                                                                 "bx  lr",
                                                                 "pokecount: .word 0",                       // 48
                                                                 "pokecountMinusTwo: .word 0",               // 52
                                                                 "pokecountMinusTwoShiftToHighBits: .word 0" // 56
                                                                 ).ToArray();

            token.ChangeData(model, freespace, newCode);
            int wordOffset = 48;

            model.WriteMultiByteValue(freespace + wordOffset, 4, token, pokecount);
            model.WriteMultiByteValue(freespace + wordOffset + 4, 4, token, pokecount - 2);
            model.WriteMultiByteValue(freespace + wordOffset + 8, 4, token, (pokecount - 2) << 16);

            model.ObserveRunWritten(token, new WordRun(freespace + wordOffset, PokemonCountConstant, 2, 0, 1));
            model.ObserveRunWritten(token, new WordRun(freespace + wordOffset + 4, PokemonCountConstant, 2, -2, 1));
            model.ObserveRunWritten(token, new WordRun(freespace + wordOffset + 10, PokemonCountConstant, 2, -2, 1));

            return(freespace);
        }
        private void UpdatePokemonThumbConstants(IEditableViewPort viewPort, ModelDelta token, int pokecountFunctionAddress)
        {
            var model = viewPort.Model;

            byte[] compile(int adr, int reg) => viewPort.Tools.CodeTool.Parser.Compile(token, model, adr, $"bl <{pokecountFunctionAddress + reg * 4:X6}>").ToArray();

            var registerUpdates = new[] {
                new[] { 0x00FFFA, 0x0118D0, 0x02A81A, 0x02CEAC, 0x07FE12, // r0
                        0x0E6590, 0x0A0470, 0x0F31B2, 0x0FBFD6, 0x0DABB4,
                        0x0DAC1A, 0x094A1A, 0x043766, 0x043C42, 0x043E5C,
                        0x0440FE, 0x113EC0, 0x113EE0, 0x05148E, 0x052174,
                        0x05287E, 0x0535D0, 0x04FAA2, 0x04FC5E, 0x04FC8C,
                        0x04FCA2, 0x04FD04, 0x11AC1E, 0x11ADD4, 0x11ADF0,
                        0x11B030, 0x11B19A, 0x074658, 0x074728, 0x074788,
                        0x076BEC, 0x076CC8, 0x011F74, 0x0459CC, 0x00EC94,
                        0x00ED6C, 0x00F0E4, 0x00F1B0, 0x096E72, 0x096F86,
                        0x0970A6, 0x09713E, 0x0971D2, 0x0971FE, 0x040FDA,
                        0x09700A, },
                new[] { 0x0C839C, 0x0C8756, 0x0C882C, 0x0392CE, 0x0394FC, // r1
                        0x03994C, 0x039BC0, 0x03A234, 0x00D7E4, 0x00D854,
                        0x01196A, 0x013384, 0x013400, 0x01348C, 0x025BF8,
                        0x026DF0, 0x02B9A8, 0x02C9C8, 0x019CA4, 0x019D5A,
                        0x0CAD20, 0x0F23E4, 0x0F2E32, 0x0F32A4, 0x0F32E6,
                        0x040D0C, 0x15EBE0, 0x1193FA, 0x11B11C, 0x074624,
                        0x0746F0, 0x076BD8, 0x076C98, 0x011F3C, 0x096F78, },
                new[] { 0x026E8E, 0x00ED3E, 0x00F182, 0x096FFC, }, // r2
                new[] { 0x04FAE6 },                                // r3
                new[] { 0x040036, 0x0401A6, 0x12EAA4 },            // r4
                new int[0],                                        // r5
                new int[0],                                        // r6
                new int[] { 0x0A0224 },                            // r7
            };

            for (int register = 0; register < 8; register++)
            {
                foreach (var address in registerUpdates[register])
                {
                    token.ChangeData(model, address, compile(address, register));
                }
            }

            token.ChangeData(model, 0x103726, viewPort.Tools.CodeTool.Parser.Compile(token, model, 0x103726, $"bl <{pokecountFunctionAddress + 32:X6}>").ToArray()); // pokedex_screen
            token.ChangeData(model, 0x0BECA2, viewPort.Tools.CodeTool.Parser.Compile(token, model, 0x0BECA2, $"bl <{pokecountFunctionAddress + 36:X6}>").ToArray()); // ReadMail
            token.ChangeData(model, 0x12EAB4, viewPort.Tools.CodeTool.Parser.Compile(token, model, 0x12EAB4, $"bl <{pokecountFunctionAddress + 40:X6}>").ToArray()); // Menu2_GetMonSpriteAnchorCoord, species = SPECIES_OLD_UNOWN_B + unownLetter - 1
        }
        private void UpdatePokedexThumbConstants(IEditableViewPort viewPort, ModelDelta token, int dexCount, int dexcountFunctionAddress)
        {
            var countMinusOne = new[] { 0x088EA4, 0x1037D4, 0x103870, 0x103920, 0x104C28 };

            foreach (var address in countMinusOne)
            {
                viewPort.Model.WriteMultiByteValue(address, 2, token, dexCount - 1);
                viewPort.Model.ObserveRunWritten(token, new WordRun(address, PokedexCountConstant, 2, -1, 1));
            }

            var model = viewPort.Model;

            byte[] compile(int adr, int offset) => viewPort.Tools.CodeTool.Parser.Compile(token, model, adr, $"bl <{dexcountFunctionAddress + offset:X6}>").ToArray();

            // update  1025EC to bl <r0=dex_size*8>
            // update  103534 to bl <r2=dex_size>
            compile(0x1025EC, 0);
            compile(0x103534, 8);
        }
        private int AddPokedexThumbConstantCode(IEditableViewPort viewPort, ModelDelta token, int dexCount)
        {
            var model = viewPort.Model;

            var insertPoint = 0x157868;
            var newCode     = viewPort.Tools.CodeTool.Parser.Compile(token, model, insertPoint,
                                                                     "ldr r0, [pc, <dexcount>]", // 0
                                                                     "lsl r0, r0, #3",
                                                                     "bx  lr",
                                                                     "nop",
                                                                     "ldr r2, [pc, <dexcount>]", // 8
                                                                     "bx  lr",
                                                                     "dexcount: .word 0"         // 12
                                                                     ).ToArray();

            token.ChangeData(model, insertPoint, newCode);
            int wordOffset = 12;

            model.WriteMultiByteValue(insertPoint + wordOffset, 4, token, dexCount);
            model.ObserveRunWritten(token, new WordRun(insertPoint + wordOffset, PokedexCountConstant, 2, 0, 1));

            return(insertPoint);
        }
        private int UpdateConstants(IEditableViewPort viewPort, ModelDelta token)
        {
            var model     = viewPort.Model;
            var pokecount = model.GetTable(HardcodeTablesModel.PokemonNameTable).ElementCount; // TODO this can fail...

            var pokeCount0 = new[] { 0x168E09, 0x16B2BC };                                     // 2 bytes, equal to number of pokemon
            var pokeCount1 = new[] { 0x043240, 0x0CB160, 0x0CB16C, 0x14420C };                 // 2 bytes, equal to number of pokemon-1
            var pokeCount2 = new[] { 0x12EAB0, };                                              // 2 bytes, equal to number of pokemon+1

            foreach (var address in pokeCount0)
            {
                model.WriteMultiByteValue(address, 2, token, pokecount);
            }
            foreach (var address in pokeCount1)
            {
                model.WriteMultiByteValue(address, 2, token, pokecount - 1);
            }
            foreach (var address in pokeCount2)
            {
                model.WriteMultiByteValue(address, 2, token, pokecount + 1);
            }

            foreach (var address in pokeCount0)
            {
                model.ObserveRunWritten(token, new WordRun(address, PokemonCountConstant, 2, 0, 1));
            }
            foreach (var address in pokeCount1)
            {
                model.ObserveRunWritten(token, new WordRun(address, PokemonCountConstant, 2, -1, 1));
            }
            foreach (var address in pokeCount2)
            {
                model.ObserveRunWritten(token, new WordRun(address, PokemonCountConstant, 2, 1, 1));
            }

            return(pokecount);
        }
Esempio n. 7
0
        public static async Task <ErrorInfo> ExpandMoveEffects(ThumbParser parser, IEditableViewPort viewPort, ModelDelta token, double targetLoadingPercent)
        {
            // make move effects 2 bytes instead of 1 byte
            var model      = viewPort.Model;
            var table      = model.GetTable(MoveDataTable);
            var fieldNames = table.ElementContent.Select(seg => seg.Name).ToArray();

            async Task <ErrorInfo> shiftField(int i)
            {
                var result = RefactorMoveByteFieldInTable(parser, model, token, MoveDataTable, fieldNames[i], i + 1);
                await viewPort.UpdateProgress((9 - i) / 9.0 *targetLoadingPercent);

                return(result);
            }

            // effect. power. type. accuracy. pp. effectAccuracy. target. priority. info. unused. unused:
            ErrorInfo error;

            error = await shiftField(8); if (error.HasError)
            {
                return(error);
            }
            error = await shiftField(7); if (error.HasError)
            {
                return(error);
            }
            error = await shiftField(6); if (error.HasError)
            {
                return(error);
            }
            error = await shiftField(5); if (error.HasError)
            {
                return(error);
            }
            error = await shiftField(4); if (error.HasError)
            {
                return(error);
            }
            error = await shiftField(3); if (error.HasError)
            {
                return(error);
            }
            error = await shiftField(2); if (error.HasError)
            {
                return(error);
            }
            error = await shiftField(1); if (error.HasError)
            {
                return(error);
            }
            error = RefactorByteToHalfWordInTable(parser, model, token, MoveDataTable, fieldNames[0]); if (error.HasError)
            {
                return(error);
            }
            await viewPort.UpdateProgress(targetLoadingPercent);

            // update offset pointers (because the PP field moved)
            foreach (OffsetPointerRun pointerRun in table.PointerSources
                     .Select(address => model.GetNextRun(address))
                     .Where(pointer => pointer is OffsetPointerRun)
                     )
            {
                model.ClearFormat(token, pointerRun.Start, 4);
                model.WritePointer(token, pointerRun.Start, table.Start + 5);
                model.ObserveRunWritten(token, new OffsetPointerRun(pointerRun.Start, 5));
            }

            return(ErrorInfo.NoError);
        }