Пример #1
0
        /****************************************************
         *   This is a bit of a "reverse-quick-stack" in that only items that add to
         *   stacks currently in the player's inventory will be pulled from the chest.
         *
         *   The code actually works out to be a bit of a combination of the
         *   QuickStack and LootAll methods.
         *   Also based a fair amount on Player.GetItem()
         *   !ref:Player:#4497.00#
         */
        public static void SmartLoot()
        {
            if (Main.localPlayer.chest == -1)
            {
                return;
            }

            var pInventory = Main.localPlayer.inventory;  //Item[]
            var chestItems = Main.localPlayer.chestItems; //Item[]
            var sendNetMsg = Main.localPlayer.chest > -1; //bool

            int index;

            //for each item in inventory (including coins & hotbar)...
            for (int i = -8; i < 50; i++)   //this trick from the vanilla code
            {
                index = i < 0 ? 58 + i : i; //do ammo and coins first

                //...if item is not blank && not a full stack...
                if (!pInventory[index].IsBlank() && pInventory[index].stack < pInventory[index].maxStack)
                {   //...check every item in chest...
                    int j = -1;
                    // quit if we max out this stack or reach the end of the chest;
                    // also note that the DoCoins() call may reduce this stack to 0, so check that too
                    while (pInventory[index].stack < pInventory[index].maxStack &&
                           ++j < Chest.maxItems && pInventory[index].stack > 0)
                    {   //...for a matching item stack...
                        if (!chestItems[j].IsBlank() && chestItems[j].IsTheSameAs(pInventory[index]))
                        {
                            Sound.ItemMoved.Play();
                            //...and merge it to the Player's inventory

                            // I *think* this ItemText.NewText command just makes the text pulse...
                            // I don't entirely grok how it works, but included for parity w/ vanilla
                            ItemText.NewText(chestItems[j], IHUtils.StackMergeD(ref chestItems[j], ref pInventory[index]));
                            Main.localPlayer.DoCoins(index);
                            if (chestItems[j].stack <= 0)
                            {
                                chestItems[j] = new Item(); //reset this item if all stack transferred
                                // if (sendNetMsg) IHUtils.SendNetMessage(j); //only for non-bank chest
                                break;
                            }
                            // if (sendNetMsg) IHUtils.SendNetMessage(j);
                        }
                    }
                }
            }
            //when all is said and done, check for newly available recipes.
            Recipe.FindRecipes();
        }
Пример #2
0
        protected TexturedButton(ButtonSlot <TexturedButton> parent,
                                 TIH action,
                                 string label,
                                 string tooltip          = "",
                                 Color?bg_color          = null,
                                 Texture2D texture       = null,
                                 Rectangle?inactive_rect = null,
                                 Rectangle?active_rect   = null
                                 ) : base(parent, action, label)
        {
            Tooltip         = tooltip; // this should set ShowTooltip = true automatically if not ""
            BackgroundColor = bg_color ?? Color.White;

            Texture      = (texture == null) ? IHBase.ButtonGrid : texture;
            InactiveRect = inactive_rect.HasValue ? inactive_rect : IHUtils.GetSourceRect(action);
            ActiveRect   = active_rect.HasValue ? active_rect : IHUtils.GetSourceRect(action, true);
        }
Пример #3
0
        /****************************************************
         *   This will compare the categories of items in the player's
         *  inventory to those of items in the open container and
         *  deposit any items of matching categories.
         */
        public static void SmartDeposit()
        {
            if (Main.localPlayer.chest == -1)
            {
                return;
            }

            var pInventory = Main.localPlayer.inventory;  //Item[]
            var chestItems = Main.localPlayer.chestItems; //Item[]
            var sendNetMsg = Main.localPlayer.chest > -1; //bool

            // define a query that creates category groups for the items in the chests,
            // then pulls out the category keys into a distinct list (List<ItemCat>)
            var catList =
                (from item in chestItems
                 where !item.IsBlank()
                 group item by item.GetCategory() into catGroup
                 from cat in catGroup
                 select catGroup.Key).Distinct()     //no duplicates
                .ToList();                           //store the query results

            if (IHBase.ModOptions["LockingEnabled"]) //slot locking on
            {
                for (int i = 49; i >= 10; i--)       // reverse through player inv
                {
                    if (!pInventory[i].IsBlank() && !IHPlayer.SlotLocked(i) &&
                        catList.Contains(pInventory[i].GetCategory()))
                    {
                        IHUtils.MoveItemToChest(i, sendNetMsg);
                    }
                }
            }
            else //no locking
            {
                for (int i = 49; i >= 10; i--)
                {
                    // if chest contains a matching category
                    if (!pInventory[i].IsBlank() && catList.Contains(pInventory[i].GetCategory()))
                    {
                        IHUtils.MoveItemToChest(i, sendNetMsg);
                    }
                }
            }
            Recipe.FindRecipes();
        }
