Exemple #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("");
        }
Exemple #2
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);
        }
Exemple #3
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;
                }
            }
        }
        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);
        }
        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();
            }
        }