using System; using System.Collections.Generic; using System.Drawing; using System.IO; using IOPath = System.IO.Path; using Decal.Adapter; using Decal.Adapter.Wrappers; using Decal.Filters; namespace SpellbarSaver { [MyClasses.MetaViewWrappers.MVView("SpellbarSaver.MainView.xml")] [MyClasses.MetaViewWrappers.MVWireUpControlEvents] public partial class PluginCore : PluginBase { private const int AegisRedIcon = 0x060018DC; private static string[] msRomanNumerals = { "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X" }; private static Dictionary msRomanToInt = new Dictionary(StringComparer.OrdinalIgnoreCase); static PluginCore() { for (int i = 0; i < msRomanNumerals.Length; i++) { msRomanToInt[msRomanNumerals[i]] = i + 1; } } private class SpellSchools { public const int War = 1, Life = 2, Item = 3, Creature = 4; } #region Control References #pragma warning disable 649 [MyClasses.MetaViewWrappers.MVControlReference("nbkTabs")] private MyClasses.MetaViewWrappers.INotebook nbkTabs; private static class SpellList { public const int Icon = 0, Name = 1, SpellId = 2, OrigSpellId = 3; } private static class SpellListColors { public static readonly Color Yellow = Util.ColorRgb(0xEEDD44); public static readonly Color Green = Util.ColorRgb(0x33DD11); public static readonly Color RedGray = Util.ColorRgb(0xCC9999); } [MyClasses.MetaViewWrappers.MVControlReferenceArray("lst1", "lst2", "lst3", "lst4", "lst5", "lst6", "lst7")] private MyClasses.MetaViewWrappers.IList[] lstSpells; [MyClasses.MetaViewWrappers.MVControlReference("choLoad")] private MyClasses.MetaViewWrappers.ICombo choLoad; [MyClasses.MetaViewWrappers.MVControlReference("edtSaveAs")] private MyClasses.MetaViewWrappers.ITextBox edtSaveAs; [MyClasses.MetaViewWrappers.MVControlReference("chkReplCrit")] private MyClasses.MetaViewWrappers.ICheckBox chkReplCrit; [MyClasses.MetaViewWrappers.MVControlReference("choLowCrit")] private MyClasses.MetaViewWrappers.ICombo choLowCrit; [MyClasses.MetaViewWrappers.MVControlReference("choHighCrit")] private MyClasses.MetaViewWrappers.ICombo choHighCrit; [MyClasses.MetaViewWrappers.MVControlReference("chkReplLife")] private MyClasses.MetaViewWrappers.ICheckBox chkReplLife; [MyClasses.MetaViewWrappers.MVControlReference("choLowLife")] private MyClasses.MetaViewWrappers.ICombo choLowLife; [MyClasses.MetaViewWrappers.MVControlReference("choHighLife")] private MyClasses.MetaViewWrappers.ICombo choHighLife; [MyClasses.MetaViewWrappers.MVControlReference("chkReplItem")] private MyClasses.MetaViewWrappers.ICheckBox chkReplItem; [MyClasses.MetaViewWrappers.MVControlReference("choLowItem")] private MyClasses.MetaViewWrappers.ICombo choLowItem; [MyClasses.MetaViewWrappers.MVControlReference("choHighItem")] private MyClasses.MetaViewWrappers.ICombo choHighItem; [MyClasses.MetaViewWrappers.MVControlReference("chkReplWar")] private MyClasses.MetaViewWrappers.ICheckBox chkReplWar; [MyClasses.MetaViewWrappers.MVControlReference("choLowWar")] private MyClasses.MetaViewWrappers.ICombo choLowWar; [MyClasses.MetaViewWrappers.MVControlReference("choHighWar")] private MyClasses.MetaViewWrappers.ICombo choHighWar; [MyClasses.MetaViewWrappers.MVControlReference("chkOnlyReplUnknown")] private MyClasses.MetaViewWrappers.ICheckBox chkOnlyReplUnknown; [MyClasses.MetaViewWrappers.MVControlReference("edtToTab")] private MyClasses.MetaViewWrappers.ITextBox edtToTab; [MyClasses.MetaViewWrappers.MVControlReference("chkShowAsSaved")] private MyClasses.MetaViewWrappers.ICheckBox chkShowAsSaved; [MyClasses.MetaViewWrappers.MVControlReference("chkShowAsLoaded")] private MyClasses.MetaViewWrappers.ICheckBox chkShowAsLoaded; [MyClasses.MetaViewWrappers.MVControlReference("chkAutoBackup")] private MyClasses.MetaViewWrappers.ICheckBox chkAutoBackup; [MyClasses.MetaViewWrappers.MVControlReference("txtTitle")] private MyClasses.MetaViewWrappers.IStaticText txtTitle; #pragma warning restore 649 #endregion private void MainView_InitializeBeforeSettings() { txtTitle.Text = Util.PluginNameVer + " by Digero of Leafcull"; choLoad.Clear(); choLoad.Add("", null); choLoad.Selected = 0; } private void MainView_InitializeAfterSettings() { DirectoryInfo spellbarDir = new DirectoryInfo(Util.FullPath("Spellbars")); if (!spellbarDir.Exists) { spellbarDir.Create(); } else { SortedDictionary profiles = new SortedDictionary(StringComparer.OrdinalIgnoreCase); foreach (FileInfo file in spellbarDir.GetFiles()) { if (file.Name.EndsWith(".xml", StringComparison.OrdinalIgnoreCase)) { string profileName = file.Name.Substring(0, file.Name.Length - 4); profiles[profileName] = file.FullName; } } foreach (KeyValuePair namePath in profiles) { choLoad.Add(namePath.Key, namePath.Value); } } edtSaveAs.Text = Core.CharacterFilter.Name; } private void MainView_Dispose() { } private bool IsDisplayingCurrentChar { get { return choLoad.Selected == 0; } } private string ToRomanNumeral(int i) { if (i >= 1 && i <= msRomanNumerals.Length) return msRomanNumerals[i - 1]; return i.ToString(); } private bool TryParseRomanNumeral(string romanNumeral, out int i) { return msRomanToInt.TryGetValue(romanNumeral.Trim(), out i) || int.TryParse(romanNumeral, out i); } private void DisplaySpellTabs(List[] spellTabs) { for (int t = 0; t < spellTabs.Length; t++) { lstSpells[t].Clear(); if (spellTabs[t].Count == 0) { InsertEmptyTabRow(lstSpells[t]); } else { for (int i = 0; i < spellTabs[t].Count; i++) { InsertSpellRow(lstSpells[t], i, spellTabs[t][i]); } } } } private bool IsEmptyTab(MyClasses.MetaViewWrappers.IList tab) { return tab.RowCount == 0 || (tab.RowCount == 1 && (string)tab[0][SpellList.Name][0] == EmptyTabString); } private void InsertEmptyTabRow(MyClasses.MetaViewWrappers.IList tab) { MyClasses.MetaViewWrappers.IListRow row = tab.Add(); row[SpellList.Icon][1] = AegisRedIcon; row[SpellList.Name][0] = EmptyTabString; row[SpellList.SpellId][0] = "-1"; row[SpellList.OrigSpellId][0] = "-1"; } private void InsertSpellRow(MyClasses.MetaViewWrappers.IList tab, int index, Spell spell) { MyClasses.MetaViewWrappers.IListRow row = (index >= tab.RowCount) ? tab.Add() : tab.Insert(index); UpdateSpellRow(row, index, spell); } private void RefreshSpellTabs() { for (int t = 0; t < lstSpells.Length; t++) { if (!IsEmptyTab(lstSpells[t])) { for (int r = 0; r < lstSpells[t].RowCount; r++) { UpdateSpellRow(lstSpells[t][r], r); } } } } private void UpdateSpellRow(MyClasses.MetaViewWrappers.IListRow row, int index) { int origSpellId = int.Parse((string)row[SpellList.OrigSpellId][0]); Spell origSpell = mFS.SpellTable.GetById(origSpellId); UpdateSpellRow(row, index, origSpell); } private void UpdateSpellRow(MyClasses.MetaViewWrappers.IListRow row, int index, Spell spell) { Color rowColor = Color.White; if (!Core.CharacterFilter.IsSpellKnown(spell.Id)) { rowColor = SpellListColors.RedGray; } bool replace; int minLevel, maxLevel; switch (spell.School.Id) { case SpellSchools.Creature: replace = chkReplCrit.Checked; minLevel = choLowCrit.Selected + 1; maxLevel = choHighCrit.Selected + 1; break; case SpellSchools.Item: replace = chkReplItem.Checked; minLevel = choLowItem.Selected + 1; maxLevel = choHighItem.Selected + 1; break; case SpellSchools.Life: replace = chkReplLife.Checked; minLevel = choLowLife.Selected + 1; maxLevel = choHighLife.Selected + 1; break; case SpellSchools.War: replace = chkReplWar.Checked; minLevel = choLowWar.Selected + 1; maxLevel = choHighWar.Selected + 1; break; default: throw new Exception("Unknown spell school: " + spell.School.Name + " (ID: " + spell.School.Id + ")"); } // Search for the highest level spell known in the group int curLevel = 0; int bestSpellId = spell.Id, bestLevel = minLevel; int displayIcon = spell.IconId; string displayName = spell.Name; if (!IsDisplayingCurrentChar && replace && (!Core.CharacterFilter.IsSpellKnown(spell.Id) || !chkOnlyReplUnknown.Checked)) { List group; if (SpellIdToGroup.TryGetValue(spell.Id, out group)) { foreach (SpellAndLevel sl in group) { if (spell.Id == sl.SpellId) { curLevel = sl.Level; if (curLevel < minLevel) { // Don't upgrade if the current spell is lower than the min level bestSpellId = spell.Id; break; } } if (Core.CharacterFilter.IsSpellKnown(sl.SpellId) && sl.Level >= bestLevel && sl.Level <= maxLevel) { bestSpellId = sl.SpellId; bestLevel = sl.Level; } } if (bestSpellId != spell.Id) { if (bestLevel < curLevel) { rowColor = SpellListColors.Yellow; } else if (bestLevel > curLevel) { rowColor = SpellListColors.Green; } else if (bestLevel == curLevel) { // The rare case where they may know a spell such as // Dark Flame, but not Flame Bolt V rowColor = Color.White; } if (chkShowAsLoaded.Checked) { Spell tmp = mFS.SpellTable.GetById(bestSpellId); displayIcon = tmp.IconId; displayName = tmp.Name; } } } } row[SpellList.Icon][1] = displayIcon; row[SpellList.Name][0] = "(" + (index + 1) + ") " + displayName; row[SpellList.Name].Color = rowColor; row[SpellList.SpellId][0] = bestSpellId.ToString(); row[SpellList.OrigSpellId][0] = spell.Id.ToString(); } [MyClasses.MetaViewWrappers.MVControlEvent("nbkTabs", "Change")] private void nbkTabs_Change(object sender, MyClasses.MetaViewWrappers.MVIndexChangeEventArgs e) { try { edtToTab.Text = ToRomanNumeral(e.Index + 1); } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("lst1", "Selected")] [MyClasses.MetaViewWrappers.MVControlEvent("lst2", "Selected")] [MyClasses.MetaViewWrappers.MVControlEvent("lst3", "Selected")] [MyClasses.MetaViewWrappers.MVControlEvent("lst4", "Selected")] [MyClasses.MetaViewWrappers.MVControlEvent("lst5", "Selected")] [MyClasses.MetaViewWrappers.MVControlEvent("lst6", "Selected")] [MyClasses.MetaViewWrappers.MVControlEvent("lst7", "Selected")] private void lstSpells_Selected(object sender, MyClasses.MetaViewWrappers.MVListSelectEventArgs e) { try { } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("choLoad", "Change")] private void choLoad_Change(object sender, MyClasses.MetaViewWrappers.MVIndexChangeEventArgs e) { try { if (mSettingsLoaded && e.Index >= 0) { if (IsDisplayingCurrentChar) { DisplaySpellTabs(mSpellTabs); } else { DisplaySpellTabs(LoadTabsXml(choLoad.Text[choLoad.Selected])); } } } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("btnDelete", "Click")] private void btnDelete_Click(object sender, MyClasses.MetaViewWrappers.MVControlEventArgs e) { try { string profileName = choLoad.Text[choLoad.Selected]; if (IsDisplayingCurrentChar) { Util.Warning("You can't delete the profile."); } else if (!Util.IsControlDown()) { Util.Warning("Please hold down CTRL and click Delete to delete the " + profileName + " profile."); } else { File.Delete(Util.FullPath(@"Spellbars\" + profileName + ".xml")); Util.Message("Profile " + profileName + " deleted."); int curSel = choLoad.Selected; choLoad.Selected = 0; choLoad.Remove(curSel); } } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("btnSave", "Click")] private void btnSave_Click(object sender, MyClasses.MetaViewWrappers.MVControlEventArgs e) { try { string profileName = edtSaveAs.Text; char[] invalidChars = IOPath.GetInvalidFileNameChars(); foreach (char invalid in invalidChars) { if (profileName.Contains(invalid.ToString())) { string err = "The profile name can't contain any of the following characters:"; foreach (char invalid2 in invalidChars) { err += " " + invalid2; } Util.Error(err); return; } } SaveTabsXml(mSpellTabs, profileName, false); } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("chkReplCrit", "Change")] private void chkReplCrit_Change(object sender, MyClasses.MetaViewWrappers.MVCheckBoxChangeEventArgs e) { try { RefreshSpellTabs(); } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("choLowCrit", "Change")] private void choLowCrit_Change(object sender, MyClasses.MetaViewWrappers.MVIndexChangeEventArgs e) { try { if (chkReplCrit.Checked) { RefreshSpellTabs(); } } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("choHighCrit", "Change")] private void choHighCrit_Change(object sender, MyClasses.MetaViewWrappers.MVIndexChangeEventArgs e) { try { if (chkReplCrit.Checked) { RefreshSpellTabs(); } } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("chkReplLife", "Change")] private void chkReplLife_Change(object sender, MyClasses.MetaViewWrappers.MVCheckBoxChangeEventArgs e) { try { RefreshSpellTabs(); } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("choLowLife", "Change")] private void choLowLife_Change(object sender, MyClasses.MetaViewWrappers.MVIndexChangeEventArgs e) { try { if (chkReplLife.Checked) { RefreshSpellTabs(); } } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("choHighLife", "Change")] private void choHighLife_Change(object sender, MyClasses.MetaViewWrappers.MVIndexChangeEventArgs e) { try { if (chkReplLife.Checked) { RefreshSpellTabs(); } } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("chkReplItem", "Change")] private void chkReplItem_Change(object sender, MyClasses.MetaViewWrappers.MVCheckBoxChangeEventArgs e) { try { RefreshSpellTabs(); } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("choLowItem", "Change")] private void choLowItem_Change(object sender, MyClasses.MetaViewWrappers.MVIndexChangeEventArgs e) { try { if (chkReplItem.Checked) { RefreshSpellTabs(); } } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("choHighItem", "Change")] private void choHighItem_Change(object sender, MyClasses.MetaViewWrappers.MVIndexChangeEventArgs e) { try { if (chkReplItem.Checked) { RefreshSpellTabs(); } } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("chkReplWar", "Change")] private void chkReplWar_Change(object sender, MyClasses.MetaViewWrappers.MVCheckBoxChangeEventArgs e) { try { RefreshSpellTabs(); } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("choLowWar", "Change")] private void choLowWar_Change(object sender, MyClasses.MetaViewWrappers.MVIndexChangeEventArgs e) { try { if (chkReplWar.Checked) { RefreshSpellTabs(); } } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("choHighWar", "Change")] private void choHighWar_Change(object sender, MyClasses.MetaViewWrappers.MVIndexChangeEventArgs e) { try { if (chkReplWar.Checked) { RefreshSpellTabs(); } } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("chkOnlyReplUnknown", "Change")] private void chkOnlyReplUnknown_Change(object sender, MyClasses.MetaViewWrappers.MVCheckBoxChangeEventArgs e) { try { RefreshSpellTabs(); } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("btnLoadAll", "Click")] private void btnLoadAll_Click(object sender, MyClasses.MetaViewWrappers.MVControlEventArgs e) { try { if (IsDisplayingCurrentChar) { Util.Warning("You can't load the profile, that's what's already on your spellbars"); return; } if (chkAutoBackup.Checked) { SaveTabsXml(mSpellTabs, Core.CharacterFilter.Name + "-backup", true); } for (int t = 0; t < NumSpellTabs; t++) { LoadBar(t, t); } } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("edtToTab", "End")] private void edtToTab_End(object sender, MyClasses.MetaViewWrappers.MVTextBoxEndEventArgs e) { try { int tab; if (TryParseRomanNumeral(edtToTab.Text, out tab) && tab >= 1 && tab <= NumSpellTabs) { edtToTab.Text = ToRomanNumeral(tab); } else { tab = nbkTabs.ActiveTab + 1; Util.Error("Please enter a number or roman numeral betweeen I and " + ToRomanNumeral(NumSpellTabs) + "."); } edtToTab.Text = ToRomanNumeral(tab); } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("btnLoadCurTab", "Click")] private void btnLoadCurTab_Click(object sender, MyClasses.MetaViewWrappers.MVControlEventArgs e) { try { if (IsDisplayingCurrentChar) { Util.Warning("You can't load the profile, that's what's already on your spellbars"); return; } if (chkAutoBackup.Checked) { SaveTabsXml(mSpellTabs, Core.CharacterFilter.Name + "-backup", true); } int tab; if (TryParseRomanNumeral(edtToTab.Text, out tab) && tab >= 1 && tab <= NumSpellTabs) { LoadBar(nbkTabs.ActiveTab, tab - 1); } else { Util.Error("Invalid destination tab. Must be a number or roman numeral betweeen I and " + ToRomanNumeral(NumSpellTabs) + "."); } } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("chkShowAsSaved", "Change")] private void chkShowAsSaved_Change(object sender, MyClasses.MetaViewWrappers.MVCheckBoxChangeEventArgs e) { try { chkShowAsLoaded.Checked = !e.Checked; RefreshSpellTabs(); } catch (Exception ex) { Util.HandleException(ex); } } [MyClasses.MetaViewWrappers.MVControlEvent("chkShowAsLoaded", "Change")] private void chkShowAsLoaded_Change(object sender, MyClasses.MetaViewWrappers.MVCheckBoxChangeEventArgs e) { try { chkShowAsSaved.Checked = !e.Checked; RefreshSpellTabs(); } catch (Exception ex) { Util.HandleException(ex); } } } }