Пример #4
0
        /// <summary>
        /// Takes an Action and will perform it wrapped in some net update code if we are a client. Otherwise it just does whatever it is.
        /// </summary>
        /// <param name="action">An Action (a lambda with no output)</param>
        public static void DoChestUpdateAction(Action action)
        {
            var player = Main.localPlayer;

            // check net status and make sure a non-bank chest is open
            // (bank-chests, i.e. piggy-bank & safe, are handled solely client-side)
            if (Main.netMode == 1 && player.chest > -1)
            {
                Item[] oldItems = new Item[player.chestItems.Length];

                // make an exact copy of the chest's original contents
                for (int i = 0; i < oldItems.Length; i++)
                {
                    oldItems[i] = player.chestItems[i].Clone();
                }

                // perform the requested action
                action();

                // compare each item in the old copy of the original contents
                // to the chest's new contents and send net-update message
                // if they do not match.
                for (int i = 0; i < oldItems.Length; i++)
                {
                    var oldItem = oldItems[i];
                    var newItem = player.chestItems[i];

                    if (oldItem.IsNotTheSameAs(newItem) || oldItem.stack != newItem.stack)
                    {
                        IHUtils.SendNetMessage(i);
                    }
                }
            }
            else // And this is important...
            {
                action();
            }
        }
