private void readRotationOriginPoints(VAVAddr address, EndianBinaryReader s, MapDescriptor mapDescriptor, AddressMapper addressMapper)
 {
     mapDescriptor.SwitchRotationOriginPoints.Clear();
     // Special case handling: in the original game these values are initialized at run time only. So we need to hardcode them:
     if (address == addressMapper.toVersionAgnosticAddress((BSVAddr)0x806b8df0)) // magmageddon
     {
         // no points
     }
     else if (address == addressMapper.toVersionAgnosticAddress((BSVAddr)0x8047d598)) // collosus
     {
         mapDescriptor.SwitchRotationOriginPoints[0] = new OriginPoint(-288, -32);
         mapDescriptor.SwitchRotationOriginPoints[1] = new OriginPoint(288, -32);
     }
     else if (address == addressMapper.toVersionAgnosticAddress((BSVAddr)0x8047d5b4)) // observatory
     {
         mapDescriptor.SwitchRotationOriginPoints[0] = new OriginPoint(0, 0);
     }
     else if (addressMapper.canConvertToFileAddress(address))
     {
         s.Seek(addressMapper.toFileAddress(address), SeekOrigin.Begin);
         var originPointCount = s.ReadUInt32();
         for (int i = 0; i < originPointCount; i++)
         {
             OriginPoint point = new OriginPoint();
             point.X = s.ReadSingle();
             var z = s.ReadSingle(); // ignore Z value
             point.Y = s.ReadSingle();
             mapDescriptor.SwitchRotationOriginPoints[i] = point;
         }
     }
 }
        protected VAVAddr writeIconTable(Dictionary <string, VAVAddr> mapIcons, out Dictionary <string, VAVAddr> iconTableMap)
        {
            // write the map icon lookup table and remember the location of each pointer in the mapIconLookupTable dictionary
            var iconTableOffsetMap = new Dictionary <string, int>();

            iconTableMap = new Dictionary <string, VAVAddr>();
            var iconTable = new List <VAVAddr>();
            var i         = 0;

            foreach (var entry in mapIcons)
            {
                var addr = entry.Value;
                iconTable.Add(addr);
                iconTableOffsetMap.Add(entry.Key, i);
                i += 4;
            }
            VAVAddr iconTableAddr = allocate(iconTable, "IconTable");

            foreach (var entry in iconTableOffsetMap)
            {
                string icon   = entry.Key;
                int    offset = entry.Value;
                iconTableMap[icon] = iconTableAddr + offset;
            }
            return(iconTableAddr);
        }
        private List <UInt32> writeSubroutineForceFetchFakeVentureCard(VAVAddr fakeVentureCard)
        {
            PowerPcAsm.Pair16Bit v = PowerPcAsm.make16bitValuePair((UInt32)fakeVentureCard);

            // precondition: r3 is ChanceCardUI *
            // ChanceCardUI->field_0x34 is ChanceBoard *
            // ChanceBoard->field_0x158 is current venture card id

            var asm = new List <UInt32>();

            asm.Add(PowerPcAsm.lis(6, v.upper16Bit));      // \
            asm.Add(PowerPcAsm.addi(6, 6, v.lower16Bit));  // / r6 <- forceVentureCardVariable
            asm.Add(PowerPcAsm.lwz(4, 0x0, 6));            // | r4 <- forceVentureCard
            asm.Add(PowerPcAsm.cmpwi(4, 0x0));             // | if(forceVentureCard != 0)
            asm.Add(PowerPcAsm.beq(7));                    // | {
            asm.Add(PowerPcAsm.lwz(5, 0x34, 3));           // |   r5 <- ChanceCardUI.ChanceBoard
            asm.Add(PowerPcAsm.stw(4, 0x158, 5));          // |   ChanceBoard.currentVentureCardId <- r4
            asm.Add(PowerPcAsm.li(5, 0));                  // |\  forceVentureCard <- 0
            asm.Add(PowerPcAsm.stw(5, 0x0, 6));            // |/
            asm.Add(PowerPcAsm.li(8, 0x0));                // |   r8 <- 0 (the venture card is initialized)
            asm.Add(PowerPcAsm.blr());                     // |   return r4 and r8
                                                           // | }
            asm.Add(PowerPcAsm.li(4, -0x1));               // | r4 <- -1
            asm.Add(PowerPcAsm.li(8, 0x3));                // | r8 <- 3 (the venture card is continued to be executed)
            asm.Add(PowerPcAsm.blr());                     // | return r4 and r8


            return(asm);
        }
 public void addFreeSpace(VAVAddr start, VAVAddr end)
 {
     if (startedAllocating)
     {
         throw new InvalidOperationException("Can't add more free space after calling allocateUnusedSpace()");
     }
     totalFreeSpaceBlocks.Add(end, start);
     remainingFreeSpaceBlocks.Add(end, start);
 }
 private void readLoopingModeConfig(VAVAddr address, EndianBinaryReader s, MapDescriptor mapDescriptor, AddressMapper addressMapper)
 {
     if (addressMapper.canConvertToFileAddress(address))
     {
         s.Seek(addressMapper.toFileAddress(address), SeekOrigin.Begin);
         mapDescriptor.LoopingModeRadius              = s.ReadSingle();
         mapDescriptor.LoopingModeHorizontalPadding   = s.ReadSingle();
         mapDescriptor.LoopingModeVerticalSquareCount = s.ReadSingle();
     }
 }
        protected VAVAddr writeTable(List <MapDescriptor> mapDescriptors, VAVAddr bgSequenceMarioStadium)
        {
            var bgSequenceTable = new List <VAVAddr>();

            foreach (var mapDescriptor in mapDescriptors)
            {
                // the BGSequence is only used for mario stadium to animate the Miis playing baseball in the background. As such this will be hardcoded whenever bg004 is selected.
                bgSequenceTable.Add(mapDescriptor.Background == "bg004" ? bgSequenceMarioStadium : VAVAddr.NullAddress);
            }
            return(allocate(bgSequenceTable, "BGSequenceTable"));
        }
