Advertisement
jarppaaja

HoveredItemInfo rev 941

Feb 3rd, 2019
409
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 22.06 KB | None | 0 0
  1. // HoveredItemInfo.cs "$Revision: 941 $" "$Date: 2019-02-03 15:38:54 +0200 (su, 03 helmi 2019) $"
  2. using SharpDX.DirectInput;
  3. using System;
  4. using System.Text;
  5. using System.Drawing;
  6. using Turbo.Plugins;
  7. using Turbo.Plugins.Default;
  8. using System.Collections.Generic;
  9. using SharpDX.DirectWrite;
  10.  
  11. namespace Turbo.plugins.JarJar
  12. {
  13.     class HoveredItemInfo : BasePlugin, IKeyEventHandler, IInGameTopPainter
  14.     {
  15.         public Key ToggleDialogKey { get; set; } = Key.LeftControl;     // Key to toggle Dialog on/off.
  16.         public Key DumpKey { get; set; } = Key.Multiply;
  17.  
  18.         public bool UseKeepDecision { get; set; } = false;
  19.         public string[] KeepLabels { get; set; } = {
  20.             /* 0 */ "is null",
  21.             /* 1 */ "is Good",
  22.             /* 2 */ "is Bad",
  23.             /* 3 */ "is Irrelevant",
  24.             /* 4 */ "is Yellow",
  25.             /* 5 */ "is Blue",
  26.             /* 6 */ "is Grey",
  27.         };
  28.  
  29.         // Item description parameter substitution.
  30.         public string ValueChar { get; set; } = "$";
  31.         public string ValueChar1 { get; set; } = "$1";
  32.         public string ValueChar2 { get; set; } = "$2";
  33.  
  34.         // Default fonts.
  35.         public IFont LooksGood { get; set; }
  36.         public IFont DefinitelyBad { get; set; }
  37.         public IFont TextFont { get; set; }
  38.         // Rank fonts.
  39.         public IFont TextFontMissing;
  40.         public IFont[] rankFont;
  41.  
  42.         public ColorDialog Dialog { get; set; }
  43.  
  44.         // Dialog positioning.
  45.         public float leftX { get; set; } = 0.005f;      // left pos
  46.         public float topY { get; set; } = 0.005f;       // top pos
  47.         public float rightX { get; set; } = 0.995f;     // right pos
  48.         public float bottomY { get; set; } = 0.995f;    // bottom pos
  49.         public float marginW { get; set; } = 0.01f;     // base width w/o content (margin around content)
  50.         public float marginH { get; set; } = 0.03f;     // base height
  51.  
  52.         string titleText;
  53.         string titleQuality;
  54.         List<string> contentLines;
  55.  
  56.         IItem hoveredItem;
  57.         string hoveredItemUniqueId;
  58.         StringBuilder builder = new StringBuilder();
  59.         PaintData dialogData;
  60.         SizeF dialogSize;
  61.         bool stashVisible;
  62.         bool dialogVisible = true;      // For dialog toggle.
  63.  
  64.         public HoveredItemInfo() { Enabled = true; }
  65.  
  66.         public override void Load(IController hud)
  67.         {
  68.             base.Load(hud);
  69.  
  70.             leftX *= Hud.Window.Size.Width;
  71.             rightX *= Hud.Window.Size.Width;
  72.             topY *= Hud.Window.Size.Height;
  73.             bottomY *= Hud.Window.Size.Height;
  74.             marginW *= Hud.Window.Size.Width;
  75.             marginH *= Hud.Window.Size.Height;
  76.  
  77.             LooksGood = hud.Render.CreateFont("tahoma", 9, 255, 0, 204, 0, true, false, false);             // green
  78.             DefinitelyBad = hud.Render.CreateFont("tahoma", 9, 255, 204, 102, 0, true, false, false);       // brownish
  79.             TextFont = hud.Render.CreateFont("consolas", 7, 255, 255, 255, 255, false, false, false);       // white
  80.  
  81.             int alpha80 = (int)(256 * 0.80);
  82.             TextFontMissing = Hud.Render.CreateFont("consolas", 7, alpha80, 0xe0, 0xe0, 0xe0, true, false, false);  // Light grey with alpha.
  83.             int[][] rgb = new[]
  84.             {
  85.                 // Orange "rank" slider.
  86.                 new int[] { 0x00, 0xcc, 0x00 }, // Greenish.
  87.                 new int[] { 0xcc, 0x66, 0x00 },
  88.                 new int[] { 0xf0, 0x80, 0x00 },
  89.                 new int[] { 0xff, 0x99, 0x33 },
  90.                 new int[] { 0xff, 0xb2, 0x66 },
  91.                 new int[] { 0xff, 0xcc, 0x99 },
  92.                 new int[] { 0xff, 0xcc, 0xcc }, // Pinkish.
  93.             };
  94.             rankFont = new IFont[rgb.Length];
  95.             for (int i = 0; i < rgb.Length; ++i)
  96.             {
  97.                 rankFont[i] = Hud.Render.CreateFont("consolas", 7, 255, rgb[i][0], rgb[i][1], rgb[i][2], true, false, false);
  98.             }
  99.  
  100.             Dialog = new ColorDialog(hud)
  101.             {
  102.                 BorderBrush = hud.Render.CreateBrush(255, 180, 147, 109, -1),
  103.                 BackgroundBrush = hud.Render.CreateBrush(225, 0, 0, 0, 0),
  104.             };
  105.             dialogData = new PaintData()
  106.             {
  107.                 LeftHeader = new Tuple<string, IFont>("Left", LooksGood),
  108.                 RightHeader = new Tuple<string, IFont>("Right", DefinitelyBad),
  109.                 Lines = new List<System.Tuple<string, IFont>>(),
  110.             };
  111.         }
  112.  
  113.         IFont getLineFont(int rank)
  114.         {
  115.             if (rank >= 100) return rankFont[0];
  116.             if (rank >= 90) return rankFont[1];
  117.             if (rank >= 80) return rankFont[2];
  118.             if (rank >= 60) return rankFont[3];
  119.             if (rank >= 40) return rankFont[4];
  120.             if (rank >= 20) return rankFont[5];
  121.             if (rank >= 00) return rankFont[6];
  122.             if (rank == -1) return TextFont;
  123.             return TextFontMissing;
  124.         }
  125.  
  126.         public void PaintTopInGame(ClipState clipState)
  127.         {
  128.             if (Hud.Render.UiHidden) return;
  129.             if (clipState == ClipState.Inventory)
  130.             {
  131.                 var stash = Hud.Inventory.StashMainUiElement;
  132.                 stashVisible = stash.Visible;
  133.                 return;
  134.             }
  135.             if (!Hud.Game.IsInTown || Hud.Render.UiHidden) return;
  136.             if (clipState != ClipState.AfterClip) return;
  137.  
  138.             hoveredItem = Hud.Inventory.HoveredItem;    // Save current hovered item.
  139.             if (hoveredItem != null)
  140.             {
  141.                 if (hoveredItem.Unidentified || hoveredItem.Location == ItemLocation.Merchant)
  142.                 {
  143.                     reset();    // Can't or won't show.
  144.                 }
  145.                 else if (hoveredItem.ItemUniqueId != hoveredItemUniqueId)
  146.                 {
  147.                     bool isValid = IsValid(hoveredItem);
  148.                     hoveredItemUniqueId = hoveredItem.ItemUniqueId;
  149.                     List<int> quality = new List<int>();
  150.                     try
  151.                     {
  152.                         titleText = GetItemTitle(hoveredItem, isValid);
  153.                         titleQuality = GetItemQuality(hoveredItem, isValid);
  154.                         contentLines = GetItemDetails(hoveredItem, ref quality);
  155.                     }
  156.                     catch (Exception x)
  157.                     {
  158.                         titleText = "Error";
  159.                         titleQuality = "";
  160.                         contentLines.Clear();
  161.                         contentLines.Add(x.Message);
  162.                     }
  163.                     dialogData.LeftHeader = new Tuple<string, IFont>(titleText, LooksGood);
  164.                     dialogData.RightHeader = new Tuple<string, IFont>(titleQuality, DefinitelyBad);
  165.                     dialogData.Lines.Clear();
  166.                     for (int i = 0; i < contentLines.Count; ++i)
  167.                     {
  168.                         string line = contentLines[i];
  169.                         dialogData.Lines.Add(new Tuple<string, IFont>(line, getLineFont(quality[i])));
  170.                     }
  171.                     dialogSize = Dialog.CalculateLayout(dialogData);
  172.                 }
  173.             }
  174.             else if (contentLines != null)
  175.             {
  176.                 reset();
  177.             }
  178.             // Draw Actual dialog if available!
  179.             if (hoveredItem != null)
  180.             {
  181.                 if (stashVisible)
  182.                 {
  183.                     // bottom right.
  184.                     float curX = rightX - dialogSize.Width;
  185.                     float curY = bottomY - dialogSize.Height;
  186.                     if (Dialog.Location.X != curX || Dialog.Location.Y != curY)
  187.                     {
  188.                         Dialog.Location = new PointF(curX, curY);
  189.                     }
  190.                     Dialog.RenderDialog(dialogSize);
  191.                 }
  192.                 else
  193.                 {
  194.                     // top left
  195.                     if (Dialog.Location.X != leftX)
  196.                     {
  197.                         Dialog.Location = new PointF(leftX, topY);
  198.                     }
  199.                     Dialog.RenderDialog(dialogSize);
  200.                 }
  201.             }
  202.         }
  203.  
  204.         public void OnKeyEvent(IKeyEvent keyEvent)
  205.         {
  206.             if (keyEvent.IsPressed)
  207.             {
  208.                 if (keyEvent.Key == DumpKey)
  209.                 {
  210.                     if (hoveredItem != null)
  211.                     {
  212.                         Hud.Debug(string.Format("ITEM NameEnglish \"{0}\"\r\n{1} {2}\r\n{3}",
  213.                             hoveredItem.SnoItem.NameEnglish,
  214.                             titleText, titleQuality,
  215.                             string.Join("\r\n", contentLines)));
  216.                     }
  217.                 }
  218.             }
  219.         }
  220.  
  221.         void reset()
  222.         {
  223.             hoveredItem = null;
  224.             hoveredItemUniqueId = null;
  225.         }
  226.  
  227.         string GetItemTitle(IItem item, bool isValid)
  228.         {
  229.             return hoveredItem.FullNameEnglish;
  230.         }
  231.  
  232.         string GetItemQuality(IItem item, bool isValid)
  233.         {
  234.             if (isValid)
  235.             {
  236.                 string itemType = item.SnoItem.MainGroupCode == "pants" || string.Compare(item.SnoItem.MainGroupCode, item.SnoItem.SnoItemType.Code, true) == 0
  237.                     ? item.SnoItem.SnoItemType.Code
  238.                     : item.SnoItem.MainGroupCode + " " + item.SnoItem.SnoItemType.Code;
  239.                 return string.Format("{0} {1} ({2:0}%)",
  240.                     itemType,
  241.                     UseKeepDecision ? GetKeepDecision(item) : "",
  242.                     item.Perfection);
  243.             }
  244.             return "";
  245.         }
  246.  
  247.         List<string> GetItemDetails(IItem item, ref List<int> quality)
  248.         {
  249.             List<string> lines = new List<string>();
  250.             builder.Clear();
  251.             builder
  252.                 .AppendFormat("{0,-37}", item.SnoItem.Code)
  253.                 .AppendFormat("{0,12}", GetAncientRank(item))
  254.                 .AppendFormat("  sno={0,-11}", item.SnoItem.Sno);
  255.             if (item.SetSno != uint.MaxValue)
  256.             {
  257.                 builder.AppendFormat(" set={0,-11}", item.SetSno);
  258.             }
  259.             builder.Append(' ').Append(item.Location);
  260.             lines.Add(builder.ToString());
  261.             quality.Add(-1);
  262.             builder.Clear();
  263.  
  264.             builder
  265.                 .AppendFormat("#{0}", item.Perfections == null ? 0 : item.Perfections.Length);
  266.             lines.Add(builder.ToString());
  267.             quality.Add(-1);
  268.             builder.Clear();
  269.             if (item.Perfections != null)
  270.             {
  271.                 foreach (IItemPerfection perfection in item.Perfections)
  272.                 {
  273.                     double rawRank = calculateRank(perfection);
  274.                     string precision = perfection.Attribute.ValueType == AttributeValueType._int ? "G0" : "G7";
  275.                     string range = string.Format("[{0}-{1}]", perfection.Min.ToString(precision), perfection.Max.ToString(precision));
  276.                     string curValue = Math.Round(perfection.Cur, 3).ToString(precision);
  277.                     string modifier = getModifier(perfection);
  278.                     double rankValue = calculateRank(perfection);
  279.                     builder
  280.                         .AppendFormat("{0,-37}", perfection.Attribute.Code)
  281.                         .AppendFormat("{0,13}", range)
  282.                         .AppendFormat("{0,6}", curValue)
  283.                         .AppendFormat("{0,5}", formatRankValue(perfection, rankValue))
  284.                         .AppendFormat("  mod={0,-8}", modifier)
  285.                         .Append(GetAttributeDescription(perfection));
  286.                     lines.Add(builder.ToString());
  287.                     quality.Add((int)rankValue);
  288.                     builder.Clear();
  289.                 }
  290.             }
  291.             if (item.SocketCount > 0)
  292.             {
  293.                 builder
  294.                     .AppendFormat("sockets = {0}", item.SocketCount);
  295.                 lines.Add(builder.ToString());
  296.                 quality.Add(-1);
  297.                 builder.Clear();
  298.             }
  299.             return lines;
  300.         }
  301.  
  302.         const uint MOD_NaturalConstant = 1048575;
  303.  
  304.         static char GetAncientRank(IItem item)
  305.         {
  306.             return item == null || item.AncientRank < 1 ? ' ' : item.AncientRank == 1 ? 'A' : 'P';
  307.         }
  308.  
  309.         static string formatRankValue(IItemPerfection perfection, double rankValue)
  310.         {
  311.             if (perfection.Min == perfection.Max) return "~ ";
  312.             return string.Format("{0:0}%", rankValue);
  313.         }
  314.  
  315.         public string GetKeepDecision(IItem item)
  316.         {
  317.             if (item == null) return KeepLabels[0];
  318.             if (item.IsLegendary)
  319.             {
  320.                 return item.KeepDecision == ItemKeepDecision.LooksGood ? KeepLabels[1]
  321.                       : item.KeepDecision == ItemKeepDecision.DefinitelyBad ? KeepLabels[2]
  322.                       : KeepLabels[3];
  323.             }
  324.             if (item.IsRare) return KeepLabels[4];
  325.             if (item.IsMagic) return KeepLabels[5];
  326.             return KeepLabels[6];
  327.         }
  328.  
  329.         public static bool IsValid(IItem item)
  330.         {
  331.             ISnoItem snoItem = item.SnoItem;
  332.             if (snoItem == null || !(snoItem.Kind == ItemKind.loot || snoItem.Kind == ItemKind.craft)) return false;
  333.             return
  334.                 snoItem.MainGroupCode == "1h" ||
  335.                 snoItem.MainGroupCode == "2h" ||
  336.                 snoItem.MainGroupCode == "amulet" ||
  337.                 snoItem.MainGroupCode == "belt" ||
  338.                 snoItem.MainGroupCode == "boots" ||
  339.                 snoItem.MainGroupCode == "bracers" ||
  340.                 snoItem.MainGroupCode == "chestarmor" ||
  341.                 snoItem.MainGroupCode == "crusadershield" ||
  342.                 snoItem.MainGroupCode == "follower" ||
  343.                 snoItem.MainGroupCode == "gloves" ||
  344.                 snoItem.MainGroupCode == "helm" ||
  345.                 snoItem.MainGroupCode == "mojo" ||
  346.                 snoItem.MainGroupCode == "necromanceroffhand" ||
  347.                 snoItem.MainGroupCode == "pants" ||
  348.                 snoItem.MainGroupCode == "quiver" ||
  349.                 snoItem.MainGroupCode == "ring" ||
  350.                 snoItem.MainGroupCode == "shield" ||
  351.                 snoItem.MainGroupCode == "shoulders" ||
  352.                 snoItem.MainGroupCode == "source" ||
  353.                 snoItem.MainGroupCode == "staffofcow";
  354.         }
  355.  
  356.         static string getModifier(IItemPerfection perfection)
  357.         {
  358.             return perfection.Modifier == 1048575 // typical/default attribute modifier in perfections.
  359.                 ? "-"
  360.                 : perfection.Modifier.ToString();
  361.         }
  362.  
  363.         string GetAttributeDescription(IItemPerfection perfection)
  364.         {
  365.             string description = perfection.Attribute.GetDescription(perfection.Modifier);
  366.             if (description == null)
  367.             {
  368.                 description = "null";
  369.             }
  370.             return description
  371.                 .Replace("{VALUE}", ValueChar)
  372.                 .Replace("{VALUE1}", ValueChar1)
  373.                 .Replace("{VALUE2}", ValueChar2);
  374.         }
  375.  
  376.         static double calculateRank(IItemPerfection perfection)
  377.         {
  378.             if (perfection == null) return 0;
  379.             double cur = perfection.Cur;
  380.             double min = perfection.Min;
  381.             double max = perfection.Max;
  382.             if (perfection.Attribute.ValueType == AttributeValueType._float)
  383.             {
  384.                 cur = Math.Round(perfection.Cur, 3);
  385.                 min = Math.Round(perfection.Min, 3);
  386.                 max = Math.Round(perfection.Max, 3);
  387.             }
  388.             else
  389.             {
  390.                 cur = perfection.Cur;
  391.                 min = perfection.Min;
  392.                 max = perfection.Max;
  393.             }
  394.             return calculate(cur, min, max);
  395.         }
  396.  
  397.         static double calculate(double cur, double min, double max)
  398.         {
  399.             if (cur > min && cur < max)
  400.             {
  401.                 // Current value relative distance % from Min to Max (0-100).
  402.                 return (((cur - min) / (max - min)) * 100.0);
  403.             }
  404.             // Edge cases and for example: "Sockets [1-1]=1" or "Crossbow [1-1]=2"
  405.             return !(cur < max) ? 100.0 : 0.0;
  406.         }
  407.     }
  408.  
  409.     // this is not a plugin, just a helper class to display a dialog on the screen.
  410.  
  411.     public class PaintData
  412.     {
  413.         public Tuple<string, IFont> LeftHeader;         // Left header
  414.         public Tuple<string, IFont> RightHeader;        // Right header
  415.         public List<Tuple<string, IFont>> Lines;        // Content lines.
  416.     }
  417.  
  418.     public class ColorDialog : ITransparentCollection
  419.     {
  420.         public PointF Location { get; set; }            // Dialog location.
  421.         public float PaddingW { get; set; }             // Vertical padding.
  422.         public float PaddingH { get; set; }             // Horizontal padding.
  423.  
  424.         public IBrush BackgroundBrush { get; set; }
  425.         public IBrush BorderBrush { get; set; }
  426.  
  427.         IController Hud { get; }
  428.         PaintData data;
  429.         TextLayout leftLayout;
  430.         TextLayout rightLayout;
  431.         float titleHeight;
  432.         float maxLineWidth;
  433.         TextLayout[] textLayout = new TextLayout[0];
  434.         int drawCount = 0;
  435.  
  436.         public ColorDialog(IController hud)
  437.         {
  438.             Hud = hud;
  439.  
  440.             Location = new PointF(Hud.Window.Size.Width / 100f, Hud.Window.Size.Height / 100f);
  441.             PaddingW = 4 * Hud.Window.Size.Width / 1920.0f;
  442.             PaddingH = 3 * Hud.Window.Size.Height / 1020.0f;
  443.         }
  444.  
  445.         public void Paint(PaintData data)
  446.         {
  447.             // Convenience method when dialog position is stationary.
  448.             RenderDialog(CalculateLayout(data));
  449.         }
  450.  
  451.         public SizeF CalculateLayout(PaintData data)
  452.         {
  453.             // Calcualte dialog size and prepare for rendering it.
  454.             this.data = data;
  455.  
  456.             leftLayout = data.LeftHeader != null ? data.LeftHeader.Item2.GetTextLayout(data.LeftHeader.Item1) : null;
  457.             rightLayout = data.RightHeader != null ? data.RightHeader.Item2.GetTextLayout(data.RightHeader.Item1) : null;
  458.             maxLineWidth = (leftLayout != null ? leftLayout.Metrics.Width : 0.0f) + (rightLayout != null ? rightLayout.Metrics.Width : 0.0f);
  459.             titleHeight = Math.Max((leftLayout != null ? leftLayout.Metrics.Height : 0.0f), (rightLayout != null ? rightLayout.Metrics.Height : 0.0f));
  460.             float totalHeight = titleHeight;
  461.             if (BorderBrush != null)
  462.             {
  463.                 totalHeight += 2f * PaddingH;
  464.             }
  465.             if (data.Lines != null)
  466.             {
  467.                 if (data.Lines.Count > textLayout.Length)
  468.                 {
  469.                     textLayout = new TextLayout[data.Lines.Count];
  470.                 }
  471.                 for (int i = 0; i < data.Lines.Count; ++i)
  472.                 {
  473.                     textLayout[i] = data.Lines[i].Item2.GetTextLayout(data.Lines[i].Item1);
  474.                     if (maxLineWidth < textLayout[i].Metrics.Width)
  475.                     {
  476.                         maxLineWidth = textLayout[i].Metrics.Width;
  477.                     }
  478.                     totalHeight += textLayout[i].Metrics.Height;
  479.                 }
  480.             }
  481.             drawCount = 0;
  482.             return new SizeF(maxLineWidth + 2f * PaddingW, totalHeight + 2f * PaddingH);
  483.         }
  484.  
  485.         public void RenderDialog(SizeF dialogSize)
  486.         {
  487.             if (drawCount > 0)
  488.             {
  489.                 // Recalculate layouts.
  490.                 dialogSize = CalculateLayout(data);
  491.             }
  492.             // Render dialog using given rect.
  493.             if (BackgroundBrush != null)
  494.             {
  495.                 BackgroundBrush.DrawRectangle(Location.X, Location.Y, dialogSize.Width, dialogSize.Height);
  496.             }
  497.             // Line pointer.
  498.             float currentY = Location.Y;
  499.             // Header line.
  500.             if (leftLayout != null || rightLayout != null)
  501.             {
  502.                 if (leftLayout != null)
  503.                 {
  504.                     data.LeftHeader.Item2.DrawText(leftLayout, Location.X + PaddingW, currentY + PaddingH);
  505.                 }
  506.                 if (rightLayout != null)
  507.                 {
  508.                     data.RightHeader.Item2.DrawText(rightLayout, Location.X - PaddingW + maxLineWidth - rightLayout.Metrics.Width, currentY + PaddingH);
  509.                 }
  510.                 if (BorderBrush != null)
  511.                 {
  512.                     // Borderline under header.
  513.                     currentY += titleHeight + 2f * PaddingH;
  514.                     BorderBrush.DrawLine(Location.X, currentY, Location.X + dialogSize.Width, currentY);
  515.                     currentY += PaddingH;
  516.                 }
  517.                 else
  518.                 {
  519.                     currentY += titleHeight;
  520.                 }
  521.             }
  522.             // Content lines.
  523.             if (data.Lines != null)
  524.             {
  525.                 for (int i = 0; i < data.Lines.Count; ++i)
  526.                 {
  527.                     data.Lines[i].Item2.DrawText(textLayout[i], Location.X + PaddingW, currentY);
  528.                     currentY += textLayout[i].Metrics.Height;
  529.                 }
  530.             }
  531.             if (BorderBrush != null)
  532.             {
  533.                 BorderBrush.DrawRectangle(Location.X, Location.Y, dialogSize.Width, dialogSize.Height);
  534.             }
  535.             drawCount += 1;
  536.         }
  537.  
  538.         public IEnumerable<ITransparent> GetTransparents()
  539.         {
  540.             yield return BackgroundBrush;
  541.             yield return BorderBrush;
  542.             if (data != null)
  543.             {
  544.                 if (data.LeftHeader != null) yield return data.LeftHeader.Item2;
  545.                 if (data.RightHeader != null) yield return data.RightHeader.Item2;
  546.                 if (data.Lines != null)
  547.                 {
  548.                     foreach (var line in data.Lines)
  549.                     {
  550.                         yield return line.Item2;
  551.                     }
  552.                 }
  553.             }
  554.         }
  555.     }
  556. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement