Exemple #1
0
            // **********************************************************************************************
            // *****          Stash replacement accurately and neatly finds a free stash location       *****
            // **********************************************************************************************
            private static bool GilesStashAttempt(CacheACDItem item, out int[] XY, out int StashPage)
            {
                XY=new int[] { -1, -1 };
                     StashPage=-1;

                     int iPlayerDynamicID=ZetaDia.Me.CommonData.DynamicId;
                     int iOriginalGameBalanceId=item.ThisBalanceID;
                     int iOriginalDynamicID=item.ThisDynamicID;
                     int iOriginalStackQuantity=item.ThisItemStackQuantity;
                     string sOriginalItemName=item.ThisRealName;
                     string sOriginalInternalName=item.ThisInternalName;
                     GilesItemType OriginalGilesItemType=DetermineItemType(item.ThisInternalName, item.ThisDBItemType, item.ThisFollowerType);
                     GilesBaseItemType thisGilesBaseType=DetermineBaseType(OriginalGilesItemType);
                     bool bOriginalTwoSlot=DetermineIsTwoSlot(OriginalGilesItemType);
                     bool bOriginalIsStackable=DetermineIsStackable(OriginalGilesItemType);
                     int iAttempts;
                     if (_dictItemStashAttempted.TryGetValue(iOriginalDynamicID, out iAttempts))
                     {
                          Log("GSError: Detected a duplicate stash attempt, DB item mis-read error, now forcing this item as a 2-slot item");
                          _dictItemStashAttempted[iOriginalDynamicID]=iAttempts+1;
                          bOriginalTwoSlot=true;
                          bOriginalIsStackable=false;
                          if (iAttempts>6)
                          {
                                Log("GSError: Detected an item stash loop risk, now re-mapping stash treating everything as 2-slot and re-attempting");
                                // Array for what blocks are or are not blocked
                                for (int iRow=0; iRow<=29; iRow++)
                                     for (int iColumn=0; iColumn<=6; iColumn++)
                                          GilesStashSlotBlocked[iColumn, iRow]=false;
                                // Block off the entire of any "protected stash pages"
                                foreach (int iProtPage in Zeta.CommonBot.Settings.CharacterSettings.Instance.ProtectedStashPages)
                                     for (int iProtRow=0; iProtRow<=9; iProtRow++)
                                          for (int iProtColumn=0; iProtColumn<=6; iProtColumn++)
                                                GilesStashSlotBlocked[iProtColumn, iProtRow+(iProtPage*10)]=true;
                                // Remove rows we don't have
                                for (int iRow=(ZetaDia.Me.NumSharedStashSlots/7); iRow<=29; iRow++)
                                     for (int iColumn=0; iColumn<=6; iColumn++)
                                          GilesStashSlotBlocked[iColumn, iRow]=true;
                                // Map out all the items already in the stash
                                foreach (ACDItem tempitem in ZetaDia.Me.Inventory.StashItems)
                                {
                                     if (tempitem.BaseAddress!=IntPtr.Zero)
                                     {
                                          int inventoryRow=tempitem.InventoryRow;
                                          int inventoryColumn=tempitem.InventoryColumn;
                                          // Mark this slot as not-free
                                          GilesStashSlotBlocked[inventoryColumn, inventoryRow]=true;
                                          // Try and reliably find out if this is a two slot item or not
                                          GilesStashSlotBlocked[inventoryColumn, inventoryRow+1]=true;
                                          if (inventoryRow!=19&&inventoryRow!=9&&inventoryRow!=29)
                                          {
                                                GilesStashSlotBlocked[inventoryColumn, inventoryRow+1]=true;
                                          }
                                     }
                                }
                          }
                          if (iAttempts>15)
                          {
                                Log("***************************");
                                Log("GSError: Emergency Stop: No matter what we tried, we couldn't prevent an infinite stash loop. Sorry. Now stopping the bot.");
                                BotMain.Stop();
                                return false;
                          }
                     }
                     else
                     {
                          _dictItemStashAttempted.Add(iOriginalDynamicID, 1);
                     }
                     // Safety incase it's not actually in the backpack anymore
                     /*if (item.InventorySlot != InventorySlot.PlayerBackpack)
                     {
                          Log("GSError: Diablo 3 memory read error, or item became invalid [StashAttempt-4]", true);
                          return false;
                     }*/
                     int iLeftoverStackQuantity=0;
                     // Item log for cool stuff stashed

                     if (thisGilesBaseType==GilesBaseItemType.WeaponTwoHand||thisGilesBaseType==GilesBaseItemType.WeaponOneHand||thisGilesBaseType==GilesBaseItemType.WeaponRange||
                          thisGilesBaseType==GilesBaseItemType.Armor||thisGilesBaseType==GilesBaseItemType.Jewelry||thisGilesBaseType==GilesBaseItemType.Offhand||
                          thisGilesBaseType==GilesBaseItemType.FollowerItem)
                     {
                          double iThisItemValue=ValueThisItem(item, OriginalGilesItemType);
                          LogGoodItems(item, thisGilesBaseType, OriginalGilesItemType, iThisItemValue);
                     }

                     int iPointX=-1;
                     int iPointY=-1;
                     // First check if we can top-up any already-existing stacks in the stash
                     if (bOriginalIsStackable)
                     {
                          foreach (ACDItem tempitem in ZetaDia.Me.Inventory.StashItems)
                          {
                                if (tempitem.BaseAddress==IntPtr.Zero)
                                {
                                     Log("GSError: Diablo 3 memory read error, or stash item became invalid [StashAttempt-5]", true);
                                     return false;
                                }
                                // Check if we combine the stacks, we won't overfill them
                                if ((tempitem.GameBalanceId==iOriginalGameBalanceId)&&(tempitem.ItemStackQuantity<tempitem.MaxStackCount))
                                {
                                     iLeftoverStackQuantity=(tempitem.ItemStackQuantity+iOriginalStackQuantity)-tempitem.MaxStackCount;
                                     iPointX=tempitem.InventoryColumn;
                                     iPointY=tempitem.InventoryRow;

                                     // Will we have leftovers?
                                     if (iLeftoverStackQuantity<=0)
                                          goto FoundStashLocation;
                                     else
                                          goto HandleStackMovement;
                                }
                          }
                HandleStackMovement:
                          if ((iPointX>=0)&&(iPointY>=0))
                          {
                                ZetaDia.Me.Inventory.MoveItem(iOriginalDynamicID, iPlayerDynamicID, InventorySlot.PlayerSharedStash, iPointX, iPointY);
                          }
                     }
                     iPointX=-1;
                     iPointY=-1;
                     // If it's a 2-square item, find a double-slot free
                     if (bOriginalTwoSlot)
                     {
                          for (int iRow=0; iRow<=29; iRow++)
                          {
                                bool bBottomPageRow=(iRow==9||iRow==19||iRow==29);
                                for (int iColumn=0; iColumn<=6; iColumn++)
                                {
                                     // If nothing in the 1st row
                                     if (!GilesStashSlotBlocked[iColumn, iRow])
                                     {
                                          bool bNotEnoughSpace=false;
                                          // Bottom row of a page = no room
                                          if (bBottomPageRow)
                                                bNotEnoughSpace=true;
                                          // Already something in the stash in the 2nd row)
                                          else if (GilesStashSlotBlocked[iColumn, iRow+1])
                                                bNotEnoughSpace=true;
                                          if (!bNotEnoughSpace)
                                          {
                                                iPointX=iColumn;
                                                iPointY=iRow;
                                                goto FoundStashLocation;
                                          }
                                     }
                                }
                          }
                     } // 2 slot item?
                     // Now deal with any leftover 1-slot items
                     else
                     {
                          // First we try and find somewhere "sensible"
                          for (int iRow=0; iRow<=29; iRow++)
                          {
                                bool bTopPageRow=(iRow==0||iRow==10||iRow==20);
                                bool bBottomPageRow=(iRow==9||iRow==19||iRow==29);
                                for (int iColumn=0; iColumn<=6; iColumn++)
                                {
                                     // Nothing in this slot
                                     if (!GilesStashSlotBlocked[iColumn, iRow])
                                     {
                                          bool bSensibleLocation=false;
                                          if (!bTopPageRow&&!bBottomPageRow)
                                          {
                                                // Something above and below this slot, or an odd-numbered row, so put something here
                                                if ((GilesStashSlotBlocked[iColumn, iRow+1]&&GilesStashSlotBlocked[iColumn, iRow-1])||
                                                     (iRow)%2!=0)
                                                     bSensibleLocation=true;
                                          }
                                          // Top page row with something directly underneath already blocking
                                          else if (bTopPageRow)
                                          {
                                                if (GilesStashSlotBlocked[iColumn, iRow+1])
                                                     bSensibleLocation=true;
                                          }
                                          // Bottom page row with something directly over already blocking
                                          else
                                          {
                                                bSensibleLocation=true;
                                          }
                                          // Sensible location? Yay, stash it here!
                                          if (bSensibleLocation)
                                          {
                                                iPointX=iColumn;
                                                iPointY=iRow;
                                                // Keep looking for places if it's a stackable to try to stick it at the end
                                                if (!bOriginalIsStackable)
                                                     goto FoundStashLocation;
                                          }
                                     }
                                }
                          }
                          // Didn't find a "sensible" place, let's try and force it in absolutely anywhere
                          if ((iPointX<0)||(iPointY<0))
                          {
                                for (int iRow=0; iRow<=29; iRow++)
                                {
                                     for (int iColumn=0; iColumn<=6; iColumn++)
                                     {
                                          // Nothing in this spot, we're good!
                                          if (!GilesStashSlotBlocked[iColumn, iRow])
                                          {
                                                iPointX=iColumn;
                                                iPointY=iRow;
                                                // Keep looking for places if it's a stackable to try to stick it at the end
                                                if (!bOriginalIsStackable)
                                                     goto FoundStashLocation;
                                          }
                                     }
                                }
                          }
                     }
                FoundStashLocation:
                     if ((iPointX<0)||(iPointY<0))
                     {
                          Log("Fatal Error: No valid stash location found for '"+sOriginalItemName+"' ["+sOriginalInternalName+" - "+OriginalGilesItemType.ToString()+"]", true);
                          Log("***************************");
                          Log("GSError: Emergency Stop: You need to stash an item but no valid space could be found. Stash is full? Stopping the bot to prevent infinite town-run loop.");
                          MuleBehavior=true;
                          ZetaDia.Service.Party.LeaveGame(false);
                          return false;
                     }
                     // We have two valid points that are empty, move the object here!
                     GilesStashSlotBlocked[iPointX, iPointY]=true;
                     if (bOriginalTwoSlot)
                          GilesStashSlotBlocked[iPointX, iPointY+1]=true;

                     XY=new int[] { iPointX, iPointY };

                     if (iPointY<10)
                          StashPage=0;
                     else if (iPointY<20)
                          StashPage=1;
                     else
                          StashPage=2;

                     return true;
            }
        private static void StashedItemLog(CacheACDItem i)
        {
            if (Bot.BotStatistics.ProfileStats.CurrentProfile==null)
                return;

            switch (i.ACDItem.ItemType)
            {
                case ItemType.CraftingPage:
                case ItemType.CraftingPlan:
                     case ItemType.CraftingReagent:
                          Bot.BotStatistics.ProfileStats.CurrentProfile.ItemStats.stashedItemTotals[(int)LootIndex.Crafting]++;
                    break;
                case ItemType.Gem:
                          Bot.BotStatistics.ProfileStats.CurrentProfile.ItemStats.stashedItemTotals[(int)LootIndex.Gem]++;
                    break;
                case ItemType.Amulet:
                case ItemType.Axe:
                case ItemType.Belt:
                case ItemType.Boots:
                case ItemType.Bow:
                case ItemType.Bracer:
                case ItemType.CeremonialDagger:
                case ItemType.Chest:
                case ItemType.Cloak:
                case ItemType.Crossbow:
                case ItemType.Dagger:
                case ItemType.Daibo:
                case ItemType.FistWeapon:
                case ItemType.FollowerSpecial:
                case ItemType.Gloves:
                case ItemType.HandCrossbow:
                case ItemType.Helm:
                case ItemType.Legs:
                case ItemType.Mace:
                case ItemType.MightyBelt:
                case ItemType.MightyWeapon:
                case ItemType.Mojo:
                case ItemType.Orb:
                case ItemType.Polearm:
                case ItemType.Quiver:
                case ItemType.Ring:
                case ItemType.Shield:
                case ItemType.Shoulder:
                case ItemType.Spear:
                case ItemType.SpiritStone:
                case ItemType.Staff:
                case ItemType.Sword:
                case ItemType.VoodooMask:
                case ItemType.Wand:
                case ItemType.WizardHat:
                    if (i.ThisQuality == ItemQuality.Legendary)
                                Bot.BotStatistics.ProfileStats.CurrentProfile.ItemStats.stashedItemTotals[3]++;
                    else if (i.ThisQuality > ItemQuality.Magic3)
                                Bot.BotStatistics.ProfileStats.CurrentProfile.ItemStats.stashedItemTotals[2]++;
                    else
                                Bot.BotStatistics.ProfileStats.CurrentProfile.ItemStats.stashedItemTotals[1]++;
                    break;
            }
        }