示例#7
0
        /// <summary>
        /// Write the subroutine which takes a compressed venture card table as input and writes it into ventureCardDecompressedTableAddr
        /// </summary>
        /// <param name="ventureCardDecompressedTableAddr">The address for the reserved memory space to store the decompressed venture card table in</param>
        private List <UInt32> writeSubroutine(VAVAddr ventureCardDecompressedTableAddr)
        {
            var asm = new List <UInt32>();

            PowerPcAsm.Pair16Bit ventureCardTableAddrPair = PowerPcAsm.make16bitValuePair((UInt32)ventureCardDecompressedTableAddr);
            ///
            /// assume:
            /// r6 = ventureCardCompressedTableAddr
            ///
            /// variables:
            /// r4 = ventureCardId
            /// r5 = ventureCardCompressedTableAddr
            /// r6 = ventureCardDecompressedTableAddr
            /// r7 = ventureCardCompressedWord
            /// r8 = bitIndex
            /// r0 = tmp / currentByte
            ///
            /// return:
            /// r6 = ventureCardDecompressedTableAddr
            ///
            asm.Add(PowerPcAsm.li(4, 0));                                                           // ventureCardId = 0
            asm.Add(PowerPcAsm.mr(5, 6));                                                           // r6 is ventureCardCompressedTableAddr at this point. Copy it to r5 with which we will be working
            asm.Add(PowerPcAsm.lis(6, ventureCardTableAddrPair.upper16Bit));                        // \ load the ventureCardDecompressedTableAddr into r6. This address is
            asm.Add(PowerPcAsm.addi(6, 6, ventureCardTableAddrPair.lower16Bit));                    // /  where we will store the decompressed venture card table.
            int whileVentureCardIdSmaller128 = asm.Count;                                           // do {

            {                                                                                       //
                asm.Add(PowerPcAsm.li(0, 0));                                                       //     \ load the next compressed word from ventureCardCompressedTableAddr
                asm.Add(PowerPcAsm.lwzx(7, 5, 0));                                                  //     /  into r7. We will decompress the venture card table word by word.
                asm.Add(PowerPcAsm.li(8, 31));                                                      //     bitIndex = 31
                int whileBitIndexGreaterEqual32 = asm.Count;                                        //     do
                {                                                                                   //     {
                    asm.Add(PowerPcAsm.mr(0, 7));                                                   //         get the current compressed word
                    asm.Add(PowerPcAsm.srw(0, 0, 8));                                               //         shift it bitIndex times to the right
                    asm.Add(PowerPcAsm.andi(0, 0, 1));                                              //         retrieve the lowest bit of it -> r0 contains the decompressed venture card byte now.
                    asm.Add(PowerPcAsm.stbx(0, 4, 6));                                              //         store it into ventureCardDecompressedTableAddr[ventureCardId]
                    asm.Add(PowerPcAsm.subi(8, 8, 1));                                              //         bitIndex--
                    asm.Add(PowerPcAsm.addi(4, 4, 1));                                              //         ventureCardId++
                    asm.Add(PowerPcAsm.cmpwi(8, 0));                                                //
                    asm.Add(PowerPcAsm.bge(asm.Count, whileBitIndexGreaterEqual32));                //     } while(bitIndex >= 0)
                }                                                                                   //
                asm.Add(PowerPcAsm.addi(5, 5, 4));                                                  //     ventureCardCompressedTableAddr += 4
                asm.Add(PowerPcAsm.cmpwi(4, 128));                                                  //
                asm.Add(PowerPcAsm.blt(asm.Count, whileVentureCardIdSmaller128));                   // } while(ventureCardId < 128)
            }                                                                                       //
            asm.Add(PowerPcAsm.li(4, 0));                                                           // \ reset r4 = 0
            asm.Add(PowerPcAsm.li(5, 0));                                                           // / reset r5 = 0
            asm.Add(PowerPcAsm.blr());                                                              // return

            return(asm);
        }
