Browse Source

init

tags/v0.0.1
anonymous 9 months ago
commit
1c28fa04d6
7 changed files with 24696 additions and 0 deletions
  1. +6
    -0
      Better.lua
  2. +10
    -0
      Better.toc
  3. +24223
    -0
      Items.lua
  4. +6
    -0
      Makefile
  5. +65
    -0
      extract.rb
  6. +204
    -0
      main.fnl
  7. +182
    -0
      main.lua

+ 6
- 0
Better.lua View File

@@ -0,0 +1,6 @@
-- slash command /better as addon entrypoint
SLASH_BETTER1 = "/better"
SlashCmdList["BETTER"] = function(msg)
main(msg)
end


+ 10
- 0
Better.toc View File

@@ -0,0 +1,10 @@
## Interface: 20400
## Title: Better
## Notes: Shows better item for given slot
## Author: L
## Version: 0.0.1

Items.lua

main.lua
Better.lua

+ 24223
- 0
Items.lua
File diff suppressed because it is too large
View File


+ 6
- 0
Makefile View File

@@ -0,0 +1,6 @@
#!make

.PHONY: default

default:
fennel --compile main.fnl > main.lua

+ 65
- 0
extract.rb View File

@@ -0,0 +1,65 @@
#!/usr/bin/ruby

require 'sqlite3'
require 'json'

db = SQLite3::Database.open '/tmp/tbc.db'
db.results_as_hash = true

items = db.execute 'select i.entry, i.class, i.subclass, i.name, i.inventorytype, i.itemlevel, i.requiredlevel, i.dmg_min1, i.dmg_max1, "" as mobs, delay, %s from item_template i;' % [(1..10).to_a.map { |n| "stat_type#{n} as k#{n}, stat_value#{n} as v#{n}" }.join(', ')]

total = items.length

items_w_loot = []
keys = (1..10).map { |n| "k#{n}" }
vals = (1..10).map { |n| "v#{n}" }

skip_keys = keys + ['delay', 'mobs']

def truncate(s, len)
s.length > len ? "#{s[0...len]}..." : s
end

items.each_with_index do |item, idx|
mobs = db.execute 'select c.name as name, cl.ChanceOrQuestChance as chance from creature_loot_template cl left join creature_template c on c.entry=cl.entry where cl.item=%d order by chance desc' % [item['entry']]

new = []

item.each_pair do |k, v|
if skip_keys.include?(k) or vals.include?(k)
next
end

new.push k
new.push v
end
new.push 'mobs'
new.push(truncate ((mobs.map {|m| m['name']}.join ',') or ""), 300)

(0..56).each do |type|
val = 0
keys.each_with_index do |k, kidx|
if item[k] == type
val = item[vals[kidx]]
end
end

new.push val
end

if item['delay']
new.push item['delay']
end

if idx % 100 == 0
print "\r%f%%" % [(idx * 100).to_f / total]
end

if idx > 50
# break
end

File.write(File.join(Dir.home, 'items_w_loot.json'), (new.to_json.concat ",\n"), mode: 'a+')
end

+ 204
- 0
main.fnl View File

@@ -0,0 +1,204 @@
;; coll utils

(fn length-of [coll]
(if coll
(do
(var c 0)
(each [k (pairs coll)]
(set c (+ c 1)))
c)
0))

(fn first [coll]
(let [key (next coll)]
(. coll key)))

;; str utils

(fn starts-with [s patt]
(= (string.sub s 1 (string.len patt)) patt))

(fn un-quote [s]
(string.gsub s "\'" ""))

;; lang utils

(fn matches [a b]
(if (starts-with a "lte:")
(>= (tonumber (string.sub a 5)) (tonumber b))

(starts-with a "gte:")
(<= (tonumber (string.sub a 5)) (tonumber b))

(= a b)))

;; querying

(lambda find-items [params ?sort]
(let [results (icollect [_ row (ipairs items)]
(do
(var hit true)
(each [key param (pairs params)]
(do
(set hit (and hit (matches param (. row key))))))
(if hit
row)))]
(if (and ?sort results)
(do
(table.sort results ?sort)
results)
results)))

(lambda find-item [params ?sort]
(let [results (find-items params ?sort)]
(if results
(first results))))

