Example #1
0
        public static string GetProfessionDescription(int whichProfession)
        {
            switch (whichProfession)
            {
            case Professions.Shaper:
                return("Lucky transmutes affected by daily luck twice as much (1-25% is now 2-50%).");

            case Professions.Sage:
                return($"When you rebound, you still take damage but you succeed anyway.");

            case Professions.Transmuter:
                double nextCoefficientCost = Alchemy.GetTransmutationMarkupPercentage(10) * 100D;
                return($"Transmutation (item creation only) is twice as lucky.");

            case Professions.Adept:
                return($"Leyline proximity increases your lucky rate up to 15%.");

            case Professions.Aurumancer:
                double nextCoefficientValue = Alchemy.GetLiquidationValuePercentage(10) * 100D;
                return($"Liquidation of items worth less than 1% of your current money can't rebound.");

            case Professions.Conduit:
                return($"Transmutation or liquidation worth less than 1% of your money doesn't cost stamina.");
            }
            return("");
        }
Example #2
0
        //sets up the basic structure of either transmute event, since they have some common ground
        private static void HandleEitherTransmuteEvent(string keyPressed)
        {
            // save is loaded
            if (Context.IsWorldReady)
            {
                //per the advice of Ento, abort if the player is in an event
                if (Game1.CurrentEvent != null)
                {
                    return;
                }

                //something may have gone wrong if this is null, maybe there's no save data?
                if (Game1.player != null)
                {
                    //get the player's current item
                    Item heldItem = Game1.player.CurrentItem;

                    //player is holding item
                    if (heldItem != null)
                    {
                        //get the item's ID
                        int heldItemID = heldItem.parentSheetIndex;

                        //abort any transmutation event for blacklisted items or items that for whatever reason can't exist in world.
                        if (blackListedItemIDs.Contains(heldItemID) || !heldItem.canBeDropped())
                        {
                            return;
                        }

                        //get the transmutation value, it's based on what it's worth to the player, including profession bonuses. This affects both cost and value.
                        int actualValue = ((StardewValley.Object)heldItem).sellToStorePrice();

                        //try to transmute [copy] the item
                        if (keyPressed.ToString() == instance.Config.TransmuteKey)
                        {
                            Alchemy.HandleTransmuteEvent(heldItem, actualValue);
                        }

                        //try to liquidate the item [sell for gold]
                        if (keyPressed.ToString() == instance.Config.LiquidateKey)
                        {
                            Alchemy.HandleLiquidateEvent(heldItem, actualValue);
                        }

                        //try to normalize the item [make all items of a different quality one quality and exchange any remainder for gold]
                        if (keyPressed.ToString() == instance.Config.NormalizeKey)
                        {
                            Alchemy.HandleNormalizeEvent(heldItem, actualValue);
                        }
                    }
                }
            }
        }
Example #3
0
        public List <string> GetExtraInfoForLevel(int whichLevel, int luckLevel)
        {
            double        nextCoefficientCost     = (Alchemy.GetTransmutationMarkupPercentage(whichLevel) - Alchemy.TRANSMUTATION_BONUS_PER_LEVEL) * 100D;
            double        nextCoefficientValue    = (Alchemy.GetLiquidationValuePercentage(whichLevel) + Alchemy.LIQUIDATION_BONUS_PER_LEVEL) * 100D;
            string        coefficientCost         = $"Cost: {nextCoefficientCost.ToString()}% Value: {nextCoefficientValue.ToString()}%";
            double        luckyTransmuteMinimum   = ((Alchemy.GetLuckyTransmuteChanceWithoutDailyOrProfessionBonuses(whichLevel, luckLevel) + 0.01) * 100);
            double        luckyTransmuteMaximum   = ((Alchemy.GetLuckyTransmuteChanceWithoutDailyOrProfessionBonuses(whichLevel, luckLevel) + Alchemy.LUCK_NORMALIZATION_FOR_FREE_TRANSMUTES) * 100);
            string        luckyTransmuteChance    = $"Lucky transmutes: {luckyTransmuteMinimum.ToString()}-{luckyTransmuteMaximum.ToString()}% Stamina drain -{ ((1 - Alchemy.GetAlchemyStaminaCostSkillMultiplierForLevel(whichLevel)) * 100).ToString() }%";
            string        distanceFromTowerImpact = $"Leyline distance negated by { (whichLevel) }.";
            List <string> extraInfoList           = new List <string>();

            extraInfoList.Add(coefficientCost);
            extraInfoList.Add(luckyTransmuteChance);
            extraInfoList.Add(distanceFromTowerImpact);
            return(extraInfoList);
        }
Example #4
0
        public static bool HandleTransmuteEvent(Item heldItem, int actualValue)
        {
            // if the recipes list doesn't contain the item you're holding, you can't transmute that.
            var recipes = EquivalentExchange.GetTransmutationFormulas();

            // sorted recipe list
            var validRecipes = recipes.GetRecipesForOutput(heldItem.parentSheetIndex);

            if (validRecipes.Count == 0)
            {
                return(true);
            }

            // use more sorting magic to find a potential recipe from the player's inventory
            // prioritize the recipes by their input costs (cheapest inputs are prioritized by the function GetRecipesForOutput)
            var optimalRecipe = validRecipes.FindBestRecipe(Game1.player);

            // something has stopped us from finding a valid recipe. The player either doesn't have the necessary items
            // or doesn't have the energy to do the transmutation.
            if (optimalRecipe == null)
            {
                return(true);
            }

            var breakRepeaterLoop = false;

            Alchemy.HandleAlchemyEnergyDeduction(optimalRecipe.GetEnergyCost(), false);

            if (optimalRecipe.GetEnergyCost() > EquivalentExchange.CurrentEnergy)
            {
                breakRepeaterLoop = true;
            }

            Alchemy.IncreaseTotalTransmuteValue((int)Math.Floor(Math.Max(1D, optimalRecipe.GetEnergyCost())));

            Util.TakeItemFromPlayer(optimalRecipe.InputId, optimalRecipe.GetInputCost(), Game1.player);

            Item spawnedItem = heldItem.getOne();

            spawnedItem.Stack = optimalRecipe.GetOutputQuantity();

            Util.GiveItemToPlayer((StardewValley.Object)spawnedItem, Game1.player);

            SoundUtil.PlayMagickySound();

            return(breakRepeaterLoop);
        }
        public static void DoPostRenderHudEvent()
        {
            if (Game1.activeClickableMenu != null)
            {
                return;
            }

            Type t = Type.GetType("ExperienceBars.Mod, ExperienceBars");

            int currentAlchemyLevel      = EquivalentExchange.instance.currentPlayerData.AlchemyLevel;
            int currentAlchemyExperience = EquivalentExchange.instance.currentPlayerData.AlchemyExperience;
            int x = 10;
            int y = (int)Util.GetStaticField(t, "expBottom");

            int previousExperienceRequired = 0, nextExperienceRequired = 1;

            if (currentAlchemyLevel == 0)
            {
                nextExperienceRequired = Alchemy.GetAlchemyExperienceNeededForNextLevel();
            }
            else if (currentAlchemyLevel != 10)
            {
                previousExperienceRequired = Alchemy.GetAlchemyExperienceNeededForLevel(currentAlchemyLevel - 1);
                nextExperienceRequired     = Alchemy.GetAlchemyExperienceNeededForLevel(currentAlchemyLevel);
            }

            int   progressTowardCurrentLevel   = currentAlchemyExperience - previousExperienceRequired;
            int   experienceGapForCurrentLevel = nextExperienceRequired - previousExperienceRequired;
            float progressBarPercentage        = (float)progressTowardCurrentLevel / experienceGapForCurrentLevel;

            if (currentAlchemyLevel == 10)
            {
                progressBarPercentage = -1;
            }

            object[] args = new object[]
            {
                x, y,
                alchemySkillIcon, new Rectangle(0, 0, 16, 16),
                currentAlchemyLevel, progressBarPercentage,
                new Color(196, 79, 255),
            };
            Util.CallStaticMethod(t, "renderSkillBar", args);

            Util.SetStaticField(t, "expBottom", y + 40);
        }
Example #6
0
        //handles draining energy/stamina on successful transmute
        public static void HandleAlchemyEnergyDeduction(double energyCost, bool isForcedStaminaDrain)
        {
            double remainingStaminaCost = energyCost;

            // if the stamina drain is "forced" it means you can't pay for this transaction with energy
            // the *entire* cost goes to stamina.
            if (!isForcedStaminaDrain)
            {
                //if you have any alkahestry energy, it will try to use as much as it can
                double alkahestryCost = (double)Math.Min(EquivalentExchange.CurrentEnergy, energyCost);

                //and deduct that from whatever stamina cost might be left over (which may be all of it)
                remainingStaminaCost -= alkahestryCost;

                Alchemy.ReduceAlkahestryEnergy(alkahestryCost);
            }
            Game1.player.Stamina -= (float)remainingStaminaCost;
            EquivalentExchange.AddAlchemyExperience((int)Math.Floor(Math.Max(energyCost, 1D)));
        }
Example #7
0
        //command to give yourself experience for debug purposes primarily

        private void GiveAlchemyExperience(object sender, string[] args)
        {
            if (args.Length != 1)
            {
                Log.info("Command format: giveAlchemyExp <amount>");
                return;
            }

            int amt = 0;

            try
            {
                amt = Convert.ToInt32(args[0]);
            }
            catch (Exception e)
            {
                Log.error("Bad experience amount.");
                return;
            }

            Alchemy.AddAlchemyExperience(amt);
            Log.info("Added " + amt + " alchemy experience.");
        }
Example #8
0
 private static void HandleToolTransmuteConsequence(float cost)
 {
     Alchemy.HandleAlchemyEnergyDeduction(GetToolTransmutationEnergyCost(EquivalentExchange.AlchemyLevel, cost), false);
     Alchemy.HandleAlchemyEnergyDeduction(GetToolTransmutationStaminaCost(EquivalentExchange.AlchemyLevel, cost), true);
     Alchemy.IncreaseTotalTransmuteValue((int)Math.Floor(cost));
 }
Example #9
0
        //this was almost entirely stolen from spacechase0 with very little contribution on my part.
        internal static void HandleToolTransmute(Tool tool)
        {
            int alchemyLevel = (EquivalentExchange.IsShiftKeyPressed() ? 0 : Alchemy.GetToolTransmuteRadius());
            int toolLevel    = tool.UpgradeLevel;

            //set last user to dodge a null pointer
            var toolPlayerFieldReflector = tool.GetType().GetField("lastUser", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);

            toolPlayerFieldReflector.SetValue(tool, Game1.player);

            Point hitLocation = GetMouseHitLocation();

            GameLocation location = Game1.player.currentLocation;

            bool performedAction = false;

            //getting this out of the way, helps with easily determining tool types
            bool isScythe      = tool is MeleeWeapon && tool.Name.ToLower().Contains("scythe");
            bool isAxe         = tool is StardewValley.Tools.Axe;
            bool isPickaxe     = tool is StardewValley.Tools.Pickaxe;
            bool isHoe         = tool is StardewValley.Tools.Hoe;
            bool isWateringCan = tool is StardewValley.Tools.WateringCan;

            for (int xOffset = -alchemyLevel; xOffset <= alchemyLevel; xOffset++)
            {
                for (int yOffset = -alchemyLevel; yOffset <= alchemyLevel; yOffset++)
                {
                    if (!isScythe)
                    {
                        if (!IsCapableOfWithstandingToolTransmuteCost(Game1.player, 2F))
                        {
                            return;
                        }
                    }

                    Vector2 offsetPosition = new Vector2(xOffset + hitLocation.X, yOffset + hitLocation.Y);

                    if (location.objects.ContainsKey(offsetPosition))
                    {
                        if (isAxe || isScythe || isPickaxe || isHoe)
                        {
                            var snapshotPlayerExperience = Game1.player.experiencePoints;
                            performedAction = DoToolFunction(location, Game1.player, tool, (int)offsetPosition.X, (int)offsetPosition.Y);
                            RestorePlayerExperience(snapshotPlayerExperience);
                            if (performedAction && !isScythe)
                            {
                                HandleToolTransmuteConsequence(2F);
                            }
                        }
                    }
                    else if (location.terrainFeatures.ContainsKey(offsetPosition))
                    {
                        //a terrain feature, rather than a tool check, might respond to the tool
                        TerrainFeature terrainFeature = location.terrainFeatures[offsetPosition];

                        //don't break stumps unless the player is in precision mode.
                        if (terrainFeature is Tree && isAxe && (!(terrainFeature as Tree).stump || EquivalentExchange.IsShiftKeyPressed()))
                        {
                            Netcode.NetArray <int, Netcode.NetInt> snapshotPlayerExperience = Game1.player.experiencePoints;
                            //trees get removed automatically
                            performedAction = DoToolFunction(location, Game1.player, tool, (int)offsetPosition.X, (int)offsetPosition.Y);
                            RestorePlayerExperience(snapshotPlayerExperience);

                            if (performedAction)
                            {
                                HandleToolTransmuteConsequence(2F);
                            }
                        }
                        else if (terrainFeature is Grass && location is Farm && isScythe)
                        {
                            int oldHay = (location as Farm).piecesOfHay;
                            var snapshotPlayerExperience = Game1.player.experiencePoints;
                            if (terrainFeature.performToolAction(tool, 0, offsetPosition, location))
                            {
                                location.terrainFeatures.Remove(offsetPosition);
                                //HandleToolTransmuteConsequence(); Scythe transmute is special and doesn't cost anything, but you don't get experience.
                                performedAction = true;
                            }
                            RestorePlayerExperience(snapshotPlayerExperience);

                            //hay get! spawn the sprite animation for acquisition of hay
                            if (oldHay < (location as Farm).piecesOfHay)
                            {
                                SpawnHayAnimationSprite(location, offsetPosition, Game1.player);
                            }
                        }
                        else if (terrainFeature is HoeDirt && isWateringCan && (tool as WateringCan).WaterLeft > 0)
                        {
                            //state of 0 is unwatered.
                            if ((terrainFeature as HoeDirt).state != 1)
                            {
                                var snapshotPlayerExperience = Game1.player.experiencePoints;
                                terrainFeature.performToolAction(tool, 0, offsetPosition, location);
                                RestorePlayerExperience(snapshotPlayerExperience);
                                (tool as WateringCan).WaterLeft = (tool as WateringCan).WaterLeft - 1;
                                SpawnWateringCanAnimationSprite(location, offsetPosition);
                                HandleToolTransmuteConsequence(2F);
                                performedAction = true;
                            }
                        }
                        else if (isPickaxe && terrainFeature is HoeDirt)
                        {
                            var snapshotPlayerExperience = Game1.player.experiencePoints;
                            performedAction = DoToolFunction(location, Game1.player, tool, (int)offsetPosition.X, (int)offsetPosition.Y);
                            RestorePlayerExperience(snapshotPlayerExperience);

                            if (performedAction)
                            {
                                HandleToolTransmuteConsequence(2F);
                            }
                        }
                    }
                    else if ((isPickaxe || isAxe))
                    {
                        ICollection <ResourceClump> largeResourceClusters = null;
                        if (location is Farm)
                        {
                            largeResourceClusters = (NetCollection <ResourceClump>)location.GetType().GetField("resourceClumps", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).GetValue(location);
                        }
                        else if (location is MineShaft)
                        {
                            largeResourceClusters = (NetObjectList <ResourceClump>)location.GetType().GetField("resourceClumps", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).GetValue(location);
                        }
                        else if (location is Woods)
                        {
                            largeResourceClusters = (location as Woods).stumps;
                        }
                        DoLargeResourceClusterAction(largeResourceClusters, tool, offsetPosition, performedAction);
                    }
                    else if (isHoe)
                    {
                        var snapshotPlayerExperience = Game1.player.experiencePoints;
                        performedAction = DoToolFunction(location, Game1.player, tool, (int)offsetPosition.X, (int)offsetPosition.Y);
                        RestorePlayerExperience(snapshotPlayerExperience);

                        if (performedAction)
                        {
                            HandleToolTransmuteConsequence(2F);
                        }
                    }
                }
            }

            if (performedAction)
            {
                SoundUtil.PlayMagickySound();
            }
        }
        //sets up the basic structure of either transmute event, since they have some common ground
        private static void HandleEitherTransmuteEvent(string keyPressed)
        {
            // save is loaded
            if (Context.IsWorldReady)
            {
                //per the advice of Ento, abort if the player is in an event
                if (Game1.CurrentEvent != null)
                {
                    return;
                }

                //something may have gone wrong if this is null, maybe there's no save data?
                if (Game1.player != null)
                {
                    //get the player's current item
                    Item heldItem = Game1.player.CurrentItem;

                    //player is holding item
                    if (heldItem != null)
                    {
                        //get the item's ID
                        int heldItemID = heldItem.parentSheetIndex;

                        //alchemy energy can be used to execute a complex tool action if a tool is in hand.
                        if (heldItem is StardewValley.Tool && keyPressed.ToString() == instance.Config.TransmuteKey)
                        {
                            Tool itemTool = heldItem as Tool;

                            bool isScythe      = itemTool is MeleeWeapon && itemTool.Name.ToLower().Contains("scythe");
                            bool isAxe         = itemTool is Axe;
                            bool isPickaxe     = itemTool is Pickaxe;
                            bool isHoe         = itemTool is Hoe;
                            bool isWateringCan = itemTool is WateringCan;

                            bool canDoToolAlchemy = isScythe || isAxe || isPickaxe || isHoe || isWateringCan;

                            if (canDoToolAlchemy)
                            {
                                Alchemy.HandleToolTransmute(itemTool);
                            }
                        }

                        //try to normalize the item [make all items of a different quality one quality and exchange any remainder for gold]
                        if (keyPressed.ToString() == instance.Config.NormalizeKey)
                        {
                            Alchemy.HandleNormalizeEvent(heldItem);
                            return;
                        }

                        //abort any transmutation event for blacklisted items or items that for whatever reason can't exist in world.
                        if (!GetTransmutationFormulas().HasItem(heldItemID) || !heldItem.canBeDropped())
                        {
                            return;
                        }

                        //get the transmutation value, it's based on what it's worth to the player, including profession bonuses. This affects both cost and value.
                        int actualValue = ((StardewValley.Object)heldItem).sellToStorePrice();

                        //try to transmute [copy] the item
                        if (keyPressed.ToString() == instance.Config.TransmuteKey)
                        {
                            var shouldBreakOutOfRepeater = Alchemy.HandleTransmuteEvent(heldItem, actualValue);
                            if (shouldBreakOutOfRepeater && !brokeRepeaterDueToNoEnergy)
                            {
                                brokeRepeaterDueToNoEnergy = true;
                                instance.heldCounter       = 1;
                                instance.updateTickCount   = AUTO_REPEAT_UPDATE_RATE_REFRESH * 2;
                            }
                        }
                    }
                }
            }
        }
 private void SpaceEvents_ShowNightEndMenus(object sender, EventArgsShowNightEndMenus e)
 {
     //the new day hook seems to be inconsistent, so this is a full restore at the end of the night.
     Alchemy.RestoreAlkahestryEnergyForNewDay();
 }
