Exemple #1
0
        private static int ComputeModifiedStack(int CombinedQuantity, double MaxEffect, int PreviousValue, out double Effect, out double ValueBeforeRandomization)
        {
            Effect = Math.Min(MaxEffect, ModEntry.UserConfig.ComputeProcessingPower(CombinedQuantity));
            double DesiredNewValue = PreviousValue * Effect;

            ValueBeforeRandomization = DesiredNewValue;
            return(RNGHelpers.WeightedRound(DesiredNewValue));
        }
        private static void OnReadyForHarvest(SObject Machine)
        {
            if (Context.IsMainPlayer)
            {
                try
                {
                    if (Machine.heldObject.Value != null && Machine.TryGetCombinedQuantity(out int CombinedQuantity) && !Machine.HasModifiedOutput())
                    {
                        int PreviousOutputStack = Machine.heldObject.Value.Stack;

                        double OutputEffect    = ModEntry.UserConfig.ComputeProcessingPower(CombinedQuantity);
                        double DesiredNewValue = PreviousOutputStack * OutputEffect;
                        int    NewOutputStack  = RNGHelpers.WeightedRound(DesiredNewValue);

                        Machine.heldObject.Value.Stack = NewOutputStack;
                        ModEntry.LogTrace(CombinedQuantity, Machine, Machine.TileLocation, "HeldObject.Stack", PreviousOutputStack, DesiredNewValue, NewOutputStack, OutputEffect);
                    }
                }
                finally { Machine.SetHasModifiedOutput(false); }
            }
        }
Exemple #3
0
 public static void Postfix(CrabPot __instance, GameLocation location)
 {
     try
     {
         //  Check if the output item was just set
         if (PrefixData != null && PrefixData.CrabPot == __instance && PrefixData.PreviousHeldObject == null && PrefixData.CurrentHeldObject != null)
         {
             //  Modify the output quantity based on the combined machine's processing power
             if (__instance.IsCombinedMachine() && ModEntry.UserConfig.ShouldModifyInputsAndOutputs(__instance) && __instance.TryGetCombinedQuantity(out int CombinedQuantity))
             {
                 double Power           = ModEntry.UserConfig.ComputeProcessingPower(CombinedQuantity);
                 double DesiredNewValue = PrefixData.CurrentHeldObjectQuantity * Power;
                 int    RoundedNewValue = RNGHelpers.WeightedRound(DesiredNewValue);
                 __instance.heldObject.Value.Stack = RoundedNewValue;
                 ModEntry.LogTrace(CombinedQuantity, PrefixData.CrabPot, PrefixData.CrabPot.TileLocation, "HeldObject.Stack", PrefixData.CurrentHeldObjectQuantity,
                                   DesiredNewValue, RoundedNewValue, Power);
             }
         }
     }
     catch (Exception ex)
     {
         ModEntry.Logger.Log(string.Format("Unhandled Error in {0}.{1}:\n{2}", nameof(CrabPot_DayUpdatePatch), nameof(Postfix), ex), LogLevel.Error);
     }
 }
