diff --git a/Bindings.xml b/Bindings.xml new file mode 100644 index 0000000..6d7d97e --- /dev/null +++ b/Bindings.xml @@ -0,0 +1,5 @@ + + + post_auctions_bind() + + \ No newline at end of file diff --git a/README_Geojak.md b/README_Geojak.md new file mode 100644 index 0000000..064b4ac --- /dev/null +++ b/README_Geojak.md @@ -0,0 +1,10 @@ +1. Added auto bid feature, doubled the existing auto buy code and slighly editted +2. Added auto pricing heuristic, these are activate when posting an item with bid price 0, the buyout price works as a minimum +3. Added a keybind for the post button, this significantly speeds up mass posting of items +4. Changed the default post stack size to rand(1,max) instead of always max +5. FIXED TWILLIGHT CULTIST SET NOT DISENCHATABLE +6. use SHagu tweaks vendor values if aux values not avaialbe +7. dont auto bid on own items +8. new filter disenchant-percent and bid-disencahnt-percent +9. enchanting created wands are not encahntabke, same with twillight stuff at 5. reworked implementation for easier addition +10. disenchant values are calcualted from min(value,value_today), this protects users from low enchanting mat prices \ No newline at end of file diff --git a/aux-addon.lua b/aux-addon.lua index e4c3790..b86e066 100644 --- a/aux-addon.lua +++ b/aux-addon.lua @@ -58,7 +58,7 @@ function handle.LOAD() ignore_owner = true, crafting_cost = true, post_bid = false, - post_duration = post.DURATION_8, + post_duration = post.DURATION_24, items = {}, item_ids = {}, auctionable_items = {}, diff --git a/aux-addon.toc b/aux-addon.toc index 82b078a..919f718 100644 --- a/aux-addon.toc +++ b/aux-addon.toc @@ -1,5 +1,6 @@ ## Interface: 11200 ## Author: shirsig +## OptionalDeps: ShaguTweaks ## Title: aux ## Notes: Auction House replacement ## SavedVariables: aux @@ -51,4 +52,6 @@ tabs\bids\frame.lua core\crafting.lua +localization.lua + diff --git a/core/crafting.lua b/core/crafting.lua index b00df11..6124f6e 100644 --- a/core/crafting.lua +++ b/core/crafting.lua @@ -89,7 +89,10 @@ do total_cost = total_cost + value * count end end - TradeSkillReagentLabel:SetText(SPELL_REAGENTS .. ' ' .. cost_label(total_cost)) + TradeSkillReagentLabel:SetText(SPELL_REAGENTS .. ' ' .. cost_label(total_cost)) + if ATSWReagentLabel then + ATSWReagentLabel:SetText(SPELL_REAGENTS .. ' ' .. cost_label(total_cost)) + end return unpack(ret) end) for i = 1, 8 do diff --git a/core/disenchant.lua b/core/disenchant.lua index 3d61dab..b6e5637 100644 --- a/core/disenchant.lua +++ b/core/disenchant.lua @@ -33,22 +33,32 @@ local WEAPON = T.set( 'INVTYPE_RANGEDRIGHT' ) -function M.value(slot, quality, level) +function M.value(slot, quality, level, item_id) local expectation - for _, event in distribution(slot, quality, level) do + for _, event in distribution(slot, quality, level, item_id) do local value = history.value(event.item_id .. ':' .. 0) - if not value then + if not value then return - else - expectation = (expectation or 0) + event.probability * (event.min_quantity + event.max_quantity) / 2 * value end + local market_value = history.market_value(event.item_id .. ':' .. 0) + if market_value then + value=min(value,market_value) + end + expectation = (expectation or 0) + event.probability * (event.min_quantity + event.max_quantity) / 2 * value end return expectation end -function M.distribution(slot, quality, level) +function M.distribution(slot, quality, level, item_id) if not ARMOR[slot] and not WEAPON[slot] or level == 0 then return T.acquire() + elseif --special items not following general rules + --twillight cultist items are not disenchantable + item_id==20408 or item_id==20407 or item_id==20406 + --enchanting created wands are not disenchantable + or item_id==11288 or item_id==11290 or item_id==11287 or item_id==11289 + then + return T.acquire() end local function p(probability_armor, probability_weapon) diff --git a/core/post.lua b/core/post.lua index b34c05b..0e8415f 100644 --- a/core/post.lua +++ b/core/post.lua @@ -3,6 +3,8 @@ module 'aux.core.post' local aux = require 'aux' local info = require 'aux.util.info' local stack = require 'aux.core.stack' +local history = require 'aux.core.history' +local disenchant = require 'aux.core.disenchant' local state @@ -41,8 +43,97 @@ function post_auction(slot, k) PickupContainerItem(unpack(slot)) ClickAuctionSellItemButton() ClearCursor() + + local start_price = state.unit_start_price + local buyout_price = state.unit_buyout_price + + --use autoprice heuristic if start bid 0 is set + if start_price == 0 then + + local kz_daily = 0 + local kz_pricing = 0 + local kz_warn = 0 + + if buyout_price > 0 then + kz_pricing=1 + start_price = buyout_price + end + + if history.market_value(state.item_key) ~= nil then + local tmp = tonumber(history.market_value(state.item_key)) + tmp = max(0.99*tmp,tmp-50) + buyout_price = max(buyout_price,tmp) + kz_daily = 1 + end + + if history.value(state.item_key) ~= nil then + if kz_pricing == 1 and kz_daily == 1 then + buyout_price = max(buyout_price,1.0*tonumber(history.value(state.item_key))) + elseif kz_daily == 1 then + start_price = max(start_price,0.91*tonumber(history.value(state.item_key))) + else + buyout_price = max(buyout_price,0.99* tonumber(history.value(state.item_key))) + end + else + kz_warn = kz_warn + 1 + end + + if disenchant.value(item_info.slot, item_info.quality, item_info.level, item_info.item_id) ~= nil then + start_price = max(start_price,0.85* tonumber(disenchant.value(item_info.slot, item_info.quality, item_info.level, item_info.item_id))) + end + + if aux.account_data.merchant_buy[item_info.item_id] ~= nil then + local tmp = tostring(aux.account_data.merchant_buy[item_info.item_id]) + tmp = strsub(tmp,1,-3) + start_price = max(start_price,tonumber(tmp) * 1.1) + buyout_price = max(buyout_price,tonumber(tmp) * 1.15) + else + local vendor_price = 0 + if aux.account_data.merchant_sell[item_info.item_id] ~= nil then + vendor_price = tonumber(aux.account_data.merchant_sell[item_info.item_id]) + elseif ShaguTweaks.SellValueDB[item_info.item_id] ~= nil then + local charges = 1 + if info.max_item_charges(item_info.item_id) ~= nil then + charges=info.max_item_charges(item_info.item_id) + end + vendor_price = ShaguTweaks.SellValueDB[item_info.item_id] / charges + end + if vendor_price > 0 then + if kz_daily == 0 then + start_price = max(start_price, vendor_price * (1.35+3.65*math.exp(-(1/4000)* vendor_price))) + else + start_price = max(start_price, vendor_price * 1.35) + end + else + kz_warn = kz_warn + 1 + end + end + + start_price = max(start_price,0.91 * buyout_price) + buyout_price = max(start_price, buyout_price) + + if kz_warn == 2 and kz_pricing == 0 then + print("WARNING, insufficient data for autopricing!") + if start_price == 0 then + return stop() + end + end + + local gold = floor(start_price / COPPER_PER_GOLD) + local silver = floor(mod(start_price, COPPER_PER_GOLD) / COPPER_PER_SILVER) + local copper = aux.round(mod(start_price, COPPER_PER_SILVER)) + + print("bid_price: "..gold.."g "..silver.."s "..copper.."c") + + gold = floor(buyout_price / COPPER_PER_GOLD) + silver = floor(mod(buyout_price, COPPER_PER_GOLD) / COPPER_PER_SILVER) + copper = aux.round(mod(buyout_price, COPPER_PER_SILVER)) + + print("buyout_price: "..gold.."g "..silver.."s "..copper.."c") - StartAuction(max(1, aux.round(state.unit_start_price * item_info.aux_quantity)), aux.round(state.unit_buyout_price * item_info.aux_quantity), state.duration) + end + + StartAuction(max(1, aux.round(start_price * item_info.aux_quantity)), aux.round(buyout_price * item_info.aux_quantity), state.duration) local send_signal, signal_received = aux.signal() aux.when(signal_received, function() diff --git a/core/scan.lua b/core/scan.lua index bab9f1a..7da6a61 100644 --- a/core/scan.lua +++ b/core/scan.lua @@ -146,8 +146,12 @@ function scan_page(i) auction_info.query_type = get_state().params.type history.process_auction(auction_info) - - if (get_state().params.auto_buy_validator or pass)(auction_info) then + + if (get_state().params.auto_bid_validator or pass)(auction_info) and auction_info.owner ~= UnitName("player") then + local send_signal, signal_received = aux.signal() + aux.when(signal_received, scan_page, i) + return aux.place_bid(auction_info.query_type, auction_info.index, auction_info.bid_price, send_signal) + elseif (get_state().params.auto_buy_validator or pass)(auction_info) and auction_info.owner ~= UnitName("player") then local send_signal, signal_received = aux.signal() aux.when(signal_received, scan_page, i) return aux.place_bid(auction_info.query_type, auction_info.index, auction_info.buyout_price, send_signal) diff --git a/core/tooltip.lua b/core/tooltip.lua index c43365b..353e893 100644 --- a/core/tooltip.lua +++ b/core/tooltip.lua @@ -54,7 +54,7 @@ function M.extend_tooltip(tooltip, link, quantity) quantity = IsShiftKeyDown() and quantity or 1 local item_info = T.temp-info.item(item_id) if item_info then - local distribution = disenchant.distribution(item_info.slot, item_info.quality, item_info.level) + local distribution = disenchant.distribution(item_info.slot, item_info.quality, item_info.level, item_id) if getn(distribution) > 0 then if settings.disenchant_distribution then tooltip:AddLine('Disenchants into:', aux.color.tooltip.disenchant.distribution()) @@ -64,7 +64,7 @@ function M.extend_tooltip(tooltip, link, quantity) end end if settings.disenchant_value then - local disenchant_value = disenchant.value(item_info.slot, item_info.quality, item_info.level) + local disenchant_value = disenchant.value(item_info.slot, item_info.quality, item_info.level, item_id) tooltip:AddLine('Disenchant: ' .. (disenchant_value and money.to_string2(disenchant_value) or UNKNOWN), aux.color.tooltip.disenchant.value()) end end @@ -77,6 +77,13 @@ function M.extend_tooltip(tooltip, link, quantity) end if settings.merchant_sell then local price = info.merchant_info(item_id) + if price == nil and ShaguTweaks.SellValueDB[item_id] ~= nil then + local charges = 1 + if info.max_item_charges(item_id) ~= nil then + charges=info.max_item_charges(item_id) + end + price = ShaguTweaks.SellValueDB[item_id] / charges + end if price ~= 0 then tooltip:AddLine('Vendor: ' .. (price and money.to_string2(price * quantity) or UNKNOWN), aux.color.tooltip.merchant()) end diff --git a/localization.lua b/localization.lua new file mode 100644 index 0000000..37e3b3a --- /dev/null +++ b/localization.lua @@ -0,0 +1,7 @@ +BINDING_HEADER_AUX = "aux"; + +local post = require 'aux.tabs.post' + +function post_auctions_bind() + post.post_auctions_bind() +end \ No newline at end of file diff --git a/tabs/post/core.lua b/tabs/post/core.lua index d749c5b..08a3581 100644 --- a/tabs/post/core.lua +++ b/tabs/post/core.lua @@ -248,6 +248,58 @@ function post_auctions() end end +function M.post_auctions_bind() + if selected_item then + local unit_start_price = get_unit_start_price() + local unit_buyout_price = get_unit_buyout_price() + local stack_size = stack_size_slider:GetValue() + local stack_count + stack_count = stack_count_slider:GetValue() + local duration = UIDropDownMenu_GetSelectedValue(duration_dropdown) + local key = selected_item.key + + local duration_code + if duration == DURATION_2 then + duration_code = 2 + elseif duration == DURATION_8 then + duration_code = 3 + elseif duration == DURATION_24 then + duration_code = 4 + end + + post.start( + key, + stack_size, + duration, + unit_start_price, + unit_buyout_price, + stack_count, + function(posted) + if not frame:IsShown() then + return + end + for i = 1, posted do + record_auction(key, stack_size, unit_start_price * stack_size, unit_buyout_price, duration_code, UnitName'player') + end + update_inventory_records() + local same + for _, record in inventory_records do + if record.key == key then + same = record + break + end + end + if same then + update_item(same) + else + selected_item = nil + end + refresh = true + end + ) + end +end + function validate_parameters() if not selected_item then post_button:Disable() @@ -258,7 +310,7 @@ function validate_parameters() return end if get_unit_start_price() == 0 then - post_button:Disable() + post_button:Enable() return end if stack_count_slider:GetValue() == 0 then @@ -379,18 +431,23 @@ function update_item(item) UIDropDownMenu_SetSelectedValue(duration_dropdown, settings.duration) hide_checkbox:SetChecked(settings.hidden) - + local ii = 1 if selected_item.max_charges then for i = selected_item.max_charges, 1, -1 do if selected_item.availability[i] > 0 then stack_size_slider:SetMinMaxValues(1, i) + ii=i break end end else + ii = min(selected_item.max_stack, selected_item.aux_quantity) stack_size_slider:SetMinMaxValues(1, min(selected_item.max_stack, selected_item.aux_quantity)) end - stack_size_slider:SetValue(aux.huge) + + stack_size_slider:SetValue(math.random(1,ii)) + --stack_size_slider:SetValue(aux.huge) + --stack_size_slider:SetValue(1) quantity_update(true) unit_start_price_input:SetText(money.to_string(settings.start_price, true, nil, nil, true)) diff --git a/tabs/search/filter.lua b/tabs/search/filter.lua index 44618bf..eaac271 100644 --- a/tabs/search/filter.lua +++ b/tabs/search/filter.lua @@ -323,7 +323,7 @@ function set_filter_display_offset(x_offset, y_offset) end function initialize_filter_dropdown() - for _, filter in ipairs(T.temp-T.list('and', 'or', 'not', 'price', 'profit', 'vendor-profit', 'disenchant-profit', 'percent', 'bid-price', 'bid-profit', 'bid-vendor-profit', 'bid-disenchant-profit', 'bid-percent', 'item', 'tooltip', 'min-level', 'max-level', 'rarity', 'left', 'utilizable', 'seller')) do + for _, filter in ipairs(T.temp-T.list('and', 'or', 'not', 'price', 'profit', 'vendor-profit', 'disenchant-profit', 'percent', 'disenchant-percent', 'bid-price', 'bid-profit', 'bid-vendor-profit', 'bid-disenchant-profit', 'bid-percent', 'bid-disenchant-percent', 'item', 'tooltip', 'min-level', 'max-level', 'rarity', 'left', 'utilizable', 'seller')) do UIDropDownMenu_AddButton(T.map( 'text', filter, 'value', filter, diff --git a/tabs/search/frame.lua b/tabs/search/frame.lua index d319b09..24a5d3a 100644 --- a/tabs/search/frame.lua +++ b/tabs/search/frame.lua @@ -547,7 +547,7 @@ for _ = 1, 5 do end favorite_searches_listing = listing.new(frame.saved.favorite) -favorite_searches_listing:SetColInfo{{name='Auto Buy', width=.07, align='CENTER'}, {name='Favorite Searches', width=.93}} +favorite_searches_listing:SetColInfo{{name='Auto', width=.07, align='CENTER'}, {name='Favorite Searches', width=.93}} recent_searches_listing = listing.new(frame.saved.recent) recent_searches_listing:SetColInfo{{name='Recent Searches', width=1}} diff --git a/tabs/search/results.lua b/tabs/search/results.lua index 48e85f2..6f9e863 100644 --- a/tabs/search/results.lua +++ b/tabs/search/results.lua @@ -151,6 +151,7 @@ function start_real_time_scan(query, search, continuation) type = 'list', queries = {query}, auto_buy_validator = search.auto_buy_validator, + auto_bid_validator = search.auto_bid_validator, on_scan_start = function() search.status_bar:update_status(.9999, .9999) search.status_bar:set_text('Scanning last page ...') @@ -227,6 +228,7 @@ function start_search(queries, continuation) type = 'list', queries = queries, auto_buy_validator = search.auto_buy_validator, + auto_bid_validator = search.auto_bid_validator, on_scan_start = function() search.status_bar:update_status(0, 0) if continuation then @@ -336,6 +338,7 @@ function M.execute(resume, real_time) search.last_page = last_page search.real_time = real_time search.auto_buy_validator = get_auto_buy_validator() + search.auto_bid_validator = get_auto_bid_validator() end local continuation = resume and current_search().continuation diff --git a/tabs/search/saved.lua b/tabs/search/saved.lua index b2043a0..8089e79 100644 --- a/tabs/search/saved.lua +++ b/tabs/search/saved.lua @@ -15,7 +15,7 @@ function update_search_listings() local search = favorite_searches[i] local name = strsub(search.prettified, 1, 250) tinsert(favorite_search_rows, T.map( - 'cols', T.list(T.map('value', search.auto_buy and aux.color.red'X' or ''), T.map('value', name)), + 'cols', T.list(T.map('value', search.auto_buy and aux.color.red'X' or search.auto_bid and aux.color.red'Y' or ''), T.map('value', name)), 'search', search, 'index', i )) @@ -68,8 +68,10 @@ handlers = { u(d) elseif st == favorite_searches_listing then local auto_buy = data.search.auto_buy + local auto_bid = data.search.auto_bid gui.menu( (auto_buy and 'Disable' or 'Enable') .. ' Auto Buy', function() if auto_buy then data.search.auto_buy = nil else enable_auto_buy(data.search) end u() end, + (auto_bid and 'Disable' or 'Enable') .. ' Auto Bid', function() if auto_bid then data.search.auto_bid = nil else enable_auto_bid(data.search) end u() end, 'Move Up', function() move_up(favorite_searches, data.index); u() end, 'Move Down', function() move_down(favorite_searches, data.index); u() end, 'Delete', function() tremove(favorite_searches, data.index); u() end @@ -106,6 +108,23 @@ function get_auto_buy_validator() end end +function get_auto_bid_validator() + local validators = T.acquire() + for _, search in favorite_searches do + if search.auto_bid then + local queries, error = filter_util.queries(search.filter_string) + if queries then + tinsert(validators, queries[1].validator) + else + aux.print('Invalid auto bid filter:', error) + end + end + end + return function(record) + return aux.any(validators, function(validator) return validator(record) end) + end +end + function add_favorite(filter_string) local queries, error = filter_util.queries(filter_string) if queries then @@ -134,6 +153,21 @@ function enable_auto_buy(search) end end +function enable_auto_bid(search) + local queries, error = filter_util.queries(search.filter_string) + if queries then + if getn(queries) > 1 then + aux.print('Error: Auto Bid does not support multi-queries') + elseif aux.size(queries[1].blizzard_query) > 0 and not filter_util.parse_filter_string(search.filter_string).blizzard.exact then + aux.print('Error: Auto Bid does not support Blizzard filters') + else + search.auto_bid = true + end + else + aux.print('Invalid filter:', error) + end +end + function move_up(list, index) if list[index - 1] then list[index], list[index - 1] = list[index - 1], list[index] diff --git a/util/filter.lua b/util/filter.lua index bb7092e..e997192 100644 --- a/util/filter.lua +++ b/util/filter.lua @@ -110,6 +110,16 @@ M.filters = { end end }, + + ['bid-disenchant-percent'] = { + input_type = 'number', + validator = function(pct) + return function(auction_record) + return disenchant.value(auction_record.slot, auction_record.quality, auction_record.level, auction_record.item_id) + and auction_record.unit_bid_price / disenchant.value(auction_record.slot, auction_record.quality, auction_record.level, auction_record.item_id) * 100 <= pct + end + end + }, ['percent'] = { input_type = 'number', @@ -121,6 +131,17 @@ M.filters = { end end }, + + ['disenchant-percent'] = { + input_type = 'number', + validator = function(pct) + return function(auction_record) + return auction_record.unit_buyout_price > 0 + and disenchant.value(auction_record.slot, auction_record.quality, auction_record.level, auction_record.item_id) + and auction_record.unit_buyout_price / disenchant.value(auction_record.slot, auction_record.quality, auction_record.level, auction_record.item_id) * 100 <= pct + end + end + }, ['bid-profit'] = { input_type = 'money', @@ -144,8 +165,8 @@ M.filters = { input_type = 'money', validator = function(amount) return function(auction_record) - local disenchant_value = disenchant.value(auction_record.slot, auction_record.quality, auction_record.level) - return disenchant_value and disenchant_value - auction_record.bid_price >= amount + local disenchant_value = disenchant.value(auction_record.slot, auction_record.quality, auction_record.level, auction_record.item_id) + return disenchant_value and disenchant_value - auction_record.bid_price >= amount end end }, @@ -154,8 +175,8 @@ M.filters = { input_type = 'money', validator = function(amount) return function(auction_record) - local disenchant_value = disenchant.value(auction_record.slot, auction_record.quality, auction_record.level) - return auction_record.buyout_price > 0 and disenchant_value and disenchant_value - auction_record.buyout_price >= amount + local disenchant_value = disenchant.value(auction_record.slot, auction_record.quality, auction_record.level, auction_record.item_id) + return auction_record.buyout_price > 0 and disenchant_value and disenchant_value - auction_record.buyout_price >= amount end end }, @@ -165,6 +186,16 @@ M.filters = { validator = function(amount) return function(auction_record) local vendor_price = info.merchant_info(auction_record.item_id) + if not vendor_price then + vendor_price = ShaguTweaks.SellValueDB[auction_record.item_id] + if vendor_price then + local charges = 1 + if info.max_item_charges(auction_record.item_id) ~= nil then + info.charges=info.max_item_charges(auction_record.item_id) + end + vendor_price= vendor_price/ charges + end + end return vendor_price and vendor_price * auction_record.aux_quantity - auction_record.bid_price >= amount end end @@ -175,6 +206,16 @@ M.filters = { validator = function(amount) return function(auction_record) local vendor_price = info.merchant_info(auction_record.item_id) + if not vendor_price then + vendor_price = ShaguTweaks.SellValueDB[auction_record.item_id] + if vendor_price then + local charges = 1 + if info.max_item_charges(auction_record.item_id) ~= nil then + info.charges=info.max_item_charges(auction_record.item_id) + end + vendor_price= vendor_price/ charges + end + end return auction_record.buyout_price > 0 and vendor_price and vendor_price * auction_record.aux_quantity - auction_record.buyout_price >= amount end end