示例#8
0
        protected string resolveAddressToString(VAVAddr virtualAddress, EndianBinaryReader stream, AddressMapper addressMapper)
        {
            if (virtualAddress == VAVAddr.NullAddress)
            {
                return(null);
            }
            int fileAddress = addressMapper.toFileAddress(virtualAddress);
            var pos         = stream.BaseStream.Position;

            stream.Seek(fileAddress, SeekOrigin.Begin);
            byte[] buff = stream.ReadBytes(64);
            stream.BaseStream.Seek(pos, SeekOrigin.Begin);
            return(HexUtil.byteArrayToString(buff));
        }
        protected string resolveAddressAddressToString(VAVAddr virtualAddressAddress, EndianBinaryReader stream, AddressMapper addressMapper)
        {
            if (virtualAddressAddress == VAVAddr.NullAddress)
            {
                return(null);
            }
            int fileAddress = addressMapper.toFileAddress(virtualAddressAddress);
            var pos         = stream.BaseStream.Position;

            stream.Seek(fileAddress, SeekOrigin.Begin);
            VAVAddr virtualAddress = (VAVAddr)stream.ReadUInt32();

            stream.BaseStream.Seek(pos, SeekOrigin.Begin);
            return(resolveAddressToString(virtualAddress, stream, addressMapper));
        }
        protected VAVAddr writeMapIconPointerTable(List <MapDescriptor> mapDescriptors, Dictionary <string, VAVAddr> iconTableMap)
        {
            var mapIconTable = new List <VAVAddr>();

            foreach (MapDescriptor mapDescriptor in mapDescriptors)
            {
                VAVAddr mapIconAddr = VAVAddr.NullAddress;
                if (mapDescriptor.MapIcon != null)
                {
                    mapIconAddr = iconTableMap[mapDescriptor.MapIcon];
                }
                mapIconTable.Add(mapIconAddr);
            }
            return(allocate(mapIconTable, "MapIconPointerTable"));
        }
        public VAVAddr allocateUnusedSpace(byte[] bytes, EndianBinaryWriter stream, AddressMapper fileMapper, IProgress <ProgressInfo> progress, string purpose)
        {
            if (!string.IsNullOrEmpty(purpose))
            {
                purpose = " for " + purpose;
            }
            startedAllocating = true;
            string str = HexUtil.byteArrayToStringOrHex(bytes);

            if (reuseValues.ContainsKey(bytes))
            {
                progress?.Report(new ProgressInfo("Reuse " + str + " at " + reuseValues[bytes].ToString() + purpose, true));
                return(reuseValues[bytes]);
            }
            else
            {
                VAVAddr end   = findSuitableFreeSpaceBlock(bytes.Length);
                VAVAddr start = remainingFreeSpaceBlocks[end];
                VAVAddr addr  = start;

                VAVAddr newStartPos = start + bytes.Length;
                while (newStartPos % 4 != 0)
                {
                    newStartPos++;
                }
                if (newStartPos > end)
                {
                    newStartPos = end;
                }
                remainingFreeSpaceBlocks[end] = newStartPos;

                stream.Seek(fileMapper.toFileAddress(addr), SeekOrigin.Begin);
                stream.Write(bytes);
                byte[] fillUpToAlign = new byte[(int)(newStartPos - addr - bytes.Length)];
                stream.Write(fillUpToAlign);

                reuseValues.Add(bytes, addr);
                progress?.Report(new ProgressInfo("Allocate " + str + " (" + bytes.Length + " bytes) at " + addr.ToString() + purpose, true));
                return(addr);
            }
        }
        private VAVAddr findLargestFreeSpaceBlock(Dictionary <VAVAddr, VAVAddr> freeSpaceBlocks)
        {
            int     largestFreeSpaceBlockSize = -1;
            VAVAddr largestFreeSpaceBlockEnd  = (VAVAddr)uint.MaxValue;

            foreach (var entry in remainingFreeSpaceBlocks)
            {
                var start = entry.Value;
                var end   = entry.Key;
                int freeSpaceBlockSize = (int)(end - start);
                if (freeSpaceBlockSize > largestFreeSpaceBlockSize)
                {
                    largestFreeSpaceBlockSize = freeSpaceBlockSize;
                    largestFreeSpaceBlockEnd  = end;
                }
            }
            if (largestFreeSpaceBlockEnd == (VAVAddr)uint.MaxValue)
            {
                throw new InsufficientMemoryException("Could not determine the largest free space block.");
            }
            return(largestFreeSpaceBlockEnd);
        }
        private VAVAddr findSuitableFreeSpaceBlock(int requiredSize)
        {
            // search for a suitable free space where it fits best (fill smallest free space blocks first which still hold the space)
            int     smallestFreeSpaceBlockSize = int.MaxValue;
            VAVAddr smallestFreeSpaceBlockEnd  = VAVAddr.MaxValue;

            foreach (var entry in remainingFreeSpaceBlocks)
            {
                var start = entry.Value;
                var end   = entry.Key;
                int freeSpaceBlockSize = (int)(end - start);
                if (freeSpaceBlockSize < smallestFreeSpaceBlockSize && freeSpaceBlockSize >= requiredSize)
                {
                    smallestFreeSpaceBlockSize = freeSpaceBlockSize;
                    smallestFreeSpaceBlockEnd  = end;
                }
            }
            if (smallestFreeSpaceBlockEnd == VAVAddr.MaxValue)
            {
                throw new InsufficientMemoryException("Could not find a suitable free space block in the main.dol to allocate " + requiredSize + " bytes.");
            }
            return(smallestFreeSpaceBlockEnd);
        }
        private List <UInt32> writeSubroutineMakeNoneMapIconsInvisible(AddressMapper addressMapper, VAVAddr entryAddr, VAVAddr returnContinueAddr, VAVAddr returnMakeInvisibleAddr)
        {
            var Scene_Layout_Obj_SetVisible = addressMapper.toVersionAgnosticAddress((BSVAddr)0x8006f854);
            // precondition:  r31  MapIconButton*
            //                 r5  is unused
            // postcondition:  r0  is map icon type
            //                 r5  is 0
            var asm = new List <UInt32>();

            asm.Add(PowerPcAsm.lwz(5, 0x188, 31));                                     // get current map id into r5
            asm.Add(PowerPcAsm.cmpwi(5, -1));                                          // map id == -1 ?
            asm.Add(PowerPcAsm.bne(8));                                                // {
            asm.Add(PowerPcAsm.lwz(3, 0x28, 31));                                      //   \ 
            asm.Add(PowerPcAsm.li(5, 0));                                              //   |
            asm.Add(PowerPcAsm.lwz(4, -0x6600, 13));                                   //   | make "NEW" text invisible
            asm.Add(PowerPcAsm.bl(entryAddr, asm.Count, Scene_Layout_Obj_SetVisible)); //   /
            asm.Add(PowerPcAsm.lwz(3, 0x28, 31));                                      //   \ 
            asm.Add(PowerPcAsm.li(5, 0));                                              //   / make Locked Map Icon "(?)" invisible
            asm.Add(PowerPcAsm.b(entryAddr, asm.Count, returnMakeInvisibleAddr));      //   returnMakeInvisibleAddr
                                                                                       // } else {
            asm.Add(PowerPcAsm.lwz(0, 0x184, 3));                                      //   get map icon type (replaced opcode)
            asm.Add(PowerPcAsm.b(entryAddr, asm.Count, returnContinueAddr));           //   returnContinueAddr
                                                                                       // }
            return(asm);
        }
        private List <UInt32> writeSubroutineInitMapIdsForMapIcons(AddressMapper addressMapper, VAVAddr entryAddr)
        {
            var JUtility_memset = addressMapper.toVersionAgnosticAddress((BSVAddr)0x80004714);
            // precondition: r3 is newly created map icon array
            //               r16 is the amount of map ids in the array (size / 4)
            //               r24 is unused
            // postcondition: r24 is the map icon array
            var asm = new List <UInt32>();

            asm.Add(PowerPcAsm.mflr(24));                                     // save the link register
            asm.Add(PowerPcAsm.li(4, -1));                                    // fill with 0xff
            asm.Add(PowerPcAsm.rlwinm(5, 16, 0x3, 0x0, 0x1d));                // get the size of the array
            asm.Add(PowerPcAsm.bl(entryAddr, asm.Count, JUtility_memset));    // call JUtility_memset(array*, 0xff, array.size)
            asm.Add(PowerPcAsm.mtlr(24));                                     // restore the link register
            asm.Add(PowerPcAsm.mr(24, 3));                                    // move array* to r24
            asm.Add(PowerPcAsm.blr());                                        // return
            return(asm);
        }
        private List <UInt32> writeSubroutineSkipMapUnlockCheck(AddressMapper addressMapper, VAVAddr entryAddr, VAVAddr returnContinueAddr, VAVAddr returnSkipMapUnlockedCheck)
        {
            // precondition:  r26  is mapid
            //                 r3  is unused
            // postcondition:  r3  is mapid
            var asm = new List <UInt32>();

            asm.Add(PowerPcAsm.or(3, 26, 26));                                         // r3 <- mapid
            asm.Add(PowerPcAsm.cmpwi(3, -1));                                          // mapid == -1 ?
            asm.Add(PowerPcAsm.beq(entryAddr, asm.Count, returnSkipMapUnlockedCheck)); //   goto skipMapUnlockedCheck
            asm.Add(PowerPcAsm.b(entryAddr, asm.Count, returnContinueAddr));           // else goto returnContinueAddr
            return(asm);
        }
