Beispiel #1
0
        private void HoeDirt_performUseAction_hand(LocalBuilder var_temp_harvestMethod)
        {
            // Do plucking logic
            var harvest_hand = FindCode(
                // if ((int)crop.harvestMethod == 0) {
                OpCodes.Ldarg_0,
                Instructions.Call_get(typeof(HoeDirt), nameof(HoeDirt.crop)),
                Instructions.Ldfld(typeof(Crop), nameof(Crop.harvestMethod)),
                OpCodes.Call, // NetCode implicit cast.
                OpCodes.Brtrue
                );

            harvest_hand.Replace(
                // var temp_harvestmethod = crop.harvestMethod;
                harvest_hand[0],
                harvest_hand[1],
                harvest_hand[2],
                harvest_hand[3],
                Instructions.Stloc_S(var_temp_harvestMethod),

                // if (ModEntry.CanHarvestCrop(crop, 0)) {
                Instructions.Ldarg_0(),
                harvest_hand[1],
                Instructions.Ldc_I4_0(),
                Instructions.Call(typeof(ModEntry), nameof(CanHarvestCrop), typeof(Crop), typeof(int)),
                Instructions.Brfalse((Label)harvest_hand[4].operand),

                // crop.harvestMethod = 0;
                Instructions.Ldarg_0(),
                harvest_hand[1],
                harvest_hand[2],
                Instructions.Ldc_I4_0(),
                Instructions.Call_set(typeof(NetInt), nameof(NetInt.Value))
                );
        }
Beispiel #2
0
        private void HoeDirt_performUseAction_scythe(LocalBuilder var_temp_harvestMethod)
        {
            // Do scything logic
            var harvest_scythe = FindCode(
                // if ((int)crop.harvestMethod == 1) {
                OpCodes.Ldarg_0,
                Instructions.Call_get(typeof(HoeDirt), nameof(HoeDirt.crop)),
                Instructions.Ldfld(typeof(Crop), nameof(Crop.harvestMethod)),
                OpCodes.Call, // NetCode implicit cast.
                OpCodes.Ldc_I4_1,
                OpCodes.Bne_Un
                );

            harvest_scythe.Replace(
                // crop.harvestMethod = temp_harvestmethod;
                harvest_scythe[0],
                harvest_scythe[1],
                harvest_scythe[2],
                Instructions.Ldloc_S(var_temp_harvestMethod),
                Instructions.Call_set(typeof(NetInt), nameof(NetInt.Value)),

                // if (ModEntry.CanHarvestCrop(crop, 1)) {
                Instructions.Ldarg_0(),
                harvest_scythe[1],
                Instructions.Ldc_I4_1(),
                Instructions.Call(typeof(ModEntry), nameof(CanHarvestCrop), typeof(Crop), typeof(int)),
                Instructions.Brfalse((Label)harvest_scythe[5].operand)
                );
        }
Beispiel #3
0
        void Object_performToolAction()
        {
            var   code  = BeginCode();
            Label begin = AttachLabel(code[0]);

            code.Prepend(
                // Check if Tool is scythe.
                Instructions.Ldarg_1(),
                Instructions.Isinst(typeof(MeleeWeapon)),
                Instructions.Brfalse(begin),
                Instructions.Ldarg_1(),
                Instructions.Isinst(typeof(MeleeWeapon)),
                Instructions.Ldc_I4_M1(),
                Instructions.Callvirt(typeof(MeleeWeapon), nameof(MeleeWeapon.isScythe), typeof(int)),
                Instructions.Brfalse(begin),
                // Hook
                Instructions.Ldarg_0(),
                Instructions.Ldarg_1(),
                Instructions.Ldarg_2(),
                Instructions.Call(typeof(ModEntry), nameof(ScytheForage), typeof(StardewValley.Object), typeof(Tool), typeof(GameLocation)),
                Instructions.Brfalse(begin),
                Instructions.Ldc_I4_1(),
                Instructions.Ret()
                );
        }
Beispiel #4
0
        void Object_performToolAction()
        {
            var   code  = BeginCode();
            Label begin = AttachLabel(code[0]);

            code.Prepend(
                // Check if Tool is scythe.
                Instructions.Ldarg_1(),
                Instructions.Isinst(typeof(StardewValley.Tools.MeleeWeapon)),
                Instructions.Brfalse(begin),
                Instructions.Ldarg_1(),
                Instructions.Isinst(typeof(StardewValley.Tools.MeleeWeapon)),
                Instructions.Callvirt_get(typeof(StardewValley.Tool), "BaseName"),
                Instructions.Ldstr("Scythe"),
                Instructions.Callvirt(typeof(System.String), "Equals", typeof(string)),
                Instructions.Brfalse(begin),
                // Hook
                Instructions.Ldarg_0(),
                Instructions.Ldarg_1(),
                Instructions.Ldarg_2(),
                Instructions.Call(typeof(ModEntry), "ScytheForage", typeof(StardewValley.Object), typeof(StardewValley.Tool), typeof(StardewValley.GameLocation)),
                Instructions.Brfalse(begin),
                Instructions.Ldc_I4_1(),
                Instructions.Ret()
                );
        }
Beispiel #5
0
        void InventoryPage_performHoverAction()
        {
            // Change code responsible for obtaining the tooltip information.
            var var_item = generator.DeclareLocal(typeof(Item));
            InstructionRange code;

            try {
                code = FindCode(
                    OpCodes.Ldloc_1,
                    Instructions.Ldfld(typeof(ClickableComponent), nameof(ClickableComponent.name)),
                    OpCodes.Stloc_2,
                    OpCodes.Ldloc_2,
                    Instructions.Ldstr("Hat")
                    );
            } catch (System.Exception err) {
                LogException(err, LogLevel.Trace);
                code = FindCode(
                    OpCodes.Ldloc_0,
                    Instructions.Ldfld(typeof(ClickableComponent), nameof(ClickableComponent.name)),
                    OpCodes.Stloc_2,
                    OpCodes.Ldloc_2,
                    OpCodes.Brfalse,
                    OpCodes.Ldloc_2,
                    Instructions.Ldstr("Hat")
                    );
            }
            code.Extend(
                OpCodes.Ldarg_0,
                Instructions.Call_get(typeof(Game1), nameof(Game1.player)),
                Instructions.Ldfld(typeof(Farmer), nameof(Farmer.boots)),
                OpCodes.Callvirt,
                Instructions.Callvirt_get(typeof(Item), nameof(Item.DisplayName)),
                Instructions.Stfld(typeof(InventoryPage), "hoverTitle")
                );
            code.Replace(
                // var item = EquipmentIcon.item
                code[0],
                Instructions.Ldfld(typeof(ClickableComponent), nameof(ClickableComponent.item)),
                Instructions.Stloc_S(var_item),
                // if (item != null)
                Instructions.Ldloc_S(var_item),
                Instructions.Brfalse(AttachLabel(code.End[0])),
                // hoveredItem = item;
                Instructions.Ldarg_0(),
                Instructions.Ldloc_S(var_item),
                Instructions.Stfld(typeof(InventoryPage), "hoveredItem"),
                // hoverText = item.getDescription();
                Instructions.Ldarg_0(),
                Instructions.Ldloc_S(var_item),
                Instructions.Callvirt(typeof(Item), nameof(Item.getDescription)),
                Instructions.Stfld(typeof(InventoryPage), "hoverText"),
                // hoverTitle = item.DisplayName;
                Instructions.Ldarg_0(),
                Instructions.Ldloc_S(var_item),
                Instructions.Callvirt_get(typeof(Item), nameof(Item.DisplayName)),
                Instructions.Stfld(typeof(InventoryPage), "hoverTitle")
                );
        }