;; specialized querying

(fn find-item-by-name [name]
(find-item {8 name}))

(fn find-next-better-item [class subclass invtype lv ilv stat-position item-stat ?sort]
(find-items {4 class
6 subclass
10 invtype
14 (string.format "lte:%d" lv)
14 (string.format "gte:%d" (- lv 4))
;; 12 (string.format "gte:%d" ilv)
stat-position (string.format "gte:%d" item-stat)}
?sort))
(lambda find-good-item [invtype lv stat-position stat-baseline ?sort]
(find-items {10 invtype
14 (string.format "lte:%d" lv)
14 (string.format "gte:%d" (- lv 6))
stat-position (string.format "gte:%d" stat-baseline)}
?sort))

;; arg parsing

(fn parse-opts [msg]
(icollect [k v (string.gmatch msg "%w+")] v))

;; ui

(fn ui-print [msg]
(UIErrorsFrame:AddMessage msg))

(fn stat-name [n]
(let [stat-names ["Mana" "Health" "No Visible Effect"
"Agility" "Strength" "Intellect"
"Spirit" "Stamina" "No Visible Effect" "No Visible Effect"

"No Visible Effect" "No Visible Effect*" "Defense Rating"
"Dodge" "Parry Rating" "Shield Block Rating"
"Melee Hit Rating" "Ranged Hit Rating" "Spell Hit Rating"

"Melee Critical Strike" "Ranged Critical Strike" "Spell Critical Strike"
"Melee Hit Avoidance" "Ranged Hit Avoidance" "Spell Hit Avoidance"
"Melee Critical Avoidance" "Spell Critical Avoidance" "Melee Haste Rating"

"Ranged Haste Rating" "Spell Haste Rating" "Hit Avoidance Rating"
"Hit Rating" "Critical Strike" "Hit Avoidance Rating"

"Critical Avoidance Rating" "Resilience" "Haste"
"Expertise" "Attack Power" "Ranged Attack Power"
"No Visible Effect" "Healing Done By Magical Spells and Effects up to value" "Damage Done By Magical Spells and Effects up to value"

"Mana Regeneration (Ticks every 5 seconds)" "Armor Penetration Rating" "Spell Power"
"Health Regeneration (Ticks every 5 seconds)" "Spell Penetration" "Block Value of Shield"
"Mastery" "Armor" "Fire Resist"

"Frost Resist" "Shadow Resist" "Nature Resist"
"Arcane Resist"]]
(.. (. stat-names (+ n 1)) " (" n ")")))

(fn stat-print [item]
(var val "")
(for [n 22 56]
(if (< 0 (. item n))
(set val (.. val " " (stat-name (- n 21)) ": " (. item n)))))
val)

;; main

(global
main
(fn main [msg]
(let [opts (icollect [v (string.gmatch msg "%w+")] v)
[slot stat gear-index] opts

slot (.. slot "Slot") ;; omit the need to type it out
stat (+ 21 (tonumber stat)) ;; stats start after field 21, so agility (3) is 22+3, etc
gear-index (tonumber (or gear-index "1"))

inv-slot (GetInventorySlotInfo slot)
i-link (GetInventoryItemLink "player" inv-slot)

p-level (UnitLevel "player")]
;; (print (string.format "slot %s stat %s gear-index %s" slot stat gear-index))
(if (not i-link)
;; empty
(let [best (. (find-good-item inv-slot (UnitLevel "player") stat 0 (fn [a b] (< (. a 12) (. b 12)))) gear-index)]
(if best
(do
(ui-print (.. "next best available: "
(. best 8)
" "
(stat-print best)
" at "
(or (. best 20)) "N/A")))))

;; exists
(let [i-name (GetItemInfo i-link)
stats (find-item-by-name (un-quote i-name))]

(if stats
(let [i-class (. stats 4)
i-subclass (. stats 6)
i-invtype (. stats 10)
i-level (. stats 12)
i-stat (. stats stat)
best (. (find-next-better-item i-class i-subclass i-invtype p-level i-level stat i-stat (fn [a b] (< (. a stat) (. b stat)))) gear-index)]
(if best
(do
(ui-print (.. "next best available: "
(. best 8)
" "
(stat-print best)
" at "
(or (. best 20)) "N/A"))
(ui-print (.. "currently equipped " i-name " " (or (. stats stat) "N/A")))))))
"ok")))))
(fn maxxed []
(let [slots ["AmmoSlot"
"BackSlot"
"Bag0Slot"
"Bag1Slot"
"Bag2Slot"
"Bag3Slot"
"ChestSlot"
"FeetSlot"
"Finger0Slot"
"Finger1Slot"
"HandsSlot"
"HeadSlot"
"LegsSlot"
"MainHandSlot"
"NeckSlot"
"RangedSlot"
"SecondaryHandSlot"
"ShirtSlot"
"ShoulderSlot"
"TabardSlot"
"Trinket0Slot"
"Trinket1Slot"
"WaistSlot"
"WristSlot"]]
slots))