示例#17
0
 public static UInt32 beq(VAVAddr startPos, int offset, VAVAddr targetPos)
 {
     return(beq((uint)(startPos + offset * 4), (uint)targetPos));
 }
        private List <UInt32> writeProcStopEventSquareRoutine(AddressMapper addressMapper, VAVAddr forceVentureCardVariable, VAVAddr routineStartAddress)
        {
            PowerPcAsm.Pair16Bit v            = PowerPcAsm.make16bitValuePair((UInt32)forceVentureCardVariable);
            var gameProgressChangeModeRoutine = addressMapper.toVersionAgnosticAddress((BSVAddr)0x800c093c);
            var endOfSwitchCase = addressMapper.toVersionAgnosticAddress((BSVAddr)0x800fac38);

            var asm = new List <UInt32>();

            asm.Add(PowerPcAsm.lwz(3, 0x188, 28));                                                 // \
            asm.Add(PowerPcAsm.lwz(3, 0x74, 3));                                                   // / r3_place = gameChara.currentPlace
            asm.Add(PowerPcAsm.lbz(6, 0x18, 3));                                                   // | r6_ventureCardId = r3_place.districtId

            asm.Add(PowerPcAsm.lis(3, v.upper16Bit));                                              // \
            asm.Add(PowerPcAsm.addi(3, 3, v.lower16Bit));                                          // | forceVentureCardVariable <- r6_ventureCardId
            asm.Add(PowerPcAsm.stw(6, 0x0, 3));                                                    // /

            asm.Add(PowerPcAsm.lwz(3, 0x18, 20));                                                  // \ lwz r3,0x18(r20)
            asm.Add(PowerPcAsm.li(4, 0x1f));                                                       // | li r4,0x1f  (the GameProgress mode id 0x1f is for executing a venture card)
            asm.Add(PowerPcAsm.li(5, -0x1));                                                       // | li r5,-0x1
            asm.Add(PowerPcAsm.li(6, -0x1));                                                       // | li r6,-0x1
            asm.Add(PowerPcAsm.li(7, 0x0));                                                        // | li r7,0x0
            asm.Add(PowerPcAsm.bl(routineStartAddress, asm.Count, gameProgressChangeModeRoutine)); // | bl Game::GameProgress::changeMode
            asm.Add(PowerPcAsm.b(routineStartAddress, asm.Count, endOfSwitchCase));                // / goto end of switch case
            return(asm);
        }
        protected override void writeAsm(EndianBinaryWriter stream, AddressMapper addressMapper, List <MapDescriptor> mapDescriptors)
        {
            var mapIcons = writeIconStrings(mapDescriptors);
            Dictionary <string, VAVAddr> iconTableMap;
            VAVAddr iconTableAddr       = writeIconTable(mapIcons, out iconTableMap);
            VAVAddr mapIconPointerTable = writeMapIconPointerTable(mapDescriptors, iconTableMap);
            ushort  iconCount           = (ushort)iconTableMap.Count;
            short   tableRowCount       = (short)mapDescriptors.Count;

            PowerPcAsm.Pair16Bit v = PowerPcAsm.make16bitValuePair((UInt32)iconTableAddr);
            PowerPcAsm.Pair16Bit w = PowerPcAsm.make16bitValuePair((UInt32)mapIconPointerTable);
            // note: To add custom icons, the following files need to be editted as well:
            // - ui_menu_19_00a.brlyt within game_sequence.arc and within game_sequence_wifi.arc
            // - ui_menu_19_00a_Tag_*.brlan within game_sequence.arc and within game_sequence_wifi.arc

            // custom map icon hack (change it that way that it will call the GetMapDifficulty routine instead of the GetMapOrigin routine
            // the GetMapDifficulty routine is mostly unused by the game and we repurpose it to return the pointer to the pointer of the string of the map icon instead
            // then we go through all map icon pointer pointers and check if it is the same as the one retrieved. If it is then we make it visible, otherwise we set the visibility to false.
            var GetMapDifficulty = addressMapper.toVersionAgnosticAddress((BSVAddr)0x80211da4);

            // bl GetMapOrigin                                     -> bl GetMapDifficulty
            var offset = addressMapper.toVersionAgnosticAddress((BSVAddr)0x8021e77c);

            stream.Seek(addressMapper.toFileAddress(offset), SeekOrigin.Begin); stream.Write(PowerPcAsm.bl(offset, GetMapDifficulty));
            // cmpw r28,r30                                        -> cmpw r29,r30
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8021e790), SeekOrigin.Begin); stream.Write(PowerPcAsm.cmpw(29, 30));
            // cmplwi r28,0x12                                     -> cmplwi r28,iconCount
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8021e7c0), SeekOrigin.Begin); stream.Write(PowerPcAsm.cmplwi(28, iconCount));
            // bl GetMapOrigin                                     -> bl GetMapDifficulty
            offset = addressMapper.toVersionAgnosticAddress((BSVAddr)0x8021e8a4);
            stream.Seek(addressMapper.toFileAddress(offset), SeekOrigin.Begin); stream.Write(PowerPcAsm.bl(offset, GetMapDifficulty));
            // cmpw r29,r28                                        -> cmpw r30,r28
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8021e8b8), SeekOrigin.Begin); stream.Write(PowerPcAsm.cmpw(30, 28));
            // cmplwi r29,0x12                                     -> cmplwi r29,iconCount
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8021e8e8), SeekOrigin.Begin); stream.Write(PowerPcAsm.cmplwi(29, iconCount));
            // bl GetMapOrigin                                     -> bl GetMapDifficulty
            offset = addressMapper.toVersionAgnosticAddress((BSVAddr)0x8021e824);
            stream.Seek(addressMapper.toFileAddress(offset), SeekOrigin.Begin); stream.Write(PowerPcAsm.bl(offset, GetMapDifficulty));
            // cmplwi r28,0x12                                     -> cmplwi r28,iconCount
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8021e84c), SeekOrigin.Begin); stream.Write(PowerPcAsm.cmplwi(28, iconCount));
            // r29 <- 0x8047f5c0                                   -> r29 <- iconTableAddr
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8021e780), SeekOrigin.Begin); stream.Write(PowerPcAsm.lis(29, v.upper16Bit)); stream.Seek(4, SeekOrigin.Current); stream.Write(PowerPcAsm.addi(29, 29, v.lower16Bit));
            // r30 <- 0x8047f5c0                                   -> r30 <- iconTableAddr
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8021e8a8), SeekOrigin.Begin); stream.Write(PowerPcAsm.lis(30, v.upper16Bit)); stream.Seek(4, SeekOrigin.Current); stream.Write(PowerPcAsm.addi(30, 30, v.lower16Bit));
            // r30 <- 0x8047f5c0                                   -> r30 <- iconTableAddr
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8021e828), SeekOrigin.Begin); stream.Write(PowerPcAsm.lis(30, v.upper16Bit)); stream.Seek(4, SeekOrigin.Current); stream.Write(PowerPcAsm.addi(30, 30, v.lower16Bit));
            // mr r3,r28                                           -> mr r3,r26
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8021e94c), SeekOrigin.Begin); stream.Write(PowerPcAsm.mr(3, 26));
            // mr r3,r28                                           -> mr r3,r26
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x8021e968), SeekOrigin.Begin); stream.Write(PowerPcAsm.mr(3, 26));

            // Modify the GetMapDifficulty routine to retrieve the current map icon addr addr
            // subi r31,r3,0x15                                   ->  nop
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80211dc8), SeekOrigin.Begin); stream.Write(PowerPcAsm.nop());
            // cmpwi r31,0x12                                     ->  cmpwi r31,tableRowCount
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80211dd4), SeekOrigin.Begin); stream.Write(PowerPcAsm.cmpwi(31, tableRowCount));
            // li r3,0x15                                         ->  nop
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80211e4c), SeekOrigin.Begin); stream.Write(PowerPcAsm.nop());
            // mulli r4,r3,0x24                                   ->  mulli r4,r3,0x04
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80211e58), SeekOrigin.Begin); stream.Write(PowerPcAsm.mulli(4, 3, 0x04));
            // r3 <- 804363c8                                     ->  r3 <- mapIconPointerTable
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80211e5c), SeekOrigin.Begin); stream.Write(PowerPcAsm.lis(3, w.upper16Bit)); stream.Write(PowerPcAsm.addi(3, 3, w.lower16Bit));
            // mulli r0,r31,0x24                                  ->  mulli r0,r31,0x04
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80211e64), SeekOrigin.Begin); stream.Write(PowerPcAsm.mulli(0, 31, 0x04));
            // lwz r3,0x1c(r3)                                    ->  lwz r3,0x0(r3)
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80211e78), SeekOrigin.Begin); stream.Write(PowerPcAsm.lwz(3, 0x0, 3));

            // --- Hack to make icons invisible which do not have a map ---
            // -- Init Maps in the map array with -1 --
            var subroutineInitMapIdsForMapIcons = allocate(writeSubroutineInitMapIdsForMapIcons(addressMapper, VAVAddr.NullAddress), "SubroutineInitMapIdsForMapIcons");

            stream.Seek(addressMapper.toFileAddress(subroutineInitMapIdsForMapIcons), SeekOrigin.Begin);
            stream.Write(writeSubroutineInitMapIdsForMapIcons(addressMapper, subroutineInitMapIdsForMapIcons)); // re-write the routine again since now we know where it is located in the main dol
            // increase the array size
            // rlwinm r3,r16,0x2,0x0,0x1d                            -> r3,r16,0x3,0x0,0x1d
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80187794), SeekOrigin.Begin); stream.Write(PowerPcAsm.rlwinm(3, 16, 0x3, 0x0, 0x1d));
            var hijackAddr = addressMapper.toVersionAgnosticAddress((BSVAddr)0x8018779c);

            // cmpwi r3,0x0                                          ->  bl subroutineInitMapIdsForMapIcons
            stream.Seek(addressMapper.toFileAddress(hijackAddr), SeekOrigin.Begin); stream.Write(PowerPcAsm.bl(hijackAddr, subroutineInitMapIdsForMapIcons));
            // mr r24,r3                                             ->  cmpwi r3,0x0
            stream.Write(PowerPcAsm.cmpwi(3, 0));
            // increase the array size
            // rlwinm r3,r16,0x2,0x0,0x1d                            -> r3,r16,0x3,0x0,0x1d
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80187aa4), SeekOrigin.Begin); stream.Write(PowerPcAsm.rlwinm(3, 16, 0x3, 0x0, 0x1d));
            hijackAddr = addressMapper.toVersionAgnosticAddress((BSVAddr)0x80187aac);
            // cmpwi r3,0x0                                          ->  bl subroutineInitMapIdsForMapIcons
            stream.Seek(addressMapper.toFileAddress(hijackAddr), SeekOrigin.Begin); stream.Write(PowerPcAsm.bl(hijackAddr, subroutineInitMapIdsForMapIcons));
            // mr r24,r3                                             ->  cmpwi r3,0x0
            stream.Write(PowerPcAsm.cmpwi(3, 0));
            // -- if a map id is -1, make the map icon invisible --
            hijackAddr = addressMapper.toVersionAgnosticAddress((BSVAddr)0x8021e73c);
            var returnContinueAddr                  = addressMapper.toVersionAgnosticAddress((BSVAddr)0x8021e740);
            var returnMakeInvisibleAddr             = addressMapper.toVersionAgnosticAddress((BSVAddr)0x8021e808);
            var subroutineMakeNoneMapIconsInvisible = allocate(writeSubroutineMakeNoneMapIconsInvisible(addressMapper, VAVAddr.NullAddress, returnContinueAddr, returnMakeInvisibleAddr), "SubroutineMakeNoneMapIconsInvisibleMultiplayer");

            stream.Seek(addressMapper.toFileAddress(subroutineMakeNoneMapIconsInvisible), SeekOrigin.Begin);
            stream.Write(writeSubroutineMakeNoneMapIconsInvisible(addressMapper, subroutineMakeNoneMapIconsInvisible, returnContinueAddr, returnMakeInvisibleAddr)); // re-write the routine again since now we know where it is located in the main dol
            // lwz r0,0x184(r3)                                      ->  b subroutineMakeNoneMapIconsInvisible
            stream.Seek(addressMapper.toFileAddress(hijackAddr), SeekOrigin.Begin); stream.Write(PowerPcAsm.b(hijackAddr, subroutineMakeNoneMapIconsInvisible));

            // -- if the map id is -1, do not check if it has been unlocked or not ---
            hijackAddr         = addressMapper.toVersionAgnosticAddress((BSVAddr)0x8021e570);
            returnContinueAddr = addressMapper.toVersionAgnosticAddress((BSVAddr)0x8021e574);
            var returnSkipMapUnlockedCheck = addressMapper.toVersionAgnosticAddress((BSVAddr)0x8021e5a8);
            var subroutineWriteSubroutineSkipMapUnlockCheck = allocate(writeSubroutineSkipMapUnlockCheck(addressMapper, VAVAddr.NullAddress, returnContinueAddr, returnSkipMapUnlockedCheck), "SubroutineWriteSubroutineSkipMapUnlockCheck");

            stream.Seek(addressMapper.toFileAddress(subroutineWriteSubroutineSkipMapUnlockCheck), SeekOrigin.Begin);
            stream.Write(writeSubroutineSkipMapUnlockCheck(addressMapper, subroutineWriteSubroutineSkipMapUnlockCheck, returnContinueAddr, returnSkipMapUnlockedCheck)); // re-write the routine again since now we know where it is located in the main dol
            // or r3,r26,r26                                      ->  b subroutineWriteSubroutineSkipMapUnlockCheck
            stream.Seek(addressMapper.toFileAddress(hijackAddr), SeekOrigin.Begin); stream.Write(PowerPcAsm.b(hijackAddr, subroutineWriteSubroutineSkipMapUnlockCheck));

            // --- Various Map UI Fixes ---
            // -- if the map index is over the map array size, do not loop around to the first map index again --
            // ble 0x80187e1c                                        ->  b 0x80187e1c
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80187dfc), SeekOrigin.Begin); stream.Write(PowerPcAsm.b(8));
            // -- fix map selection going out of bounds in tour mode --
            // bne 0x80188258                                        ->  nop
            stream.Seek(addressMapper.toFileAddress((BSVAddr)0x80188230), SeekOrigin.Begin); stream.Write(PowerPcAsm.nop());
        }