Beispiel #6
0
        void HoeDirt_performToolAction()
        {
            // Find the first (and only) harvestMethod==1 check.
            var HarvestMethodCheck = FindCode(
                OpCodes.Ldarg_0,
                Instructions.Call_get(typeof(HoeDirt), nameof(HoeDirt.crop)),
                Instructions.Ldfld(typeof(Crop), nameof(Crop.harvestMethod)),
                OpCodes.Call, // Netcode implicit conversion
                OpCodes.Ldc_I4_1,
                OpCodes.Bne_Un
                );

            // Change the harvestMethod==1 check to:
            //   damage=harvestMethod;
            //   if (CanHarvestCrop(crop, 1)) {
            //   harvestMethod=1
            // This code block is followed by a call to crop.harvest().
            HarvestMethodCheck.Replace(
                // damage = crop.harvestMethod.
                HarvestMethodCheck[0],
                HarvestMethodCheck[1],
                HarvestMethodCheck[2],
                HarvestMethodCheck[3],
                Instructions.Starg_S(2), // damage

                // if (CanHarvestCrop(crop, 1)) {
                HarvestMethodCheck[0],
                HarvestMethodCheck[1],
                Instructions.Ldc_I4_1(),
                Instructions.Call(typeof(ModEntry), nameof(CanHarvestCrop), typeof(Crop), typeof(int)),
                Instructions.Brfalse((Label)HarvestMethodCheck[5].operand),

                // crop.harvestMethod = 1
                HarvestMethodCheck[0],
                HarvestMethodCheck[1],
                HarvestMethodCheck[2],
                Instructions.Ldc_I4_1(),
                Instructions.Call_set(typeof(NetInt), nameof(NetInt.Value))
                );

            // Restore harvestMethod by setting harvestMethod=damage
            // after the following crop!=null check.
            HarvestMethodCheck.FindNext(
                OpCodes.Ldarg_0,
                Instructions.Call_get(typeof(HoeDirt), nameof(HoeDirt.crop)),
                Instructions.Ldfld(typeof(Crop), nameof(Crop.dead)),
                OpCodes.Call, // Netcode
                OpCodes.Brfalse
                ).Prepend(
                HarvestMethodCheck[0],
                HarvestMethodCheck[1],
                HarvestMethodCheck[2],
                Instructions.Ldarg_2(), // damage
                Instructions.Call_set(typeof(NetInt), nameof(NetInt.Value))
                );
        }
Beispiel #7
0
        // Change the behavior of the grass growth & spreading.
        void GameLocation_growWeedGrass()
        {
            // Stop grass from growing & spreading.
            AllCode().Prepend(
                Instructions.Call(GetType(), nameof(getDisableGrowth)),
                Instructions.Brfalse(AttachLabel(AllCode()[0])),
                Instructions.Ret()
                );

            // Change grass growth to spread mostly everywhere.
            var growWeedGrass = BeginCode();

            // For each of the 4 directions
            for (int i = 0; i < 4; i++)
            {
                growWeedGrass = growWeedGrass.FindNext(
                    OpCodes.Ldarg_0,
                    null,
                    null,
                    null,
                    null,
                    Instructions.Ldstr("Diggable"),
                    Instructions.Ldstr("Back"),
                    Instructions.Call(typeof(GameLocation), nameof(GameLocation.doesTileHaveProperty), typeof(int), typeof(int), typeof(string), typeof(string)),
                    OpCodes.Brfalse
                    );
                growWeedGrass.Prepend(
                    Instructions.Call(GetType(), nameof(getGrowEverywhere)),
                    Instructions.Brtrue(AttachLabel(growWeedGrass.End[0]))
                    );
            }

            // Growth chance
            FindCode(
                Instructions.Ldc_R8(0.65),
                OpCodes.Bge_Un,
                OpCodes.Ldloca_S
                )[0] = Instructions.Call(GetType(), nameof(getGrowthChance));

            // Spread
            var spreadGrass = BeginCode();

            // For each of the 4 directions
            for (int i = 0; i < 4; i++)
            {
                spreadGrass = spreadGrass.FindNext(
                    Instructions.Ldc_R8(0.25),
                    OpCodes.Bge_Un,
                    OpCodes.Ldarg_0
                    );
                spreadGrass[0] = Instructions.Call(GetType(), nameof(getSpreadChance));
            }
        }
Beispiel #8
0
        private void HoeDirt_performUseAction_scythe(LocalBuilder var_temp_harvestMethod)
        {
            // Do scything logic
            var harvest_scythe = FindCode(
                // if ((int)crop.harvestMethod == 1) {
                OpCodes.Ldarg_0,
                HoeDirt_crop,
                Instructions.Ldfld(typeof(Crop), nameof(Crop.harvestMethod)),
                OpCodes.Call, // NetCode implicit cast.
                OpCodes.Ldc_I4_1,
                OpCodes.Bne_Un
                );

            harvest_scythe.Replace(
                // crop.harvestMethod = temp_harvestmethod;
                harvest_scythe[0],
                harvest_scythe[1],
                harvest_scythe[2],
                Instructions.Ldloc_S(var_temp_harvestMethod),
                Instructions.Call_set(typeof(NetInt), nameof(NetInt.Value)),

                // if (ModEntry.CanHarvestCrop(crop, 1)) {
                Instructions.Ldarg_0(),
                harvest_scythe[1],
                Instructions.Ldc_I4_1(),
                Instructions.Call(typeof(ModEntry), nameof(CanHarvestCrop), typeof(Crop), typeof(int)),
                Instructions.Brfalse((Label)harvest_scythe[5].operand)
                );

            harvest_scythe = harvest_scythe.FindNext(
                // Game1.player.CurrentTool is MeleeWeapon &&
                Instructions.Call_get(typeof(Game1), nameof(Game1.player)),
                Instructions.Callvirt_get(typeof(Farmer), nameof(Farmer.CurrentTool)),
                Instructions.Isinst(typeof(MeleeWeapon)),
                OpCodes.Brfalse,

                // (Game1.player.CurrentTool as MeleeWeapon).isScythe()
                Instructions.Call_get(typeof(Game1), nameof(Game1.player)),
                Instructions.Callvirt_get(typeof(Farmer), nameof(Farmer.CurrentTool)),
                Instructions.Isinst(typeof(MeleeWeapon)),
                OpCodes.Ldc_I4_M1,
                Instructions.Callvirt(typeof(MeleeWeapon), nameof(MeleeWeapon.isScythe), typeof(int)),
                OpCodes.Brfalse
                );

            harvest_scythe.Replace(
                harvest_scythe[0],
                harvest_scythe[1],
                Instructions.Call(GetType(), nameof(IsScythe), typeof(Tool)),
                harvest_scythe[3]
                );
        }