Example #12
0
        private static void GraphicsEvents_OnPreRenderHudEvent(object sender, EventArgs e)
        {
            if (!Context.IsWorldReady)
            {
                return;
            }

            if (Game1.eventUp)
            {
                return;
            }

            if (!allowInfoBubbleToRender)
            {
                return;
            }

            //per the advice of Ento, abort if the player is in an event
            if (Game1.CurrentEvent != null)
            {
                return;
            }

            //something may have gone wrong if this is null, maybe there's no save data?
            if (Game1.player != null)
            {
                //get the player's current item
                Item heldItem = Game1.player.CurrentItem;

                //player is holding item
                if (heldItem != null)
                {
                    //get the item's ID
                    int heldItemID = heldItem.parentSheetIndex;

                    //abort any transmutation event for blacklisted items or items that for whatever reason can't exist in world.
                    if (blackListedItemIDs.Contains(heldItemID) || !heldItem.canBeDropped())
                    {
                        return;
                    }

                    //get the transmutation value, it's based on what it's worth to the player, including profession bonuses. This affects both cost and value.
                    int   actualValue    = ((StardewValley.Object)heldItem).sellToStorePrice();
                    int   transmuteCost  = (int)Math.Ceiling(Alchemy.GetTransmutationMarkupPercentage() * actualValue);
                    int   liquidateValue = (int)Math.Floor(Alchemy.GetLiquidationValuePercentage() * actualValue);
                    float staminaDrain   = (float)Math.Round(Alchemy.GetStaminaCostForTransmutation(actualValue), 2);
                    float luckyChance    = (float)Math.Round(Alchemy.GetLuckyTransmuteChance() * 100, 2);
                    float reboundChance  = (float)Math.Round(Alchemy.GetReboundChance(false, false) * 100, 2);
                    int   reboundDamage  = Alchemy.GetReboundDamage(actualValue);

                    int    xPos  = -15;
                    int    yPos  = 0;// Game1.viewport.Height / 2 - 200;
                    int    xSize = 240;
                    int    ySize = 320;
                    int    dialogPositionMarkerX = xPos + 40;
                    int    dialogPositionMarkerY = yPos + 100;
                    string cost       = $"Make -{transmuteCost.ToString()}g";
                    string value      = $"Melt +{liquidateValue.ToString()}g";
                    string luck       = $"Luck {luckyChance.ToString()}%";
                    string stam       = $"Stam -{staminaDrain.ToString()}";
                    string rebound    = $"Fail {reboundChance.ToString()}%";
                    string damage     = $"HP -{reboundDamage.ToString()}";
                    int    rowSpacing = 30;
                    Game1.drawDialogueBox(xPos, yPos, xSize, ySize, false, true, (string)null, false);
                    Game1.spriteBatch.DrawString(Game1.smallFont, cost, new Microsoft.Xna.Framework.Vector2(dialogPositionMarkerX, dialogPositionMarkerY), Game1.textColor);
                    dialogPositionMarkerY += rowSpacing;
                    Game1.spriteBatch.DrawString(Game1.smallFont, value, new Microsoft.Xna.Framework.Vector2(dialogPositionMarkerX, dialogPositionMarkerY), Game1.textColor);
                    dialogPositionMarkerY += rowSpacing;
                    Game1.spriteBatch.DrawString(Game1.smallFont, luck, new Microsoft.Xna.Framework.Vector2(dialogPositionMarkerX, dialogPositionMarkerY), Game1.textColor);
                    dialogPositionMarkerY += rowSpacing;
                    Game1.spriteBatch.DrawString(Game1.smallFont, stam, new Microsoft.Xna.Framework.Vector2(dialogPositionMarkerX, dialogPositionMarkerY), Game1.textColor);
                    dialogPositionMarkerY += rowSpacing;
                    Game1.spriteBatch.DrawString(Game1.smallFont, rebound, new Microsoft.Xna.Framework.Vector2(dialogPositionMarkerX, dialogPositionMarkerY), Game1.textColor);
                    dialogPositionMarkerY += rowSpacing;
                    Game1.spriteBatch.DrawString(Game1.smallFont, damage, new Microsoft.Xna.Framework.Vector2(dialogPositionMarkerX, dialogPositionMarkerY), Game1.textColor);
                    dialogPositionMarkerY += rowSpacing;
                }
            }
        }