Пример #5
0
        // TODO: Here are my thoughts on making sure shift-click syncs correctly with
        // the server: obviously, blindly placing the NetMessage update calls
        // wherever it seemed like Vanilla indicated they should go didn't work.
        // Now that I have a better understanding of what all that rigamarole is
        // supposed to do, I think that the most efficient way to handle this
        // would be to have any function that modifies a slot or slots in a
        // container record or return a list of the indices of those slots.
        // Numerous methods in IHUtils already return an int to indicate the
        // effect of their run, but only under certain conditions does that int
        // indicate the affected index. Other return statuses (statii?) could
        // indicate a modified slot or even multiple slots, but since I didn't
        // think I had any immediate need to know which slots those were, that
        // information was not recorded.

        // Now, it wouldn't be too hard to whip up a small data-transfer-object
        // that can be passed between method calls and hold both the return
        // status as it is now and a record of any slots which were modified
        // along the way; this would prevent us from having to take a
        // sledgehammer approach like we did with the calls that modify
        // chest-item-slot en-masse. While the sledge may be the best or
        // most-effective tool when many slots are likely to be modified at
        // once, this shift-click isn't likely to affect more than a few during
        // any one run, and looping over the entire container atleast twice for
        // each click is probably something we should avoid if we can.

        // Of course this is all obvious and I'm just being verbose for
        // absolute-clarity's sake. My point--and the catch--is that even
        // though the DTO would be simple to create and use, the code in IHUtils
        // is much more of a tangled mass of spaghetti-code than I realized, and
        // tracing down every spot where we'd need to make changes (though
        // likely small) to the code to integrate the object will be a delicate
        // job very prone to breaking things in unexpected ways. At least with
        // my luch it would be.  Anyway, that's why, for now, I'm going to take
        // the sledgehammer to this and hope it doesn't affect performance too
        // badly.

        /// <summary>
        /// Shift + Left Click on item slot to move it between inventory and chest
        /// </summary>
        /// <param name="slot"> </param>
        /// <param name="release"> </param>
        /// <returns>True if shift not held while left-clicking, or if no applicable
        /// recipient is present to move item into. </returns>
        public override bool PreItemSlotLeftClick(ItemSlot slot, ref bool release)
        {
            if (!(bool)IHBase.Instance.options["enableShiftMove"].Value)
            {
                return(true);
            }

            if (slot.modBase == null && release && KState.Special.Shift.Down())
            {
                if (Main.localPlayer.chestItems != null && !slot.MyItem.IsBlank()) //chests and banks
                {
                    // Moving inventory item -> chest
                    if (slot.type == "Inventory" || slot.type == "Coin" || slot.type == "Ammo")
                    {
                        IHPlayer.DoChestUpdateAction(
                            () => {
                            if (IHUtils.ShiftToChest(ref slot))
                            {
                                Recipe.FindRecipes(); // !ref:Main:#22640.36#
                            }
                        });
                    }
                    // Moving chest item -> inventory
                    else if (slot.type == "Chest")
                    {
                        if (IHUtils.ShiftToPlayer(ref slot, Main.localPlayer.chest > -1))
                        {
                            Recipe.FindRecipes();

                            // We can take the easy route here since there's only
                            // one chest slot that could have been affected.
                            if (Main.netMode == 1 && Main.localPlayer.chest > -1) //non-bank
                            {
                                IHUtils.SendNetMessage(slot.index);
                            }
                        }
                    }
                    return(false);
                }
                if (Main.craftGuide) //the Guide's crafting info slot
                {
                    if (Main.guideItem.IsBlank() && !slot.MyItem.IsBlank() && (slot.type == "Inventory" || slot.type == "Coin" || slot.type == "Ammo"))
                    {
                        if (slot.MyItem.material && !slot.MyItem.notMaterial)
                        {
                            Sound.ItemMoved.Play();
                            Main.guideItem = slot.MyItem.Clone();
                            slot.MyItem    = new Item();
                            Recipe.FindRecipes();
                        }
                    }
                    else if (!Main.guideItem.IsBlank() && slot.type == "CraftGuide")
                    {
                        if (IHUtils.ShiftToPlayer(ref slot, false))
                        {
                            Main.guideItem = new Item();
                        }
                        Recipe.FindRecipes();
                    }
                    return(false);
                }
                if (Main.reforge) //Item reforging
                {
                    if (Main.reforgeItem.IsBlank() && slot.type == "Inventory" && !slot.MyItem.IsBlank())
                    {
                        if (slot.MyItem.maxStack == 1 && Prefix.CanHavePrefix(slot.MyItem))
                        {
                            Sound.ItemMoved.Play();
                            Main.reforgeItem = slot.MyItem.Clone();
                            slot.MyItem      = new Item();
                            Recipe.FindRecipes();
                        }
                    }
                    else if (!Main.reforgeItem.IsBlank() && slot.type == "Reforge")
                    {
                        if (IHUtils.ShiftToPlayer(ref slot, false))
                        {
                            Main.reforgeItem = new Item();
                        }
                        Recipe.FindRecipes();
                    }
                    return(false);
                }
            }
            return(true);
        }
        private void addIconButtons()
        {
            // offset of lock indicator
            var lockOffset = new Vector2(-(float)(int)((float)Constants.ButtonW / 2) - 4,
                                         -(float)(int)((float)Constants.ButtonH / 2) + 8);

            Func <TIH, string> getLabel = a => Constants.DefaultButtonLabels[a];
            Func <TIH, Color>  getBGcol = (a) => (a == TIH.SaveName)
                                                ? Constants.EquipSlotColor * 0.85f
                                                : Constants.ChestSlotColor * 0.85f;
            Func <TIH, string> getTtip;

            if (IHBase.ModOptions["ShowTooltips"])
            {
                if (IHBase.ModOptions["ShowKeyBind"])
                {
                    getTtip = a => getLabel(a) + IHUtils.GetKeyTip(a);
                }
                else
                {
                    getTtip = a => getLabel(a);
                }
            }
            else
            {
                getTtip = a => "";
            }

            Func <TIH, TIH, TexturedButton> getButton
                = (base_by_action, a)
                  => TexturedButton.New((ButtonSlot <TexturedButton>)ButtonBases[base_by_action],
                                        action: a,
                                        label: getLabel(a),
                                        tooltip: getTtip(a),
                                        bg_color: getBGcol(a),
                                        texture: IHBase.ButtonGrid,
                                        inactive_rect: IHUtils.GetSourceRect(a),
                                        active_rect: IHUtils.GetSourceRect(a, true)
                                        );

            // Btn obj            Socket Action   Button Action
            // -------            -------------   -------------
            var sort  = getButton(TIH.Sort, TIH.Sort);
            var rsort = getButton(TIH.Sort, TIH.ReverseSort);
            var loot  = getButton(TIH.LootAll, TIH.LootAll);
            var depo  = getButton(TIH.DepositAll, TIH.DepositAll);
            var sdep  = getButton(TIH.DepositAll, TIH.SmartDeposit);
            var qstk  = getButton(TIH.QuickStack, TIH.QuickStack);
            var sloo  = getButton(TIH.QuickStack, TIH.SmartLoot);
            var rena  = getButton(TIH.Rename, TIH.Rename);
            var save  = getButton(TIH.Rename, TIH.SaveName);

            var cancel = TextButton.New(CancelEditBase, TIH.CancelEdit, getLabel(TIH.CancelEdit));


            // Add Services //

            // sort enables default action for sort/rsort by ... default.
            sort.AddSortToggle(rsort);
            //for funsies let's just make that whole toggle thing pointless
            sort.Hooks.OnRightClick  += () => IHPlayer.Sort(true);
            rsort.Hooks.OnRightClick += () => IHPlayer.Sort();


            // add default click, let rClick lock it, and make shift switch buttons
            depo.EnableDefault().MakeLocking(lockOffset, Color.Firebrick).AddToggle(sdep.EnableDefault());
            qstk.EnableDefault().MakeLocking(lockOffset, Color.Firebrick).AddToggle(sloo.EnableDefault());

            // these just need their default actions enabled.
            loot.EnableDefault().Hooks.OnRightClick += () => IHPlayer.CleanStacks();  //why not
            cancel.EnableDefault();
            // this prevents the "Cancel" text from being too big when the player
            // goes back into the rename interface (though it seems the vanilla
            // "Cancel" text behaves the same way...improvement!)
            cancel.Hooks.OnClick += CancelEditBase.ResetScale;

            // make Rename Chest button change to Save Name button when
            // clicked, and vice-versa. Well, technically, the buttons will
            // switch automatically when Main.editChest changes state, but
            // since that's what clicking these buttons does...
            save.EnableDefault().AddDynamicToggle(rena.EnableDefault(), () => Main.editChest);
        }