Beispiel #9
0
        void HoeDirt_performUseAction()
        {
            var harvest_hand = FindCode(
                OpCodes.Ldarg_0,
                OpCodes.Call,
                OpCodes.Ldfld,
                OpCodes.Call,
                OpCodes.Brtrue
                );

            // Logic here depends on whether flowers can be harvested by scythe.
            if (config.ScytheHarvestFlowers)
            {
                // Entirely remove logic related to harvesting by hand.
                harvest_hand.Extend(
                    OpCodes.Ldarg_0,
                    OpCodes.Call,
                    OpCodes.Ldfld,
                    OpCodes.Call,
                    OpCodes.Ldc_I4_1,
                    OpCodes.Bne_Un
                    );
                harvest_hand.Remove();
            }
            else
            {
                // Only allow harvesting by hand for flowers. Otherwise those would not be harvestable.
                harvest_hand.Replace(
                    harvest_hand[0],
                    harvest_hand[1],
                    Instructions.Ldfld(typeof(Crop), nameof(Crop.programColored)),
                    Instructions.Call_get(typeof(NetBool), nameof(NetBool.Value)),
                    Instructions.Brfalse((Label)harvest_hand[4].operand)
                    );
                var harvest_scythe = FindCode(
                    OpCodes.Ldarg_0,
                    OpCodes.Call,
                    OpCodes.Ldfld,
                    OpCodes.Call,
                    OpCodes.Ldc_I4_1,
                    OpCodes.Bne_Un
                    );
                harvest_scythe.Replace(
                    harvest_scythe[0],
                    harvest_scythe[1],
                    Instructions.Ldfld(typeof(Crop), nameof(Crop.programColored)),
                    Instructions.Call_get(typeof(NetBool), nameof(NetBool.Value)),
                    Instructions.Brtrue((Label)harvest_scythe[5].operand)
                    );
            }
        }
Beispiel #10
0
        // Support harvesting of spring onions with scythe
        private void Crop_harvest_support_spring_onion(LocalBuilder var_vector)
        {
            if (config.HarvestMode.SpringOnion == HarvestModeEnum.HAND)
            {
                return;
            }

            // Note: the branch
            //   if (this.forageCrop)
            // refers mainly to the crop spring union.

            // Find the lines:
            var AddItem = FindCode(
                // if (Game1.player.addItemToInventoryBool (@object, false)) {
                Instructions.Call_get(typeof(Game1), nameof(Game1.player)),
                InstructionMatcher.AnyOf( // @object
                    OpCodes.Ldloc_0,
                    OpCodes.Ldloc_1
                    ),
                OpCodes.Ldc_I4_0,
                Instructions.Callvirt(typeof(Farmer), nameof(Farmer.addItemToInventoryBool), typeof(Item), typeof(bool)),
                OpCodes.Brfalse
                );

            var ldarg_0      = Instructions.Ldarg_0();
            var Ldloc_object = AddItem[1];
            var tail         = AttachLabel(AddItem.FindNext(
                                               OpCodes.Ldarg_0,
                                               Instructions.Ldfld(typeof(Crop), nameof(Crop.regrowAfterHarvest))
                                               )[0]);

            // Insert check for harvesting with scythe and act accordingly.
            AddItem.ReplaceJump(0, ldarg_0);
            AddItem.Prepend(
                // if (this.harvestMethod != 0) {
                ldarg_0,
                Instructions.Ldfld(typeof(Crop), nameof(Crop.harvestMethod)),
                Instructions.Call_get(typeof(NetInt), nameof(NetInt.Value)),
                Instructions.Brfalse(AttachLabel(AddItem[0])),
                // Game1.createItemDebris (@object, vector, -1, null, -1)
                Ldloc_object,                     // @object
                Instructions.Ldloc_S(var_vector), // vector
                Instructions.Ldc_I4_M1(),         // -1
                Instructions.Ldnull(),            // null
                Instructions.Ldc_I4_M1(),         // -1
                Instructions.Call(typeof(Game1), nameof(Game1.createItemDebris), typeof(Item), typeof(Vector2), typeof(int), typeof(GameLocation), typeof(int)),
                Instructions.Pop(),               // For SDV 1.4
                // Jump to tail
                Instructions.Br(tail)
                );
        }
Beispiel #11
0
        void Object_performToolAction()
        {
            var   code  = BeginCode();
            Label begin = AttachLabel(code[0]);

            code.Prepend(
                // Hook
                Instructions.Ldarg_0(),
                Instructions.Ldarg_1(),
                Instructions.Ldarg_2(),
                Instructions.Call(typeof(ModEntry), nameof(ScytheForage), typeof(StardewValley.Object), typeof(Tool), typeof(GameLocation)),
                Instructions.Brfalse(begin),
                Instructions.Ldc_I4_1(),
                Instructions.Ret()
                );
        }