Example #13
0
        public static void HandleNormalizeEvent(Item heldItem, int actualValue)
        {
            //get the id of the item the player is holding
            int itemID = heldItem.parentSheetIndex;

            //if it's a blacklisted item, abort.
            if (EquivalentExchange.blackListedItemIDs.Contains(itemID))
            {
                return;
            }

            //declare vars to remember how many items of each quality the player has.
            float normalQuality  = 0;
            int   silverQuality  = 0;
            int   goldQuality    = 0;
            int   iridiumQuality = 0;

            //search the inventory for items of the same type
            foreach (Item inventoryItem in Game1.player.items)
            {
                if (inventoryItem == null)
                {
                    continue;
                }

                if (inventoryItem.parentSheetIndex != itemID)
                {
                    continue;
                }

                //if the item can't be cast as an object, abort.
                StardewValley.Object itemObject = inventoryItem as StardewValley.Object;
                if (itemObject == null)
                {
                    return;
                }

                switch (itemObject.quality)
                {
                case 0:
                    normalQuality += itemObject.Stack;
                    break;

                case 1:
                    silverQuality += itemObject.Stack;
                    break;

                case 2:
                    goldQuality += itemObject.Stack;
                    break;

                case 4:
                    iridiumQuality += itemObject.Stack;
                    break;

                default:
                    break;
                }
            }

            //destroy all the items
            while (Game1.player.hasItemInInventory(itemID, 1))
            {
                Game1.player.removeFirstOfThisItemFromInventory(itemID);
            }

            //calculate the normalized value of all qualities
            normalQuality += (5F / 4F) * silverQuality;
            normalQuality += (3F / 2F) * goldQuality;
            normalQuality += (2F) * iridiumQuality;

            float remainder = normalQuality % 1F;

            normalQuality -= normalQuality % 1F;

            StardewValley.Object newItemObject = new StardewValley.Object(itemID, 1);

            //the remainder is liquidated, and the liquidation factor of your skill level is applied.
            remainder *= newItemObject.sellToStorePrice() * (float)Alchemy.GetLiquidationValuePercentage();

            while (normalQuality > 0)
            {
                newItemObject = new StardewValley.Object(itemID, 1);

                if (Game1.player.couldInventoryAcceptThisItem((Item)newItemObject))
                {
                    Game1.player.addItemToInventory((Item)newItemObject);
                }
                else
                {
                    Game1.createItemDebris((Item)newItemObject, Game1.player.getStandingPosition(), Game1.player.FacingDirection, (GameLocation)null);
                }
                normalQuality--;
            }

            //floored, any excess is truncated. Sorry math.
            Game1.player.Money += (int)Math.Floor(remainder);
        }
