diff --git a/tbc/items.go b/tbc/items.go index 31f0599..ae44d9d 100644 --- a/tbc/items.go +++ b/tbc/items.go @@ -324,6 +324,7 @@ func NewEquipmentSet(equipSpec EquipmentSpec) Equipment { const ( SubslotUnknown byte = iota SubslotShield + SubslotTwoHand ) // slot consts @@ -531,16 +532,16 @@ var items = []Item{ {ID: 27910, Slot: EquipOffhand, SubSlot: SubslotShield, Name: "Silvermoon Crest Shield", Phase: 1, Quality: ItemQualityRare, SourceZone: "SLabs - Murmur", SourceDrop: "", Stats: Stats{20, 0, 0, 0, 23, 0, 5}}, {ID: 30984, Slot: EquipOffhand, SubSlot: SubslotShield, Name: "Spellbreaker's Buckler", Phase: 1, Quality: ItemQualityRare, SourceZone: "Akama's Promise - SMV Quest", SourceDrop: "", Stats: Stats{10, 22, 0, 0, 29, 0, 0}}, {ID: 27534, Slot: EquipOffhand, Name: "Hortus' Seal of Brilliance", Phase: 1, Quality: ItemQualityRare, SourceZone: "SH - Warchief Kargath Bladefist", SourceDrop: "", Stats: Stats{20, 18, 0, 0, 23, 0, 0}}, - {ID: 29355, Slot: EquipWeapon, Name: "Terokk's Shadowstaff", Phase: 1, Quality: ItemQualityEpic, SourceZone: "H SH - Talon King Ikiss", SourceDrop: "", Stats: Stats{42, 40, 37, 0, 168, 0, 0}}, - {ID: 29130, Slot: EquipWeapon, Name: "Auchenai Staff", Phase: 1, Quality: ItemQualityRare, SourceZone: "The Aldor - Revered", SourceDrop: "", Stats: Stats{46, 0, 26, 19, 121, 0, 0}}, - {ID: 28341, Slot: EquipWeapon, Name: "Warpstaff of Arcanum", Phase: 1, Quality: ItemQualityRare, SourceZone: "Bot - Warp Splinter", SourceDrop: "", Stats: Stats{38, 37, 26, 16, 121, 0, 0}}, - {ID: 31308, Slot: EquipWeapon, Name: "The Bringer of Death", Phase: 1, Quality: ItemQualityRare, SourceZone: "BoE World Drop", SourceDrop: "", Stats: Stats{31, 32, 42, 0, 121, 0, 0}}, - {ID: 28188, Slot: EquipWeapon, Name: "Bloodfire Greatstaff", Phase: 1, Quality: ItemQualityRare, SourceZone: "BM - Aeonus", SourceDrop: "", Stats: Stats{42, 42, 28, 0, 121, 0, 0}}, - {ID: 30011, Slot: EquipWeapon, Name: "Ameer's Impulse Taser", Phase: 1, Quality: ItemQualityRare, SourceZone: "Nexus-King Salhadaar - Netherstorm Quest", SourceDrop: "", Stats: Stats{27, 27, 27, 17, 103, 0, 0}}, - {ID: 27842, Slot: EquipWeapon, Name: "Grand Scepter of the Nexus-Kings", Phase: 1, Quality: ItemQualityRare, SourceZone: "H MT - Nexus-Prince Shaffar", SourceDrop: "", Stats: Stats{43, 45, 0, 19, 121, 0, 0}}, + {ID: 29355, Slot: EquipWeapon, SubSlot: SubslotTwoHand, Name: "Terokk's Shadowstaff", Phase: 1, Quality: ItemQualityEpic, SourceZone: "H SH - Talon King Ikiss", SourceDrop: "", Stats: Stats{42, 40, 37, 0, 168, 0, 0}}, + {ID: 29130, Slot: EquipWeapon, SubSlot: SubslotTwoHand, Name: "Auchenai Staff", Phase: 1, Quality: ItemQualityRare, SourceZone: "The Aldor - Revered", SourceDrop: "", Stats: Stats{46, 0, 26, 19, 121, 0, 0}}, + {ID: 28341, Slot: EquipWeapon, SubSlot: SubslotTwoHand, Name: "Warpstaff of Arcanum", Phase: 1, Quality: ItemQualityRare, SourceZone: "Bot - Warp Splinter", SourceDrop: "", Stats: Stats{38, 37, 26, 16, 121, 0, 0}}, + {ID: 31308, Slot: EquipWeapon, SubSlot: SubslotTwoHand, Name: "The Bringer of Death", Phase: 1, Quality: ItemQualityRare, SourceZone: "BoE World Drop", SourceDrop: "", Stats: Stats{31, 32, 42, 0, 121, 0, 0}}, + {ID: 28188, Slot: EquipWeapon, SubSlot: SubslotTwoHand, Name: "Bloodfire Greatstaff", Phase: 1, Quality: ItemQualityRare, SourceZone: "BM - Aeonus", SourceDrop: "", Stats: Stats{42, 42, 28, 0, 121, 0, 0}}, + {ID: 30011, Slot: EquipWeapon, SubSlot: SubslotTwoHand, Name: "Ameer's Impulse Taser", Phase: 1, Quality: ItemQualityRare, SourceZone: "Nexus-King Salhadaar - Netherstorm Quest", SourceDrop: "", Stats: Stats{27, 27, 27, 17, 103, 0, 0}}, + {ID: 27842, Slot: EquipWeapon, SubSlot: SubslotTwoHand, Name: "Grand Scepter of the Nexus-Kings", Phase: 1, Quality: ItemQualityRare, SourceZone: "H MT - Nexus-Prince Shaffar", SourceDrop: "", Stats: Stats{43, 45, 0, 19, 121, 0, 0}}, {ID: 28346, Slot: EquipOffhand, Name: "Gladiator's Endgame", Phase: 1, Quality: ItemQualityEpic, SourceZone: "Arena Season 1 Reward", SourceDrop: "", Stats: Stats{14, 21, 0, 0, 19, 0, 0}}, - {ID: 24557, Slot: EquipWeapon, Name: "Gladiator's War Staff", Phase: 1, Quality: ItemQualityEpic, SourceZone: "Arena Season 1 Reward", SourceDrop: "", Stats: Stats{35, 48, 36, 21, 199, 0, 0}}, + {ID: 24557, Slot: EquipWeapon, SubSlot: SubslotTwoHand, Name: "Gladiator's War Staff", Phase: 1, Quality: ItemQualityEpic, SourceZone: "Arena Season 1 Reward", SourceDrop: "", Stats: Stats{35, 48, 36, 21, 199, 0, 0}}, {ID: 29389, Slot: EquipTotem, Name: "Totem of the Pulsing Earth", Phase: 1, Quality: ItemQualityEpic, SourceZone: "15 Badge of Justice - G'eras", SourceDrop: "", Stats: Stats{0, 0, 0, 0, 0, 0, 0}, Activate: ActivateTotemOfPulsingEarth, ActivateCD: neverExpires}, // {Slot: EquipTotem, Name: "Totem of Impact", Phase: 1, Quality: ItemQualityRare, SourceZone: "15 Mark of Thrallmar/ Honor Hold", SourceDrop: "", Stats: Stats{0, 0, 0, 0, 0, 0, 0}}, @@ -651,9 +652,9 @@ var items = []Item{ {ID: 30723, Slot: EquipWeapon, Name: "Talon of the Tempest", Phase: 1, Quality: ItemQualityEpic, SourceZone: "World Boss", SourceDrop: "Doomwalker", Stats: Stats{StatStm: 0, StatInt: 10, StatSpellDmg: 194, StatSpellCrit: 19, StatSpellHit: 9}, GemSlots: []GemColor{GemColorYellow, GemColorYellow}, SocketBonus: Stats{StatInt: 3}}, {ID: 34009, Slot: EquipWeapon, Name: "Hammer of Judgement", Phase: 3, Quality: ItemQualityEpic, SourceZone: "Hyjal", SourceDrop: "Trash", Stats: Stats{StatStm: 33, StatInt: 22, StatSpellDmg: 236, StatSpellHit: 22}}, {ID: 32237, Slot: EquipWeapon, Name: "The Maelstrom's Fury", Phase: 3, Quality: ItemQualityEpic, SourceZone: "BT", SourceDrop: "Najentus", Stats: Stats{StatStm: 33, StatInt: 21, StatSpellDmg: 236, StatSpellCrit: 22}}, - {ID: 28633, Slot: EquipWeapon, Name: "Staff of Infinite Mysteries", Phase: 1, Quality: ItemQualityEpic, SourceZone: "Kara", SourceDrop: "Curator", Stats: Stats{StatStm: 61, StatInt: 51, StatSpellDmg: 185, StatSpellHit: 23}}, - {ID: 29988, Slot: EquipWeapon, Name: "The Nexus Key", Phase: 2, Quality: ItemQualityEpic, SourceZone: "TK", SourceDrop: "Kaelthas", Stats: Stats{StatStm: 76, StatInt: 52, StatSpellDmg: 236, StatSpellCrit: 51}}, - {ID: 32374, Slot: EquipWeapon, Name: "Zhar'doom, Greatstaff of the Devourer", Phase: 3, Quality: ItemQualityEpic, SourceZone: "BT", SourceDrop: "Illidan", Stats: Stats{StatStm: 70, StatInt: 47, StatSpellDmg: 259, StatHaste: 55, StatSpellCrit: 36}}, + {ID: 28633, Slot: EquipWeapon, SubSlot: SubslotTwoHand, Name: "Staff of Infinite Mysteries", Phase: 1, Quality: ItemQualityEpic, SourceZone: "Kara", SourceDrop: "Curator", Stats: Stats{StatStm: 61, StatInt: 51, StatSpellDmg: 185, StatSpellHit: 23}}, + {ID: 29988, Slot: EquipWeapon, SubSlot: SubslotTwoHand, Name: "The Nexus Key", Phase: 2, Quality: ItemQualityEpic, SourceZone: "TK", SourceDrop: "Kaelthas", Stats: Stats{StatStm: 76, StatInt: 52, StatSpellDmg: 236, StatSpellCrit: 51}}, + {ID: 32374, Slot: EquipWeapon, SubSlot: SubslotTwoHand, Name: "Zhar'doom, Greatstaff of the Devourer", Phase: 3, Quality: ItemQualityEpic, SourceZone: "BT", SourceDrop: "Illidan", Stats: Stats{StatStm: 70, StatInt: 47, StatSpellDmg: 259, StatHaste: 55, StatSpellCrit: 36}}, {ID: 28734, Slot: EquipOffhand, Name: "Jewel of Infinite Possibilities", Phase: 1, Quality: ItemQualityEpic, SourceZone: "Kara", SourceDrop: "Netherspite", Stats: Stats{StatStm: 19, StatInt: 18, StatSpellDmg: 23, StatSpellHit: 21}}, {ID: 28611, Slot: EquipOffhand, SubSlot: SubslotShield, Name: "Dragonheart Flameshield", Phase: 1, Quality: ItemQualityEpic, SourceZone: "Kara", SourceDrop: "Nightbane", Stats: Stats{StatStm: 19, StatInt: 33, StatSpellDmg: 23, StatMP5: 7}}, {ID: 34011, Slot: EquipOffhand, SubSlot: SubslotShield, Name: "Illidari Runeshield", Phase: 3, Quality: ItemQualityEpic, SourceZone: "BT", SourceDrop: "Trash", Stats: Stats{StatStm: 45, StatInt: 39, StatSpellDmg: 34}}, diff --git a/ui/components/gear.js b/ui/components/gear.js index 0bb51e7..9fd35ce 100644 --- a/ui/components/gear.js +++ b/ui/components/gear.js @@ -80,6 +80,13 @@ class GearUI { item.Enchant = null; item.Gems = null; this.currentGear[slot] = item; + + // If the item is a 2h, remove any offhand that is currently equipped. + if (item.subSlot == 2 && this.currentGear["equipoffhand"] != null) { + this.currentGear["equipoffhand"] = null; + this.itemCompSlots["equipoffhand"].updateEquipped(null); + } + itemComp.updateEquipped(item); } else if (change.gem != null) { if (this.currentGear[slot].Gems == null) { diff --git a/ui/components/selector.js b/ui/components/selector.js index 6d15e48..f8a75f2 100644 --- a/ui/components/selector.js +++ b/ui/components/selector.js @@ -603,7 +603,6 @@ function itemQualityCssClass(itemQuality) { return 'qualityUncommon'; case 2: return 'qualityRare'; - this.name.style.color = "#589BE1" case 3: return 'qualityEpic'; case 4: diff --git a/ui/index.html b/ui/index.html index 5431810..747e1ca 100644 --- a/ui/index.html +++ b/ui/index.html @@ -244,7 +244,7 @@

Standard Elemental Build

- +
@@ -255,7 +255,7 @@

Standard Elemental Build

- + @@ -264,7 +264,7 @@

Standard Elemental Build

- + @@ -273,8 +273,44 @@

Standard Elemental Build

Dmg MP5
Mean WeightWeight 0 0 0 0
90% Confidence Weight Range90% Conf - 0 0 0
- -
+
+
+ +
+
+ +
+
  • @@ -290,13 +326,13 @@

    Standard Elemental Build

                             
  • - +
    - v1.1.14 + v1.1.15
    diff --git a/ui/lib.wasm b/ui/lib.wasm index 78d9320..86900bb 100755 Binary files a/ui/lib.wasm and b/ui/lib.wasm differ diff --git a/ui/ui.js b/ui/ui.js index d0d797c..7bdada7 100644 --- a/ui/ui.js +++ b/ui/ui.js @@ -650,55 +650,80 @@ function showGearRecommendations(weights) { if (curEquip != null && curEquip.Name == item.Name) { curSlotWeights[item.Slot] = itemEP; } - itemWeightsBySlot[item.Slot].push({ Name: item.Name, Weight: itemEP }); + itemWeightsBySlot[item.Slot].push({ Name: item.Name, Weight: itemEP, ID: item.ID }); itemWeightsBySlot[item.Slot] = itemWeightsBySlot[item.Slot].sort((a, b) => b.Weight - a.Weight); }); - var uptab = document.getElementById("upgrades"); - uptab.innerHTML = ""; - - var curSlot = -1; + let curSlot = -1; + let slotTable; + let simFuncs = {}; Object.entries(itemWeightsBySlot).forEach((entry) => { if (entry[0] == 14) { // Skip trinkets for now. Trinkets will be separate return; } if (curSlot != entry[0]) { - var row = document.createElement("tr"); - var col1 = document.createElement("td"); - slotToID[entry[0]].replace("equip", ""); - var title = slotToID[entry[0]].replace("equip", ""); - col1.innerHTML = "

    " + title.charAt(0).toUpperCase() + title.substr(1) + "

    "; - - var col2 = document.createElement("td"); - var col3 = document.createElement("td"); - row.appendChild(col1); - row.appendChild(col2); - row.appendChild(col3); - uptab.appendChild(row); + slotTable = document.getElementById("up" + slotToID[entry[0]].replace("equip", "")); + slotTable.innerHTML = ""; // clear table so we can regen. + simFuncs[entry[0]] = []; + + const simAllRow = document.createElement("tr"); + simAllRow.appendChild(document.createElement("td")); + simAllRow.appendChild(document.createElement("td")); + simAllRow.appendChild(document.createElement("td")); + const lastCol = document.createElement("td"); + lastCol.style.float = "right"; + const simAllButton = document.createElement("button"); + simAllButton.innerText = "Sim All"; + simAllButton.onclick = (e) => { + simFuncs[entry[0]].forEach((f) => { + f(); + }); + }; + lastCol.appendChild(simAllButton); + simAllRow.appendChild(lastCol); + slotTable.appendChild(simAllRow); curSlot = entry[0]; } + // get current item slot. - var alt = 0; + let alt = 0; entry[1].forEach((v) => { alt++; - var row = document.createElement("tr"); + const row = document.createElement("tr"); if (alt % 2 == 0) { row.style.backgroundColor = "#808080"; } - var col1 = document.createElement("td"); - col1.innerText = v.Name; - var col2 = document.createElement("td"); - col2.innerText = Math.round(v.Weight - curSlotWeights[curSlot]); - var col3 = document.createElement("td"); - var col4 = document.createElement("td"); - var simbut = document.createElement("button"); + const col1 = document.createElement("td"); + const nameLink = document.createElement("a"); + nameLink.setAttribute("href", "https://tbc.wowhead.com/item=" + v.ID); + nameLink.innerText = v.Name; + col1.appendChild(nameLink); + + const col2 = document.createElement("td"); + const eptext = document.createElement("text"); + eptext.innerText = Math.round(v.Weight); + const epdifftext = document.createElement("text"); + const diff = Math.round(v.Weight - curSlotWeights[entry[0]]); + epdifftext.innerText = " (" + diff + ")"; + if (diff > 0) { + epdifftext.style.color = "green"; + } else if (diff < 0) { + epdifftext.style.color = "red"; + } + col2.appendChild(eptext); + col2.appendChild(epdifftext); + + + const col3 = document.createElement("td"); + const col4 = document.createElement("td"); + const simbut = document.createElement("button"); simbut.innerText = "Sim"; - var item = Object.assign({ Name: "" }, gearUI.allitems[v.Name]); - simbut.addEventListener("click", (e) => { + const item = Object.assign({ Name: "" }, gearUI.allitems[v.Name]); + let simfunc = (e) => { col4.innerHTML = "
    "; - var newgear = {}; - var slotID = slotToID[item.Slot]; + const newgear = {}; + const slotID = slotToID[item.Slot]; if (slotID == "equipfinger") { slotID = "equipfinger1"; // hardcode finger 1 replacement. } @@ -717,7 +742,11 @@ function showGearRecommendations(weights) { }); } item.Enchant = entry[1].Enchant; - } else { + } else if (entry[0] == "equipoffhand" && item.subSlot == 2 ) { + // If the item is a 2h and the piece of gear to copy is an offhand, dont include it. + return; + } + else { newgear[entry[0]] = entry[1]; } }); @@ -734,13 +763,15 @@ function showGearRecommendations(weights) { workerPool.runSimulation(simRequest).then(simResult => { col4.innerText = Math.round(simResult.DpsAvg).toString() + " +/- " + Math.round(simResult.DpsStDev).toString(); }); - }); + } + simFuncs[curSlot].push(simfunc); + simbut.addEventListener("click", simfunc); col3.appendChild(simbut); row.appendChild(col1); row.appendChild(col2); row.appendChild(col3); row.appendChild(col4); - uptab.appendChild(row); + slotTable.appendChild(row); }) }); } diff --git a/web.go b/web.go index 307b7ab..44c1369 100644 --- a/web.go +++ b/web.go @@ -63,7 +63,7 @@ func main() { var err error if *useFS { // read file straight off disk - uijs, err = ioutil.ReadFile("favicon.ico") + uijs, err = ioutil.ReadFile("ui/favicon.ico") } else { uijs, err = uifs.ReadFile("ui/favicon.ico") // modify so that simworker is replaced with networker.