示例#20
0
 public int toFileAddress(VAVAddr versionAddress)
 {
     return((int)fileMapper.map((long)versionAddress));
 }
示例#21
0
 public bool canConvertToFileAddress(VAVAddr versionAddress)
 {
     return(fileMapper.findSection((long)versionAddress) != null);
 }
        private List <UInt32> writeRuleSetFromMapRoutine(AddressMapper addressMapper, VAVAddr routineStartAddress)
        {
            var Game_GetRuleFlag = addressMapper.toVersionAgnosticAddress((BSVAddr)0x801cca98);

            // precondition: r24 is mapId
            // precondition: r25 is global rule set which we are gonna use to store the linkreturn
            var asm = new List <UInt32>();

            asm.Add(PowerPcAsm.mflr(25));
            asm.Add(PowerPcAsm.mr(3, 24));                                             // r3 <- r24
            asm.Add(PowerPcAsm.bl(routineStartAddress, asm.Count, Game_GetRuleFlag));  // r3 <- bl Game_GetRuleFlag(r3)
            asm.Add(PowerPcAsm.stw(3, 0x53f4, 29));                                    // gameRule <- r3
            asm.Add(PowerPcAsm.mtlr(25));
            asm.Add(PowerPcAsm.blr());                                                 // return
            return(asm);
        }
        private List <UInt32> writeSubroutineGetMapsInZone(AddressMapper addressMapper, List <MapDescriptor> mapDescriptors, VAVAddr mapSetZoneOrderTable, VAVAddr entryAddr, VAVAddr returnAddr)
        {
            PowerPcAsm.Pair16Bit v = PowerPcAsm.make16bitValuePair((UInt32)mapSetZoneOrderTable);
            // precondition:  r5  MapSet
            //               r29  _ZONE_TYPE
            //               r30  int* array containing map ids
            //                r3,r4,r6,r7,r31  unused
            // postcondition: r3  num maps (must be same as in SubroutineGetNumMapsInZone)
            var asm    = new List <UInt32>();
            var asm_l2 = new List <UInt32>();
            var asm_l3 = new List <UInt32>();

            asm.Add(PowerPcAsm.li(3, 0));
            var mapSets = (from m in mapDescriptors where m.MapSet != -1 orderby m.MapSet select m.MapSet).Distinct();

            foreach (var mapSet in mapSets)
            {
                asm.Add(PowerPcAsm.cmpwi(5, mapSet));
                var zones = (from m in mapDescriptors where m.MapSet == mapSet && m.Zone != -1 orderby m.Zone select m.Zone).Distinct();
                asm_l2.Clear();
                foreach (var zone in zones)
                {
                    asm_l2.Add(PowerPcAsm.cmpwi(29, zone));
                    IOrderedEnumerable <MapDescriptor> maps;
                    if (zone == 0)
                    {
                        maps = from m in mapDescriptors where m.MapSet == mapSet && m.Zone == 1 orderby m.Order select m;
                    }
                    else if (zone == 1)
                    {
                        maps = from m in mapDescriptors where m.MapSet == mapSet && m.Zone == 0 orderby m.Order select m;
                    }
                    else
                    {
                        maps = from m in mapDescriptors where m.MapSet == mapSet && m.Zone == zone orderby m.Order select m;
                    }
                    short i = 0;
                    asm_l3.Clear();
                    asm_l3.Add(PowerPcAsm.li(3, (short)maps.Count()));
                    foreach (var map in maps)
                    {
                        short mapId         = (short)mapDescriptors.IndexOf(map);
                        var   mapDescriptor = mapDescriptors[i];
                        asm_l3.Add(PowerPcAsm.li(4, mapId));
                        asm_l3.Add(PowerPcAsm.stw(4, i, 30));
                        i += 4;
                    }
                    asm_l2.Add(PowerPcAsm.bne(asm_l3.Count + 1));
                    asm_l2.AddRange(asm_l3);
                }
                asm.Add(PowerPcAsm.bne(asm_l2.Count + 1));
                asm.AddRange(asm_l2);
            }
            asm.Add(PowerPcAsm.b(entryAddr, asm.Count, returnAddr));
            return(asm);
        }