+ 182
- 0
main.lua View File

@@ -0,0 +1,182 @@
local function length_of(coll)
if coll then
local c = 0
for k in pairs(coll) do
c = (c + 1)
end
return c
else
return 0
end
end
local function first(coll)
local key = next(coll)
return coll[key]
end
local function starts_with(s, patt)
return (string.sub(s, 1, string.len(patt)) == patt)
end
local function un_quote(s)
return string.gsub(s, "'", "")
end
local function matches(a, b)
if starts_with(a, "lte:") then
return (tonumber(string.sub(a, 5)) >= tonumber(b))
elseif starts_with(a, "gte:") then
return (tonumber(string.sub(a, 5)) <= tonumber(b))
else
return (a == b)
end
end
local function find_items(params, _3fsort)
_G.assert((nil ~= params), "Missing argument params on main.fnl:37")
local results
do
local tbl_17_auto = {}
local i_18_auto = #tbl_17_auto
for _, row in ipairs(items) do
local val_19_auto
do
local hit = true
for key, param in pairs(params) do
hit = (hit and matches(param, row[key]))
end
if hit then
val_19_auto = row
else
val_19_auto = nil
end
end
if (nil ~= val_19_auto) then
i_18_auto = (i_18_auto + 1)
do end (tbl_17_auto)[i_18_auto] = val_19_auto
else
end
end
results = tbl_17_auto
end
if (_3fsort and results) then
table.sort(results, _3fsort)
return results
else
return results
end
end
local function find_item(params, _3fsort)
_G.assert((nil ~= params), "Missing argument params on main.fnl:52")
local results = find_items(params, _3fsort)
if results then
return first(results)
else
return nil
end
end
local function find_item_by_name(name)
return find_item({[8] = name})
end
local function find_next_better_item(class, subclass, invtype, lv, ilv, stat_position, item_stat, _3fsort)
return find_items({[4] = class, [6] = subclass, [10] = invtype, [14] = string.format("gte:%d", (lv - 4)), [stat_position] = string.format("gte:%d", item_stat)}, _3fsort)
end
local function find_good_item(invtype, lv, stat_position, stat_baseline, _3fsort)
_G.assert((nil ~= stat_baseline), "Missing argument stat-baseline on main.fnl:72")
_G.assert((nil ~= stat_position), "Missing argument stat-position on main.fnl:72")
_G.assert((nil ~= lv), "Missing argument lv on main.fnl:72")
_G.assert((nil ~= invtype), "Missing argument invtype on main.fnl:72")
return find_items({[10] = invtype, [14] = string.format("gte:%d", (lv - 6)), [stat_position] = string.format("gte:%d", stat_baseline)}, _3fsort)
end
local function parse_opts(msg)
local tbl_17_auto = {}
local i_18_auto = #tbl_17_auto
for k, v in string.gmatch(msg, "%w+") do
local val_19_auto = v
if (nil ~= val_19_auto) then
i_18_auto = (i_18_auto + 1)
do end (tbl_17_auto)[i_18_auto] = val_19_auto
else
end
end
return tbl_17_auto
end
local function ui_print(msg)
return UIErrorsFrame:AddMessage(msg)
end
local function stat_name(n)
local stat_names = {"Mana", "Health", "No Visible Effect", "Agility", "Strength", "Intellect", "Spirit", "Stamina", "No Visible Effect", "No Visible Effect", "No Visible Effect", "No Visible Effect*", "Defense Rating", "Dodge", "Parry Rating", "Shield Block Rating", "Melee Hit Rating", "Ranged Hit Rating", "Spell Hit Rating", "Melee Critical Strike", "Ranged Critical Strike", "Spell Critical Strike", "Melee Hit Avoidance", "Ranged Hit Avoidance", "Spell Hit Avoidance", "Melee Critical Avoidance", "Spell Critical Avoidance", "Melee Haste Rating", "Ranged Haste Rating", "Spell Haste Rating", "Hit Avoidance Rating", "Hit Rating", "Critical Strike", "Hit Avoidance Rating", "Critical Avoidance Rating", "Resilience", "Haste", "Expertise", "Attack Power", "Ranged Attack Power", "No Visible Effect", "Healing Done By Magical Spells and Effects up to value", "Damage Done By Magical Spells and Effects up to value", "Mana Regeneration (Ticks every 5 seconds)", "Armor Penetration Rating", "Spell Power", "Health Regeneration (Ticks every 5 seconds)", "Spell Penetration", "Block Value of Shield", "Mastery", "Armor", "Fire Resist", "Frost Resist", "Shadow Resist", "Nature Resist", "Arcane Resist"}
return (stat_names[(n + 1)] .. " (" .. n .. ")")
end
local function stat_print(item)
local val = ""
for n = 22, 56 do
if (0 < item[n]) then
val = (val .. " " .. stat_name((n - 21)) .. ": " .. item[n])
else
end
end
return val
end
local function main0(msg)
local opts
do
local tbl_17_auto = {}
local i_18_auto = #tbl_17_auto
for v in string.gmatch(msg, "%w+") do
local val_19_auto = v
if (nil ~= val_19_auto) then
i_18_auto = (i_18_auto + 1)
do end (tbl_17_auto)[i_18_auto] = val_19_auto
else
end
end
opts = tbl_17_auto
end
local _let_10_ = opts
local slot = _let_10_[1]
local stat = _let_10_[2]
local gear_index = _let_10_[3]
local slot0 = (slot .. "Slot")
local stat0 = (21 + tonumber(stat))
local gear_index0 = tonumber((gear_index or "1"))
local inv_slot = GetInventorySlotInfo(slot0)
local i_link = GetInventoryItemLink("player", inv_slot)
local p_level = UnitLevel("player")
if not i_link then
local best
local function _11_(a, b)
return (a[12] < b[12])
end
best = (find_good_item(inv_slot, UnitLevel("player"), stat0, 0, _11_))[gear_index0]
if best then
return ui_print(("next best available: " .. best[8] .. " " .. stat_print(best) .. " at " .. best[20] .. "N/A"))
else
return nil
end
else
local i_name = GetItemInfo(i_link)
local stats = find_item_by_name(un_quote(i_name))
if stats then
local i_class = stats[4]
local i_subclass = stats[6]
local i_invtype = stats[10]
local i_level = stats[12]
local i_stat = stats[stat0]
local best
local function _13_(a, b)
return (a[stat0] < b[stat0])
end
best = (find_next_better_item(i_class, i_subclass, i_invtype, p_level, i_level, stat0, i_stat, _13_))[gear_index0]
if best then
ui_print(("next best available: " .. best[8] .. " " .. stat_print(best) .. " at " .. best[20] .. "N/A"))
ui_print(("currently equipped " .. i_name .. " " .. (stats[stat0] or "N/A")))
else
end
else
end
return "ok"
end
end
main = main0
local function maxxed()
local slots = {"AmmoSlot", "BackSlot", "Bag0Slot", "Bag1Slot", "Bag2Slot", "Bag3Slot", "ChestSlot", "FeetSlot", "Finger0Slot", "Finger1Slot", "HandsSlot", "HeadSlot", "LegsSlot", "MainHandSlot", "NeckSlot", "RangedSlot", "SecondaryHandSlot", "ShirtSlot", "ShoulderSlot", "TabardSlot", "Trinket0Slot", "Trinket1Slot", "WaistSlot", "WristSlot"}
return slots
end
return maxxed

Loading…
Cancel
Save