Exemple #3
0
        //D3 v1.07 new plans
        //Amulet
        //Archon Armor
        //Archon Gauntlets
        //Archon Spaulders
        //Razorspikes
        // **********************************************************************************************
        // *****      Determine if we should stash this item or not based on item type and score    *****
        // **********************************************************************************************
        private static bool ShouldWeStashThis(CacheACDItem thisitem)
        {
            // Stash all unidentified items - assume we want to keep them since we are using an identifier over-ride
                if (thisitem.IsUnidentified)
                {
                     if (bOutputItemScores) Log(thisitem.ThisRealName+" ["+thisitem.ThisInternalName+"] = (autokeep unidentified items)");
                     return true;
                }
                // Now look for Misc items we might want to keep
                GilesItemType TrueItemType=DetermineItemType(thisitem.ThisInternalName, thisitem.ThisDBItemType, thisitem.ThisFollowerType);

                if (TrueItemType==GilesItemType.StaffOfHerding)
                {
                     if (bOutputItemScores) Log(thisitem.ThisRealName+" ["+thisitem.ThisInternalName+"] ["+TrueItemType.ToString()+"] = (autokeep staff of herding)");
                     return true;
                }
                if (TrueItemType==GilesItemType.CraftingMaterial)
                {
                     if (bOutputItemScores) Log(thisitem.ThisRealName+" ["+thisitem.ThisInternalName+"] ["+TrueItemType.ToString()+"] = (autokeep craft materials)");
                     return true;
                }
                if (TrueItemType==GilesItemType.CraftingPlan)
                {
                     if (bOutputItemScores) Log(thisitem.ThisRealName+" ["+thisitem.ThisInternalName+"] ["+TrueItemType.ToString()+"] = (autokeep plans)");
                     return true;
                }
                if (TrueItemType==GilesItemType.Emerald)
                {
                     if (bOutputItemScores) Log(thisitem.ThisRealName+" ["+thisitem.ThisInternalName+"] ["+TrueItemType.ToString()+"] = (autokeep gems)");
                     return true;
                }
                if (TrueItemType==GilesItemType.Amethyst)
                {
                     if (bOutputItemScores) Log(thisitem.ThisRealName+" ["+thisitem.ThisInternalName+"] ["+TrueItemType.ToString()+"] = (autokeep gems)");
                     return true;
                }
                if (TrueItemType==GilesItemType.Topaz)
                {
                     if (bOutputItemScores) Log(thisitem.ThisRealName+" ["+thisitem.ThisInternalName+"] ["+TrueItemType.ToString()+"] = (autokeep gems)");
                     return true;
                }
                if (TrueItemType==GilesItemType.Ruby)
                {
                     if (bOutputItemScores) Log(thisitem.ThisRealName+" ["+thisitem.ThisInternalName+"] ["+TrueItemType.ToString()+"] = (autokeep gems)");
                     return true;
                }
                if (TrueItemType==GilesItemType.CraftTome)
                {
                     if (bOutputItemScores) Log(thisitem.ThisRealName+" ["+thisitem.ThisInternalName+"] ["+TrueItemType.ToString()+"] = (autokeep tomes)");
                     return true;
                }
                if (TrueItemType==GilesItemType.InfernalKey)
                {
                     if (bOutputItemScores) Log(thisitem.ThisRealName+" ["+thisitem.ThisInternalName+"] ["+TrueItemType.ToString()+"] = (autokeep infernal key)");
                     return true;
                }
                if (TrueItemType==GilesItemType.HealthPotion)
                {
                     if (bOutputItemScores) Log(thisitem.ThisRealName+" ["+thisitem.ThisInternalName+"] ["+TrueItemType.ToString()+"] = (ignoring potions)");
                     return false;
                }

                if (thisitem.ThisQuality>=ItemQuality.Legendary)
                {
                     if (bOutputItemScores) Log(thisitem.ThisRealName+" ["+thisitem.ThisInternalName+"] ["+TrueItemType.ToString()+"] = (autokeep legendaries)");
                     return true;
                }

                // Ok now try to do some decent item scoring based on item types
                double iNeedScore=ScoreNeeded(TrueItemType);
                double iMyScore=ValueThisItem(thisitem, TrueItemType);
                if (bOutputItemScores) Log(thisitem.ThisRealName+" ["+thisitem.ThisInternalName+"] ["+TrueItemType.ToString()+"] = "+iMyScore.ToString());
                if (iMyScore>=iNeedScore) return true;

                // If we reached this point, then we found no reason to keep the item!
                return false;
        }
Exemple #4
0
                //Sets List to current backpack contents
                public void Update()
                {
                    int CurrentItemCount=ZetaDia.Me.Inventory.Backpack.Count();
                                if (CurrentItemCount!=CacheItemList.Count||ZetaDia.Me.Inventory.Backpack.Any(i => !CacheItemList.ContainsKey(i.ACDGuid)))
                                {
                                     CacheItemList=new Dictionary<int, CacheACDItem>();
                                     foreach (var thisitem in ZetaDia.Me.Inventory.Backpack)
                                     {
                                          using (ZetaDia.Memory.AcquireFrame())
                                          {
                                                //CacheACDItem thiscacheditem=new CacheACDItem(thisitem.InternalName, thisitem.Name, thisitem.Level, thisitem.ItemQualityLevel, thisitem.Gold, thisitem.GameBalanceId,
                                                //            thisitem.DynamicId, thisitem.Stats.WeaponDamagePerSecond, thisitem.IsOneHand, thisitem.DyeType, thisitem.ItemType, thisitem.FollowerSpecialType,
                                                //            thisitem.IsUnidentified, thisitem.ItemStackQuantity, thisitem.Stats, thisitem, thisitem.InventoryRow, thisitem.InventoryColumn, thisitem.IsPotion, thisitem.ACDGuid);
                                                CacheACDItem thiscacheditem=new CacheACDItem(thisitem);
                                                CacheItemList.Add(thiscacheditem.ACDGUID,thiscacheditem);
                                          }
                                     }
                                }

                                //We refresh our BPItem Cache whenever we are checking for looted items!
                                if (Bot.Combat.ShouldCheckItemLooted)
                                {
                                     //Get a list of current BP Cached ACDItems
                                     List<ACDItem> BPItemsACDItemList=(from backpackItems in BPItems
                                                                                  select backpackItems.Ref_ACDItem).ToList();
                                     var NewItems=ZetaDia.Me.Inventory.Backpack.Where<ACDItem>(I => !BPItemsACDItemList.Contains(I));
                                     if (NewItems.Count()==0) return;

                                     //Now get items that are not currently in the BPItems List.
                                     using (ZetaDia.Memory.AcquireFrame())
                                     {
                                          foreach (var item in NewItems)
                                          {
                                                BPItems.Add(new CacheBPItem(item.ACDGuid, item));
                                          }
                                     }
                                }
                }