Beispiel #12
0
        void InventoryPage_performHoverAction()
        {
            // Change code responsible for obtaining the tooltip information.
            var var_item = generator.DeclareLocal(typeof(Item));
            var code     = FindCode(
                OpCodes.Ldloc_1,
                Instructions.Ldfld(typeof(StardewValley.Menus.ClickableComponent), "name"),
                OpCodes.Stloc_2,
                OpCodes.Ldloc_2,
                Instructions.Ldstr("Hat")
                );

            code.Extend(
                OpCodes.Ldarg_0,
                Instructions.Call_get(typeof(Game1), "player"),
                Instructions.Ldfld(typeof(Farmer), "boots"),
                OpCodes.Callvirt,
                Instructions.Callvirt_get(typeof(Item), "DisplayName"),
                Instructions.Stfld(typeof(StardewValley.Menus.InventoryPage), "hoverTitle")
                );
            code.Replace(
                // var item = EquipmentIcon.item
                Instructions.Ldloc_1(),
                Instructions.Ldfld(typeof(StardewValley.Menus.ClickableComponent), "item"),
                Instructions.Stloc_S(var_item),
                // if (item != null)
                Instructions.Ldloc_S(var_item),
                Instructions.Brfalse(AttachLabel(code.End[0])),
                // hoveredItem = item;
                Instructions.Ldarg_0(),
                Instructions.Ldloc_S(var_item),
                Instructions.Stfld(typeof(StardewValley.Menus.InventoryPage), "hoveredItem"),
                // hoverText = item.getDescription();
                Instructions.Ldarg_0(),
                Instructions.Ldloc_S(var_item),
                Instructions.Callvirt(typeof(Item), "getDescription"),
                Instructions.Stfld(typeof(StardewValley.Menus.InventoryPage), "hoverText"),
                // hoverTitle = item.DisplayName;
                Instructions.Ldarg_0(),
                Instructions.Ldloc_S(var_item),
                Instructions.Callvirt_get(typeof(Item), "DisplayName"),
                Instructions.Stfld(typeof(StardewValley.Menus.InventoryPage), "hoverTitle")
                );
        }
Beispiel #13
0
        void Crop_harvest()
        {
            // >>> Fix harvesting of spring onions.

            // Find the line:
            //   if (Game1.player.addItemToInventoryBool (@object, false)) {
            var AddItem = FindCode(
                Instructions.Call_get(typeof(StardewValley.Game1), "player"),
                OpCodes.Ldloc_0,
                OpCodes.Ldc_I4_0,
                Instructions.Callvirt(typeof(StardewValley.Farmer), "addItemToInventoryBool", typeof(StardewValley.Item), typeof(bool)),
                OpCodes.Brfalse
                );

            // Make jumps to the start of AddItem jump to the start of our new code instead.
            var ldarg0 = Instructions.Ldarg_0();

            AddItem.ReplaceJump(0, ldarg0);

            // Insert check for harvesting with scythe and act accordingly.
            AddItem.Prepend(
                // if (this.harvestMethod != 0) {
                ldarg0,
                Instructions.Ldfld(typeof(StardewValley.Crop), "harvestMethod"),
                Instructions.Call_get(typeof(Netcode.NetInt), "Value"), // this.indexOfHarvest
                Instructions.Brfalse(AttachLabel(AddItem[0])),
                // Game1.createObjectDebris (@object.ParentSheetIndex, xTile, yTile, -1, @object.Quality, 1.0, null);
                Instructions.Ldloc_0(),
                Instructions.Callvirt_get(typeof(StardewValley.Item), "ParentSheetIndex"), // @object.ParentSheetIndex
                Instructions.Ldarg_1(),                                                    // xTile
                Instructions.Ldarg_2(),                                                    // yTile
                Instructions.Ldc_I4_M1(),                                                  // -1
                Instructions.Ldloc_0(),
                Instructions.Callvirt_get(typeof(StardewValley.Object), "Quality"),        // @object.Quality
                Instructions.Ldc_R4(1),                                                    // 1.0
                Instructions.Ldnull(),                                                     // null
                Instructions.Call(typeof(StardewValley.Game1), "createObjectDebris", typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(float), typeof(StardewValley.GameLocation)),
                // Game1.player.gainExperience (2, howMuch);
                Instructions.Call_get(typeof(StardewValley.Game1), "player"),
                Instructions.Ldc_I4_2(),
                Instructions.Ldloc_1(),
                Instructions.Callvirt(typeof(StardewValley.Farmer), "gainExperience", typeof(int), typeof(int)),
                // return true
                Instructions.Ldc_I4_1(),
                Instructions.Ret()
                // }
                );

            // >>> Patch code to drop sunflower seeds when harvesting with scythe.
            // Patch is configurable, so it can be disabled in case it breaks in the future.
            if (config.HarvestSeeds)
            {
                // Find tail of harvestMethod==1 branch
                var ScytheBranchTail = FindCode(
                    OpCodes.Ldarg_0,
                    Instructions.Ldfld(typeof(StardewValley.Crop), "harvestMethod"),
                    OpCodes.Call, // Netcode
                    OpCodes.Ldc_I4_1,
                    OpCodes.Bne_Un
                    ).Follow(4);
                // Select starting from the exp code.
                ScytheBranchTail.ExtendBackwards(
                    Instructions.Ldsfld(typeof(StardewValley.Game1), "objectInformation"),
                    OpCodes.Ldarg_0,
                    Instructions.Ldfld(typeof(StardewValley.Crop), "indexOfHarvest"),
                    OpCodes.Call, // Netcode
                    OpCodes.Callvirt,
                    OpCodes.Ldc_I4_1
                    );

                // Monitor.Log(ScytheBranchTail.ToString());
                if (ScytheBranchTail.length > 60)
                {
                    throw new Exception("Too many operations in tail of harvestMethod branch");
                }

                // Find the start of the 'drop sunflower seeds' part.
                var DropSunflowerSeeds = FindCode(
                    OpCodes.Ldarg_0,
                    Instructions.Ldfld(typeof(StardewValley.Crop), "indexOfHarvest"),
                    OpCodes.Call,             // Netcode
                    Instructions.Ldc_I4(421), // 421 = Item ID of Sunflower.
                    OpCodes.Bne_Un
                    );

                // Find the local variable that stores the amount being dropped.
                var DropAmount = DropSunflowerSeeds.FindNext(
                    Instructions.Callvirt(typeof(System.Random), "Next", typeof(int), typeof(int)),
                    OpCodes.Stloc_S
                    );
                // Rewrite the tail of the Scythe harvest branch.
                ScytheBranchTail.Replace(
                    // Set num2 = 0.
                    Instructions.Ldc_I4_0(),
                    Instructions.Stloc_S((LocalBuilder)DropAmount[1].operand),
                    // Jump to the 'drop subflower seeds' part.
                    Instructions.Br(AttachLabel(DropSunflowerSeeds[0]))
                    );
            }
        }
