Esempio n. 1
0
        static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions)
        {
            bool patchComplete = false;
            var  ilcodes       = new List <CodeInstruction>(instructions);

            for (int i = 0; i < ilcodes.Count; i++)
            {
                if (PatchHelpers.InstructionsAreEqual(ilcodes[i], TargetInstruction))
                {
                    if (ilcodes[i - 2].opcode == OpCodes.Br)
                    {
                        object jumpTarget = ilcodes[i - 2].operand;
                        List <CodeInstruction> optionSwitch = PatchHelpers.ILBlocks.IfOptionYesJumpTo(Options.Exploration.OptionStrings.DisableMagnets, jumpTarget);

                        //clone and then null out this instruction, preserving the jump label here
                        CodeInstruction shiftedInstruction = ilcodes[i - 1].Clone();
                        ilcodes[i - 1].opcode  = OpCodes.Nop;
                        ilcodes[i - 1].operand = null;

                        //insert our option checking code next after the Nop/label
                        ilcodes.InsertRange(i, optionSwitch);

                        //reinsert the cloned instruction we copied earlier (now without a label)
                        ilcodes.Insert(i + optionSwitch.Count, shiftedInstruction);

                        patchComplete = true;
                        break;
                    }
                }
            }
            if (patchComplete)
            {
                PatchHelpers.LogPatchResult("MagneticPulse",
                                            "Patched successfully." /* Enables option to prevent pulsed field magnets from ripping items from your inventory. */);
            }
            else
            {
                PatchHelpers.LogPatchResult("MagneticPulse",
                                            "Failed. This patch may not be compatible with the current game version. "
                                            + "The option to prevent pulsed field magnets from ripping items from your inventory won't work.");
            }
            return(ilcodes.AsEnumerable());
        }
Esempio n. 2
0
        static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions)
        {
            int             idx          = 0;
            int             gap          = 0;
            int             patchSegment = 1;
            bool            found        = false;
            CodeInstruction instruction_LoadLocal_AbilityNodeArray = null;
            CodeInstruction instruction_LoadLocal_AbilityNodeIndex = null;
            CodeInstruction instruction_LoadLocal_TextBlock        = null;
            bool            patchComplete = false;

            foreach (var instruction in instructions)
            {
                if (found)
                {
                    if (patchSegment == 1)
                    {
                        if (idx == 0 && instruction.opcode == OpCodes.Brfalse_S)
                        {
                            idx++;
                            //do nothing, we're just confirming the expected instruction is here
                        }
                        else if (idx == 1 && PatchHelpers.IsLoadLocalInstruction(instruction))
                        {
                            instruction_LoadLocal_AbilityNodeArray = instruction.Clone();
                            idx++;
                        }
                        else if (idx == 2 && PatchHelpers.IsLoadLocalInstruction(instruction))
                        {
                            instruction_LoadLocal_AbilityNodeIndex = instruction.Clone();
                            found = false;
                            idx   = 0;
                            patchSegment++;
                        }
                    }
                    else if (!patchComplete)
                    {
                        if (idx == 0 && instruction.opcode == OpCodes.Stloc_S)
                        {
                            idx++;
                            instruction_LoadLocal_TextBlock = new CodeInstruction(OpCodes.Ldloc_S, instruction.operand);
                        }
                        else if (idx == 1)
                        {
                            //inject our patch code
                            //get the current AbilityNode item from the array and load it onto the stack
                            yield return(instruction_LoadLocal_AbilityNodeArray);

                            yield return(instruction_LoadLocal_AbilityNodeIndex);

                            yield return(new CodeInstruction(OpCodes.Callvirt, List_AbilityNode_get_Item));

                            //load the TextBlock onto the stack before the game uses it to write to the screen
                            yield return(instruction_LoadLocal_TextBlock);

                            //call our custom function to update the text block
                            yield return(new CodeInstruction(OpCodes.Call, AbilityManagerExtender_UpdateAbilityText));

                            PatchHelpers.LogPatchResult("AbilityManager",
                                                        "Patched successfully." /* Improves activated ability descriptions and cooldown information on the Manage Abilities screen. */);
                            patchComplete = true;
                        }
                    }
                }
                else if (patchSegment == 1)
                {
                    if (PatchHelpers.InstructionsAreEqual(instruction, FirstSegmentTargetInstructions[idx]))
                    {
                        if (++idx == FirstSegmentTargetInstructions.Count())
                        {
                            found = true;
                            idx   = 0;
                        }
                        gap = 0;
                    }
                    else
                    {
                        if (++gap > AllowedInstructionDistance)
                        {
                            idx = 0;
                        }
                    }
                }
                else if (patchSegment == 2)
                {
                    if (PatchHelpers.InstructionsAreEqual(instruction, SecondSegmentTargetInstruction))
                    {
                        found = true;
                    }
                }
                yield return(instruction);
            }
            if (patchComplete == false)
            {
                PatchHelpers.LogPatchResult("AbilityManager",
                                            "Failed. This patch may not be compatible with the current game version. Improved activated ability descriptions and cooldown information won't be added to the Manage Abilities screen.");
            }
        }
Esempio n. 3
0
        static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions)
        {
            int    patchSegment                  = 1;
            int    patchSegment1_stloc_ct        = 0;
            object ingredientList_LocalVarIndex  = null;
            object ingredientBools_LocalVarIndex = null;
            object recipeList_LocalVarIndex      = null;
            int    idx           = 0;
            int    gap           = 0;
            bool   found         = false;
            bool   patchComplete = false;

            foreach (var instruction in instructions)
            {
                if (found)
                {
                    if (patchSegment == 1)
                    {
                        if (instruction.opcode == OpCodes.Stloc_S)
                        {
                            patchSegment1_stloc_ct++;
                        }
                        if (patchSegment1_stloc_ct == 2)
                        {
                            //save the local variable index of the ingredient list
                            ingredientList_LocalVarIndex = instruction.operand;
                            patchSegment++;
                            found = false;
                        }
                    }
                    else if (patchSegment == 2)
                    {
                        if (instruction.opcode == OpCodes.Stloc_S)
                        {
                            ingredientBools_LocalVarIndex = instruction.operand;
                            patchSegment++;
                            found = false;
                        }
                    }
                    else if (patchSegment == 3)
                    {
                        //ignore all the lines that push stuff onto the stack for Popup.ShowOptionList
                        if (!PatchHelpers.InstructionsAreEqual(instruction, ThirdSegmentFinalInstruction))
                        {
                            continue;
                        }
                        //replace the call to Popup.ShowOptionList with our custom ingredient selection menu
                        yield return(new CodeInstruction(OpCodes.Ldloc_S, ingredientList_LocalVarIndex));

                        yield return(new CodeInstruction(OpCodes.Ldloc_S, ingredientBools_LocalVarIndex));

                        yield return(new CodeInstruction(OpCodes.Call, QudUX_IngredientSelectionScreen_Static_Show));

                        patchSegment++;
                        found = false;
                        continue;
                    }
                    else if (patchSegment == 4)
                    {
                        //unused
                    }
                    else if (patchSegment == 5)
                    {
                        if (recipeList_LocalVarIndex == null && instruction.opcode == OpCodes.Ldloc_S)
                        {
                            //grab the recipe list variable, we'll need it below
                            recipeList_LocalVarIndex = instruction.operand;
                        }
                        else if (PatchHelpers.InstructionsAreEqual(instruction, FifthSegmentFinalInstruction))
                        {
                            //replace the call to Popup.ShowOptionList with our custom recipe selection menu
                            yield return(new CodeInstruction(OpCodes.Ldloc_S, recipeList_LocalVarIndex));

                            yield return(new CodeInstruction(OpCodes.Call, QudUX_RecipeSelectionScreen_Static_Show));

                            patchSegment++;
                            found = false;
                        }
                        continue;
                    }
                    else if (!patchComplete)
                    {
                        if (PatchHelpers.InstructionsAreEqual(instruction, SixthSegmentFinalInstruction))
                        {
                            patchComplete = true;
                            PatchHelpers.LogPatchResult("Campfire",
                                                        "Patched successfully." /* Adds completely new UI screens for ingredient- and recipe-based cooking. */);
                            //allow this instruction to fall through, we want it and everything after it.
                        }
                        else
                        {
                            //null out various instructions (several of them are used as labels, so can't just ignore them)
                            instruction.opcode  = OpCodes.Nop;
                            instruction.operand = null;
                        }
                    }
                }
                else if (patchSegment == 1)
                {
                    if (PatchHelpers.InstructionsAreEqual(instruction, FirstSegmentTargetInstruction))
                    {
                        found = true;
                        idx   = 0;
                    }
                }
                else if (patchSegment == 2)
                {
                    if (PatchHelpers.InstructionsAreEqual(instruction, SecondSegmentTargetInstructions[idx]))
                    {
                        if (++idx == SecondSegmentTargetInstructions.Count())
                        {
                            found = true;
                            idx   = 0;
                        }
                        gap = 0;
                    }
                    else
                    {
                        if (++gap > AllowedInstructionDistance)
                        {
                            idx = 0;
                        }
                    }
                }
                else if (patchSegment == 3)
                {
                    if (PatchHelpers.InstructionsAreEqual(instruction, ThirdSegmentTargetInstructions[idx]))
                    {
                        if (++idx == ThirdSegmentTargetInstructions.Count())
                        {
                            found = true;
                            instruction.opcode  = OpCodes.Nop; //null out this instruction (can't remove it because it's used as a label)
                            instruction.operand = null;
                            idx = 0;
                        }
                        gap = 0;
                    }
                    else
                    {
                        if (++gap > AllowedInstructionDistance)
                        {
                            idx = 0;
                        }
                    }
                }
                else if (patchSegment == 4)
                {
                    if (idx == 0)
                    {
                        if (PatchHelpers.InstructionsAreEqual(instruction, FourthSegmentTarget1_Instruction))
                        {
                            idx++;
                        }
                    }
                    else if (idx == 1)
                    {
                        if (instruction.opcode == FourthSegmentTarget2_OpCodeOnly)
                        {
                            idx++;
                        }
                        else
                        {
                            idx = 0;
                        }
                    }
                    else if (idx == 2)
                    {
                        if (!PatchHelpers.InstructionsAreEqual(instruction, FourthSegmentTarget3_Instruction))
                        {
                            if (++gap > FourthSegmentAllowedInstructionDistance)
                            {
                                idx = 0;
                                gap = 0;
                            }
                        }
                        else
                        {
                            instruction.opcode = OpCodes.Ldc_I4_1; //modify to set flag to true instead of false, so that recipes without ingredients on hand aren't hidden from the array
                            patchSegment++;
                            idx = 0;
                            gap = 0;
                        }
                    }
                }
                else if (patchSegment == 5)
                {
                    if (PatchHelpers.InstructionsAreEqual(instruction, FifthSegmentTargetInstruction))
                    {
                        found = true;
                        instruction.opcode  = OpCodes.Nop; //null out this instruction (can't remove it because it's used as a label)
                        instruction.operand = null;
                    }
                }
                else if (patchSegment == 6)
                {
                    if (PatchHelpers.InstructionsAreEqual(instruction, SixthSegmentTargetInstruction))
                    {
                        found = true;
                        instruction.opcode  = OpCodes.Nop;
                        instruction.operand = null;
                    }
                }
                yield return(instruction);
            }
            if (patchComplete == false)
            {
                PatchHelpers.LogPatchResult("Campfire",
                                            "Failed. This patch may not be compatible with the current game version. "
                                            + "The game's default cooking UI pop-ups will be used instead of QudUX's revamped screens.");
            }
        }