Beispiel #1
0
        /// <summary>
        /// This method is called when attempting to remove a param value that once pointed to another location (Pointer type) that MIGHT be an external subroutine call
        /// <para>If it is determined to be a call to an external subroutine, the external subroutine data table is updated to no longer pointer to it</para>
        /// </summary>
        /// <param name="removedPsaCommand">The psa command being removed</param>
        /// <param name="commandParamPointerValueLocation">The pointer to the param's value location</param>
        private void UpdateExternalPointerLogic(PsaCommand removedPsaCommand, int commandParamPointerValueLocation)
        {
            // iterate through each external subroutine in the external data table
            for (int externalSubRoutineIndex = 0; externalSubRoutineIndex < PsaFile.NumberOfExternalSubRoutines; externalSubRoutineIndex++)
            {
                // get a external subroutine's pointer
                int externalSubRoutineLocationIndex = (PsaFile.NumberOfDataTableEntries + externalSubRoutineIndex) * 2;
                int externalSubRoutineLocation      = PsaFile.DataTableSections[externalSubRoutineLocationIndex];
                if (externalSubRoutineLocation >= 8096 && externalSubRoutineLocation < PsaFile.DataSectionSize)
                {
                    // if the param being removed was pointing to an external subroutine
                    if (commandParamPointerValueLocation == externalSubRoutineLocation)
                    {
                        // get the location of the value of the param
                        int commandExternalSubroutineValueLocation = commandParamPointerValueLocation / 4;

                        // This stops the external data table from pointing to the command param pointer value location
                        if (PsaFile.DataSection[commandExternalSubroutineValueLocation] >= 8096 &&
                            PsaFile.DataSection[commandExternalSubroutineValueLocation] < PsaFile.DataSectionSize &&
                            PsaFile.DataSection[commandExternalSubroutineValueLocation] % 4 == 0)
                        {
                            PsaFile.DataTableSections[externalSubRoutineLocationIndex] = PsaFile.DataSection[commandExternalSubroutineValueLocation];
                        }
                        else
                        {
                            PsaFile.DataTableSections[externalSubRoutineLocationIndex] = -1;
                        }
                        break;
                    }

                    // same deal as above for the most part, but I am NOT sure what location "externalSubRoutineCodeBlockLocation" actually is (I don't think it's right currently)
                    // it's tough to test further because I also can't really figure out how to get this code to trigger at the moment, so I'm just going to leave this as is
                    int externalSubRoutineCodeBlockLocation = externalSubRoutineLocation / 4;

                    int externalSubRoutineCommandsPointerLocation = PsaFile.DataSection[externalSubRoutineCodeBlockLocation];
                    if (externalSubRoutineCommandsPointerLocation >= 8096 &&
                        externalSubRoutineCommandsPointerLocation < PsaFile.DataSectionSize &&
                        removedPsaCommand.CommandParametersLocation == externalSubRoutineCommandsPointerLocation)
                    {
                        int commandExternalDataPointerValue = removedPsaCommand.GetCommandParameterValueLocation(0);
                        if (PsaFile.DataSection[commandExternalDataPointerValue] >= 8096 &&
                            PsaFile.DataSection[commandExternalDataPointerValue] < PsaFile.DataSectionSize &&
                            PsaFile.DataSection[commandExternalDataPointerValue] % 4 == 0)
                        {
                            PsaFile.DataTableSections[externalSubRoutineCodeBlockLocation] = PsaFile.DataSection[commandExternalDataPointerValue];
                        }
                        else
                        {
                            PsaFile.DataTableSections[externalSubRoutineCodeBlockLocation] = -1;
                        }
                        break;
                    }
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Modify a command with existing parameters
        /// <para>Case 1: both old and new command have same number of parameters, which is an easy params replace 1 by 1</para>
        /// <para>Case 2: new command has less params than old command, which is the same as case 1, but the unused param space needs to be converted to free space (FADEF00D)</para>
        /// <para>Case 3: new command has more params than old command, which will result in finding a new location for the parameters that has enough space</para>
        /// </summary>
        /// <param name="commandLocation">The location of the command in the code block</param>
        /// <param name="oldPsaCommand">The old psa command (the one that is being modified)</param>
        /// <param name="newPsaCommand">The new psa command (the one that is replcaing the old psa command)</param>
        private void ModifyExistingCommandParametersLocation(int commandLocation, PsaCommand oldPsaCommand, PsaCommand newPsaCommand)
        {
            // If modifying a command that pointed to another location (the "Pointer" param type), the pointer location needs to be removed from the offset interlock tracker
            // If the pointer param was an external subroutine (from the external data table) (such as Mario's Up B, the item ones like the home run bat, etc),
            // some additional work needs to be done to remove references to it from the external data table
            // This if statement checks if the first parameter is of type Pointer or the second, which matches commands like "goto", "subroutine", and "concurrent subroutine"
            if (PsaFile.DataSection[oldPsaCommand.CommandParametersValuesLocation] == 2 ||
                (PsaFile.DataSection[oldPsaCommand.CommandParametersValuesLocation + 2] == 2 && oldPsaCommand.NumberOfParams == 2))
            {
                // Get the pointer location of the param value that is currently pointing to another location
                int commandParamPointerValueLocation = PsaFile.DataSection[oldPsaCommand.CommandParametersValuesLocation] == 2
                    ? oldPsaCommand.CommandParametersLocation + 4
                    : oldPsaCommand.CommandParametersLocation + 12;

                // Attempt to remove the above offset from the offset interlock tracker
                bool wasOffsetRemoved = PsaFileHelperMethods.RemoveOffsetFromOffsetInterlockTracker(commandParamPointerValueLocation);

                // If offset was not successfully removed, it means it either doesn't exist or is an external subroutine
                // The below method call UpdateExternalPointerLogic will do some necessary work if the offset turns out to be an external subroutine call
                if (!wasOffsetRemoved)
                {
                    UpdateExternalPointerLogic(oldPsaCommand, commandParamPointerValueLocation);
                }
            }

            // Replace old param values with free space (FADEF00D)
            for (int paramIndex = 0; paramIndex < oldPsaCommand.NumberOfParams; paramIndex++)
            {
                int commandParameterTypeLocation  = oldPsaCommand.GetCommandParameterTypeLocation(paramIndex);
                int commandParameterValueLocation = oldPsaCommand.GetCommandParameterValueLocation(paramIndex);
                PsaFile.DataSection[commandParameterTypeLocation]  = Constants.FADEF00D;
                PsaFile.DataSection[commandParameterValueLocation] = Constants.FADEF00D;
            }

            // set new command instruction
            PsaFile.DataSection[commandLocation] = newPsaCommand.Instruction;

            // if new command has no parameters, set pointer to parameters to nothing (which is 0) and remove the pointer to the parameters from the offset interlock
            if (newPsaCommand.NumberOfParams == 0)
            {
                // remove pointer to params since this command has no params
                PsaFile.DataSection[commandLocation + 1] = 0;

                // remove offset from interlock tracker since it no longer exists
                int commandParametersPointerLocation = commandLocation * 4 + 4;
                PsaFileHelperMethods.RemoveOffsetFromOffsetInterlockTracker(commandParametersPointerLocation);
            }

            // if new command has parameters
            else
            {
                // if new command has a less or equal parameter count to the old command, the parameter values location does not need to be relocated
                // if the new command has a higher parameter count than the old command, the paramter values location will need to be expanded/relocated to have enough room for all the parameters
                int newCommandParametersValuesLocation = oldPsaCommand.NumberOfParams >= newPsaCommand.NumberOfParams
                    ? oldPsaCommand.CommandParametersValuesLocation
                    : ExpandCommandParametersSection(oldPsaCommand, newPsaCommand);

                PsaFile.DataSection[commandLocation + 1] = newCommandParametersValuesLocation * 4;


                // put param values in new param values location one by one
                for (int paramIndex = 0; paramIndex < newPsaCommand.NumberOfParams; paramIndex++)
                {
                    int paramTypeLocation  = paramIndex * 2;
                    int paramValueLocation = paramIndex * 2 + 1;

                    // if command param type is Pointer and it actually points to something
                    if (newPsaCommand.Parameters[paramIndex].Type == 2 && newPsaCommand.Parameters[paramIndex].Value > 0)
                    {
                        // I believe this points to the location of the param value (if the param is a pointer)
                        int commandParameterPointerValueLocation = (newCommandParametersValuesLocation + paramTypeLocation) * 4 + 4;
                        PsaFile.OffsetSection.Add(commandParameterPointerValueLocation);
                    }

                    // place parameter type in value in proper place
                    PsaFileHelperMethods.SetDataSectionValue(newCommandParametersValuesLocation + paramTypeLocation, newPsaCommand.Parameters[paramIndex].Type);
                    PsaFileHelperMethods.SetDataSectionValue(newCommandParametersValuesLocation + paramValueLocation, newPsaCommand.Parameters[paramIndex].Value);
                }
            }
        }