Beispiel #14
0
        void GameLocation_checkAction_Chain()
        {
            var var_object = generator.DeclareLocal(typeof(StardewValley.Object));
            InstructionRange code;
            Label            cant_harvest;

            try {
                code = FindCode(
                    // if (who.couldInventoryAcceptThisItem (objects [vector])) {
                    OpCodes.Ldarg_0,
                    OpCodes.Ldfld, // who
                    OpCodes.Ldarg_0,
                    OpCodes.Ldfld, // objects
                    Instructions.Ldfld(typeof(GameLocation), nameof(GameLocation.objects)),
                    null,          // Either LdLoc_1 or LdLoc_S(8).
                    OpCodes.Callvirt,
                    // <- Insert is here.
                    Instructions.Callvirt(typeof(Farmer), nameof(Farmer.couldInventoryAcceptThisItem), typeof(Item)),
                    OpCodes.Brfalse,
                    null // To make this InstructionRange have the same length as the one below for android.
                    );
                cant_harvest = (Label)code[8].operand;
            } catch (Exception err) {
                LogException(err, LogLevel.Trace);

                // Android adds a boolean to the couldInventoryAcceptThisItem method.
                code = FindCode(
                    // if (who.couldInventoryAcceptThisItem (objects [vector], true)) {
                    OpCodes.Ldarg_0,
                    OpCodes.Ldfld, // who
                    OpCodes.Ldarg_0,
                    OpCodes.Ldfld, // objects
                    Instructions.Ldfld(typeof(GameLocation), nameof(GameLocation.objects)),
                    null,          // Either LdLoc_1 or LdLoc_S(8).
                    OpCodes.Callvirt,
                    // <- Insert is here.
                    OpCodes.Ldc_I4_1,
                    Instructions.Callvirt(typeof(Farmer), nameof(Farmer.couldInventoryAcceptThisItem), typeof(Item), typeof(bool)),
                    OpCodes.Brfalse
                    );
                cant_harvest = (Label)code[9].operand;
            }
            // Check whether harvesting forage by hand is allowed.
            code.Replace(
                // var object = objects [vector];
                code[0],
                code[3], // objects
                code[4],
                code[5],
                code[6],
                Instructions.Stloc_S(var_object),
                // if (ModEntry.CanHarvestObject(object, 0)) {
                Instructions.Ldloc_S(var_object),
                Instructions.Ldc_I4_0(),
                Instructions.Call(typeof(ModEntry), nameof(CanHarvestObject), typeof(StardewValley.Object), typeof(int)),
                Instructions.Brfalse(cant_harvest),
                // if (who.couldInventoryAcceptThisItem (object)) {
                code[2],
                code[1], // who
                Instructions.Ldloc_S(var_object),
                code[7], // true or couldInventoryAcceptThisItem
                code[8],
                code[9]
                );

            // Move to this.objects [vector].Quality = quality;
            code = code.FindNext(
                OpCodes.Ldarg_0,
                OpCodes.Ldfld,
                Instructions.Ldfld(typeof(GameLocation), nameof(GameLocation.objects)),
                null, // Either LdLoc_1 or LdLoc_S(8).
                OpCodes.Callvirt,
                OpCodes.Ldloc_S,
                Instructions.Callvirt_set(typeof(StardewValley.Object), nameof(StardewValley.Object.Quality))
                );
            var label_dont_scythe = AttachLabel(code.End[0]);

            // Append code to handle trigger harvest with scythe.
            code.Append(
                // if (ModEntry.CanHarvestObject(object, HARVEST_SCYTHING) {
                Instructions.Ldloc_S(var_object),
                Instructions.Ldc_I4_1(), // HARVEST_SCYTHING
                Instructions.Call(typeof(ModEntry), nameof(ModEntry.CanHarvestObject), typeof(StardewValley.Object), typeof(int)),
                Instructions.Brfalse(label_dont_scythe),
                // ModEntry.TryScythe()
                Instructions.Call(typeof(ModEntry), nameof(ModEntry.TryScythe))
                );
        }
Beispiel #15
0
        void GameLocation_checkAction()
        {
            var var_object = generator.DeclareLocal(typeof(StardewValley.Object));
            InstructionRange code;
            Label            cant_harvest;

            code = FindCode(
                // if (who.couldInventoryAcceptThisItem (objects [vector])) {
                OpCodes.Ldarg_3, // who
                OpCodes.Ldarg_0,
                Instructions.Ldfld(typeof(GameLocation), nameof(GameLocation.objects)),
                OpCodes.Ldloc_1,
                OpCodes.Callvirt,
                // <- Insert is here.
                Instructions.Callvirt(typeof(Farmer), nameof(Farmer.couldInventoryAcceptThisItem), typeof(Item)),
                OpCodes.Brfalse
                );
            cant_harvest = (Label)code[6].operand;

            // Check whether harvesting forage by hand is allowed.
            code.Replace(
                // var object = objects [vector];
                code[1], // objects
                code[2],
                code[3],
                code[4],
                Instructions.Stloc_S(var_object),

                // if (ModEntry.CanHarvestObject(object, location, 0)) {
                Instructions.Ldloc_S(var_object),
                Instructions.Ldarg_0(),
                Instructions.Ldc_I4_0(),
                Instructions.Call(typeof(ModEntry), nameof(CanHarvestObject), typeof(StardewValley.Object), typeof(GameLocation), typeof(int)),
                Instructions.Brfalse(cant_harvest),

                // if (who.couldInventoryAcceptThisItem (object)) {
                code[0], // who
                Instructions.Ldloc_S(var_object),
                code[5], // couldInventoryAcceptThisItem
                code[6]
                );

            // Move to this.objects [vector].Quality = quality;
            code = code.FindNext(
                OpCodes.Ldarg_0,
                Instructions.Ldfld(typeof(GameLocation), nameof(GameLocation.objects)),
                OpCodes.Ldloc_1,
                OpCodes.Callvirt,
                OpCodes.Ldloc_S,
                Instructions.Callvirt_set(typeof(StardewValley.Object), nameof(StardewValley.Object.Quality))
                );
            var label_dont_scythe = AttachLabel(code.End[0]);

            // Append code to handle trigger harvest with scythe.
            code.Append(
                // if (ModEntry.CanHarvestObject(object, location, HARVEST_SCYTHING) {
                Instructions.Ldloc_S(var_object),
                Instructions.Ldarg_0(),
                Instructions.Ldc_I4_1(), // HARVEST_SCYTHING
                Instructions.Call(typeof(ModEntry), nameof(ModEntry.CanHarvestObject), typeof(StardewValley.Object), typeof(GameLocation), typeof(int)),
                Instructions.Brfalse(label_dont_scythe),
                // ModEntry.TryScythe()
                Instructions.Call(typeof(ModEntry), nameof(ModEntry.TryScythe))
                );
        }