示例#24
0
 public static UInt32 b(VAVAddr startPos, VAVAddr targetPos)
 {
     return(b(startPos, 0, targetPos));
 }
        private List <UInt32> writeUploadSimulatedButtonPress(AddressMapper addressMapper, VAVAddr routineStartAddress, VAVAddr returnAddr)
        {
            var asm = new List <UInt32>();
            // 0x804363b4 (4 bytes): force simulated button press
            var forceSimulatedButtonPress = PowerPcAsm.make16bitValuePair((UInt32)addressMapper.toVersionAgnosticAddress((BSVAddr)0x804363b4));
            var pressedButtonsBitArray    = PowerPcAsm.make16bitValuePair((UInt32)addressMapper.toVersionAgnosticAddress((BSVAddr)0x8078C880));

            asm.Add(PowerPcAsm.lis(6, forceSimulatedButtonPress.upper16Bit));                // \
            asm.Add(PowerPcAsm.addi(6, 6, forceSimulatedButtonPress.lower16Bit));            // / r6 <- &forceSimulatedButtonPress
            asm.Add(PowerPcAsm.lis(7, pressedButtonsBitArray.upper16Bit));                   // \
            asm.Add(PowerPcAsm.addi(7, 7, pressedButtonsBitArray.lower16Bit));               // / r7 <- &pressedButtonsBitArray
            asm.Add(PowerPcAsm.lwz(0, 0x0, 6));                                              // r0 <- forceSimulatedButtonPress
            asm.Add(PowerPcAsm.cmpwi(0, 0x0));                                               // if (forceSimulatedButtonPress != 0)
            asm.Add(PowerPcAsm.beq(4));                                                      // {
            asm.Add(PowerPcAsm.stw(0, 0x0, 7));                                              //   pressedButtonsBitArray <- forceSimulatedButtonPress
            asm.Add(PowerPcAsm.li(0, 0x0));                                                  //   \ 
            asm.Add(PowerPcAsm.stw(0, 0x0, 6));                                              //   / forceSimulatedButtonPress <- 0
                                                                                             // }
            asm.Add(PowerPcAsm.lwz(0, 0x4, 3));                                              // *replaced opcode*
            asm.Add(PowerPcAsm.b(routineStartAddress, asm.Count, returnAddr));               // return

            return(asm);
        }
        private List <UInt32> writeGetDescriptionForCustomSquareRoutine(AddressMapper addressMapper, VAVAddr routineStartAddress)
        {
            var asm = new List <UInt32>();
            var gameUiTextGetString  = addressMapper.toVersionAgnosticAddress((BSVAddr)0x800f78dc);
            var gameUiTextGetCardMsg = addressMapper.toVersionAgnosticAddress((BSVAddr)0x800f837c);
            var gameBoard            = PowerPcAsm.make16bitValuePair((UInt32)addressMapper.toVersionAgnosticAddress((BSVAddr)0x8054d018));

            asm.Add(PowerPcAsm.lis(7, gameBoard.upper16Bit));                                //
            asm.Add(PowerPcAsm.addi(7, 7, gameBoard.lower16Bit));                            // r7 <- start of gameboard table containing all squares
            asm.Add(PowerPcAsm.mulli(8, 24, 0x54));                                          // r8 <- squareId * 0x54 (the size of each square)
            asm.Add(PowerPcAsm.add(6, 7, 8));                                                // r6 <- the current square
            asm.Add(PowerPcAsm.lbz(8, 0x4d, 6));                                             // r8 <- square.squareType
            asm.Add(PowerPcAsm.cmpwi(8, 0x2e));                                              // if(square.squareType == 0x2e)
            asm.Add(PowerPcAsm.bne(3));                                                      // {
            asm.Add(PowerPcAsm.lbz(4, 0x18, 6));                                             //   r4 <- square.district_color
            asm.Add(PowerPcAsm.b(routineStartAddress, asm.Count, gameUiTextGetCardMsg));     //   goto Game::uitext::get_card_message(r4)
                                                                                             // }
            asm.Add(PowerPcAsm.li(6, 0x0));                                                  // \
            asm.Add(PowerPcAsm.li(7, 0x0));                                                  // | No message arguments
            asm.Add(PowerPcAsm.li(8, 0x0));                                                  // /
            asm.Add(PowerPcAsm.b(routineStartAddress, asm.Count, gameUiTextGetString));      // goto Game::uitext::get_string(r4, 0, 0, 0)

            return(asm);
        }