Exemple #5
0
        // **********************************************************************************************
        // *****             The bizarre mystery function to score your lovely items!               *****
        // **********************************************************************************************
        private static double ValueThisItem(CacheACDItem thisitem, GilesItemType thisGilesItemType)
        {
            double iTotalPoints = 0;
            bool bAbandonShip = true;
            double[] iThisItemsMaxStats = new double[TOTALSTATS];
            double[] iThisItemsMaxPoints = new double[TOTALSTATS];
            GilesBaseItemType thisGilesBaseType = DetermineBaseType(thisGilesItemType);

            #region CopyTotalStats

            // One Handed Weapons
            if (thisGilesItemType == GilesItemType.Axe || thisGilesItemType == GilesItemType.CeremonialKnife || thisGilesItemType == GilesItemType.Dagger ||
                 thisGilesItemType == GilesItemType.FistWeapon || thisGilesItemType == GilesItemType.Mace || thisGilesItemType == GilesItemType.MightyWeapon ||
                 thisGilesItemType == GilesItemType.Spear || thisGilesItemType == GilesItemType.Sword || thisGilesItemType == GilesItemType.Wand)
            {
                Array.Copy(iMaxWeaponOneHand, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iWeaponPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                bAbandonShip = false;
            }
            // Two Handed Weapons
            if (thisGilesItemType == GilesItemType.TwoHandAxe || thisGilesItemType == GilesItemType.TwoHandDaibo || thisGilesItemType == GilesItemType.TwoHandMace ||
                thisGilesItemType == GilesItemType.TwoHandMighty || thisGilesItemType == GilesItemType.TwoHandPolearm || thisGilesItemType == GilesItemType.TwoHandStaff ||
                thisGilesItemType == GilesItemType.TwoHandSword)
            {
                Array.Copy(iMaxWeaponTwoHand, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iWeaponPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                bAbandonShip = false;
            }
            // Ranged Weapons
            if (thisGilesItemType == GilesItemType.TwoHandCrossbow || thisGilesItemType == GilesItemType.TwoHandBow || thisGilesItemType == GilesItemType.HandCrossbow)
            {
                Array.Copy(iMaxWeaponRanged, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iWeaponPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                if (thisGilesItemType == GilesItemType.HandCrossbow)
                {
                    iThisItemsMaxStats[TOTALDPS] -= 150;
                }
                bAbandonShip = false;
            }
            // Off-handed stuff
            // Mojo, Source, Quiver
            if (thisGilesItemType == GilesItemType.Mojo || thisGilesItemType == GilesItemType.Source || thisGilesItemType == GilesItemType.Quiver)
            {
                Array.Copy(iMaxOffHand, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iArmorPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                bAbandonShip = false;
            }
            // Shields
            if (thisGilesItemType == GilesItemType.Shield)
            {
                Array.Copy(iMaxShield, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iArmorPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                bAbandonShip = false;
            }
            // Jewelry
            // Ring
            if (thisGilesItemType == GilesItemType.Amulet)
            {
                Array.Copy(iMaxAmulet, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iJewelryPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                bAbandonShip = false;
            }
            // Ring
            if (thisGilesItemType == GilesItemType.Ring)
            {
                Array.Copy(iMaxRing, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iJewelryPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                bAbandonShip = false;
            }
            // Armor
            // Belt
            if (thisGilesItemType == GilesItemType.Belt)
            {
                Array.Copy(iMaxBelt, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iArmorPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                bAbandonShip = false;
            }
            // Boots
            if (thisGilesItemType == GilesItemType.Boots)
            {
                Array.Copy(iMaxBoots, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iArmorPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                bAbandonShip = false;
            }
            // Bracers
            if (thisGilesItemType == GilesItemType.Bracers)
            {
                Array.Copy(iMaxBracer, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iArmorPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                bAbandonShip = false;
            }
            // Chest
            if (thisGilesItemType == GilesItemType.Chest)
            {
                Array.Copy(iMaxChest, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iArmorPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                bAbandonShip = false;
            }
            if (thisGilesItemType == GilesItemType.Cloak)
            {
                Array.Copy(iMaxCloak, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iArmorPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                bAbandonShip = false;
            }
            // Gloves
            if (thisGilesItemType == GilesItemType.Gloves)
            {
                Array.Copy(iMaxGloves, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iArmorPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                bAbandonShip = false;
            }
            // Helm
            if (thisGilesItemType == GilesItemType.Helm)
            {
                Array.Copy(iMaxHelm, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iArmorPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                bAbandonShip = false;
            }
            // Pants
            if (thisGilesItemType == GilesItemType.Pants)
            {
                Array.Copy(iMaxPants, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iArmorPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                bAbandonShip = false;
            }
            if (thisGilesItemType == GilesItemType.MightyBelt)
            {
                Array.Copy(iMaxMightyBelt, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iArmorPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                bAbandonShip = false;
            }
            // Shoulders
            if (thisGilesItemType == GilesItemType.Shoulders)
            {
                Array.Copy(iMaxShoulders, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iArmorPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                bAbandonShip = false;
            }
            if (thisGilesItemType == GilesItemType.SpiritStone)
            {
                Array.Copy(iMaxSpiritStone, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iArmorPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                bAbandonShip = false;
            }
            if (thisGilesItemType == GilesItemType.VoodooMask)
            {
                Array.Copy(iMaxVoodooMask, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iArmorPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                bAbandonShip = false;
            }
            // Wizard Hat
            if (thisGilesItemType == GilesItemType.WizardHat)
            {
                Array.Copy(iMaxWizardHat, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iArmorPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                bAbandonShip = false;
            }
            // Follower Items
            if (thisGilesItemType == GilesItemType.FollowerEnchantress || thisGilesItemType == GilesItemType.FollowerScoundrel || thisGilesItemType == GilesItemType.FollowerTemplar)
            {
                Array.Copy(iMaxFollower, iThisItemsMaxStats, TOTALSTATS);
                Array.Copy(iJewelryPointsAtMax, iThisItemsMaxPoints, TOTALSTATS);
                bAbandonShip = false;
            }
            #endregion

            // Constants for convenient stat names
            double[] iHadStat = new double[TOTALSTATS] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
            double[] iHadPoints = new double[TOTALSTATS] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

            double iSafeLifePercentage = 0;

            bool bSocketsCanReplacePrimaries = false;

            double iHighestScoringPrimary = 0;
            int iWhichPrimaryIsHighest = 0;
            double iAmountHighestScoringPrimary = 0;

            // Double safety check for unidentified items
            if (thisitem.IsUnidentified) bAbandonShip = true;

            // Make sure we got a valid item here, otherwise score it a big fat 0
            if (bAbandonShip)
            {

                return 0;
            }

            double iGlobalMultiplier = 1;

                TownRunManager.sValueItemStatString="";
            TownRunManager.sJunkItemStatString = "";
            // We loop through all of the stats, in a particular order. The order *IS* important, because it pulls up primary stats first, BEFORE other stats
            for (int i = 0; i <= (TOTALSTATS - 1); i++)
            {
                double iTempStatistic = 0;
                // Now we lookup each stat on this item we are scoring, and store it in the variable "iTempStatistic" - which is used for calculations further down

                #region statSwitch
                switch (i)
                {
                    case DEXTERITY: iTempStatistic = thisitem.Dexterity; break;
                    case INTELLIGENCE: iTempStatistic = thisitem.Intelligence; break;
                    case STRENGTH: iTempStatistic = thisitem.Strength; break;
                    case VITALITY: iTempStatistic = thisitem.Vitality; break;
                    case LIFEPERCENT: iTempStatistic = thisitem.LifePercent; break;
                    case LIFEONHIT: iTempStatistic = thisitem.LifeOnHit; break;
                    case LIFESTEAL: iTempStatistic = thisitem.LifeSteal; break;
                    case LIFEREGEN: iTempStatistic = thisitem.HealthPerSecond; break;
                    case MAGICFIND: iTempStatistic = thisitem.MagicFind; break;
                    case GOLDFIND: iTempStatistic = thisitem.GoldFind; break;
                    case MOVEMENTSPEED: iTempStatistic = thisitem.MovementSpeed; break;
                    case PICKUPRADIUS: iTempStatistic = thisitem.PickUpRadius; break;
                    case SOCKETS: iTempStatistic = thisitem.Sockets; break;
                    case CRITCHANCE: iTempStatistic = thisitem.CritPercent; break;
                    case CRITDAMAGE: iTempStatistic = thisitem.CritDamagePercent; break;
                    case ATTACKSPEED: iTempStatistic = thisitem.AttackSpeedPercent; break;
                    case MINDAMAGE: iTempStatistic = thisitem.MinDamage; break;
                    case MAXDAMAGE: iTempStatistic = thisitem.MaxDamage; break;
                    case BLOCKCHANCE: iTempStatistic = thisitem.BlockChance; break;
                    case THORNS: iTempStatistic = thisitem.Thorns; break;
                    case ALLRESIST: iTempStatistic = thisitem.ResistAll; break;
                    case RANDOMRESIST:
                        if (thisitem.ResistArcane > iTempStatistic) iTempStatistic = thisitem.ResistArcane;
                        if (thisitem.ResistCold > iTempStatistic) iTempStatistic = thisitem.ResistCold;
                        if (thisitem.ResistFire > iTempStatistic) iTempStatistic = thisitem.ResistFire;
                        if (thisitem.ResistHoly > iTempStatistic) iTempStatistic = thisitem.ResistHoly;
                        if (thisitem.ResistLightning > iTempStatistic) iTempStatistic = thisitem.ResistLightning;
                        if (thisitem.ResistPhysical > iTempStatistic) iTempStatistic = thisitem.ResistPhysical;
                        if (thisitem.ResistPoison > iTempStatistic) iTempStatistic = thisitem.ResistPoison;
                        break;
                    case TOTALDPS: iTempStatistic = thisitem.WeaponDamagePerSecond; break;
                    case ARMOR: iTempStatistic = thisitem.ArmorBonus; break;
                    case MAXDISCIPLINE: iTempStatistic = thisitem.MaxDiscipline; break;
                    case MAXMANA: iTempStatistic = thisitem.MaxMana; break;
                    case ARCANECRIT: iTempStatistic = thisitem.ArcaneOnCrit; break;
                    case MANAREGEN: iTempStatistic = thisitem.ManaRegen; break;
                    case GLOBEBONUS: iTempStatistic = thisitem.GlobeBonus; break;
                }
                #endregion

                iHadStat[i] = iTempStatistic;
                iHadPoints[i] = 0;
                // Now we check that the current statistic in the "for" loop, actually exists on this item, and is a stat we are measuring (has >0 in the "max stats" array)
                if (iThisItemsMaxStats[i] > 0 && iTempStatistic > 0)
                #region AttributeScoring
                {
                    // Final bonus granted is an end-of-score multiplier. 1 = 100%, so all items start off with 100%, of course!
                    double iFinalBonusGranted = 1;

                    // Temp percent is what PERCENTAGE of the *MAXIMUM POSSIBLE STAT*, this stat is at.
                    // Note that stats OVER the max will get a natural score boost, since this value will be over 1!
                    double iTempPercent = iTempStatistic / iThisItemsMaxStats[i];
                    // Now multiply the "max points" value, by that percentage, as the start/basis of the scoring for this statistic
                    double iTempPoints = iThisItemsMaxPoints[i] * iTempPercent;

                    // Check if this statistic is over the "bonus threshold" array value for this stat - if it is, then it gets a score bonus when over a certain % of max-stat
                    if (iTempPercent > iBonusThreshold[i] && iBonusThreshold[i] > 0f)
                    {
                        iFinalBonusGranted += ((iTempPercent - iBonusThreshold[i]) * 0.9);
                    }

                    // We're going to store the life % stat here for quick-calculations against other stats. Don't edit this bit!
                    if (i == LIFEPERCENT)
                    {
                        if (iThisItemsMaxStats[LIFEPERCENT] > 0)
                        {
                            iSafeLifePercentage = (iTempStatistic / iThisItemsMaxStats[LIFEPERCENT]);
                        }
                        else
                        {
                            iSafeLifePercentage = 0;
                        }
                    }

                    // This *REMOVES* score from follower items for stats that followers don't care about
                    if (thisGilesBaseType == GilesBaseItemType.FollowerItem && (i == CRITDAMAGE || i == LIFEONHIT || i == ALLRESIST))
                        iFinalBonusGranted -= 0.9;

                    // Bonus 15% for being *at* the stat cap (ie - completely maxed out, or very very close to), but not for the socket stat (since sockets are usually 0 or 1!)
                    if (i != SOCKETS)
                    {
                        if ((iTempStatistic / iThisItemsMaxStats[i]) >= 0.99)
                            iFinalBonusGranted += 0.15;
                        // Else bonus 10% for being in final 95%
                        else if ((iTempStatistic / iThisItemsMaxStats[i]) >= 0.95)
                            iFinalBonusGranted += 0.10;
                    }

                    // ***************
                    // Socket handling
                    // ***************
                    // Sockets give special bonuses for certain items, depending how close to the max-socket-count it is for that item
                    // It also enables bonus scoring for stats which usually rely on a high primary stat - since a socket can make up for a lack of a high primary (you can socket a +primary stat!)
                    if (i == SOCKETS)
                    {
                        // Off-handers get less value from sockets
                        if (thisGilesBaseType == GilesBaseItemType.Offhand)
                        {
                            iFinalBonusGranted -= 0.35;
                        }

                        // Chest
                        if (thisGilesItemType == GilesItemType.Chest || thisGilesItemType == GilesItemType.Cloak)
                        {
                            if (iTempStatistic >= 2)
                            {
                                bSocketsCanReplacePrimaries = true;
                                if (iTempStatistic >= 3)
                                    iFinalBonusGranted += 0.25;
                            }
                        }

                        // Pants
                        if (thisGilesItemType == GilesItemType.Pants)
                        {
                            if (iTempStatistic >= 2)
                            {
                                bSocketsCanReplacePrimaries = true;
                                iFinalBonusGranted += 0.25;
                            }
                        }
                        // Helmets can have a bonus for a socket since it gives amazing MF/GF
                        if (iTempStatistic >= 1 && (thisGilesItemType == GilesItemType.Helm || thisGilesItemType == GilesItemType.WizardHat || thisGilesItemType == GilesItemType.VoodooMask ||
                            thisGilesItemType == GilesItemType.SpiritStone))
                        {
                            bSocketsCanReplacePrimaries = true;
                        }
                        // And rings and amulets too
                        if (iTempStatistic >= 1 && (thisGilesItemType == GilesItemType.Ring || thisGilesItemType == GilesItemType.Amulet))
                        {
                            bSocketsCanReplacePrimaries = true;
                        }

                    }

                    // Right, here's quite a long bit of code, but this is basically all about granting all sorts of bonuses based on primary stat values of all different ranges
                    // For all item types *EXCEPT* weapons
                    if (thisGilesBaseType != GilesBaseItemType.WeaponRange && thisGilesBaseType != GilesBaseItemType.WeaponOneHand && thisGilesBaseType != GilesBaseItemType.WeaponTwoHand)
                    {
                        double iSpecialBonus = 0;
                        if (i > LIFEPERCENT)
                        {
                            // Knock off points for being particularly low
                            if ((iTempStatistic / iThisItemsMaxStats[i]) < 0.2 && (iBonusThreshold[i] <= 0f || iBonusThreshold[i] >= 0.2))
                                iFinalBonusGranted -= 0.35;
                            else if ((iTempStatistic / iThisItemsMaxStats[i]) < 0.4 && (iBonusThreshold[i] <= 0f || iBonusThreshold[i] >= 0.4))
                                iFinalBonusGranted -= 0.15;
                            // Remove 80% if below minimum threshold
                            if ((iTempStatistic / iThisItemsMaxStats[i]) < iMinimumThreshold[i] && iMinimumThreshold[i] > 0f)
                                iFinalBonusGranted -= 0.8;

                            // Primary stat/vitality minimums or zero-check reductions on other stats
                            if (iStatMinimumPrimary[i] > 0)
                            {
                                // Remove 40% from all stats if there is no prime stat present or vitality/life present and this is below 90% of max
                                if (((iTempStatistic / iThisItemsMaxStats[i]) < .90) && ((iHadStat[DEXTERITY] / iThisItemsMaxStats[DEXTERITY]) < iStatMinimumPrimary[i]) &&
                                    ((iHadStat[STRENGTH] / iThisItemsMaxStats[STRENGTH]) < (iStatMinimumPrimary[i] + 0.1)) && ((iHadStat[INTELLIGENCE] / iThisItemsMaxStats[INTELLIGENCE]) < iStatMinimumPrimary[i]) &&
                                    ((iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) < iStatMinimumPrimary[i]) && (iSafeLifePercentage < (iStatMinimumPrimary[i] * 2.5)) && !bSocketsCanReplacePrimaries)
                                {
                                    if (thisGilesItemType != GilesItemType.Ring && thisGilesItemType != GilesItemType.Amulet)
                                        iFinalBonusGranted -= 0.4;
                                    else
                                        iFinalBonusGranted -= 0.3;
                                    // And another 25% off for armor and all resist which are more useful with primaries, as long as not jewelry
                                    if ((i == ARMOR || i == ALLRESIST || i == RANDOMRESIST) && thisGilesItemType != GilesItemType.Ring && thisGilesItemType != GilesItemType.Amulet && !bSocketsCanReplacePrimaries)
                                        iFinalBonusGranted -= 0.15;
                                }
                            }
                            else
                            {
                                // Almost no primary stats or health at all
                                if (iHadStat[DEXTERITY] <= 60 && iHadStat[STRENGTH] <= 60 && iHadStat[INTELLIGENCE] <= 60 && iHadStat[VITALITY] <= 60 && iSafeLifePercentage < 0.9 && !bSocketsCanReplacePrimaries)
                                {
                                    // So 35% off for all items except jewelry which is 20% off
                                    if (thisGilesItemType != GilesItemType.Ring && thisGilesItemType != GilesItemType.Amulet)
                                    {
                                        iFinalBonusGranted -= 0.35;
                                        // And another 25% off for armor and all resist which are more useful with primaries
                                        if (i == ARMOR || i == ALLRESIST)
                                            iFinalBonusGranted -= 0.15;
                                    }
                                    else
                                    {
                                        iFinalBonusGranted -= 0.20;
                                    }

                                }
                            }

                            if (thisGilesBaseType == GilesBaseItemType.Armor || thisGilesBaseType == GilesBaseItemType.Jewelry)
                            {
                                // Grant a 50% bonus to stats if a primary is above 200 AND (vitality above 200 or life% within 90% max)
                                if ((iHadStat[DEXTERITY] > 200 || iHadStat[STRENGTH] > 200 || iHadStat[INTELLIGENCE] > 200) && (iHadStat[VITALITY] > 200 || iSafeLifePercentage > .97))
                                {
                                    if (0.5 > iSpecialBonus) iSpecialBonus = 0.5;
                                }
                                // Else grant a 40% bonus to stats if a primary is above 200
                                if (iHadStat[DEXTERITY] > 200 || iHadStat[STRENGTH] > 200 || iHadStat[INTELLIGENCE] > 200)
                                {
                                    if (0.4 > iSpecialBonus) iSpecialBonus = 0.4;
                                }
                                // Grant a 30% bonus if vitality > 200 or life percent within 90% of max
                                if (iHadStat[VITALITY] > 200 || iSafeLifePercentage > .97)
                                {
                                    if (0.3 > iSpecialBonus) iSpecialBonus = 0.3;
                                }
                            }

                            // Checks for various primary & health levels
                            if ((iHadStat[DEXTERITY] / iThisItemsMaxStats[DEXTERITY]) > .85 || (iHadStat[STRENGTH] / iThisItemsMaxStats[STRENGTH]) > .85
                                || (iHadStat[INTELLIGENCE] / iThisItemsMaxStats[INTELLIGENCE]) > .85)
                            {
                                if ((iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > .6 || iSafeLifePercentage > .90)
                                {
                                    if (0.5 > iSpecialBonus) iSpecialBonus = 0.5;
                                }
                                else if ((iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > .35 || iSafeLifePercentage > .85)
                                {
                                    if (0.4 > iSpecialBonus) iSpecialBonus = 0.4;
                                }
                                else
                                {
                                    if (0.2 > iSpecialBonus) iSpecialBonus = 0.2;
                                }
                            }
                            if ((iHadStat[DEXTERITY] / iThisItemsMaxStats[DEXTERITY]) > .75 || (iHadStat[STRENGTH] / iThisItemsMaxStats[STRENGTH]) > .75
                                || (iHadStat[INTELLIGENCE] / iThisItemsMaxStats[INTELLIGENCE]) > .75)
                            {
                                if ((iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > .6 || iSafeLifePercentage > .90)
                                {
                                    if (0.35 > iSpecialBonus) iSpecialBonus = 0.35;
                                }
                                else if ((iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > .35 || iSafeLifePercentage > .85)
                                {
                                    if (0.30 > iSpecialBonus) iSpecialBonus = 0.30;
                                }
                                else
                                {
                                    if (0.15 > iSpecialBonus) iSpecialBonus = 0.15;
                                }
                            }
                            if ((iHadStat[DEXTERITY] / iThisItemsMaxStats[DEXTERITY]) > .65 || (iHadStat[STRENGTH] / iThisItemsMaxStats[STRENGTH]) > .65
                                || (iHadStat[INTELLIGENCE] / iThisItemsMaxStats[INTELLIGENCE]) > .65)
                            {
                                if ((iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > .6 || iSafeLifePercentage > .90)
                                {
                                    if (0.26 > iSpecialBonus) iSpecialBonus = 0.26;
                                }
                                else if ((iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > .35 || iSafeLifePercentage > .85)
                                {
                                    if (0.22 > iSpecialBonus) iSpecialBonus = 0.22;
                                }
                                else
                                {
                                    if (0.11 > iSpecialBonus) iSpecialBonus = 0.11;
                                }
                            }
                            if ((iHadStat[DEXTERITY] / iThisItemsMaxStats[DEXTERITY]) > .55 || (iHadStat[STRENGTH] / iThisItemsMaxStats[STRENGTH]) > .55
                                || (iHadStat[INTELLIGENCE] / iThisItemsMaxStats[INTELLIGENCE]) > .55)
                            {
                                if ((iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > .6 || iSafeLifePercentage > .90)
                                {
                                    if (0.18 > iSpecialBonus) iSpecialBonus = 0.18;
                                }
                                else if ((iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > .35 || iSafeLifePercentage > .85)
                                {
                                    if (0.14 > iSpecialBonus) iSpecialBonus = 0.14;
                                }
                                else
                                {
                                    if (0.08 > iSpecialBonus) iSpecialBonus = 0.08;
                                }
                            }
                            if ((iHadStat[DEXTERITY] / iThisItemsMaxStats[DEXTERITY]) > .5 || (iHadStat[STRENGTH] / iThisItemsMaxStats[STRENGTH]) > .5
                                || (iHadStat[INTELLIGENCE] / iThisItemsMaxStats[INTELLIGENCE]) > .5)
                            {
                                if ((iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > .6 || iSafeLifePercentage > .90)
                                {
                                    if (0.12 > iSpecialBonus) iSpecialBonus = 0.12;
                                }
                                else if ((iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > .35 || iSafeLifePercentage > .85)
                                {
                                    if (0.05 > iSpecialBonus) iSpecialBonus = 0.05;
                                }
                                else
                                {
                                    if (0.03 > iSpecialBonus) iSpecialBonus = 0.03;
                                }
                            }
                            if (thisGilesItemType == GilesItemType.Ring || thisGilesItemType == GilesItemType.Amulet)
                            {
                                if ((iHadStat[DEXTERITY] / iThisItemsMaxStats[DEXTERITY]) > .4 || (iHadStat[STRENGTH] / iThisItemsMaxStats[STRENGTH]) > .4
                                    || (iHadStat[INTELLIGENCE] / iThisItemsMaxStats[INTELLIGENCE]) > .4)
                                {
                                    if ((iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > .6 || iSafeLifePercentage > .90)
                                    {
                                        if (0.10 > iSpecialBonus) iSpecialBonus = 0.10;
                                    }
                                    else if ((iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > .35 || iSafeLifePercentage > .85)
                                    {
                                        if (0.08 > iSpecialBonus) iSpecialBonus = 0.08;
                                    }
                                    else
                                    {
                                        if (0.05 > iSpecialBonus) iSpecialBonus = 0.05;
                                    }
                                }
                            }
                            if ((iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > .8 || iSafeLifePercentage > .98)
                            {
                                if (0.20 > iSpecialBonus) iSpecialBonus = 0.20;
                            }
                            if ((iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > .7 || iSafeLifePercentage > .95)
                            {
                                if (0.16 > iSpecialBonus) iSpecialBonus = 0.16;
                            }
                            if ((iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > .6 || iSafeLifePercentage > .92)
                            {
                                if (0.12 > iSpecialBonus) iSpecialBonus = 0.12;
                            }
                            if ((iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > .55 || iSafeLifePercentage > .89)
                            {
                                if (0.07 > iSpecialBonus) iSpecialBonus = 0.07;
                            }
                            else if ((iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > .5 || iSafeLifePercentage > .87)
                            {
                                if (0.05 > iSpecialBonus) iSpecialBonus = 0.05;
                            }
                            else if ((iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > .45 || iSafeLifePercentage > .86)
                            {
                                if (0.02 > iSpecialBonus) iSpecialBonus = 0.02;
                            }
                        } // This stat is one after life percent stat
                        // Shields get less of a special bonus from high prime stats
                        if (thisGilesItemType == GilesItemType.Shield)
                            iSpecialBonus *= 0.7;

                        iFinalBonusGranted += iSpecialBonus;
                    } // NOT A WEAPON!?

                    // Knock off points for being particularly low
                    if ((iTempStatistic / iThisItemsMaxStats[i]) < iMinimumThreshold[i] && iMinimumThreshold[i] > 0f)
                        iFinalBonusGranted -= 0.35;
                    // Grant a 20% bonus to vitality or Life%, for being paired with any prime stat above minimum threshold +.1
                    if (((i == VITALITY && (iTempStatistic / iThisItemsMaxStats[VITALITY]) > iMinimumThreshold[VITALITY]) ||
                          i == LIFEPERCENT && (iTempStatistic / iThisItemsMaxStats[LIFEPERCENT]) > iMinimumThreshold[LIFEPERCENT]) &&
                        ((iHadStat[DEXTERITY] / iThisItemsMaxStats[DEXTERITY]) > (iMinimumThreshold[DEXTERITY] + 0.1)
                        || (iHadStat[STRENGTH] / iThisItemsMaxStats[STRENGTH]) > (iMinimumThreshold[STRENGTH] + 0.1) ||
                         (iHadStat[INTELLIGENCE] / iThisItemsMaxStats[INTELLIGENCE]) > (iMinimumThreshold[INTELLIGENCE] + 0.1)))
                        iFinalBonusGranted += 0.2;

                    // Blue item point reduction for non-weapons
                    if (thisitem.ThisQuality < ItemQuality.Rare4 && (thisGilesBaseType == GilesBaseItemType.Armor || thisGilesBaseType == GilesBaseItemType.Offhand ||
                        thisGilesBaseType == GilesBaseItemType.Jewelry || thisGilesBaseType == GilesBaseItemType.FollowerItem) && ((iTempStatistic / iThisItemsMaxStats[i]) < 0.88))
                        iFinalBonusGranted -= 0.9;

                    // Special all-resist bonuses
                    if (i == ALLRESIST)
                    {
                        // Shields with < 60% max all resist, lost some all resist score
                        if (thisGilesItemType == GilesItemType.Shield && (iTempStatistic / iThisItemsMaxStats[i]) <= 0.6)
                            iFinalBonusGranted -= 0.30;

                        double iSpecialBonus = 0;
                        // All resist gets a special bonus if paired with good strength and some vitality
                        if ((iHadStat[STRENGTH] / iThisItemsMaxStats[STRENGTH]) > 0.7 && (iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > 0.3)
                            if (0.45 > iSpecialBonus) iSpecialBonus = 0.45;
                        // All resist gets a smaller special bonus if paired with good dexterity and some vitality
                        if ((iHadStat[DEXTERITY] / iThisItemsMaxStats[DEXTERITY]) > 0.7 && (iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > 0.3)
                            if (0.35 > iSpecialBonus) iSpecialBonus = 0.35;
                        // All resist gets a slight special bonus if paired with good intelligence and some vitality
                        if ((iHadStat[INTELLIGENCE] / iThisItemsMaxStats[INTELLIGENCE]) > 0.7 && (iHadStat[INTELLIGENCE] / iThisItemsMaxStats[INTELLIGENCE]) > 0.3)
                            if (0.25 > iSpecialBonus) iSpecialBonus = 0.25;

                        // Smaller bonuses for smaller stats
                        // All resist gets a special bonus if paired with good strength and some vitality
                        if ((iHadStat[STRENGTH] / iThisItemsMaxStats[STRENGTH]) > 0.55 && (iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > 0.3)
                            if (0.45 > iSpecialBonus) iSpecialBonus = 0.20;
                        // All resist gets a smaller special bonus if paired with good dexterity and some vitality
                        if ((iHadStat[DEXTERITY] / iThisItemsMaxStats[DEXTERITY]) > 0.55 && (iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > 0.3)
                            if (0.35 > iSpecialBonus) iSpecialBonus = 0.15;
                        // All resist gets a slight special bonus if paired with good intelligence and some vitality
                        if ((iHadStat[INTELLIGENCE] / iThisItemsMaxStats[INTELLIGENCE]) > 0.55 && (iHadStat[INTELLIGENCE] / iThisItemsMaxStats[INTELLIGENCE]) > 0.3)
                            if (0.25 > iSpecialBonus) iSpecialBonus = 0.10;

                        // This stat is one after life percent stat
                        iFinalBonusGranted += iSpecialBonus;

                        // Global bonus to everything
                        if ((iThisItemsMaxStats[i] - iTempStatistic) < 10.2f)
                            iGlobalMultiplier += 0.05;
                    } // All resist special bonuses

                    if (thisGilesItemType != GilesItemType.Ring && thisGilesItemType != GilesItemType.Amulet)
                    {
                        // Shields get 10% less on everything
                        if (thisGilesItemType == GilesItemType.Shield)
                            iFinalBonusGranted -= 0.10;

                        // Prime stat gets a 20% bonus if 50 from max possible
                        if ((i == DEXTERITY || i == STRENGTH || i == INTELLIGENCE || i == VITALITY) && (iThisItemsMaxStats[i] - iTempStatistic) < 50.5f)
                            iFinalBonusGranted += 0.25;

                        // Reduce a prime stat by 75% if less than 100 *OR* less than 50% max
                        if ((i == DEXTERITY || i == STRENGTH || i == INTELLIGENCE) && (iTempStatistic < 100 || ((iTempStatistic / iThisItemsMaxStats[i]) < 0.5)))
                            iFinalBonusGranted -= 0.75;
                        // Reduce a vitality/life% stat by 60% if less than 80 vitality/less than 60% max possible life%
                        if ((i == VITALITY && iTempStatistic < 80) || (i == LIFEPERCENT && ((iTempStatistic / iThisItemsMaxStats[LIFEPERCENT]) < 0.6)))
                            iFinalBonusGranted -= 0.6;
                        // Grant 10% to any 4 main stat above 200
                        if ((i == DEXTERITY || i == STRENGTH || i == INTELLIGENCE || i == VITALITY) && iTempStatistic > 200)
                            iFinalBonusGranted += 0.1;

                        // *************************************************
                        // Special stat handling stuff for non-jewelry types
                        // *************************************************
                        // Within 2 block chance
                        if (i == BLOCKCHANCE && (iThisItemsMaxStats[i] - iTempStatistic) < 2.3f)
                            iFinalBonusGranted += 1;

                        // Within final 5 gold find
                        if (i == GOLDFIND && (iThisItemsMaxStats[i] - iTempStatistic) < 5.3f)
                        {
                            iFinalBonusGranted += 0.04;
                            // Even bigger bonus if got prime stat & vit
                            if (((iHadStat[DEXTERITY] / iThisItemsMaxStats[DEXTERITY]) > iMinimumThreshold[DEXTERITY] || (iHadStat[STRENGTH] / iThisItemsMaxStats[STRENGTH]) > iMinimumThreshold[STRENGTH] ||
                                (iHadStat[INTELLIGENCE] / iThisItemsMaxStats[INTELLIGENCE]) > iMinimumThreshold[INTELLIGENCE]) && (iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > iMinimumThreshold[VITALITY])
                                iFinalBonusGranted += 0.02;
                        }
                        // Within final 3 gold find
                        if (i == GOLDFIND && (iThisItemsMaxStats[i] - iTempStatistic) < 3.3f)
                        {
                            iFinalBonusGranted += 0.04;
                        }
                        // Within final 2 gold find
                        if (i == GOLDFIND && (iThisItemsMaxStats[i] - iTempStatistic) < 2.3f)
                        {
                            iFinalBonusGranted += 0.05;
                        }
                        // Within final 3 magic find
                        if (i == MAGICFIND && (iThisItemsMaxStats[i] - iTempStatistic) < 3.3f)
                            iFinalBonusGranted += 0.08;
                        // Within final 2 magic find
                        if (i == MAGICFIND && (iThisItemsMaxStats[i] - iTempStatistic) < 2.3f)
                        {
                            iFinalBonusGranted += 0.04;
                            // Even bigger bonus if got prime stat & vit
                            if (((iHadStat[DEXTERITY] / iThisItemsMaxStats[DEXTERITY]) > iMinimumThreshold[DEXTERITY] || (iHadStat[STRENGTH] / iThisItemsMaxStats[STRENGTH]) > iMinimumThreshold[STRENGTH] ||
                                (iHadStat[INTELLIGENCE] / iThisItemsMaxStats[INTELLIGENCE]) > iMinimumThreshold[INTELLIGENCE]) && (iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > iMinimumThreshold[VITALITY])
                                iFinalBonusGranted += 0.03;
                        }
                        // Within final magic find
                        if (i == MAGICFIND && (iThisItemsMaxStats[i] - iTempStatistic) < 1.3f)
                        {
                            iFinalBonusGranted += 0.05;
                        }
                        // Within final 10 all resist
                        if (i == ALLRESIST && (iThisItemsMaxStats[i] - iTempStatistic) < 10.2f)
                        {
                            iFinalBonusGranted += 0.05;
                            // Even bigger bonus if got prime stat & vit
                            if (((iHadStat[DEXTERITY] / iThisItemsMaxStats[DEXTERITY]) > iMinimumThreshold[DEXTERITY] || (iHadStat[STRENGTH] / iThisItemsMaxStats[STRENGTH]) > iMinimumThreshold[STRENGTH] ||
                                (iHadStat[INTELLIGENCE] / iThisItemsMaxStats[INTELLIGENCE]) > iMinimumThreshold[INTELLIGENCE]) && (iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY]) > iMinimumThreshold[VITALITY])
                                iFinalBonusGranted += 0.20;
                        }
                        // Within final 50 armor
                        if (i == ARMOR && (iThisItemsMaxStats[i] - iTempStatistic) < 50.2f)
                        {
                            iFinalBonusGranted += 0.10;
                            if ((iHadStat[STRENGTH] / iThisItemsMaxStats[STRENGTH]) > iMinimumThreshold[STRENGTH])
                                iFinalBonusGranted += 0.10;
                        }
                        // Within final 15 armor
                        if (i == ARMOR && (iThisItemsMaxStats[i] - iTempStatistic) < 15.2f)
                            iFinalBonusGranted += 0.15;

                        // Within final 5 critical hit damage
                        if (i == CRITDAMAGE && (iThisItemsMaxStats[i] - iTempStatistic) < 5.2f)
                            iFinalBonusGranted += 0.25;
                        // More than 2.5 crit chance out
                        if (i == CRITCHANCE && (iThisItemsMaxStats[i] - iTempStatistic) > 2.45f)
                            iFinalBonusGranted -= 0.35;
                        // More than 20 crit damage out
                        if (i == CRITDAMAGE && (iThisItemsMaxStats[i] - iTempStatistic) > 19.95f)
                            iFinalBonusGranted -= 0.35;
                        // More than 2 attack speed out
                        if (i == ATTACKSPEED && (iThisItemsMaxStats[i] - iTempStatistic) > 1.95f)
                            iFinalBonusGranted -= 0.35;
                        // More than 2 move speed
                        if (i == MOVEMENTSPEED && (iThisItemsMaxStats[i] - iTempStatistic) > 1.95f)
                            iFinalBonusGranted -= 0.35;
                        // More than 5 gold find out
                        if (i == GOLDFIND && (iThisItemsMaxStats[i] - iTempStatistic) > 5.2f)
                            iFinalBonusGranted -= 0.40;
                        // More than 8 gold find out
                        if (i == GOLDFIND && (iThisItemsMaxStats[i] - iTempStatistic) > 8.2f)
                            iFinalBonusGranted -= 0.1;
                        // More than 5 magic find out
                        if (i == MAGICFIND && (iThisItemsMaxStats[i] - iTempStatistic) > 5.2f)
                            iFinalBonusGranted -= 0.40;
                        // More than 7 magic find out
                        if (i == MAGICFIND && (iThisItemsMaxStats[i] - iTempStatistic) > 7.2f)
                            iFinalBonusGranted -= 0.1;
                        // More than 20 all resist out
                        if (i == ALLRESIST && (iThisItemsMaxStats[i] - iTempStatistic) > 20.2f)
                            iFinalBonusGranted -= 0.50;
                        // More than 30 all resist out
                        if (i == ALLRESIST && (iThisItemsMaxStats[i] - iTempStatistic) > 30.2f)
                            iFinalBonusGranted -= 0.20;
                    }
                    // And now for jewelry checks...
                    else
                    {
                        // Global bonus to everything if jewelry has an all resist above 50%
                        if (i == ALLRESIST && (iTempStatistic / iThisItemsMaxStats[i]) > 0.5)
                            iGlobalMultiplier += 0.08;
                        // Within final 10 all resist
                        if (i == ALLRESIST && (iThisItemsMaxStats[i] - iTempStatistic) < 10.2f)
                            iFinalBonusGranted += 0.10;

                        // Within final 5 critical hit damage
                        if (i == CRITDAMAGE && (iThisItemsMaxStats[i] - iTempStatistic) < 5.2f)
                            iFinalBonusGranted += 0.25;

                        // Within 3 block chance
                        if (i == BLOCKCHANCE && (iThisItemsMaxStats[i] - iTempStatistic) < 3.3f)
                            iFinalBonusGranted += 0.15;

                        // Reduce a prime stat by 60% if less than 60
                        if ((i == DEXTERITY || i == STRENGTH || i == INTELLIGENCE) && (iTempStatistic < 60 || ((iTempStatistic / iThisItemsMaxStats[i]) < 0.3)))
                            iFinalBonusGranted -= 0.6;
                        // Reduce a vitality/life% stat by 50% if less than 50 vitality/less than 40% max possible life%
                        if ((i == VITALITY && iTempStatistic < 50) || (i == LIFEPERCENT && ((iTempStatistic / iThisItemsMaxStats[LIFEPERCENT]) < 0.4)))
                            iFinalBonusGranted -= 0.5;
                        // Grant 20% to any 4 main stat above 150
                        if ((i == DEXTERITY || i == STRENGTH || i == INTELLIGENCE || i == VITALITY) && iTempStatistic > 150)
                            iFinalBonusGranted += 0.2;

                        // ***************************************
                        // Special stat handling stuff for jewelry
                        // ***************************************
                        if (thisGilesItemType == GilesItemType.Ring)
                        {
                            // Prime stat gets a 25% bonus if 30 from max possible
                            if ((i == DEXTERITY || i == STRENGTH || i == INTELLIGENCE || i == VITALITY) && (iThisItemsMaxStats[i] - iTempStatistic) < 30.5f)
                                iFinalBonusGranted += 0.25;

                            // Within final 5 magic find
                            if (i == MAGICFIND && (iThisItemsMaxStats[i] - iTempStatistic) < 5.2f)
                                iFinalBonusGranted += 0.4;
                            // Within final 5 gold find
                            if (i == GOLDFIND && (iThisItemsMaxStats[i] - iTempStatistic) < 5.2f)
                                iFinalBonusGranted += 0.35;
                            // Within final 45 life on hit
                            if (i == LIFEONHIT && (iThisItemsMaxStats[i] - iTempStatistic) < 45.2f)
                                iFinalBonusGranted += 1.2;
                            // Within final 50 armor
                            if (i == ARMOR && (iThisItemsMaxStats[i] - iTempStatistic) < 50.2f)
                            {
                                iFinalBonusGranted += 0.30;
                                if ((iHadStat[STRENGTH] / iThisItemsMaxStats[STRENGTH]) > iMinimumThreshold[STRENGTH])
                                    iFinalBonusGranted += 0.30;
                            }
                            // Within final 15 armor
                            if (i == ARMOR && (iThisItemsMaxStats[i] - iTempStatistic) < 15.2f)
                                iFinalBonusGranted += 0.20;

                            // More than 2.5 crit chance out
                            if (i == CRITCHANCE && (iThisItemsMaxStats[i] - iTempStatistic) > 5.55f)
                                iFinalBonusGranted -= 0.20;
                            // More than 20 crit damage out
                            if (i == CRITDAMAGE && (iThisItemsMaxStats[i] - iTempStatistic) > 19.95f)
                                iFinalBonusGranted -= 0.20;
                            // More than 2 attack speed out
                            if (i == ATTACKSPEED && (iThisItemsMaxStats[i] - iTempStatistic) > 1.95f)
                                iFinalBonusGranted -= 0.20;
                            // More than 15 gold find out
                            if (i == GOLDFIND && (iThisItemsMaxStats[i] - iTempStatistic) > 15.2f)
                                iFinalBonusGranted -= 0.1;
                            // More than 15 magic find out
                            if (i == MAGICFIND && (iThisItemsMaxStats[i] - iTempStatistic) > 15.2f)
                                iFinalBonusGranted -= 0.1;
                            // More than 30 all resist out
                            if (i == ALLRESIST && (iThisItemsMaxStats[i] - iTempStatistic) > 20.2f)
                                iFinalBonusGranted -= 0.1;
                            // More than 40 all resist out
                            if (i == ALLRESIST && (iThisItemsMaxStats[i] - iTempStatistic) > 30.2f)
                                iFinalBonusGranted -= 0.1;
                        }
                        else
                        {
                            // Prime stat gets a 25% bonus if 60 from max possible
                            if ((i == DEXTERITY || i == STRENGTH || i == INTELLIGENCE || i == VITALITY) && (iThisItemsMaxStats[i] - iTempStatistic) < 60.5f)
                                iFinalBonusGranted += 0.25;

                            // Within final 10 magic find
                            if (i == MAGICFIND && (iThisItemsMaxStats[i] - iTempStatistic) < 10.2f)
                                iFinalBonusGranted += 0.4;
                            // Within final 10 gold find
                            if (i == GOLDFIND && (iThisItemsMaxStats[i] - iTempStatistic) < 10.2f)
                                iFinalBonusGranted += 0.35;
                            // Within final 40 life on hit
                            if (i == LIFEONHIT && (iThisItemsMaxStats[i] - iTempStatistic) < 40.2f)
                                iFinalBonusGranted += 1.2;
                            // Within final 50 armor
                            if (i == ARMOR && (iThisItemsMaxStats[i] - iTempStatistic) < 50.2f)
                            {
                                iFinalBonusGranted += 0.30;
                                if ((iHadStat[STRENGTH] / iThisItemsMaxStats[STRENGTH]) > iMinimumThreshold[STRENGTH])
                                    iFinalBonusGranted += 0.30;
                            }
                            // Within final 15 armor
                            if (i == ARMOR && (iThisItemsMaxStats[i] - iTempStatistic) < 15.2f)
                                iFinalBonusGranted += 0.20;

                            // More than 2.5 crit chance out
                            if (i == CRITCHANCE && (iThisItemsMaxStats[i] - iTempStatistic) > 5.55f)
                                iFinalBonusGranted -= 0.20;
                            // More than 20 crit damage out
                            if (i == CRITDAMAGE && (iThisItemsMaxStats[i] - iTempStatistic) > 19.95f)
                                iFinalBonusGranted -= 0.20;
                            // More than 2 attack speed out
                            if (i == ATTACKSPEED && (iThisItemsMaxStats[i] - iTempStatistic) > 1.95f)
                                iFinalBonusGranted -= 0.20;
                            // More than 15 gold find out
                            if (i == GOLDFIND && (iThisItemsMaxStats[i] - iTempStatistic) > 15.2f)
                                iFinalBonusGranted -= 0.1;
                            // More than 15 magic find out
                            if (i == MAGICFIND && (iThisItemsMaxStats[i] - iTempStatistic) > 15.2f)
                                iFinalBonusGranted -= 0.1;
                            // More than 30 all resist out
                            if (i == ALLRESIST && (iThisItemsMaxStats[i] - iTempStatistic) > 20.2f)
                                iFinalBonusGranted -= 0.1;
                            // More than 40 all resist out
                            if (i == ALLRESIST && (iThisItemsMaxStats[i] - iTempStatistic) > 30.2f)
                                iFinalBonusGranted -= 0.1;
                        }
                    }

                    // *****************************
                    // All the "set to 0" checks now
                    // *****************************

                    // Disable specific primary stat scoring for certain class-specific item types
                    if ((thisGilesItemType == GilesItemType.VoodooMask || thisGilesItemType == GilesItemType.WizardHat || thisGilesItemType == GilesItemType.Wand ||
                        thisGilesItemType == GilesItemType.CeremonialKnife || thisGilesItemType == GilesItemType.Mojo || thisGilesItemType == GilesItemType.Source)
                        && (i == STRENGTH || i == DEXTERITY))
                        iFinalBonusGranted = 0;
                    if ((thisGilesItemType == GilesItemType.Quiver || thisGilesItemType == GilesItemType.HandCrossbow || thisGilesItemType == GilesItemType.Cloak ||
                        thisGilesItemType == GilesItemType.SpiritStone || thisGilesItemType == GilesItemType.TwoHandDaibo || thisGilesItemType == GilesItemType.FistWeapon)
                        && (i == STRENGTH || i == INTELLIGENCE))
                        iFinalBonusGranted = 0;
                    if ((thisGilesItemType == GilesItemType.MightyBelt || thisGilesItemType == GilesItemType.MightyWeapon || thisGilesItemType == GilesItemType.TwoHandMighty)
                        && (i == DEXTERITY || i == INTELLIGENCE))
                        iFinalBonusGranted = 0;
                    // Remove unwanted follower stats for specific follower types
                    if (thisGilesItemType == GilesItemType.FollowerEnchantress && (i == STRENGTH || i == DEXTERITY))
                        iFinalBonusGranted = 0;
                    if (thisGilesItemType == GilesItemType.FollowerEnchantress && (i == INTELLIGENCE || i == VITALITY))
                        iFinalBonusGranted -= 0.4;
                    if (thisGilesItemType == GilesItemType.FollowerScoundrel && (i == STRENGTH || i == INTELLIGENCE))
                        iFinalBonusGranted = 0;
                    if (thisGilesItemType == GilesItemType.FollowerScoundrel && (i == DEXTERITY || i == VITALITY))
                        iFinalBonusGranted -= 0.4;
                    if (thisGilesItemType == GilesItemType.FollowerTemplar && (i == DEXTERITY || i == INTELLIGENCE))
                        iFinalBonusGranted = 0;
                    if (thisGilesItemType == GilesItemType.FollowerTemplar && (i == STRENGTH || i == VITALITY))
                        iFinalBonusGranted -= 0.4;
                    // Attack speed is always on a quiver so forget it
                    if ((thisGilesItemType == GilesItemType.Quiver) && (i == ATTACKSPEED))
                        iFinalBonusGranted = 0;
                    // Single resists worth nothing without all-resist
                    if (i == RANDOMRESIST && (iHadStat[ALLRESIST] / iThisItemsMaxStats[ALLRESIST]) < iMinimumThreshold[ALLRESIST])
                        iFinalBonusGranted = 0;

                    if (iFinalBonusGranted < 0)
                        iFinalBonusGranted = 0;

                    // ***************************
                    // Grant the final bonus total
                    // ***************************
                    iTempPoints *= iFinalBonusGranted;

                    // If it's a primary stat, log the highest scoring primary... else add these points to the running total
                    if (i == DEXTERITY || i == STRENGTH || i == INTELLIGENCE)
                    {
                        if (iTempPoints > iHighestScoringPrimary)
                        {
                            iHighestScoringPrimary = iTempPoints;
                            iWhichPrimaryIsHighest = i;
                            iAmountHighestScoringPrimary = iTempStatistic;
                        }
                    }
                    else
                    {

                        iTotalPoints += iTempPoints;
                    }

                    iHadPoints[i] = iTempPoints;

                    // For item logs
                    if (i != DEXTERITY && i != STRENGTH && i != INTELLIGENCE)
                    {
                                if (String.IsNullOrEmpty(TownRunManager.sValueItemStatString))
                                     TownRunManager.sValueItemStatString+=". ";
                        TownRunManager.sValueItemStatString += StatNames[i] + "=" + Math.Round(iTempStatistic).ToString();
                                if (!String.IsNullOrEmpty(TownRunManager.sJunkItemStatString))
                                     TownRunManager.sJunkItemStatString+=". ";
                                TownRunManager.sJunkItemStatString+=StatNames[i]+"="+Math.Round(iTempStatistic).ToString();
                    }
                }
                #endregion
            } // End of main 0-TOTALSTATS stat loop

            int iTotalRequirements;
            // Now add on one of the three primary stat scores, whichever was higher
            if (iHighestScoringPrimary > 0)
            {
                // Give a 30% of primary-stat-score-possible bonus to the primary scoring if paired with a good amount of life % or vitality
                if ((iHadStat[VITALITY] / iThisItemsMaxStats[VITALITY] > (iMinimumThreshold[VITALITY] + 0.1)) || iSafeLifePercentage > 0.85)
                    iHighestScoringPrimary += iThisItemsMaxPoints[iWhichPrimaryIsHighest] * 0.3;
                // Reduce a primary a little if there is no vitality or life
                if ((iHadStat[VITALITY] < 40) || iSafeLifePercentage < 0.7)
                    iHighestScoringPrimary *= 0.8;

                iTotalPoints += iHighestScoringPrimary;
                     TownRunManager.sValueItemStatString=StatNames[iWhichPrimaryIsHighest]+"="+Math.Round(iAmountHighestScoringPrimary).ToString()+". "+TownRunManager.sValueItemStatString;
                     TownRunManager.sJunkItemStatString=StatNames[iWhichPrimaryIsHighest]+"="+Math.Round(iAmountHighestScoringPrimary).ToString()+". "+TownRunManager.sJunkItemStatString;
            }

            // Global multiplier
            iTotalPoints *= iGlobalMultiplier;

            // 2 handed weapons and ranged weapons lose a large score for low DPS
            if (thisGilesBaseType == GilesBaseItemType.WeaponRange || thisGilesBaseType == GilesBaseItemType.WeaponTwoHand)
            {
                if ((iHadStat[TOTALDPS] / iThisItemsMaxStats[TOTALDPS]) <= 0.7)
                    iTotalPoints *= 0.75;
            }
            else if (thisGilesBaseType == GilesBaseItemType.WeaponOneHand)
            {
                if ((iHadStat[TOTALDPS] / iThisItemsMaxStats[TOTALDPS]) < 0.6)
                    iTotalPoints *= 0.75;
            }

            // Weapons should get a nice 15% bonus score for having very high primaries
            if (thisGilesBaseType == GilesBaseItemType.WeaponRange || thisGilesBaseType == GilesBaseItemType.WeaponOneHand || thisGilesBaseType == GilesBaseItemType.WeaponTwoHand)
            {
                if (iHighestScoringPrimary > 0 && (iHighestScoringPrimary >= iThisItemsMaxPoints[iWhichPrimaryIsHighest] * 0.9))
                {
                    iTotalPoints *= 1.15;
                }
                // And an extra 15% for a very high vitality
                if (iHadStat[VITALITY] > 0 && (iHadStat[VITALITY] >= iThisItemsMaxPoints[VITALITY] * 0.9))
                {
                    iTotalPoints *= 1.15;
                }
                // And an extra 15% for a very high life-on-hit
                if (iHadStat[LIFEONHIT] > 0 && (iHadStat[LIFEONHIT] >= iThisItemsMaxPoints[LIFEONHIT] * 0.9))
                {
                    iTotalPoints *= 1.15;
                }
            }

            // Shields
            if (thisGilesItemType == GilesItemType.Shield)
            {
                // Strength/Dex based shield calculations
                if (iWhichPrimaryIsHighest == STRENGTH || iWhichPrimaryIsHighest == DEXTERITY)
                {
                    if (iHadStat[BLOCKCHANCE] < 20)
                    {
                        iTotalPoints *= 0.7;
                    }
                    else if (iHadStat[BLOCKCHANCE] < 25)
                    {
                        iTotalPoints *= 0.9;
                    }
                }
                // Intelligence/no primary based shields
                else
                {
                    if (iHadStat[BLOCKCHANCE] < 28)
                        iTotalPoints -= iHadPoints[BLOCKCHANCE];
                }
            }

            // Quivers
            if (thisGilesItemType == GilesItemType.Quiver)
            {
                iTotalRequirements = 0;
                if (iHadStat[DEXTERITY] >= 100)
                    iTotalRequirements++;
                else
                    iTotalRequirements -= 3;
                if (iHadStat[DEXTERITY] >= 160)
                    iTotalRequirements++;
                if (iHadStat[DEXTERITY] >= 250)
                    iTotalRequirements++;
                if (iHadStat[ATTACKSPEED] < 14)
                    iTotalRequirements -= 2;
                if (iHadStat[VITALITY] >= 70 || iSafeLifePercentage >= 0.85)
                    iTotalRequirements++;
                else
                    iTotalRequirements--;
                if (iHadStat[VITALITY] >= 260)
                    iTotalRequirements++;
                if (iHadStat[MAXDISCIPLINE] >= 8)
                    iTotalRequirements++;
                if (iHadStat[MAXDISCIPLINE] >= 10)
                    iTotalRequirements++;
                if (iHadStat[SOCKETS] >= 1)
                    iTotalRequirements++;
                if (iHadStat[CRITCHANCE] >= 6)
                    iTotalRequirements++;
                if (iHadStat[CRITCHANCE] >= 8)
                    iTotalRequirements++;
                if (iHadStat[LIFEPERCENT] >= 8)
                    iTotalRequirements++;
                if (iHadStat[MAGICFIND] >= 18)
                    iTotalRequirements++;
                if (iTotalRequirements < 4)
                    iTotalPoints *= 0.4;
                else if (iTotalRequirements < 5)
                    iTotalPoints *= 0.5;
                if (iTotalRequirements >= 7)
                    iTotalPoints *= 1.2;
            }
            // Mojos and Sources
            if (thisGilesItemType == GilesItemType.Source || thisGilesItemType == GilesItemType.Mojo)
            {
                iTotalRequirements = 0;
                if (iHadStat[INTELLIGENCE] >= 100)
                    iTotalRequirements++;
                else if (iHadStat[INTELLIGENCE] < 80)
                    iTotalRequirements -= 3;
                else if (iHadStat[INTELLIGENCE] < 100)
                    iTotalRequirements -= 1;
                if (iHadStat[INTELLIGENCE] >= 160)
                    iTotalRequirements++;
                if (iHadStat[MAXDAMAGE] >= 250)
                    iTotalRequirements++;
                else
                    iTotalRequirements -= 2;
                if (iHadStat[MAXDAMAGE] >= 340)
                    iTotalRequirements++;
                if (iHadStat[MINDAMAGE] >= 50)
                    iTotalRequirements++;
                else
                    iTotalRequirements--;
                if (iHadStat[MINDAMAGE] >= 85)
                    iTotalRequirements++;
                if (iHadStat[VITALITY] >= 70)
                    iTotalRequirements++;
                if (iHadStat[SOCKETS] >= 1)
                    iTotalRequirements++;
                if (iHadStat[CRITCHANCE] >= 6)
                    iTotalRequirements++;
                if (iHadStat[CRITCHANCE] >= 8)
                    iTotalRequirements++;
                if (iHadStat[LIFEPERCENT] >= 8)
                    iTotalRequirements++;
                if (iHadStat[MAGICFIND] >= 15)
                    iTotalRequirements++;
                if (iHadStat[MAXMANA] >= 60)
                    iTotalRequirements++;
                if (iHadStat[ARCANECRIT] >= 8)
                    iTotalRequirements++;
                if (iHadStat[ARCANECRIT] >= 10)
                    iTotalRequirements++;
                if (iTotalRequirements < 4)
                    iTotalPoints *= 0.4;
                else if (iTotalRequirements < 5)
                    iTotalPoints *= 0.5;
                if (iTotalRequirements >= 8)
                    iTotalPoints *= 1.2;
            }

            // Chests/cloaks/pants without a socket lose 17% of total score
            if ((thisGilesItemType == GilesItemType.Chest || thisGilesItemType == GilesItemType.Cloak || thisGilesItemType == GilesItemType.Pants) && iHadStat[SOCKETS] == 0)
                iTotalPoints *= 0.83;

            // Boots with no movement speed get reduced score
            if ((thisGilesItemType == GilesItemType.Boots) && iHadStat[MOVEMENTSPEED] <= 6)
                iTotalPoints *= 0.75;

            // Helmets
            if (thisGilesItemType == GilesItemType.Helm || thisGilesItemType == GilesItemType.WizardHat || thisGilesItemType == GilesItemType.VoodooMask || thisGilesItemType == GilesItemType.SpiritStone)
            {
                // Helmets without a socket lose 20% of total score, and most of any MF/GF bonus
                if (iHadStat[SOCKETS] == 0)
                {
                    iTotalPoints *= 0.8;
                    if (iHadStat[MAGICFIND] > 0 || iHadStat[GOLDFIND] > 0)
                    {
                        if (iHadStat[MAGICFIND] > 0 && iHadStat[GOLDFIND] > 0)
                            iTotalPoints -= ((iHadPoints[MAGICFIND] * 0.25) + (iHadPoints[GOLDFIND] * 0.25));
                        else
                            iTotalPoints -= ((iHadPoints[MAGICFIND] * 0.65) + (iHadPoints[GOLDFIND] * 0.65));
                    }
                }
            }

            // Gold-find and pickup radius combined
            if ((iHadStat[GOLDFIND] / iThisItemsMaxStats[GOLDFIND] > 0.55) && (iHadStat[PICKUPRADIUS] / iThisItemsMaxStats[PICKUPRADIUS] > 0.5))
                iTotalPoints += (((iThisItemsMaxPoints[PICKUPRADIUS] + iThisItemsMaxPoints[GOLDFIND]) / 2) * 0.25);

            // All-resist and pickup radius combined
            if ((iHadStat[ALLRESIST] / iThisItemsMaxStats[ALLRESIST] > 0.55) && (iHadStat[PICKUPRADIUS] > 0))
                iTotalPoints += (((iThisItemsMaxPoints[PICKUPRADIUS] + iThisItemsMaxPoints[ALLRESIST]) / 2) * 0.65);

            // Special crit hit/crit chance/attack speed combos
            double dBestFinalBonus = 1d;
            if ((iHadStat[CRITCHANCE] > (iThisItemsMaxStats[CRITCHANCE] * 0.8)) && (iHadStat[CRITDAMAGE] > (iThisItemsMaxStats[CRITDAMAGE] * 0.8)) && (iHadStat[ATTACKSPEED] > (iThisItemsMaxStats[ATTACKSPEED] * 0.8)))
            {
                if (dBestFinalBonus < 3.2 && thisGilesItemType != GilesItemType.Quiver) dBestFinalBonus = 3.2;
            }
            if ((iHadStat[CRITCHANCE] > (iThisItemsMaxStats[CRITCHANCE] * 0.8)) && (iHadStat[CRITDAMAGE] > (iThisItemsMaxStats[CRITDAMAGE] * 0.8)))
            {
                if (dBestFinalBonus < 2.3) dBestFinalBonus = 2.3;
            }
            if ((iHadStat[CRITCHANCE] > (iThisItemsMaxStats[CRITCHANCE] * 0.8)) && (iHadStat[ATTACKSPEED] > (iThisItemsMaxStats[ATTACKSPEED] * 0.8)))
            {
                if (dBestFinalBonus < 2.1 && thisGilesItemType != GilesItemType.Quiver) dBestFinalBonus = 2.1;
            }
            if ((iHadStat[CRITDAMAGE] > (iThisItemsMaxStats[CRITDAMAGE] * 0.8)) && (iHadStat[ATTACKSPEED] > (iThisItemsMaxStats[ATTACKSPEED] * 0.8)))
            {
                if (dBestFinalBonus < 1.8 && thisGilesItemType != GilesItemType.Quiver) dBestFinalBonus = 1.8;
            }
            if ((iHadStat[CRITCHANCE] > (iThisItemsMaxStats[CRITCHANCE] * 0.65)) && (iHadStat[CRITDAMAGE] > (iThisItemsMaxStats[CRITDAMAGE] * 0.65)) && (iHadStat[ATTACKSPEED] > (iThisItemsMaxStats[ATTACKSPEED] * 0.65)))
            {
                if (dBestFinalBonus < 2.1 && thisGilesItemType != GilesItemType.Quiver) dBestFinalBonus = 2.1;
            }
            if ((iHadStat[CRITCHANCE] > (iThisItemsMaxStats[CRITCHANCE] * 0.65)) && (iHadStat[CRITDAMAGE] > (iThisItemsMaxStats[CRITDAMAGE] * 0.65)))
            {
                if (dBestFinalBonus < 1.9) dBestFinalBonus = 1.9;
            }
            if ((iHadStat[CRITCHANCE] > (iThisItemsMaxStats[CRITCHANCE] * 0.65)) && (iHadStat[ATTACKSPEED] > (iThisItemsMaxStats[ATTACKSPEED] * 0.65)))
            {
                if (dBestFinalBonus < 1.7 && thisGilesItemType != GilesItemType.Quiver) dBestFinalBonus = 1.7;
            }
            if ((iHadStat[CRITDAMAGE] > (iThisItemsMaxStats[CRITDAMAGE] * 0.65)) && (iHadStat[ATTACKSPEED] > (iThisItemsMaxStats[ATTACKSPEED] * 0.65)))
            {
                if (dBestFinalBonus < 1.5 && thisGilesItemType != GilesItemType.Quiver) dBestFinalBonus = 1.5;
            }
            if ((iHadStat[CRITCHANCE] > (iThisItemsMaxStats[CRITCHANCE] * 0.45)) && (iHadStat[CRITDAMAGE] > (iThisItemsMaxStats[CRITDAMAGE] * 0.45)) && (iHadStat[ATTACKSPEED] > (iThisItemsMaxStats[ATTACKSPEED] * 0.45)))
            {
                if (dBestFinalBonus < 1.7 && thisGilesItemType != GilesItemType.Quiver) dBestFinalBonus = 1.7;
            }
            if ((iHadStat[CRITCHANCE] > (iThisItemsMaxStats[CRITCHANCE] * 0.45)) && (iHadStat[CRITDAMAGE] > (iThisItemsMaxStats[CRITDAMAGE] * 0.45)))
            {
                if (dBestFinalBonus < 1.4) dBestFinalBonus = 1.4;
            }
            if ((iHadStat[CRITCHANCE] > (iThisItemsMaxStats[CRITCHANCE] * 0.45)) && (iHadStat[ATTACKSPEED] > (iThisItemsMaxStats[ATTACKSPEED] * 0.45)))
            {
                if (dBestFinalBonus < 1.3 && thisGilesItemType != GilesItemType.Quiver) dBestFinalBonus = 1.3;
            }
            if ((iHadStat[CRITDAMAGE] > (iThisItemsMaxStats[CRITDAMAGE] * 0.45)) && (iHadStat[ATTACKSPEED] > (iThisItemsMaxStats[ATTACKSPEED] * 0.45)))
            {
                if (dBestFinalBonus < 1.1 && thisGilesItemType != GilesItemType.Quiver) dBestFinalBonus = 1.1;
            }

            iTotalPoints *= dBestFinalBonus;

            //1h Weapons that fall below the 60% range get docked!

            return Math.Round(iTotalPoints);
        }
Exemple #6
0
        // **********************************************************************************************
        // *****                      Log the nice items we found and stashed                       *****
        // **********************************************************************************************
        internal static void LogGoodItems(CacheACDItem thisgooditem, GilesBaseItemType thisgilesbaseitemtype, GilesItemType thisgilesitemtype, double ithisitemvalue)
        {
            FileStream LogStream=null;
                try
                {

                     LogStream=File.Open(LoggingFolderPath+LoggingPrefixString+" -- StashLog.log", FileMode.Append, FileAccess.Write, FileShare.Read);
                     using (StreamWriter LogWriter=new StreamWriter(LogStream))
                     {
                          if (!TownRunManager.bLoggedAnythingThisStash)
                          {
                                TownRunManager.bLoggedAnythingThisStash=true;
                                LogWriter.WriteLine(DateTime.Now.ToString()+":");
                                LogWriter.WriteLine("====================");
                          }
                          string sLegendaryString="";
                          if (thisgooditem.ThisQuality>=ItemQuality.Legendary)
                          {
                                if (!thisgooditem.IsUnidentified)
                                {
                                     AddNotificationToQueue(thisgooditem.ThisRealName+" ["+thisgilesitemtype.ToString()+"] (Score="+ithisitemvalue.ToString()+". "+TownRunManager.sValueItemStatString+")", ZetaDia.Service.CurrentHero.Name+" new legendary!", ProwlNotificationPriority.Emergency);
                                     sLegendaryString=" {legendary item}";
                                     // Change made by bombastic
                                     Logging.Write("+=+=+=+=+=+=+=+=+ LEGENDARY FOUND +=+=+=+=+=+=+=+=+");
                                     Logging.Write("+  Name:       "+thisgooditem.ThisRealName+" ("+thisgilesitemtype.ToString()+")");
                                     Logging.Write("+  Score:       "+Math.Round(ithisitemvalue).ToString());
                                     Logging.Write("+  Attributes: "+ thisgooditem.ItemStatString);
                                     Logging.Write("+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+");
                                }
                                else
                                {
                                     Logging.Write("+=+=+=+=+=+=+=+=+ LEGENDARY FOUND +=+=+=+=+=+=+=+=+");
                                     Logging.Write("+  Unid:       "+thisgilesitemtype.ToString());
                                     Logging.Write("+  Level:       "+thisgooditem.ThisLevel.ToString());
                                     Logging.Write("+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+");
                                }

                          }
                          else
                          {
                                // Check for non-legendary notifications
                                bool bShouldNotify=false;
                                switch (thisgilesbaseitemtype)
                                {
                                     case GilesBaseItemType.WeaponOneHand:
                                     case GilesBaseItemType.WeaponRange:
                                     case GilesBaseItemType.WeaponTwoHand:
                                          //if (ithisitemvalue >= settings.iNeedPointsToNotifyWeapon)
                                          //  bShouldNotify = true;
                                          break;
                                     case GilesBaseItemType.Armor:
                                     case GilesBaseItemType.Offhand:
                                          //if (ithisitemvalue >= settings.iNeedPointsToNotifyArmor)
                                          //bShouldNotify = true;
                                          break;
                                     case GilesBaseItemType.Jewelry:
                                          //if (ithisitemvalue >= settings.iNeedPointsToNotifyJewelry)
                                          //bShouldNotify = true;
                                          break;
                                }
                                if (bShouldNotify)
                                     AddNotificationToQueue(thisgooditem.ThisRealName+" ["+thisgilesitemtype.ToString()+"] (Score="+ithisitemvalue.ToString()+". "+TownRunManager.sValueItemStatString+")", ZetaDia.Service.CurrentHero.Name+" new item!", ProwlNotificationPriority.Emergency);
                          }
                          if (!thisgooditem.IsUnidentified)
                          {
                                LogWriter.WriteLine(thisgilesbaseitemtype.ToString()+" - "+thisgilesitemtype.ToString()+" '"+thisgooditem.ThisRealName+"'. Score = "+Math.Round(ithisitemvalue).ToString()+sLegendaryString);
                                LogWriter.WriteLine("  "+thisgooditem.ItemStatString);
                                LogWriter.WriteLine("");
                          }
                          else
                          {
                                LogWriter.WriteLine(thisgilesbaseitemtype.ToString()+" - "+thisgilesitemtype.ToString()+" '"+sLegendaryString);
                                LogWriter.WriteLine("  "+thisgooditem.ThisLevel.ToString());
                                LogWriter.WriteLine("");
                          }
                     }

                } catch (IOException)
                {
                     Log("Fatal Error: File access error for stash log file.");
                }
        }
Exemple #7
0
        // **********************************************************************************************
        // *****                   Log the rubbish junk items we salvaged or sold                   *****
        // **********************************************************************************************
        internal static void LogJunkItems(CacheACDItem thisgooditem, GilesBaseItemType thisgilesbaseitemtype, GilesItemType thisgilesitemtype, double ithisitemvalue)
        {
            FileStream LogStream=null;
                try
                {
                     LogStream=File.Open(LoggingFolderPath+LoggingPrefixString+" -- JunkLog.log", FileMode.Append, FileAccess.Write, FileShare.Read);
                     using (StreamWriter LogWriter=new StreamWriter(LogStream))
                     {
                          if (!TownRunManager.bLoggedJunkThisStash)
                          {
                                TownRunManager.bLoggedJunkThisStash=true;
                                LogWriter.WriteLine(DateTime.Now.ToString()+":");
                                LogWriter.WriteLine("====================");
                          }
                          string sLegendaryString="";
                          if (thisgooditem.ThisQuality>=ItemQuality.Legendary)
                                sLegendaryString=" {legendary item}";
                          LogWriter.WriteLine(thisgilesbaseitemtype.ToString()+" - "+thisgilesitemtype.ToString()+" '"+thisgooditem.ThisRealName+"'. Score = "+Math.Round(ithisitemvalue).ToString()+sLegendaryString);
                          if (!String.IsNullOrEmpty(TownRunManager.sJunkItemStatString))
                                LogWriter.WriteLine("  "+TownRunManager.sJunkItemStatString);
                          else
                                LogWriter.WriteLine("  (no scorable attributes)");
                          LogWriter.WriteLine("");
                     }

                } catch (IOException)
                {
                     Log("Fatal Error: File access error for junk log file.");
                }
        }