Beispiel #16
0
        void Crop_harvest()
        {
            #region Fix vector
            Harmony.CodeInstruction ins = null;
            // Remove line (2x)
            // Vector2 vector = new Vector2 ((float)xTile, (float)yTile);
            for (int i = 0; i < 2; i++)
            {
                var vec = FindCode(
                    OpCodes.Ldloca_S,
                    OpCodes.Ldarg_1,
                    OpCodes.Conv_R4,
                    OpCodes.Ldarg_2,
                    OpCodes.Conv_R4,
                    OpCodes.Call
                    );
                ins = vec[5];
                vec.Remove();
            }

            // Add to begin of function
            // Vector2 vector = new Vector2 ((float)xTile*64., (float)yTile*64.);
            BeginCode().Append(
                Instructions.Ldloca_S(3),
                Instructions.Ldarg_1(),
                Instructions.Conv_R4(),
                Instructions.Ldc_R4(64),
                Instructions.Mul(),
                Instructions.Ldarg_2(),
                Instructions.Conv_R4(),
                Instructions.Ldc_R4(64),
                Instructions.Mul(),
                ins
                );

            // Replace (4x):
            //   from: new Vector2 (vector.X * 64f, vector.Y * 64f)
            //   to:   vector
            for (int i = 0; i < 4; i++)
            {
                FindCode(
                    null,
                    OpCodes.Ldfld,
                    Instructions.Ldc_R4(64),
                    OpCodes.Mul,
                    null,
                    OpCodes.Ldfld,
                    Instructions.Ldc_R4(64),
                    OpCodes.Mul,
                    OpCodes.Newobj
                    ).Replace(
                    Instructions.Ldloc_3() // vector
                    );
            }
            #endregion

            #region Support harvesting of spring onions with scythe
            // Note: the branch
            //   if (this.forageCrop)
            // refers mainly to the crop spring union.

            // Find the lines:
            var AddItem = FindCode(
                // if (Game1.player.addItemToInventoryBool (@object, false)) {
                Instructions.Call_get(typeof(Game1), nameof(Game1.player)),
                OpCodes.Ldloc_0,
                OpCodes.Ldc_I4_0,
                Instructions.Callvirt(typeof(Farmer), nameof(Farmer.addItemToInventoryBool), typeof(Item), typeof(bool)),
                OpCodes.Brfalse
                );

            // Swap the lines (add '*64' to vector) &
            // Insert check for harvesting with scythe and act accordingly.
            AddItem.Prepend(
                // if (this.harvestMethod != 0) {
                Instructions.Ldarg_0(),
                Instructions.Ldfld(typeof(Crop), nameof(Crop.harvestMethod)),
                Instructions.Call_get(typeof(NetInt), nameof(NetInt.Value)),
                Instructions.Brfalse(AttachLabel(AddItem[0])),
                // Game1.createItemDebris (@object, vector, -1, null, -1)
                Instructions.Ldloc_0(),   // @object
                Instructions.Ldloc_3(),   // vector
                Instructions.Ldc_I4_M1(), // -1
                Instructions.Ldnull(),    // null
                Instructions.Ldc_I4_M1(), // -1
                Instructions.Call(typeof(Game1), nameof(Game1.createItemDebris), typeof(Item), typeof(Vector2), typeof(int), typeof(GameLocation), typeof(int)),
                // Game1.player.gainExperience (2, howMuch);
                Instructions.Call_get(typeof(Game1), nameof(Game1.player)),
                Instructions.Ldc_I4_2(),
                Instructions.Ldloc_1(),
                Instructions.Callvirt(typeof(Farmer), nameof(Farmer.gainExperience), typeof(int), typeof(int)),
                // return true
                Instructions.Ldc_I4_1(),
                Instructions.Ret()
                // }
                );
            #endregion

            #region Sunflower drops
            // >>> Patch code to drop sunflower seeds when harvesting with scythe.
            // >>> Patch code to let harvesting with scythe drop only 1 item.
            // >>> The other item drops are handled by the plucking code.

            // Remove start of loop
            var start_loop = FindCode(
                // for (int i = 0
                OpCodes.Ldc_I4_0,
                OpCodes.Stloc_S,
                OpCodes.Br,
                // junimoHarvester != null
                Instructions.Ldarg_S(4),
                OpCodes.Brfalse
                );
            // Get a reference to the 'i' variable.
            var var_i = (LocalBuilder)start_loop[1].operand;
            // Remove the head of the loop.
            start_loop.length = 3;
            start_loop.Remove();

            // Find the start of the 'drop sunflower seeds' part.
            var DropSunflowerSeeds = FindCode(
                OpCodes.Ldarg_0,
                Instructions.Ldfld(typeof(Crop), nameof(Crop.indexOfHarvest)),
                OpCodes.Call,             // Netcode
                Instructions.Ldc_I4(421), // 421 = Item ID of Sunflower.
                OpCodes.Bne_Un
                );
            // Set quality for seeds to 0.
            DropSunflowerSeeds.Append(
                Instructions.Ldc_I4_0(),
                Instructions.Stloc_S(5)
                );

            // Remove end of loop and everything after that until the end of the harvest==1 branch.
            var ScytheBranchTail = FindCode(
                OpCodes.Ldarg_0,
                Instructions.Ldfld(typeof(Crop), nameof(Crop.harvestMethod)),
                OpCodes.Call, // Netcode
                OpCodes.Ldc_I4_1,
                OpCodes.Bne_Un
                ).Follow(4);
            ScytheBranchTail.ExtendBackwards(
                Instructions.Ldloc_S(var_i),
                OpCodes.Ldc_I4_1,
                OpCodes.Add,
                Instructions.Stloc_S(var_i),
                Instructions.Ldloc_S(var_i),
                Instructions.Ldloc_S(4),
                OpCodes.Blt
                );

            // Change jump to end of loop into jump to drop sunflower seeds.
            ScytheBranchTail.ReplaceJump(0, DropSunflowerSeeds[0]);

            // Rewrite the tail of the Scythe harvest branch.
            ScytheBranchTail.Replace(
                // Jump to the 'drop subflower seeds' part.
                Instructions.Br(AttachLabel(DropSunflowerSeeds[0]))
                );
            #endregion

            #region Colored flowers
            // For colored flowers we need to call createItemDebris instead of createObjectDebris
            FindCode(
                // Game1.createObjectDebris (indexOfHarvest, xTile, yTile, -1, num3, 1f, null);
                OpCodes.Ldarg_0,
                OpCodes.Ldfld,
                OpCodes.Call,
                OpCodes.Ldarg_1,
                OpCodes.Ldarg_2,
                OpCodes.Ldc_I4_M1,
                OpCodes.Ldloc_S,
                OpCodes.Ldc_R4,
                OpCodes.Ldnull,
                OpCodes.Call
                ).Replace(
                // var tmp = CreateObject(this, num3);
                Instructions.Ldarg_0(),  // this
                Instructions.Ldloc_S(5), // num3
                Instructions.Call(typeof(ModEntry), nameof(CreateObject), typeof(Crop), typeof(int)),
                // Game1.createItemDebris(tmp, vector, -1, null, -1);
                Instructions.Ldloc_3(),   // vector
                Instructions.Ldc_I4_M1(), // -1
                Instructions.Ldnull(),    // null
                Instructions.Ldc_I4_M1(), // -1
                Instructions.Call(typeof(Game1), nameof(Game1.createItemDebris), typeof(Item), typeof(Vector2), typeof(int), typeof(GameLocation), typeof(int))
                );
            #endregion

            if (config.AllHaveQuality)
            {
                // Patch function calls for additional harvest to pass on the harvest quality.
                FindCode(
                    OpCodes.Ldc_I4_M1,
                    OpCodes.Ldc_I4_0,
                    Instructions.Ldc_R4(1.0f),
                    OpCodes.Ldnull,
                    Instructions.Call(typeof(Game1), nameof(Game1.createObjectDebris), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(float), typeof(GameLocation))
                    )[1] = Instructions.Ldloc_S(5);

                FindCode(
                    OpCodes.Ldc_I4_1,
                    OpCodes.Ldc_I4_0,
                    OpCodes.Ldc_I4_M1,
                    OpCodes.Ldc_I4_0,
                    OpCodes.Newobj,
                    Instructions.Callvirt(typeof(JunimoHarvester), nameof(JunimoHarvester.tryToAddItemToHut), typeof(Item))
                    )[3] = Instructions.Ldloc_S(5);
            }

            if (!config.ScytheHarvestFlowers)
            {
                var lbl = AttachLabel(instructions[0]);
                BeginCode().Append(
                    // if (harvestMethod==1 && programColored) {
                    Instructions.Ldarg_0(),
                    Instructions.Ldfld(typeof(Crop), nameof(Crop.harvestMethod)),
                    Instructions.Call_get(typeof(NetInt), nameof(NetInt.Value)),
                    Instructions.Brfalse(lbl),
                    Instructions.Ldarg_0(),
                    Instructions.Ldfld(typeof(Crop), nameof(Crop.programColored)),
                    Instructions.Call_get(typeof(NetBool), nameof(NetBool.Value)),
                    Instructions.Brfalse(lbl),
                    // return false
                    Instructions.Ldc_I4_0(),
                    Instructions.Ret()
                    // }
                    );
            }
        }