Exemple #4
0
        public static void Postfix(SObject __instance)
        {
            try
            {
                if (Context.IsMainPlayer)
                {
                    if (__instance is Cask CaskInstance)
                    {
                        CaskInstance.agingRate.fieldChangeEvent += (field, oldValue, newValue) =>
                        {
                            try
                            {
                                //  Prevent recursive fieldChangeEvents from being invoked when our code sets Cask.agingRate.Value
                                if (CurrentlyModifying.Contains(CaskInstance))
                                {
                                    return;
                                }

                                if (Context.IsMainPlayer && Context.IsWorldReady && oldValue != newValue)
                                {
                                    if (ModEntry.UserConfig.ShouldModifyProcessingSpeed(__instance) && __instance.TryGetCombinedQuantity(out int CombinedQuantity))
                                    {
                                        double DefaultAgingRate = CaskInstance.GetAgingMultiplierForItem(CaskInstance.heldObject.Value);

                                        bool IsTrackedValueChange = false;
                                        if (oldValue <= 0 && newValue > 0) // Handle the first time agingRate is initialized
                                        {
                                            IsTrackedValueChange = true;
                                        }
                                        else if (newValue == DefaultAgingRate) // Handle cases where the game tries to reset the agingRate
                                        {
                                            IsTrackedValueChange = true;
                                        }

                                        if (IsTrackedValueChange)
                                        {
                                            float  PreviousAgingRate  = CaskInstance.agingRate.Value;
                                            double DurationMultiplier = ModEntry.UserConfig.ComputeProcessingPower(CombinedQuantity);
                                            float  NewAgingRate       = (float)(DurationMultiplier * PreviousAgingRate);

                                            if (NewAgingRate != PreviousAgingRate)
                                            {
                                                try
                                                {
                                                    CurrentlyModifying.Add(CaskInstance);
                                                    CaskInstance.agingRate.Value = NewAgingRate;
                                                }
                                                finally { CurrentlyModifying.Remove(CaskInstance); }

                                                ModEntry.Logger.Log(string.Format("Set {0} agingRate from {1} to {2} ({3}%)",
                                                                                  __instance.Name, PreviousAgingRate, NewAgingRate, (DurationMultiplier * 100.0).ToString("0.##")), ModEntry.InfoLogLevel);
                                            }
                                        }
                                    }
                                }
                            }
                            catch (Exception Error)
                            {
                                ModEntry.Logger.Log(string.Format("Unhandled Error in {0}.{1}.FieldChangeEvent(Cask):\n{2}", nameof(MinutesUntilReadyPatch), nameof(Postfix), Error), LogLevel.Error);
                            }
                        };
                    }
                    else
                    {
                        __instance.minutesUntilReady.fieldChangeEvent += (field, oldValue, newValue) =>
                        {
                            try
                            {
                                if (Context.IsMainPlayer && Context.IsWorldReady && oldValue != newValue && oldValue < newValue && newValue > 0)
                                {
                                    if (ModEntry.UserConfig.ShouldModifyProcessingSpeed(__instance) && __instance.TryGetCombinedQuantity(out int CombinedQuantity))
                                    {
                                        int    PreviousMinutes    = __instance.MinutesUntilReady;
                                        double DurationMultiplier = 1.0 / ModEntry.UserConfig.ComputeProcessingPower(CombinedQuantity);
                                        double TargetValue        = DurationMultiplier * PreviousMinutes;
                                        int    NewMinutes         = RNGHelpers.WeightedRound(TargetValue);

                                        //  Round to nearest 10 since the game processes machine outputs every 10 game minutes
                                        //  EX: If NewValue = 38, then there is a 20% chance of rounding down to 30, 80% chance of rounding up to 40
                                        int SmallestDigit = NewMinutes % 10;
                                        NewMinutes = NewMinutes - SmallestDigit;     // Round down to nearest 10
                                        if (RNGHelpers.RollDice(SmallestDigit / 10.0))
                                        {
                                            NewMinutes += 10;     // Round up
                                        }
                                        //  There seems to be a bug where there is no product if the machine is instantly done processing.
                                        NewMinutes = Math.Max(10, NewMinutes); // temporary fix - require at least one 10-minute processing cycle

                                        if (NewMinutes != PreviousMinutes)
                                        {
                                            __instance.MinutesUntilReady = NewMinutes;
                                            if (NewMinutes <= 0)
                                            {
                                                __instance.readyForHarvest.Value = true;
                                            }

                                            ModEntry.Logger.Log(string.Format("Set {0} MinutesUntilReady from {1} to {2} ({3}%, Target value before weighted rounding = {4})",
                                                                              __instance.Name, PreviousMinutes, NewMinutes, (DurationMultiplier * 100.0).ToString("0.##"), TargetValue.ToString("0.#")), ModEntry.InfoLogLevel);
                                        }
                                    }
                                }
                            }
                            catch (Exception Error)
                            {
                                ModEntry.Logger.Log(string.Format("Unhandled Error in {0}.{1}.FieldChangeEvent:\n{2}", nameof(MinutesUntilReadyPatch), nameof(Postfix), Error), LogLevel.Error);
                            }
                        };
                    }
                }
            }
            catch (Exception ex)
            {
                ModEntry.Logger.Log(string.Format("Unhandled Error in {0}.{1}:\n{2}", nameof(MinutesUntilReadyPatch), nameof(Postfix), ex), LogLevel.Error);
            }
        }