Example #14
0
        public static void HandleLiquidateEvent(Item heldItem, int actualValue)
        {
            //if the player is holding only one item, don't let them transmute it to money unless they're holding shift.
            if (heldItem.Stack == 1 && !EquivalentExchange.IsShiftKeyPressed())
            {
                return;
            }

            //placeholder for determining if the transmute occurs, so it knows to play a sound.
            bool didTransmuteOccur = false;

            //placeholder for determining if the transmute rebounds, so it knows to play a different sound.
            bool didTransmuteFail = false;

            //if the transmute did fail, this preserves the damage so we can apply it in one cycle, otherwise batches look weird af
            int reboundDamageTaken = 0;

            //needed for some profession effects
            bool isItemWorthLessThanOnePercentOfMoney = (Game1.player.money * 0.01F > actualValue);

            //stamina cost is overridden for conduits if money is > 100x the item's value.
            double staminaCost = (isItemWorthLessThanOnePercentOfMoney && Game1.player.professions.Contains(Professions.Conduit)) ? 0D : Alchemy.GetStaminaCostForTransmutation(actualValue);

            //if the player lacks the stamina to execute a transmute, abort
            if (Game1.player.Stamina <= staminaCost)
            {
                return;
            }

            //if we fail this check, it's because a rebound would kill the player.
            //if the rebound chance is zero, this check will automatically pass.
            if (!Alchemy.CanSurviveRebound(actualValue, isItemWorthLessThanOnePercentOfMoney, true))
            {
                return;
            }

            //if we fail this check, transmutation will fail this cycle.
            //this is our "rebound check"
            if (Alchemy.DidPlayerFailReboundCheck(isItemWorthLessThanOnePercentOfMoney, true))
            {
                reboundDamageTaken += Alchemy.GetReboundDamage(actualValue);
                didTransmuteFail    = true;
            }

            //the conduit profession makes it so that the transmutation succeeds anyway, after taking damage.
            if (Game1.player.professions.Contains((int)Professions.Sage) || !didTransmuteFail)
            {
                //if we reached this point transmutation will succeed
                didTransmuteOccur = true;

                Alchemy.HandleStaminaDeduction(staminaCost, false);

                //we floor the math here because we don't want weirdly divergent values based on stack count - the rate is fixed regardless of quantity
                //this occurs at the expense of rounding - liquidation is lossy.
                int liquidationValue = (int)Math.Floor(Alchemy.GetLiquidationValuePercentage() * actualValue);

                int totalValue = liquidationValue;

                Game1.player.Money += totalValue;

                Game1.player.reduceActiveItemByOne();

                //the percentage of experience you get is increased by the lossiness of the transmute
                //as you increase in levels, this amount diminishes to a minimum of 1.
                double experienceValueCoefficient = 1D - Alchemy.GetLiquidationValuePercentage();
                int    experienceValue            = (int)Math.Floor(Math.Sqrt(experienceValueCoefficient * actualValue / 10 + 1));

                Alchemy.AddAlchemyExperience(experienceValue);

                //a transmute (at least one) happened, play the cash money sound
                if (didTransmuteOccur && !didTransmuteFail)
                {
                    SoundUtil.PlayMoneySound();
                }
            }

            //a rebound occurred, apply the damage and also play the ouchy sound.
            if (didTransmuteFail)
            {
                Alchemy.TakeDamageFromRebound(reboundDamageTaken);
                SoundUtil.PlayReboundSound();
            }
        }
Example #15
0
        public static void HandleTransmuteEvent(Item heldItem, int actualValue)
        {
            //cost of a single item, multiplied by the cost multiplier below
            int transmutationCost = (int)Math.Ceiling(Alchemy.GetTransmutationMarkupPercentage() * actualValue);

            //nor should totalCost of a single cycle
            int totalCost = transmutationCost;

            //placeholder for determining if the transmute occurs, so it knows to play a sound.
            bool didTransmuteOccur = false;

            //placeholder for determining if the transmute rebounds, so it knows to play a different sound.
            bool didTransmuteFail = false;

            //if the transmute did fail, this preserves the damage so we can apply it in one cycle, otherwise batches look weird af
            int reboundDamageTaken = 0;

            //needed for some profession effects
            bool isItemWorthLessThanOnePercentOfMoney = (Game1.player.money * 0.01F > actualValue);

            //stamina cost is overridden for conduits if money is > 100x the item's value.
            double staminaCost = (isItemWorthLessThanOnePercentOfMoney && Game1.player.professions.Contains(Professions.Conduit)) ? 0D : Alchemy.GetStaminaCostForTransmutation(actualValue);

            //loop for each transmute-cycle attempt
            if (Game1.player.money >= totalCost)
            {
                //if the player lacks the stamina to execute a transmute, abort
                if (Game1.player.Stamina <= staminaCost)
                {
                    return;
                }

                //if we fail this check, it's because a rebound would kill the player.
                //if the rebound chance is zero, this check will automatically pass.
                if (!Alchemy.CanSurviveRebound(actualValue, isItemWorthLessThanOnePercentOfMoney, false))
                {
                    return;
                }

                //if we fail this check, transmutation will fail this cycle.
                //this is our "rebound check"
                if (Alchemy.DidPlayerFailReboundCheck(isItemWorthLessThanOnePercentOfMoney, false))
                {
                    reboundDamageTaken += Alchemy.GetReboundDamage(actualValue);
                    didTransmuteFail    = true;
                    //the conduit profession makes it so that the transmutation succeeds anyway, after taking damage.
                }
                if (Game1.player.professions.Contains((int)Professions.Sage) || !didTransmuteFail)
                {
                    didTransmuteOccur = true;

                    Alchemy.HandleStaminaDeduction(staminaCost, true);

                    Game1.player.Money -= totalCost;

                    Item spawnedItem = heldItem.getOne();

                    Game1.createItemDebris(spawnedItem, Game1.player.getStandingPosition(), Game1.player.FacingDirection, (GameLocation)null);

                    //the percentage of experience you get is increased by the lossiness of the transmute
                    //as you increase in levels, this amount diminishes to a minimum of 1.
                    double experienceValueCoefficient = Alchemy.GetTransmutationMarkupPercentage() - 1D;
                    int    experienceValue            = (int)Math.Floor(Math.Sqrt(experienceValueCoefficient * actualValue / 10 + 1));

                    Alchemy.AddAlchemyExperience(experienceValue);
                }
            }

            //a transmute (at least one) happened, play the magicky sound
            if (didTransmuteOccur && !didTransmuteFail)
            {
                SoundUtil.PlayMagickySound();
            }

            //a rebound occurred, apply the damage and also play the ouchy sound.
            if (didTransmuteFail)
            {
                Alchemy.TakeDamageFromRebound(reboundDamageTaken);
                SoundUtil.PlayReboundSound();
            }
        }