/trunk
## Interface: 20300 |
## Author: Cogwheel |
## Title: BuyDropper |
## Version: 0.9B2-2.3 |
## Notes: Keeps you stocked with items from merchants or your bank. |
## X-Website: http://cogwheel.wowinterface.com |
## X-Category: Inventory |
## SavedVariables: BuyDropperDB |
## OptionalDeps: CogsBagSpace |
Ace2\Ace2.xml |
CogsBagSpace\CogsBagSpace.lua |
BuyDropper.lua |
BuyDropperEngine.lua |
BuyDropperOptions.lua |
BuyDropperConsole.lua |
BuyDropperQueue.lua |
BuyDropper.xml |
BUYDROPPER_PURCHASE_DELAY = 0.5 |
function BuyDropper:InitPurchaseQueue() |
self.queue = {} |
end |
function BuyDropper:QueuePurchase(index, priority) |
local item = self.list[priority] |
if not item.index then -- Items with indexes have already been added to the list |
item.priority = priority |
item.index = index |
tinsert(self.queue, item) |
end |
end |
function BuyDropper:ClearPurchaseQueue() |
for i = 1, #self.queue do |
local item = tremove(self.queue) |
item.index = nil |
item.priority = nil |
end |
self:CleanupPurchaseQueue() |
end |
function BuyDropper:CleanupPurchaseQueue() |
self.hasWaited = nil |
self:CancelScheduledEvent("BUYDROPPER_MERCHANT_WAIT") |
self:CancelScheduledEvent("BUYDROPPER_DO_PURCHASES") |
end |
function BuyDropper:ReleasePurchaseQueue() |
sort(self.queue, function(item1, item2) |
return item1.priority < item2.priority |
end) |
self:ScheduleRepeatingEvent("BUYDROPPER_DO_PURCHASES", function() |
self:PurchaseNextQueued() |
end, BUYDROPPER_PURCHASE_DELAY) |
end |
function BuyDropper:PurchaseNextQueued() |
if self.hasWaited then |
self.hasPurchased = true |
local item = tremove(self.queue, 1) |
if item then |
local didPurchase = self:PurchaseItem(item) |
item.index = nil |
item.priority = nil |
if not didPurchase then |
self:ClearPurchaseQueue() |
end |
else |
self:CleanupPurchaseQueue() |
end |
end |
end |
function BuyDropper:GetQueueCost() |
local cost = 0 |
for i, item in ipairs(self.queue) do |
local num = self:NumToBuy(item) |
cost = cost + (num * item.price) |
end |
return cost |
end |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
<html xmlns="http://www.w3.org/1999/xhtml"> |
<head> |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> |
<title>BuyDropper Readme</title> |
<style type="text/css"> |
h2,h3 { border-bottom: 1px solid; } |
a:visited:after { content: "Â â"; } |
p.notice { |
font-size: smaller; |
color: #999; |
} |
ol.footnotes { |
font-size: small; |
} |
.item { |
font-size: small; |
font-family: Arial, Helvetica, sans-serif; |
border: solid 1px; |
border-top-color: #FFF; |
border-left-color: #888; |
border-right-color: #888; |
border-bottom-color: #555; |
-moz-border-radius: 4px; |
background-color: #000; |
color: #FFF; |
padding: 2px; |
} |
.poor { color: gray; } |
.common { color: white; } |
.uncommon { color: #1EFF00; } |
.rare { color: #0080FF; } |
.epic { color: #B048F8; } |
.legendary { color: #F07902; } |
.artifact { color: #FFCF00; } |
.captionedImage { |
float: right; |
font-size: small; |
font-family: Arial, Helvetica, sans-serif; |
border: solid 1px; |
border-top-color: #FFF; |
border-left-color: #888; |
border-right-color: #888; |
border-bottom-color: #555; |
-moz-border-radius: 4px; |
background-color: #000; |
color: #FFF; |
padding: 2px; |
} |
.captionedImage div { |
text-align: center; |
} |
@media screen { |
body { |
font-family: "Trebuchet MS", Helvetica, Verdana, Arial, sans-serif; |
color: #FFF; |
background: #333; |
width: 80%; |
min-width: 600px; |
padding-left: 30px; |
} |
h1,h2,h3,h4,h5,h6 { |
font-family: Georgia, "Times New Roman", Times, serif; |
color: #ED0; |
} |
h1,h2,h3,h5,h6 { |
font-family: Georgia, "Times New Roman", Times, serif; |
} |
h2,h3 { border-bottom-color: #ED0; } |
p,h3,h4,h5,h6 { margin-left: 30px; } |
a:link { |
color: #FC0; |
text-decoration: none; |
} |
a:visited { |
color: #999; |
text-decoration: none; |
} |
a:hover { |
color: #0F0; |
} |
a:active { |
color: #0F0; |
} |
.gold { color: #ED0; } |
.silver { color: #BBB; } |
.copper { color: #D63; } |
} |
@media print { |
body { |
font-family: "Times New Roman", Times, serif; |
} |
h1,h2,h3,h4,h5,h6 { |
font-family: Arial, Helvetica, sans-serif; |
} |
} |
</style> |
</head> |
<body> |
<h1>BuyDropper</h1> |
<p>By Cogwheel â v0.9B2-2.3<br /> |
Inspired by FreeRefills by Kyahx </p> |
<p>BuyDropper keeps a list of items to purchase automatically from vendors.</p> |
<p>Please visit <a href="http://cogwheel.wowinterface.com">Cogwheelâs Workshop</a> for updates, bug reports, feature requests, etc. </p> |
<p class="notice">THE SOFTWARE IS PROVIDED âAS ISâ, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
THE SOFTWARE. </p> |
<ul> |
<li><a href="#guide">Guide</a> |
<ul> |
<li><a href="#managing">Managing your list |
</a> |
<ul> |
<li><a href="#adding">Adding items </a></li> |
</ul> |
</li> |
</ul> |
</li> |
<li><a href="#reference">Reference</a> |
<ul> |
<li><a href="#options">options</a></li> |
<li><a href="#add">add</a></li> |
<li><a href="#list">list</a></li> |
<li><a href="#change">change</a></li> |
<li><a href="#priority">priority</a></li> |
<li><a href="#remove">remove</a></li> |
<li><a href="#clear">clear</a> </li> |
<li><a href="#vendor">vendor</a> |
<ul> |
<li><a href="#vendortoggle">toggle</a></li> |
<li><a href="#confirm">confirm</a></li> |
<li><a href="#budget">budget</a></li> |
<li><a href="#fallthrough">fallthrough</a></li> |
</ul> |
</li> |
<li><a href="#bank">bank</a></li> |
<li><a href="#overstock">overstock</a></li> |
<li><a href="#dropper">dropper</a> |
<ul> |
<li><a href="#droppertoggle">toggle</a></li> |
<li><a href="#position">position</a></li> |
<li><a href="#label">label</a></li> |
</ul> |
</li> |
<li><a href="#profile">profile</a></li> |
<li><a href="#standby">standby</a></li> |
<li><a href="#about">about</a></li> |
</ul> |
</li> |
<li><a href="#bugs">Bugs/Improvements</a></li> |
<li><a href="#changes">Changes</a></li> |
</ul> |
<h2><a name="guide" id="guide"></a>Guide</h2> |
<h3><a name="managing" id="managing"></a>Managing your list</h3> |
<h4><a name="adding" id="adding"></a>Adding items </h4> |
<div class="captionedImage"><img src="images/dropper.jpg" alt="Picture of Dropper" width="156" height="138" /> |
<div>Dropper</div></div><p>The first thing youâll want to do is add an item to BuyDropperâs tracking list. This can be done in two easy ways. By default, every vendor window has a dropper in the upper right and there is also a dropper on BuyDropperâs options window. Simply drag and drop an item onto one of these droppers and a window will appear where you can enter the amount you want to track. When you click Accept or press Enter, BuyDropper will print a message showing the item and quantity added to the list.</p> |
<p>The other way to add items is the /buydropper add command. This duality of GUI/slash commands is seen throughout BuyDropperâs operations. For the rest of the guide, I will focus on the GUI aspects. You can use the Reference below to discover how to use the various commands.</p> |
<p style="color: #F00">[TODO: Rest of the documentation. For now, take a look at /buydropper options and the Reference below] </p> |
<h2><a name="reference" id="reference"></a>Reference</h2> |
<p>These are all the slash commands available from BuyDropper. Typing /buydropper (or /bd) will show this list of commands. Sub-commands are displayed when you enter the main command with no options. E.g. /buydropper vendor will display all the sub-commands of vendor. </p> |
<h3><a name="options" id="options"></a>options</h3> |
<p>Usage: /buydropper options</p> |
<p>Opens the BuyDropper options window. The options window provides support for most of the operations of the following slash commands. Any that are unique to the slash commands will be so noted.</p> |
<h3><a name="add" id="add"></a>add</h3> |
<p>Usage: /buydropper add <item link> <amount></p> |
<p>Adds an item to the bottom of your tracking list or changes the amount of an item you are already tracking. </p> |
<p>To use this command, type <kbd>/buydropper add</kbd> with a space after it. Now shift-click any item at a vendor, in your backpack, on your character, etc. Add another space, and type in the amount of the item you want to track. </p> |
<h3><a name="list" id="list"></a>list - slash command only (for now) </h3> |
<p>Usage: /buydropper list</p> |
<p>Lists the items you are currently tracking in order of descending priority.</p> |
<h3><a name="change" id="change"></a>change - slash command only (for now)</h3> |
<p>Usage: /buydropper change <priority> <amount></p> |
<p>Changes the tracking amount for the given item. priority is obtained from the list command. amount must be 1 or more. </p> |
<h3><a name="priority" id="priority"></a>priority - slash command only (for now) </h3> |
<p>Usage: /buydropper priority <current priority> <new priority></p> |
<p>Changes the priority of an item in your tracking list. current priority is obtained from the <a href="#list">list</a> command. new priority must be a number from 1 to the number of items you are tracking. The itemâs entry is removed from its current location and inserted at the new priority, shifting the item currently at that priority down the list.</p> |
<h3><a name="remove" id="remove"></a>remove - slash command only (for now) </h3> |
<p>Usage: /buydropper remove <priority></p> |
<p>Removes the item at the specified priority from your tracking list.</p> |
<h3><a name="clear" id="clear"></a>clear</h3> |
<p>Usage: /buydropper clear</p> |
<p>Clears all items from your list. A confirmation will appear to make sure you mean it. </p> |
<h3><a name="vendor" id="vendor"></a>vendor</h3> |
<p>Usage: /buydropper vendor <sub-command></p> |
<p>Sub-commands:</p> |
<h4><a name="vendortoggle" id="vendortoggle"></a>toggle</h4> |
<p>Usage: /buydropper vendor toggle<br /> |
Default: enabled </p> |
<p>Toggles whether vendors should be scanned for items you are tracking.</p> |
<h4><a name="confirm" id="confirm"></a>confirm </h4> |
<p>Usage: /buydropper vendor confirm <br /> |
Default: enabled </p> |
<p>Toggles whether to confirm purchases from vendors.</p> |
<h4><a name="budget" id="budget"></a>budget - slash command only (for now) </h4> |
<p>Usage: /buydropper vendor budget <number><br /> |
Default: 50 </p> |
<p>Sets your budget for automatic purchases from vendors. number must be from 1 to 100 and represents the percentage of your total money BuyDropper is allowed to use when purchasing a given item at a vendor. This is only applicable if the confirmation is turned off. </p> |
<h4><a name="fallthrough" id="fallthrough"></a>fallthrough - slash command only (for now) </h4> |
<p>Usage: /buydropper vendor fallthrough<br /> |
Default: disabled </p> |
<p>Toggles whether to continue purchasing lower-priority items when higher-priority items cannot be purchased for lack of space or money. </p> |
<h3><a name="bank" id="bank"></a>bank</h3> |
<p>Usage: /buydropper bank<br /> |
Default: enabled </p> |
<p>Toggles whether to withdraw items from the bank. Note: bank withdrawals are not yet implemented. </p> |
<h3><a name="overstock" id="overstock"></a>overstock</h3> |
<p>Usage: /buydropper overstock<br /> |
Default: disabled </p> |
<p>Toggles whether to overstock items that come in preset stacks like food or water. For example, say you are tracking <span class="item common">Ice Cold Milk</span> Ã 20 and you have 17 in your inventory and you open a vendor who sells <span class="item common">Ice Cold Milk</span>. With overstock enabled, you will buy a bundle of 5 to bring your total to 22.</p> |
<h3><a name="dropper" id="dropper"></a>dropper</h3> |
<p>Usage: /buydropper dropper <sub-command></p> |
<p>Sub-commands:</p> |
<h4><a name="droppertoggle" id="droppertoggle"></a>toggle</h4> |
<p>Usage: /buydropper dropper toggle<br /> |
Default: enabled |
</p> |
<p>Toggles whether to show the dropper in vendor windows. </p> |
<h4><a name="position" id="position"></a>position</h4> |
<p>Usage: /buydropper dropper position <number><br /> |
Default: 100 </p> |
<p>Sets the position of the dropper in vendor windows. number must be from 1 to 100 and represents the percentage from 0 in the far left to 100 in the far right. </p> |
<h4><a name="label" id="label"></a>label </h4> |
<p>Usage: /buydropper dropper label<br /> |
Default: enabled</p> |
<p>Toggles whether to show the label next to the dropper in vendor windows. </p> |
<h3><a name="profile" id="profile"></a>profile - slash command only </h3> |
<p>Usage: /buydropper profile <sub-command></p> |
<p>Sub-commands:</p> |
<h4><a name="choose" id="choose"></a>choose</h4> |
<p>Usage: /buydropper profile choose <name or shortcut><br /> |
Default: Character: <name> of <realm></p> |
<p>Chooses a pre-existing profile to use for BuyDropperâs settings. This is stored per-character so every character can use a particular profile. Using this command without providing a profile parameter will display a list of possible profiles to use. If you want to create a new profile, use the other sub-command.</p> |
<p>You can provide either the full name of the profile, e.g. Character: Cogwheel of Shadowsong or a shortcut. Possible shortcuts are char, realm, or class.</p> |
<h4><a name="other" id="other"></a>other</h4> |
<p>Usage: /buydropper profile other <name or shortcut><br /> |
Default: char</p> |
<p>Similar to the choose sub-command, but creates a profile if the name you specify does not exist.</p> |
<h4><a name="copy" id="copy"></a>copy</h4> |
<p>Usage: /buydropper profile copy <name or shortcut></p> |
<p>Copies the data from another profile into your currently active profile. Running this command without providing a profile will display a list of profiles from which you can choose.</p> |
<h3><a name="standby" id="standby"></a>standby - slash command only (for now)</h3> |
<p>Usage: /buydropper standby<br /> |
Default: enabled</p> |
<p>Turns BuyDropper on and off. When disabled, it will not do anything when you open a vendor or visit the bank.</p> |
<h3><a name="about" id="about"></a>about - slash command only</h3> |
<p>Usage: /buydropper about </p> |
<p>Displays some basic information about BuyDropper. </p> |
<h2><a name="bugs" id="bugs"></a>Bugs/Improvements</h2> |
<ul> |
<li>The GUI is not complete: |
<ul> |
<li> It does not support the Budget or Fallthrough vendor options.</li> |
<li>The tracking list is not functional (hence none of the tracking list controls are either).</li> |
</ul> |
</li> |
<li>BuyDropper does not yet withdraw items from the bank </li> |
</ul> |
<p>Please visit <a href="http://cogwheel.wowinterface.com">Cogwheelâs Workshop</a> if you have any suggestions or bug reports, and to see what is in store for the future.</p> |
<h2><a name="changes" id="changes"></a>Changes</h2> |
<h4>v0.9B2-2.3</h4> |
<ul> |
<li>Updated Ace libraries. You no longer need other Ace mods to use this. </li> |
</ul> |
<h4>v0.9B2</h4> |
<ul> |
<li>Fixed a bug where an error would occur when buying items if you do not have BuyEmAll installed.</li> |
</ul> |
<h4>v0.9B1</h4> |
<ul> |
<li>Purchasing is now enabled.</li> |
<li>Enabling BuyDropper while at a vendor will now scan the vendor.</li> |
<li>Uses the new GetCursorInfo API instead of hooking all the Pickup_____Item functions (PickupMerchantItem is still hooked because GetCursorInfo doesnât returns nil for merchant items).</li> |
<li>Fixed the bug where if an error occurs while buying an item it will no longer attempt to buy that item when you open the vendor again.</li> |
<li>Added /buydropper change command. </li> |
<li>Budget will now only affect purchases if the confirmation is turned off. </li> |
<li>Implemented the Clear List button in the options window.</li> |
<li>/buydropper clear no longer requires the âyesâ parameter. Instead it shows a confirmation dialog like the Clear List button in the options window.</li> |
<li>Fixed a validation bug for the /buydropper priority command.</li> |
</ul> |
<h4><a name="09A4" id="09A4"></a>v0.9A4</h4> |
<ul> |
<li>Added purchasing code. You must un comment the section starting on line 275 of BuyDropperEngine.lua in order to enable this functionality. </li> |
<li>No longer re scans a vendor from which youâve already purchased an item until your next visit.</li> |
<li>Added this readme</li> |
</ul> |
<h4>v0.9A3</h4> |
<ul> |
<li>Updated for 2.0.3.</li> |
</ul> |
<h4>v0.9A2</h4> |
<ul> |
<li>Fixed bug with CogsBagSpace.</li> |
</ul> |
<h4>v0.9A1</h4> |
<ul> |
<li>No longer requires FreeRefills.</li> |
<li>Added all slash commands and the GUI options window.</li> |
</ul> |
<h4>v0.3</h4> |
<ul> |
<li>Added commands to customize the vendor dropper.</li> |
<li>Updated Ace2 libraries.</li> |
</ul> |
<h4>v0.2</h4> |
<ul> |
<li>Entering 0 for the amount now removes the item from the list.</li> |
<li>Added tracking buttons.</li> |
</ul> |
<h4>v0.1</h4> |
<ul> |
<li>Initial Release.</li> |
</ul> |
</body> |
</html> |
BUYDROPPER_MERCHANT_DELAY = 1 |
--[[ |
Tracking List Methods |
]] |
function BuyDropper:AddTrackingItem(link, amount) |
local item = self:GetLinkItem(link) |
if not item then |
item = { id = self:ExtractItemID(link) } |
tinsert(self.list, item) |
self.idPriorityCache[item.id] = #self.list |
end |
item.amount = amount |
self:UpdateDisplays() |
if MerchantFrame:IsVisible() then |
for index, item in self:IterateTrackedMerchantItems() do |
self:UpdatePrice(index, item) |
end |
end |
self:Print("Added %s à %d", link, amount) |
end |
function BuyDropper:ChangeTrackingItem(priority, amount) |
local item = self.list[priority] |
local old = item.amount |
item.amount = amount |
self:UpdateDisplays() |
self:Print("Changed tracking amount of %s from %d to %d", self:MakeItemLink(item.id), old, amount) |
end |
function BuyDropper:RemoveTrackingItem(priority) |
local item = self:_RemoveTrackingItem(priority) |
if priority <= #self.list then |
self:UpdatePriorityCache() |
end |
self:UpdateDisplays() |
self:Print("Removed %s from tracking list", self:MakeItemLink(item.id)) |
end |
function BuyDropper:ClearTrackingList() |
for i = #self.list, 1, -1 do |
self:_RemoveTrackingItem(priority) |
end |
self:UpdateDisplays() |
self:Print("Tracking list cleared") |
end |
function BuyDropper:_RemoveTrackingItem(priority) |
local item = tremove(self.list, priority) |
self.idPriorityCache[item.id] = nil |
return item |
end |
function BuyDropper:SetTrackingPriority(current, new) |
tinsert(self.list, new, tremove(self.list, current)) |
self:UpdatePriorityCache() |
self:UpdateDisplays() |
self:Print("Changed priority on %s from %d to %d", self:MakeItemLink(self.list[new].id), current, new) |
end |
function BuyDropper:GetLinkItem(link) |
local id = self:ExtractItemID(link) |
local priority = self.idPriorityCache[id] |
return self.list[priority], priority |
end |
function BuyDropper:UpdatePriorityCache() |
for priority, item in ipairs(self.list) do |
self.idPriorityCache[item.id] = priority |
end |
end |
function BuyDropper:UpdateDisplays() |
if BuyDropperOptions:IsVisible() then |
self:UpdateTrackingList() |
end |
if MerchantFrame:IsVisible() then |
self:UpdateLabels() |
end |
end |
--[[ |
Purchasing Methods |
]] |
function BuyDropper:ScanMerchant() |
if self.db.profile.vendor.enabled and not self.hasPurchased then |
local hasNeededItem |
for index, item, priority in self:IterateTrackedMerchantItems() do |
self:UpdatePrice(index, item) |
if self:NumToBuy(item) > 0 then |
self:QueuePurchase(index, priority) |
hasNeededItem = true |
end |
end |
if hasNeededItem then |
if self.db.profile.vendor.confirm then |
self:ConfirmPurchases() |
else |
self:ReleasePurchaseQueue() |
end |
if BuyDropperOptions:IsVisible() then |
self:UpdateTrackingList() |
end |
end |
if not self.hasWaited then |
self:ScheduleEvent("BUYDROPPER_MERCHANT_WAIT", function() |
self.hasWaited = true |
end, BUYDROPPER_MERCHANT_DELAY) |
end |
end |
end |
function BuyDropper:IterateTrackedMerchantItems() |
return function(num, index) |
return self:TrackedItemIterator(num, index) |
end, |
GetMerchantNumItems(), |
0 |
end |
function BuyDropper:TrackedItemIterator(num, index) |
while index < num do |
index = index + 1 |
local link = GetMerchantItemLink(index) |
if link then -- Sometimes info isn't available for all indexes right away |
local item, priority = self:GetLinkItem(link) |
if item then |
return index, item, priority |
end |
else |
return |
end |
end |
end |
function BuyDropper:UpdatePrice(index, item) |
local price, quantity = select(3, GetMerchantItemInfo(index)) |
item.price = price |
item.preset = quantity |
end |
function BuyDropper:NumToBuy(item) |
local toBuy = item.amount - CogsBagSpace:GetBagItemCount(item.id) |
if item.preset > 1 then |
toBuy = (self.db.profile.overstock and ceil or floor)(toBuy/item.preset) |
end |
return toBuy |
end |
function BuyDropper:ConfirmPurchases() |
local which = "BUYDROPPER_CONFIRM_PURCHASE" |
local dialog = StaticPopup_FindVisible(which) |
if not dialog then |
StaticPopup_Show(which, self:FormatMoney(self:GetQueueCost())) |
else |
getglobal(dialog:GetName().."Text"):SetText(format(StaticPopupDialogs[which].text, self:FormatMoney(self:GetQueueCost()))) |
end |
end |
function BuyDropper:PurchaseItem(item) |
local num = self:NumToBuy(item) |
local absoluteNum = num * item.preset |
local cost = num * item.price |
local link = self:MakeItemLink(item.id) |
local db = self.db.profile |
local budget = GetMoney() * (db.confirm and 1 or db.vendor.budget) |
local ret = true |
if cost > budget then |
repeat |
num = num - 1 |
cost = num * item.price |
absoluteNum = num * item.preset |
until cost < budget or num == 0 |
if num == 0 then |
self:Print("Can't afford to buy %s à %d", link, absoluteNum) |
return false |
else |
self:Print("Only able to afford %s à %d", link, absoluteNum) |
ret = false |
end |
end |
local space = self:CheckFreeSpace(item, num) |
if space == 0 then |
return false |
elseif space < num then |
num = space |
cost = num * item.price |
absoluteNum = num * item.preset |
ret = false |
end |
self:Print("Buying %s à %d for %s", link, absoluteNum, self:FormatMoney(cost)) |
self:DoPurchase(item, num) |
return ret |
end |
function BuyDropper:CheckFreeSpace(item, num) |
local free, special = CogsBagSpace:FreeBagSpace(item.id) |
free = floor((free + special) / item.preset) |
if free == 0 then |
self:Print("Not enough room in your bags for %s", self:MakeItemLink(item.id)) |
return 0 |
elseif free < num then |
self:Print("Only able to fit %d more of %s into your bags", free * item.preset, self:MakeItemLink(item.id)) |
return free |
end |
return num |
end |
function BuyDropper:DoPurchase(item, num) |
local numLoops, purchAmount, leftover |
local stack = select(8, GetItemInfo(item.id)) |
if item.preset > 1 then |
numLoops = num |
purchAmount = 1 |
leftover = 0 |
else |
numLoops = floor(num/stack) |
purchAmount = stack |
leftover = num % stack |
end |
for i = 1, numLoops do |
BuyMerchantItem(item.index, purchAmount) |
end |
if leftover > 0 then |
BuyMerchantItem(item.index, leftover) |
end |
end |
--[[ |
General functions |
]] |
function BuyDropper:ExtractItemID(link) |
return tonumber(strmatch(link, "item:(%d+):")) |
end |
function BuyDropper:MakeItemLink(id) |
return (select(2, GetItemInfo(id))) |
end |
BDOPTS_REFILL_OPTIONS = "Refill Options" |
BDOPTS_DROPPER_OPTIONS = "Vendor Dropper" |
BDOPTS_CURRENTLY_TRACKING = "Currently Tracking" |
BDOPTS_OPERATIONS = "Operations" |
BDOPTS_SELECT = "Select" |
BDOPTS_MODIFY = "Edit list" |
BDOPTS_REMOVE_SELECTED = "Remove Selected" |
BDOPTS_CLEAR_LIST = "Clear List" |
BDOPTS_NOT_IMPLEMENTED = "Not implemented yet\nUse /buydropper list" |
BDOPTS_ITEM_HEIGHT = 56 |
local optionsChecks = { |
Vendor = { label = "Buy from vendors", parent = "vendor", field = "enabled" }, |
Confirm = { label = "Confirm purchase", parent = "vendor", field = "confirm" }, |
Bank = { label = "Withdraw from bank", field = "bank"}, |
Overstock = { label = "Overstock", field = "overstock", tooltipText = "Buy more than your set amount if the item comes in preset stacks" }, |
Dropper = { label = "Enable Dropper", parent = "dropper", field = "enabled" }, |
Label = { label = "Show Label", parent = "dropper", field = "label" }, |
} |
function BuyDropper:OptionsLoad(this) |
this:RegisterForDrag("LeftButton") |
for which, options in pairs(optionsChecks) do |
local button = getglobal("BuyDropper"..which.."Check") |
local label = getglobal("BuyDropper"..which.."CheckText") |
label:SetText(options.label) |
button.tooltipText = options.tooltipText |
button.db = { parent = options.parent, field = options.field } |
end |
BuyDropperPositionSliderHigh:SetText "Right" |
BuyDropperPositionSliderLow:SetText "Left" |
BuyDropperPositionSliderText:SetText "Position" |
BuyDropperOptionsOperationsDropperLabel:SetText("Add an item") |
BuyDropperOptionsOperationsDropperLabel:Anchor("RIGHT") |
--[[local items = {} |
items[1] = CreateFrame("Frame", "TrackingItem1", TrackingListScrollFrame, "BuyDropperTrackingItemButton") |
items[1]:SetPoint("TOPLEFT", 42, 0) |
for i = 2, 7 do |
items[i] = CreateFrame("Frame", "TrackingItem"..i, TrackingListScrollFrame, "BuyDropperTrackingItemButton") |
items[i]:SetPoint("TOPLEFT", items[i-1], "BOTTOMLEFT", 0, -8) |
end |
BuyDropperOptionsTrackingListScrollFrame:UpdateScrollChildRect() |
self.trackingItems = items]] |
end |
function BuyDropper:OptionBoxLoad(this, title) |
this:SetBackdropBorderColor(0.4, 0.4, 0.4) |
this:SetBackdropColor(0.15, 0.15, 0.15) |
getglobal(this:GetName().."Title"):SetText(title) |
end |
function BuyDropper:OptionsShow() |
PlaySound("igMainMenuOption") |
local db = self.db.profile |
for which, options in pairs(optionsChecks) do |
local checked = options.parent and db[options.parent][options.field] or db[options.field] |
getglobal("BuyDropper"..which.."Check"):SetChecked(checked) |
end |
self:UpdateEnabled() |
self:UpdateTrackingList() |
end |
function BuyDropper:SetCheckData(this) |
local db, checked = self.db.profile, this:GetChecked() |
db = this.db.parent and db[this.db.parent] or db |
db[this.db.field] = checked and true or false -- GetChecked returns nil or 1, but nils aren't saved |
end |
function BuyDropper:UpdateEnabled() |
local profile = self.db.profile |
do |
local checked = profile.vendor.enabled |
if checked then |
OptionsFrame_EnableCheckBox(BuyDropperConfirmCheck) |
else |
OptionsFrame_DisableCheckBox(BuyDropperConfirmCheck) |
end |
end |
do |
local unchecked = not profile.vendor.enabled and not profile.bank |
if not unchecked then |
OptionsFrame_EnableCheckBox(BuyDropperOverstockCheck) |
else |
OptionsFrame_DisableCheckBox(BuyDropperOverstockCheck) |
end |
end |
do |
checked = profile.dropper.enabled |
if checked then |
OptionsFrame_EnableSlider(BuyDropperPositionSlider) |
BuyDropperPositionSlider:SetValue(profile.dropper.position) |
OptionsFrame_EnableCheckBox(BuyDropperLabelCheck) |
else |
OptionsFrame_DisableSlider(BuyDropperPositionSlider) |
OptionsFrame_DisableCheckBox(BuyDropperLabelCheck) |
end |
end |
end |
function BuyDropper:PositionSliderValueChanged(this) |
if self.db then -- ValueChanged can occur before variables are loaded |
self.db.profile.dropper.position = this:GetValue() |
self:UpdateDropper() |
end |
end |
function BuyDropper:UpdateTrackingList() |
end |
function BuyDropper:TrackingItemOnLoad(this) |
local button = getglobal(this:GetName().."ItemButton") |
button:SetScript("OnEnter", function(this) |
GameTooltip:SetOwner(this, "ANCHOR_RIGHT") |
GameTooltip:SetText("Click to change tracking amount", 1, 1, 1, true) |
GameTooltip:Show() |
end) |
button:SetScript("OnLeave", function() |
GameTooltip:Hide() |
end) |
end |
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ |
..\..\UI.xsd"> |
<Script file="AceLibrary\AceLibrary.lua"/> |
<Script file="AceOO-2.0\AceOO-2.0.lua"/> |
<Script file="AceHook-2.1\AceHook-2.1.lua"/> |
<Script file="AceEvent-2.0\AceEvent-2.0.lua"/> |
<Script file="AceAddon-2.0\AceAddon-2.0.lua"/> |
<Script file="AceConsole-2.0\AceConsole-2.0.lua"/> |
<Script file="AceDB-2.0\AceDB-2.0.lua"/> |
</Ui> |
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/ |
..\UI.xsd"> |
<!-- ************************************************************************************ |
TEMPLATES |
************************************************************************************ --> |
<!-- Basic Dropper --> |
<Button name="BuyDropperDropperTemplate" virtual="true"> |
<Size x="37" y="37"/> |
<Layers> |
<Layer level="BACKGROUND"> |
<Texture file="Interface\Buttons\UI-Slot-Background"> |
<Size x="39" y="39"/> |
<Anchors> |
<Anchor point="TOPLEFT"> |
<Offset x="-2" y="2"/> |
</Anchor> |
</Anchors> |
<TexCoords left="0" right="0.640625" top="0" bottom="0.640625"/> |
</Texture> |
</Layer> |
<Layer level="ARTWORK"> |
<FontString name="$parentCount" inherits="NumberFontNormal" justifyH="RIGHT"> |
<Anchors> |
<Anchor point="BOTTOMRIGHT"> |
<Offset x="-5" y="2"/> |
</Anchor> |
</Anchors> |
</FontString> |
<FontString name="$parentLabel" inherits="GameFontNormal" text="BUYDROPPER" justifyH="RIGHT"/> |
</Layer> |
<Layer level="BORDER"> |
<Texture name="$parentIconTexture"/> |
</Layer> |
</Layers> |
<Scripts> |
<OnLoad> |
BuyDropper:DropperLoad(self) |
</OnLoad> |
<OnReceiveDrag> |
BuyDropper:DropperClick(self) |
</OnReceiveDrag> |
<OnDragStart> |
BuyDropper:DropperClick(self) |
</OnDragStart> |
<OnClick> |
BuyDropper:DropperClick(self) |
</OnClick> |
<OnEnter> |
GameTooltip:SetOwner(self, "ANCHOR_RIGHT") |
if self.link then |
GameTooltip:SetHyperlink(self.link) |
else |
GameTooltip:SetText("Drag an item here to add it to BuyDropper", 1.0, 1.0, 1.0) |
end |
</OnEnter> |
<OnLeave> |
GameTooltip:Hide() |
</OnLeave> |
</Scripts> |
<HighlightTexture alphaMode="ADD" file="Interface\Buttons\ButtonHilight-Square"/> |
</Button> |
<!-- Font used for tracking buttons --> |
<Font name="NumberFontNormalGreen" inherits="NumberFontNormal" justifyH="RIGHT"> |
<FontHeight val="10"/> |
<Color a="1" r="0.1" g="1.0" b="0.1"/> |
</Font> |
<!-- Tracking button template (instantiated in Lua) --> |
<Button name="BuyDropperMerchantTracking" virtual="true" frameStrata="HIGH"> |
<Size x="30" y="16"/> |
<Scripts> |
<OnClick> |
self:GetParent():Click() |
BuyDropperMerchantDropper:Click() |
</OnClick> |
<OnEnter> |
GameTooltip:SetOwner(self, "ANCHOR_RIGHT") |
GameTooltip:SetText("BuyDropper") |
GameTooltip:AddLine("You are currently tracking "..self:GetText().." of this item. Click to change.", 1, 1, 1, 1) |
GameTooltip:Show() |
</OnEnter> |
<OnLeave> |
GameTooltip:Hide() |
</OnLeave> |
</Scripts> |
<ButtonText font="NumberFontNormalGreen"> |
<Anchors> |
<Anchor point="TOPRIGHT"/> |
</Anchors> |
</ButtonText> |
</Button> |
<!-- Tracking List Items --> |
<Button name="BuyDropperTrackingItemButton" virtual="true" inherits="MerchantItemTemplate"> |
<Frames> |
<CheckButton name="$parentSelectCheck" inherits="OptionsCheckButtonTemplate"> |
<Anchors> |
<Anchor point="RIGHT" relativePoint="LEFT"> |
<Offset x="-5" y="0"/> |
</Anchor> |
</Anchors> |
<HitRectInsets left="0" right="0" top="0" bottom="0"/> |
</CheckButton> |
</Frames> |
<Scripts> |
<OnLoad> |
BuyDropper:TrackingItemOnLoad(self) |
</OnLoad> |
</Scripts> |
</Button> |
<CheckButton name="BuyDropperCheck" virtual="true" inherits="OptionsCheckButtonTemplate"> |
<Scripts> |
<OnClick> |
BuyDropper:SetCheckData(self) |
BuyDropper:UpdateEnabled() |
BuyDropper:UpdateDropper() |
</OnClick> |
</Scripts> |
</CheckButton> |
<!-- ************************************************************************************ |
FRAMES |
************************************************************************************ --> |
<!-- Position of this dropper is set by Lua based on saved variables --> |
<Button name="BuyDropperMerchantDropper" parent="MerchantFrame" inherits="BuyDropperDropperTemplate"/> |
<!-- Options Frame --> |
<Frame name="BuyDropperOptions" toplevel="true" frameStrata="DIALOG" movable="true" enableMouse="true" hidden="true" parent="UIParent"> |
<Size x="450" y="450"/> |
<Anchors> |
<Anchor point="CENTER"/> |
</Anchors> |
<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true"> |
<BackgroundInsets> |
<AbsInset left="11" right="12" top="12" bottom="11"/> |
</BackgroundInsets> |
<TileSize> |
<AbsValue val="32"/> |
</TileSize> |
<EdgeSize> |
<AbsValue val="32"/> |
</EdgeSize> |
</Backdrop> |
<Layers> |
<Layer level="ARTWORK"> |
<Texture name="$parentHeader" file="Interface\DialogFrame\UI-DialogBox-Header"> |
<Size x="256" y="64"/> |
<Anchors> |
<Anchor point="TOP"> |
<Offset x="0" y="12"/> |
</Anchor> |
</Anchors> |
</Texture> |
<FontString inherits="GameFontNormal" text="BUYDROPPER"> |
<Anchors> |
<Anchor point="TOP" relativeTo="$parentHeader"> |
<Offset x="0" y="-14"/> |
</Anchor> |
</Anchors> |
</FontString> |
</Layer> |
</Layers> |
<Frames> |
<Frame name="$parentRefillOptions" inherits="OptionFrameBoxTemplate"> |
<Size x="200" y="132"/> |
<Anchors> |
<Anchor point="TOPLEFT"> |
<Offset x="12" y="-39"/> |
</Anchor> |
</Anchors> |
<Frames> |
<CheckButton name="BuyDropperVendorCheck" inherits="BuyDropperCheck"> |
<Anchors> |
<Anchor point="TOPLEFT"> |
<Offset x="10" y="-11"/> |
</Anchor> |
</Anchors> |
</CheckButton> |
<CheckButton name="BuyDropperConfirmCheck" inherits="BuyDropperCheck"> |
<Size x="26" y="26"/> |
<Anchors> |
<Anchor point="TOPLEFT" relativeTo="BuyDropperVendorCheck" relativePoint="BOTTOMLEFT"> |
<Offset x="5" y="4"/> |
</Anchor> |
</Anchors> |
</CheckButton> |
<CheckButton name="BuyDropperBankCheck" inherits="BuyDropperCheck"> |
<Anchors> |
<Anchor point="TOPLEFT" relativeTo="BuyDropperConfirmCheck" relativePoint="BOTTOMLEFT"> |
<Offset x="-5" y="4"/> |
</Anchor> |
</Anchors> |
</CheckButton> |
<CheckButton name="BuyDropperOverstockCheck" inherits="BuyDropperCheck"> |
<Anchors> |
<Anchor point="TOPLEFT" relativeTo="BuyDropperBankCheck" relativePoint="BOTTOMLEFT"> |
<Offset x="0" y="4"/> |
</Anchor> |
</Anchors> |
</CheckButton> |
</Frames> |
<Scripts> |
<OnLoad> |
BuyDropper:OptionBoxLoad(self, BDOPTS_REFILL_OPTIONS) |
</OnLoad> |
</Scripts> |
</Frame> |
<Frame name="$parentDropperOptions" inherits="OptionFrameBoxTemplate"> |
<Size x="200" y="117"/> |
<Anchors> |
<Anchor point="TOPLEFT" relativeTo="$parentRefillOptions" relativePoint="BOTTOMLEFT"> |
<Offset x="0" y="-20"/> |
</Anchor> |
</Anchors> |
<Frames> |
<CheckButton name="BuyDropperDropperCheck" inherits="BuyDropperCheck"> |
<Anchors> |
<Anchor point="TOPLEFT"> |
<Offset x="10" y="-11"/> |
</Anchor> |
</Anchors> |
</CheckButton> |
<Slider name="BuyDropperPositionSlider" inherits="OptionsSliderTemplate" minValue="70" maxValue="306" valueStep="1" defaultValue="70"> |
<Size x="160" y="17"/> |
<Anchors> |
<Anchor point="TOPLEFT" relativeTo="BuyDropperDropperCheck" relativePoint="BOTTOMLEFT"> |
<Offset x="10" y="-6"/> |
</Anchor> |
</Anchors> |
<Scripts> |
<OnValueChanged> |
BuyDropper:PositionSliderValueChanged(self) |
</OnValueChanged> |
</Scripts> |
</Slider> |
<CheckButton name="BuyDropperLabelCheck" inherits="BuyDropperCheck"> |
<Size x="26" y="26"/> |
<Anchors> |
<Anchor point="TOPLEFT" relativeTo="BuyDropperPositionSlider" relativePoint="BOTTOMLEFT"> |
<Offset x="-5" y="-10"/> |
</Anchor> |
</Anchors> |
</CheckButton> |
</Frames> |
<Scripts> |
<OnLoad> |
BuyDropper:OptionBoxLoad(self, BDOPTS_DROPPER_OPTIONS) |
</OnLoad> |
</Scripts> |
</Frame> |
<Frame name="$parentTrackingList" inherits="OptionFrameBoxTemplate"> |
<Size x="225" y="269"/> |
<Anchors> |
<Anchor point="TOPRIGHT"> |
<Offset x="-12" y="-39"/> |
</Anchor> |
</Anchors> |
<Layers> |
<Layer> |
<FontString text="BDOPTS_NOT_IMPLEMENTED" inherits="GameFontDisable"> |
<Anchors> |
<Anchor point="CENTER"/> |
</Anchors> |
</FontString> |
</Layer> |
</Layers> |
<Frames> |
<ScrollFrame name="$parentScrollFrame" inherits="UIPanelScrollFrameTemplate"> |
<Size x="194" y="256"/> |
<Anchors> |
<Anchor point="TOP"> |
<Offset x="-16" y="-8"/> |
</Anchor> |
</Anchors> |
<Layers> |
<Layer level="ARTWORK"> |
<Texture file="Interface\PaperDollInfoFrame\UI-Character-ScrollBar"> |
<Size x="31" y="256"/> |
<Anchors> |
<Anchor point="TOPLEFT" relativePoint="TOPRIGHT"> |
<Offset x="-2" y="5"/> |
</Anchor> |
</Anchors> |
<TexCoords left="0" right="0.484375" top="0" bottom="1.0"/> |
</Texture> |
<Texture file="Interface\PaperDollInfoFrame\UI-Character-ScrollBar"> |
<Size x="31" y="106"/> |
<Anchors> |
<Anchor point="BOTTOMLEFT" relativePoint="BOTTOMRIGHT"> |
<Offset x="-2" y="-2"/> |
</Anchor> |
</Anchors> |
<TexCoords left="0.515625" right="1.0" top="0" bottom="0.4140625"/> |
</Texture> |
</Layer> |
</Layers> |
<ScrollChild> |
<Frame name="TrackingListScrollFrame"> |
<!-- Tracking items will be instantiated in Lua --> |
<Size x="1" y="1"/><!-- Dummy size so it'll show at all --> |
</Frame> |
</ScrollChild> |
</ScrollFrame> |
</Frames> |
<Scripts> |
<OnLoad> |
BuyDropper:OptionBoxLoad(self, BDOPTS_CURRENTLY_TRACKING) |
</OnLoad> |
</Scripts> |
</Frame> |
<Frame name="$parentOperations" inherits="OptionFrameBoxTemplate"> |
<Size x="425" y="80"/> |
<Anchors> |
<Anchor point="TOPLEFT" relativeTo="$parentDropperOptions" relativePoint="BOTTOMLEFT"> |
<Offset x="0" y="-20"/> |
</Anchor> |
</Anchors> |
<Layers> |
<Layer level="OVERLAY"> |
<FontString name="BuyDropperOptionsSelectLabel" inherits="GameFontNormal" text="BDOPTS_SELECT"> |
<Anchors> |
<Anchor point="TOPLEFT"> |
<Offset x="206" y="-7"/> |
</Anchor> |
</Anchors> |
</FontString> |
<FontString name="BuyDropperOptionsModifyLabel" inherits="GameFontNormal" text="BDOPTS_MODIFY"> |
<Anchors> |
<Anchor point="LEFT" relativeTo="BuyDropperOptionsSelectLabel" relativePoint="RIGHT"> |
<Offset x="38" y="0"/> |
</Anchor> |
</Anchors> |
</FontString> |
</Layer> |
</Layers> |
<Frames> |
<Button name="$parentDropper" inherits="BuyDropperDropperTemplate"> |
<Anchors> |
<Anchor point="TOPLEFT"> |
<Offset x="15" y="-22"/> |
</Anchor> |
</Anchors> |
</Button> |
<Button name="$parentSelectAll" inherits="UIPanelButtonTemplate" text="ALL"> |
<Size x="60" y="24"/> |
<Anchors> |
<Anchor point="TOPLEFT" relativeTo="BuyDropperOptionsSelectLabel" relativePoint="BOTTOMLEFT"> |
<Offset x="7" y="-3"/> |
</Anchor> |
</Anchors> |
<Scripts> |
<OnLoad> |
self:Disable() |
</OnLoad> |
</Scripts> |
</Button> |
<Button name="$parentSelectNone" inherits="UIPanelButtonTemplate" text="NONE"> |
<Size x="60" y="24"/> |
<Anchors> |
<Anchor point="TOPLEFT" relativeTo="$parentSelectAll" relativePoint="BOTTOMLEFT"/> |
</Anchors> |
<Scripts> |
<OnLoad> |
self:Disable() |
</OnLoad> |
</Scripts> |
</Button> |
<Button name="$parentRemoveSelected" inherits="UIPanelButtonTemplate" text="BDOPTS_REMOVE_SELECTED"> |
<Size x="125" y="24"/> |
<Anchors> |
<Anchor point="TOPLEFT" relativeTo="BuyDropperOptionsModifyLabel" relativePoint="BOTTOMLEFT"> |
<Offset x="7" y="-3"/> |
</Anchor> |
</Anchors> |
<Scripts> |
<OnLoad> |
self:Disable() |
</OnLoad> |
</Scripts> |
</Button> |
<Button name="$parentClearList" inherits="UIPanelButtonTemplate" text="BDOPTS_CLEAR_LIST"> |
<Size x="125" y="24"/> |
<Anchors> |
<Anchor point="TOPLEFT" relativeTo="$parentRemoveSelected" relativePoint="BOTTOMLEFT"/> |
</Anchors> |
<Scripts> |
<OnClick> |
StaticPopup_Show("BUYDROPPER_CONFIRM_CLEAR") |
</OnClick> |
</Scripts> |
</Button> |
</Frames> |
<Scripts> |
<OnLoad> |
BuyDropper:OptionBoxLoad(self, BDOPTS_OPERATIONS) |
</OnLoad> |
</Scripts> |
</Frame> |
<Button name="$parentCloseButton" inherits="UIPanelButtonTemplate2" text="CLOSE"> |
<Size x="72" y="24"/> |
<Anchors> |
<Anchor point="BOTTOMRIGHT"> |
<Offset x="-16" y="16"/> |
</Anchor> |
</Anchors> |
<Scripts> |
<OnClick> |
PlaySound("gsTitleOptionExit") |
this:GetParent():Hide() |
</OnClick> |
</Scripts> |
</Button> |
</Frames> |
<Scripts> |
<OnLoad> |
BuyDropper:OptionsLoad(self) |
</OnLoad> |
<OnShow> |
BuyDropper:OptionsShow() |
</OnShow> |
<OnDragStart> |
this:StartMoving() |
</OnDragStart> |
<OnDragStop> |
this:StopMovingOrSizing() |
</OnDragStop> |
</Scripts> |
</Frame> |
</Ui> |
--[[ BuyDropper - By Cogwheel |
Inspired by FreeRefills by Kyahx ]] |
BUYDROPPER = "BuyDropper" |
DROPPER_MIN_X = 70 |
DROPPER_MAX_X = 306 |
BuyDropper = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0", "AceHook-2.1", "AceConsole-2.0", "AceDB-2.0") |
function BuyDropper:OnInitialize() |
self:InitDB() -- Set up saved variables |
self:InitConsole() -- Create slash commands |
self:InitPopup() -- Create amount entry popup dialog |
self:InitLabels() -- Create tracking labels in merchant window |
self:InitPurchaseQueue()-- Initialization for the purchase queue |
self:UpdateDropper() -- Position the Merchant Dropper based on saved preferences |
end |
function BuyDropper:InitDB() |
self:RegisterDB("BuyDropperDB") |
self:RegisterDefaults("char", { |
profile = "char" |
}) |
self:RegisterDefaults("profile", { |
list = {}, |
vendor = { |
enabled = true, |
confirm = true, |
budget = 0.50, |
fallthrough = false |
}, |
bank = true, |
overstock = false, |
dropper = { |
enabled = true, |
position = DROPPER_MAX_X, |
label = true |
}, |
}) |
self:SetProfile(self.db.char.profile) |
end |
function BuyDropper:InitPopup() |
StaticPopupDialogs["BUYDROPPER_ASK_AMOUNT"] = { |
text = "Please enter the amount of this item would you like to keep in stock:", |
button1 = ACCEPT, |
button2 = CANCEL, |
hasEditBox = 1, |
maxLetters = 5, |
timeout = 0, |
OnAccept = function() |
self:AcceptAmount(this:GetParent().data, tonumber(getglobal(this:GetParent():GetName().."EditBox"):GetText())) |
end, |
OnCancel = function() |
end, |
OnShow = function() |
local name = this:GetName() |
getglobal(name.."EditBox"):SetText("") |
getglobal(name.."Button1"):Disable() |
getglobal(name.."EditBox"):SetFocus() |
end, |
OnHide = function() |
getglobal(this.data:GetName().."IconTexture"):SetTexture(nil) |
this.data.link = nil |
end, |
EditBoxOnTextChanged = function() |
local name = this:GetParent():GetName() |
local button = getglobal(name.."Button1") |
if tonumber(getglobal(name.."EditBox"):GetText()) then |
button:Enable() |
else |
button:Disable() |
end |
end, |
EditBoxOnEnterPressed = function() |
if getglobal(this:GetParent():GetName().."Button1"):IsEnabled() then |
self:AcceptAmount(this:GetParent().data, tonumber(getglobal(this:GetParent():GetName().."EditBox"):GetText())) |
end |
this:GetParent():Hide() |
end, |
} |
StaticPopupDialogs["BUYDROPPER_CONFIRM_PURCHASE"] = { |
text = "BuyDropper would like to buy items from this vendor totaling %s. Proceed?", |
button1 = YES, |
button2 = NO, |
OnAccept = function() |
self:ReleasePurchaseQueue() |
end, |
timeout = 0, |
hideOnEscape = true, |
} |
StaticPopupDialogs["BUYDROPPER_CONFIRM_CLEAR"] = { |
text = "Are you sure you want to clear your BuyDropper tracking list?", |
button1 = YES, |
button2 = NO, |
OnAccept = function() |
self:ClearTrackingList() |
end, |
timeout = 0, |
hideOnEscape = true, |
} |
end |
function BuyDropper:InitLabels() |
local labels = {} |
for i=1,10 do |
labels[i] = CreateFrame("Button", nil, getglobal("MerchantItem"..i.."ItemButton"), "BuyDropperMerchantTracking") |
labels[i]:SetPoint("TOPRIGHT", getglobal("MerchantItem"..i.."ItemButtonCount"), "BOTTOMRIGHT") |
labels[i].Update = function(this) |
local link = GetMerchantItemLink(this:GetParent():GetID()) |
local item = link and self:GetLinkItem(link) |
if item and self.enabled then |
this:SetText(item.amount) |
this:Show() |
else |
this:Hide() |
end |
end |
end |
self.merchantLabels = labels |
end |
function BuyDropper:UpdateDropper() |
local db = self.db.profile.dropper |
local dropper = BuyDropperMerchantDropper |
local label = BuyDropperMerchantDropperLabel |
if db.enabled then |
dropper:Show() |
dropper:ClearAllPoints() |
dropper:SetPoint("TOPLEFT", db.position, -36) |
label:Anchor(db.position < label:GetWidth() + 70 and "RIGHT" or "LEFT") |
if db.label then |
label:Show() |
else |
label:Hide() |
end |
else |
dropper:Hide() |
end |
end |
function BuyDropper:OnEnable() |
self.enabled = true |
-- These two hooks are only necessary until GetCursorInfo returns data for merchant items |
self:SecureHook("PickupMerchantItem", function(index) |
self.link = GetMerchantItemLink(index) |
end) |
self:SecureHook("ClearCursor", function() |
self.link = nil |
end) |
self:SecureHook("MerchantFrame_UpdateMerchantInfo", "UpdateLabels") |
self:RegisterEvent("MERCHANT_SHOW", function() |
for i, item in ipairs(self.list) do |
item.priority = nil |
item.index = nil |
end |
self:ScanMerchant() |
end) |
self:RegisterEvent("MERCHANT_UPDATE", "ScanMerchant") |
self:RegisterEvent("MERCHANT_CLOSED", "Cleanup") |
self.list = self.db.profile.list |
self.idPriorityCache = {} |
self:UpdatePriorityCache() |
self:UpdateLabels() |
if MerchantFrame:IsVisible() then |
self:ScanMerchant() |
end |
end |
function BuyDropper:OnDisable() |
self.enabled = nil |
self:UpdateDropper() |
self:UpdateLabels() |
self:Cleanup() |
end |
function BuyDropper:Cleanup() |
StaticPopup_Hide("BUYDROPPER_ASK_AMOUNT") |
StaticPopup_Hide("BUYDROPPER_CONFIRM_PURCHASE") |
self:ClearPurchaseQueue() |
self.hasPurchased = nil |
end |
function BuyDropper:DropperLoad(this) |
this:RegisterForDrag "LeftButton" |
local label = getglobal(this:GetName().."Label") |
if not self.labelAnchors then |
self.labelAnchors = { |
LEFT = { |
point = "RIGHT", |
relative = "LEFT", |
offX = -4 |
}, |
RIGHT = { |
point = "LEFT", |
relative = "RIGHT", |
offX = 2 |
} |
} |
end |
function label.Anchor(this, which) |
which = which and which:upper() or "" |
local t = self.labelAnchors[which] |
this:ClearAllPoints() |
this:SetPoint(t.point, this:GetParent(), t.relative, t.offX, 0) |
end |
label:Anchor("LEFT") |
end |
function BuyDropper:DropperClick(this) |
local which, id, link = GetCursorInfo() |
if not link then -- Only until GetCursorInfo returns data for merchant items |
link = self.link |
which = "item" |
end |
if not link or which ~= "item" then |
return |
end |
this.link = link |
local texture = select(10, GetItemInfo(link)) |
getglobal(this:GetName().."IconTexture"):SetTexture(texture) |
ClearCursor() |
local dialog = StaticPopup_Show("BUYDROPPER_ASK_AMOUNT") |
dialog.data = this |
end |
function BuyDropper:AcceptAmount(button, amount) |
if amount > 0 then |
self:AddTrackingItem(button.link, amount) |
else |
self:RemoveTrackingItem(select(2, self:GetLinkItem(button.link))) |
end |
end |
function BuyDropper:UpdateLabels() |
for i, label in ipairs(self.merchantLabels) do |
label:Update() |
end |
end |
function BuyDropper:FormatMoney(copper) |
local gold = floor(copper / COPPER_PER_GOLD) |
local silver = floor(copper / COPPER_PER_SILVER) % SILVER_PER_GOLD |
copper = copper % COPPER_PER_SILVER |
return format( "|cFFEEDD00%s|r|cFFBBBBBB%s|r|cFFDD6633%s|r", |
gold > 0 and gold.."g"..((silver > 0 or copper > 0) and " " or "") or "", |
silver > 0 and silver.."s"..(copper > 0 and " " or "") or "", |
copper > 0 and copper.."c" or "") |
end |
function BuyDropper:InitConsole() |
self:RegisterChatCommand({"/buydropper", "/bd"}, {type = "group", args = { |
options = { |
type = "execute", |
name = "Options", |
desc = "Open the BuyDropper options window", |
func = function() |
BuyDropperOptions:Show() |
end |
}, |
add = { |
type = "text", |
name = "Add Item", |
desc = "Add an item to the tracking list (also changes amount of existing items)", |
usage = "<item link> <amount>", |
validate = function(text) |
local link, amount = self:ParseAddCommand(text) |
return link and amount > 0 |
end, |
get = false, |
set = function(text) |
local link, amount = self:ParseAddCommand(text) |
self:AddTrackingItem(link, amount) |
end |
}, |
list = { |
type = "execute", |
name = "List Items", |
desc = "List the items you are currently tracking (high to low priority)", |
func = function() |
local message = "Currently Tracking:" |
if #self.list == 0 then |
message = message.."\n Nothing" |
end |
for priority, item in ipairs(self.list) do |
message = message..format("\n%4d: %s à %s", priority, self:MakeItemLink(item.id), item.amount) |
end |
self:Print(message) |
end |
}, |
change = { |
type = "text", |
name = "Change Amount Tracked", |
desc = "Change the tracked amount of an item", |
usage = "<priority> <amount>\n".. |
" <priority> is obtained from /buydropper list\n".. |
" <amount> must be 1 or more", |
input = true, |
validate = function(priority, amount) |
priority, amount = tonumber(priority), tonumber(amount) |
return priority and amount and priority >= 1 and priority <= #self.list and amount >= 1 |
end, |
get = false, |
set = function(priority, amount) |
self:ChangeTrackingItem(tonumber(priority), tonumber(amount)) |
end |
}, |
priority = { |
type = "text", |
name = "Set Item Priority", |
desc = "Change an item's priority", |
usage = "<current priority> <new priority>\n".. |
" <current priority> is obtained from /buydropper list\n".. |
" <new priority> must be a number from 1 to the number of items you are tracking", |
input = true, |
validate = function(old, new) |
old, new = tonumber(old), tonumber(new) |
return old and new and old >= 1 and old <= #self.list and new >= 1 and new <= #self.list |
end, |
get = false, |
set = function(old, new) |
self:SetTrackingPriority(tonumber(old), tonumber(new)) |
end |
}, |
remove = { |
type = "text", |
name = "Remove Item", |
desc = "Remove an item from your tracking list", |
usage = "<index>\n".. |
" <index> is obtained from /buydropper list", |
validate = function(index) |
index = tonumber(index) |
return index and index > 0 and index < #self.list |
end, |
get = false, |
set = function(index) |
self:RemoveTrackingItem(tonumber(index)) |
end |
}, |
clear = { |
type = "execute", |
name = "Clear List", |
desc = "Remove all items from your tracking list", |
func = function() |
StaticPopup_Show("BUYDROPPER_CONFIRM_CLEAR") |
end |
}, |
vendor = { |
type = "group", |
name = "Vendor Options", |
desc = "Options for vendor purchases", |
args = { |
toggle = { |
type = "toggle", |
name = "Toggle Purchase", |
desc = "Toggles the automatic purchase of items from vendors", |
map = { [true] = GREEN_FONT_COLOR_CODE.."Enabled|r", [false] = RED_FONT_COLOR_CODE.."Disabled|r" }, |
get = function() |
return self.db.profile.vendor.enabled |
end, |
set = function(value) |
self.db.profile.vendor.enabled = value |
if BuyDropperOptions:IsVisible() then |
BuyDropperVendorCheck:SetChecked(value) |
end |
self:UpdateEnabled() |
end |
}, |
confirm = { |
type = "toggle", |
name = "Confirm Purchases", |
desc = "Toggles whether to confirm purchases from vendors", |
map = { [true] = GREEN_FONT_COLOR_CODE.."Yes|r", [false] = RED_FONT_COLOR_CODE.."No|r" }, |
disabled = function() |
return not self.db.profile.vendor.enabled |
end, |
get = function() |
return self.db.profile.vendor.confirm |
end, |
set = function(value) |
self.db.profile.vendor.confirm = value |
if BuyDropperOptions:IsVisible() then |
BuyDropperConfirmCheck:SetChecked(value) |
end |
end |
}, |
budget = { |
type = "range", |
name = "Budget", |
desc = "Sets the percentage of your total money BuyDropper is allowed to use to purchase an item", |
min = .01, max = 1, |
isPercent = true, |
disabled = function() |
return not self.db.profile.vendor.enabled |
end, |
get = function() |
return self.db.profile.vendor.budget |
end, |
set = function(value) |
self.db.profile.vendor.budget = value |
end |
}, |
fallthrough = { |
type = "toggle", |
name = "Fall-through Purchases", |
desc = "Toggles whether to purchase lower-priority items when higher-priority items cannot be purchased", |
map = { [true] = GREEN_FONT_COLOR_CODE.."Enabled|r", [false] = RED_FONT_COLOR_CODE.."Disabled|r" }, |
disabled = function() |
return not self.db.profile.vendor.enabled |
end, |
get = function() |
return self.db.profile.vendor.fallthrough |
end, |
set = function(value) |
self.db.profile.vendor.fallthrough = value |
end |
} |
} |
}, |
bank = { |
type = "toggle", |
name = "Withdraw Items", |
desc = "Toggles whether to withdraw items from your bank", |
map = { [true] = GREEN_FONT_COLOR_CODE.."Yes|r", [false] = RED_FONT_COLOR_CODE.."No|r" }, |
get = function() |
return self.db.profile.bank |
end, |
set = function(value) |
self.db.profile.bank = value |
if BuyDropperOptions:IsVisible() then |
BuyDropperBankCheck:SetChecked(value) |
end |
self:UpdateEnabled() |
end |
}, |
overstock = { |
type = "toggle", |
name = "Overstock Items", |
desc = "Toggles whether to overstock items that come in preset stacks (like food and water)", |
map = { [true] = GREEN_FONT_COLOR_CODE.."Yes|r", [false] = RED_FONT_COLOR_CODE.."No|r" }, |
disabled = function() |
local data = self.db.profile |
return not data.bank and not data.vendor.enabled |
end, |
get = function() |
return self.db.profile.overstock |
end, |
set = function(value) |
self.db.profile.overstock = value |
if BuyDropperOptions:IsVisible() then |
BuyDropperOverstockCheck:SetChecked(value) |
end |
end |
}, |
dropper = { |
type = "group", |
name = "Vendor Dropper Options", |
desc = "Options for the dropper in vendor windows", |
args = { |
toggle = { |
type = "toggle", |
name = "Toggle Vendor Dropper", |
desc = "Toggles whether to show a dropper in vendor windows", |
map = { [true] = GREEN_FONT_COLOR_CODE.."Enabled|r", [false] = RED_FONT_COLOR_CODE.."Disabled|r" }, |
get = function() |
return self.db.profile.dropper.enabled |
end, |
set = function(value) |
self.db.profile.dropper.enabled = value |
if BuyDropperOptions:IsVisible() then |
BuyDropperDropperCheck:SetChecked(value) |
end |
self:UpdateEnabled() |
if MerchantFrame:IsVisible() then |
self:UpdateDropper() |
end |
end |
}, |
position = { |
type = "range", |
name = "Dropper Position", |
desc = "Sets the horizontal position of the dropper in vendor windows (0 = left, 100 = right)", |
min = 0, max = 100, |
disabled = function() |
return not self.db.profile.dropper.enabled |
end, |
get = function() |
return (self.db.profile.dropper.position - DROPPER_MIN_X) / (DROPPER_MAX_X - DROPPER_MIN_X) * 100 |
end, |
set = function(value) |
local newValue = value / 100 * (DROPPER_MAX_X - DROPPER_MIN_X) + DROPPER_MIN_X |
self.db.profile.dropper.position = newValue |
if BuyDropperOptions:IsVisible() then |
BuyDropperPositionSlider:SetValue(newValue) |
end |
if MerchantFrame:IsVisible() then |
self:UpdateDropper() |
end |
end |
}, |
label = { |
type = "toggle", |
name = "Toggle Dropper Label", |
desc = "Toggles visibility of the vendor dropper's label", |
disabled = function() |
return not self.db.profile.dropper.enabled |
end, |
get = function() |
return self.db.profile.dropper.label |
end, |
set = function(value) |
self.db.profile.dropper.label = value |
if BuyDropperOptions:IsVisible() then |
BuyDropperLabelCheck:SetChecked(value) |
end |
if MerchantFrame:IsVisible() then |
self:UpdateDropper() |
end |
end |
} |
} |
}, |
}})end |
function BuyDropper:ParseAddCommand(text) |
local link, amount = strmatch(strtrim(text), "^(|c%x-|Hitem:%-?%d+:%-?%d+:%-?%d+:%-?%d+:%-?%d+:%-?%d+:%-?%d+:%-?%d+|h%[.-%]|h|r)%s-(%d+)$") |
amount = tonumber(amount) |
return link, amount |
end |