Exemple #5
0
        /// <summary>Intended to be invoked whenever the player inserts materials into a machine that requires inputs, such as when placing copper ore into a furnace.</summary>
        private static void OnInputsInserted(PerformObjectDropInData PODIData)
        {
            if (PODIData == null || PODIData.CurrentHeldObject == null || PODIData.Input == null)
            {
                return;
            }

            bool IsCurrentPlayer = (!Context.IsMultiplayer && !Context.IsSplitScreen) || PODIData.Farmer.UniqueMultiplayerID == Game1.player.UniqueMultiplayerID;

            if (!IsCurrentPlayer)
            {
                return;
            }

            SObject Machine = PODIData.Machine;

            if (!ModEntry.UserConfig.ShouldModifyInputsAndOutputs(Machine) || !Machine.TryGetCombinedQuantity(out int CombinedQuantity))
            {
                return;
            }

            int SecondaryInputQuantityAvailable = int.MaxValue;

            if (PODIData.Input.IsOre() && PODIData.Farmer != null && ModEntry.UserConfig.FurnaceMultiplyCoalInputs)
            {
                SecondaryInputQuantityAvailable = PODIData.Farmer.Items.Where(x => x != null && x.IsCoal()).Sum(x => x.Stack);
            }

            //  Compute the maximum multiplier we can apply to the input and output based on how many more of the inputs the player has
            int    PreviousInputQuantityUsed = PODIData.PreviousInputQuantity - PODIData.CurrentInputQuantity;
            double MaxMultiplier             = Math.Min(SecondaryInputQuantityAvailable, PreviousInputQuantityUsed == 0 ?
                                                        PODIData.CurrentInputQuantity :
                                                        Math.Abs(PODIData.PreviousInputQuantity * 1.0 / PreviousInputQuantityUsed));

            //  Modify the output
            int PreviousOutputStack = PODIData.CurrentHeldObjectQuantity;
            int NewOutputStack      = ComputeModifiedStack(CombinedQuantity, MaxMultiplier, PreviousOutputStack, out double OutputEffect, out double DesiredNewOutputValue);

            PODIData.CurrentHeldObject.Stack = NewOutputStack;
            Machine.SetHasModifiedOutput(true);
            ModEntry.LogTrace(CombinedQuantity, PODIData.Machine, PODIData.Machine.TileLocation, "HeldObject.Stack", PreviousOutputStack, DesiredNewOutputValue, NewOutputStack, OutputEffect);

            //  Modify the input
            int    CurrentInputQuantityUsed;
            double InputEffect;
            double DesiredNewInputValue;

            if (PreviousInputQuantityUsed <= 0)
            {
                //  No clue why, but for some machines the game hasn't actually taken the input yet by the time Object.performObjectDropIn finishes.
                //  so assume the input amount was = to 1.
                CurrentInputQuantityUsed = ComputeModifiedStack(CombinedQuantity, MaxMultiplier, 1, out InputEffect, out DesiredNewInputValue) - 1 - Math.Abs(PreviousInputQuantityUsed);
            }
            else
            {
                CurrentInputQuantityUsed = ComputeModifiedStack(CombinedQuantity, MaxMultiplier, PreviousInputQuantityUsed, out InputEffect, out DesiredNewInputValue);
            }
            int NewInputStack = PODIData.PreviousInputQuantity - CurrentInputQuantityUsed;

            PODIData.Input.Stack = NewInputStack;
            if (NewInputStack <= 0)
            {
                if (PODIData.WasInputInInventory)
                {
                    PODIData.Farmer.removeItemFromInventory(PODIData.Input);
                }
                else
                {
                    PODIData.Input.Stack = 1; // Just a failsafe to avoid glitched out Items with zero quantity, such as if the input came from a chest due to the Automate mod
                }
            }

            if (PODIData.Input.IsOre() && PODIData.Farmer != null && ModEntry.UserConfig.FurnaceMultiplyCoalInputs)
            {
                int RemainingCoalToConsume = RNGHelpers.WeightedRound(OutputEffect) - 1; // 1 coal was already automatically consumed by the vanilla function
                for (int i = 0; i < PODIData.Farmer.Items.Count; i++)
                {
                    Item CurrentItem = PODIData.Farmer.Items[i];
                    if (CurrentItem != null && CurrentItem.IsCoal())
                    {
                        int AmountToConsume = Math.Min(CurrentItem.Stack, RemainingCoalToConsume);
                        CurrentItem.Stack      -= AmountToConsume;
                        RemainingCoalToConsume -= AmountToConsume;

                        if (CurrentItem.Stack <= 0)
                        {
                            PODIData.Farmer.removeItemFromInventory(i);
                        }

                        if (RemainingCoalToConsume <= 0)
                        {
                            break;
                        }
                    }
                }
            }
        }