Advertisement
jarppaaja

AlternateSkillBar

Aug 2nd, 2019
912
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 13.68 KB | None | 0 0
  1. // AlternateSkillBar.cs "$Revision: 2527 $" "$Date: 2019-08-21 14:33:38 +0300 (ke, 21 elo 2019) $"
  2. // https://www.ownedcore.com/forums/diablo-3/turbohud/turbohud-community-plugins/797402-alternateskillbar.html
  3. // https://pastebin.com/FZd2xr7z
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Globalization;
  7. using System.Linq;
  8. using SharpDX;
  9. using Turbo.Plugins.Default;
  10.  
  11. namespace Turbo.Plugins.JarJar.DefaultUI
  12. {
  13.     public class AlternateSkillBar : BasePlugin, IInGameTopPainter
  14.     {
  15.         public float offsetX { get; set; } = 0.60f;     // Percent-X pos
  16.         public float offsetY { get; set; } = 0.05f;     // Percent-Y pos
  17.         public float IconSize { get; set; } = 55.0f;    // Icon size.
  18.         public float IconSpacing { get; set; } = 3.0f;  // Icon gap.
  19.  
  20.         public uint HealthPotionTextureid { get; set; } = 3247534500;   // See https://ibb.co/wCVDFzz or /plugins_support/_images/d3_potions_textureid.png
  21.         public bool IncludeHeal { get; set; } = true;
  22.         public bool ShowHealAlways { get; set; } = false;
  23.  
  24.         public Func<IController, IEnumerable<IPlayerSkill>> SkillProvider { get; set; } // Gets skills to show in correct order.
  25.         public List<ActionKey> SkillOrder { get; set; }
  26.         public ISnoPower[] ExcludedSkills { get; set; }
  27.         public ISnoPower[] SkillsWithStack { get; set; }
  28.  
  29.         public XDAV_SkillPainter SkillPainter { get; set; }
  30.  
  31.         public AlternateSkillBar() { Enabled = true; Order = 100; }
  32.  
  33.         public override void Load(IController hud)
  34.         {
  35.             base.Load(hud);
  36.             var p = Hud.Sno.SnoPowers;
  37.             SkillProvider = DefaultSkills;
  38.             SkillOrder = new List<ActionKey>
  39.             {
  40.                 ActionKey.Skill1, ActionKey.Skill2, ActionKey.Skill3, ActionKey.Skill4, ActionKey.LeftSkill, ActionKey.RightSkill, ActionKey.Heal
  41.             };
  42.             ExcludedSkills = new ISnoPower[]
  43.             {
  44.                 p.Barbarian_Whirlwind,
  45.                 p.Crusader_SweepAttack,
  46.                 p.DemonHunter_ClusterArrow,
  47.                 p.DemonHunter_EvasiveFire,
  48.                 p.DemonHunter_Impale,
  49.                 p.DemonHunter_Multishot,
  50.                 //p.DemonHunter_Vault,      // Tumble and Acrobatics has duration or cooldown!
  51.                 p.Necromancer_Devour,
  52.             };
  53.             SkillPainter = new XDAV_SkillPainter(Hud)
  54.             {
  55.                 SkillsWitchStacks = new Dictionary<uint, int>()     // skill sno and iconIdex to read stack count from: skill.Buff.IconCounts[iconIdex].
  56.                 {
  57.                     { p.Necromancer_BoneArmor.Sno, 0 },
  58.                 },
  59.                 HealthPotionTextureid = HealthPotionTextureid,
  60.             };
  61.         }
  62.  
  63.         public void PaintTopInGame(ClipState clipState)
  64.         {
  65.             if (Hud.Render.UiHidden || clipState != ClipState.BeforeClip || Hud.Game.MapMode == MapMode.WaypointMap || Hud.Game.MapMode == MapMode.ActMap || Hud.Game.MapMode == MapMode.Map)
  66.                 return;
  67.  
  68.             var posX = offsetX * Hud.Window.Size.Width;
  69.             var posY = offsetY * Hud.Window.Size.Height;
  70.             foreach (var skill in SkillProvider(Hud))
  71.             {
  72.                 var rect = new RectangleF(posX, posY, IconSize, IconSize);
  73.                 SkillPainter.Paint(Hud.Game.Me, skill, rect);
  74.                 posX += rect.Width + IconSpacing;
  75.             }
  76.         }
  77.  
  78.         private IEnumerable<IPlayerSkill> DefaultSkills(IController hud)
  79.         {
  80.             var currentSkills = hud.Game.Me.Powers.CurrentSkills.Where(x => !ExcludedSkills.Contains(x.SnoPower)).ToList();
  81.             if (IncludeHeal)
  82.             {
  83.                 var heal = hud.Game.Me.Powers.HealthPotionSkill;
  84.                 var isOnCooldown = heal.CooldownFinishTick > Hud.Game.CurrentGameTick;
  85.                 if (ShowHealAlways || isOnCooldown)
  86.                 {
  87.                     currentSkills.Add(heal);
  88.                 }
  89.             }
  90.             currentSkills.Sort((a, b) => SkillOrder.IndexOf(a.Key).CompareTo(SkillOrder.IndexOf(b.Key)));
  91.             return currentSkills;
  92.         }
  93.     }
  94.  
  95.     public class XDAV_SkillPainter : ITransparentCollection
  96.     {
  97.         // Original from https://www.ownedcore.com/forums/diablo-3/turbohud/turbohud-community-plugins/787962-eng-combin-plugin-of-party-cooldown-archon-downtime.html
  98.         public float ShowDecimalLimit { get; set; } = 1.0f;
  99.         public bool ShowSpinner { get; set; } = true;
  100.         public bool ShowActiveSkillBorder { get; set; } = true;
  101.         public IFont CooldownFont { get; set; }
  102.         public IFont StacksFont { get; set; }
  103.         public IFont ChargesFont { get; set; }
  104.         public IFont ActiveFont { get; set; }
  105.         public IFont SpinnerFont { get; set; }
  106.         public IBrush ActiveSkillBorderBrush { get; set; }
  107.         public Dictionary<uint, int> SkillsWitchStacks { get; set; } = new Dictionary<uint, int>();
  108.         public float MoveUpRectRatio { get; set; } = 0.2f;
  109.         public float MoveDownRectRatio { get; set; } = 0.2f;
  110.         public float MoveLeftRectRatio { get; set; } = 0.2f;
  111.         public uint HealthPotionTextureid = 3247534500;
  112.  
  113.         private IController Hud { get; set; }
  114.         private readonly string[] spinner = new string[] { "+", "x", "+", "x", "+", "x", "+", "x", "+", "x", };
  115.  
  116.         public XDAV_SkillPainter(IController hud)
  117.         {
  118.             Hud = hud;
  119.  
  120.             var color = Color.Gold;     // D3 UI shows only progressbar for active time!
  121.             ActiveFont = Hud.Render.CreateFont("tahoma", 10, 255, color.R, color.G, color.B, true, false, 255, 0, 0, 0, true);
  122.             color = Color.White;
  123.             CooldownFont = Hud.Render.CreateFont("tahoma", 10, 255, color.R, color.G, color.B, true, false, 255, 0, 0, 0, true);
  124.             ChargesFont = Hud.Render.CreateFont("tahoma", 10, 255, color.R, color.G, color.B, true, false, 255, 0, 0, 0, true);
  125.             color = Color.LawnGreen;
  126.             StacksFont = Hud.Render.CreateFont("tahoma", 10, 255, color.R, color.G, color.B, true, false, 255, 0, 0, 0, true);
  127.             color = Color.GreenYellow;
  128.             SpinnerFont = Hud.Render.CreateFont("tahoma", 10, 255, color.R, color.G, color.B, true, false, 255, 0, 0, 0, true);
  129.             ActiveSkillBorderBrush = Hud.Render.CreateBrush(200, color.R, color.G, color.B, 3f);    // Slightly transparent!
  130.         }
  131.  
  132.         public virtual void Paint(IPlayer player, IPlayerSkill skill, RectangleF rect)
  133.         {
  134.             // Heal SnoPower 30211 DrinkHealthPotion does not have a texture id :-(
  135.             var texture = skill.SnoPower.NormalIconTextureId != 0
  136.                 ? Hud.Texture.GetTexture(skill.SnoPower.NormalIconTextureId)
  137.                 : (Hud.Texture.GetTexture(HealthPotionTextureid) ?? Hud.Texture.EmptySocketTexture);
  138.             if (texture != null)
  139.             {
  140.                 texture.Draw(rect.X, rect.Y, rect.Width, rect.Height);
  141.             }
  142.             if (skill.SnoPower.Sno == Hud.Sno.SnoPowers.DemonHunter_Sentry.Sno)
  143.             {
  144.                 var count = 0;
  145.                 foreach (var actor in Hud.Game.Actors)
  146.                 {
  147.                     if (actor.SummonerAcdDynamicId == player.SummonerId)
  148.                     {
  149.                         switch (actor.SnoActor.Sno)
  150.                         {
  151.                             case ActorSnoEnum._dh_sentry:
  152.                             case ActorSnoEnum._dh_sentry_addsmissiles:
  153.                             case ActorSnoEnum._dh_sentry_addsduration:
  154.                             case ActorSnoEnum._dh_sentry_tether:
  155.                             case ActorSnoEnum._dh_sentry_addsheals:
  156.                             case ActorSnoEnum._dh_sentry_addsshield:
  157.                                 count += 1;
  158.                                 break;
  159.                         }
  160.                     }
  161.                 }
  162.                 var text = count.ToString(CultureInfo.InvariantCulture);
  163.                 var layout = ActiveFont.GetTextLayout(text);
  164.                 ActiveFont.DrawText(layout, rect.X + (rect.Width / 5f), rect.Y + ((rect.Height - layout.Metrics.Height) / 2));
  165.  
  166.                 text = skill.Charges.ToString(CultureInfo.InvariantCulture);
  167.                 layout = SpinnerFont.GetTextLayout(text);
  168.                 SpinnerFont.DrawText(layout, rect.X + rect.Width - (rect.Width / 5f) - layout.Metrics.Width, rect.Y + ((rect.Height - layout.Metrics.Height) / 2));
  169.                 return;
  170.             }
  171.             var remainingSeconds = 0d;
  172.             var stackCount = -1;
  173.             IFont font = null;
  174.             if (skill.BuffIsActive)
  175.             {
  176.                 if (SkillsWitchStacks.TryGetValue(skill.SnoPower.Sno, out var iconIdex))
  177.                 {
  178.                     stackCount = skill.Buff.IconCounts[iconIdex];
  179.                 }
  180.                 if (ShowActiveSkillBorder)
  181.                 {
  182.                     // TODO: add alternate border when skill is about about to expire - like BuffPainter.UseAlternateStyleWhenBuffIsAlmostGone.
  183.                     ActiveSkillBorderBrush.DrawRectangle(rect.X, rect.Y, rect.Width, rect.Height);
  184.                 }
  185.                 var buff = skill.Buff;
  186.                 if (buff.TimeLeftSeconds[0] == 0 && buff.TimeLeftSeconds[1] == 0 && buff.TimeLeftSeconds[2] == 0)
  187.                 {
  188.                     if (skill.SnoPower.Sno == Hud.Sno.SnoPowers.Wizard_StormArmor.Sno)
  189.                     {
  190.                         remainingSeconds = buff.TimeLeftSeconds[3];     // At least one rune uses "extra" slot!
  191.                     }
  192.                 }
  193.                 else
  194.                 {
  195.                     remainingSeconds = Math.Max(buff.TimeLeftSeconds[0], Math.Max(buff.TimeLeftSeconds[1], buff.TimeLeftSeconds[2]));
  196.                 }
  197.                 font = ActiveFont;
  198.                 if (remainingSeconds <= 0)
  199.                 {
  200.                     remainingSeconds = (skill.CooldownFinishTick - Hud.Game.CurrentGameTick) / 60.0d;
  201.                     if (skill.SnoPower.Sno == Hud.Sno.SnoPowers.Wizard_Archon.Sno)
  202.                     {
  203.                         // Archon does not go to cooldown immediately like other skills!
  204.                         font = CooldownFont;
  205.                     }
  206.                     else if (remainingSeconds <= 0 && ShowSpinner)
  207.                     {
  208.                         // Show "spinner" if skill is active and timeleft and cooldown are zero (or less)!
  209.                         // - e.g. Call Of The Ancients can last until they die.
  210.                         var seconds = Hud.Game.CurrentGameTick / 60;
  211.                         drawText(SpinnerFont, spinner[seconds % 10], rect);
  212.                         return;
  213.                     }
  214.                 }
  215.             }
  216.             else
  217.             {
  218.                 remainingSeconds = (skill.CooldownFinishTick - Hud.Game.CurrentGameTick) / 60.0d;
  219.                 font = CooldownFont;
  220.             }
  221.             if (remainingSeconds > 0)
  222.             {
  223.                 if (stackCount >= 0)
  224.                 {
  225.                     var upperRect = new RectangleF(rect.X, rect.Y - (rect.Height * MoveUpRectRatio), rect.Width, rect.Height);
  226.                     drawText(font, remainingSeconds, upperRect);
  227.                     var lowerRect = new RectangleF(rect.X - (rect.Width * MoveLeftRectRatio), rect.Y + (rect.Height * MoveDownRectRatio), rect.Width, rect.Height);
  228.                     var text = stackCount.ToString(CultureInfo.InvariantCulture);
  229.                     drawText(ChargesFont, text, lowerRect);
  230.                 }
  231.                 else
  232.                 {
  233.                     drawText(font, remainingSeconds, rect);
  234.                 }
  235.             }
  236.             else if (skill.Charges > 0)
  237.             {
  238.                 var leftRect = new RectangleF(rect.X + (rect.Width * MoveLeftRectRatio), rect.Y + (rect.Height * MoveDownRectRatio), rect.Width, rect.Height);
  239.                 var text = skill.Charges.ToString(CultureInfo.InvariantCulture);
  240.                 drawText(ChargesFont, text, leftRect);
  241.             }
  242.             else if (stackCount >= 0)
  243.             {
  244.                 var lowerRect = new RectangleF(rect.X - (rect.Width * MoveLeftRectRatio), rect.Y + (rect.Height * MoveDownRectRatio), rect.Width, rect.Height);
  245.                 var text = stackCount.ToString(CultureInfo.InvariantCulture);
  246.                 drawText(ChargesFont, text, lowerRect);
  247.             }
  248.         }
  249.  
  250.         public IEnumerable<ITransparent> GetTransparents()
  251.         {
  252.             yield return CooldownFont;
  253.             yield return ActiveFont;
  254.         }
  255.  
  256.         protected void drawText(IFont font, double timeLeft, RectangleF rect)
  257.         {
  258.             var text = "";
  259.             if (timeLeft > ShowDecimalLimit)
  260.             {
  261.                 if (timeLeft < 60)
  262.                 {
  263.                     text = timeLeft.ToString("F0", CultureInfo.InvariantCulture);
  264.                 }
  265.                 else
  266.                 {
  267.                     var mins = Convert.ToInt32(Math.Floor(timeLeft / 60.0d));
  268.                     var secs = Math.Floor(timeLeft - (mins * 60.0d));
  269.                     text = mins.ToString("F0", CultureInfo.InvariantCulture) + ":" + (secs < 10 ? "0" : "") + secs.ToString("F0", CultureInfo.InvariantCulture);
  270.                 }
  271.             }
  272.             else
  273.             {
  274.                 text = timeLeft.ToString("F1", CultureInfo.InvariantCulture);
  275.             }
  276.             drawText(font, text, rect);
  277.         }
  278.  
  279.         protected void drawText(IFont font, string text, RectangleF rect)
  280.         {
  281.             var layout = font.GetTextLayout(text);
  282.             font.DrawText(layout, rect.X + ((rect.Width - (float)Math.Ceiling(layout.Metrics.Width)) / 2.0f), rect.Y + ((rect.Height - layout.Metrics.Height) / 2));
  283.         }
  284.     }
  285. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement