You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

469 lines
17 KiB

-- module independent variables --
----------------------------------
local addon, ns = ...;
local C, L, I = ns.LC.color, ns.L, ns.I;
-- module own local variables and local cached functions --
-----------------------------------------------------------
local name = "Durability"; -- DURABILITY L["ModDesc-Durability"]
local ttName,tt,module,_ = name.."TT";
local last_repairs = {};
local merchant,currentDurability = {repair=false,costs=0,diff=0,single=0},{0, 0, 0, 100, 100, false};
local discount = {[5]=0.95,[6]=0.9,[7]=0.85,[8]=0.8};
local slotNames = {
HEADSLOT,NECKSLOT,SHOULDERSLOT,SHIRTSLOT,CHESTSLOT,WAISTSLOT,LEGSSLOT,FEETSLOT,
WRISTSLOT,HANDSSLOT,FINGER0SLOT_UNIQUE,FINGER1SLOT_UNIQUE,TRINKET0SLOT_UNIQUE,
TRINKET1SLOT_UNIQUE,BACKSLOT,MAINHANDSLOT,SECONDARYHANDSLOT,RANGEDSLOT
};
local date_format = "%Y-%m-%d %H:%M";
local date_formats = {
["%d.%m. %H:%M"] = "28.07. 16:23",
["%d.%m. %I:%M %p"] = "28.07. 04:23 pm",
["%Y-%m-%d %H:%M"] = "2099-07-28 16:23",
["%Y-%m-%d %I:%M %p"] = "2099-07-28 04:23 pm",
["%d/%m/%Y %H:%M"] = "28/07/2099 16:23",
["%d/%m/%Y %I:%M %p"] = "28/07/2099 04:23 pm"
};
local colorSets = setmetatable({values={}},{
__newindex = function(t,k,v)
local tb,n = {},0;
for i,col in ns.pairsByKeys(v) do
table.insert(tb,C(col,(n<100 and n.."-" or "")..i.."%"));
n = i+1;
end
rawset(t.values,k,table.concat(tb,", "));
rawset(t,k,v);
end,
__call = function(t,d)
local c,n = nil,0
local set = t[ns.profile[name].colorSet]
for i,v in ns.pairsByKeys(set) do if d>=n and d<=i then c,n = v,i+1 end end
return c
end
})
-- register icon names and default files --
-------------------------------------------
I[name] = {iconfile="Interface\\Minimap\\TRACKING\\Repair",coords={0.05,0.95,0.05,0.95}}; --IconName::Durability--
-- some local functions --
--------------------------
local function updateBroker()
local obj = ns.LDB:GetDataObjectByName(module.ldbName) or {};
local repairCosts, equipCost, bagCost, dA, dL, dLSlot, d = unpack(currentDurability);
if (ns.profile[name].inBroker=="costs") then
obj.text = ns.GetCoinColorOrTextureString(name,repairCosts)
else
d = floor((ns.profile[name].lowestItem) and dL or dA);
if (ns.profile[name].inBroker=="percent") then
obj.text = C(colorSets(d)or "blue",d.."%");
elseif (ns.profile[name].inBroker=="percent/costs") then
obj.text = C(colorSets(d)or "blue",d.."%")..", "..ns.GetCoinColorOrTextureString(name,repairCosts);
elseif (ns.profile[name].inBroker=="costs/percent") then
obj.text = ns.GetCoinColorOrTextureString(name,repairCosts)..", "..C(colorSets(d) or "blue",d.."%");
end
end
end
local function nsItems2Callback()
local repairCost,durabilitySum,lowest,tbl,slot,bag = {bags=0,inv=0},{current=0,max=0,count=0},{1,false};
for sharedSlot in pairs(ns.items.equip)do
local tbl = sharedSlot<0 and "inv" or "bags";
local obj = ns.items.bySlot[sharedSlot];
local durability, durabilityMax = 0,0;
if obj and obj.equip then
local d,dM;
if tbl=="inv" then
d,dM = GetInventoryItemDurability(obj.slot);
else
d,dM = (C_Container and C_Container.GetContainerItemDurability or GetContainerItemDurability)(obj.bag,obj.slot);
end
durability, durabilityMax = d or 0, dM or 0;
end
if obj and obj.equip and durabilityMax>0 then
durabilitySum.count = durabilitySum.count+1;
durabilitySum.current = durabilitySum.current + durability;
durabilitySum.max = durabilitySum.max + durabilityMax;
local percentage = durability/durabilityMax;
if percentage<1 then
if tbl=="inv" and percentage<lowest[1] then
lowest = {percentage,obj.slot};
end
local itemRepairCost = 0;
if C_TooltipInfo then -- api changed since dragonflight
local hasItem
if tbl=="inv" then
hasItem = C_TooltipInfo.GetInventoryItem("player",obj.slot);
else
hasItem = C_TooltipInfo.GetBagItem(obj.bag,obj.slot);
end
if type(hasItem)=="table" then
if hasItem.args then
TooltipUtil.SurfaceArgs(hasItem);
end
if hasItem.repairCost then
itemRepairCost = hasItem.repairCost;
end
end
else -- prev api and classic; need tooltip to get item repair costs
local data = {type=tbl=="bags" and "bag" or "inventory",slot=obj.slot,bag=obj.bag};
ns.ScanTT.query(data,true);
itemRepairCost = tonumber(data.repairCost) or 0;
end
repairCost[tbl] = repairCost[tbl] + itemRepairCost;
end
end
end
local avPercentage = 1;
if durabilitySum.max>0 then
avPercentage = durabilitySum.current/durabilitySum.max;
end
local total = repairCost.bags+repairCost.inv;
if merchant.repair then
total = GetRepairAllCost() or 0;
end
currentDurability = {total, repairCost.inv, repairCost.bags, avPercentage*100, lowest[1]*100, lowest[2]};
updateBroker();
end
local function lastRepairs_add(cost,fund,repairType)
local t = {};
table.insert(last_repairs,1,{time(),cost,(fund==true),(repairType==true)});
for i,v in ipairs(last_repairs) do
if (#t<50) then table.insert(t,v); end
end
last_repairs = t;
if (ns.profile[name].saveCosts) then
ns.toon[name] = t;
end
end
local function AutoRepairAll(costs)
local chat = ns.profile[name].chatRepairInfo;
if (ns.profile[name].autorepairbyguild==true) and (IsInGuild()==true) and (CanGuildBankRepair()==true) and (costs < GetGuildBankWithdrawMoney()) then
if (not GetGuildInfoText():find("%[noautorepair%]")) then -- auto repair with guild fund allowed by guild leader?
merchant = {repair=false,costs=0,diff=0,single=0}; -- must be changed befor Repair all items
RepairAllItems(true);
lastRepairs_add(costs,true,true);
if (chat) then
ns:print(L["Automatically repaired with guild money"]..HEADER_COLON,ns.GetCoinColorOrTextureString(name,costs,{color="white"}));
end
return true;
elseif (chat) then
ns:print(L["AutoRepair"],L["Your guild leadership denied the use of guild money for auto repair."],L["Try fallback to player money."]);
end
end
if (costs < GetMoney()) then
merchant = {repair=false,costs=0,diff=0,single=0}; -- must be changed befor Repair all items
RepairAllItems();
lastRepairs_add(costs,nil,true);
if (chat) then
ns:print(L["Automatically repaired with player money"]..HEADER_COLON,ns.GetCoinColorOrTextureString(name,costs,{color="white"}));
end
return nil;
end
return false;
end
local function createTooltip(tt)
if not (tt and tt.key and tt.key==ttName) then return end -- don't override other LibQTip tooltips...
if tt.lines~=nil then tt:Clear(); end
local repairCost, equipCost, bagCost, durabilityA, durabilityL, durabilityLslot = unpack(currentDurability);
local repairCostN = repairCost;
local reputation = UnitReaction("npc", "player");
if discount[reputation] and ns.client_version>=2 then
repairCostN = floor(repairCost/discount[reputation]);
end
durabilityA = floor(durabilityA);
durabilityL = floor(durabilityL);
local a,g,d = ns.profile[name].autorepair, ns.profile[name].autorepairbyguild;
local lst = setmetatable({},{__call = function(t,a) rawset(t,#t+1,a) end});
lst({sep={3,0,0,0,0}});
lst({c1=C("ltblue",gsub(REPAIR_COST,HEADER_COLON,"")),c2=ns.GetCoinColorOrTextureString(name,repairCost,{inTooltip=true})});
lst({sep={1}});
lst({c1=CHARACTER,c2=ns.GetCoinColorOrTextureString(name,equipCost,{inTooltip=true})});
lst({c1=L["Bags"],c2=ns.GetCoinColorOrTextureString(name,bagCost,{inTooltip=true})});
if ns.profile[name].showDiscount and ns.client_version>=2 then
lst({sep={3,0,0,0,0}});
lst({c0=C("ltblue",L["Reputation discounts"])});
lst({sep={1}});
lst({c1=C("white",FACTION_STANDING_LABEL4), c2=ns.GetCoinColorOrTextureString(name,repairCostN,{inTooltip=true})});
lst({c1=C("white",FACTION_STANDING_LABEL5), c2=ns.GetCoinColorOrTextureString(name,ceil(repairCostN * discount[5]),{inTooltip=true})});
lst({c1=C("white",FACTION_STANDING_LABEL6), c2=ns.GetCoinColorOrTextureString(name,ceil(repairCostN * discount[6]),{inTooltip=true})});
lst({c1=C("white",FACTION_STANDING_LABEL7), c2=ns.GetCoinColorOrTextureString(name,ceil(repairCostN * discount[7]),{inTooltip=true})});
lst({c1=C("white",FACTION_STANDING_LABEL8), c2=ns.GetCoinColorOrTextureString(name,ceil(repairCostN * discount[8]),{inTooltip=true})});
end
if (ns.profile[name].listCosts) then
lst({sep={3,0,0,0,0}});
if (ns.profile[name].saveCosts) then
lst({c0=C("ltblue",L["Last %d repair costs"]:format(ns.profile[name].maxCosts))});
else
lst({c1=C("ltblue",L["Last %d repair costs"]:format(ns.profile[name].maxCosts)),c2=C("ltblue",L["(session only)"])});
end
lst({sep={1}});
if (#last_repairs>0) then
local indicator = "";
for i,v in ipairs(last_repairs) do
if (i<=tonumber(ns.profile[name].maxCosts)) then
indicator = ((v[4]) and "a" or "") .. ((v[3]) and "G" or "P");
lst({c1=date(date_format,v[1]) .. (strlen(indicator)>0 and " "..indicator or ""), c2=ns.GetCoinColorOrTextureString(name,ceil(v[2]),{inTooltip=true})});
end
end
else
lst({c0=L["No data found"]});
end
end
tt:AddHeader(C("dkyellow",DURABILITY));
tt:AddSeparator();
local slotName = "";
if (durabilityLslot) and (durabilityLslot~=0) then
if (slotNames[durabilityLslot]) then
slotName = (" (%s)"):format(slotNames[durabilityLslot]);
end
end
tt:AddLine(L["Lowest item"]..slotName, C(colorSets(durabilityL) or "blue", durabilityL.."%"));
tt:AddLine(GMSURVEYRATING3, C(colorSets(durabilityA) or "blue", durabilityA.."%"));
for i,v in ipairs(lst) do
if (v.sep~=nil) then
tt:AddSeparator(unpack(v.sep));
elseif (v.c0~=nil) then
local l,c = tt:AddLine();
tt:SetCell(l,1,v.c0,nil,nil,2);
if (v.f0~=nil) then
tt:SetCellScript(l,1,"OnMouseUp",v.f0);
end
else
local l,c = tt:AddLine();
tt:SetCell(l,1,v.c1);
tt:SetCell(l,2,v.c2);
end
end
if (ns.profile.GeneralOptions.showHints) then
tt:AddSeparator(4,0,0,0,0);
ns.ClickOpts.ttAddHints(tt,name);
end
ns.roundupTooltip(tt);
end
-- module functions and variables --
------------------------------------
module = {
events = {
"PLAYER_LOGIN",
"PLAYER_DEAD",
"PLAYER_REGEN_ENABLED",
"MERCHANT_CLOSED",
"MERCHANT_SHOW",
"PLAYER_MONEY",
"CHAT_MSG_MONEY"
},
config_defaults = {
enabled = false,
inBroker = "percent",
colorSet = "set1",
autorepair = false,
autorepairbyguild = false,
listCosts = true,
saveCosts = true,
maxCosts = 5,
dateFormat = "%Y-%m-%d %H:%M",
showDiscount = true,
lowestItem = true,
chatRepairInfo = false
},
clickOptionsRename = {
["charinfo"] = "1_open_character_info",
["menu"] = "2_open_menu"
},
clickOptions = {
["charinfo"] = "CharacterInfo", -- _LEFT
["menu"] = "OptionMenuCustom"
}
};
ns.ClickOpts.addDefaults(module,{
charinfo = "_LEFT",
menu = "_RIGHT"
});
function module.options()
return {
broker = {
lowestItem={ type="toggle", order=1, name=L["Lowest durability"], desc=L["Display the lowest item durability in broker."] },
inBroker={ type="select", order=2, name=L["Broker format"], desc=L["Choose your favorite display format for the broker button."],
values={
["percent"]="54%",
["costs"]="34.23.01",
["costs/percent"]="32.27.16, 54%",
["percent/costs"]="54%, 32.27.16"
}
},
},
tooltip = {
showDiscount={ type="toggle", order=1, name=L["Show discount"], desc=L["Show list of reputation discounts in tooltip"], hidden=ns.IsClassicClient },
dateFormat={ type="select", order=2, name=L["Date format"], desc=L["Choose the date format if used in the list of repair costs"], values=date_formats },
},
misc = {
colorSet={ type="select", order=1, name=L["Percent color set"], desc=L["Choose your favorite color set in which the percent text in broker should be displayed."], values=colorSets.values, width="double" },
header={ type="header", order=2, name=L["Repair options"] },
autorepair={ type="toggle", order=4, name=L["Enable auto repair"], desc=L["Automatically repair your equipment on opening a merchant with repair option."] },
autorepairbyguild={ type="toggle", order=5, name=L["Use guild money"], desc=function() return L["Use guild money on auto repair if you can"].. ( (GetGuildInfoText():find("%[noautorepair%]")) and "|n"..C("red",L["Your guild leadership denied the use of guild money for auto repair."]) or ""); end, --[[disabled=function() return (GetGuildInfoText():find("%[noautorepair%]")); end]] },
chatRepairInfo={ type="toggle", order=6, name=L["Repair info"], desc=L["Post repair actions in chatframe"] },
listCosts={ type="toggle", order=7, name=L["List of repair costs"], desc=L["Display a list of the last repair costs in tooltip"] },
saveCosts={ type="toggle", order=8, name=L["Save repair costs"], desc=L["Save the list of repair costs over the session"] },
maxCosts={ type="range", order=9, name=L["Max. list entries"], desc=L["Choose how much entries the list of repair costs can have."], min=1, max=50, step=1 },
},
},
{
dateFormat=true,
colorSet=true,
autorepair=true,
autorepairbyguild=true
}
end
function module.OptionMenu(self,button,modName)
if (tt~=nil) and (tt:IsShown()) then ns.hideTooltip(tt); end
ns.EasyMenu:InitializeMenu();
ns.EasyMenu:AddConfig(name);
ns.EasyMenu:AddEntry({ separator = true });
ns.EasyMenu:AddEntry({
label = L["Reset last repairs"],
colorName = "yellow",
func = function()
wipe(last_repairs);
wipe(ns.toon[name]);
end,
disabled = (false)
});
ns.EasyMenu:ShowMenu(self);
end
function module.init()
colorSets.set1 = {[20]="red",[40]="orange",[99]="yellow",[100]="green"};
colorSets.set2 = {[15]="red",[40]="orange",[70]="yellow",[100]="white"};
colorSets.set3 = {[20]="red",[40]="orange",[60]="yellow",[99]="green",[100]="ltblue"};
colorSets.set4 = {[15]="red",[40]="orange",[60]="yellow",[80]="green",[100]="white"};
date_format = ns.profile[name].dateFormat;
if (ns.toon[name]==nil) then
ns.toon[name] = {};
end
if (ns.profile[name].saveCosts) then
last_repairs = ns.toon[name];
end
MerchantRepairAllButton:HookScript("OnClick",function(self,button)
module.onevent({},"BE_EVENT_REPAIRALL_PLAYER");
end);
MerchantGuildBankRepairButton:HookScript("OnClick",function(self,button)
module.onevent({},"BE_EVENT_REPAIRALL_GUILD");
end);
ns.items.RegisterCallback(name,nsItems2Callback,"equip");
end
function module.onevent(self,event,arg1)
if event=="BE_UPDATE_CFG" then
if arg1 and arg1:find("^ClickOpt") then
ns.ClickOpts.update(name);
return;
end
date_format = ns.profile[name].dateFormat;
end
if event=="MERCHANT_SHOW" then
local costs, canRepair = GetRepairAllCost();
if (costs>0) and (canRepair) then
merchant.repair=true;
merchant.costs=costs;
if (ns.profile[name].autorepair) then
if (AutoRepairAll(costs)==false) and (ns.profile[name].chatRepairInfo) then
ns:print(L["AutoRepair"], L["Automatically repair failed. Not enough money..."]);
end
end
end
elseif ns.eventPlayerEnteredWorld then
-- RepairAll - ButtonHooks - custom events
if (event=="BE_EVENT_REPAIRALL_GUILD") then
lastRepairs_add(merchant.costs,true);
if (ns.profile[name].chatRepairInfo) then
ns:print(L["RepairAll"],L["by guild fund"]..HEADER_COLON,ns.GetCoinColorOrTextureString(name,merchant.costs,{color="white"}));
end
merchant.costs=0;
elseif (event=="BE_EVENT_REPAIRALL_PLAYER") then
lastRepairs_add(merchant.costs);
if (ns.profile[name].chatRepairInfo) then
ns:print(L["RepairAll"],L["by player money"]..HEADER_COLON,ns.GetCoinColorOrTextureString(name,merchant.costs,{color="white"}));
end
merchant.costs=0;
end
if (merchant.repair) then
if (InRepairMode()) and (merchant.costs>0) and (event=="PLAYER_MONEY") then
local costs = GetRepairAllCost();
merchant.diff = merchant.costs-costs;
if (merchant.diff>0) then
merchant.costs = costs;
merchant.single = merchant.single + merchant.diff; -- single item repair mode, step 1
end
end
if (event=="MERCHANT_CLOSED") then
if (merchant.single>0) then -- single item repair mode, step 2
lastRepairs_add(merchant.single, nil, false);
if (ns.profile[name].chatRepairInfo) then
ns:print(L["SingleRepairSummary"]..HEADER_COLON,ns.GetCoinColorOrTextureString(name,merchant.single,{color="white"}));
end
end
merchant = {repair=false,costs=0,diff=0,single=0};
end
end
end
end
-- function module.onclick(self,button) end
-- function module.onmousewheel(self,direction) end
-- function module.optionspanel(panel) end
-- function module.ontooltip(tt) end
-- function module.ondblclick(self,button) end
function module.onenter(self)
if (ns.tooltipChkOnShowModifier(false)) then return; end
tt = ns.acquireTooltip({ttName, 2, "LEFT", "RIGHT"},{true},{self});
createTooltip(tt);
end
-- function module.onleave(self) end
-- final module registration --
-------------------------------
ns.modules[name] = module;