Beispiel #17
0
        void InventoryPage_performHoverAction()
        {
            // Change code responsible for obtaining the tooltip information.
            var var_item = generator.DeclareLocal(typeof(Item));
            InstructionRange code;

            try {
                // Linux & MacOS
                code = FindCode(
                    // switch (equipmentIcon.name) {
                    OpCodes.Ldloc_1,
                    Instructions.Ldfld(typeof(ClickableComponent), nameof(ClickableComponent.name)),
                    OpCodes.Stloc_2,
                    // case null: break;
                    OpCodes.Ldloc_2,
                    OpCodes.Brfalse,
                    // case "Hat":
                    OpCodes.Ldloc_2,
                    Instructions.Ldstr("Hat")
                    );
                code.Extend(code.Follow(4));
            } catch (Exception err) {
                LogException(err, LogLevel.Trace);
                // Windows
                code = FindCode(
                    // switch (equipmentIcon.name) {
                    OpCodes.Ldloc_1,
                    Instructions.Ldfld(typeof(ClickableComponent), nameof(ClickableComponent.name)),
                    OpCodes.Stloc_2,
                    // case "Hat":
                    OpCodes.Ldloc_2,
                    Instructions.Ldstr("Hat")
                    );
                code.Extend(
                    OpCodes.Ldloc_2,
                    Instructions.Ldstr("Pants"),
                    OpCodes.Call,
                    OpCodes.Brtrue,
                    OpCodes.Br
                    );
                code.Extend(code.End.Follow(-1));
            }
            code.Replace(
                // var item = EquipmentIcon.item
                code[0],
                Instructions.Ldfld(typeof(ClickableComponent), nameof(ClickableComponent.item)),
                Instructions.Stloc_S(var_item),
                // if (item != null)
                Instructions.Ldloc_S(var_item),
                Instructions.Brfalse(AttachLabel(code.End[0])),
                // hoveredItem = item;
                Instructions.Ldarg_0(),
                Instructions.Ldloc_S(var_item),
                Instructions.Stfld(typeof(InventoryPage), "hoveredItem"),
                // hoverText = item.getDescription();
                Instructions.Ldarg_0(),
                Instructions.Ldloc_S(var_item),
                Instructions.Callvirt(typeof(Item), nameof(Item.getDescription)),
                Instructions.Stfld(typeof(InventoryPage), "hoverText"),
                // hoverTitle = item.DisplayName;
                Instructions.Ldarg_0(),
                Instructions.Ldloc_S(var_item),
                Instructions.Callvirt_get(typeof(Item), nameof(Item.DisplayName)),
                Instructions.Stfld(typeof(InventoryPage), "hoverTitle")
                );
        }
Beispiel #18
0
        // Support harvesting of spring onions with scythe
        private void Crop_harvest_support_spring_onion(LocalBuilder var_vector)
        {
            if (config.HarvestMode.SpringOnion == HarvestModeEnum.HAND)
            {
                return;
            }

            // Note: the branch
            //   if (this.forageCrop)
            // refers mainly to the crop spring union.

            InstructionMatcher addItemToInventoryBool = Instructions.Callvirt(typeof(Farmer), nameof(Farmer.addItemToInventoryBool), typeof(Item), typeof(bool));

            if (helper.ModRegistry.IsLoaded("spacechase0.MoreRings"))
            {
                try {
                    addItemToInventoryBool = InstructionMatcher.AnyOf(
                        addItemToInventoryBool,
                        Instructions.Callvirt(AccessTools.TypeByName("MoreRings.Patches.CropPatcher"), "Farmer_AddItemToInventoryBool", typeof(Farmer), typeof(Item), typeof(bool))
                        );
                } catch (Exception e) {
                    Monitor.Log("The More Rings mod was loaded, but MoreRings.Patches.CropPatcher.Farmer_AddItemToInventoryBool(...) was not found.");
                    LogException(e, LogLevel.Warn);
                }
            }

            // Find the lines:
            InstructionRange AddItem;

            AddItem = FindCode(
                // if (Game1.player.addItemToInventoryBool (@object, false)) {
                Instructions.Call_get(typeof(Game1), nameof(Game1.player)),
                InstructionMatcher.AnyOf( // @object
                    OpCodes.Ldloc_0,
                    OpCodes.Ldloc_1
                    ),
                OpCodes.Ldc_I4_0,
                addItemToInventoryBool,
                OpCodes.Brfalse
                );

            var ldarg_0      = Instructions.Ldarg_0();
            var Ldloc_object = AddItem[1];
            var tail         = AttachLabel(AddItem.FindNext(
                                               OpCodes.Ldarg_0,
                                               Instructions.Ldfld(typeof(Crop), nameof(Crop.regrowAfterHarvest))
                                               )[0]);

            // Insert check for harvesting with scythe and act accordingly.
            AddItem.ReplaceJump(0, ldarg_0);
            AddItem.Prepend(
                // if (this.harvestMethod != 0) {
                ldarg_0,
                Instructions.Ldfld(typeof(Crop), nameof(Crop.harvestMethod)),
                Instructions.Call_get(typeof(NetInt), nameof(NetInt.Value)),
                Instructions.Brfalse(AttachLabel(AddItem[0])),
                // Game1.createItemDebris (@object, vector, -1, null, -1)
                Ldloc_object,                     // @object
                Instructions.Ldloc_S(var_vector), // vector
                Instructions.Ldc_I4_M1(),         // -1
                Instructions.Ldnull(),            // null
                Instructions.Ldc_I4_M1(),         // -1
                Instructions.Call(typeof(Game1), nameof(Game1.createItemDebris), typeof(Item), typeof(Vector2), typeof(int), typeof(GameLocation), typeof(int)),
                Instructions.Pop(),               // For SDV 1.4
                // Jump to tail
                Instructions.Br(tail)
                );
        }
Beispiel #19
0
        void InventoryPage_receiveLeftClick()
        {
            // Handle a ring-inventory slot being clicked.
            InstructionRange code;

            try {
                // Linux & MacOS
                code = FindCode(
                    // switch (equipmentIcon.name) {
                    OpCodes.Ldloc_1,
                    Instructions.Ldfld(typeof(ClickableComponent), nameof(ClickableComponent.name)),
                    OpCodes.Stloc_3,
                    // case null: break;
                    OpCodes.Ldloc_3,
                    OpCodes.Brfalse,
                    // case "Hat":
                    OpCodes.Ldloc_3,
                    Instructions.Ldstr("Hat")
                    );
                code.Extend(code.Follow(4));
            } catch (Exception err) {
                LogException(err, LogLevel.Trace);
                // Windows
                code = FindCode(
                    // switch (equipmentIcon.name) {
                    OpCodes.Ldloc_1,
                    Instructions.Ldfld(typeof(ClickableComponent), nameof(ClickableComponent.name)),
                    OpCodes.Stloc_3,
                    // case "Hat":
                    OpCodes.Ldloc_3,
                    Instructions.Ldstr("Hat")
                    );
                code.Extend(
                    OpCodes.Ldloc_3,
                    Instructions.Ldstr("Pants"),
                    OpCodes.Call,
                    OpCodes.Brtrue,
                    OpCodes.Br
                    );
                code.Extend(code.End.Follow(-1));
            }
            code.Replace(
                code[0],
                Instructions.Call(typeof(ModEntry), nameof(EquipmentClick), typeof(ClickableComponent)),
                Instructions.Pop()
                );

            // Select code for equipping items through shift+click.
            code = code.FindNext(
                // if (checkHeldItem ((Item i) => i is Ring))
                OpCodes.Ldarg_0,
                OpCodes.Ldsfld,
                OpCodes.Dup,
                OpCodes.Brtrue,
                //
                OpCodes.Pop,
                OpCodes.Ldsfld,
                OpCodes.Ldftn,
                OpCodes.Newobj,
                OpCodes.Dup,
                OpCodes.Stsfld,
                //
                Instructions.Callvirt(typeof(InventoryPage), "checkHeldItem", typeof(Func <Item, bool>)),
                OpCodes.Brfalse,
                // if (Game1.player.leftRing.Value == null)
                Instructions.Call_get(typeof(Game1), nameof(Game1.player)),
                Instructions.Ldfld(typeof(Farmer), nameof(Farmer.leftRing)),
                OpCodes.Callvirt,
                OpCodes.Brtrue
                );
            code.Extend(
                Instructions.Call_get(typeof(Game1), nameof(Game1.player)),
                Instructions.Ldfld(typeof(Farmer), nameof(Farmer.pantsItem)),
                OpCodes.Callvirt,
                OpCodes.Brtrue
                );
            Label equip_failed = (Label)code.End[-1].operand;

            code.Extend(code.End.Follow(-1));

            code.Replace(
                Instructions.Ldarg_0(),
                Instructions.Call(typeof(ModEntry), nameof(AutoEquipment), typeof(InventoryPage)),
                // if (true) return;
                Instructions.Brfalse(equip_failed),
                Instructions.Ret()
                );
        }
Beispiel #20
0
        void Tree_DayUpdate()
        {
            // Erase code related to tree spreading.
            var spread = FindCode(
                // if ((int)growthStage >= 5
                OpCodes.Ldarg_0,
                Instructions.Ldfld(typeof(Tree), nameof(Tree.growthStage)),
                OpCodes.Call,
                OpCodes.Ldc_I4_5,
                OpCodes.Blt,
                // && environment is Farm ...
                OpCodes.Ldarg_1,
                Instructions.Isinst(typeof(Farm)),
                OpCodes.Brfalse
                );

            spread.Extend(
                // hasSeed.Value = false;
                OpCodes.Ldarg_0,
                Instructions.Ldfld(typeof(Tree), nameof(Tree.hasSeed)),
                OpCodes.Ldc_I4_0,
                OpCodes.Callvirt
                );
            spread.length -= 4;

            spread.Prepend(
                // if (!tapped && config.OnlyPreventTapped)
                Instructions.Ldarg_0(),
                Instructions.Ldfld(typeof(Tree), nameof(Tree.tapped)),
                Instructions.Call_get(typeof(NetBool), nameof(NetBool.Value)),
                Instructions.Brtrue(AttachLabel(spread.End[0])),
                Instructions.Call(GetType(), nameof(isOnlyPreventTapped)),
                Instructions.Brfalse(AttachLabel(spread.End[0]))
                );
            spread.ReplaceJump(6, spread[0]);

            // if RetainSeed: Don't remove seeds when on the farm
            var remove_seed = spread.End;

            remove_seed.length += 4;

            // if (!config.RetainSeed || !environment is Farm)
            var lbl = generator.DefineLabel();

            remove_seed.Prepend(
                Instructions.Call(GetType(), nameof(isRetainSeed)),
                Instructions.Brfalse(lbl),
                Instructions.Ldarg_1(),
                Instructions.Isinst(typeof(Farm)),
                Instructions.Brtrue(AttachLabel(remove_seed.End[0]))
                );
            remove_seed.ReplaceJump(5, remove_seed[0]);
            remove_seed[5].labels.Add(lbl);

            // Increase chance that tree has a seed.
            // float num3 = 0.05f;
            var seed = remove_seed.FindNext(
                Instructions.Ldc_R4(0.05f),
                OpCodes.Stloc_1
                );

            seed[0] = Instructions.Call(GetType(), nameof(getSeedChance));
        }