Hello, I release here an AutoInterrupt plugin for TheNoobBot, you can also use it as SDK for your own plugins !
You will be able to load it using TheNoobBot (General Settings > Plugins Manager) in the next release of TheNoobBot that should go out in less than 12 hours from now.
You can see that I added a delay before kick, it really make it looks "leggit"/"by a real player" since it will interrupt at arround 20% of the cast bar.
Also, because the plugins system works out of the CombatClass, you can use it as standalone (run the bot without starting any product).
If you use it with a product (and then with CombatClass activated), it will even improve your kick possibility because most of the kicks works out of GCD, so CombatClass may miss some kicks the plugins will make sure to interrupt.
I will add "List of spells to don't interrupt (ignore)" for the update of the bot.
Code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using nManager.Helpful;
using nManager.Plugins;
using nManager.Wow.Class;
using nManager.Wow.Enums;
using nManager.Wow.ObjectManager;
#region Interface Implementation - Edition Expert only
public class Main : IPlugins
{
private bool _checkFieldRunning;
public bool Loop
{
get { return MyPluginClass.InternalLoop; }
set { MyPluginClass.InternalLoop = value; }
}
public string Name
{
get { return MyPluginClass.Name; }
}
public string Author
{
get { return MyPluginClass.Author; }
}
public string Description
{
get { return MyPluginClass.Description; }
}
public string TargetVersion
{
get { return MyPluginClass.TargetVersion; }
}
public string Version
{
get { return MyPluginClass.Version; }
}
public bool IsStarted
{
get { return Loop && !_checkFieldRunning; }
}
public void Dispose()
{
Loop = false;
}
public void Initialize()
{
Logging.WriteDebug(string.Format("The plugin {0} is loading.", Name));
Initialize(false);
}
public void ShowConfiguration()
{
MyPluginClass.ShowConfiguration();
}
public void ResetConfiguration()
{
MyPluginClass.ResetConfiguration();
}
public void CheckFields() // do not edit.
{
_checkFieldRunning = true;
Loop = true;
while (Loop)
{
Thread.Sleep(1000); // Don't do any action.
}
}
public void Initialize(bool configOnly, bool resetSettings = false)
{
try
{
if (!configOnly && !resetSettings)
Loop = true;
MyPluginClass.Init();
}
catch (Exception e)
{
Logging.WriteError("IPlugins.Main.Initialize(bool configOnly, bool resetSettings = false): " + e);
}
Logging.Write(string.Format("The plugin {0} has stopped.", Name));
}
}
#endregion
#region Plugin core - Your plugin should be coded here
public static class MyPluginClass
{
public static bool InternalLoop = true;
public static string Author = "Vesper";
public static string Name = "AutoInterrupt";
public static string TargetVersion = "3.0";
public static string Version = "1.0.2";
public static string Description = "Interrupt automatically when our target is casting or channeling a spell.";
private static readonly List<Spell> AvailableInterruptersPVP = new List<Spell>();
private static readonly List<Spell> AvailableInterruptersPve = new List<Spell>();
private static readonly MyPluginSettings MySettings = MyPluginSettings.GetSettings();
public static void Init()
{
GetAllAvailableInterrupters();
if (AvailableInterruptersPVP.Count <= 0 && AvailableInterruptersPve.Count <= 0)
{
Logging.WriteDebug(Name + ": No spell capable of interrupt has been found.");
return;
}
MainLoop();
}
public static void MainLoop()
{
while (InternalLoop)
{
CheckToInterrupt();
Thread.Sleep(1);
}
}
public static void CheckToInterrupt()
{
if (ObjectManager.Me.Target <= 0 || ObjectManager.Target.IsDead)
return;
if (ObjectManager.Target.Type == WoWObjectType.Player)
InterruptPVP();
if (ObjectManager.Target.Type == WoWObjectType.Unit)
InterruptPve();
}
public static bool IsTargetEnnemyPlayer()
{
if (ObjectManager.Target is WoWPlayer)
{
var p = ObjectManager.Target as WoWPlayer;
if (p.PlayerFaction != ObjectManager.Me.PlayerFaction)
return true;
}
return false;
}
public static void InterruptPVP()
{
if (!IsTargetEnnemyPlayer())
return;
if (ObjectManager.Target.CanInterruptCurrentCast && !IsSpellInIgnoreList())
{
var rnd = new Random();
int sleepTime = rnd.Next(100, 400);
Thread.Sleep(sleepTime); // Wait randomly between 70ms to 400ms before interrupt for account safety reason.
while (ObjectManager.Target.CanInterruptCurrentCast && !IsSpellInIgnoreList())
{
foreach (Spell kicker in AvailableInterruptersPVP)
{
if (ObjectManager.Target.GetDistance > kicker.MaxRangeHostile)
continue; // We are too far for this spell, try another one ASAP.
if (ObjectManager.Target.GetDistance < kicker.MinRangeFriend)
continue; // We are too close for this spell, try another one ASAP.
if (!kicker.IsSpellUsable)
continue; // This spell is on cooldown.
kicker.Launch();
Logging.Write(ObjectManager.Target.Name + " interrupted.");
}
}
}
}
public static void InterruptPve()
{
if (!ObjectManager.Target.InCombatWithMe)
return; // We don't wanna pull creatures.
if (ObjectManager.Target.CanInterruptCurrentCast && !IsSpellInIgnoreList())
{
var rnd = new Random();
int sleepTime = rnd.Next(100, 400);
Thread.Sleep(sleepTime); // Wait randomly between 70ms to 400ms before interrupt for account safety reason.
while (ObjectManager.Target.CanInterruptCurrentCast && !IsSpellInIgnoreList())
{
foreach (Spell kicker in AvailableInterruptersPve)
{
if (ObjectManager.Target.GetDistance > kicker.MaxRangeHostile)
continue; // We are too far for this spell, try another one ASAP.
if (ObjectManager.Target.GetDistance < kicker.MinRangeFriend)
continue; // We are too close for this spell, try another one ASAP.
if (!kicker.IsSpellUsable)
continue; // This spell is on cooldown.
kicker.Launch();
Logging.Write(ObjectManager.Target.Name + " interrupted.");
}
}
}
}
public static bool IsSpellInIgnoreList()
{
string[] spellListPVP = MySettings.DontInterruptSpellList.Split(',');
foreach (string sId in spellListPVP)
{
if (sId.Contains(ObjectManager.Target.CastingSpellId.ToString()))
{
return true;
}
}
return false;
}
public static void GetAllAvailableInterrupters()
{
string[] spellListPVP = MySettings.SpellListPVP.Split(',');
foreach (string sId in spellListPVP)
{
uint id = Others.ToUInt32(sId.Trim());
var spell = new Spell(id);
if (spell.Name != "" && spell.KnownSpell)
{
if (MySettings.ActivateInterruptPVP)
AvailableInterruptersPVP.Add(spell);
if (MySettings.ActivateInterruptPve)
AvailableInterruptersPve.Add(spell);
}
}
if (!MySettings.ActivateInterruptPve)
return;
string[] spellListPve = MySettings.SpellListPve.Split(',');
foreach (string sId in spellListPve)
{
uint id = Others.ToUInt32(sId.Trim());
var spell = new Spell(id);
if (spell.Name != "" && spell.KnownSpell)
{
AvailableInterruptersPve.Add(spell);
}
}
}
public static void ResetConfiguration()
{
string currentSettingsFile = Application.StartupPath + "\\Plugins\\Settings\\" + Name + ".xml";
var currentSetting = new MyPluginSettings();
currentSetting.ToForm();
currentSetting.Save(currentSettingsFile);
}
public static void ShowConfiguration()
{
string currentSettingsFile = Application.StartupPath + "\\Plugins\\Settings\\" + Name + ".xml";
var currentSetting = new MyPluginSettings();
if (File.Exists(currentSettingsFile))
{
currentSetting = Settings.Load<MyPluginSettings>(currentSettingsFile);
}
currentSetting.ToForm();
currentSetting.Save(currentSettingsFile);
}
[Serializable]
public class MyPluginSettings : Settings
{
public bool ActivateInterruptPVP = true;
public bool ActivateInterruptPve = true;
public string DontInterruptSpellList = "";
public string SpellListPVP = "106839, 78675, 147362, 34490, 2139, 116705, 31935, 96231, 1766, 57994, 19647, 115782, 6552, 47528";
public string SpellListPve = "15487, 47476";
public MyPluginSettings()
{
ConfigWinForm(Name + " Spells Management");
AddControlInWinForm("List of spells to not interrupt (ignore) :", "DontInterruptSpellList", Name + " Spells Management", "List");
AddControlInWinForm("Auto Interrupt in PVP", "ActivateInterruptPVP", Name + " Spells Management");
AddControlInWinForm("List of spells that can interrupt in PVP :", "SpellListPVP", Name + " Spells Management", "List");
AddControlInWinForm("Auto Interrupt in PVE", "ActivateInterruptPve", Name + " Spells Management");
AddControlInWinForm("List of spells that can only interrupt in PVE (will complete the PVP list in PVE) :", "SpellListPve", Name + " Spells Management", "List");
}
public static MyPluginSettings CurrentSetting { get; set; }
public static MyPluginSettings GetSettings()
{
string currentSettingsFile = Application.StartupPath + "\\Plugins\\Settings\\" + Name + ".xml";
if (File.Exists(currentSettingsFile))
{
return CurrentSetting = Load<MyPluginSettings>(currentSettingsFile);
}
return new MyPluginSettings();
}
}
}
#endregion
[F] 16:05:57 - Cast Rebuke
[S] 16:05:58 - Manifestation of Pride interrupted.
[F] 16:06:43 - Cast Rebuke
[S] 16:06:44 - Vestige of Pride interrupted.
[F] 16:07:11 - Cast Rebuke
[S] 16:07:11 - Vestige of Pride interrupted.
[F] 16:07:35 - Cast Rebuke
[S] 16:07:36 - Manifestation of Pride interrupted.
[F] 16:08:06 - Cast Rebuke
[S] 16:08:07 - Quid interrupted.
[F] 16:08:22 - Cast Rebuke
[S] 16:08:23 - Manifestation of Pride interrupted.