diff --git a/Debug.lua b/Debug.lua new file mode 100644 index 0000000..b8c6587 --- /dev/null +++ b/Debug.lua @@ -0,0 +1,228 @@ +if true then return end +--@do-not-package@ +local me, ns = ... +local addon=ns.addon --#addon +local L=ns.L +local D=ns.D +local C=ns.C +local AceGUI=ns.AceGUI +local _G=_G +local pp=print +_G.GAC=addon + +--- Enable a trace for every function call. It's a VERY heavy debug +-- +if ns.HD then +local memorysinks={} +local callstack={} +local lib=LibStub("LibInit") +for k,v in pairs(addon) do + if (type(v))=="function" and not lib[k] then + local wrapped + do + local original=addon[k] + wrapped=function(...) + pp(k) + tinsert(callstack,k) + local membefore=GetAddOnMemoryUsage("GarrisonCommander") + local a1,a2,a3,a4,a5,a6,a7,a8,a9=original(...) + local memafter=GetAddOnMemoryUsage("GarrisonCommander") + tremove(callstack) + memorysinks[k].mem=memorysinks[k].mem+memafter-membefore + memorysinks[k].calls=memorysinks[k].calls+1 + if (#callstack) then + memorysinks[k].callers=strjoin("->",unpack(callstack)) + else + memorysinks[k].callers="main" + end + if (memafter-membefore > 20) then + pp(C(k,'Red'),'used ',memafter-membefore) + end + return a1,a2,a3,a4,a5,a6,a7,a8,a9 + end + end + addon[k]=wrapped + memorysinks[k]={mem=0,calls=0,callers=""} + end +end +function addon:ResetSinks() + for k,v in pairs(memorysinks) do + memorysinks[k].mem=0 + memorysinks[k].calls=0 + end +end +local sorted={} +function addon:DumpSinks() + local scroll=self:GetScroller("Sinks",nil,400,1000) + wipe(sorted) + for k,v in pairs(memorysinks) do + if v.mem then + tinsert(sorted,format("Mem %06d (calls: %03d) Mem per call:%03.2f Callstack:%s(%s)",v.mem,v.calls,v.mem/v.calls,C(k,"Orange"),v.callers)) + end + end + table.sort(sorted,function(a,b) return a>b end) + self:cutePrint(scroll,sorted) +end +end +function addon:GetScroller(title,type,h,w) + h=h or 800 + w=w or 400 + type=type or "Frame" + local scrollerWindow=AceGUI:Create("Frame") + scrollerWindow:SetTitle(title) + scrollerWindow:SetLayout("Fill") + --local scrollcontainer = AceGUI:Create("SimpleGroup") -- "InlineGroup" is also good + --scrollcontainer:SetFullWidth(true) + --scrollcontainer:SetFullHeight(true) -- probably? + --scrollcontainer:SetLayout("Fill") -- important! + --scrollerWindow:AddChild(scrollcontainer) + local scroll = AceGUI:Create("ScrollFrame") + scroll:SetLayout("Flow") -- probably? + scroll:SetFullWidth(true) + scroll:SetFullHeight(true) + scrollerWindow:AddChild(scroll) + scrollerWindow:SetCallback("OnClose","Release") + scrollerWindow:SetHeight(h) + scrollerWindow:SetWidth(w) + scrollerWindow:SetPoint("CENTER") + scrollerWindow:Show() + scroll.AddRow=function (self,...) return addon:AddRow(self,...) end + return scroll +end +function addon:AddRow(obj,text,...) +--[===[@debug@ + assert(obj) +--@end-debug@]===] + if (obj) then + local l=AceGUI:Create("Label") + l:SetText(text) + l:SetColor(...) + l:SetFullWidth(true) + obj:AddChild(l) + end +end +function addon:cutePrint(scroll,level,k,v) + if (type(level)=="table") then + for k,v in pairs(level) do + self:cutePrint(scroll,"",k,v) + end + return + end + if (type(v)=="table") then + self:AddRow(scroll,level..C(k,"Azure")..":" ..C("Table","Orange")) + for kk,vv in pairs(v) do + self:cutePrint(scroll,level .. " ",kk,vv) + end + else + if (type(v)=="string" and v:sub(1,2)=='0x') then + v=v.. " " ..tostring(self:GetFollowerData(v,'name')) + end + self:AddRow(scroll,level..C(k,"White")..":" ..C(v,"Yellow")) + end +end +function addon:DumpFollower(name) + local follower=self:GetFollowerData(name) + if (follower) then + local scroll=self:GetScroller(follower.name) + self:cutePrint(scroll,follower) + end + +end +function addon:DumpStatus(title) + local scroll=self:GetScroller(title) + for i=1,#followersCache do + local followerID=followersCache[i].followerID + scroll:AddRow(format("%s (%s): %d",self:GetFollowerData(followerID,'fullname'),self:GetFollowerData(followerID,'followerID'),G.GetFollowerXP(followerID))) + end + scroll:AddRow("Garrison resources: " .. select(2,GetCurrencyInfo(GARRISON_CURRENCY))) + scroll:AddRow("Money: " .. GetMoneyString(GetMoney())) +end +function addon:DumpFollowers() + local scroll=self:GetScroller("Followers Cache (" .. #followersCache ..")" ) + self:cutePrint(scroll,followersCache) +end +function addon:DumpFollowerMissions(missionID) + local scroll=self:GetScroller("FollowerMissions " .. self:GetMissionData(missionID,'name')) + self:cutePrint(scroll,followerMissions.missions[missionID]) +end +function addon:DumpIgnored() + local scroll=self:GetScroller("Ignored") + self:cutePrint(scroll,self.privatedb.profile.ignored) +end +function addon:DumpMission(missionID) + local scroll=self:GetScroller("MissionCache " .. self:GetMissionData(missionID,'name')) + self:cutePrint(scroll,cache.missions[missionID]) +end +function addon:DumpMissions() + local scroll=self:GetScroller("MissionCache") + for id,data in pairs(cache.missions) do + self:cutePrint(scroll,id .. '.'..data.name) + end +end +--- +-- Debug function +--@param missionID Identificativo missione +function addon:DumpCounters(missionID) + local scroll=self:GetScroller("Counters " .. self:GetMissionData(missionID,'name')) + self:cutePrint(scroll,counters[missionID]) + self:cutePrint(scroll,"Lista per follower","","") + self:cutePrint(scroll,counterFollowerIndex[missionID]) + self:cutePrint(scroll,"Lista per threat","","") + self:cutePrint(scroll,counterThreatIndex[missionID]) +end +function addon:Dump(title,data) + local scroll=self:GetScroller(title) + self:cutePrint(scroll,data) + return scroll +end +function addon:DumpCounterers(missionID) + local scroll=self:GetScroller("Counterers " .. self:GetMissionData(missionID,'name')) + self:cutePrint(scroll,cache.missions[missionID].counterers) +end +function addon:DumpParty(missionID) + local scroll=self:GetScroller("Party " .. self:GetMissionData(missionID,'name')) + self:cutePrint(scroll,parties[missionID]) +end +function addon:DumpAgeDb() + local t=new() + for i,v in pairs(dbcache.seen) do + tinsert(t,format("%80s %s %d",self:GetMissionData(i,'name'),date("%d/%m/%y %H:%M:%S",v),ns.wowhead[i])) + end + local scroll=self:GetScroller("Expire db") + self:cutePrint(scroll,t) + del(t) +end +_G.GCF=GCF +_G.MW=173 +--[[ +PlaySound("UI_Garrison_CommandTable_Open"); + PlaySound("UI_Garrison_CommandTable_Close"); + PlaySound("UI_Garrison_Nav_Tabs"); + PlaySound("UI_Garrison_Nav_Tabs"); + PlaySound("UI_Garrison_CommandTable_SelectMission"); + PlaySound("UI_Garrison_CommandTable_IncreaseSuccess"); + PlaySound("UI_Garrison_CommandTable_100Success"); + PlaySound("UI_Garrison_CommandTable_ReducedSuccessChance"); + PlaySound("UI_Garrison_Mission_Threat_Countered"); + PlaySoundKitID(43507); -- 100% chance reached + PlaySound("UI_Garrison_CommandTable_AssignFollower"); + PlaySound("UI_Garrison_CommandTable_UnassignFollower"); + PlaySound("UI_Garrison_Mission_Threat_Countered"); + PlaySound("UI_Garrison_CommandTable_MissionStart"); + PlaySound("UI_Garrison_CommandTable_ViewMissionReport"); + PlaySound("UI_Garrison_Mission_Complete_Encounter_Chance"); + PlaySound("UI_Garrison_CommandTable_Nav_Next"); + PlaySound("UI_Garrison_CommandTable_ChestUnlock_Gold_Success"); + PlaySound("UI_Garrison_Mission_Threat_Countered"); + PlaySound("UI_Garrison_MissionEncounter_Animation_Generic"); + PlaySoundKitID(currentAnim.castSoundID); + PlaySoundKitID(currentAnim.impactSoundID); + PlaySound("UI_Garrison_Mission_Complete_Encounter_Fail"); + PlaySound("UI_Garrison_Mission_Complete_Mission_Success"); + PlaySound("UI_Garrison_CommandTable_MissionSuccess_Stinger"); + PlaySound("UI_Garrison_Mission_Complete_MissionFail_Stinger"); + PlaySound("UI_Garrison_CommandTable_ChestUnlock"); + PlaySound("UI_Garrison_CommandTable_Follower_LevelUp"); + +--]] +--@end-do-not-package@ diff --git a/FollowerCache.lua b/FollowerCache.lua new file mode 100644 index 0000000..ff9f9df --- /dev/null +++ b/FollowerCache.lua @@ -0,0 +1,133 @@ +local me,ns=... +local addon=ns.addon --#addon +local holdEvents,releaseEvents=addon.holdEvents,addon.releaseEvents +local xdump=ns.xdump +--upvalue +local C=ns.C +local G=C_Garrison +local GMF=GarrisonMissionFrame +local type=type +local select=select +local pairs=pairs +local tonumber=tonumber +local tinsert=tinsert +local Mbase = GarrisonMissionFrameFollowers +local GARRISON_FOLLOWER_MAX_UPGRADE_QUALITY=GARRISON_FOLLOWER_MAX_UPGRADE_QUALITY +local GARRISON_FOLLOWER_MAX_LEVEL=GARRISON_FOLLOWER_MAX_LEVEL +local format=format +local tostring=tostring +local GetItemInfo=GetItemInfo +local index={} +local sorted={} +local function keyToIndex(key) + if (not Mbase.followers or not next(Mbase.followers)) then + Mbase.dirtyList=false + Mbase.followers = G.GetFollowers(); + end + local idx=key and index[key] or nil + if (idx and idx <= #Mbase.followers) then + if Mbase.followers[idx].followerID==key then + return idx + else + idx=nil + end + end + wipe(index) + wipe(sorted) + for i=1,#Mbase.followers do + if Mbase.followers[i].isCollected then + index[Mbase.followers[i].followerID]=i + tinsert(sorted,i) + if Mbase.followers[i].followerID==key then + idx=i + end + end + end + return idx +end +local maxrank=GARRISON_FOLLOWER_MAX_UPGRADE_QUALITY*1000+GARRISON_FOLLOWER_MAX_LEVEL +local function AddExtraData(follower,refreshrank) + follower.rank=follower.level < GARRISON_FOLLOWER_MAX_LEVEL and follower.level or follower.iLevel + follower.qLevel=follower.quality*1000+follower.level + follower.coloredname=C(follower.name,tostring(follower.quality)) + follower.fullname=format("%3d %s",follower.rank,follower.coloredname) + follower.maxed=follower.qLevel>=maxrank + local weaponItemID, weaponItemLevel, armorItemID, armorItemLevel = G.GetFollowerItems(follower.followerID); + follower.weaponItemID=weaponItemID + follower.weaponItemLevel=weaponItemLevel + follower.armorItemID=armorItemID + follower.armorItemLevel=armorItemLevel + follower.weaponQuality=select(3,GetItemInfo(weaponItemID)) + follower.armorQuality=select(3,GetItemInfo(armorItemID)) + follower.abilities=G.GetFollowerAbilities(follower.followerID) +end +function addon:FollowerCacheInit() + GarrisonFollowerList_UpdateFollowers(Mbase) +end +function addon:CanCounter(followerID,id) + local abilities=self:GetFollowerData(followerID,'abilities') + for i=1,#abilities do + local ability=abilities[i] + for k,v in pairs(ability.counter) do + if (k==trait or v.name==trait) then + return true + end + end + end +end +function addon:HasTrait(followerID,trait) + local abilities=self:GetFollowerData(followerID,'abilities') + for i=1,#abilities do + local ability=abilities[i] + if ability.isTrait then + if ability.ID==trait then + return true + end + end + end +end +function addon:GetFollowerData(followerID,key,default) + local idx=keyToIndex(followerID) + local follower=Mbase.followers[idx] + if (not follower) then + ns.dprint("Not found",followerID,key,"at",idx,"len",#Mbase.followers) + end + if (key==nil) then + return follower + end + if (type(follower[key])~='nil') then + return follower[key] + end + AddExtraData(follower) + return follower[key] or default +end +local sorters={} +sorters.leveldesc = function(a,b) + return (Mbase.followers[a].iLevel * 10 + Mbase.followers[a].level) > (Mbase.followers[b].iLevel * 10 + Mbase.followers[b].level) +end +sorters.levelasc = function(a,b) + return (Mbase.followers[a].iLevel * 10 + Mbase.followers[a].level) < (Mbase.followers[b].iLevel * 10 + Mbase.followers[b].level) +end + + +---@function +-- Iterator function +-- @param func type of sorting (can be mitted if we dont care) +-- +function addon:GetFollowerIterator(func) + keyToIndex() + if (func) then + table.sort(sorted,sorters[func]) + end + local f=Mbase.followers + return function(sorted,i) + i=i+1 + local x = sorted[i] + if x then + local v=f[x] and f[x].followerID or nil + if v then + return i,v + end + end + end,sorted,0 +end \ No newline at end of file diff --git a/FollowerPage.lua b/FollowerPage.lua new file mode 100644 index 0000000..e69de29 diff --git a/FollowerRecruiting.lua b/FollowerRecruiting.lua new file mode 100644 index 0000000..e69de29 diff --git a/GarrisonCommander-Broker/ldb.lua b/GarrisonCommander-Broker/ldb.lua index 964440d..824735a 100644 --- a/GarrisonCommander-Broker/ldb.lua +++ b/GarrisonCommander-Broker/ldb.lua @@ -1,15 +1,26 @@ local me, ns = ... if (not LibStub:GetLibrary("LibDataBroker-1.1",true)) then - --@debug@ + --[===[@debug@ print("Missing libdatabroker") - --@end-debug@ + --@end-debug@]===] return end if (LibDebug) then LibDebug() end local L=LibStub("AceLocale-3.0"):GetLocale(me,true) local addon=LibStub("AceAddon-3.0"):NewAddon(me,"AceTimer-3.0","AceEvent-3.0") local dataobj +local SecondsToTime=SecondsToTime +local type=type +local strsplit=strsplit +local tonumber=tonumber +local tremove=tremove +local time=time +local tinsert=tinsert local G=C_Garrison +local NONE=NONE +local DONE=DONE +local format=format +local table=table function addon:ldbCleanup() local now=time() for i=1,#self.db.realm.missions do @@ -26,15 +37,17 @@ function addon:ldbCleanup() end function addon:ldbUpdate() local now=time() + local completed=0 for i=1,#self.db.realm.missions do local t,missionID,pc=strsplit('.',self.db.realm.missions[i]) t=tonumber(t) or 0 if t>now then local duration=t-now local duration=duration < 60 and duration or math.floor(duration/60)*60 - dataobj.text=format("Next mission on |cff20ff20%s|r in %s",pc,SecondsToTime(duration)) + dataobj.text=format("Next mission on |cff20ff20%s|r in %s (%d completed)",pc,SecondsToTime(duration),completed) return end + completed=completed+1 end dataobj.text=NONE end @@ -90,8 +103,8 @@ end function dataobj:OnLeave() GameTooltip:Hide() end ---@debug@ +--[===[@debug@ _G.GACDB=addon ---@end-debug@ +--@end-debug@]===] --function dataobj:OnClick(button) --end diff --git a/GarrisonCommander.lua b/GarrisonCommander.lua index 8c59f4d..09a1795 100644 --- a/GarrisonCommander.lua +++ b/GarrisonCommander.lua @@ -1,27 +1,15 @@ local me, ns = ... -ns.me=GetUnitName("player",true) +local addon=ns.addon --#addon +local L=ns.L +local D=ns.D +local C=ns.C +local P=ns.party +local AceGUI=ns.AceGUI +local xprint=ns.xprint local _G=_G local pp=print local HD=false ---@debug@ - LoadAddOn("Blizzard_DebugTools") ---@end-debug@ -local addon=LibStub("LibInit"):NewAddon(me,'AceHook-3.0','AceTimer-3.0','AceEvent-3.0','AceBucket-3.0') --#Addon -local AceGUI=LibStub("AceGUI-3.0") -local D=LibStub("LibDeformat-3.0") -local C=addon:GetColorTable() -local L=addon:GetLocale() -local print=addon:Wrap("Print") -local dprint=print -local trace=addon:Wrap("Trace") -local xprint=function() end -local xdump=function() end -local xtrace=function() end ---@debug@ ---xprint=function(...) print("DBG",...) end ---xdump=function(d,t) print(t) DevTools_Dump(d) end ---xtrace=trace ---@end-debug@ +local print=ns.print local pairs=pairs local select=select local next=next @@ -36,7 +24,6 @@ local wipe=wipe local format=format local tostring=tostring local collectgarbage=collectgarbage -local bigscreen=true local GMM=false local MP=false local MPGoodGuy=false @@ -47,6 +34,10 @@ local pin=false local baseHeight local minHeight if (LibDebug) then LibDebug() end +ns.bigscreen=true +-- Blizzard functions override support +local orig={} --#originals +local over={} --#overridden local backdrop = { --bgFile="Interface\\TutorialFrame\\TutorialFrameBackground", bgFile="Interface\\DialogFrame\\UI-DialogBox-Background-Dark", @@ -73,63 +64,12 @@ local function tcopy(obj, seen) for k, v in pairs(obj) do res[tcopy(k, s)] = tcopy(v, s) end return res end ------------------------------------------------------------------ --- Recycling function from ACE3 + +local parties -local missionautocompleting local lastTab=1 -local new, del, copy -do - --@debug@ - local newcount, delcount,createdcount,cached = 0,0,0 - --@end-debug@ - local pool = setmetatable({},{__mode="k"}) - function new() - --@debug@ - newcount = newcount + 1 - --@end-debug@ - local t = next(pool) - if t then - pool[t] = nil - return t - else - --@debug@ - createdcount = createdcount + 1 - --@end-debug@ - return {} - end - end - function copy(t) - local c = new() - for k, v in pairs(t) do - c[k] = v - end - return c - end - function del(t) - --@debug@ - delcount = delcount + 1 - --@end-debug@ - wipe(t) - pool[t] = true - end - --@debug@ - function cached() - local n = 0 - for k in pairs(pool) do - n = n + 1 - end - return n - end - function addon:CacheStats() - print("Created:",createdcount) - print("Aquired:",newcount) - print("Released:",delcount) - print("Cached:",cached()) - end - --@end-debug@ -end +local new, del, copy =ns.new,ns.del,ns.copy local function capitalize(s) s=tostring(s) @@ -160,6 +100,8 @@ local GARRISON_MISSION_PERCENT_CHANCE="%d%%"-- GARRISON_MISSION_PERCENT_CHANCE --local GARRISON_CURRENCY=GARRISON_CURRENCY --824 --local GARRISON_FOLLOWER_MAX_UPGRADE_QUALITY=GARRISON_FOLLOWER_MAX_UPGRADE_QUALITY -- 4 --local GARRISON_FOLLOWER_MAX_LEVEL=GARRISON_FOLLOWER_MAX_LEVEL -- 100 +local GARRISON_CURRENCY=GARRISON_CURRENCY +local GetMoneyString=GetMoneyString local SHORTDATE=SHORTDATE.. " %s" local LEVEL=LEVEL -- Level local MISSING=ADDON_MISSING @@ -180,7 +122,7 @@ local GMFMissionListButtons=GMF.MissionTab.MissionList.listScroll.buttons local GarrisonFollowerTooltip=GarrisonFollowerTooltip local GarrisonMissionFrameMissionsListScrollFrame=GarrisonMissionFrameMissionsListScrollFrame local IGNORE_UNAIVALABLE_FOLLOWERS=IGNORE.. ' ' .. UNAVAILABLE -local IGNORE_UNAIVALABLE_FOLLOWERS_DETAIL=IGNORE.. ' ' .. GARRISON_FOLLOWER_INACTIVE .. ',' .. GARRISON_FOLLOWER_ON_MISSION ..',' .. GARRISON_FOLLOWER_WORKING.. ' ' .. GARRISON_FOLLOWERS +local IGNORE_UNAIVALABLE_FOLLOWERS_DETAIL= GARRISON_FOLLOWER_ON_MISSION ..',' .. GARRISON_FOLLOWER_WORKING .. ' ' .. GARRISON_FOLLOWERS .. '. ' .. GARRISON_FOLLOWER_INACTIVE .. " are always ignored" local PARTY=PARTY -- "Party" local SPELL_TARGET_TYPE1_DESC=capitalize(SPELL_TARGET_TYPE1_DESC) -- any local SPELL_TARGET_TYPE4_DESC=capitalize(SPELL_TARGET_TYPE4_DESC) -- party member @@ -235,18 +177,10 @@ local BIGBUTTON=BIGSIZEW-GCSIZE local SMALLBUTTON=BIGSIZEW-GCSIZE local GCF local GMC -local GMCUsedFollowers={} local GCFMissions local GCFBusyStatus local GameTooltip=GameTooltip -- Want to know what I call!! ---local GarrisonMissionButton_OnEnter=GarrisonMissionButton_OnEnter -local GarrisonFollowerList_UpdateFollowers=GarrisonFollowerList_UpdateFollowers -local GarrisonMissionList_UpdateMissions=GarrisonMissionList_UpdateMissions -local GarrisonMissionPage_ClearFollower=GarrisonMissionPage_ClearFollower -local GarrisonMissionPage_UpdateMissionForParty=GarrisonMissionPage_UpdateMissionForParty -local GarrisonMissionPage_SetFollower=GarrisonMissionPage_SetFollower -local GarrisonMissionButton_SetRewards=GarrisonMissionButton_SetRewards local GetItemInfo=GetItemInfo local type=type local ITEM_QUALITY_COLORS=ITEM_QUALITY_COLORS @@ -331,258 +265,111 @@ local function inTable(table, value) end ---- Parties storage --- --- -local parties=setmetatable({},{ - __index=function(t,k) rawset(t,k,{members={},perc=0,full=false}) return t[k] end -}) -local function inParty(missionID,followerID) - return inTable(parties[missionID].members,followerID) -end ---- Follower Missions Info --- -local followerMissions=setmetatable({},{ - __index=function(t,k) rawset(t,k,{}) return t[k] end -}) - - -local holdEvents,releaseEvents -do - local stacklevel=0 - local frames - function holdEvents() - if stacklevel==0 then - frames={GetFramesRegisteredForEvent('GARRISON_FOLLOWER_LIST_UPDATE')} - for i=1,#frames do - frames[i]:UnregisterEvent("GARRISON_FOLLOWER_LIST_UPDATE") - end - end - stacklevel=stacklevel+1 - end - function releaseEvents() - stacklevel=stacklevel-1 - assert(stacklevel>=0) - if (stacklevel==0) then - for i=1,#frames do - frames[i]:RegisterEvent("GARRISON_FOLLOWER_LIST_UPDATE") - end - frames=nil - end - end -end -- --- Temporary party management -local openParty,partyIgnore,isPartyIgnored,isInParty,pushFollower,removeFollower,fillParty,closeParty,roomInParty,storeFollowers,dumpParty,isPartyEmpty,addTrait,needTrait - -do - local ID,maxFollowers,members,ignored=0,1,{},{} - ---@function [parent=#party] openParty - function openParty(missionID,followers) - wipe(members) - maxFollowers=followers - ID=missionID - holdEvents() - end - - ---@function [parent=#party] partyIgnore - function partyIgnore(followerID,soft) - ignored[followerID]=soft and 1 or 2 - end - ---@function [parent=#party] isPartyIgnored - function isPartyIgnored(followerID) - return ignored[followerID] - end - - ---@function [parent=#party] isInParty - function isInParty(followerID) - return inTable(members,followerID) - end - - ---@function [parent=#party] roomInParty - function roomInParty() - return maxFollowers-#members - end - - ---@function [parent=#party] isPartyEmpty - function isPartyEmpty() - return maxFollowers>0 and #members==0 - end - ---@function [parent=#party] dumpParty - function dumpParty() - for i=1,3 do - if (members[i]) then - xprint(i,addon:GetFollowerData(members[i],'fullname')) - end +-- These local will became conf var +-- locally upvalued, doing my best to not interfere with other sorting modules, +-- First time i am called to verride it I save it, so I give other modules a chance to hook it, too +-- Could even do a trick and secureHook it at the expense of a double sort... +local origGarrison_SortMissions +local sorters={} +sorters.EndTime=function (mission1, mission2) + if type(mission1)~="table" or type(mission2) ~="table" then return end + if ns.toc >=60100 then + local p1=G.GetFollowerMissionTimeLeftSeconds(mission1.followers[1]) + local p2=G.GetFollowerMissionTimeLeftSeconds(mission2.followers[1]) + if (p1==p2) then + return strcmputf8i(mission1.name, mission2.name) < 0 + else + return p1 < p2 end - end - - ---@function [parent=#party] pushFollower - function pushFollower(followerID) - if (followerID:sub(1,2) ~= '0x') then trace(followerID .. "is not an id") end - if (roomInParty()>0) then - local rc,code=pcall (C_Garrison.AddFollowerToMission,ID,followerID) - if (rc and code) then - tinsert(members,followerID) - return true ---@debug@ - else - xprint("Unable to add", n[followerID],"to",ID,code) ---@end-debug@ - end + else + local running=addon.privatedb.profile.running + local p1=tonumber(running[mission1.missionID].started)+tonumber(running[mission1.missionID].duration) + local p2=tonumber(running[mission2.missionID].started)+tonumber(running[mission2.missionID].duration) + if (p1==p2) then + return strcmputf8i(mission1.name, mission2.name) < 0 + else + return p1 < p2 end end - ---@function [parent=#party] removeFollowers - function removeFollower(followerID) - for i=1,maxFollowers do - if (followerID==members[i]) then - tremove(members,i) - local rc,code=pcall(C_Garrison.RemoveFollowerFromMission,ID,followerID) ---@debug@ - if (not rc) then trace("Unable to remove", n[members[i]],"from",ID,code) end ---@end-debug@ - return true end - end +end +sorters.Chance=function (mission1, mission2) + if type(mission1)~="table" or type(mission2) ~="table" then return end + local p1=addon:GetParty(mission1.missionID) + local p2=addon:GetParty(mission2.missionID) + if (p2.full and not p1.full) then return false end + if (p1.full and not p2.full) then return true end + if (p1.perc==p2.perc) then + return strcmputf8i(mission1.name, mission2.name) < 0 + else + return p1.perc > p2.perc end - - ---@function [parent=#party] storeFollowers - function storeFollowers(table) - wipe(table) - for i=1,#members do - tinsert(table,members[i]) - end - return #table - end - ---@function [parent=#party] fillParty - function fillParty() - if roomInParty() < 1 then return end - for followerID,soft in pairs(ignored) do - if soft==1 then - if not isInParty(followerID) then - pushFollower(followerID) - end - if (roomInParty()<=0) then - break - end - end - end +end +sorters.Age=function (mission1, mission2) + if type(mission1)~="table" or type(mission2) ~="table" then return end + local p1=addon:GetMissionData(mission1.missionID,'offerEndTime') + local p2=addon:GetMissionData(mission2.missionID,'offerEndTime') + if (p1==p2) then + return strcmputf8i(mission1.name, mission2.name) < 0 + else + return p1 < p2 end - - ---@function [parent=#party] closeParty - function closeParty() - local perc=select(4,G.GetPartyMissionInfo(ID)) - for i=1,3 do - if (members[i]) then - local rc,code=pcall(C_Garrison.RemoveFollowerFromMission,ID,members[i]) ---@debug@ - if (not rc) then trace("Unable to pop", members[i]," from ",ID,code) end ---@end-debug@ - - else - break - end - end - releaseEvents() - wipe(members) - wipe(ignored) - return perc or 0 +end +sorters.Followers=function(mission1, mission2) + if type(mission1)~="table" or type(mission2) ~="table" then return end + local p1=addon:GetMissionData(mission1.missionID,'numFollowers') + local p2=addon:GetMissionData(mission2.missionID,'numFollowers') + if (p1==p2) then + return strcmputf8i(mission1.name, mission2.name) < 0 + else + return p1 < p2 end end --- ---@debug@ -local origGarrisonMissionButton_OnEnter = _G.GarrisonMissionButton_OnEnter -function _G.GarrisonMissionButton_OnEnter(this,button) - origGarrisonMissionButton_OnEnter(this,button) - GameTooltip:AddDoubleLine("ID:",this.info.missionID) - GameTooltip:Show() +sorters.Xp=function (mission1, mission2) + if type(mission1)~="table" or type(mission2) ~="table" then return end + local p1=addon:GetMissionData(mission1.missionID,'globalXp') + local p2=addon:GetMissionData(mission2.missionID,'globalXp') + if (p1==p2) then + return strcmputf8i(mission1.name, mission2.name) < 0 + else + return p2 < p1 + end end ---@end-debug@ --- These local will became conf var --- locally upvalued, doing my best to not interfere with other sorting modules, --- First time i am called to verride it I save it, so I give other modules a chance to hook it, too --- Could even do a trick and secureHook it at the expense of a double sort... -local origGarrison_SortMissions - function addon.Garrison_SortMissions_Chance(missionsList) - - local comparison - do - function comparison(mission1, mission2) - if type(mission1)~="table" or type(mission2) ~="table" then return end - local p1=parties[mission1.missionID] - local p2=parties[mission2.missionID] - if (p2.full and not p1.full) then return false end - if (p1.full and not p2.full) then return true end - if (p1.perc==p2.perc) then - return strcmputf8i(mission1.name, mission2.name) < 0 - else - return p1.perc > p2.perc - end - end - end - table.sort(missionsList, comparison); + xprint("Sorting on chance") + addon:OnAllMissions(function(missionID) addon:MatchMaker(missionID) end) + table.sort(missionsList, sorters.Chance); end function addon.Garrison_SortMissions_Age(missionsList) - local comparison - do - function comparison(mission1, mission2) - if type(mission1)~="table" or type(mission2) ~="table" then return end - local p1=parties[mission1.missionID] - local p2=parties[mission2.missionID] - if (p2.full and not p1.full) then return false end - if (p1.full and not p2.full) then return true end - local age1=tonumber(dbcache.seen[mission1.missionID]) or 0 - local age2=tonumber(dbcache.seen[mission2.missionID]) or 0 - if (age1==age2) then - return strcmputf8i(mission1.name, mission2.name) < 0 - else - return age1 < age2 - end - end - end - table.sort(missionsList, comparison); + xprint("Sorting on age") + addon:OnAllMissions(function(missionID) addon:MatchMaker(missionID) end) + table.sort(missionsList, sorters.Age); end function addon.Garrison_SortMissions_Followers(missionsList) - local comparison - do - function comparison(mission1, mission2) - if type(mission1)~="table" or type(mission2) ~="table" then return end - local p1=mission1.numFollowers - local p2=mission2.numFollowers - if (p1==p2) then - return strcmputf8i(mission1.name, mission2.name) < 0 - else - return p1 < p2 - end - end - end - table.sort(missionsList, comparison); + xprint("Sorting on followers") + addon:OnAllMissions(function(missionID) addon:MatchMaker(missionID) end) + table.sort(missionsList, sorters.Followers); end function addon.Garrison_SortMissions_Xp(missionsList) - local comparison - do - function comparison(mission1, mission2) - if type(mission1)~="table" or type(mission2) ~="table" then return end - local p1=addon:GetMissionData(mission1.missionID,'globalXp') - local p2=addon:GetMissionData(mission2.missionID,'globalXp') - if (p1==p2) then - return strcmputf8i(mission1.name, mission2.name) < 0 - else - return p2 < p1 - end - end - end - table.sort(missionsList, comparison); + xprint("Sorting on xp") + addon:OnAllMissions(function(missionID) addon:MatchMaker(missionID) end) + table.sort(missionsList, sorters.Xp); +end +function addon.Garrison_SortMissions_Original(missionsList) + xprint("Sorting on original") + addon:OnAllMissions(function(missionID) addon:MatchMaker(missionID) end) + origGarrison_SortMissions(missionsList) end function addon:OnInitialized() ---@debug@ - xprint("OnInitialized") +--[===[@debug@ + ns.xprint("OnInitialized") self.evdebug=CreateFrame("Frame") self.evdebug:SetScript("OnEvent",function(...) return print('|cffff2020event|r',...) end) ---@end-debug@ +--@end-debug@]===] + --parties=self:GetParty() for _,b in ipairs(GMFMissionsListScrollFrame.buttons) do local scale=0.8 local f,h,s=b.Title:GetFont() @@ -604,27 +391,26 @@ function addon:OnInitialized() self:AddToggle("IGM",true,IGNORE_UNAIVALABLE_FOLLOWERS,IGNORE_UNAIVALABLE_FOLLOWERS_DETAIL) self:AddToggle("IGP",true,L['Ignore "maxed"'],L["Level 100 epic followers are not used for xp only missions."]) self:AddToggle("NOFILL",false,L["No mission prefill"],L["Disables automatic population of mission page screen. You can also press control while clicking to disable it for a single mission"]) - self:AddToggle("DAYS",false,L["Show since"],L["Show esxpiration as days since first seen"]) self:AddSelect("MSORT","Garrison_SortMissions_Original", { Garrison_SortMissions_Original=L["Original method"], Garrison_SortMissions_Chance=L["Success Chance"], Garrison_SortMissions_Followers=L["Number of followers"], - Garrison_SortMissions_Age=L["Days since first seen"], + Garrison_SortMissions_Age=L["Expiration Time"], Garrison_SortMissions_Xp=L["Global approx. xp reward"], }, L["Sort missions by:"],L["Original sort restores original sorting method, whatever it was (If you have another addon sorting mission, it should kick in again)"]) - bigscreen=self:GetBoolean("BIGSCREEN") + ns.bigscreen=self:GetBoolean("BIGSCREEN") self:AddLabel("Followers Panel") self:AddSlider("MAXMISSIONS",5,1,8,L["Mission shown for follower"],nil,1) self:AddSlider("MINPERC",50,0,100,L["Minimun chance success under which ignore missions"],nil,5) self:AddToggle("ILV",true,L["Show weapon/armor level"],L["When checked, show on each follower button weapon and armor level for maxed followers"]) --self:AddPrivateAction("ShowMissionControl",L["Mission control"],L["You can choose some criteria and have GC autosumbit missions for you"]) ---@debug@ +--[===[@debug@ self:AddLabel("Developers options") self:AddToggle("DBG",false, "Enable Debug") self:AddToggle("TRC",false, "Enable Trace") ---@end-debug@ +--@end-debug@]===] self:Trigger("MSORT") return true end @@ -649,12 +435,11 @@ end function addon:CheckGMM() if (IsAddOnLoaded("GarrisonMissionManager")) then GMM=true - self:RefreshMission() + self:RefreshMissions() end end function addon:ApplyIGM(value) - self:BuildMissionsCache(false,true) - self:RefreshMission() + self:RefreshMissions() end function addon:ApplyCKMP(value) if (HD) then self:Clock() end @@ -665,7 +450,7 @@ function addon:ApplyCKMP(value) MasterPlanMissionList:Show() end end - self:RefreshMission() + self:RefreshMissions() end function addon:ApplyDBG(value) dbg=value @@ -688,10 +473,10 @@ function addon:ApplyBIGSCREEN(value) ) end function addon:ApplyIGP(value) - self:BuildMissionsCache(false,true) - self:RefreshMission() + self:RefreshMissions() end function addon:ApplyMSORT(value) + ns.xprint("Sorting by ",value) if (not origGarrison_SortMissions) then origGarrison_SortMissions=Garrison_SortMissions end @@ -699,9 +484,10 @@ function addon:ApplyMSORT(value) if (type(func)=="function") then _G.Garrison_SortMissions=self[value] else + print("Could not found ",value," in addon") _G.Garrison_SortMissions=origGarrison_SortMissions end - self:RefreshMission() + self:RefreshMissions() end function addon:ApplyMAXMISSIONS(value) MAXMISSIONS=value @@ -712,483 +498,6 @@ function addon:ApplyMINPERC(value) BUSY_MESSAGE=format(BUSY_MESSAGE_FORMAT,MAXMISSIONS,MINPERC) end - ---[[ -function addon:RestoreTooltip() - local self = GMF.MissionTab.MissionList; - local scrollFrame = self.listScroll; - local buttons = scrollFrame.buttons; - for i =1,#buttons do - buttons[i]:SetScript("OnEnter",GarrisonMissionButton_OnEnter) - end -end ---]] ---[[ - [12]={ - description="Iron Horde raiders have descended on nearby draenei villages. Find the raiders' camp and raid it. Turnabout, they say, is fair play.", - cost=15, - duration="4 hr", - slots={ - ["Minion Swarms"]=1, - Type=1, - ["Deadly Minions"]=1 - }, - durationSeconds=14400, - party={ - party2="<empty>", - party1="<empty>" - }, - level=100, - type="Combat", - counters={ - ["0x00000000001BE95D"]={ - [1]={ - counterIcon="Interface\\ICONS\\Ability_Rogue_FanofKnives.blp", - name="Minion Swarms", - counterName="Fan of Knives", - icon="Interface\\ICONS\\Spell_DeathKnight_ArmyOfTheDead.blp", - description="An enemy with many allies. Susceptible to area-of-effect damage." - } - }, - ["0x00000000002D61EB"]={ - [1]={ - counterIcon="Interface\\ICONS\\Spell_Shaman_Hex.blp", - name="Deadly Minions", - counterName="Hex", - icon="Interface\\ICONS\\Achievement_Boss_TwinOrcBrutes.blp", - description="An enemy with powerful allies that should be neutralized." - } - } - }, - traits={ - ["0x00000000001BE95D"]={ - [1]={ - traitID=236, - icon="Interface\\ICONS\\Item_Hearthstone_Card.blp" - } - } - }, - locPrefix="GarrMissionLocation-Nagrand", - rewards={ - [795]={ - itemID=120301, - quantity=1 - } - }, - numRewards=1, - numFollowers=2, - state=-2, - iLevel=0, - name="Raiding the Raiders", - followers={ - }, - location="Nagrand", - isRare=false, - typeAtlas="GarrMission_MissionIcon-Combat", - missionID=380 - } -} ---]] --- True manda a davani -local function cmp(a,b) - - if (a.mechanic and b.trait) then return true end - if (a.trait and b.mechanic) then return false end - if (a.name==a.name) then - if a.bias==b.bias then - if (a.rank==b.rank) then - return a.quality < b.quality - else - return a.rank < b.rank - end - else - return a.bias > b.bias - end - else - return a.name < b.name - end - --if (a.name~=b.name) then return a.name < b.name end - --if (a.bias==-1) then return false end - --if (b.bias==-1) then return true end - --if (a.bias~=b.bias) then return (a.bias>b.bias) end - --if (a.rank ~= b.rank) then return (a.rank < b.rank) end - return a.quality < b.quality -end - - -function addon:FillCounters(missionID,mission) - if (not mission) then mission=self:GetMissionData(missionID) end - local slots=mission.slots - local missioncounters=counters[missionID] - wipe(missioncounters) - local t=G.GetBuffedFollowersForMission(missionID) - if t then - for id,d in pairs(t) do - local rank=self:GetFollowerData(id,'rank') - local quality=self:GetFollowerData(id,'quality') - local bias= G.GetFollowerBiasForMission(missionID,id); - for i,l in pairs(d) do - -- i is meaningful - -- l.counterIcon - -- l.name - -- l.counterName - -- l.icon - -- l.description - tinsert(missioncounters,{k=cleanicon(l.icon),mechanic=true,name=l.name,followerID=id,bias=bias,rank=rank,quality=quality,icon=l.icon}) - followerMissions[id][missionID]=1+ (tonumber(followerMissions[id][missionID]) or 0) - end - end - end - t= G.GetFollowersTraitsForMission(missionID) - if t then - for id,d in pairs(t) do - local bias= G.GetFollowerBiasForMission(missionID,id); - local rank=self:GetFollowerData(id,'rank') - local quality=self:GetFollowerData(id,'quality') - for i,l in pairs(d) do - --l.traitID - --l.icon - followerMissions[id][missionID]=1+ (tonumber(followerMissions[id][missionID]) or 0) - tinsert(missioncounters,{k=cleanicon(l.icon),trait=true,name=l.traitID,followerID=id,bias=bias,rank=rank,quality=quality,icon=l.icon}) - end - end - table.sort(missioncounters,cmp) - local cf=wipe(counterFollowerIndex[missionID]) - local ct=wipe(counterThreatIndex[missionID]) - for i=1,#missioncounters do - tinsert(cf[missioncounters[i].followerID],i) - tinsert(ct[missioncounters[i].k],i) - end - end -end - ---[[ -Matchmaker debug for Spell Check -Slots -["Danger Zones"]=1, -Type="Interface\\ICONS\\Achievement_Reputation_Ogre.blp", -["Interface\\ICONS\\Achievement_Reputation_Ogre.blp"]=1, -["Powerful Spell"]=1 -[1]={ - name="Danger Zones", - icon="Interface\\ICONS\\spell_Shaman_Earthquake.blp", - quality=4, - bias=-0.66666668653488, - follower="0x00000000002D57C4", - rank=96 -}, -[2]={ - name="Interface\\ICONS\\Achievement_Reputation_Ogre.blp", - icon="Interface\\ICONS\\Achievement_Reputation_Ogre.blp", - quality=4, - bias=0.66666668653488, - follower="0x00000000001978B6", - rank=600 -}, -[3]={ - name="Interface\\ICONS\\Achievement_Reputation_Ogre.blp", - icon="Interface\\ICONS\\Achievement_Reputation_Ogre.blp", - quality=4, - bias=-0.66666668653488, - follower="0x00000000002D57C4", - rank=96 -}, -[4]={ - name="Interface\\ICONS\\Item_Hearthstone_Card.blp", - icon="Interface\\ICONS\\Item_Hearthstone_Card.blp", - quality=2, - bias=0.66666668653488, - follower="0x00000000001BE95D", - rank=600 -} -Preparying party -Considering Shelly Hamby for Danger Zones -Considering Qiana Moonshadow for Interface\ICONS\Achievement_Reputation_Ogre.blp -Considering Shelly Hamby for Interface\ICONS\Achievement_Reputation_Ogre.blp -Considering Bruma Swiftstone for Interface\ICONS\Item_Hearthstone_Card.blp -Dopo check per nil -["Danger Zones"]={ -}, -["Interface\\ICONS\\Achievement_Reputation_Ogre.blp"]={ -}, -["Interface\\ICONS\\Item_Hearthstone_Card.blp"]={ -} -Party filling -Party is not full -Verifying Delvar Ironfist 0 600 3 -Verifying Rangari Chel 0 91 3 -Party filling -Party is not full -Verifying Rangari Chel 0 91 3 -Party filling -Matchmaker end - ---]] ---[[ -Button fields -LocBG table -HighlightBR table -Highlight table -inProgressFresh boolean -Party table -gcPANEL table -HighlightB table -HighlightTR table -Level table -Expire table -MissionType table -Overlay table -info table -ItemLevel table -id number -HighlightBL table -Rewards table -Threats table -HighlightT table -0 userdata -RareText table -IconBG table -Title table -Projections table -RareOverlay table -Summary table -HighlightTL table ---]] -local epicMountTrait=221 -local extraTrainingTrait=80 --all followers +35 -local fastLearnerTrait=29 -- only this follower +50 -local hearthStoneProTrait=236 -- all followers +36 -local scavengerTrait=79 -- More resources -local function best(fid1,fid2,counters,mission) - if (not fid1) then return fid2 end - if (not fid2) then return fid1 end - local f1,f2=counters[fid1],counters[fid2] - if (dbg) then - print("Current",fid1,n[f1.followerID]," vs Candidate",fid2,n[f2.followerID]) - end - if (isInParty(f1.followerID)) then return fid1 end - if (f2.bias<0) then return fid1 end - if (f2.bias>f1.bias) then return fid2 end - if (f1.bias == f2.bias) then - if (mission.resources > 0 ) then - if addon:HasTrait(f1.followerID,scavengerTrait) then - return fid1 - end - end - if (f2.quality < f1.quality or f2.rank < f1.rank) then return fid2 end - end - return fid1 -end -function addon:MatchMaker(missionID,mission,party,fromMissionControl) - if (GMFRewardSplash:IsShown()) then return end - if (not mission) then mission=self:GetMissionData(missionID) end - if (not party) then party=parties[missionID] end - local skipBusy=self:GetBoolean("IGM") - local skipMaxed=self:GetBoolean("IGP") - dbg=missionID==(tonumber(_G.MW) or 0) - local slots=mission.slots - local missionCounters=counters[missionID] - local ct=counterThreatIndex[missionID] - openParty(missionID,mission.numFollowers) - -- Preloading skipped ones in party table. - if (dbg) then print(C("Matchmaking mission","Red"),missionID,mission.name) end - if (missionCounters) then - for i=1,#missionCounters do - local followerID=missionCounters[i].followerID - if (not followerID) then - if (dbg) then print("Trying to use [",followerID,"]") end - else - if (self:IsIgnored(followerID,missionID)) then - if (dbg) then print("Skipped",n[followerID],"due to ignored" ) end - partyIgnore(followerID,true) - elseif not self:IsFollowerAvailableForMission(followerID,skipBusy) then - if (dbg) then print("Skipped",n[followerID],"due to busy" ) end - partyIgnore(followerID) - elseif (skipMaxed and mission.xpOnly and self:GetFollowerData(followerID,'maxed')) then - if (dbg) then print("Skipped",n[followerID],"due to maxed" ) end - partyIgnore(followerID,true) - end - end - end - if (type(slots)=='table') then - for i=1,#slots do - local threat=cleanicon(slots[i].icon) - local candidates=ct[threat] - local choosen - if (dbg) then print("Checking ",threat) end - for i=1,#candidates do - local followerID=missionCounters[candidates[i]].followerID - if isInParty(followerID) then - if dbg then print("Countered by",n[followerID],"which is already in party") end - choosen=nil - break - end - if followerID then - if(not isPartyIgnored(followerID)) then - choosen=best(choosen,candidates[i],missionCounters,mission) - if (dbg) then print("Taken",n[missionCounters[choosen].followerID]) end - else - if (dbg) then print("Party Ignored",n[followerID]) end - end - end - end - if (choosen) then - if (type(missionCounters[choosen]) ~="table") then - trace(format("%s %s %d %d",mission.name,threat,missionID,tonumber(choosen) or 0)) - end - if dbg then print("Adding to party",n[missionCounters[choosen].followerID]," still need ",roomInParty()) end - pushFollower(missionCounters[choosen].followerID) - end - if (roomInParty()==0) then - break - end - end - else - xprint("Mission",missionID,"has no slots????") - end - if roomInParty() > 0 then self:AddTraitsToParty(missionID,mission) end - end - if roomInParty() > 0 then self:CompleteParty(missionID,mission,skipBusy,skipMaxed) end - if (not fromMissionControl and not isPartyEmpty()) then - if roomInParty() > 0 then self:CompleteParty(missionID,mission,skipBusy,false) end - end - storeFollowers(party.members) - party.full= roomInParty()==0 - party.perc=closeParty() -end -function addon:AddTraitsToParty(missionID,mission,skipBusy,skipMaxed) - local t=counters[missionID] - if (t) then - for i=1,#t do - local follower=t[i] - if (follower.trait and not isPartyIgnored(follower.followerID) and not isInParty(follower.followerID)) then - if mission.resources > 0 and follower.name==scavengerTrait then - pushFollower(follower.followerID) - elseif mission.xpOnly and (follower.name==extraTrainingTrait or follower.name==hearthStoneProTrait) then - pushFollower(follower.followerID) - elseif mission.durationSeconds > GARRISON_LONG_MISSION_TIME and follower.name==epicMountTrait then - pushFollower(follower.followerID) - end - end - end - end -end -function addon:CompleteParty(missionID,mission,skipBusy,skipMaxed) - local perc=select(4,G.GetPartyMissionInfo(missionID)) -- If percentage is already 100, I'll try and add the most useless character - local candidateMissions=10000 - local candidateRank=10000 - local candidateQuality=9999 - if (dbg) then - print("Attemptin to fill party, so far perc is ",perc, "and party is") - dumpParty() - end - local stash={} - for x=1,roomInParty() do - local candidate - local candidatePerc=perc - if (dbg) then print(" Perc to beat",perc, "Going for spot ",roomInParty()) end - local totFollowers=#followersCache - for i=1,totFollowers do - local data=followersCache[i] - local followerID=data.followerID - if (dbg) then print("evaluating",data.fullname) end - repeat - if isPartyIgnored(followerID) then - if (dbg) then print("Skipped due to party ignored") end - break - end - if isInParty(followerID) then - if (dbg) then print("Skipped due to already in party") end - break - end - if self:IsIgnored(followerID,missionID) then - if (dbg) then print("Skipped due to ignored") end - break - end - if (skipMaxed and data.maxed and mission.xpOnly) then - if (dbg) then print("Skipped due to maxed",skipMaxed,mission.xpOnly) end - break - end - if (not self:IsFollowerAvailableForMission(followerID,skipBusy)) then - if (dbg) then print("Skipped due to busy") end - break - end - local missions=#followerMissions[followerID] - local rank=data.rank - local quality=data.quality - perc=tonumber(perc) or 0 - if ((perc) <100) then - pushFollower(followerID) - local newperc=select(4,G.GetPartyMissionInfo(missionID)) - newperc=tonumber(newperc) or 0 - candidatePerc=tonumber(candidatePerc) or 0 - removeFollower(followerID) - if (newperc > candidatePerc) then - candidatePerc=newperc - candidate=followerID - candidateMissions=missions - candidateRank=rank - candidateQuality=quality - break -- continue - elseif (newperc <= candidatePerc) then - if (dbg) then print("Stashed ",n[followerID]) end - tinsert(stash,followerID) - break --continue - end - else - -- This candidate is not improving success chance or we are already at 100%, minimize - if (i < totFollowers and data.maxed) then - break -- Pointless using a maxed follower if we have more follower to try - end - if (missions<candidateMissions) then - candidate=followerID - candidateMissions=missions - candidateRank=rank - candidateQuality=quality - elseif(missions==candidateMissions and rank<candidateRank) then - candidate=followerID - candidateMissions=missions - candidateRank=rank - candidateQuality=quality - elseif(missions==candidateMissions and rank==candidateRank and quality<candidateQuality) then - candidate=followerID - candidateMissions=missions - candidateRank=rank - candidateQuality=quality - elseif (not candidate) then - candidate=followerID - candidateMissions=missions - candidateRank=rank - candidateQuality=quality - end - end - until true -- A poor man continue implementation using break - end - if (candidate) then - if (dbg) then print("Attempting to add to party") end - pushFollower(candidate) - if (dbg) then - print("Added member to party") - dumpParty() - end - perc=select(4,G.GetPartyMissionInfo(missionID)) - if (dbg) then print("New perc is",perc) end - end - end - for i=1,#stash do - if roomInParty()==0 then break end - if (dbg) then print("Tring stashed ",n[stash[i]]) end - pushFollower(stash[i]) - end -end -function addon:TestMission(missionID) - local party=new() - _G.MW=missionID - self:MatchMaker(missionID) - _G.MW=nil - -end - function addon:IsIgnored(followerID,missionID) if (dbcache.ignored[missionID][followerID]) then return true end if (dbcache.totallyignored[followerID]) then return true end @@ -1215,7 +524,7 @@ function addon:GetCounterBias(missionID,threat) for i=1,#index do local follower=data[index[i]] if ((tonumber(follower.bias) or -1) > bias) then - if (inParty(missionID,follower.followerID)) then + if (tContains(self:GetParty(missionID).members,follower.followerID)) then if (dbg) then print(" Choosen",self:GetFollowerData(follower.followerID,'fullname')) end bias=follower.bias who=follower.name @@ -1235,81 +544,51 @@ function addon:AddLine(name,status) end GameTooltip:AddDoubleLine(name, status,nil,nil,nil,r2,g2,b2) end -function addon:SetThreatColor(obj,missionID) - local bias=self:GetCounterBias(missionID,obj.Icon:GetTexture()) - local color=self:GetBiasColor(bias,nil,"Green") - local c=C[color] - obj.Border:SetVertexColor(c()) +function addon:SetThreatColor(obj,threat) + if type(threat)=="string" then + local _,_,bias,follower,name=strsplit(":",threat) + local color=self:GetBiasColor(tonumber(bias) or -1,nil,"Green") + local c=C[color] + obj.Border:SetVertexColor(c()) + else + obj.Border:SetVertexColor(C.red()) + end + end function addon:HookedGarrisonMissionButton_AddThreatsToTooltip(missionID) if (GMC:IsShown()) then return end return self:RenderTooltip(missionID) end -function addon:RenderTooltip(missionID) - local mission=self:GetMissionData(missionID) - if (not mission) then ---@debug@ - GameTooltip:AddLine("E dove minchia è finita??") ---@end-debug@ - return - end +function addon:AddFollowersToTooltip(missionID) local f=GarrisonMissionListTooltipThreatsFrame - if (not f.Env) then - f.Env=CreateFrame("Frame",nil,f,"GarrisonAbilityCounterTemplate") - f.Env:SetWidth(20) - f.Env:SetHeight(20) - f.Env:SetPoint("LEFT",f) - end - local t=f.EnvIcon:GetTexture(); - f.EnvIcon:Hide() - f.Env.Icon:SetTexture(t) - f.Env.Icon:SetWidth(20) - f.Env.Icon:SetHeight(20) - self:SetThreatColor(f.Env,missionID) - --local bias,who=self:GetCounterBias(missionID,t) - --local color=self:GetBiasColor(bias,nil,"Green") - --local c=C[color] - --f.Env.Border:SetVertexColor(c()) - for i=1,#f.Threats do - local th=f.Threats[i] - self:SetThreatColor(th,missionID) - end -- Adding All available followers - local fullnames=new() - local party=new() - local biascolors=new() - local partystring=strjoin("|",tostringall(unpack(parties[missionID].members))) - for followerID,refs in pairs(counterFollowerIndex[missionID]) do - local fullname= self:GetFollowerData(followerID,'fullname') - for i=1,#refs do - fullname=fullname .." |T" .. tostring(counters[missionID][refs[i]].icon) ..":16|t" - end - if (not partystring:find(followerID)) then - tinsert(fullnames,fullname) - else - tinsert(party,fullname) - end - biascolors[fullname]={self:GetBiasColor(followerID,missionID,"White"),self:GetFollowerStatus(followerID,true)} - end - table.sort(fullnames) + local party=self:GetParty(missionID) + local members=party.members + local partystring=strjoin("|",tostringall(unpack(members))) GameTooltip:AddLine(L["Other useful followers"]) - for i=1,#fullnames do - local fullname=fullnames[i] - local info=biascolors[fullname] - self:AddLine(fullname,info[2],info[1]) + for followerID,_ in pairs(G.GetFollowersTraitsForMission(missionID)) do + GameTooltip:AddDoubleLine(self:GetFollowerData(followerID,'fullname','none'),self:GetFollowerStatus(followerID,true,true)) end - - del(party) - del(fullnames) - del(biascolors) - local perc=parties[missionID].perc + for followerID,_ in pairs(G.GetBuffedFollowersForMission(missionID)) do + GameTooltip:AddDoubleLine(self:GetFollowerData(followerID,'fullname','none'),self:GetFollowerStatus(followerID,true,true)) + end + local perc=self:GetParty(missionID,'perc') local q=self:GetDifficultyColor(perc) GameTooltip:AddDoubleLine(GARRISON_MISSION_SUCCESS,format(GARRISON_MISSION_PERCENT_CHANCE,perc),nil,nil,nil,q.r,q.g,q.b) for _,i in pairs (dbcache.ignored[missionID]) do GameTooltip:AddLine(L["You have ignored followers"]) break; end + if party.goldMultiplier>1 and party.class=='gold' then + GameTooltip:AddDoubleLine(L["Gold incremented!"],party.goldMultiplier..'x',C.Green()) + end + if party.materialMultiplier>1 and party.class == 'resources' then + GameTooltip:AddDoubleLine(L["Resource incremented!"],party.materialMultiplier..'x',C.Green()) + end + if party.xpBonus>0 then + GameTooltip:AddDoubleLine(L["Xp incremented!"],'+'..party.xpBonus,C.Green()) + end if (dbcache.history[missionID]) then local tot,success=0,0 for d,r in pairs(dbcache.history[missionID]) do @@ -1334,50 +613,14 @@ local function switch(flag) end end end -function addon:RefreshMission(missionID) - if (self:IsAvailableMissionPage()) then - if (tonumber(missionID)) then - self:FillCounters(missionID) - self:MatchMaker(missionID) - end +function addon:RefreshMissions(missionID) + if (ns.toc < 60100) then + GarrisonMissionFrame_OnUpdate() + else GarrisonMissionList_UpdateMissions() end end -function addon:BuildMissionsCache(fc,mm,OnEvent) ---cache.missions ---@debug@ - local start=GetTime() - xprint("Start Full Cache Rebuild") ---@end-debug@ - local t=new() - holdEvents() - G.GetAvailableMissions(t) - for index=1,#t do - local missionID=t[index].missionID - if (not dbcache.seen[missionID]) then - dbcache.seen[missionID]=(OnEvent and time()) or dbcache.lastseen - end - self:BuildMissionCache(missionID,t[index]) - if fc then self:FillCounters(missionID) end - if mm then self:MatchMaker(missionID) end - end - for k,v in pairs(dbcache.seen) do - if (not cache.missions[k]) then - local span=time()-(tonumber(v) or time()) - if (span > db.lifespan[k]) then - db.lifespan[k]=span - end - dbcache.seen[k]=nil - end - end - releaseEvents() - del(t) - collectgarbage("step",10) ---@debug@ - xprint("Done in",GetTime()-start) ---@end-debug@ -end --[[ GARRISON_DURATION_DAYS = "%d |4day:days;"; changed to dual form GARRISON_DURATION_DAYS_HOURS = "%d |4day:days; %d hr"; changed to dual form @@ -1406,145 +649,6 @@ local function GarrisonTimeStringToSeconds(text) return 3600*24 end -function addon:BuildRunningMissionsCache() - local t=new() - G.GetInProgressMissions(t) - for index=1,#t do - local mission=t[index] - local missionID=mission.missionID - local running =dbcache.running[missionID] - running.duration=mission.durationSeconds - running.timeLeft=mission.timeLeft - if ((tonumber(running.started) or 0)==0) then running.started = time() - GarrisonTimeStringToSeconds(mission.timeLeft) end - running.followers={} - for i=1,mission.numFollowers do - running.followers[i]=mission.followers[i] - dbcache.runningIndex[mission.followers[i]]=missionID - end - end - del(t) -end ---[[ -{ - missionID=0, - counters={}, calculated - countered={ calculated - ["*"]={} - }, - counterers={ calculated - ["*"]={} - }, - slots={ calculated - ["*"]=0 - }, - numFollowers=0, -> GetMissionMaxFollowers() - name="<newmission>", GetMissionName - basePerc=0, GetPartyMissionInfo - durationSeconds=0, GePartyMissionInfo() - rewards={}, - level=0, - iLevel=0, - rank=0, - locPrefix=false -} -GetBasicInfo Table Format={ - description="With infernals and felguard invading Talador, the rest of the Burning Legion can't be far behind. Defeat them, and try to find their source.", - cost=15, - duration="8 hr", - durationSeconds=28800, - level=100, - type="Combat", - locPrefix="GarrMissionLocation-Talador", - rewards={ - [248]={ - itemID=114057, - quantity=1 - } - }, - numRewards=1, - numFollowers=3, - state=-2, - iLevel=0, - name="Burning Legion Vanguard", - followers={ - }, - location="Talador", - isRare=false, - typeAtlas="GarrMission_MissionIcon-Combat", - missionID=113 -} - ---]] -function addon:BuildMissionCache(id,data) - local mission=cache.missions[id] - if (not mission) then ---@dedbug@ - xprint("Generating new data for ",id) ---@end-debug@ - mission = data or G.GetBasicMissionInfo(id) - if (not mission) then return end - cache.missions[id]=mission - if dbg then print("Retrieved",id,mission.name) end - end - local _,xp,type,typeDesc,typeIcon,locPrefix,_,enemies=G.GetMissionInfo(id) - mission.rank=mission.level < 100 and mission.level or mission.iLevel - mission.xp=xp - mission.xpBonus=0 - mission.resources=0 - mission.gold=0 - mission.followerUpgrade=0 - mission.itemLevel=0 - for k,v in pairs(mission.rewards) do - if (v.followerXP) then mission.xpBonus=mission.xpBonus+v.followerXP end - if (v.currencyID and v.currencyID==GARRISON_CURRENCY) then mission.resources=v.quantity end - if (v.currencyID and v.currencyID==0) then mission.gold =mission.gold+v.quantity/10000 end - if (v.itemID) then - if (v.itemID~=120205) then - local itemName, itemLink, itemRarity, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount,itemEquipLoc, itemTexture, itemSellPrice = GetItemInfo(v.itemID) - if (itemName) then - if (itemLevel > 1 ) then - mission.itemLevel=itemLevel - else - mission.followerUpgrade=itemRarity - end - end - end - end - end - mission.totalXp=(tonumber(mission.xp) or 0) + (tonumber(mission.xpBonus) or 0) - mission.globalXp=mission.totalXp*mission.numFollowers - if (mission.resources==0 and mission.gold==0 and mission.itemLevel==0 and mission.followerUpgrade==0) then - mission.xpOnly=true - else - mission.xpOnly=false - end - mission.locPrefix=locPrefix - if (not type) then ---@debug@ - xprint("No type",id,data.name) ---@end-debug@ - else - if (not self.db.global.types[type]) then - self.db.global.types[type]={name=type,description=typeDesc,icon=typeIcon} - end - end - mission.slots={} - local slots=mission.slots - - for i=1,#enemies do - local mechanics=enemies[i].mechanics - for i,mechanic in pairs(mechanics) do - tinsert(slots,mechanic) - self.db.global.abilities[mechanic.name]=mechanic - end - end - if (type) then - tinsert(slots,{name=TYPE,key=type,icon=typeIcon}) - end - --collectgarbage("step",100) - mission.basePerc=select(4,G.GetPartyMissionInfo(id)) - -end function addon:SetDbDefaults(default) default.global=default.global or {} default.global["*"]={} @@ -1577,15 +681,28 @@ function addon:CreatePrivateDb() ["*"]=0 }, missionControl={ - allowedRewards = {["*"]=true}, - rewardChance={["*"]=100}, + allowedRewards = { + followerEquip=true, + gold=true, + equip=true, + resources=true, + xp=true + }, + rewardChance={ + followerEquip=100, + gold=100, + equip=100, + resources=100, + xp=100 + }, useOneChance=true, itemPrio = {}, minimumChance = 100, minDuration = 0, maxDuration = 24, epicExp = false, - skipRare=true + skipRare=true, + skipEpic=true } } }, @@ -1619,15 +736,15 @@ end -- Fires after GarrisonMissionFrame OnShow. Pretty useless function addon:EventGARRISON_MISSION_NPC_OPENED(event,...) ---@debug@ - xprint(event,...) ---@end-debug@ +--[===[@debug@ + ns.xprint(event,...) +--@end-debug@]===] if (GCF) then GCF:Show() end end function addon:EventGARRISON_MISSION_NPC_CLOSED(event,...) ---@debug@ - xprint(event,...) ---@end-debug@ +--[===[@debug@ + ns.xprint(event,...) +--@end-debug@]===] if (GCF) then self:RemoveMenu() GCF:Hide() @@ -1636,18 +753,14 @@ end function addon:EventGARRISON_MISSION_LIST_UPDATE(event) local n=0 for _,k in pairs(event) do n=n+1 end - xprint("GARRISON_MISSION_LIST_UPDATE",n,date("%d/%m/%y %H:%M:%S")) + ns.xprint("GARRISON_MISSION_LIST_UPDATE",n,date("%d/%m/%y %H:%M:%S")) local t=new() G.GetAvailableMissions(t) - local justseen={} local now=time() for i=1,#t do - justseen[t[i].missionID]=true - end - for missionID,_ in pairs(justseen) do + local missionID=t[i].missionID if (not tonumber(db.seen[missionID])) then db.seen[missionID]=now end end - self:BuildMissionsCache(false,false,true) del(t) end --- @@ -1656,9 +769,9 @@ end -- After this events fires also GARRISON_MISSION_LIST_UPDATE and GARRISON_FOLLOWER_LIST_UPDATE function addon:EventGARRISON_MISSION_STARTED(event,missionID,...) ---@debug@ - xprint(event,missionID,...) ---@end-debug@ +--[===[@debug@ + ns.xprint(event,missionID,...) +--@end-debug@]===] -- running={ -- ["*"]={ -- followers={}, @@ -1666,15 +779,19 @@ function addon:EventGARRISON_MISSION_STARTED(event,missionID,...) -- duration=0 -- } -- }, + table.sort(GMFMissions.inProgressMissions,sorters.EndTime) dbcache.running[missionID].started=time() dbcache.running[missionID].duration=select(2,G.GetPartyMissionInfo(missionID)) wipe(dbcache.running[missionID].followers) wipe(dbcache.ignored[missionID]) - for i=1,3 do - local m=parties[missionID].members[i] - if (m) then - tinsert(dbcache.running.followers,m) - dbcache.runningIndex[m]=missionID + local party=self:GetParty(missionID) + if party then + for i=1,#party.members do + local m=party.members[i] + if (m) then + tinsert(dbcache.running.followers,m) + dbcache.runningIndex[m]=missionID + end end end local v=dbcache.seen[missionID] @@ -1683,11 +800,7 @@ function addon:EventGARRISON_MISSION_STARTED(event,missionID,...) db.lifespan[missionID]=span -- IF we started it.. it was alive, so it's expire time is at least the time we waited before starting it end - dbcache.seen[missionID]=nil - counters[missionID]=nil - parties[missionID]=nil - self:BuildMissionsCache(true,true) self:RefreshFollowerStatus() end --- @@ -1700,23 +813,19 @@ end -- function addon:EventGARRISON_MISSION_FINISHED(event,missionID,...) ---@debug@ - xprint(event,missionID,...) - xdump(G.GetPartyMissionInfo(missionID)) ---@end-debug@ +--[===[@debug@ + ns.xprint(event,missionID,...) + ns.xdump(G.GetPartyMissionInfo(missionID)) +--@end-debug@]===] end function addon:EventGARRISON_FOLLOWER_LIST_UPDATE(event) --We need to update all followers, maybe this could be done in an onupdate handle - wipe(followersCache) - wipe(followersCacheIndex) - wipe(parties) - xprint("Follower cache cleaned") end function addon:EventGARRISON_MISSION_BONUS_ROLL_LOOT(event,missionID,completed,success) ---@debug@ - xprint('evt',event,missionID,completed,success) ---@end-debug@ +--[===[@debug@ + ns.xprint('evt',event,missionID,completed,success) +--@end-debug@]===] self:RefreshFollowerStatus() end --- @@ -1731,23 +840,13 @@ end --GARRISON_MISSION_BONUS_ROLL_LOOY missionID nil -- function addon:EventGARRISON_MISSION_COMPLETE_RESPONSE(event,missionID,completed,rewards) ---@debug@ - xprint('evt',event,missionID,completed,rewards) ---@end-debug@ +--[===[@debug@ + ns.xprint('evt',event,missionID,completed,rewards) +--@end-debug@]===] dbcache.history[missionID][time()]={result=100,success=rewards} dbcache.seen[missionID]=nil dbcache.running[missionID]=nil dbcache.seen[missionID]=nil - counters[missionID]=nil - parties[missionID]=nil -end -function addon:EventGARRISON_FOLLOWER_ADDED() - wipe(followersCache) - wipe(followersCacheIndex) -end -function addon:EventGARRISON_FOLLOWER_REMOVED() - wipe(followersCache) - wipe(followersCacheIndex) end ----------------------------------------------------- -- Coroutines data and clock management @@ -1761,11 +860,7 @@ local coroutines={ }, } -local lastmin=0 local MPShown=nil -local dbgFrame -local lastCPU=0 -local startTime=GetTime() -- Keeping it as a nice example of coroutine management.. but not using it anymore function addon:Clock() if (GMFMissions.showInProgress) then @@ -1773,31 +868,6 @@ function addon:Clock() else --collectgarbage("step",100) end ---@debug@ - if (not dbgFrame) then - dbgFrame=AceGUI:Create("Window") - dbgFrame:SetTitle("GC Performance") - dbgFrame:SetPoint("LEFT") - dbgFrame:SetHeight(80) - dbgFrame:SetWidth(350) - dbgFrame:SetLayout("fill") - dbgFrame.Text=AceGUI:Create("Label") - dbgFrame.Text:SetColor(1,0,0) - dbgFrame:AddChild(dbgFrame.Text) - end - local h,m=GetGameTime() - if (m~=lastmin) then - lastmin=m - end - UpdateAddOnMemoryUsage() - local cpu=GetAddOnCPUUsage("GarrisonCommander") - dbgFrame.Text:SetText(format("GC Cpu %3.2f/%2.2f/%2.2f Mem %4.3fMB ", - cpu, - cpu-lastCPU,cpu/(GetTime()-startTime), - GetAddOnMemoryUsage("GarrisonCommander")/1024) - ) - lastCPU=cpu ---@end-debug@ dbcache.lastseen=time() if (not MP or MPGoodGuy) then return end MPShown=not self:GetBoolean("CKMP") @@ -1819,7 +889,7 @@ function addon:Clock() GarrisonMissionFrameMissionsListScrollFrame:Show() GarrisonMissionFrameMissionsListScrollFrame:SetParent(GMFMissions) end ---@debug@ +--[===[@debug@ for k,d in pairs(coroutines) do local co=coroutines[k] if (not co.func) then @@ -1834,7 +904,7 @@ function addon:Clock() co.paused=co.func(self) end end ---@end-debug@ +--@end-debug@]===] end function addon:ActivateButton(button,OnClick,Tooltiptext,persistent) button:SetScript("OnClick",function(...) self[OnClick](self,...) end ) @@ -1842,9 +912,9 @@ function addon:ActivateButton(button,OnClick,Tooltiptext,persistent) button.tooltip=Tooltiptext button:SetScript("OnEnter",ShowTT) if persistent then - button:SetScript("OnLeave",function() GameTooltip:FadeOut() end) + button:SetScript("OnLeave",ns.OnLeave) else - button:SetScript("OnLeave",function() GameTooltip:Hide() end) + button:SetScript("OnLeave",ns.OnLeave) end else button:SetScript("OnEnter",nil) @@ -1864,15 +934,16 @@ function addon:Shrink(button) end do local s=setmetatable({},{__index=function(t,k) return 0 end}) - local FOLLOWER_STATUS_FORMAT=(bigscreen and "Followers status " or "" ).. + local FOLLOWER_STATUS_FORMAT=(ns.bigscreen and "Followers status " or "" ).. C(AVAILABLE..':%d ','green') .. C(GARRISON_FOLLOWER_WORKING .. ":%d ",'cyan') .. C(GARRISON_FOLLOWER_ON_MISSION .. ":%d ",'red') .. C(GARRISON_FOLLOWER_INACTIVE .. ":%d","silver") function addon:RefreshFollowerStatus() + wipe(s) - for i=1,#followersCache do - local status=self:GetFollowerStatus(followersCache[i].followerID) + for _,followerID in self:GetFollowerIterator() do + local status=self:GetFollowerStatus(followerID) s[status]=s[status]+1 end if (GMF.FollowerStatusInfo) then @@ -1891,7 +962,9 @@ do end end function addon:ShowMissionControl() - if missionautocompleting then return end + ns.xprint("Click1") + --if ns.missionautocompleting then return end + ns.xprint("Click2") if (not GMC:IsShown()) then GarrisonMissionFrame_SelectTab(999) GMF.FollowerTab:Hide() @@ -1900,10 +973,10 @@ function addon:ShowMissionControl() GMF.TitleText:SetText("Garrison Commander Mission Control") GMC:Show() GMC.startButton:Click() - GMC.tabMC:SetChecked(true) + GMF.tabMC:SetChecked(true) else GMC:Hide() - GMC.tabMC:SetChecked(false) + GMF.tabMC:SetChecked(false) GarrisonMissionFrame_SelectTab(1) end end @@ -2021,106 +1094,6 @@ function addon:GenerateMissionsWidgets() self:GenerateMissionContainer() self:GenerateMissionButton() end -local generated -function addon:GenerateMissionCompleteList(title) - if not generated then - generated=true - self:GenerateContainer() - do - local Type="GCMCList" - local Version=1 - local m={} - local function onEnter(self) - if (self.itemlink) then - GameTooltip:SetHyperlink(self.itemlink) - GameTooltip:Show() - end - end - function m:OnAcquire() - end - function m:Show() - self.frame:Show() - end - function m:Hide() - self.frame:Hide() - self:Release() - end - function m:AddMissionName(name,result) - local obj=self.scroll - local l=AceGUI:Create("Label") - l:SetFontObject(QuestFontNormalSmall) - l:SetColor(C:Yellow()) - l:SetText(format("%s: %s",name,result)) - l:SetFullWidth(true) - obj:AddChild(l) - end - function m:AddRow(data,...) - local obj=self.scroll - local l=AceGUI:Create("InteractiveLabel") - l:SetFontObject(GameFontNormalSmall) - l:SetText(data) - l:SetColor(...) - l:SetFullWidth(true) - obj:AddChild(l) - end - function m:AddFollower(followerID,data) - if (data[1]==0) then - return self:AddRow(format("%s is already at maximum xp",addon:GetFollowerData(followerID,'fullname'))) - end - local quality=G.GetFollowerQuality(followerID) or data[4] - local level=G.GetFollowerLevel(followerID) or data[3] - xprint(followerID,quality,level,data[3],data[4]) - local levelup=((quality > data[4]) or (level > data[3])) - --local levelup=true - if levelup then - PlaySound("UI_Garrison_CommandTable_Follower_LevelUp"); - else - - end - --local text=format("%d %s gained %d xp",self:GetFo) - return self:AddRow(format("%s gained %d xp%s",addon:GetFollowerData(followerID,'fullname',true),data[1], - levelup and ". **Level Up!!!**" or format(". %d to go.",addon:GetFollowerData(followerID,'levelXP')-addon:GetFollowerData(followerID,'xp')))) - end - function m:AddIconText(icon,text,qt) - local obj=self.scroll - local l=AceGUI:Create("Label") - l:SetFontObject(GameFontNormalSmall) - if (qt) then - l:SetText(format("%s x %s",text,qt)) - else - l:SetText(text) - end - l:SetImage(icon) - l:SetImageSize(24,24) - l:SetFullWidth(true) - obj:AddChild(l) - return l - end - function m:AddItem(itemID,qt) - local obj=self.scroll - local _,itemlink,itemquality,_,_,_,_,_,_,itemtexture=GetItemInfo(itemID) - self:AddIconText(itemtexture,itemlink,qt).itemlink=itemlink - end - local function Constructor() - local widget=AceGUI:Create("GCGUIContainer") - widget:SetLayout("Fill") - local scroll = AceGUI:Create("ScrollFrame") - scroll:SetLayout("Flow") -- probably? - scroll:SetFullWidth(true) - scroll:SetFullHeight(true) - widget:AddChild(scroll) - for k,v in pairs(m) do widget[k]=v end - widget:Show() - widget.scroll=scroll - return widget - end - AceGUI:RegisterWidgetType(Type,Constructor,Version) - end - end - local w=AceGUI:Create("GCMCList") - w:SetTitle(title) - return w -end do local generated function addon:GenerateContainer() @@ -2144,7 +1117,7 @@ function addon:GenerateContainer() for _,f in pairs({frame:GetRegions()}) do if (f:GetObjectType()=="Texture" and f:GetAtlas()=="Garr_WoodFrameCorner") then f:Hide() end end - local widget={frame=frame} + local widget={frame=frame,missions={}} widget.type=Type widget.SetTitle=function(self,...) self.frame.TitleText:SetText(...) end widget.SetTitleColor=function(self,...) self.frame.TitleText:SetTextColor(...) end @@ -2262,82 +1235,72 @@ end function addon:GenerateMissionButton() do - local Type="GMCMissionButton" + local Type1="GMCMissionButton" + local Type2="GMCSlimMissionButton" local Version=1 local unique=0 - local function OnAcquire(self) + local m={} + function m:OnAcquire() local frame=self.frame frame.info=nil - frame:SetHeight(80) + frame:SetHeight(self.type==Type1 and 80 or 80) self.frame:SetAlpha(1) self.frame:Enable() + for i=1,#self.scripts do + self.frame:SetScript(self.scripts[i],nil) + end + wipe(self.scripts) return self.frame:SetScale(1.0) end - local function Show(self) + function m:Show() return self.frame:Show() end - local function Hide(self) + function m:SetHeight(h) + return self.frame:SetHeight(h) + end + function m:Hide() self.frame:SetHeight(1) self.frame:SetAlpha(0) return self.frame:Disable() end - local function SetScript(self,...) - return self.frame:SetScript(...) + function m:SetScript(name,method) + tinsert(self.scripts,name) + return self.frame:SetScript(name,method) end - local function SetScale(self,...) - return self.frame:SetScale(...) + function m:SetScale(s) + return self.frame:SetScale(s) end - local function SetMission(self,mission,missionID,party) + function m:SetMission(mission,party) self.frame.info=mission - addon:BuildMissionButton(self.frame,true) + self.frame.fromFollowerPage=true self.frame:EnableMouse(true) - --self.frame:SetScript("OnEnter",GarrisonMissionPageFollowerFrame_OnEnter) - --self.frame:SetScript("OnLeave",GarrisonMissionPageFollowerFrame_OnLeave) - self.frame:SetScript("OnEnter",GarrisonMissionButton_OnEnter) - self.frame:SetScript("OnLeave",function() GameTooltip:FadeOut() end) - if (not party) then - for i=1,#GMC.ml.Parties do - party=GMC.ml.Parties[i] - if party.missionID==missionID then - break - end - end - end - self.frame.Percent:SetFormattedText("%d%%",party.perc) - self.frame.Percent:SetTextColor(addon:GetDifficultyColors(party.perc)) - local x=1 - for i=1,#party.members do - x=i+1 - addon:RenderFollowerButton(self.frame.members[i],party.members[i],missionID) - self.frame.members[i]:SetScript("OnEnter",GarrisonMissionPageFollowerFrame_OnEnter) - self.frame.members[i]:SetScript("OnLeave",GarrisonMissionPageFollowerFrame_OnLeave) - self.frame.members[i]:Show() + self.frame.party=party + if self.type==Type1 then + addon:DrawSingleButton(false,self.frame,false,false) + self.frame:SetScript("OnEnter",GarrisonMissionButton_OnEnter) + self.frame:SetScript("OnLeave",ns.OnLeave) + else + addon:DrawSingleSlimButton(false,self.frame,false,false) + self.frame:SetScript("OnEnter",nil) + self.frame:SetScript("OnLeave",nil) end - for i=x,3 do - self.frame.members[i]:SetScript("OnEnter",nil) - self.frame.members[i]:Hide() + if self.type==Type2 then + self.frame.Percent:SetFormattedText("%d%%",party.perc) + self.frame.Percent:SetTextColor(addon:GetDifficultyColors(party.perc)) end end local function Constructor() unique=unique+1 local frame=CreateFrame("Button",nil,nil,"GarrisonMissionListButtonTemplate") --"GarrisonCommanderMissionListButtonTemplate") - local indicators=CreateFrame("Frame",nil,frame,"GarrisonCommanderIndicators") frame.Title:SetFontObject("QuestFont_Shadow_Small") frame.Summary:SetFontObject("QuestFont_Shadow_Small") - if (bigscreen) then - indicators.Percent:SetJustifyH("RIGHT") - else - indicators.Percent:SetJustifyH("LEFT") - end - indicators:SetPoint("LEFT",65,0) - indicators.Age:Hide() - frame.Percent=indicators.Percent frame:SetScript("OnEnter",nil) frame:SetScript("OnLeave",nil) frame:SetScript("OnClick",function(self,button) return self.obj:Fire("OnClick",self,button) end) frame.LocBG:SetPoint("LEFT") frame.MissionType:SetPoint("TOPLEFT",5,-2) + --[[ frame.members={} for i=1,3 do local f=CreateFrame("Button",nil,frame,"GarrisonCommanderMissionPageFollowerTemplateSmall" ) @@ -2345,47 +1308,51 @@ function addon:GenerateMissionButton() f:SetPoint("BOTTOMRIGHT",-65 -65 *i,5) f:SetScale(0.8) end + --]] local widget={} setmetatable(widget,{__index=frame}) - widget.type=Type widget.frame=frame + widget.scripts={} frame.obj=widget - widget.OnAcquire=OnAcquire - widget.Show=Show - widget.Hide=Hide - widget.SetScript=SetScript - widget.SetMission=SetMission - widget.SetScale=SetScale + for k,v in pairs(m) do widget[k]=v end + return widget + end + local function Constructor1() + local widget=Constructor() + widget.type=Type1 return AceGUI:RegisterAsWidget(widget) - end - AceGUI:RegisterWidgetType(Type,Constructor,Version) + local function Constructor2() + local widget=Constructor() + local frame=widget.frame + widget.type=Type2 + local indicators=CreateFrame("Frame",nil,frame,"GarrisonCommanderIndicators") + indicators.Percent:SetJustifyH("LEFT") + indicators.Percent:SetJustifyV("CENTER") + indicators:SetPoint("LEFT",70,-20) + indicators.Age:Hide() + frame.Percent=indicators.Percent + frame.Failure=frame:CreateFontString() + frame.Success=frame:CreateFontString() + frame.Failure:SetFontObject("GameFontRedLarge") + frame.Success:SetFontObject("GameFontGreenLarge") + frame.Failure:SetText(FAILED) + frame.Success:SetText(SUCCESS) + frame.Failure:Hide() + frame.Success:Hide() + frame.Title:SetPoint("LEFT",frame.Percent,"RIGHT",-20,30) + frame.Success:SetPoint("LEFT",frame.Percent,"RIGHT",-20,0) + frame.Summary:SetPoint("LEFT",frame.Percent,"RIGHT",-20,-30) + + --widget.frame.MissionType:Hide() + --widget.frame.IconBG:Hide() + return AceGUI:RegisterAsWidget(widget) + end + AceGUI:RegisterWidgetType(Type1,Constructor1,Version) + AceGUI:RegisterWidgetType(Type2,Constructor2,Version) + end end -function addon:__GMCBuildMiniMissionButton(frame,i,mission,scale,perc,offset) - offset=offset or 20 - scale=scale or 0.6 - local panel=frame.Missions[i] - if (not panel) then - panel=CreateFrame("Button",nil,frame,"GarrisonCommanderMissionListButtonTemplate") - panel:SetPoint("TOPLEFT",frame,1,-((i-1)*panel:GetHeight() +offset)) - panel:SetPoint("TOPRIGHT",frame,-1,-((i-1)*panel:GetHeight()-offset)) - panel.orderId=i - tinsert(frame.Missions,panel) - --Creo una riga nuova - panel:SetScale(scale) - panel.LocBG:SetPoint("LEFT") - end - panel.info=mission - --panel.id=index[missionID] - self:BuildMissionButton(panel) - local q=self:GetDifficultyColor(perc) - panel.Percent:SetFormattedText(GARRISON_MISSION_PERCENT_CHANCE,perc) - panel.Percent:SetTextColor(q.r,q.g,q.b) - panel.NumMembers:SetFormattedText(GARRISON_MISSION_TOOLTIP_NUM_REQUIRED_FOLLOWERS,mission.numFollowers) - panel:Show() - return panel -end function addon:CreateOptionsLayer(...) local o=AceGUI:Create("SimpleGroup") -- a transparent frame @@ -2460,7 +1427,7 @@ function addon:Options() end GCF:SetFrameStrata(GMF:GetFrameStrata()) GCF:SetFrameLevel(GMF:GetFrameLevel()-2) - if (not bigscreen) then GCF:SetHeight(GCF:GetHeight()+35) end + if (not ns.bigscreen) then GCF:SetHeight(GCF:GetHeight()+35) end baseHeight=GCF:GetHeight() minHeight=47 GCF.CloseButton:SetScript("OnClick",nil) @@ -2520,7 +1487,7 @@ function addon:Options() GCF:RegisterForDrag("LeftButton") GCF:SetScript("OnDragStart",function(frame)if (self:GetBoolean("MOVEPANEL")) then frame:StartMoving() end end) GCF:SetScript("OnDragStop",function(frame) frame:StopMovingOrSizing() end) - if (bigscreen) then + if (ns.bigscreen) then --MinimizeButton -- It's not working well, now I dont have time to fix it if (false) then @@ -2554,9 +1521,9 @@ function addon:Options() end function addon:ScriptTrace(hook,frame,...) ---@debug@ - xprint("Triggered " .. C(hook,"red").." script on",C(frame,"Azure"),...) ---@end-debug@ +--[===[@debug@ + ns.xprint("Triggered " .. C(hook,"red").." script on",C(frame,"Azure"),...) +--@end-debug@]===] end function addon:IsProgressMissionPage() return GMF:IsShown() and GMF.MissionTab and GMF.MissionTab.MissionList.showInProgress @@ -2569,7 +1536,7 @@ function addon:IsFollowerList() end --GMFMissions.CompleteDialog function addon:IsRewardPage() - return GMF:IsShown() and GMF.MissionComplete:IsShown() + return GMF:IsShown() and GMFMissions.CompleteDialog:IsShown() end function addon:IsMissionPage() @@ -2579,9 +1546,8 @@ end -- Switches between missions (1) and followers (others) panels function addon:HookedGarrisonMissionFrame_SelectTab(id) GMC:Hide() - GMC.tabMC:SetChecked(false) + GMF.tabMC:SetChecked(false) self:RefreshFollowerStatus() - wipe(GMCUsedFollowers) end --- -- Switchs between active and availabla missions depending on tab object @@ -2598,7 +1564,7 @@ do end end function addon:HookedGarrisonMissionFrame_HideCompleteMissions() - self:BuildMissionsCache(true,true) + xprint("Complete missions closed") end @@ -2639,15 +1605,13 @@ function addon:HookedGarrisonFollowerButton_UpdateCounters(frame,follower,showCo end function addon:RenderFollowerPageFollowerButton(frame,follower,showCounters) if not frame.GCIt then + frame.GCIt=frame:CreateFontString(nil,"ARTWORK","GameFontHighlightSmall") + frame.GCIt:SetPoint("BOTTOMLEFT",frame.Name,"TOPLEFT",0,2) if not MP then frame.GCTime=frame:CreateFontString(nil,"ARTWORK","GameFontHighlightSmall") frame.GCTime:SetPoint("TOPLEFT",frame.Status,"TOPRIGHT",5,0) frame.GCXp=frame:CreateFontString(nil,"ARTWORK","GameFontHighlightSmall") - frame.GCXp:SetPoint("LEFT",frame.Name,"LEFT",0,0) - frame.GCXp:SetPoint("BOTTOM",frame,"BOTTOM",0,2) end - frame.GCIt=frame:CreateFontString(nil,"ARTWORK","GameFontHighlightSmall") - frame.GCIt:SetPoint("BOTTOMLEFT",frame.Name,"TOPLEFT",0,2) end if not frame.isCollected then if not MP then @@ -2657,7 +1621,6 @@ function addon:RenderFollowerPageFollowerButton(frame,follower,showCounters) frame.GCIt:Hide() return end - addon:RecalculateFollower(follower) if not MP then if (frame.Status:GetText() == GARRISON_FOLLOWER_ON_MISSION) then frame.GCTime:SetText(self:GetFollowerStatus(follower.followerID,true,true)) @@ -2668,37 +1631,40 @@ function addon:RenderFollowerPageFollowerButton(frame,follower,showCounters) if (follower.level >= GARRISON_FOLLOWER_MAX_LEVEL and follower.quality >= GARRISON_FOLLOWER_MAX_UPGRADE_QUALITY) then frame.GCXp:Hide() else - frame.GCXp:SetFormattedText("Xp to next upgrade: %d",follower.levelXP-follower.xp) + frame.GCXp:SetFormattedText(L["To go: %d"],follower.levelXP-follower.xp) frame.GCXp:Show() end end if (follower.level >= GARRISON_FOLLOWER_MAX_LEVEL and self:GetToggle("ILV") ) then local c1=ITEM_QUALITY_COLORS[follower.weaponQuality or 1] local c2=ITEM_QUALITY_COLORS[follower.armorQuality or 1] - frame.GCIt:SetFormattedText("W:%s%3d|r A:%s%3d|r",c1.hex,follower.weaponItemLevel,c2.hex,follower.armorItemLevel) + frame.GCIt:SetFormattedText("W:%s%3d|r A:%s%3d|r",c1.hex,self:GetFollowerData(follower.followerID,"weaponItemLevel"),c2.hex,self:GetFollowerData(follower.followerID,"armorItemLevel")) frame.GCIt:Show() + frame.GCXp:SetPoint("LEFT",frame.GCIt,"RIGHT",2,0) else frame.GCIt:Hide() + frame.GCXp:SetPoint("LEFT",frame.Name,"LEFT",0,20) end end function addon:HookedGarrisonFollowerListButton_OnClick(frame,button) if (frame.info.isCollected) then if (button=="LeftButton") then - if (bigscreen and frame and frame.info and frame.info.followerID) then self:HookedGarrisonFollowerPage_ShowFollower(frame.info,frame.info.followerID) end + if (ns.bigscreen and frame and frame.info and frame.info.followerID) then self:HookedGarrisonFollowerPage_ShowFollower(frame.info,frame.info.followerID) end end self:ScheduleTimer("HookedGarrisonFollowerButton_UpdateCounters",0.2,frame,frame.info,false) end end -- Shamelessly stolen from Blizzard Code +local fakepage={newMissionIDs={}} function addon:BuildMissionButton(button,gmc,...) + if true then return self:DrawSingleButton(fakepage,button,false,false) end local mission=button.info if (not mission or not mission.name) then if (button.missionID) then mission=self:GetMissionData(button.missionID) end end - if (not mission) then return end button.Title:SetWidth(0); button.Title:SetText(mission.name); button.Level:SetText(mission.level); @@ -2719,6 +1685,7 @@ function addon:BuildMissionButton(button,gmc,...) button.Summary:ClearAllPoints(); button.Summary:SetPoint("TOPLEFT", button.Title, "BOTTOMLEFT", 0, -4); end + if (not mission) then return end if gmc then button.Title:SetPoint("LEFT",70,25) end if ( mission.locPrefix ) then button.LocBG:Show(); @@ -2761,66 +1728,13 @@ function addon:BuildMissionButton(button,gmc,...) button:Show(); end --- Ripped bleeding from Blizzard code. In mini buttons I cant suffer MP staff -function addon:ClonedGarrisonMissionButton_SetRewards(rewards, numRewards) - if (numRewards > 0) then - local index = 1; - for id, reward in pairs(rewards) do - if (not self.Rewards[index]) then - self.Rewards[index] = CreateFrame("Frame", nil, self, "GarrisonMissionListButtonRewardTemplate"); - self.Rewards[index]:SetPoint("RIGHT", self.Rewards[index-1], "LEFT", 0, 0); - end - local Reward = self.Rewards[index]; - Reward.Quantity:Hide(); - Reward.itemID = nil; - Reward.currencyID = nil; - Reward.tooltip = nil; - if (reward.itemID) then - Reward.itemID = reward.itemID; - GarrisonMissionFrame_SetItemRewardDetails(Reward); - if ( reward.quantity > 1 ) then - Reward.Quantity:SetText(reward.quantity); - Reward.Quantity:Show(); - end - else - Reward.Icon:SetTexture(reward.icon); - Reward.title = reward.title - if (reward.currencyID and reward.quantity) then - if (reward.currencyID == 0) then - Reward.tooltip = GetMoneyString(reward.quantity); - else - Reward.currencyID = reward.currencyID; - Reward.Quantity:SetText(reward.quantity); - Reward.Quantity:Show(); - end - else - Reward.tooltip = reward.tooltip; - end - end - Reward:Show(); - index = index + 1; - end - end - - for i = (numRewards + 1), #self.Rewards do - self.Rewards[i]:Hide(); - end -end -function addon:ClonedGarrisonMissionMechanic_OnEnter(missionID,this,...) +function addon.ClonedGarrisonMissionMechanic_OnEnter(this) local tip=GameTooltip - tip:SetOwner(this, "ANCHOR_CURSOR_RIGHT"); - tip:AddLine(this.info.name,C.White()) - --tip:AddTexture(this.Icon:GetTexture()) - tip:AddLine(this.info.description,C.Orange()) - local t=new() - self:GetAllCounters(missionID,this.Icon:GetTexture(),t) - if( #t > 0) then - tip:AddLine(GARRISON_MISSION_COUNTER_FROM) - for i=1,#t do - tip:AddLine(self:GetFollowerData(t[i],'fullname'),C[self:GetBiasColor(t[i],missionID,C.White())]()) - end - end - del(t) + local button=this:GetParent() + tip:SetOwner(button, "ANCHOR_CURSOR_RIGHT"); + tip:AddLine(this.Name,C.White()) + tip:AddTexture(this.Icon:GetTexture()) + tip:AddLine(this.Description,C.Orange()) tip:Show() end function addon:HookedGarrisonFollowerPage_ShowFollower(frame,followerID,force) @@ -2840,8 +1754,9 @@ do addon:OnClick_GarrisonMissionButton(this.frame,"Leftup") lastTab=2 end - function addon:RenderFollowerPageMissionListBroken(frame,followerID,force) - if not bigscreen then return end + function addon:RenderFollowerPageMissionList(frame,followerID,force) + if not ns.bigscreen then return end + if not GMFFollowers:IsShown() then return end if (not ml) then ml=AceGUI:Create("GMCLayer") ml:SetTitle("Ninso") @@ -2876,29 +1791,27 @@ do return end wipe(partyIndex) - if (#parties==0) then - self:BuildMissionsCache(true,true) - end + local parties=self:GetParty() for missionID,party in pairs(parties) do - if (tContains(party.members,followerID)) then print("Found mission",missionID) tinsert(partyIndex,missionID) end + if (tContains(party.members,followerID)) then ns.xprint("Found mission",missionID) tinsert(partyIndex,missionID) end end table.sort(partyIndex,function(a,b) return parties[a].perc > parties[b].perc end) for i=1,#partyIndex do local missionID=partyIndex[i] local party=parties[missionID] - local mission=cache.missions[missionID] + local mission=self:GetMissionData(missionID) if (mission) then local mb=AceGUI:Create("GMCMissionButton") mb:SetScale(0.6) ml:PushChild(mb,missionID) mb:SetFullWidth(true) - mb:SetMission(mission,missionID,party) + mb:SetMission(mission,party) mb:SetCallback("OnClick",MissionOnClick) end end end - function addon:RenderFollowerPageMissionList(frame,followerID,force) - xprint("hook",followerID,force) + function addon:RenderFollowerPageMissionListOld(frame,followerID,force) + ns.xprint("hook",followerID,force) if (followerID==lastFollowerID and not force) then return end lastFollowerID=followerID local i=0 @@ -2906,8 +1819,8 @@ do if (not GCFMissions.Missions) then GCFMissions.Missions={} end if (not Busystatusmessage) then Busystatusmessage=C(BUSY_MESSAGE,"Red)") end -- frame has every info you can need on a follower, but here I dont really need them, maybe just counters - --xdump(table.Counters) - xprint("Passed",followerID) + --ns.xdump(table.Counters) + ns.xprint("Passed",followerID) local followerName=self:GetFollowerData(followerID,'name',true) repeat -- a poor man goto if (type(frame.followerID)=="number") then @@ -2959,10 +1872,10 @@ do for z = 1,#partyIndex do local missionID=partyIndex[z] if not(tonumber(missionID)) then - --@debug@ - xprint("missionid not a number",missionID) + --[===[@debug@ + ns.xprint("missionid not a number",missionID) self:Dump("partyIndex table",partyIndex) - --@end-debug@ + --@end-debug@]===] perc=-1 --(lowering perc to ignore this mission end @@ -3026,9 +1939,10 @@ end --- --Initial one time setup function addon:SetUp(...) ---@debug@ - xprint("Setup") ---@end-debug@ + self:FollowerCacheInit() +--[===[@debug@ + ns.dprint("Setup") +--@end-debug@]===] --@alpha@ if (not db.alfa.v220) then self:Popup(L["You are using an Alpha version of Garrison Commander. Please post bugs on Curse if you find them"],10) @@ -3041,23 +1955,25 @@ function addon:SetUp(...) self:CheckGMM() self:Options() self:GenerateMissionsWidgets() - self:GMCBuildPanel() + GMC=self:GMCBuildPanel(ns.bigscreen) local tabMC=CreateFrame("CheckButton",nil,GMF,"SpellBookSkillLineTabTemplate") + GMF.tabMC=tabMC tabMC.tooltip="Open Garrison Commander Mission Control" --tab:SetNormalTexture("World\\Dungeon\\Challenge\\clockRunes.blp") --tab:SetNormalTexture("Interface\\Timer\\Challenges-Logo.blp") tabMC:SetNormalTexture("Interface\\ICONS\\ACHIEVEMENT_GUILDPERK_WORKINGOVERTIME.blp") self:MarkAsNew(tabMC,'MissionControl','New in 2.2.0! Try automatic mission management!') tabMC:Show() - GMC.tabMC=tabMC GMF.FollowerStatusInfo=GMF:CreateFontString(nil, "BORDER", "GameFontNormal") GMF.FollowerStatusInfo:SetPoint("TOPRIGHT",-30,-5) local tabCF=CreateFrame("Button",nil,GMF,"SpellBookSkillLineTabTemplate") + GMF.tabCF=tabCF tabCF.tooltip="Open Garrison Commander Configuration Screen" tabCF:SetNormalTexture("Interface\\ICONS\\Trade_Engineering.blp") tabCF:SetPushedTexture("Interface\\ICONS\\Trade_Engineering.blp") tabCF:Show() local tabHP=CreateFrame("Button",nil,GMF,"SpellBookSkillLineTabTemplate") + GMF.tabHP=tabHP tabHP.tooltip="Open Garrison Commander Help" tabHP:SetNormalTexture("Interface\\ICONS\\INV_Misc_QuestionMark.blp") tabHP:SetPushedTexture("Interface\\ICONS\\INV_Misc_QuestionMark.blp") @@ -3074,7 +1990,7 @@ function addon:SetUp(...) bt:SetText(L["Garrison Comander Quick Mission Completion"]) bt:SetPoint("CENTER",0,-50) addon:ActivateButton(bt,"MissionComplete","Complete all missions without confirmation") - self:StartUp() + return self:StartUp() --collectgarbage("step",10) --/Interface/FriendsFrame/UI-Toast-FriendOnlineIcon end @@ -3082,12 +1998,15 @@ function addon:AddMenu() local menu,size=self:CreateOptionsLayer(MP and 'CKMP' or nil,'BIGSCREEN','MOVEPANEL','IGM','IGP','NOFILL','MSORT') --self:AddOptionToOptionsLayer(GCF.Menu,'MSORT') --self:AddOptionToOptionsLayer(GCF.Menu,'ShowMissionControl') ---@debug@ +--[===[@debug@ self:AddOptionToOptionsLayer(menu,'DBG') self:AddOptionToOptionsLayer(menu,'TRC') ---@end-debug@ +--@end-debug@]===] local frame=menu.frame frame:Show() + frame:SetParent(GCF) + frame:SetFrameStrata(GCF:GetFrameStrata()) + frame:SetFrameLevel(GCF:GetFrameLevel()+2) menu:ClearAllPoints() menu:SetPoint("TOPLEFT",GCF,"TOPLEFT",25,-18) menu:SetWidth(GCF:GetWidth()-50) @@ -3112,9 +2031,9 @@ end -- This method is called every time garrison mission panel is open because -- when it closes, I remove most of used hooks function addon:StartUp(...) ---@debug@ - xprint("Startup") ---@end-debug@ +--[===[@debug@ + ns.dprint("Startup") +--@end-debug@]===] self:GrowPanel() self:Unhook(GMF,"OnShow") if (self:GetBoolean("PIN")) then @@ -3124,11 +2043,10 @@ function addon:StartUp(...) GCF:SetHeight(minHeight) end self:PermanentEvents() - self:SafeSecureHook("GarrisonMissionButton_AddThreatsToTooltip") - self:SafeSecureHook("GarrisonMissionButton_SetRewards") + --self:SafeSecureHook("GarrisonMissionButton_AddThreatsToTooltip") self:SafeSecureHook("GarrisonFollowerListButton_OnClick") -- used both to update follower mission list and itemlevel display - if (bigscreen) then - self:SafeSecureHook("GarrisonFollowerPage_ShowFollower")--,function(...) xprint("GarrisonFollowerPage_ShowFollower",...) end) + if (ns.bigscreen) then + self:SafeSecureHook("GarrisonFollowerPage_ShowFollower")--,function(...) ns.xprint("GarrisonFollowerPage_ShowFollower",...) end) self:SafeSecureHook("GarrisonFollowerTooltipTemplate_SetGarrisonFollower") end self:SafeSecureHook("GarrisonMissionFrame_HideCompleteMissions") -- Mission reward completed @@ -3147,16 +2065,14 @@ function addon:StartUp(...) for i=1,#GMFMissionListButtons do local b=GMFMissionListButtons[i] self:SafeHookScript(b,"OnClick","OnClick_GarrisonMissionButton",true) ---@debug@ - self:SafeHookScript(b,"OnEnter","AddMissionId",true) - self:ScheduleRepeatingTimer("Clock",1) ---@end-debug@ end - self:BuildMissionsCache(true,true) - self:BuildRunningMissionsCache() + --self:ScheduleRepeatingTimer("Clock",1) self:RefreshFollowerStatus() self:Trigger("MSORT") self:Trigger("CKMP") + GMFMissions.listScroll.update = over.GarrisonMissionList_Update + table.sort(GMFMissions.inProgressMissions,sorters.EndTime) + return self:RefreshMissions() end function addon:MarkAsNew(obj,key,message) if (not db.news[key]) then @@ -3183,29 +2099,29 @@ function addon:PermanentEvents() end function addon:checkMethod(method,hook) if (type(self[method])=="function") then ---@debug@ - --xprint("Hooking ",hook,"to self:" .. method) ---@end-debug@ +--[===[@debug@ + --ns.xprint("Hooking ",hook,"to self:" .. method) +--@end-debug@]===] return true ---@debug@ +--[===[@debug@ else - --xprint("Hooking ",hook,"to print") ---@end-debug@ + --ns.xprint("Hooking ",hook,"to print") +--@end-debug@]===] end end function addon:SafeRegisterEvent(event) ---@debug@ +--[===[@debug@ if not self.evdebug:IsEventRegistered(event) then self.evdebug:RegisterEvent(event) end ---@end-debug@ +--@end-debug@]===] local method="Event"..event if (self:checkMethod(method,event)) then return self:RegisterEvent(event,method) ---@debug@ +--[===[@debug@ else - return self:RegisterEvent(event,xprint) ---@end-debug@ + return self:RegisterEvent(event,ns.xprint) +--@end-debug@]===] end end function addon:SafeSecureHook(tobehooked,method) @@ -3213,13 +2129,13 @@ function addon:SafeSecureHook(tobehooked,method) method=method or "Hooked"..tobehooked if (self:checkMethod(method,tobehooked)) then return self:SecureHook(tobehooked,method) ---@debug@ +--[===[@debug@ else do local hooked=tobehooked - return self:SecureHook(tobehooked,function(...) xprint(hooked,...) end) + return self:SecureHook(tobehooked,function(...) ns.xprint(hooked,...) end) end ---@end-debug@ +--@end-debug@]===] end end function addon:SafeHookScript(frame,hook,method,postHook) @@ -3260,9 +2176,9 @@ function addon:CleanUp() GarrisonFollowerTooltip.fs:Hide() end --collectgarbage("collect") ---@debug@ - xprint("Cleaning up") ---@end-debug@ +--[===[@debug@ + ns.xprint("Cleaning up") +--@end-debug@]===] end function addon:EventGARRISON_FOLLOWER_XP_CHANGED(event,followerID,iLevel,xp,level,quality) local i=followersCacheIndex[followerID] @@ -3280,116 +2196,43 @@ function addon:EventGARRISON_FOLLOWER_XP_CHANGED(event,followerID,iLevel,xp,leve wipe(followersCache) self:GetFollowerData(followerID) -- triggering a full cache refresh end - -function addon:RecalculateFollower(follower,refreshrank) - if (refreshrank) then - follower.level=G.GetFollowerLevel(follower.followerID) - follower.quality=G.GetFollowerQuality(follower.followerID) - end - follower.rank=follower.level==100 and follower.iLevel or follower.level - follower.coloredname=C(follower.name,tostring(follower.quality)) - follower.fullname=format("%3d %s",follower.rank,follower.coloredname) - follower.maxed=follower.quality >= GARRISON_FOLLOWER_MAX_UPGRADE_QUALITY and follower.level >=GARRISON_FOLLOWER_MAX_LEVEL - local weaponItemID, weaponItemLevel, armorItemID, armorItemLevel = G.GetFollowerItems(follower.followerID); - follower.weaponItemID=weaponItemID - follower.weaponItemLevel=weaponItemLevel - follower.armorItemID=armorItemID - follower.armorItemLevel=armorItemLevel - follower.weaponQuality=select(3,GetItemInfo(weaponItemID)) - follower.armorQuality=select(3,GetItemInfo(armorItemID)) -end -function addon:CanCounter(followerID,id) - local abilities=self:GetFollowerData(followerID,abilities) - for i=1,#abilities do - local ability=abilities[i] - for k,v in pairs(ability.counter) do - if (k==trait or v.name==trait) then - return true - end - end +function addon:IsFollowerAvailableForMission(followerID,skipbusy) + if self:GMCBusy(followerID) then + return false end -end -function addon:HasTrait(followerID,trait) - local abilities=self:GetFollowerData(followerID,abilities) - for i=1,#abilities do - local ability=abilities[i] - if ability.isTrait then - if ability.ID==trait then - return true - end - end + if (not skipbusy) then + return self:GetFollowerStatus(followerID) ~= GARRISON_FOLLOWER_WORKING + else + return self:GetFollowerStatus(followerID) == AVAILABLE end end -function addon:GetFollowerData(key,subkey,refresh) - local k=followersCacheIndex[key] - if (not followersCache[1]) then - followersCache=G.GetFollowers() - for i,follower in pairs(followersCache) do - if (not follower.isCollected) then - followersCache[i]=nil - else - self:RecalculateFollower(follower) - follower.abilities=G.GetFollowerAbilities(follower.followerID) - end - end - refresh=false - end - local t=followersCache - if (not k) then - for i=1,#t do - if (t[i] and (t[i].followerID == key or t[i].name==key)) then - followersCacheIndex[t[i].followerID]=i - followersCacheIndex[t[i].name]=i - k=i - break - end +if ns.toc < 60100 then + G.GetFollowerMissionTimeLeft= function(followerID) + local running=dbcache.running[dbcache.runningIndex[followerID]] + if (running) then + return SecondsToTime(running.started + running.duration - time(),true) + else + return 0 end end - if (k and type(t[k]=='table')) then - if (refresh) then - self:RecalculateFollower(t[k],true) - end - if (subkey) then - return t[k][subkey] + G.GetFollowerMissionTimeLeftSeconds=function(followerID) + local running=dbcache.running[dbcache.runningIndex[followerID]] + if (running) then + return running.started + running.duration - time() else - return t[k] + return 0 end - else - return nil - end -end -function addon:GetMissionData(missionID,subkey) - local missionCache=cache.missions[missionID] - if (not missionCache) then ---@debug@ - xprint("Found a new mission",missionID,"Refreshing it") ---@end-debug@ - self:BuildMissionCache(missionID) - self:FillCounters(missionID,cache.missions[missionID]) - self:MatchMaker(missionID,cache.missions[missionID]) - end - if (subkey) then - if not missionCache then return 0 end - return missionCache[subkey] - end - return missionCache -end -function addon:IsFollowerAvailableForMission(followerID,skipbusy) - if (GMCUsedFollowers[followerID]) then - return false end - if (not skipbusy) then - return true - else - return self:GetFollowerStatus(followerID) == AVAILABLE + G.IsMechanicFullyCountered=function(missionID,followerID) + return G.GetFollowerBiasForMission(missionID,followerID)>0.99 end end function addon:GetFollowerStatus(followerID,withTime,colored) + --C_Garrison.GetFollowerMissionTimeLeftSeconds(follower.followerID) if (not followerID) then return UNAVAILABLE end local status=G.GetFollowerStatus(followerID) if (status and status== GARRISON_FOLLOWER_ON_MISSION and withTime) then - local running=dbcache.running[dbcache.runningIndex[followerID]] - status=SecondsToTime(running.started + running.duration - time() ,true) + status=G.GetFollowerMissionTimeLeft(followerID) end -- The only case a follower appears in party is after a refused mission due to refresh triggered before GARRISON_FOLLOWER_LIST_UPDATE if (status and status~=GARRISON_FOLLOWER_IN_PARTY) then @@ -3406,17 +2249,15 @@ end function addon:FillMissionPage(missionInfo) if type(missionInfo)=="number" then missionInfo=self:GetMissionData(missionInfo) end if not missionInfo then return end - if( IsControlKeyDown()) then xprint("Shift key, ignoring mission prefill") return end + if( IsControlKeyDown()) then ns.xprint("Shift key, ignoring mission prefill") return end if (self:GetBoolean("NOFILL")) then return end local missionID=missionInfo.missionID ---@debug@ - xprint("UpdateMissionPage for",missionID,missionInfo.name,missionInfo.numFollowers) ---@end-debug@ - --xdump(missionInfo) - --self:BuildMissionData(missionInfo.missionID.missionInfo) - holdEvents() +--[===[@debug@ + ns.xprint("UpdateMissionPage for",missionID,missionInfo.name,missionInfo.numFollowers) +--@end-debug@]===] + self:holdEvents() GarrisonMissionPage_ClearParty() - local party=parties[missionID] + local party=self:GetParty(missionID) if (party) then local members=party.members for i=1,missionInfo.numFollowers do @@ -3425,9 +2266,9 @@ function addon:FillMissionPage(missionInfo) local status=G.GetFollowerStatus(followerID) if (false and status) then if status == GARRISON_FOLLOWER_IN_PARTY then -- Left from a previous assignment? ---@debug@ - xprint(followerID,self:GetFollowerData(followerID,"name"),"was already on mission") ---@end-debug@ +--[===[@debug@ + ns.xprint(followerID,self:GetFollowerData(followerID,"name"),"was already on mission") +--@end-debug@]===] self:RemoveFromAllMissions(followerID) GarrisonMissionPage_AddFollower(followerID) else @@ -3435,14 +2276,18 @@ function addon:FillMissionPage(missionInfo) end else pcall(G.RemoveFollowerFromMission,missionID,followerID) - xprint("Adding",followerID,G.GetFollowerName(followerID)) + ns.xprint("Adding",followerID,G.GetFollowerName(followerID)) GarrisonMissionPage_AddFollower(followerID) end end end end - GarrisonMissionPage_UpdateMissionForParty() - releaseEvents() + if ns.toc>=60100 then + GarrisonMissionPage_UpdateParty() + else + GarrisonMissionPage_UpdateMissionForParty() + end + self:releaseEvents() end local firstcall=true @@ -3451,7 +2296,7 @@ local firstcall=true -- function addon:GrowPanel() GCF:Show() - if (bigscreen) then + if (ns.bigscreen) then -- GMF:ClearAllPoints() -- GMF:SetPoint("TOPLEFT",GCF,"BOTTOMLEFT") -- GMF:SetPoint("TOPRIGHT",GCF,"BOTTOMRIGHT") @@ -3503,7 +2348,7 @@ function addon:GetBiasColor(followerID,missionID,goodcolor) end return goodcolor end -function addon:RenderFollowerButton(frame,followerID,missionID) +function addon:RenderFollowerButton(frame,followerID,missionID,b,t) if (not frame) then return end if (frame.Threats) then for i=1,#frame.Threats do @@ -3533,6 +2378,7 @@ function addon:RenderFollowerButton(frame,followerID,missionID) frame.info=nil return end + frame:EnableMouse(true) frame.PortraitFrame.Level:SetTextColor(1,1,1,1) frame.PortraitFrame.Portrait:Show() local info=self:GetFollowerData(followerID) @@ -3563,22 +2409,27 @@ function addon:RenderFollowerButton(frame,followerID,missionID) frame.PortraitFrame.LevelBorder:SetWidth(58); showItemLevel = false; end - GarrisonMissionFrame_SetFollowerPortrait(frame.PortraitFrame, info, showItemLevel); + GarrisonMissionFrame_SetFollowerPortrait(frame.PortraitFrame, info, false); -- Counters icon - if (frame.Name) then - if (missionID and not GMF.MissionTab.MissionList.showInProgress) then + if (frame.Name and frame.Threats) then + if (missionID and not GMFMissions.showInProgress) then local tohide=1 - local missionCounters=counters[missionID] - local index=counterFollowerIndex[missionID][followerID] - for i=1,#index do - local k=index[i] - local t=frame.Threats[i] - local tx=missionCounters[k].icon - t.Icon:SetTexture(tx) - local color=self:GetBiasColor(missionCounters[k].bias,nil,"Green") - t.Border:SetVertexColor(C[color]()) - t:Show() - tohide=i+1 + if b and b[followerID] then + for i=1,#b[followerID] do + local th=frame.Threats[tohide] + th.Icon:SetTexture(b[followerID][i].icon) + th:Show() + tohide=tohide+1 + end + end + if t and t[followerID] then + for i=1,#t[followerID] do + if tohide>#frame.Threats then break end + local th=frame.Threats[tohide] + th.Icon:SetTexture(t[followerID][i].icon) + th:Show() + tohide=tohide+1 + end end else frame.Status:Hide() @@ -3587,11 +2438,12 @@ function addon:RenderFollowerButton(frame,followerID,missionID) end -- pseudo static local scale=0.9 -function addon:BuildFollowersButtons(button,bg,limit) + +function addon:BuildFollowersButtons(button,bg,limit,bigscreen) if (bg.Party) then return end bg.Party={} for numMembers=1,3 do - local f=CreateFrame("Button",nil,bg,bigscreen and "GarrisonCommanderMissionPageFollowerTemplate" or "GarrisonCommanderMissionPageFollowerTemplateSmall" ) + local f=CreateFrame("Button","fol_"..button.info.missionID.."_"..numMembers,bg,bigscreen and "GarrisonCommanderMissionPageFollowerTemplate" or "GarrisonCommanderMissionPageFollowerTemplateSmall" ) if (numMembers==1) then f:SetPoint("BOTTOMLEFT",button.Rewards[1],"BOTTOMRIGHT",10,0) else @@ -3603,8 +2455,7 @@ function addon:BuildFollowersButtons(button,bg,limit) end tinsert(bg.Party,f) f:EnableMouse(true) - f:SetScript("OnEnter",GarrisonMissionPageFollowerFrame_OnEnter) - f:SetScript("OnLeave",GarrisonMissionPageFollowerFrame_OnLeave) + f.missionID=button.info.missionID f:RegisterForClicks("AnyUp") f:SetScript("OnClick",function(...) self:OnClick_PartyMember(...) end) if (bigscreen) then @@ -3630,93 +2481,6 @@ function addon:BuildFollowersButtons(button,bg,limit) button.Threats[1]:SetPoint("TOPLEFT",165,0) end end -function addon:RenderExtraButton(button,numRewards) - local panel=button.gcINDICATOR - local missionInfo=button.info - local missionID=missionInfo.missionID - panel.missionID=missionID - local mission=missionInfo - if not mission then return end -- something went wrong while refreshing - if (not bigscreen) then - local index=mission.numFollowers+numRewards-3 - local position=(index * -65) - 130 - button.gcPANEL.Party[1]:ClearAllPoints() - button.gcPANEL.Party[1]:SetPoint("BOTTOMLEFT",button.Rewards[1],"BOTTOMLEFT", position,0) - end - if (GMF.MissionTab.MissionList.showInProgress) then - local perc=select(4,G.GetPartyMissionInfo(missionID)) - panel.Percent:SetFormattedText(GARRISON_MISSION_PERCENT_CHANCE,perc) - panel.Percent:SetJustifyV("CENTER") - panel.Age:Hide() - panel.Percent:SetTextColor(self:GetDifficultyColors(perc)) - for i=1,3 do - local frame=button.gcPANEL.Party[i] - if (missionInfo.followers[i]) then - self:RenderFollowerButton(frame,missionInfo.followers[i],missionID) - frame:Show() - else - frame:Hide() - end - end - return - else - panel.Percent:SetJustifyV("BOTTOM") - end - local party=parties[missionID] - if (#party.members==0) then - local mission=self:GetMissionData(missionID) -- matchmaker and fillcounters need our enriched mission - self:FillCounters(missionID,mission) - self:MatchMaker(missionID,mission,party) - end - local perc=party.perc - local age=tonumber(dbcache.seen[missionID]) - local notFull=false - for i=1,3 do - local frame=button.gcPANEL.Party[i] - if (i>mission.numFollowers) then - frame:Hide() - else - if (party.members[i]) then - self:RenderFollowerButton(frame,party.members[i],missionID) - if (bigscreen) then frame.NotFull:Hide() end - else - self:RenderFollowerButton(frame,false) - if (bigscreen) then frame.NotFull:Show() end - end - frame:Show() - end - end - panel=button.gcINDICATOR - panel.Percent:SetFormattedText(GARRISON_MISSION_PERCENT_CHANCE,perc) - panel.Percent:SetTextColor(self:GetDifficultyColors(perc)) - panel.Percent:SetWidth(80) - panel.Percent:SetJustifyH("RIGHT") - local text - if (age) then - local expire=ns.wowhead[missionID] - if (expire==9999999) then - panel.Age:SetText("Expires: Far far away") - panel.Age:SetTextColor(C.White()) - elseif (expire==0) then - panel.Age:SetText("Expires: " .. UNKNOWN) - panel.Age:SetTextColor(C.White()) - else - local age=(age+(expire*2)-time())/60 - if age < 0 then age=0 end - local hours=(floor((age/60)/6)+1)*6 - local q=self:GetDifficultyColor(hours+20,true) - panel.Age:SetFormattedText("Expires in less than %d hr",hours) - panel.Age:SetTextColor(q.r,q.g,q.b) - end - else - panel.Age:SetText(UNKNOWN) - end ---@debug@ - panel.Age:SetText(panel.Age:GetText().. " " .. date("%m/%d/%y %H:%M:%S",age)) ---@end-debug@ - panel.Age:Show() - panel.Percent:Show() -end function addon:CheckExpire(missionID) local age=tonumber(dbcache.seen[missionID]) local expire=ns.wowhead[missionID] @@ -3726,23 +2490,12 @@ function addon:CheckExpire(missionID) print("Age+expire",date("%m/%d/%y %H:%M:%S",age+expire)) print("Delta",age+expire-time()) end -function addon:BuildExtraButton(button) - local bg=CreateFrame("Button",nil,button,"GarrisonCommanderMissionButton") - local indicators=CreateFrame("Frame",nil,button,"GarrisonCommanderIndicators") - indicators:SetPoint("LEFT",70,0) - bg:SetPoint("RIGHT") - bg.button=button - bg:SetScript("OnEnter",function(this) GarrisonMissionButton_OnEnter(this.button) end) - bg:SetScript("OnLeave",function() GameTooltip:FadeOut() end) - bg:RegisterForClicks("AnyUp") - bg:SetScript("OnClick",function(...) self:OnClick_GCMissionButton(...) end) - button.gcPANEL=bg - button.gcINDICATOR=indicators - if (not bg.Party) then self:BuildFollowersButtons(button,bg,3) end +function addon:BuildExtraButton(button,bigscreen) + end function addon:OnShow_FollowerPage(page) if not GCFMissions then return end - xprint("Onshow") + ns.xprint("Onshow") if type(GCFMissions.Header.info)=="table" then self:HookedGarrisonFollowerPage_ShowFollower(page,GCFMissions.Header.info.followerID,true) -- local s =self:GetScroller("GFCMissions.Header") @@ -3808,7 +2561,7 @@ function addon:IgnoreFollower(table,missionID,followerID,flag) end -- full ignore disabled for now dbcache.totallyignored[followerID]=nil - self:RefreshMission(missionID) + self:RefreshMissions(missionID) end function addon:UnignoreFollower(table,missionID,followerID,flag) if (followerID=='all') then @@ -3816,7 +2569,7 @@ function addon:UnignoreFollower(table,missionID,followerID,flag) else dbcache.ignored[missionID][followerID]=nil end - self:RefreshMission(missionID) + self:RefreshMissions(missionID) end function addon:OpenFollowersTab() GarrisonMissionFrame_SelectTab(2) @@ -3837,9 +2590,9 @@ function addon:OnClick_GarrisonMissionButton(tab,button) return end if (type(tab.info)~="table") then return end ---@debug@ - xprint("Clicked GarrisonMissionButton") ---@end-debug@ +--[===[@debug@ + ns.xprint("Clicked GarrisonMissionButton") +--@end-debug@]===] if (tab.fromFollowerPage) then if (#tab.info.followers>0) then return @@ -3858,1254 +2611,624 @@ function addon:OnClick_GCMissionButton(frame,button) end end -function addon:HookedGarrisonMissionButton_SetRewards(button,rewards,numRewards) - if GMF.MissionTab.MissionList.showInProgress and button.info.missionID==button.lastMissionID then collectgarbage("step",50) return end - button.lastMissionID=button.info.missionID - return self:RenderButton(button,rewards,numRewards) -end -function addon:RenderButton(button,rewards,numRewards) - if (not button or not button.Title) then ---@debug@ - error(strconcat("Called on I dunno what ",tostring(button)," ", tostring(button:GetName()))) - return ---@end-debug@ - end - local missionID=button.info.missionID - if (bigscreen) then - local width=GMF.MissionTab.MissionList.showInProgress and BIGBUTTON or SMALLBUTTON - button:SetWidth(width+600) - button.Rewards[1]:SetPoint("RIGHT",button,"RIGHT",-500 - (GMM and 40 or 0),0) - end - if (not button.xp) then - button.xp=button:CreateFontString(nil, "ARTWORK", "QuestMaprewardsFont") - button.xp:SetPoint("TOPRIGHT",button.Rewards[1],"TOPRIGHT") - button.xp:SetJustifyH("RIGHT") - end - button.MissionType:SetPoint("TOPLEFT",5,-2) - button.xp:SetWidth(0) - if (not GMF.MissionTab.MissionList.showInProgress) then - button.xp:SetFormattedText("Xp: %d (approx)",self:GetMissionData(missionID,'globalXp')) - button.xp:SetTextColor(self:GetDifficultyColors(self:GetMissionData(missionID,'totalXp')/3000*100)) - button.xp:Show() +--[[ +addon.oldSetUp=addon.SetUp +function addon:ExperimentalSetUp() + +end +addon.SetUp=addon.ExperimentalSetUp +--]] + + +-- Blizzard functions override +local function override(blizfunc) + if not orig[blizfunc] then + orig[blizfunc]=_G[blizfunc] + _G[blizfunc]=over[blizfunc] + end +--[===[@debug@ + print("Overriding ",blizfunc) +--@end-debug@]===] +end +function over.StolenGarrisonMissionPageFollowerFrame_OnEnter(self) + if not self.info then + return; + end + + GarrisonFollowerTooltip:ClearAllPoints(); + GarrisonFollowerTooltip:SetPoint("TOPLEFT", self, "BOTTOMRIGHT"); + GarrisonFollowerTooltip_Show(self.info.garrFollowerID, + self.info.isCollected, + C_Garrison.GetFollowerQuality(self.info.followerID), + C_Garrison.GetFollowerLevel(self.info.followerID), + C_Garrison.GetFollowerXP(self.info.followerID), + C_Garrison.GetFollowerLevelXP(self.info.followerID), + C_Garrison.GetFollowerItemLevelAverage(self.info.followerID), + C_Garrison.GetFollowerAbilityAtIndex(self.info.followerID, 1), + C_Garrison.GetFollowerAbilityAtIndex(self.info.followerID, 2), + C_Garrison.GetFollowerAbilityAtIndex(self.info.followerID, 3), + C_Garrison.GetFollowerAbilityAtIndex(self.info.followerID, 4), + C_Garrison.GetFollowerTraitAtIndex(self.info.followerID, 1), + C_Garrison.GetFollowerTraitAtIndex(self.info.followerID, 2), + C_Garrison.GetFollowerTraitAtIndex(self.info.followerID, 3), + C_Garrison.GetFollowerTraitAtIndex(self.info.followerID, 4), + true, + C_Garrison.GetFollowerBiasForMission(self.missionID, self.info.followerID) < 0.0 + ); +end + +function over.GarrisonMissionFrame_SetFollowerPortrait(portraitFrame, followerInfo, forMissionPage) + local color = ITEM_QUALITY_COLORS[followerInfo.quality]; + portraitFrame.PortraitRingQuality:SetVertexColor(color.r, color.g, color.b); + portraitFrame.LevelBorder:SetVertexColor(color.r, color.g, color.b); + if ( forMissionPage ) then + local boosted = false; + local followerLevel = followerInfo.level; + if ( MISSION_PAGE_FRAME.mentorLevel and MISSION_PAGE_FRAME.mentorLevel > followerLevel ) then + followerLevel = MISSION_PAGE_FRAME.mentorLevel; + boosted = true; + end + if ( MISSION_PAGE_FRAME.showItemLevel and followerLevel == GarrisonMissionFrame.followerMaxLevel ) then + local followerItemLevel = followerInfo.iLevel; + if ( MISSION_PAGE_FRAME.mentorItemLevel and MISSION_PAGE_FRAME.mentorItemLevel > followerItemLevel ) then + followerItemLevel = MISSION_PAGE_FRAME.mentorItemLevel; + boosted = true; + end + portraitFrame.Level:SetFormattedText(GARRISON_FOLLOWER_ITEM_LEVEL, followerItemLevel); + portraitFrame.LevelBorder:SetAtlas("GarrMission_PortraitRing_iLvlBorder"); + portraitFrame.LevelBorder:SetWidth(70); + else + portraitFrame.Level:SetText(followerLevel); + portraitFrame.LevelBorder:SetAtlas("GarrMission_PortraitRing_LevelBorder"); + portraitFrame.LevelBorder:SetWidth(58); + end + local followerBias = C_Garrison.GetFollowerBiasForMission(MISSION_PAGE_FRAME.missionInfo.missionID, followerInfo.followerID); + if ( followerBias == -1 ) then + portraitFrame.Level:SetTextColor(1, 0.1, 0.1); + elseif ( followerBias < 0 ) then + portraitFrame.Level:SetTextColor(1, 0.5, 0.25); + elseif ( boosted ) then + portraitFrame.Level:SetTextColor(0.1, 1, 0.1); + else + portraitFrame.Level:SetTextColor(1, 1, 1); + end + portraitFrame.Caution:SetShown(followerBias < 0); + else - button.xp:Hide() + portraitFrame.Level:SetText(followerInfo.level); end - --button.Title:SetText("123456789012345678901234567890123456789012345678901234567890") -- Used for design - local offset= bigscreen and (numRewards *65) or (button.info.numFollowers+numRewards) *65 - local tw=button:GetWidth() - 165 - if (button.Title:GetWidth() + button.Summary:GetWidth() + button.xp:GetWidth() < (tw -offset) ) then - button.Title:SetPoint("LEFT", 165, 5); - button.Summary:ClearAllPoints(); - button.Summary:SetPoint("BOTTOMLEFT", button.Title, "BOTTOMRIGHT", 8, 0); - else - button.Title:SetPoint("LEFT", 165, 25); - button.Title:SetWidth(tw - offset); - button.Summary:ClearAllPoints(); - button.Summary:SetPoint("TOPLEFT", button.Title, "BOTTOMLEFT", 0, -4); + if ( followerInfo.displayID ) then + GarrisonFollowerPortrait_Set(portraitFrame.Portrait, followerInfo.portraitIconID); end - local threatIndex=1 - if (not GMF.MissionTab.MissionList.showInProgress) then - if (not button.Threats) then -- I am a good guy. If MP present, I dont make my own threat indicator (Only MP <= 1.8) - if (not button.Env) then - button.Env=CreateFrame("Frame",nil,button,"GarrisonAbilityCounterTemplate") - button.Env:SetWidth(20) - button.Env:SetHeight(20) - button.Env:SetPoint("BOTTOMLEFT",button,165,8) - button.GcThreats={} +end + +function over.GarrisonMissionPage_Close(self) + GarrisonMissionPage_ClearParty(); + GarrisonMissionFrame.MissionTab.MissionPage:Hide(); + GarrisonMissionFrame.followerCounters = nil; + GarrisonMissionFrame.MissionTab.MissionPage.missionInfo = nil; + if (lastTab) then + GarrisonMissionFrame_SelectTab(lastTab) + end + -- I hooked this handler, so I dont want it to be called in the middle of cleanup operations + GarrisonMissionFrame.MissionTab.MissionList:Show(); +end +function over.GarrisonMissionButton_SetRewards(self, rewards, numRewards) + if (numRewards > 0) then + local index = 1; + local party=self.party + local mission=self.info + for id, reward in pairs(rewards) do + if (not self.Rewards[index]) then + self.Rewards[index] = CreateFrame("Frame", nil, self, "GarrisonMissionListButtonRewardTemplate"); + self.Rewards[index]:SetPoint("RIGHT", self.Rewards[index-1], "LEFT", 0, 0); end - local slots=self:GetMissionData(missionID,'slots') - if (not GMF.MissionTab.MissionList.showInProgress) then - button.Env:Show() - for i=1,#slots do - local slot=slots[i] - if (slot.name==TYPE) then - button.Env.Icon:SetTexture(slot.icon) - self:SetThreatColor(button.Env,missionID) - button.Env.info=self.db.global.types[slot.key] - button.Env:SetScript("OnEnter",function(...) addon:ClonedGarrisonMissionMechanic_OnEnter(missionID,...) end) - button.Env:SetScript("OnLeave",function() GameTooltip:Hide() end) - else - local th=button.GcThreats[threatIndex] - if (not th) then - th=CreateFrame("Frame",nil,button,"GarrisonAbilityCounterTemplate") - th:SetWidth(20) - th:SetHeight(20) - th:SetPoint("BOTTOMLEFT",button,165 + 35 * threatIndex,8) - button.GcThreats[threatIndex]=th - end - th.info=slot - threatIndex=threatIndex+1 - th.Icon:SetTexture(slot.icon) - self:SetThreatColor(th,missionID) - th:Show() - th:SetScript("OnEnter",function(...) addon:ClonedGarrisonMissionMechanic_OnEnter(missionID,...) end) - th:SetScript("OnLeave",function() GameTooltip:Hide() end) + local Reward = self.Rewards[index]; + Reward.Quantity:Hide(); + Reward.itemID = nil; + Reward.currencyID = nil; + Reward.tooltip = nil; + Reward.Quantity:SetTextColor(C.White()) + if (reward.itemID) then + Reward.itemID = reward.itemID; + GarrisonMissionFrame_SetItemRewardDetails(Reward); + if ( reward.quantity > 1 ) then + Reward.Quantity:SetText(reward.quantity); + Reward.Quantity:Show(); + elseif reward.itemID==120205 then + Reward.Quantity:SetText(self.info.xp); + Reward.Quantity:Show(); + else + local name,link,quality,iLevel,level=GetItemInfo(reward.itemID) + if (name) then + Reward.Quantity:SetText(iLevel==1 and level or iLevel); + Reward.Quantity:SetTextColor(ITEM_QUALITY_COLORS[quality].r,ITEM_QUALITY_COLORS[quality].g,ITEM_QUALITY_COLORS[quality].b) + Reward.Quantity:Show(); end + end else - button.Env:Hide() - end - end - if (numRewards > 0) then - local index=1 - for id,reward in pairs(rewards) do - local Reward = button.Rewards[index]; - Reward.Quantity:SetTextColor(C.Yellow()) - if (reward.followerXP) then - Reward.Quantity:SetText(reward.followerXP) - Reward.Quantity:Show() - elseif (reward.currencyID==0) then - Reward.Quantity:SetFormattedText("%d",reward.quantity/10000) - Reward.Quantity:Show() - elseif (reward.itemID and reward.itemID==120205) then - Reward.Quantity:SetFormattedText("%d",self:GetMissionData(missionID,'xp') or 1) - Reward.Quantity:Show() - elseif (reward.itemID and reward.quantity==1) then - local _,_,q,i=GetItemInfo(reward.itemID) - Reward.Quantity:SetText(i) - local c=ITEM_QUALITY_COLORS[q] - if (not c) then - Reward.Quantity:SetTextColor(1,1,1) + Reward.Icon:SetTexture(reward.icon); + Reward.title = reward.title + if (reward.currencyID and reward.quantity) then + if (reward.currencyID == 0) then + local multi=party.goldMultiplier or 1 + Reward.tooltip = GetMoneyString(reward.quantity); + Reward.Quantity:SetText(reward.quantity/10000 *multi); + Reward.Quantity:Show(); + if multi >1 then + Reward.Quantity:SetTextColor(C:Green()) + else + Reward.Quantity:SetTextColor(C:Gold()) + end + elseif (reward.currencyID == GARRISON_CURRENCY) then + local multi=party.materialMultiplier or 1 + Reward.tooltip = GetMoneyString(reward.quantity); + Reward.Quantity:SetText(reward.quantity * multi); + Reward.Quantity:Show(); + if multi >1 then + Reward.Quantity:SetTextColor(C:Green()) + else + Reward.Quantity:SetTextColor(C:Gold()) + end else - Reward.Quantity:SetTextColor(c.r,c.g,c.b) + Reward.currencyID = reward.currencyID; + Reward.Quantity:SetText(reward.quantity); + Reward.Quantity:Show(); + Reward.Quantity:SetTextColor(C:Gold()) end - Reward.Quantity:Show() - end - index=index+1 - end - end - else - if (button.Env) then button.Env:Hide() end - end - if (button.GcThreats) then - for i=threatIndex,#button.GcThreats do - button.GcThreats[i]:Hide() - end - end - if (button.fromFollowerPage) then - return - end - if (not button.gcPANEL) then - self:BuildExtraButton(button) - end - return self:RenderExtraButton(button,numRewards) -end - --- Courtesy of Motig --- Concept and interface reused with permission --- Mission building rewritten from scratch -local GMC_G = {} ---GMC_G.frame = CreateFrame('FRAME') -local aMissions={} - -function addon:GMCCreateMissionList(workList) - --First get rid of unwanted rewards and missions that are too long - local settings=self.privatedb.profile.missionControl - local ar=settings.allowedRewards - wipe(workList) - for missionID,mission in pairs(cache.missions) do - local discarded=false - repeat - if (mission.durationSeconds > settings.maxDuration * 3600 or mission.durationSeconds < settings.minDuration * 3600) then - xprint(missionID,"discarded due to len",mission.durationSeconds /3600) - break - end -- Mission too long, out of here - if (mission.isRare and settings.skipRare) then - xprint(missionID,"discarded due to rarity") - break - end - for k,v in pairs(ar) do - if (not v) then - if (mission[k] and mission[k]~=0) then -- we have a forbidden reward - discarded=true - break + else + if reward.followerXP then + Reward.Quantity:SetText(reward.followerXP); + Reward.Quantity:Show(); + if party.xpBonus and party.xpBonus > 0 then + Reward.Quantity:SetTextColor(C:Green()) + else + Reward.Quantity:SetTextColor(C:Gold()) + end end + Reward.tooltip = reward.tooltip; end end - if (not discarded) then - tinsert(workList,missionID) - end - until true - end - local function msort(i1,i2) - local m1=addon:GetMissionData(i1) - local m2=addon:GetMissionData(i2) - for i=1,#GMC.settings.itemPrio do - local criterium=GMC.settings.itemPrio[i] - if (criterium) then - if (m1[criterium] ~= m2[criterium]) then - return m1[criterium] > m2[criterium] - end - end - end - if (parties[m1.missionID].perc and parties[m2.missionID].perc) then - return parties[m1.missionID].perc > parties[m2.missionID].perc - end - return m1.level > m2.level - end - table.sort(workList,msort) - --@debug@ - xprint("Sorted list") - local x=new() - for i=1,#workList do - local mission=self:GetMissionData(workList[i]) - local t=new() - for i=1,#GMC.settings.itemPrio do - local criterium=GMC.settings.itemPrio[i] - tinsert(t,format("%s: %d",criterium,mission[criterium])) + Reward:Show(); + index = index + 1; end - tinsert(x,mission.name .." ".. strjoin("\t",unpack(t)) .. " Success" .. tostring(parties[mission.missionID].perc)) - del(t) end - local scroll=self:GetScroller("Sorted missions") - self:cutePrint(scroll,x) - del(x) - --@end-debug@ + for i = (numRewards + 1), #self.Rewards do + self.Rewards[i]:Hide(); + end end -local factory={} --#factory do - local nonce=0 - local GetTime=GetTime - function factory:Slider(father,min,max,current,message) - local name=tostring(self)..GetTime()*1000 ..nonce - nonce=nonce+1 - local sl = CreateFrame('Slider',name, father, 'OptionsSliderTemplate') - sl:SetWidth(128) - sl:SetHeight(20) - sl:SetOrientation('HORIZONTAL') - sl:SetMinMaxValues(min, max) - sl:SetValue(current) - sl:SetValueStep(1) - sl.Low=_G[name ..'Low'] - sl.Low:SetText(min) - sl.High=_G[name .. 'High'] - sl.High:SetText(max) - sl.Text=_G[name.. 'Text'] - sl.Text:SetText(message) - sl.OnValueChanged=function(this,value) - if (not this.unrounded) then - value = math.floor(value) - end - if (this.isPercent) then - this.Text:SetFormattedText('%d%%',value) + local lastcall=math.floor(GetTime()*10) + local progressing + function over.GarrisonMissionList_Update() + local self = GarrisonMissionFrame.MissionTab.MissionList; + local missions; + if (self.showInProgress) then + -- Ten times in a second is enough... + local tick=math.floor(GetTime()*10) + if (tick == lastcall) then else - this.Text:SetText(value) + collectgarbage("step",100) + lastcall=tick + return end - return value + table.sort(self.inProgressMissions,sorters.EndTime) + missions = self.inProgressMissions; + else + progressing=false + missions = self.availableMissions; end - sl:SetScript("OnValueChanged",sl.OnValueChanged) - return sl - end - function factory:Checkbox(father,current,message) - local name=tostring(self)..GetTime()*1000 ..nonce - nonce=nonce+1 - local ck=CreateFrame("CheckButton",name,father,"ChatConfigCheckButtonTemplate") - ck.Text=_G[name..'Text'] - ck.Text:SetText(message) - ck:SetChecked(current) - return ck - end -end ---- This routine can be called both as coroutin and as a standard one --- In standard version, delay between group building and submitting is done via a self schedule ---@param #integer missionID Optional, to run a single mission ---@param #bool start Optional, tells that follower already are on mission and that we need just to start it -function addon:GMCRunMission(missionID,start) - xprint("Asked to start mission",missionID) - if (start) then - G.StartMission(missionID) - PlaySound("UI_Garrison_CommandTable_MissionStart") - return + local numMissions = #missions; + local scrollFrame = self.listScroll; + local offset = HybridScrollFrame_GetOffset(scrollFrame); + local buttons = scrollFrame.buttons; + local numButtons = #buttons; + + if (numMissions == 0) then + self.EmptyListString:Show(); + else + self.EmptyListString:Hide(); + end + for i = 1, numButtons do + dbg=i==1 + local button = buttons[i]; + local index = offset + i; -- adjust index + if ( index <= numMissions) then + local mission = missions[index]; + button.id = index; + button.info = mission; + button.party=addon:GetParty(mission.missionID) + else + button.id=0 + button.info=nil + button.party=nil + end + addon:DrawSingleButton(self,button,false,ns.bigscreen) + end + local totalHeight = numMissions * scrollFrame.buttonHeight; + local displayedHeight = numButtons * scrollFrame.buttonHeight; + HybridScrollFrame_Update(scrollFrame, totalHeight, displayedHeight); + end +end +function over.GarrisonMissionPageFollowerFrame_OnEnter(self) + if not self.info then + return; + end + GarrisonFollowerTooltip:ClearAllPoints(); + GarrisonFollowerTooltip:SetPoint("TOPLEFT", self, "BOTTOMRIGHT"); + GarrisonFollowerTooltip_Show(self.info.garrFollowerID, + self.info.isCollected, + C_Garrison.GetFollowerQuality(self.info.followerID), + C_Garrison.GetFollowerLevel(self.info.followerID), + C_Garrison.GetFollowerXP(self.info.followerID), + C_Garrison.GetFollowerLevelXP(self.info.followerID), + C_Garrison.GetFollowerItemLevelAverage(self.info.followerID), + C_Garrison.GetFollowerAbilityAtIndex(self.info.followerID, 1), + C_Garrison.GetFollowerAbilityAtIndex(self.info.followerID, 2), + C_Garrison.GetFollowerAbilityAtIndex(self.info.followerID, 3), + C_Garrison.GetFollowerAbilityAtIndex(self.info.followerID, 4), + C_Garrison.GetFollowerTraitAtIndex(self.info.followerID, 1), + C_Garrison.GetFollowerTraitAtIndex(self.info.followerID, 2), + C_Garrison.GetFollowerTraitAtIndex(self.info.followerID, 3), + C_Garrison.GetFollowerTraitAtIndex(self.info.followerID, 4), + true, + self.missionID and self.info.followerID and + C_Garrison.GetFollowerBiasForMission(self.missionID, self.info.followerID) < 0.0 + or false + ); +end +function over.GarrisonMissionButton_OnEnter(self, button) + if ns.toc < 60100 then +--[===[@non-debug@ + return orig.GarrisonMissionButton_OnEnter(self,button) +--@end-non-debug@]===] + addon:RenderTooltip(self.info.missionID) +--[===[@debug@ + orig.GarrisonMissionButton_OnEnter(self,button) + GameTooltip:AddDoubleLine("MissionID",self.info.missionID) + GameTooltip:AddDoubleLine("xp",addon:GetMissionData(self.info.missionID,'xp')) + GameTooltip:AddDoubleLine("xpBonus",addon:GetMissionData(self.info.missionID,'xpBonus')) + + GameTooltip:Show() + return +--@end-debug@]===] end - for i=1,#GMC.ml.Parties do - local party=GMC.ml.Parties[i] - xprint("Checking",party.missionID) - if (missionID and party.missionID==missionID or not missionID) then - GMC.ml.widget:RemoveChild(party.missionID) - GMC.ml.widget:DoLayout() - if (party.full) then - for j=1,#party.members do - G.AddFollowerToMission(party.missionID, party.members[j]) - end - if (not missionID) then - coroutine.yield(true) - G.StartMission(party.missionID) - PlaySound("UI_Garrison_CommandTable_MissionStart") - coroutine.yield(true) - else - self:ScheduleTimer("GMCRunMission",0.25,party.missionID,true) - end - end - end + if (self.info == nil) then + return; end -end -do - local timeElapsed=0 - local currentMission=0 - local x=0 - function addon:GMCCalculateMissions(this,elapsed) - db.news.MissionControl=true - timeElapsed = timeElapsed + elapsed - if (#aMissions == 0 ) then - if timeElapsed >= 1 then - currentMission=0 - x=0 - self:Unhook(this,"OnUpdate") - GMC.ml.widget:SetTitle(READY) - GMC.ml.widget:SetTitleColor(C.Green()) - this:Enable() - if (#GMC.ml.Parties>0) then - GMC.runButton:Enable() - end - end - return - end - if (timeElapsed >=0.) then - currentMission=currentMission+1 - if (currentMission > #aMissions) then - wipe(aMissions) - currentMission=0 - x=0 - timeElapsed=0.2 - else - GMC.ml.widget:SetFormattedTitle("Processing mission %d of %d",currentMission,#aMissions) - local missionID=aMissions[currentMission] - if (dbg) then print(C("Processing ","Red"),missionID) end - local party={members={},perc=0} - local mission=self:GetMissionData(missionID) - if (not mission ) then - if dbg then print ("NO data for",missionID) end - return - end - self:MatchMaker(missionID,mission,party) -- I need my mission data - local minimumChance=0 - if (GMC.settings.useOneChance) then - minimumChance=GMC.settings.minimumChance - end - for prio,enabled in pairs(GMC.settings.allowedRewards) do - if (dbg) then print("Chance from ",prio,"=",GMC.settings.rewardChance[prio],enabled) end - if (enabled and (tonumber(self:GetMissionData(missionID,prio)) or 0) >0) then - minimumChance=math.max(GMC.settings.rewardChance[prio],minimumChance) - end - end - if (dbg) then print ("Missionid",missionID,"Chance",minimumChance,"chance",party.perc) end - if ( party.full and party.perc >= minimumChance) then - if (dbg) then print("Preparing button for",missionID) end - local mb=AceGUI:Create("GMCMissionButton") - for i=1,#party.members do - GMCUsedFollowers[party.members[i]]=true - end - party.missionID=missionID - tinsert(GMC.ml.Parties,party) - GMC.ml.widget:PushChild(mb,missionID) - mb:SetFullWidth(true) - mb:SetMission(mission) - mb:SetCallback("OnClick",function(...) - addon:GMCRunMission(missionID) - GMC.ml.widget:RemoveChild(missionID) - end - ) - end - timeElapsed=0 - end - end + + GameTooltip:SetOwner(self, "ANCHOR_CURSOR_RIGHT"); + + if(self.info.inProgress) then + GarrisonMissionButton_SetInProgressTooltip(self.info); + else + GameTooltip:SetText(self.info.name); + GameTooltip:AddLine(string.format(GARRISON_MISSION_TOOLTIP_NUM_REQUIRED_FOLLOWERS, self.info.numFollowers), 1, 1, 1); + GarrisonMissionButton_AddThreatsToTooltip(self.info.missionID); + --if (self.info.isRare) then + if ns.toc >=60100 then + GameTooltip:AddLine(GARRISON_MISSION_AVAILABILITY); + GameTooltip:AddLine(self.info.offerTimeRemaining, 1, 1, 1); + end + if not C_Garrison.IsOnGarrisonMap() then + GameTooltip:AddLine(" "); + GameTooltip:AddLine(GARRISON_MISSION_TOOLTIP_RETURN_TO_START, nil, nil, nil, 1); + end + addon:AddFollowersToTooltip(self.info.missionID) + GameTooltip:Show() end +--@debu@ + GameTooltip:AddDoubleLine("MissionID",self.info.missionID) +--@end-debug@]===] + GameTooltip:Show(); + GarrisonMissionFrame.MissionTab.MissionList.newMissionIDs[self.info.missionID] = nil; + --GarrisonMissionList_Update(); end +---@function +-- Main mission button draw routine. +-- @param page GarrisonMissionFrameMissions or nil. +-- @param button scrolllist element +-- @param progressing true if at second iteration of progress page +-- @param bigscreen enlarge button or not -function addon:GMC_OnClick_Run(this,button) - this:Disable() - do - local elapsed=0 - local co=coroutine.wrap(self.GMCRunMission) - self:RawHookScript(GMC.runButton,'OnUpdate',function(this,ts) - elapsed=elapsed+ts - if (elapsed>0.25) then - elapsed=0 - local rc=co(self) - if (not rc) then - self:Unhook(GMC.runButton,'OnUpdate') - end - end +function addon:DrawSingleButton(page,button,progressing,bigscreen) + local mission=button.info + if mission then + local missionID=mission.missionID + if not button.party then button.party=self:GetParty(missionID) end + self:AddStandardDataToButton(page,button,mission,missionID,bigscreen) + self:AddIndicatorToButton(button,mission,missionID,bigscreen) + over.GarrisonMissionButton_SetRewards(button, mission.rewards, mission.numRewards); + self:AddFollowersToButton(button,mission,missionID,bigscreen) + if page and not self:IsRewardPage() then + addon:AddThreatsToButton(button,mission,missionID,bigscreen) + end + local a1,f,a2,h,v=button.Title:GetPoint(1) + v=v+10 + button.Title:ClearAllPoints() + button.Title:SetPoint(a1,f,a2,h,v) + button:Show(); + + else + button:Hide(); + button.info=nil end - ) +end +function addon:DrawSingleSlimButton(page,button,progressing,bigscreen) + local mission=button.info + if mission then + local missionID=mission.missionID + local frame=button + self:AddStandardDataToButton(page,button,mission,missionID,bigscreen) + over.GarrisonMissionButton_SetRewards(button, mission.rewards, mission.numRewards); + self:AddFollowersToButton(button,mission,missionID,bigscreen) + frame.Title:SetPoint("TOPLEFT",frame.Percent,"TOPLEFT",0,5) + frame.Success:SetPoint("LEFT",frame.Percent,"RIGHT",0,0) + frame.Failure:SetPoint("LEFT",frame.Percent,"RIGHT",0,0) + frame.Summary:ClearAllPoints() + frame.Summary:SetPoint("BOTTOMLEFT",frame.Title,"BOTTOMRIGHT",0,0) + button:Show(); + else + button:Hide(); + button.info=nil end end -function addon:GMC_OnClick_Start(this,button) - xprint(C("-------------------------------------------------","Yellow")) - this:Disable() - GMC.ml.widget:ClearChildren() - if (self:GetTotFollowers(AVAILABLE) == 0) then - self:Popup("All followers are busy",10) - this:Enable() - return +function addon:AddStandardDataToButton(page,button,mission,missionID,bigscreen) + button.Title:SetWidth(0); + button.Title:SetText(mission.name); + button.Level:SetText(mission.level); + if ( mission.durationSeconds >= GARRISON_LONG_MISSION_TIME ) then + local duration = format(GARRISON_LONG_MISSION_TIME_FORMAT, mission.duration); + button.Summary:SetFormattedText(PARENS_TEMPLATE, duration); + else + button.Summary:SetFormattedText(PARENS_TEMPLATE, mission.duration); end - addon:GMCCreateMissionList(aMissions) - wipe(GMCUsedFollowers) - wipe(GMC.ml.Parties) - self:RefreshFollowerStatus() - if (#aMissions>0) then - GMC.ml.widget:SetFormattedTitle(L["Processing mission %d of %d"],1,#aMissions) + if ( mission.locPrefix ) then + button.LocBG:Show(); + button.LocBG:SetAtlas(mission.locPrefix.."-List"); else - GMC.ml.widget:SetTitle("No mission matches your criteria") - GMC.ml.widget:SetTitleColor(C.Red()) + button.LocBG:Hide(); end - self:RawHookScript(GMC.startButton,'OnUpdate',"GMCCalculateMissions") - -end -local chestTexture -function addon:GMCBuildPanel() - --PanelTemplates_SetNumTabs(GarrisonMissionFrame, 4) - --PanelTemplates_UpdateTabs(GarrisonMissionFrame) - chestTexture='GarrMission-'..UnitFactionGroup('player').. 'Chest' - GMC = CreateFrame('FRAME', 'GMCOptions', GarrisonMissionFrame) - GMC.settings=dbcache.missionControl - GMC:SetPoint('CENTER') - GMC:SetSize(GarrisonMissionFrame:GetWidth(), GarrisonMissionFrame:GetHeight()) - GMC:Hide() - local chance=self:GMCBuildChance() - local duration=self:GMCBuildDuration() - local rewards=self:GMCBuildRewards() - local priorities=self:GMCBuildPriorities() - local list=self:GMCBuildMissionList() - duration:SetPoint("TOPLEFT",0,-50) - chance:SetPoint("TOPLEFT",duration,"TOPRIGHT",bigscreen and 50 or 10,0) - priorities:SetPoint("TOPLEFT",duration,"BOTTOMLEFT",25,-40) - rewards:SetPoint("TOPLEFT",priorities,"TOPRIGHT",bigscreen and 50 or 15,0) - list:SetPoint("TOPLEFT",chance,"TOPRIGHT",10,0) - list:SetPoint("BOTTOMRIGHT",GMF,"BOTTOMRIGHT",-25,25) - GMC.startButton = CreateFrame('BUTTON',nil, list.frame, 'GameMenuButtonTemplate') - GMC.startButton:SetText('Calculate') - GMC.startButton:SetWidth(148) - GMC.startButton:SetPoint('TOPLEFT',15,25) - GMC.startButton:SetScript('OnClick', function(this,button) self:GMC_OnClick_Start(this,button) end) - GMC.startButton:SetScript('OnEnter', function() GameTooltip:SetOwner(GMC.startButton, 'ANCHOR_TOPRIGHT') GameTooltip:AddLine('Assign your followers to missions.') GameTooltip:Show() end) - GMC.startButton:SetScript('OnLeave', function() GameTooltip:Hide() end) - GMC.runButton = CreateFrame('BUTTON', nil,list.frame, 'GameMenuButtonTemplate') - GMC.runButton:SetText('Send all mission at once') - GMC.runButton:SetScript('OnEnter', function() - GameTooltip:SetOwner(GMC.runButton, 'ANCHOR_TOPRIGHT') - GameTooltip:AddLine('Submit all yopur mission at once. No question asked.') - GameTooltip:AddLine('You can also send mission one by one clicking on each button.') - GameTooltip:Show() - end) - GMC.runButton:SetScript('OnLeave', function() GameTooltip:Hide() end) - GMC.runButton:SetWidth(148) - GMC.runButton:SetPoint('TOPRIGHT',-15,25) - GMC.runButton:SetScript('OnClick',function(this,button) self:GMC_OnClick_Run(this,button) end) - GMC.runButton:Disable() - GMC.skipRare=factory:Checkbox(GMC,GMC.settings.skipRare,L["Ignore rare missions"]) - GMC.skipRare:SetPoint("TOPLEFT",priorities,"BOTTOMLEFT",0,-10) - GMC.skipRare:SetScript("OnClick",function(this) - GMC.settings.skipRare=this:GetChecked() - addon:GMC_OnClick_Start(GMC.startButton,"LeftUp") - end) - GMC.Credits=GMC:CreateFontString(nil,"ARTWORK","ReputationDetailFont") - GMC.Credits:SetWidth(0) - GMC.Credits:SetFormattedText("Original concept and interface by %s",C("Motig","Red") ) - GMC.Credits:SetPoint("BOTTOMLEFT",25,25) -end -function addon:GMCRewardRefresh() - local single=GMC.settings.useOneChance - local ref - for i=1,#GMC.ignoreFrames do - local frame=GMC.ignoreFrames[i] - local allowed=GMC.settings.allowedRewards[frame.key] - frame.icon:SetDesaturated(not allowed) - local a1,o,a2,x,y=frame:GetPoint(1) - if (not single) then - frame.chest:Show() - frame.slider:Show() - frame:SetPoint(a1,o,a2,0,y) - else - frame.chest:Hide() - frame.slider:Hide() - frame:SetPoint(a1,o,a2,100,y) - end - ref=frame + if (mission.isRare) then + button.RareOverlay:Show(); + button.RareText:Show(); + button.IconBG:SetVertexColor(0, 0.012, 0.291, 0.4) + else + button.RareOverlay:Hide(); + button.RareText:Hide(); + button.IconBG:SetVertexColor(0, 0, 0, 0.4) end - if (single) then - GMC.itf2:SetPoint('TOPLEFT',ref,'BOTTOMLEFT', -110, -15) - GMC.cp:SetDesaturated(false) - GMC.ct:SetTextColor(C.Green()) + local showingItemLevel = false; + if ( mission.level == GARRISON_FOLLOWER_MAX_LEVEL and mission.iLevel > 0 ) then + button.ItemLevel:SetFormattedText(NUMBER_IN_PARENTHESES, mission.iLevel); + button.ItemLevel:Show(); + showingItemLevel = true; else - GMC.itf2:SetPoint('TOPLEFT',ref,'BOTTOMLEFT', 10, -15) - GMC.cp:SetDesaturated(true) - GMC.ct:SetTextColor(C.Silver()) + button.ItemLevel:Hide(); end -end -function addon:GMCBuildChance() - _G['GMC']=GMC - --Chance - GMC.cf = CreateFrame('FRAME', nil, GMC) - GMC.cf:SetSize(256, 150) - - GMC.cp = GMC.cf:CreateTexture(nil, 'BACKGROUND') - GMC.cp:SetTexture('Interface\\Garrison\\GarrisonMissionUI2.blp') - GMC.cp:SetAtlas(chestTexture) - GMC.cp:SetSize((209-(209*0.25))*0.60, (155-(155*0.25))*0.60) - GMC.cp:SetPoint('CENTER', 0, 20) - - GMC.cc = GMC.cf:CreateFontString() - GMC.cc:SetFontObject('GameFontNormalHuge') - GMC.cc:SetText('Success Chance') - GMC.cc:SetPoint('TOP', 0, 0) - GMC.cc:SetTextColor(1, 1, 1) - - GMC.ct = GMC.cf:CreateFontString() - GMC.ct:SetFontObject('ZoneTextFont') - GMC.ct:SetFormattedText('%d%%',GMC.settings.minimumChance) - GMC.ct:SetPoint('TOP', 0, -40) - GMC.ct:SetTextColor(0, 1, 0) - - GMC.cs = factory:Slider(GMC.cf,0,100,GMC.settings.minimumChance,'Minumum chance to start a mission') - GMC.cs:SetPoint('BOTTOM', 10, 0) - GMC.cs:SetScript('OnValueChanged', function(self, value) - local value = math.floor(value) - GMC.ct:SetText(value..'%') - GMC.settings.minimumChance = value - end) - GMC.cs:SetValue(GMC.settings.minimumChance) - GMC.ck=factory:Checkbox(GMC.cs,GMC.settings.useOneChance,"Use this percentage for all missions") - GMC.ck.tooltip="Unchecking this will allow you to set specific success chance for each reward type" - GMC.ck:SetPoint("TOPLEFT",GMC.cs,"BOTTOMLEFT",-60,-10) - GMC.ck:SetScript("OnClick",function(this) - GMC.settings.useOneChance=this:GetChecked() - addon:GMCRewardRefresh() - end) - return GMC.cf -end -local function timeslidechange(this,value) - local value = math.floor(value) - if (this.max) then - GMC.settings.maxDuration = max(value,GMC.settings.minDuration) - if (value~=GMC.settings.maxDuration) then this:SetValue(GMC.settings.maxDuration) end + if ( showingItemLevel and mission.isRare ) then + button.Level:SetPoint("CENTER", button, "TOPLEFT", 40, -22); else - GMC.settings.minDuration = min(value,GMC.settings.maxDuration) - if (value~=GMC.settings.minDuration) then this:SetValue(GMC.settings.minDuration) end - end - local c = 1-(value*(1/24)) - if c < 0.3 then c = 0.3 end - GMC.mt:SetTextColor(1, c, c) - GMC.mt:SetFormattedText("%d-%dh",GMC.settings.minDuration,GMC.settings.maxDuration) -end -function addon:GMCBuildDuration() - -- Duration - GMC.tf = CreateFrame('FRAME', nil, GMC) - GMC.tf:SetSize(256, 180) - GMC.tf:SetPoint('LEFT', 80, 120) - - GMC.bg = GMC.tf:CreateTexture(nil, 'BACKGROUND') - GMC.bg:SetTexture('Interface\\Timer\\Challenges-Logo.blp') - GMC.bg:SetSize(100, 100) - GMC.bg:SetPoint('CENTER', 0, 0) - GMC.bg:SetBlendMode('ADD') - - GMC.tcf = GMC.tf:CreateTexture(nil, 'BACKGROUND') - --bb:SetTexture('Interface\\Timer\\Challenges-Logo.blp') - --bb:SetTexture('dungeons\\textures\\devices\\mm_clockface_01.blp') - GMC.tcf:SetTexture('World\\Dungeon\\Challenge\\clockRunes.blp') - GMC.tcf:SetSize(110, 110) - GMC.tcf:SetPoint('CENTER', 0, 0) - GMC.tcf:SetBlendMode('ADD') - - GMC.mdt = GMC.tf:CreateFontString() - GMC.mdt:SetFontObject('GameFontNormalHuge') - GMC.mdt:SetText('Mission Duration') - GMC.mdt:SetPoint('TOP', 0, 0) - GMC.mdt:SetTextColor(1, 1, 1) - - GMC.mt = GMC.tf:CreateFontString() - GMC.mt:SetFontObject('ZoneTextFont') - GMC.mt:SetFormattedText('%d-%dh',GMC.settings.minDuration,GMC.settings.maxDuration) - GMC.mt:SetPoint('CENTER', 0, 0) - GMC.mt:SetTextColor(1, 1, 1) - - GMC.ms1 = factory:Slider(GMC.tf,0,24,GMC.settings.minDuration,'Minimum mission duration.') - GMC.ms2 = factory:Slider(GMC.tf,0,24,GMC.settings.maxDuration,'Maximum mission duration.') - GMC.ms1:SetPoint('BOTTOM', 0, 0) - GMC.ms2:SetPoint('TOP', GMC.ms1,"BOTTOM",0, -25) - GMC.ms2.max=true - GMC.ms1:SetScript('OnValueChanged', timeslidechange) - GMC.ms2:SetScript('OnValueChanged', timeslidechange) - timeslidechange(GMC.ms1,GMC.settings.minDuration) - timeslidechange(GMC.ms2,GMC.settings.maxDuration) - return GMC.tf -end -function addon:GMCBuildRewards() - --Allowed rewards - GMC.aif = CreateFrame('FRAME', nil, GMC) - GMC.aif:SetPoint('CENTER', 0, 120) - - GMC.itf = GMC.aif:CreateFontString() - GMC.itf:SetFontObject('GameFontNormalHuge') - GMC.itf:SetText('Allowed Rewards') - GMC.itf:SetPoint('TOP', 0, -10) - GMC.itf:SetTextColor(1, 1, 1) - - GMC.itf2 = GMC.aif:CreateFontString() - GMC.itf2:SetFontObject('GameFontHighlight') - GMC.itf2:SetText('Click to enable/disable a reward.') - GMC.itf2:SetTextColor(1, 1, 1) - - - local t = { - {t = 'Enable/Disable money rewards.', i = 'Interface\\Icons\\inv_misc_coin_01', key = 'gold'}, - {t = 'Enable/Disable other currency awards. (Resources/Seals)', i= 'Interface\\Icons\\inv_garrison_resource', key = 'resources'}, - {t = 'Enable/Disable Follower XP Bonus rewards.', i = 'Interface\\Icons\\XPBonus_Icon', key = 'xpBonus'}, - {t = 'Enable/Disable follower equip enhancement.', i = 'Interface\\ICONS\\Garrison_ArmorUpgrade', key = 'followerUpgrade'}, - {t = 'Enable/Disable item tokens.', i = "Interface\\ICONS\\INV_Bracer_Cloth_Reputation_C_01", key = 'itemLevel'} - } - local scale=1.1 - GMC.ignoreFrames = {} - local ref - local h=37 -- itemButtonTemplate standard size - local gap=5 - for i = 1, #t do - local frame = CreateFrame('BUTTON', nil, GMC.aif, 'ItemButtonTemplate') - frame:SetScale(scale) - frame:SetPoint('TOPLEFT', 0,(i) * (-h -gap) * scale) - frame.icon:SetTexture(t[i].i) - frame.key=t[i].key - frame.tooltip=t[i].t - local allowed=GMC.settings.allowedRewards[frame.key] - local chance=GMC.settings.rewardChance[frame.key] - -- Need to resave them asap in order to populate the array for future scans - GMC.settings.allowedRewards[frame.key]=allowed - GMC.settings.rewardChance[frame.key]=chance - frame.slider=factory:Slider(frame,0,100,chance or 100,chance or 100) - frame.slider:SetWidth(128) - frame.slider:SetPoint('BOTTOMLEFT',60,0) - frame.slider.Text:SetFontObject('NumberFont_Outline_Med') - frame.slider.Text:SetTextColor(C.Green()) - frame.slider.isPercent=true - frame.slider:SetScript("OnValueChanged",function(this,value) - GMC.settings.rewardChance[this:GetParent().key]=this:OnValueChanged(value) - end - ) - frame.chest = frame:CreateTexture(nil, 'BACKGROUND') - frame.chest:SetTexture('Interface\\Garrison\\GarrisonMissionUI2.blp') - frame.chest:SetAtlas(chestTexture) - frame.chest:SetSize((209-(209*0.25))*0.30, (155-(155*0.25)) * 0.30) - frame.chest:SetPoint('CENTER',frame.slider, 0, 25) - frame:SetScript('OnClick', function(this) - local allowed= this.icon:IsDesaturated() -- ID it was desaturated, I want it allowed, now - GMC.settings.allowedRewards[this.key] = allowed - addon:GMCRewardRefresh() - end) - frame:SetScript('OnEnter', function(this) - GameTooltip:SetOwner(this, 'ANCHOR_BOTTOMRIGHT') - GameTooltip:AddLine(this.tooltip); - GameTooltip:Show() - end) - - frame:SetScript('OnLeave', function() GameTooltip:Hide() end) - GMC.ignoreFrames[i] = frame - ref=frame + button.Level:SetPoint("CENTER", button, "TOPLEFT", 40, -36); end - self:GMCRewardRefresh() - GMC.aif:SetSize(256, (scale*h+gap) * #t) - GMC.itf2:SetPoint('TOPLEFT',ref,'BOTTOMLEFT', 5, -15) - return GMC.aif -end - -local addPriorityRule,prioRefresh,removePriorityRule,prioMenu,prioTitles,prioCheck,prioVoices -do --- 1 = item, 2 = folitem, 3 = exp, 4 = money, 5 = resource - prioTitles={ - itemLevel="Gear Items", - followerUpgrade="Upgrade Items", - xpBonus="Follower XP Bonus", - gold="Gold Reward", - resources="Resource Rewards" - } - prioVoices=0 - for _ in pairs(prioTitles) do prioVoices=prioVoices+1 end - prioMenu={} - ---@function [parent=#GMC] prioRefresh - function prioRefresh() - for i=1,prioVoices do - local group=GMC.prioFrames[i] - local code=GMC.settings.itemPrio[i] - if (not code) then - group.text:Hide() - group.xbutton:Hide() - group.nr:Hide() - else - group.text:Show() - group.text:SetText(prioTitles[code]) - group.xbutton:Show() - group.nr:Show() - end - end - GMC.abutton:Hide() - for i=1,prioVoices do - local group=GMC.prioFrames[i] - if (not group.text:IsShown()) then - group.nr:Show() - GMC.abutton:SetPoint("TOPLEFT",group.text) - GMC.abutton:Show() - break - end - end + button:Enable(); + if (mission.inProgress) then + button.Overlay:Show(); + button.Summary:SetText(mission.timeLeft.." "..RED_FONT_COLOR_CODE..GARRISON_MISSION_IN_PROGRESS..FONT_COLOR_CODE_CLOSE); + else + button.Overlay:Hide(); end - ---@function [parent=#GMC] addPriorityRule - function addPriorityRule(this,key) - tinsert(GMC.settings.itemPrio,key) - prioRefresh() + if (bigscreen) then + button.Rewards[1]:SetPoint("RIGHT",button,"RIGHT",-500 - (GMM and 40 or 0),0) + local width=GMF.MissionTab.MissionList.showInProgress and BIGBUTTON or SMALLBUTTON + button:SetWidth(width+600) + button.Rewards[1]:SetPoint("RIGHT",button,"RIGHT",-500 - (GMM and 40 or 0),0) end - ---@function [parent=#GMC] removePriorityRule - function removePriorityRule(index) - tremove(GMC.settings.itemPrio,index) - prioRefresh() + button.MissionType:SetPoint("TOPLEFT",5,-2) + if page and ns.toc>=60100 then + local isNewMission = page.newMissionIDs[mission.missionID]; + if (isNewMission) then + if (not button.NewHighlight) then + button.NewHighlight = CreateFrame("Frame", nil, button, "GarrisonMissionListButtonNewHighlightTemplate"); + button.NewHighlight:SetPoint("TOPLEFT", button, "TOPLEFT", 0, 0); + button.NewHighlight:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", 0, 0); + end + button.NewHighlight:Show(); + else + if (button.NewHighlight) then + button.NewHighlight:Hide(); + end + end end - -end -_G.XPRIO=prioRefresh -function addon:GMCBuildPriorities() - --Prio - GMC.pf = CreateFrame('FRAME', nil, GMC) - GMC.pf:SetSize(256, 240) - - GMC.pft = GMC.pf:CreateFontString() - GMC.pft:SetFontObject('GameFontNormalHuge') - GMC.pft:SetText('Item Priority') - GMC.pft:SetPoint('TOP', 0, -10) - GMC.pft:SetTextColor(1, 1, 1) - - GMC.pft2 = GMC.pf:CreateFontString() - GMC.pft2:SetFontObject('GameFontNormal') - GMC.pft2:SetText('Prioritize missions with certain a reward.') - GMC.pft2:SetPoint('BOTTOM', 0, 16) - GMC.pft2:SetTextColor(1, 1, 1) - GMC.pmf = CreateFrame("FRAME", "GMC_PRIO_MENU", GMC.pf, "UIDropDownMenuTemplate") - - - GMC.prioFrames = {} - GMC.prioFrames.selected = 0 - for i = 1, prioVoices do - GMC.prioFrames[i] = {} - local this = GMC.prioFrames[i] - this.f = CreateFrame('FRAME', nil, GMC.pf) - this.f:SetSize(255, 32) - this.f:SetPoint('TOP', 0, -38-((i-1)*32)) - - this.nr = this.f:CreateFontString() - this.nr:SetFontObject('GameFontNormalHuge') - this.nr:SetText(i..'.') - this.nr:SetPoint('LEFT', 8, 0) - this.nr:SetTextColor(1, 1, 1) - - this.text = this.f:CreateFontString() - this.text:SetFontObject('GameFontNormalLarge') - this.text:SetText('Def') - this.text:SetPoint('LEFT', 32, 0) - --this.text:SetTextColor(1, 1, 0) - this.text:SetJustifyH('LEFT') - this.text:Hide() - - this.xbutton = CreateFrame('BUTTON', nil, this.f, 'GameMenuButtonTemplate') - this.xbutton:SetPoint('RIGHT', 0, 0) - this.xbutton:SetText('X') - this.xbutton:SetWidth(28) - this.xbutton:SetScript('OnClick', function() removePriorityRule(i) end) - this.xbutton:Hide() + local n=mission.numRewards + local w=button:GetWidth()-175 -- 655 for standard 830 button + if button:GetWidth()<1000 then n=n+mission.numFollowers end + --print(w,button.Title:GetWidth() + button.Summary:GetWidth() + 8,n,w - n * 65) + if ( button.Title:GetWidth() + button.Summary:GetWidth() + 8 < w - n * 65 ) then + button.Title:SetPoint("LEFT", 165, 0); + button.Summary:ClearAllPoints(); + button.Summary:SetPoint("BOTTOMLEFT", button.Title, "BOTTOMRIGHT", 8, 0); + else + button.Title:SetPoint("LEFT", 165, 10); + button.Title:SetWidth(w - n * 65); + button.Summary:ClearAllPoints(); + button.Summary:SetPoint("TOPLEFT", button.Title, "BOTTOMLEFT", 0, -4); end - - GMC.abutton = CreateFrame('BUTTON', nil, GMC.pmf, 'GameMenuButtonTemplate') - GMC.abutton:SetText(L['Add priority rule']) - GMC.abutton:SetWidth(128) - GMC.abutton:Hide() - GMC.abutton:SetScript('OnClick', function() - wipe(prioMenu) - tinsert(prioMenu,{text = L["Select an item to add as priority."], isTitle = true, isNotRadio=true,disabled=true, notCheckable=true,notClickable=true}) - for k,v in pairs(prioTitles) do - tinsert(prioMenu,{text = v, func = addPriorityRule, notCheckable=true, isNotRadio=true, arg1 = k , disabled=inTable(GMC.settings.itemPrio,k)}) - end - EasyMenu(prioMenu, GMC.pmf, "cursor", 0 , 0, "MENU") - end - ) - prioRefresh() - return GMC.pf + button.MissionType:SetAtlas(mission.typeAtlas); end -function addon:GMCBuildMissionList() - -- Mission list on follower panels --- local ml=CreateFrame("Frame",nil,GMC) --- addBackdrop(ml) --- ml:Show() --- ml.Missions={} --- ml.Parties={} --- GMC.ml=ml --- local fs=ml:CreateFontString(nil, "BACKGROUND", "GameFontNormalHugeBlack") --- fs:SetPoint("TOPLEFT",0,-5) --- fs:SetPoint("TOPRIGHT",0,-5) --- fs:SetText(READY) --- fs:SetTextColor(C.Green()) --- fs:SetHeight(30) --- fs:SetJustifyV("CENTER") --- fs:Show() --- GMC.progressText=fs --- GMC.ml.Header=fs --- return GMC.ml - local ml={widget=AceGUI:Create("GMCLayer"),Parties={}} - ml.widget:SetTitle(READY) - ml.widget:SetTitleColor(C.Green()) - ml.widget:SetTitleHeight(40) - ml.widget:SetParent(GMC) - ml.widget:Show() - GMC.ml=ml - return ml.widget - +if ns.toc < 60100 then +function GarrisonMissionButton_CheckTooltipThreat() + --print("checktooltip placeholder") end ---[[ -addon.oldSetUp=addon.SetUp -function addon:ExperimentalSetUp() - end -addon.SetUp=addon.ExperimentalSetUp ---]] -do - local missions={} - local states={} - local currentMission - local scroller - local report - local timer - local function startTimer(delay) - delay=delay or 0.2 - addon:ScheduleTimer("MissionAutoComplete",delay,"LOOP") - end - local function stopTimer() - timer=nil - end - function addon:MissionsCleanup() - stopTimer() - self:MissionEvents(false) - GMF.MissionTab.MissionList.CompleteDialog:Hide() - GMF.MissionComplete:Hide() - GMF.MissionCompleteBackground:Hide() - GMF.MissionComplete.currentIndex = nil - GMF.MissionTab:Show() - GarrisonMissionList_UpdateMissions() - -- Re-enable "view" button - GMFMissions.CompleteDialog.BorderFrame.ViewButton:SetEnabled(true) - missionautocompleting=nil - GarrisonMissionFrame_SelectTab(1) - GarrisonMissionFrame_CheckCompleteMissions() - end - function addon:MissionEvents(start) - self:UnregisterEvent("GARRISON_MISSION_BONUS_ROLL_COMPLETE") - self:UnregisterEvent("GARRISON_MISSION_BONUS_ROLL_LOOT") - self:UnregisterEvent("GARRISON_MISSION_COMPLETE_RESPONSE") - self:UnregisterEvent("GARRISON_FOLLOWER_XP_CHANGED") - self:UnregisterEvent("GET_ITEM_INFO_RECEIVED") - if start then - self:RegisterEvent("GARRISON_MISSION_BONUS_ROLL_LOOT","MissionAutoComplete") - self:RegisterEvent("GARRISON_MISSION_BONUS_ROLL_COMPLETE","MissionAutoComplete") - self:RegisterEvent("GARRISON_MISSION_COMPLETE_RESPONSE","MissionAutoComplete") - self:RegisterEvent("GARRISON_FOLLOWER_XP_CHANGED","MissionAutoComplete") - self:RegisterEvent("GET_ITEM_INFO_RECEIVED","MissionAutoComplete") - else - self:SafeRegisterEvent("GARRISON_MISSION_BONUS_ROLL_LOOT") - self:SafeRegisterEvent("GARRISON_MISSION_BONUS_ROLL_COMPLETE") - self:SafeRegisterEvent("GARRISON_MISSION_COMPLETE_RESPONSE") - self:SafeRegisterEvent("GARRISON_FOLLOWER_XP_CHANGED") - end - end - function addon:MissionComplete(this,button) - GMFMissions.CompleteDialog.BorderFrame.ViewButton:SetEnabled(false) - missions=G.GetCompleteMissions() - --GMFMissions.CompleteDialog.BorderFrame.ViewButton:SetEnabled(false) -- Disabling standard Blizzard Completion - if (missions and #missions > 0) then - missionautocompleting=true - report=self:GenerateMissionCompleteList("Missions' results") - --report:SetPoint("TOPLEFT",GMFMissions.CompleteDialog.BorderFrame) - --report:SetPoint("BOTTOMRIGHT",GMFMissions.CompleteDialog.BorderFrame) - report:SetParent(GMF) - report:SetPoint("TOP",GMF) - report:SetPoint("BOTTOM",GMF) - report:SetWidth(500) - report:SetCallback("OnClose",function() return addon:MissionsCleanup() end) - for i=1,#missions do - missions[i].followerXp={} - missions[i].items={} - for k,v in pairs(missions[i].followers) do - missions[i].followerXp[v]={0,G.GetFollowerXP(v),self:GetFollowerData(v,'level'),self:GetFollowerData(v,'quality')} - end - end - currentMission=tremove(missions) - self:MissionEvents(true) - self:MissionAutoComplete("LOOP") - end - end - function addon:MissionAutoComplete(event,ID,arg1,arg2,arg3,arg4) --- C_Garrison.MarkMissionComplete Mark mission as complete and prepare it for bonus roll, da chiamare solo in caso di successo --- C_Garrison.MissionBonusRoll - --@debug@ - print("evt",event,ID,arg1,arg2,agr3) - --@end-debug@ - if self['Event'..event] then - self['Event'..event](self,event,ID,arg1,arg2,arg3,arg4) - end - if (event =="LOOP" ) then - ID=currentMission and currentMission.missionID or "none" - arg1=currentMission and currentMission.state or "none" - end - -- GARRISON_FOLLOWER_XP_CHANGED: followerID, xpGained, actualXp, newLevel, quality - if (event=="GARRISON_FOLLOWER_XP_CHANGED") then - if (arg1 > 0) then - --report:AddFollower(ID,arg1,arg2) - currentMission.followerXp[ID][1]=currentMission.followerXp[ID][1]+arg1 - end - return - -- GET_ITEM_INFO_RECEIVED: itemID - elseif (event=="GET_ITEM_INFO_RECEIVED") then - currentMission.items[ID]=1 - return - -- GET_ITEM_INFO_RECEIVED: itemID - elseif (event=="GARRISON_MISSION_BONUS_ROLL_LOOT") then - currentMission.items[ID]=1 - return - -- GARRISON_MISSION_COMPLETE_RESPONSE: missionID, requestCompleted, succeeded - elseif (event=="GARRISON_MISSION_COMPLETE_RESPONSE") then - if (not arg1) then - -- We need to call server again - currentMission.state=0 - elseif (arg2) then -- success, we need to roll - currentMission.state=1 - else -- failure, just print results - currentMission.state=2 - startTimer(0.6) - return - end - startTimer(0.1) - return - -- GARRISON_MISSION_BONUS_ROLL_COMPLETE: missionID, requestCompleted; happens after C_Garrison.MissionBonusRoll - elseif (event=="GARRISON_MISSION_BONUS_ROLL_COMPLETE") then - if (not arg1) then - -- We need to call server again - currentMission.state=1 - else - currentMission.state=3 - startTimer(0.6) - return - end - startTimer(0.1) - return - else - if (currentMission) then - local step=currentMission.state or -1 - if (step<1) then - step=0 - currentMission.state=0 - local _ - _,_,_,currentMission.successChance,_,_,currentMission.xpBonus,currentMission.multiplier=G.GetPartyMissionInfo(currentMission.missionID) - currentMission.xp=select(2,G.GetMissionInfo(currentMission.missionID)) - end - if (step==0) then - G.MarkMissionComplete(currentMission.missionID) - elseif (step==1) then - G.MissionBonusRoll(currentMission.missionID) - elseif (step>=2) then - self:MissionPrintResults(step==3) - self:RefreshFollowerStatus() - currentMission=tremove(missions) - startTimer() - return +function addon:AddThreatsToButton(button,mission,missionID,bigscreen) + local threatIndex=1 + if (not GMF.MissionTab.MissionList.showInProgress) then + if (not button.Threats) then -- I am a good guy. If MP present, I dont make my own threat indicator (Only MP <= 1.8) + if (not GMF.MissionTab.MissionList.showInProgress) then + if (not button.Env) then + button.Env=CreateFrame("Frame",nil,button,"GarrisonAbilityCounterTemplate") + button.Env:SetWidth(20) + button.Env:SetHeight(20) + button.Env:SetPoint("BOTTOMLEFT",button,165,8) + button.GcThreats={} end - currentMission.state=step - else - report:AddRow(DONE) - end - end - end - function addon:MissionPrintResults(success) - stopTimer() - - if (success) then - report:AddMissionName(currentMission.name,C(format("Succeeded. (Chance was: %s%%)", currentMission.successChance),"Green")) - PlaySound("UI_Garrison_Mission_Complete_Mission_Success") - else - PlaySound("UI_Garrison_Mission_Complete_Encounter_Fail") - report:AddMissionName(currentMission.name,C(format("Failed. (Chance was: %s%%", currentMission.successChance),"Red")) - end ---@debug@ - --report:AddRow(format("Resource multiplier: %d Xp Bonus:%d",currentMission.multiplier,currentMission.xpBonus)) - --report:AddRow(format("ID: %d",currentMission.missionID)) ---@end-debug@ - if success then - for k,v in pairs(currentMission.rewards) do - v.quantity=v.quantity or 0 - v.multiplier=v.multiplier or 1 ---@debug@ --- xprint(format("Reward type: = %s",k)) --- for field,value in pairs(v) do --- xprint(format(" %s = %s",field,value),C.Silver()) --- end ---@end-debug@ - if v.currencyID then - if v.currencyID == 0 then - -- Money reward - report:AddIconText(v.icon,GetMoneyString(v.quantity)) - elseif v.currencyID == GARRISON_CURRENCY then - -- Garrison currency reward - report:AddIconText(v.icon,GetCurrencyLink(v.currencyID),v.quantity * v.multiplier) + local party=self:GetParty(missionID) + if mission.typeIcon then + button.Env.IsEnv=true + button.Env:Show() + button.Env.Icon:SetTexture(mission.typeIcon) + if (party.isEnvMechanicCountered) then + button.Env.Border:SetVertexColor(C.Green()) else - -- Other currency reward - report:AddIconText(v.icon,GetCurrencyLink(v.currencyID),v.quantity ) + button.Env.Border:SetVertexColor(C.Red()) end - elseif v.itemID then - -- Item reward - report:AddItem(v.itemID,1) - currentMission.items[v.itemID]=nil + button.Env.Description=mission.typeDesc + button.Env.Name=mission.type + button.Env:SetScript("OnEnter",addon.ClonedGarrisonMissionMechanic_OnEnter) + button.Env:SetScript("OnLeave",function() GameTooltip:Hide() end) else - -- Follower XP reward - --report:AddIconText(v.icon,v.name) + button.Env:SetScript("OnEnter",nil) + button.Env:Hide() + end + --local counteredThreats=P:CalculateThreats(party.members,missionID) + for i=1,#mission.enemies do + local enemy=mission.enemies[i] + for mechanicID, mechanic in pairs(enemy.mechanics) do + local th=button.GcThreats[threatIndex] + if (not th) then + th=CreateFrame("Frame",nil,button,"GarrisonAbilityCounterTemplate") + th:SetWidth(20) + th:SetHeight(20) + th:SetPoint("BOTTOMLEFT",button,165 + 35 * threatIndex,8) + button.GcThreats[threatIndex]=th + end + self:SetThreatColor(th,self:GetParty(missionID,'threats')[threatIndex]) + th.Icon:SetTexture(mechanic.icon) + th.Name=mechanic.name + th.Description=mechanic.description + --GarrisonMissionButton_CheckTooltipThreat(th,missionID,mechanicID,counteredThreats) + th:Show() + th:SetScript("OnEnter",addon.ClonedGarrisonMissionMechanic_OnEnter) + th:SetScript("OnLeave",function() GameTooltip:Hide() end) + threatIndex=threatIndex+1 + end end end end - for k,v in pairs(currentMission.items) do - report:AddItem(k,v) - end - for k,v in pairs(currentMission.followers) do - report:AddFollower(v,currentMission.followerXp[v]) - end - end -end --- Need to overrid in order to stop events while cleaning missions - -function GarrisonMissionPage_Close(self) - - GarrisonMissionFrame.MissionTab.MissionPage:Hide(); - GarrisonMissionFrame.MissionTab.MissionList:Show(); - holdEvents() - GarrisonMissionPage_ClearParty(); - releaseEvents() - GarrisonMissionFrame.followerCounters = nil; - GarrisonMissionFrame.MissionTab.MissionPage.missionInfo = nil; - if (lastTab) then - GarrisonMissionFrame_SelectTab(lastTab) + else + if (button.Env) then button.Env:Hide() end end -end -GMF.MissionTab.MissionPage.CloseButton:SetScript("OnClick",GarrisonMissionPage_Close) - ---@do-not-package@ -_G.GAC=addon - ---- Enable a trace for every function call. It's a VERY heavy debug --- -if HD then -local memorysinks={} -local callstack={} -local lib=LibStub("LibInit") -for k,v in pairs(addon) do - if (type(v))=="function" and not lib[k] then - local wrapped - do - local original=addon[k] - wrapped=function(...) - pp(k) - tinsert(callstack,k) - local membefore=GetAddOnMemoryUsage("GarrisonCommander") - local a1,a2,a3,a4,a5,a6,a7,a8,a9=original(...) - local memafter=GetAddOnMemoryUsage("GarrisonCommander") - tremove(callstack) - memorysinks[k].mem=memorysinks[k].mem+memafter-membefore - memorysinks[k].calls=memorysinks[k].calls+1 - if (#callstack) then - memorysinks[k].callers=strjoin("->",unpack(callstack)) - else - memorysinks[k].callers="main" - end - if (memafter-membefore > 20) then - pp(C(k,'Red'),'used ',memafter-membefore) - end - return a1,a2,a3,a4,a5,a6,a7,a8,a9 - end + if (button.GcThreats) then + for i=threatIndex,#button.GcThreats do + button.GcThreats[i]:Hide() end - addon[k]=wrapped - memorysinks[k]={mem=0,calls=0,callers=""} end end -function addon:ResetSinks() - for k,v in pairs(memorysinks) do - memorysinks[k].mem=0 - memorysinks[k].calls=0 - end +function addon:CalculateAge(missionID) + return "Available in 6.1" end -local sorted={} -function addon:DumpSinks() - local scroll=self:GetScroller("Sinks",nil,400,1000) - wipe(sorted) - for k,v in pairs(memorysinks) do - if v.mem then - tinsert(sorted,format("Mem %06d (calls: %03d) Mem per call:%03.2f Callstack:%s(%s)",v.mem,v.calls,v.mem/v.calls,C(k,"Orange"),v.callers)) - end +function addon:AddIndicatorToButton(button,mission,missionID,bigscreen) + if not button.gcINDICATOR then + local indicators=CreateFrame("Frame",nil,button,"GarrisonCommanderIndicators") + indicators:SetPoint("LEFT",70,0) + button.gcINDICATOR=indicators end - table.sort(sorted,function(a,b) return a>b end) - self:cutePrint(scroll,sorted) -end -end -function addon:GetScroller(title,type,h,w) - h=h or 800 - w=w or 400 - type=type or "Frame" - local scrollerWindow=AceGUI:Create("Frame") - scrollerWindow:SetTitle(title) - scrollerWindow:SetLayout("Fill") - --local scrollcontainer = AceGUI:Create("SimpleGroup") -- "InlineGroup" is also good - --scrollcontainer:SetFullWidth(true) - --scrollcontainer:SetFullHeight(true) -- probably? - --scrollcontainer:SetLayout("Fill") -- important! - --scrollerWindow:AddChild(scrollcontainer) - local scroll = AceGUI:Create("ScrollFrame") - scroll:SetLayout("Flow") -- probably? - scroll:SetFullWidth(true) - scroll:SetFullHeight(true) - scrollerWindow:AddChild(scroll) - scrollerWindow:SetCallback("OnClose","Release") - scrollerWindow:SetHeight(h) - scrollerWindow:SetWidth(w) - scrollerWindow:SetPoint("CENTER") - scrollerWindow:Show() - scroll.AddRow=function (self,...) return addon:AddRow(self,...) end - return scroll -end -function addon:AddRow(obj,text,...) ---@debug@ - assert(obj) ---@end-debug@ - if (obj) then - local l=AceGUI:Create("Label") - l:SetText(text) - l:SetColor(...) - l:SetFullWidth(true) - obj:AddChild(l) - end -end -function addon:cutePrint(scroll,level,k,v) - if (type(level)=="table") then - for k,v in pairs(level) do - self:cutePrint(scroll,"",k,v) - end - return - end - if (type(v)=="table") then - self:AddRow(scroll,level..C(k,"Azure")..":" ..C("Table","Orange")) - for kk,vv in pairs(v) do - self:cutePrint(scroll,level .. " ",kk,vv) - end + local panel=button.gcINDICATOR + local perc=select(4,G.GetPartyMissionInfo(missionID)) + if button.party then perc=button.party.perc end + panel.Percent:SetFormattedText(GARRISON_MISSION_PERCENT_CHANCE,perc) + panel.Percent:SetTextColor(self:GetDifficultyColors(perc)) + panel.Percent:SetWidth(80) + panel.Percent:Show() + if (GMFMissions.showInProgress) then + panel.Percent:SetJustifyV("CENTER") + panel.Age:Hide() else - if (type(v)=="string" and v:sub(1,2)=='0x') then - v=v.. " " ..tostring(self:GetFollowerData(v,'name')) - end - self:AddRow(scroll,level..C(k,"White")..":" ..C(v,"Yellow")) + panel.Percent:SetJustifyH("RIGHT") + panel.Age:SetFormattedText("Expires in \n%s",mission.offerTimeRemaining or self:CalculateAge(missionID)) + panel.Age:SetTextColor(C.White()) + local age=(mission.offerEndTime or GetTime() + 3600*24) -GetTime() + if age < 0 then age=0 end + local hours=floor(age/3600) + local q=self:GetDifficultyColor(hours+20,true) + panel.Age:SetTextColor(q.r,q.g,q.b) + panel.Age:Show() + end +-- XP display + if (not GMFMissions.showInProgress) then + if (not button.xp) then + button.xp=button:CreateFontString(nil, "ARTWORK", "QuestMaprewardsFont") + button.xp:SetPoint("TOP",button.Rewards[1],"TOP") + button.xp:SetJustifyH("CENTER") + end + button.xp:SetWidth(0) + local xp=(self:GetMissionData(missionID,'xp')+self:GetMissionData(missionID,'xpBonus')+(self:GetParty(missionID)['xpBonus'] or 0) )*button.info.numFollowers + button.xp:SetFormattedText("Xp: %d",xp) + button.xp:SetTextColor(self:GetDifficultyColors(xp/3000*100)) + button.xp:Show() + else + button.xp:Hide() end end -function addon:DumpFollower(name) - local follower=self:GetFollowerData(name) - if (follower) then - local scroll=self:GetScroller(follower.name) - self:cutePrint(scroll,follower) +function addon:AddFollowersToButton(button,mission,missionID,bigscreen) + if (not button.gcPANEL) then + local bg=CreateFrame("Button",nil,button,"GarrisonCommanderMissionButton") + bg:SetPoint("RIGHT") + bg.button=button + bg:SetScript("OnEnter",function(this) GarrisonMissionButton_OnEnter(this.button) end) + bg:SetScript("OnLeave",function() GameTooltip:FadeOut() end) + bg:RegisterForClicks("AnyUp") + bg:SetScript("OnClick",function(...) self:OnClick_GCMissionButton(...) end) + button.gcPANEL=bg + if (not bg.Party) then self:BuildFollowersButtons(button,bg,3,bigscreen) end end - -end -function addon:DumpStatus(title) - local scroll=self:GetScroller(title) - for i=1,#followersCache do - local followerID=followersCache[i].followerID - scroll:AddRow(format("%s (%s): %d",self:GetFollowerData(followerID,'fullname'),self:GetFollowerData(followerID,'followerID'),G.GetFollowerXP(followerID))) + local missionInfo=button.info + local missionID=missionInfo.missionID + local mission=missionInfo + if not mission then ns.print("Non ho la missione") return end -- something went wrong while refreshing + if (not bigscreen) then + local index=mission.numFollowers+mission.numRewards-3 + local position=(index * -65) - 130 + button.gcPANEL.Party[1]:ClearAllPoints() + button.gcPANEL.Party[1]:SetPoint("BOTTOMLEFT",button.Rewards[1],"BOTTOMLEFT", position,0) end - scroll:AddRow("Garrison resources: " .. select(2,GetCurrencyInfo(GARRISON_CURRENCY))) - scroll:AddRow("Money: " .. GetMoneyString(GetMoney())) -end -function addon:DumpFollowers() - local scroll=self:GetScroller("Followers Cache (" .. #followersCache ..")" ) - self:cutePrint(scroll,followersCache) -end -function addon:DumpFollowerMissions(missionID) - local scroll=self:GetScroller("FollowerMissions " .. self:GetMissionData(missionID,'name')) - self:cutePrint(scroll,followerMissions.missions[missionID]) -end -function addon:DumpIgnored() - local scroll=self:GetScroller("Ignored") - self:cutePrint(scroll,self.privatedb.profile.ignored) -end -function addon:DumpMission(missionID) - local scroll=self:GetScroller("MissionCache " .. self:GetMissionData(missionID,'name')) - self:cutePrint(scroll,cache.missions[missionID]) -end -function addon:DumpMissions() - local scroll=self:GetScroller("MissionCache") - for id,data in pairs(cache.missions) do - self:cutePrint(scroll,id .. '.'..data.name) + local party=button.party + if not party then party=self:GetParty(missionID) end + local t,b + if not GMFMissions.showInProgress then + b=G.GetBuffedFollowersForMission(missionID) + t=G.GetFollowersTraitsForMission(missionID) end -end ---- --- Debug function ---@param missionID Identificativo missione -function addon:DumpCounters(missionID) - local scroll=self:GetScroller("Counters " .. self:GetMissionData(missionID,'name')) - self:cutePrint(scroll,counters[missionID]) - self:cutePrint(scroll,"Lista per follower","","") - self:cutePrint(scroll,counterFollowerIndex[missionID]) - self:cutePrint(scroll,"Lista per threat","","") - self:cutePrint(scroll,counterThreatIndex[missionID]) -end -function addon:Dump(title,data) - local scroll=self:GetScroller(title) - self:cutePrint(scroll,data) - -end -function addon:DumpCounterers(missionID) - local scroll=self:GetScroller("Counterers " .. self:GetMissionData(missionID,'name')) - self:cutePrint(scroll,cache.missions[missionID].counterers) -end -function addon:DumpParty(missionID) - local scroll=self:GetScroller("Party " .. self:GetMissionData(missionID,'name')) - self:cutePrint(scroll,parties[missionID]) -end -function addon:DumpAgeDb() - local t=new() - for i,v in pairs(dbcache.seen) do - tinsert(t,format("%80s %s %d",self:GetMissionData(i,'name'),date("%d/%m/%y %H:%M:%S",v),ns.wowhead[i])) + for i=1,3 do + local frame=button.gcPANEL.Party[i] + if (i>mission.numFollowers) then + frame:Hide() + else + if (party.members[i]) then + self:RenderFollowerButton(frame,party.members[i],missionID,b,t) + if (frame.NotFull) then frame.NotFull:Hide() end + else + self:RenderFollowerButton(frame,false) + if (frame.NotFull) then frame.NotFull:Show() end + end + frame:Show() + end end - local scroll=self:GetScroller("Expire db") - self:cutePrint(scroll,t) - del(t) end -_G.GCF=GCF -_G.MW=173 ---[[ -PlaySound("UI_Garrison_CommandTable_Open"); - PlaySound("UI_Garrison_CommandTable_Close"); - PlaySound("UI_Garrison_Nav_Tabs"); - PlaySound("UI_Garrison_Nav_Tabs"); - PlaySound("UI_Garrison_CommandTable_SelectMission"); - PlaySound("UI_Garrison_CommandTable_IncreaseSuccess"); - PlaySound("UI_Garrison_CommandTable_100Success"); - PlaySound("UI_Garrison_CommandTable_ReducedSuccessChance"); - PlaySound("UI_Garrison_Mission_Threat_Countered"); - PlaySoundKitID(43507); -- 100% chance reached - PlaySound("UI_Garrison_CommandTable_AssignFollower"); - PlaySound("UI_Garrison_CommandTable_UnassignFollower"); - PlaySound("UI_Garrison_Mission_Threat_Countered"); - PlaySound("UI_Garrison_CommandTable_MissionStart"); - PlaySound("UI_Garrison_CommandTable_ViewMissionReport"); - PlaySound("UI_Garrison_Mission_Complete_Encounter_Chance"); - PlaySound("UI_Garrison_CommandTable_Nav_Next"); - PlaySound("UI_Garrison_CommandTable_ChestUnlock_Gold_Success"); - PlaySound("UI_Garrison_Mission_Threat_Countered"); - PlaySound("UI_Garrison_MissionEncounter_Animation_Generic"); - PlaySoundKitID(currentAnim.castSoundID); - PlaySoundKitID(currentAnim.impactSoundID); - PlaySound("UI_Garrison_Mission_Complete_Encounter_Fail"); - PlaySound("UI_Garrison_Mission_Complete_Mission_Success"); - PlaySound("UI_Garrison_CommandTable_MissionSuccess_Stinger"); - PlaySound("UI_Garrison_Mission_Complete_MissionFail_Stinger"); - PlaySound("UI_Garrison_CommandTable_ChestUnlock"); - PlaySound("UI_Garrison_CommandTable_Follower_LevelUp"); ---]] ---@end-do-not-package@ +--hooksecurefunc("GarrisonMissionList_Update",function(...)print("Original GarrisonMissionList_Update",...)end) +override("GarrisonMissionPage_Close") +override("GarrisonMissionList_Update") +override("GarrisonMissionButton_SetRewards") +override("GarrisonMissionButton_OnEnter") +override("GarrisonMissionPageFollowerFrame_OnEnter") + +GMF.MissionTab.MissionPage.CloseButton:SetScript("OnClick",over.GarrisonMissionPage_Close) +for i=1,#GMFMissionListButtons do + local b=GMFMissionListButtons[i] + b:SetScript("OnEnter",over.GarrisonMissionButton_OnEnter) +end diff --git a/GarrisonCommander.toc b/GarrisonCommander.toc index 896ea08..3e2ddae 100644 --- a/GarrisonCommander.toc +++ b/GarrisonCommander.toc @@ -4,7 +4,7 @@ ## Notes-itIT: Ti aiuta a scegliere il giusto seguace per la giusta missione ## Notes-frFR: Vous aide au moment de choisir le droit utilisateur pour la bonne mission ## Author: Alar of Daggerspine -## Version: @project-version@ @project-abbreviated-hash@ +## Version: @project-version@ ## X-Version: 2.3.0-Beta4 ## X-Revision: @project-abbreviated-hash@ ## eMail: alar@aspide.it @@ -25,5 +25,18 @@ embeds.xml localization.lua wowhead.lua +Init.lua +MissionCache.lua +FollowerCache.lua +PartyCache.lua +MissionControl.lua +MissionCompletion.lua +FollowerPage.lua +MatchMaker.lua +FollowerRecruiting.lua GarrisonCommander.xml RelNotes.lua +#@do-not-package@ +Debug.lua +#@end-do-not-package@ + diff --git a/Init.lua b/Init.lua new file mode 100644 index 0000000..99cb6d9 --- /dev/null +++ b/Init.lua @@ -0,0 +1,120 @@ +local me, ns = ... +local _G=_G +local pp=print +local setmetatable=setmetatable +local next=next +local pairs=pairs +local wipe=wipe +local GetChatFrame=GetChatFrame +local format=format +local GetTime=GetTime +local strjoin=strjoin +local tostringall=tostringall +--[===[@debug@ +LoadAddOn("Blizzard_DebugTools") +--@end-debug@]===] +ns.addon=LibStub("LibInit"):NewAddon(me,'AceHook-3.0','AceTimer-3.0','AceEvent-3.0','AceBucket-3.0') +local chatframe=ns.addon:GetChatFrame("aDebug") +local function pd(...) + --if (chatframe) then chatframe:AddMessage(format("GC:%6.3f %s",GetTime(),strjoin(' ',tostringall(...)))) end + pp(format("|cff808080GC:%6.3f|r %s",GetTime(),strjoin(' ',tostringall(...)))) +end +local addon=ns.addon --#addon +ns.toc=select(4,GetBuildInfo()) +ns.AceGUI=LibStub("AceGUI-3.0") +ns.D=LibStub("LibDeformat-3.0") +ns.C=ns.addon:GetColorTable() +ns.L=ns.addon:GetLocale() +ns.print=ns.addon:Wrap("Print") +ns.dprint=ns.print +ns.trace=ns.addon:Wrap("Trace") +ns.xprint=function() end +ns.xdump=function() end +ns.xtrace=function() end +--[===[@debug@ +--ns.xprint=function(...) pd("|cffff9900DBG|r",...) end +--ns.xdump=function(d,t) pp("|cffff9900DMP|r",t) DevTools_Dump(d) end +--ns.xtrace=ns.trace +--@end-debug@]===] +do + --[===[@debug@ + local newcount, delcount,createdcount,cached = 0,0,0 + --@end-debug@]===] + local pool = setmetatable({},{__mode="k"}) + function ns.new() + --[===[@debug@ + newcount = newcount + 1 + --@end-debug@]===] + local t = next(pool) + if t then + pool[t] = nil + return t + else + --[===[@debug@ + createdcount = createdcount + 1 + --@end-debug@]===] + return {} + end + end + function ns.copy(t) + local c = ns.new() + for k, v in pairs(t) do + c[k] = v + end + return c + end + function ns.del(t) + --[===[@debug@ + delcount = delcount + 1 + --@end-debug@]===] + wipe(t) + pool[t] = true + end + --[===[@debug@ + function cached() + local n = 0 + for k in pairs(pool) do + n = n + 1 + end + return n + end + function ns.addon:CacheStats() + ns.print("Created:",createdcount) + ns.print("Aquired:",newcount) + ns.print("Released:",delcount) + ns.print("Cached:",cached()) + end + --@end-debug@]===] +end + +local stacklevel=0 +local frames +function addon:holdEvents() + if stacklevel==0 then + frames={GetFramesRegisteredForEvent('GARRISON_FOLLOWER_LIST_UPDATE')} + for i=1,#frames do + frames[i]:UnregisterEvent("GARRISON_FOLLOWER_LIST_UPDATE") + end + end + stacklevel=stacklevel+1 +end +function addon:releaseEvents() + stacklevel=stacklevel-1 + assert(stacklevel>=0) + if (stacklevel==0) then + for i=1,#frames do + frames[i]:RegisterEvent("GARRISON_FOLLOWER_LIST_UPDATE") + end + frames=nil + end +end +local holdEvents,releaseEvents=addon.holdEvents,addon.releaseEvents +ns.OnLeave=function() GameTooltip:Hide() end + +-------------------- to be estracted to CountersCache +-- +local G=C_Garrison +ns.Abilities=setmetatable({},{ + __index=function(t,k) rawset(t,k,G.GetFollowerAbilityName(k)) return rawget(t,k) end +}) + diff --git a/MatchMaker.lua b/MatchMaker.lua new file mode 100644 index 0000000..0d8f7dc --- /dev/null +++ b/MatchMaker.lua @@ -0,0 +1,352 @@ +local me,ns=... +local pp=print +local addon=ns.addon --#addon +local C=ns.C +local P=ns.party +local _G=_G +local holdEvents,releaseEvents=addon.holdEvents,addon.releaseEvents +local new, del, copy =ns.new,ns.del,ns.copy +--upvalue +local G=C_Garrison +local GMFRewardSplash=GarrisonMissionFrameMissions.CompleteDialog +local pairs=pairs +local format=format +local tonumber=tonumber +local tinsert=tinsert +local tremove=tremove +local loadstring=loadstring +local assert=assert +local rawset=rawset +local strsplit=strsplit +local epicMountTrait=221 +local extraTrainingTrait=80 --all followers +35 +local fastLearnerTrait=29 -- only this follower +50 +local hearthStoneProTrait=236 -- all followers +36 +local scavengerTrait=79 -- More resources +local dbg +local xprint=function(...) if dbg then ns.xprint(...) end end +local xdump=function(...) if dbg then ns.xdump(...) end end +function addon:MissionScore(mission) + local totalTimeString, totalTimeSeconds, isMissionTimeImproved, successChance, partyBuffs, isEnvMechanicCountered, xpBonus, materialMultiplier,goldMultiplier = G.GetPartyMissionInfo(mission.missionID) + local r=mission.class=='resource' and materialMultiplier or xpBonus/10 + local t=isMissionTimeImproved and 1 or 0 + if r > 9999 then r= 999 end + return format("%03d%03d%01d",successChance,r,t) +end +function addon:FollowerScore(mission,followerID) + local totalTimeString, totalTimeSeconds, isMissionTimeImproved, successChance, partyBuffs, isEnvMechanicCountered, xpBonus, materialMultiplier,goldMultiplier = G.GetPartyMissionInfo(mission.missionID) + local r=0 + if mission.class=='resource' then r=materialMultiplier + --elseif mission.class=='xp' then r= xpBonus -- all time bonus + elseif mission.class=='gold' then r= goldMultiplier + else r=xpBonus>0 and 1 or 0 + end + + local t=isMissionTimeImproved and 1 or 0 + local c=(isEnvMechanicCountered and 1 or 0)+#partyBuffs + return format("%03d%01d%01d%01d%04d",successChance,r,c,t,10000-self:GetFollowerData(followerID,'rank',0)) +end +local filters={skipMaxed=false,skipBusy=false} +function filters.nop(followerID) + return true +end +function filters.maxed(followerID,missionID) + return filters.skipMaxed and addon:GetFollowerData(followerID,'maxed') or false +end +function filters.busy(followerID,missionID) + return not addon:IsFollowerAvailableForMission(followerID,filters.skipBusy) +end +function filters.ignored(followerID,missionID) + return addon:IsIgnored(followerID,missionID) +end +function filters.generic(followerID,missionID) + return filters.busy(followerID,missionID) or filters.ignored(followerID,missionID) +end +function filters.xp(followerID,missionID) + return filters.maxed(followerID,missionID) or filters.generic(followerID,missionID) +end +--alias +filters.resources=filters.generic +filters.gold=filters.generic +filters.equip=filters.generic +filters.followerequip=filters.generic +filters.epic=filters.generic +local function CreateFilter(missionClass) + local code = [[ + local filters,xprint,pairs = ... + local function filterdata(followers,missionID) + for followerID,_ in pairs(followers) do + if TEST then + xprint("Removing",C_Garrison.GetFollowerName(followerID),"due to TEST", TEST) + followers[followerID] = nil + else + xprint("Keeping",C_Garrison.GetFollowerName(followerID),"due to TEST", TEST) + end + end + end + return filterdata + ]] + code = code:gsub("TEST", " filters." ..missionClass .."(followerID,missionID)") + xprint("Compiling ",missionClass,"filter") + return assert(loadstring(code, "Filter for " .. missionClass))(filters,xprint,pairs) +end + +local filterTypes = setmetatable({}, {__index=function(self, missionClass) + local filter = CreateFilter(missionClass) + rawset(self, missionClass, CreateFilter(missionClass)) + return filter +end}) +local function AddMoreFollowers(self,mission,scores,justdo) + local missionID=mission.missionID + local filter=filters[mission.class] + local missionScore=self:MissionScore(mission) + for p=1,P:FreeSlots() do + xprint("Assigning slot ",p+1, " starting with mission score ",missionScore) + local candidate=nil + local candidateScore=missionScore + for i=1,#scores do + local score,followerID=strsplit('|',scores[i]) + xprint(C(score,'yellow'),G.GetFollowerName(followerID),filter(followerID,missionID)) + if (not filter(followerID,missionID) and not P:IsIn(followerID)) then + P:AddFollower(followerID) + local newScore=self:MissionScore(mission) + xprint(C(score,'yellow'),G.GetFollowerName(followerID),"changes score from ",candidateScore,"to",newScore) + if (newScore > missionScore or justdo) then + candidate=followerID + candidateScore=newScore + end + P:RemoveFollower(followerID) + end + end + if candidate then + xprint(C(score,'yellow'),G.GetFollowerName(candidate),"assigned to slot",p+1) + P:AddFollower(candidate) + candidate=nil + end + end +end +local function MatchMaker(self,missionID,party,includeBusy,onlyBest) + local mission=self:GetMissionData(missionID) + local class=self:GetMissionData(missionID,'class') + xprint(C(format("MATCHMAKER %s (%d) class: %s",mission.name,missionID,class),'Orange'),includeBusy and "Busy" or "Ready") + local filter=filters[class] + filters.skipMaxed=self:GetBoolean("IGP") + if (includeBusy==nil) then + filters.skipBusy=self:GetBoolean("IGM") + else + filters.skipBusy=not includeBusy + end + local scores=new() + local buffed=G.GetBuffedFollowersForMission(missionID) + local traits=G.GetFollowersTraitsForMission(missionID) + local buffeds=0 + local mechanics=G.GetMissionUncounteredMechanics(missionID) + P:Open(missionID,mission.numFollowers) + --G.GetFollowerBiasForMission(missionID,followerID) + for followerID,_ in pairs(buffed) do + P:AddFollower(followerID) + tinsert(scores,format("%010d1|%s",self:FollowerScore(mission,followerID),followerID)) + P:RemoveFollower(followerID) + buffeds=buffeds+1 + end + for _,followerID in self:GetFollowerIterator() do + if (not buffed[followerID]) then + P:AddFollower(followerID) + tinsert(scores,format("%010d0|%s",self:FollowerScore(mission,followerID),followerID)) + P:RemoveFollower(followerID) + end + end + if #scores > 0 then + local firstmember + table.sort(scores) + if (dbg) then + local s=self:GetScroller("Scores") + self:cutePrint(s,scores) + end + xprint(" First member") + for i=#scores,1,-1 do + local score,followerID=strsplit('|',scores[i]) + xprint(C(score,'yellow'),G.GetFollowerName(followerID)) + if not firstmember and not filter(followerID,missionID) then + firstmember=followerID + break + end + end + if firstmember then + P:AddFollower(firstmember) + if mission.numFollowers > 1 then + xprint(" AddMore 1") + AddMoreFollowers(self,mission,scores) + end + end + end + if P:FreeSlots() > 0 then + if not onlyBest then + filters.skipMaxed=false + xprint(" AddMore 1 with skipmaxed false",filters.skipMaxed) + AddMoreFollowers(self,mission,scores) + end + end + if P:FreeSlots() > 0 then + filters.skipMaxed=false + xprint(" AddMore 1 with just do true") + AddMoreFollowers(self,mission,scores,true) + end + if dbg then P:Dump() end + xprint("Final score",self:MissionScore(mission)) + if not party.class then + party.class=class + party.itemLevel=mission.itemLevel + party.followerUpgrade=mission.followerUpgrade + party.xpBonus=mission.xpBonus + party.gold=mission.gold + party.resources=mission.resources + end + P:StoreFollowers(party.members) + P:Close(party) + del(buffed) +end +function addon:MCMatchMaker(missionID,party) + MatchMaker(self,missionID,party,false) + if (self:GetMissionData(missionID,'class')=='xp') then + for i=1,#party.members do + if not self:GetFollowerData(party.members[i],'maxed') then + return + end + end + party.full=false + wipe(party.members) + end +end +function addon:MatchMaker(missionID,party,includeBusy) + if (not party) then party=self:GetParty(missionID) end + MatchMaker(self,missionID,party,includeBusy) +end +function addon:TestMission(missionID,includeBusy) + dbg=true + self:MatchMaker(missionID,nil,includeBusy) + dbg=false +end +function addon:MatchDebug(d) + dbg=d +end + + +--@do-not-package@ +--[[ +Dump value=GetBuffedFollowersForMission(315) +{ + ["0x0000000000079D62"]={ + [1]={ + counterIcon="Interface\\ICONS\\Ability_Rogue_FanofKnives.blp", + name="Minion Swarms", + counterName="Fan of Knives", + icon="Interface\\ICONS\\Spell_DeathKnight_ArmyOfTheDead.blp", + description="An enemy with many allies. Susceptible to area-of-effect damage." + } + }, + ["0x000000000002F5E1"]={ + [1]={ + counterIcon="Interface\\ICONS\\Spell_Nature_StrangleVines.blp", + name="Deadly Minions", + counterName="Entangling Roots", + icon="Interface\\ICONS\\Achievement_Boss_TwinOrcBrutes.blp", + description="An enemy with powerful allies that should be neutralized." + } + }, + ["0x00000000000CBDF8"]={ + [1]={ + counterIcon="Interface\\ICONS\\ability_deathknight_boneshield.blp", + name="Massive Strike", + counterName="Bone Shield", + icon="Interface\\ICONS\\Ability_Warrior_SavageBlow.blp", + description="An ability that deals massive damage." + } + } +} +Dump: value=C_Garrison.GetFollowersTraitsForMission(109) +{ + ["0x00000000001BE95D"]={ + [1]={ + traitID=236, + icon="Interface\\ICONS\\Item_Hearthstone_Card.blp" + }, + [2]={ + traitID=76, + icon="Interface\\ICONS\\Spell_Holy_WordFortitude.blp" + } + } +} +Enemies +Dump: value=GAC:GetMissionData(315,"enemies") +{ + [1]={ + portraitFileDataID=1067293, + displayID=54329, + name="Imperator Mar'gok", + mechanics={ + [9]={ + description="An enemy with powerful allies that should be neutralized.", + name="Deadly Minions", + icon="Interface\\ICONS\\Achievement_Boss_TwinOrcBrutes.blp" + }, + [10]={ + description="An enemy that must be dealt with quickly.", + name="Timed Battle", + icon="Interface\\ICONS\\SPELL_HOLY_BORROWEDTIME.BLP" + } + } + }, + [2]={ + portraitFileDataID=1067315, + displayID=54825, + name="Ko'ragh", + mechanics={ + [7]={ + description="An enemy with many allies. Susceptible to area-of-effect damage.", + name="Minion Swarms", + icon="Interface\\ICONS\\Spell_DeathKnight_ArmyOfTheDead.blp" + }, + [4]={ + description="A dangerous harmful effect that should be dispelled.", + name="Magic Debuff", + icon="Interface\\ICONS\\Spell_Shadow_ShadowWordPain.blp" + } + } + }, + [3]={ + portraitFileDataID=1067275, + displayID=53855, + name="The Butcher", + mechanics={ + [10]={ + description="An enemy that must be dealt with quickly.", + name="Timed Battle", + icon="Interface\\ICONS\\SPELL_HOLY_BORROWEDTIME.BLP" + }, + [2]={ + description="An ability that deals massive damage.", + name="Massive Strike", + icon="Interface\\ICONS\\Ability_Warrior_SavageBlow.blp" + } + } + } +} +Dump: value=C_Garrison.GetMissionUncounteredMechanics(315) +{ + [1]={ + [1]=9, + [2]=10 + }, + [2]={ + [1]=7, + [2]=4 + }, + [3]={ + [1]=10, + [2]=2 + } +} + +--]] +--@end-do-not-package@ \ No newline at end of file diff --git a/MissionCache.lua b/MissionCache.lua new file mode 100644 index 0000000..e642d4f --- /dev/null +++ b/MissionCache.lua @@ -0,0 +1,147 @@ +local me,ns=... +local addon=ns.addon --#addon +local holdEvents,releaseEvents=addon.holdEvents,addon.releaseEvents +local xdump=ns.xdump +--upvalue +local G=C_Garrison +local GMF=GarrisonMissionFrame +local GMFMissions=GarrisonMissionFrameMissions +local type=type +local select=select +local pairs=pairs +local tonumber=tonumber +local tinsert=tinsert +local wipe=wipe +local GARRISON_CURRENCY=GARRISON_CURRENCY +local GARRISON_FOLLOWER_MAX_LEVEL=GARRISON_FOLLOWER_MAX_LEVEL +local Mbase = GMFMissions +-- self=Mbase +-- C_Garrison.GetInProgressMissions(self.inProgressMissions); +-- C_Garrison.GetAvailableMissions(self.availableMissions); +local Index={} +local sorted={} +local AddExtraData +local function keyToIndex(key) + local idx=Index[key] + if (idx and idx <= #Mbase.availableMissions) then + if Mbase.availableMissions[idx].missionID==key then + return idx + else + idx=nil + end + end + wipe(Index) + wipe(sorted) + for i=1,#Mbase.availableMissions do + Index[Mbase.availableMissions[i].missionID]=i + tinsert(sorted,i) + if Mbase.availableMissions[i].missionID==key then + idx=i + end + end + return idx +end +function addon:GetMissionData(missionID,key,default) + local idx=keyToIndex(missionID) + local mission=Mbase.availableMissions[idx] + if not mission then + for i=1,#Mbase.inProgressMissions do + if missionID==Mbase.inProgressMissions[i].missionID then + mission=Mbase.inProgressMissions[i] + break + end + end + end + if (key==nil) then + return mission + end + if (type(mission[key])~='nil') then + return mission[key] + end + if (key=='rank') then + mission.rank=mission.level < GARRISON_FOLLOWER_MAX_LEVEL and mission.level or mission.iLevel + return mission.rank + elseif(key=='basePerc') then + mission.basePerc=select(4,G.GetPartyMissionInfo(missionID)) + return mission.basePerc + else + AddExtraData(mission) + return mission[key] or default + end +end +function AddExtraData(mission) + local _ + _,mission.xp,mission.type,mission.typeDesc,mission.typeIcon,mission.locPrefix,_,mission.enemies=G.GetMissionInfo(mission.missionID) + mission.rank=mission.level < 100 and mission.level or mission.iLevel + mission.resources=0 + mission.gold=0 + mission.followerUpgrade=0 + mission.itemLevel=0 + mission.xpBonus=0 + local numrewards=0 + for k,v in pairs(mission.rewards) do + numrewards=numrewards+1 + if (k==615 and v.followerXP) then mission.xpBonus=mission.xpBonus+v.followerXP end + if (v.currencyID and v.currencyID==GARRISON_CURRENCY) then mission.resources=v.quantity end + if (v.currencyID and v.currencyID==0) then mission.gold =mission.gold+v.quantity/10000 end + if (v.icon=="Interface\\Icons\\XPBonus_Icon" and v.followerXP) then + mission.xpBonus=mission.xpBonus+v.followerXP + elseif (v.itemID) then + if (v.itemID~=120205) then + local itemName, itemLink, itemRarity, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount,itemEquipLoc, itemTexture, itemSellPrice = GetItemInfo(v.itemID) + if (itemName and (not v.quantity or v.quantity==1) and not v.followerXP ) then + if (itemLevel > 1 and itemMinLevel >=90 ) then + mission.itemLevel=itemLevel + else + mission.followerUpgrade=itemRarity + end + end + end + end + end + if (mission.resources==0 and mission.gold==0 and mission.itemLevel==0 and mission.followerUpgrade==0 and numrewards <2) then + mission.xpOnly=true + mission.class="xp" + else + mission.xpOnly=false + if mission.resources > 0 then + mission.class='resources' + elseif mission.gold >0 then + mission.class='gold' + elseif mission.itemLevel >0 then + mission.class='equip' + elseif mission.followerUpgrade>0 then + mission.class='followerequip' + elseif mission.itemLevel>=645 then + mission.class='epic' + else + mission.class='generic' + end + end +end +function addon:OnAllMissions(func,inProgress) + local list=inProgress and Mbase.inProgressMissions or Mbase.availableMissions + if type(list)=='table' then + for i=1,#list do + func(list[i].missionID) + end + end +end +local sorters={} + +function addon:GetMissionIterator(func) + if (func) then + table.sort(sorted,sorters[func]) + end + local f=Mbase.availableMissions + return function(sorted,i) + i=i+1 + local x = sorted[i] + if x then + local v=f[x] and f[x].missionID or nil + if v then + return i,v + end + end + end,sorted,0 +end diff --git a/MissionCompletion.lua b/MissionCompletion.lua new file mode 100644 index 0000000..5cb7821 --- /dev/null +++ b/MissionCompletion.lua @@ -0,0 +1,363 @@ +local me, ns = ... +local addon=ns.addon --#addon +local L=ns.L +local D=ns.D +local C=ns.C +local AceGUI=ns.AceGUI +local _G=_G +local new, del, copy =ns.new,ns.del,ns.copy +local GMF=GarrisonMissionFrame +local GMFMissions=GarrisonMissionFrameMissions +local G=C_Garrison +local GARRISON_CURRENCY=GARRISON_CURRENCY +ns.missionautocompleting=false +local generated +function addon:GenerateMissionCompleteList(title) + if not generated then + generated=true + self:GenerateContainer() + do + local Type="GCMCList" + local Version=1 + local m={} --#Widget + local function onEnter(self) + if (self.itemlink) then + GameTooltip:SetHyperlink(self.itemlink) + GameTooltip:Show() + end + end + function m:OnAcquire() + wipe(self.missions) + end + function m:Show() + self.frame:Show() + end + function m:Hide() + self.frame:Hide() + self:Release() + end + function m:AddMissionButton(mission) + local obj=self.scroll + local b=AceGUI:Create("GMCSlimMissionButton") + b:SetMission(mission,addon:GetParty(mission.missionID)) + b:SetScale(0.7) + b:SetFullWidth(true) + self.missions[mission.missionID]=b + obj:AddChild(b) + end + function m:AddMissionName(missionID,success) + print("Addmissioname",missionID,success) + local mission=self.missions[missionID] + if mission then + if success then + mission.frame.Success:Show() + mission.frame.Failure:Hide() + else + mission.frame.Success:Hide() + mission.frame.Failure:Show() + end + end + end + function m:AddRow(data,...) + local obj=self.scroll + local l=AceGUI:Create("InteractiveLabel") + l:SetFontObject(GameFontNormalSmall) + l:SetText(data) + l:SetColor(...) + l:SetFullWidth(true) + obj:AddChild(l) + if (obj.scrollbar and obj.scrollbar:IsShown()) then + obj.scrollbar.ScrollDownButton:Click() + end + + end + function m:AddFollower(followerID,xp,levelup) + local follower=addon:GetFollowerData(followerID) + if follower.maxed then + return self:AddRow(format("%s is already at maximum xp",addon:GetFollowerData(followerID,'fullname'))) + end + local quality=G.GetFollowerQuality(followerID) or follower.quality + local level=G.GetFollowerLevel(followerID) or follower.level + if levelup then + PlaySound("UI_Garrison_CommandTable_Follower_LevelUp"); + end + return self:AddRow(format("%s gained %d xp%s%s",addon:GetFollowerData(followerID,'fullname',true),xp, + levelup and " *** Level Up ***." or ".", + format(" %d to go.",addon:GetFollowerData(followerID,'levelXP')-addon:GetFollowerData(followerID,'xp')))) + end + function m:AddIconText(icon,text,qt) + local obj=self.scroll + local l=AceGUI:Create("Label") + l:SetFontObject(GameFontNormalSmall) + if (qt) then + l:SetText(format("%s x %s",text,qt)) + else + l:SetText(text) + end + l:SetImage(icon) + l:SetImageSize(24,24) + l:SetFullWidth(true) + obj:AddChild(l) + if (obj.scrollbar and obj.scrollbar:IsShown()) then + obj.scrollbar.ScrollDownButton:Click() + end + return l + end + function m:AddItem(itemID,qt) + local obj=self.scroll + local _,itemlink,itemquality,_,_,_,_,_,_,itemtexture=GetItemInfo(itemID) + if not itemlink then + self:AddIconText(itemtexture,itemID) + else + self:AddIconText(itemtexture,itemlink) + end + end + local function Constructor() + local widget=AceGUI:Create("GCGUIContainer") + widget:SetLayout("Fill") + widget.missions={} + local scroll = AceGUI:Create("ScrollFrame") + scroll:SetLayout("List") -- probably? + scroll:SetFullWidth(true) + scroll:SetFullHeight(true) + widget:AddChild(scroll) + for k,v in pairs(m) do widget[k]=v end + widget:Show() + widget.scroll=scroll + return widget + end + AceGUI:RegisterWidgetType(Type,Constructor,Version) + end + end + local w=AceGUI:Create("GCMCList") + w:SetTitle(title) + return w +end + +--TODO: Portare la stampa dei risultati in fondo, e togliere il delay fra le missioni +do + local missions={} + local states={} + local currentMission + local rewards={ + items=setmetatable({},{__index=function() return 0 end}), + followerBase={}, + followerXP=setmetatable({},{__index=function() return 0 end}), + currencies=setmetatable({},{__index=function(t,k) rawset(t,k,{icon="",qt=0}) return t[k] end}), + } + local scroller + local report + local timer + local function startTimer(delay,event) + delay=delay or 0.2 + event=event or "LOOP" + addon:ScheduleTimer("MissionAutoComplete",delay,event) + end + local function stopTimer() + timer=nil + end + function addon:MissionsCleanup() + stopTimer() + self:MissionEvents(false) + GMF.MissionTab.MissionList.CompleteDialog:Hide() + GMF.MissionComplete:Hide() + GMF.MissionCompleteBackground:Hide() + GMF.MissionComplete.currentIndex = nil + GMF.MissionTab:Show() + GarrisonMissionList_UpdateMissions() + -- Re-enable "view" button + GMFMissions.CompleteDialog.BorderFrame.ViewButton:SetEnabled(true) + missionautocompleting=nil + GarrisonMissionFrame_SelectTab(1) + GarrisonMissionFrame_CheckCompleteMissions() + end + function addon:MissionEvents(start) + self:UnregisterEvent("GARRISON_MISSION_BONUS_ROLL_COMPLETE") + self:UnregisterEvent("GARRISON_MISSION_BONUS_ROLL_LOOT") + self:UnregisterEvent("GARRISON_MISSION_COMPLETE_RESPONSE") + self:UnregisterEvent("GARRISON_FOLLOWER_XP_CHANGED") + self:UnregisterEvent("GET_ITEM_INFO_RECEIVED") + if start then + self:RegisterEvent("GARRISON_MISSION_BONUS_ROLL_LOOT","MissionAutoComplete") + self:RegisterEvent("GARRISON_MISSION_BONUS_ROLL_COMPLETE","MissionAutoComplete") + self:RegisterEvent("GARRISON_MISSION_COMPLETE_RESPONSE","MissionAutoComplete") + self:RegisterEvent("GARRISON_FOLLOWER_XP_CHANGED","MissionAutoComplete") + self:RegisterEvent("GET_ITEM_INFO_RECEIVED","MissionAutoComplete") + else + self:SafeRegisterEvent("GARRISON_MISSION_BONUS_ROLL_LOOT") + self:SafeRegisterEvent("GARRISON_MISSION_BONUS_ROLL_COMPLETE") + self:SafeRegisterEvent("GARRISON_MISSION_COMPLETE_RESPONSE") + self:SafeRegisterEvent("GARRISON_FOLLOWER_XP_CHANGED") + end + end + function addon:MissionComplete(this,button) + GMFMissions.CompleteDialog.BorderFrame.ViewButton:SetEnabled(false) + missions=G.GetCompleteMissions() + --GMFMissions.CompleteDialog.BorderFrame.ViewButton:SetEnabled(false) -- Disabling standard Blizzard Completion + if (missions and #missions > 0) then + ns.missionautocompleting=true + report=self:GenerateMissionCompleteList("Missions' results") + --report:SetPoint("TOPLEFT",GMFMissions.CompleteDialog.BorderFrame) + --report:SetPoint("BOTTOMRIGHT",GMFMissions.CompleteDialog.BorderFrame) + report:SetParent(GMF) + report:SetPoint("TOP",GMF) + report:SetPoint("BOTTOM",GMF) + report:SetWidth(500) + report:SetCallback("OnClose",function() return addon:MissionsCleanup() end) + wipe(rewards.followerBase) + wipe(rewards.followerXP) + wipe(rewards.currencies) + wipe(rewards.items) + for i=1,#missions do + for k,v in pairs(missions[i].followers) do + rewards.followerBase[v]=self:GetFollowerData(v,'qLevel') + end + end + currentMission=tremove(missions) + self:MissionEvents(true) + self:MissionAutoComplete("LOOP") + end + end + function addon:MissionAutoComplete(event,ID,arg1,arg2,arg3,arg4) +-- C_Garrison.MarkMissionComplete Mark mission as complete and prepare it for bonus roll, da chiamare solo in caso di successo +-- C_Garrison.MissionBonusRoll + --[===[@debug@ + print("evt",event,ID,arg1,arg2,agr3) + --@end-debug@]===] + if self['Event'..event] then + self['Event'..event](self,event,ID,arg1,arg2,arg3,arg4) + end + if event=="LOOT" then + return addon:MissionsPrintResults() + end + + if (event =="LOOP" ) then + ID=currentMission and currentMission.missionID or "none" + arg1=currentMission and currentMission.state or "none" + end + -- GARRISON_FOLLOWER_XP_CHANGED: followerID, xpGained, actualXp, newLevel, quality + if (event=="GARRISON_FOLLOWER_XP_CHANGED") then + if (arg1 > 0) then + --report:AddFollower(ID,arg1,arg2) + rewards.followerXP[ID]=rewards.followerXP[ID]+tonumber(arg1) or 0 + end + return + -- GET_ITEM_INFO_RECEIVED: itemID + elseif (event=="GET_ITEM_INFO_RECEIVED") then + rewards.items[format("%d:%s",currentMission.missionID,ID)]=1 + return + -- GET_ITEM_INFO_RECEIVED: itemID + elseif (event=="GARRISON_MISSION_BONUS_ROLL_LOOT") then + rewards.items[format("%d:%s",currentMission.missionID,ID)]=1 + return + -- GARRISON_MISSION_COMPLETE_RESPONSE: missionID, requestCompleted, succeeded + elseif (event=="GARRISON_MISSION_COMPLETE_RESPONSE") then + if (not arg1) then + -- We need to call server again + currentMission.state=0 + elseif (arg2) then -- success, we need to roll + currentMission.state=1 + else -- failure, just print results + currentMission.state=2 + startTimer(0.1) + return + end + startTimer(0.1) + return + -- GARRISON_MISSION_BONUS_ROLL_COMPLETE: missionID, requestCompleted; happens after C_Garrison.MissionBonusRoll + elseif (event=="GARRISON_MISSION_BONUS_ROLL_COMPLETE") then + if (not arg1) then + -- We need to call server again + currentMission.state=1 + else + currentMission.state=3 + startTimer(0.1) + return + end + startTimer(0.1) + return + else + if (currentMission) then + local step=currentMission.state or -1 + if (step<1) then + step=0 + currentMission.state=0 + local _ + _,_,_,currentMission.successChance,_,_,currentMission.xpBonus,currentMission.multiplier,currentMission.golds=G.GetPartyMissionInfo(currentMission.missionID) + currentMission.golds=currentMission.golds or 1 + currentMission.xp=select(2,G.GetMissionInfo(currentMission.missionID)) + report:AddMissionButton(currentMission) + end + if (step==0) then + G.MarkMissionComplete(currentMission.missionID) + elseif (step==1) then + G.MissionBonusRoll(currentMission.missionID) + elseif (step>=2) then + self:GetMissionResults(step==3) + self:RefreshFollowerStatus() + currentMission=tremove(missions) + startTimer() + return + end + currentMission.state=step + else + report:AddRow(DONE) + startTimer(0.3,"LOOT") + end + end + end + function addon:GetMissionResults(success) + stopTimer() + if (success) then + report:AddMissionName(currentMission.missionID,true) + PlaySound("UI_Garrison_Mission_Complete_Mission_Success") + else + report:AddMissionName(currentMission.missionID,false) + PlaySound("UI_Garrison_Mission_Complete_Encounter_Fail") + end + if success then + for k,v in pairs(currentMission.rewards) do + print("Reward",k,v) + v.quantity=v.quantity or 0 + v.multiplier=v.multiplier or 1 + v.golds=v.golds or 1 + if v.currencyID then + rewards.currencies[v.currencyID].icon=v.icon + if v.currencyID == 0 then + rewards.currencies[v.currencyID].qt=rewards.currencies[v.currencyID].qt+v.quantity * v.golds + elseif v.currencyID == GARRISON_CURRENCY then + rewards.currencies[v.currencyID].qt=rewards.currencies[v.currencyID].qt+v.quantity * v.multiplier + else + rewards.currencies[v.currencyID].qt=rewards.currencies[v.currencyID].qt+v.quantity + end + elseif v.itemID then + rewards.items[format("%d:%s",currentMission.missionID,v.itemID)]=1 + end + end + end + end + function addon:MissionsPrintResults(success) + stopTimer() + self:FollowerCacheInit() + self:Dump("Ended Mission",rewards) + for k,v in pairs(rewards.currencies) do + if k == 0 then + -- Money reward + report:AddIconText(v.icon,GetMoneyString(v.qt)) + elseif k == GARRISON_CURRENCY then + -- Garrison currency reward + report:AddIconText(v.icon,GetCurrencyLink(k),v.qt) + else + -- Other currency reward + report:AddIconText(v.icon,GetCurrencyLink(k),v.qt) + end + end + for k,v in pairs(rewards.items) do + local missionid,itemid=strsplit(":",k) + report:AddItem(itemid,v) + end + for k,v in pairs(rewards.followerXP) do + report:AddFollower(k,v,self:GetFollowerData(k,'qLevel') > rewards.followerBase[k]) + end + end +end diff --git a/MissionControl.lua b/MissionControl.lua new file mode 100644 index 0000000..804a92d --- /dev/null +++ b/MissionControl.lua @@ -0,0 +1,662 @@ +local me, ns = ... +local addon=ns.addon --#addon +local L=ns.L +local D=ns.D +local C=ns.C +local AceGUI=ns.AceGUI +local _G=_G +local new, del, copy =ns.new,ns.del,ns.copy +-- Courtesy of Motig +-- Concept and interface reused with permission +-- Mission building rewritten from scratch +--local GMC_G = {} +local factory=addon:GetFactory() +--GMC_G.frame = CreateFrame('FRAME') +local aMissions={} +local dbcache +local cache +local db +local GMC +local GMF=GarrisonMissionFrame +local G=C_Garrison +local GMCUsedFollowers={} +local wipe=wipe +local pairs=pairs +local tinsert=tinsert +--[===[@debug@ +if LibDebug then LibDebug() end +--@end-debug@]===] +local dbg +function addon:GMCBusy(followerID) + return GMCUsedFollowers[followerID] +end +function addon:GMCCreateMissionList(workList) + --First get rid of unwanted rewards and missions that are too long + local settings=self.privatedb.profile.missionControl + local ar=settings.allowedRewards + wipe(workList) + for _,missionID in self:GetMissionIterator() do + local discarded=false + repeat + ns.xprint("|cffff0000",'Examing',self:GetMissionData(missionID,"name"),self:GetMissionData(missionID,"class"),"|r") + local durationSeconds=self:GetMissionData(missionID,'durationSeconds') + if (durationSeconds > settings.maxDuration * 3600 or durationSeconds < settings.minDuration * 3600) then + ns.xprint(missionID,"discarded due to len",durationSeconds /3600) + break + end -- Mission too long, out of here + if (self:GetMissionData(missionID,'isRare') and settings.skipRare) then + ns.xprint(missionID,"discarded due to rarity") + break + end + for k,v in pairs(ar) do + if (not v) then + if (self:GetMissionData(missionID,"class")==k) then -- we have a forbidden reward + ns.xprint(missionID,"discarded due to class == ", k) + discarded=true + break + end + end + end + if (not discarded) then + tinsert(workList,missionID) + end + until true + end + local parties=self:GetParty() + local function msort(i1,i2) + for i=1,#GMC.settings.itemPrio do + local criterium=GMC.settings.itemPrio[i] + if (criterium) then + if addon:GetMissionData(i1,criterium) ~= addon:GetMissionData(i2,criterium) then + return addon:GetMissionData(i1,criterium) > addon:GetMissionData(i2,criterium) + end + end + end + if (parties[i1].perc and parties[i2].perc) then + return parties[i1].perc > parties[i2].perc + end + return addon:GetMissionData(i1,'level') > addon:GetMissionData(i2,'level') + end + table.sort(workList,msort) + --[===[@debug@ + ns.xprint("Sorted list") + local x=new() + for i=1,#workList do + local mission=self:GetMissionData(workList[i]) + local t=mission.name + for i=1,#GMC.settings.itemPrio do + local criterium=GMC.settings.itemPrio[i] + t=t..format(" %s: %d",criterium,mission[criterium]) + end + tinsert(x,t .. " Success" .. tostring(parties[mission.missionID].perc)) + end + local scroll=self:GetScroller("Sorted missions",nil,600,600) + self:cutePrint(scroll,x) + del(x) + --@end-debug@]===] + +end +--- This routine can be called both as coroutin and as a standard one +-- In standard version, delay between group building and submitting is done via a self schedule +--@param #integer missionID Optional, to run a single mission +--@param #bool start Optional, tells that follower already are on mission and that we need just to start it +function addon:GMCRunMission(missionID,start) + ns.xprint("Asked to start mission",missionID) + if (start) then + G.StartMission(missionID) + PlaySound("UI_Garrison_CommandTable_MissionStart") + return + end + for i=1,#GMC.ml.Parties do + local party=GMC.ml.Parties[i] + ns.xprint("Checking",party.missionID) + if (missionID and party.missionID==missionID or not missionID) then + GMC.ml.widget:RemoveChild(party.missionID) + GMC.ml.widget:DoLayout() + if (party.full) then + for j=1,#party.members do + G.AddFollowerToMission(party.missionID, party.members[j]) + end + if (not missionID) then + coroutine.yield(true) + G.StartMission(party.missionID) + PlaySound("UI_Garrison_CommandTable_MissionStart") + coroutine.yield(true) + else + self:ScheduleTimer("GMCRunMission",0.25,party.missionID,true) + end + end + end + end +end +do + local timeElapsed=0 + local currentMission=0 + local x=0 + function addon:GMCCalculateMissions(this,elapsed) + db.news.MissionControl=true + timeElapsed = timeElapsed + elapsed + if (#aMissions == 0 ) then + if timeElapsed >= 1 then + currentMission=0 + x=0 + self:Unhook(this,"OnUpdate") + GMC.ml.widget:SetTitle(READY) + GMC.ml.widget:SetTitleColor(C.Green()) + wipe(GMCUsedFollowers) + this:Enable() + if (#GMC.ml.Parties>0) then + GMC.runButton:Enable() + end + end + return + end + if (timeElapsed >=0.) then + currentMission=currentMission+1 + if (currentMission > #aMissions) then + wipe(aMissions) + currentMission=0 + x=0 + timeElapsed=0.2 + else + GMC.ml.widget:SetFormattedTitle("Processing mission %d of %d",currentMission,#aMissions) + local missionID=aMissions[currentMission] + local class=self:GetMissionData(missionID,"class") + local checkprio=class + if checkprio=="itemLevel" then class="equip" end + if checkprio=="followerUpgrade" then class= "followerEquip" end + ns.xprint(C("Processing ","Red"),missionID,addon:GetMissionData(missionID,"name")) + local minimumChance=0 + if (GMC.settings.useOneChance) then + minimumChance=tonumber(GMC.settings.minimumChance) or 100 + else + minimumChance=tonumber(GMC.settings.rewardChance[checkprio]) or 100 + end + local party={members={},perc=0} + self:MCMatchMaker(missionID,party,false,false) + ns.xprint (" Requested",minimumChance,"Mission",party.perc,party.full) + if ( party.full and party.perc >= minimumChance) then + ns.xprint(" Mission accepted") + local mb=AceGUI:Create("GMCMissionButton") + for i=1,#party.members do + GMCUsedFollowers[party.members[i]]=true + end + party.missionID=missionID + tinsert(GMC.ml.Parties,party) + GMC.ml.widget:PushChild(mb,missionID) + mb:SetFullWidth(true) + mb:SetMission(self:GetMissionData(missionID),party) + mb:SetCallback("OnClick",function(...) + addon:GMCRunMission(missionID) + GMC.ml.widget:RemoveChild(missionID) + end + ) + end + timeElapsed=0 + end + end + end +end + +function addon:GMC_OnClick_Run(this,button) + this:Disable() + do + local elapsed=0 + local co=coroutine.wrap(self.GMCRunMission) + self:RawHookScript(GMC.runButton,'OnUpdate',function(this,ts) + elapsed=elapsed+ts + if (elapsed>0.25) then + elapsed=0 + local rc=co(self) + if (not rc) then + self:Unhook(GMC.runButton,'OnUpdate') + end + end + end + ) + end +end +function addon:GMC_OnClick_Start(this,button) + ns.xprint(C("-------------------------------------------------","Yellow")) + GMC.ml.widget:ClearChildren() + if (self:GetTotFollowers(AVAILABLE) == 0) then + GMC.ml.widget:SetTitle("All followers are busy") + return + end + this:Disable() + addon:GMCCreateMissionList(aMissions) + wipe(GMCUsedFollowers) + wipe(GMC.ml.Parties) + self:RefreshFollowerStatus() + if (#aMissions>0) then + GMC.ml.widget:SetFormattedTitle(L["Processing mission %d of %d"],1,#aMissions) + else + GMC.ml.widget:SetTitle("No mission matches your criteria") + GMC.ml.widget:SetTitleColor(C.Red()) + end + self:RawHookScript(GMC.startButton,'OnUpdate',"GMCCalculateMissions") + +end +local chestTexture +function addon:GMCBuildPanel(bigscreen) + db=self.db.global + dbcache=self.privatedb.profile + cache=self.private.profile + chestTexture='GarrMission-'..UnitFactionGroup('player').. 'Chest' + GMC = CreateFrame('FRAME', 'GMCOptions', GMF) + GMC.settings=dbcache.missionControl + GMC:SetPoint('CENTER') + GMC:SetSize(GMF:GetWidth(), GMF:GetHeight()) + GMC:Hide() + local chance=self:GMCBuildChance() + local duration=self:GMCBuildDuration() + local rewards=self:GMCBuildRewards() + local priorities=self:GMCBuildPriorities() + local list=self:GMCBuildMissionList() + duration:SetPoint("TOPLEFT",0,-50) + chance:SetPoint("TOPLEFT",duration,"TOPRIGHT",bigscreen and 50 or 10,0) + priorities:SetPoint("TOPLEFT",duration,"BOTTOMLEFT",25,-40) + rewards:SetPoint("TOPLEFT",priorities,"TOPRIGHT",bigscreen and 50 or 15,0) + list:SetPoint("TOPLEFT",chance,"TOPRIGHT",10,0) + list:SetPoint("BOTTOMRIGHT",GMF,"BOTTOMRIGHT",-25,25) + GMC.startButton = CreateFrame('BUTTON',nil, list.frame, 'GameMenuButtonTemplate') + GMC.startButton:SetText('Calculate') + GMC.startButton:SetWidth(148) + GMC.startButton:SetPoint('TOPLEFT',15,25) + GMC.startButton:SetScript('OnClick', function(this,button) self:GMC_OnClick_Start(this,button) end) + GMC.startButton:SetScript('OnEnter', function() GameTooltip:SetOwner(GMC.startButton, 'ANCHOR_TOPRIGHT') GameTooltip:AddLine('Assign your followers to missions.') GameTooltip:Show() end) + GMC.startButton:SetScript('OnLeave', function() GameTooltip:Hide() end) + GMC.runButton = CreateFrame('BUTTON', nil,list.frame, 'GameMenuButtonTemplate') + GMC.runButton:SetText('Send all mission at once') + GMC.runButton:SetScript('OnEnter', function() + GameTooltip:SetOwner(GMC.runButton, 'ANCHOR_TOPRIGHT') + GameTooltip:AddLine('Submit all yopur mission at once. No question asked.') + GameTooltip:AddLine('You can also send mission one by one clicking on each button.') + GameTooltip:Show() + end) + GMC.runButton:SetScript('OnLeave', function() GameTooltip:Hide() end) + GMC.runButton:SetWidth(148) + GMC.runButton:SetPoint('TOPRIGHT',-15,25) + GMC.runButton:SetScript('OnClick',function(this,button) self:GMC_OnClick_Run(this,button) end) + GMC.runButton:Disable() + GMC.skipRare=factory:Checkbox(GMC,GMC.settings.skipRare,L["Ignore rare missions"]) + GMC.skipRare:SetPoint("TOPLEFT",priorities,"BOTTOMLEFT",0,-10) + GMC.skipRare:SetScript("OnClick",function(this) + GMC.settings.skipRare=this:GetChecked() + addon:GMC_OnClick_Start(GMC.startButton,"LeftUp") + end) + GMC.Credits=GMC:CreateFontString(nil,"ARTWORK","ReputationDetailFont") + GMC.Credits:SetWidth(0) + GMC.Credits:SetFormattedText("Original concept and interface by %s",C("Motig","Red") ) + GMC.Credits:SetPoint("BOTTOMLEFT",25,25) + return GMC +end +function addon:GMCRewardRefresh() + local single=GMC.settings.useOneChance + local ref + for i=1,#GMC.ignoreFrames do + local frame=GMC.ignoreFrames[i] + local allowed=GMC.settings.allowedRewards[frame.key] + frame.icon:SetDesaturated(not allowed) + local a1,o,a2,x,y=frame:GetPoint(1) + if (not single) then + frame.chest:Show() + frame.slider:Show() + frame:SetPoint(a1,o,a2,0,y) + else + frame.chest:Hide() + frame.slider:Hide() + frame:SetPoint(a1,o,a2,100,y) + end + ref=frame + end + if (single) then + GMC.itf2:SetPoint('TOPLEFT',ref,'BOTTOMLEFT', -110, -15) + GMC.cp:SetDesaturated(false) + GMC.ct:SetTextColor(C.Green()) + else + GMC.itf2:SetPoint('TOPLEFT',ref,'BOTTOMLEFT', 10, -15) + GMC.cp:SetDesaturated(true) + GMC.ct:SetTextColor(C.Silver()) + end +end +function addon:GMCBuildChance() + _G['GMC']=GMC + --Chance + GMC.cf = CreateFrame('FRAME', nil, GMC) + GMC.cf:SetSize(256, 150) + + GMC.cp = GMC.cf:CreateTexture(nil, 'BACKGROUND') + GMC.cp:SetTexture('Interface\\Garrison\\GarrisonMissionUI2.blp') + GMC.cp:SetAtlas(chestTexture) + GMC.cp:SetSize((209-(209*0.25))*0.60, (155-(155*0.25))*0.60) + GMC.cp:SetPoint('CENTER', 0, 20) + + GMC.cc = GMC.cf:CreateFontString() + GMC.cc:SetFontObject('GameFontNormalHuge') + GMC.cc:SetText('Success Chance') + GMC.cc:SetPoint('TOP', 0, 0) + GMC.cc:SetTextColor(1, 1, 1) + + GMC.ct = GMC.cf:CreateFontString() + GMC.ct:SetFontObject('ZoneTextFont') + GMC.ct:SetFormattedText('%d%%',GMC.settings.minimumChance) + GMC.ct:SetPoint('TOP', 0, -40) + GMC.ct:SetTextColor(0, 1, 0) + + GMC.cs = factory:Slider(GMC.cf,0,100,GMC.settings.minimumChance,'Minumum chance to start a mission') + GMC.cs:SetPoint('BOTTOM', 10, 0) + GMC.cs:SetScript('OnValueChanged', function(self, value) + local value = math.floor(value) + GMC.ct:SetText(value..'%') + GMC.settings.minimumChance = value + end) + GMC.cs:SetValue(GMC.settings.minimumChance) + GMC.ck=factory:Checkbox(GMC.cs,GMC.settings.useOneChance,"Use this percentage for all missions") + GMC.ck.tooltip="Unchecking this will allow you to set specific success chance for each reward type" + GMC.ck:SetPoint("TOPLEFT",GMC.cs,"BOTTOMLEFT",-60,-10) + GMC.ck:SetScript("OnClick",function(this) + GMC.settings.useOneChance=this:GetChecked() + addon:GMCRewardRefresh() + end) + return GMC.cf +end +local function timeslidechange(this,value) + local value = math.floor(value) + if (this.max) then + GMC.settings.maxDuration = max(value,GMC.settings.minDuration) + if (value~=GMC.settings.maxDuration) then this:SetValue(GMC.settings.maxDuration) end + else + GMC.settings.minDuration = min(value,GMC.settings.maxDuration) + if (value~=GMC.settings.minDuration) then this:SetValue(GMC.settings.minDuration) end + end + local c = 1-(value*(1/24)) + if c < 0.3 then c = 0.3 end + GMC.mt:SetTextColor(1, c, c) + GMC.mt:SetFormattedText("%d-%dh",GMC.settings.minDuration,GMC.settings.maxDuration) +end +function addon:GMCBuildDuration() + -- Duration + GMC.tf = CreateFrame('FRAME', nil, GMC) + GMC.tf:SetSize(256, 180) + GMC.tf:SetPoint('LEFT', 80, 120) + + GMC.bg = GMC.tf:CreateTexture(nil, 'BACKGROUND') + GMC.bg:SetTexture('Interface\\Timer\\Challenges-Logo.blp') + GMC.bg:SetSize(100, 100) + GMC.bg:SetPoint('CENTER', 0, 0) + GMC.bg:SetBlendMode('ADD') + + GMC.tcf = GMC.tf:CreateTexture(nil, 'BACKGROUND') + --bb:SetTexture('Interface\\Timer\\Challenges-Logo.blp') + --bb:SetTexture('dungeons\\textures\\devices\\mm_clockface_01.blp') + GMC.tcf:SetTexture('World\\Dungeon\\Challenge\\clockRunes.blp') + GMC.tcf:SetSize(110, 110) + GMC.tcf:SetPoint('CENTER', 0, 0) + GMC.tcf:SetBlendMode('ADD') + + GMC.mdt = GMC.tf:CreateFontString() + GMC.mdt:SetFontObject('GameFontNormalHuge') + GMC.mdt:SetText('Mission Duration') + GMC.mdt:SetPoint('TOP', 0, 0) + GMC.mdt:SetTextColor(1, 1, 1) + + GMC.mt = GMC.tf:CreateFontString() + GMC.mt:SetFontObject('ZoneTextFont') + GMC.mt:SetFormattedText('%d-%dh',GMC.settings.minDuration,GMC.settings.maxDuration) + GMC.mt:SetPoint('CENTER', 0, 0) + GMC.mt:SetTextColor(1, 1, 1) + + GMC.ms1 = factory:Slider(GMC.tf,0,24,GMC.settings.minDuration,'Minimum mission duration.') + GMC.ms2 = factory:Slider(GMC.tf,0,24,GMC.settings.maxDuration,'Maximum mission duration.') + GMC.ms1:SetPoint('BOTTOM', 0, 0) + GMC.ms2:SetPoint('TOP', GMC.ms1,"BOTTOM",0, -25) + GMC.ms2.max=true + GMC.ms1:SetScript('OnValueChanged', timeslidechange) + GMC.ms2:SetScript('OnValueChanged', timeslidechange) + timeslidechange(GMC.ms1,GMC.settings.minDuration) + timeslidechange(GMC.ms2,GMC.settings.maxDuration) + return GMC.tf +end +function addon:GMCBuildRewards() + --Allowed rewards + GMC.aif = CreateFrame('FRAME', nil, GMC) + GMC.aif:SetPoint('CENTER', 0, 120) + + GMC.itf = GMC.aif:CreateFontString() + GMC.itf:SetFontObject('GameFontNormalHuge') + GMC.itf:SetText('Allowed Rewards') + GMC.itf:SetPoint('TOP', 0, -10) + GMC.itf:SetTextColor(1, 1, 1) + + GMC.itf2 = GMC.aif:CreateFontString() + GMC.itf2:SetFontObject('GameFontHighlight') + GMC.itf2:SetText('Click to enable/disable a reward.') + GMC.itf2:SetTextColor(1, 1, 1) + + + local t = { + {t = 'Enable/Disable money rewards.', i = 'Interface\\Icons\\inv_misc_coin_01', key = 'gold'}, + {t = 'Enable/Disable other currency awards. (Resources/Seals)', i= 'Interface\\Icons\\inv_garrison_resource', key = 'resources'}, + {t = 'Enable/Disable Follower XP Bonus rewards.', i = 'Interface\\Icons\\XPBonus_Icon', key = 'xp'}, + {t = 'Enable/Disable follower equip enhancement.', i = 'Interface\\ICONS\\Garrison_ArmorUpgrade', key = 'followerEquip'}, + {t = 'Enable/Disable item tokens.', i = "Interface\\ICONS\\INV_Bracer_Cloth_Reputation_C_01", key = 'equip'} + } + local scale=1.1 + GMC.ignoreFrames = {} + local ref + local h=37 -- itemButtonTemplate standard size + local gap=5 + -- converting from old data + local ar=GMC.settings.allowedRewards + local rc=GMC.settings.rewardChance + if ar.xpBonus then ar.xp=true end + ar.xpBonus=nil + if ar.followerUpgrade then ar.followerequip=true end + ar.followerUpgrade=nil + if ar.itemLevel then ar.equip=true end + ar.itemLevel=nil + if rc.xpBonus then rc.xp=rc.xpbonus or 100 end + rc.xpBonus=nil + if rc.followerUpgrade then rc.followerequip=rc.followerUpgrade or 100 end + rc.followerUpgrade=nil + if rc.itemLevel then rc.equip=rc.itemLevel or 100 end + rc.itemLevel=nil + + for i = 1, #t do + local frame = CreateFrame('BUTTON', nil, GMC.aif, 'ItemButtonTemplate') + frame:SetScale(scale) + frame:SetPoint('TOPLEFT', 0,(i) * (-h -gap) * scale) + frame.icon:SetTexture(t[i].i) + frame.key=t[i].key + frame.tooltip=t[i].t + local allowed=GMC.settings.allowedRewards[frame.key] + local chance=GMC.settings.rewardChance[frame.key] + -- Need to resave them asap in order to populate the array for future scans + GMC.settings.allowedRewards[frame.key]=allowed + GMC.settings.rewardChance[frame.key]=chance + frame.slider=factory:Slider(frame,0,100,chance or 100,chance or 100) + frame.slider:SetWidth(128) + frame.slider:SetPoint('BOTTOMLEFT',60,0) + frame.slider.Text:SetFontObject('NumberFont_Outline_Med') + frame.slider.Text:SetTextColor(C.Green()) + frame.slider.isPercent=true + frame.slider:SetScript("OnValueChanged",function(this,value) + GMC.settings.rewardChance[this:GetParent().key]=this:OnValueChanged(value) + end + ) + frame.chest = frame:CreateTexture(nil, 'BACKGROUND') + frame.chest:SetTexture('Interface\\Garrison\\GarrisonMissionUI2.blp') + frame.chest:SetAtlas(chestTexture) + frame.chest:SetSize((209-(209*0.25))*0.30, (155-(155*0.25)) * 0.30) + frame.chest:SetPoint('CENTER',frame.slider, 0, 25) + frame:SetScript('OnClick', function(this) + local allowed= this.icon:IsDesaturated() -- ID it was desaturated, I want it allowed, now + GMC.settings.allowedRewards[this.key] = allowed + addon:GMCRewardRefresh() + end) + frame:SetScript('OnEnter', function(this) + GameTooltip:SetOwner(this, 'ANCHOR_BOTTOMRIGHT') + GameTooltip:AddLine(this.tooltip); + GameTooltip:Show() + end) + + frame:SetScript('OnLeave', function() GameTooltip:Hide() end) + GMC.ignoreFrames[i] = frame + ref=frame + end + self:GMCRewardRefresh() + GMC.aif:SetSize(256, (scale*h+gap) * #t) + GMC.itf2:SetPoint('TOPLEFT',ref,'BOTTOMLEFT', 5, -15) + return GMC.aif +end + +local addPriorityRule,prioRefresh,removePriorityRule,prioMenu,prioTitles,prioCheck,prioVoices +do +-- 1 = item, 2 = folitem, 3 = exp, 4 = money, 5 = resource + prioTitles={ + itemLevel="Equipment", + followerUpgrade="Followr Upgrade", + xp="Xp gain", + gold="Gold Reward", + resources="Resource Rewards" + } + prioVoices=0 + for _ in pairs(prioTitles) do prioVoices=prioVoices+1 end + prioMenu={} + + ---@function [parent=#GMC] prioRefresh + function prioRefresh() + for i=1,prioVoices do + local group=GMC.prioFrames[i] + local code=GMC.settings.itemPrio[i] + if (not code) then + group.text:Hide() + group.xbutton:Hide() + group.nr:Hide() + else + group.text:Show() + group.text:SetText(prioTitles[code]) + group.xbutton:Show() + group.nr:Show() + end + end + GMC.abutton:Hide() + for i=1,prioVoices do + local group=GMC.prioFrames[i] + if (not group.text:IsShown()) then + group.nr:Show() + GMC.abutton:SetPoint("TOPLEFT",group.text) + GMC.abutton:Show() + break + end + end + end + ---@function [parent=#GMC] addPriorityRule + function addPriorityRule(this,key) + tinsert(GMC.settings.itemPrio,key) + prioRefresh() + end + ---@function [parent=#GMC] removePriorityRule + function removePriorityRule(index) + tremove(GMC.settings.itemPrio,index) + prioRefresh() + end + +end +_G.XPRIO=prioRefresh +function addon:GMCBuildPriorities() + --Prio + GMC.pf = CreateFrame('FRAME', nil, GMC) + GMC.pf:SetSize(256, 240) + + GMC.pft = GMC.pf:CreateFontString() + GMC.pft:SetFontObject('GameFontNormalHuge') + GMC.pft:SetText('Item Priority') + GMC.pft:SetPoint('TOP', 0, -10) + GMC.pft:SetTextColor(1, 1, 1) + + GMC.pft2 = GMC.pf:CreateFontString() + GMC.pft2:SetFontObject('GameFontNormal') + GMC.pft2:SetText('Prioritize missions with certain a reward.') + GMC.pft2:SetPoint('BOTTOM', 0, 16) + GMC.pft2:SetTextColor(1, 1, 1) + GMC.pmf = CreateFrame("FRAME", "GMC_PRIO_MENU", GMC.pf, "UIDropDownMenuTemplate") + + + GMC.prioFrames = {} + GMC.prioFrames.selected = 0 + for i = 1, prioVoices do + GMC.prioFrames[i] = {} + local this = GMC.prioFrames[i] + this.f = CreateFrame('FRAME', nil, GMC.pf) + this.f:SetSize(255, 32) + this.f:SetPoint('TOP', 0, -38-((i-1)*32)) + + this.nr = this.f:CreateFontString() + this.nr:SetFontObject('GameFontNormalHuge') + this.nr:SetText(i..'.') + this.nr:SetPoint('LEFT', 8, 0) + this.nr:SetTextColor(1, 1, 1) + + this.text = this.f:CreateFontString() + this.text:SetFontObject('GameFontNormalLarge') + this.text:SetText('Def') + this.text:SetPoint('LEFT', 32, 0) + --this.text:SetTextColor(1, 1, 0) + this.text:SetJustifyH('LEFT') + this.text:Hide() + + this.xbutton = CreateFrame('BUTTON', nil, this.f, 'GameMenuButtonTemplate') + this.xbutton:SetPoint('RIGHT', 0, 0) + this.xbutton:SetText('X') + this.xbutton:SetWidth(28) + this.xbutton:SetScript('OnClick', function() removePriorityRule(i) end) + this.xbutton:Hide() + end + + GMC.abutton = CreateFrame('BUTTON', nil, GMC.pmf, 'GameMenuButtonTemplate') + GMC.abutton:SetText(L['Add priority rule']) + GMC.abutton:SetWidth(128) + GMC.abutton:Hide() + GMC.abutton:SetScript('OnClick', function() + wipe(prioMenu) + tinsert(prioMenu,{text = L["Select an item to add as priority."], isTitle = true, isNotRadio=true,disabled=true, notCheckable=true,notClickable=true}) + for k,v in pairs(prioTitles) do + tinsert(prioMenu,{text = v, func = addPriorityRule, notCheckable=true, isNotRadio=true, arg1 = k , disabled=tContains(GMC.settings.itemPrio,k)}) + end + EasyMenu(prioMenu, GMC.pmf, "cursor", 0 , 0, "MENU") + end + ) + prioRefresh() + return GMC.pf +end +function addon:GMCBuildMissionList() + -- Mission list on follower panels +-- local ml=CreateFrame("Frame",nil,GMC) +-- addBackdrop(ml) +-- ml:Show() +-- ml.Missions={} +-- ml.Parties={} +-- GMC.ml=ml +-- local fs=ml:CreateFontString(nil, "BACKGROUND", "GameFontNormalHugeBlack") +-- fs:SetPoint("TOPLEFT",0,-5) +-- fs:SetPoint("TOPRIGHT",0,-5) +-- fs:SetText(READY) +-- fs:SetTextColor(C.Green()) +-- fs:SetHeight(30) +-- fs:SetJustifyV("CENTER") +-- fs:Show() +-- GMC.progressText=fs +-- GMC.ml.Header=fs +-- return GMC.ml + local ml={widget=AceGUI:Create("GMCLayer"),Parties={}} + ml.widget:SetTitle(READY) + ml.widget:SetTitleColor(C.Green()) + ml.widget:SetTitleHeight(40) + ml.widget:SetParent(GMC) + ml.widget:Show() + GMC.ml=ml + return ml.widget + +end diff --git a/PartyCache.lua b/PartyCache.lua new file mode 100644 index 0000000..e3c4305 --- /dev/null +++ b/PartyCache.lua @@ -0,0 +1,249 @@ +local me,ns=... +local addon=ns.addon --#addon +local holdEvents,releaseEvents=addon.holdEvents,addon.releaseEvents +--upvalue +local G=C_Garrison +local setmetatable=setmetatable +local rawset=rawset +local tContains=tContains +local wipe=wipe +local tremove=tremove +local tinsert=tinsert +local pcall=pcall + +-- +-- Temporary party management +local parties=setmetatable({},{ + __index=function(t,k) rawset(t,k, + { + members={}, + threats={}, + perc=0, + itemLevel=0, + followerUpgrade=0, + xpBonus=0, + gold=0, + resources=0, + }) return t[k] end +}) +function ns.inParty(missionID,followerID) + return tContains(ns.parties[missionID].members,followerID) +end +--- Follower Missions Info +-- +local followerMissions=setmetatable({},{ + __index=function(t,k) rawset(t,k,{}) return t[k] end +}) +ns.party={} +local party=ns.party --#party +local ID,maxFollowers,members,ignored,threats=0,1,{},{},{} +function party:Open(missionID,followers) + maxFollowers=followers + ID=missionID + for enemy,menaces in pairs(G.GetMissionUncounteredMechanics(ID)) do + for i=1,#menaces do + tinsert(threats,format("%d:%d",enemy,menaces[i])) + end + end + holdEvents() +end +function party:Ignore(followerID) + ignored[followerID]=true +end +function party:IsIgnored(followerID) + return ignored[followerID] +end + +function party:IsIn(followerID) + return tContains(members,followerID) +end +function party:MaxSlots() + return maxFollowers +end +function party:FreeSlots() + return maxFollowers-#members +end +function party:IsEmpty() + return maxFollowers>0 and #members==0 +end + +function party:Dump() + ns.xprint("Dumping party for mission",ID) + for i=1,#members do + ns.xprint(addon:GetFollowerData(members[i],'fullname'),G.GetFollowerStatus(members[i] or 1)) + end + ns.xprint(G.GetPartyMissionInfo(ID)) +end + +function party:AddFollower(followerID) + if (followerID:sub(1,2) ~= '0x') then ns.xtrace(followerID .. "is not an id") end + if (self:FreeSlots()>0) then + local rc,code=pcall (G.AddFollowerToMission,ID,followerID) + if (not rc and code==false) then + pcall(G.RemoveFollowerFromMission,ID,followerID) + rc,code=pcall (G.AddFollowerToMission,ID,followerID) + end + if (rc and code) then + tinsert(members,followerID) + return true +--[===[@debug@ + else + ns.xprint("Unable to add",followerID, G.GetFollowerName(followerID),"to",ID,code,self:IsIn(followerID),G.GetFollowerStatus(followerID)) + ns.xprint(members[1],members[2],members[3]) + ns.xprint(debugstack(1,6,0)) +--@end-debug@]===] + end + end +end +function party:RemoveFollower(followerID) + for i=1,maxFollowers do + if (followerID==members[i]) then + tremove(members,i) + local rc,code=pcall(G.RemoveFollowerFromMission,ID,followerID) +--[===[@debug@ + if (not rc) then trace("Unable to remove", G.GetFollowerName(members[i]),"from",ID,code) end +--@end-debug@]===] + return true end + end +end + +function party:StoreFollowers(table) + wipe(table) + for i=1,#members do + tinsert(table,members[i]) + end + return #table +end +local function fsort(a,b) + return addon:GetFollowerData(a,"rank")>addon:GetFollowerData(b,"rank") +end +function party:Close(desttable) + local perc + table.sort(members,fsort) + for i=1,#members do + local bias=G.GetFollowerBiasForMission(ID,members[i]) + for _id,ability in pairs(G.GetFollowerAbilities(members[i])) do + if not ability.isTrait then + for counter,data in pairs(ability.counters) do + for j=1,#threats do + local enemy,threat,oldbias,follower,name=strsplit(":",threats[j]) + oldbias=tonumber(oldbias) or -2 + if bias >oldbias and tonumber(threat)==tonumber(counter) then + threats[j]=format("%d:%d:%f:%s:%s",enemy,threat,bias or -2,members[i],G.GetFollowerName(members[i])) + end + end + end + end + end + end + if (desttable) then + desttable.totalTimeString, + desttable.totalTimeSeconds, + desttable.isMissionTimeImproved, + desttable.perc, + desttable.partyBuffs, + desttable.isEnvMechanicCountered, + desttable.xpBonus, + desttable.materialMultiplier, + desttable.goldMultiplier = G.GetPartyMissionInfo(ID) + if (ns.toc < 60100) then + desttable.goldMultiplier = 1 + end + desttable.full=self:FreeSlots()==0 + desttable.threats=desttable.threats or {} + wipe(desttable.threats) + for i=1,#threats do + tinsert(desttable.threats,threats[i]) + end + perc=desttable.perc + else + perc=select(4,G.GetPartyMissionInfo(ID)) + end + for i=1,3 do + if (members[i]) then + local rc,code=pcall(G.RemoveFollowerFromMission,ID,members[i]) +--[===[@debug@ + if (not rc) then ns.xtrace("Unable to pop", G.GetFollowerName(members[i])," from ",ID,code) end +--@end-debug@]===] + + else + break + end + end + releaseEvents() + wipe(members) + wipe(ignored) + wipe(threats) + return perc or 0 +end +function party:CalculateThreats(followers,missionID) + local threats = {}; + threats.full = {}; + threats.partial = {}; + threats.away = {}; + threats.worker = {}; + missionID=missionID or ID + local followerList=followers or members + for i = 1, #followerList do + local followerID = followerList[i]; + local status=G.GetFollowerStatus(followerID) + local bias = G.GetFollowerBiasForMission(missionID, followerID); + if ( bias > -1.0 ) then + local abilities = G.GetFollowerAbilities(followerID); + for j = 1, #abilities do + for counterMechanicID in pairs(abilities[j].counters) do + if ( status ) then + if ( status == GARRISON_FOLLOWER_ON_MISSION ) then + local time = G.GetFollowerMissionTimeLeftSeconds(followerID); + if ( not threats.away[counterMechanicID] ) then + threats.away[counterMechanicID] = {}; + end + table.insert(threats.away[counterMechanicID], time); + elseif ( status == GARRISON_FOLLOWER_WORKING ) then + threats.worker[counterMechanicID] = (threats.worker[counterMechanicID] or 0) + 1; + end + else + local isFullCounter = G.IsMechanicFullyCountered(missionID, followerID, counterMechanicID, abilities[j].id); + if ( isFullCounter ) then + threats.full[counterMechanicID] = (threats.full[counterMechanicID] or 0) + 1; + else + threats.partial[counterMechanicID] = (threats.partial[counterMechanicID] or 0) + 1; + end + end + end + end + end + end + + for counter, times in pairs(threats.away) do + table.sort(times); + end + return threats; +end +function addon:GetBusyParty(missionID) + return self:GetParty(missionID).busy +end +function addon:GetReadyParty(missionID,key) + return self:GetParty(missionID) +end +function addon:GetParties() + return self:GetParty() +end +function addon:GetParty(missionID,key) + if not missionID then return parties end + local party=parties[missionID] + if #party.members==0 and G.GetNumFollowersOnMission(missionID)>0 then + local followers=self:GetMissionData(missionID,'followers') + party.perc=select(4,G.GetPartyMissionInfo(missionID)) + for i=1,#followers do + party.members[i]=followers[i] + end + --Running Mission, taking followers from mission data + end + if key then + return party[key] + else + return party + end + +end \ No newline at end of file diff --git a/doc.txt b/doc.txt index 83ed7f0..9e14563 100644 --- a/doc.txt +++ b/doc.txt @@ -291,3 +291,154 @@ Xp bonus: 570 593 +------- Methods +AddFollowerToMission", +AssignFollowerToBuilding", +CanGenerateRecruits", +CanOpenMissionChest", +CanSetRecruitmentPreference", +CanUpgradeGarrison", +CancelConstruction", +CastSpellOnFollower", +CastSpellOnMission", +CloseArchitect", +CloseGarrisonTradeskillNPC", +CloseMissionNPC", +CloseRecruitmentNPC", +CloseTradeskillCrafter", +GenerateRecruits", +GetAllEncounterThreats() Returns the full list of possibile threats +GetAvailableMissions", +GetAvailableRecruits", +GetBasicMissionInfo", +GetBuildingInfo", +GetBuildingLockInfo", +GetBuildingSizes", +GetBuildingSpecInfo", +GetBuildingTimeRemaining", +GetBuildingTooltip", +GetBuildingUpgradeInfo", +GetBuildings", +GetBuildingsForPlot", +GetBuildingsForSize", +GetCompleteMissions", +GetFollowerAbilities(followerID), +GetFollowerAbilityAtIndex", +GetFollowerAbilityAtIndexByID", +GetFollowerAbilityCounterMechanicInfo", +GetFollowerAbilityDescription", +GetFollowerAbilityIcon", +GetFollowerAbilityIsTrait", +GetFollowerAbilityLink", +GetFollowerAbilityName", +GetFollowerActivationCost", +GetFollowerBiasForMission", +GetFollowerClassSpec", +GetFollowerClassSpecAtlas", +GetFollowerClassSpecByID", +GetFollowerClassSpecName", +GetFollowerDisplayID", +GetFollowerDisplayIDByID", +GetFollowerInfo", +GetFollowerInfoForBuilding", +GetFollowerItemLevelAverage", +GetFollowerItems", +GetFollowerLevel", +GetFollowerLevelXP", +GetFollowerLink", +GetFollowerLinkByID", +GetFollowerMissionCompleteInfo" +GetFollowerMissionTimeLeft", +GetFollowerMissionTimeLeftSeconds", +GetFollowerModelItems", +GetFollowerName", +GetFollowerNameByID", +GetFollowerPortraitIconIDByID" +GetFollowerQuality", +GetFollowerQualityTable", +GetFollowerSoftCap", +GetFollowerSourceTextByID", +GetFollowerStatus" +GetFollowerTraitAtIndex", +GetFollowerTraitAtIndexByID", +GetFollowerXP", +GetFollowerXPTable", +GetFollowersTraitsForMission" +GetGarrisonInfo", +GetGarrisonUpgradeCost", +GetInProgressMissions", +GetLandingPageItems", +GetLandingPageShipmentCount", +GetLandingPageShipmentInfo", +GetMissionCompleteEncounters", +GetMissionDisplayIDs", +GetMissionInfo", +GetMissionLink", +GetMissionMaxFollowers", +GetMissionName", +GetMissionRewardInfo", +GetMissionSuccessChance", +GetMissionTimes", +GetMissionUncounteredMechanics", +GetNumActiveFollowers", +GetNumFollowerActivationsRemaining", +GetNumFollowerDailyActivations", +GetNumFollowers", +GetNumFollowersForMechanic", +GetNumFollowersOnMission", +GetNumPendingShipments", +GetNumShipmentReagents", +GetOwnedBuildingInfo", +GetOwnedBuildingInfoAbbrev", +GetPartyBuffs", +GetPartyMentorLevels", +GetPartyMissionInfo", +GetPendingShipmentInfo", +GetPlots", +GetPlotsForBuilding", +GetPossibleFollowersForBuilding" +GetRecruitAbilities", +GetRecruiterAbilityCategories", +GetRecruiterAbilityList", +GetRecruitmentPreferences", +GetRewardChance", +GetShipmentContainerInfo", +GetShipmentItemInfo", +GetShipmentReagentCurrencyInfo", +GetShipmentReagentInfo", +GetShipmentReagentItemLink", +GetSpecChangeCost", +GetTabForPlot", +IsAboveFollowerSoftCap", +IsFollowerCollected", +IsFollowerUnique", +IsInvasionAvailable", +IsMechanicFullyCountered", +IsOnGarrisonMap", +IsOnShipmentQuestForNPC", +IsUsingPartyGarrison", +IsVisitGarrisonAvailable", +MarkMissionComplete", +MissionBonusRoll", +PlaceBuilding", +RecruitFollower", +RemoveFollower", +RemoveFollowerFromBuilding", +RemoveFollowerFromMission", +RequestGarrisonUpgradeable", +RequestLandingPageShipmentInfo", +RequestShipmentCreation", +RequestShipmentInfo", +SearchForFollower", +SetBuildingActive", +SetBuildingSpecialization", +SetFollowerFavorite", +SetFollowerInactive", +SetRecruitmentPreferences", +SetUsingPartyGarrison", +StartMission", +SwapBuildings", +TargetSpellHasFollowerItemLevelUpgrade", +UpgradeBuilding", +UpgradeGarrison", + diff --git a/libs/LibDeformat-3.0/LibDeformat-3.0.lua b/libs/LibDeformat-3.0/LibDeformat-3.0.lua index f4bcb52..6580517 100644 --- a/libs/LibDeformat-3.0/LibDeformat-3.0.lua +++ b/libs/LibDeformat-3.0/LibDeformat-3.0.lua @@ -211,7 +211,7 @@ function LibDeformat.Deformat(text, pattern) return get_deformat_function(pattern)(text) end ---@debug@ +--[===[@debug@ function LibDeformat.Test() local function tuple(success, ...) if success then @@ -267,6 +267,6 @@ function LibDeformat.Test() test("Hello, friend", "Cost: $%d", nil) print("LibDeformat-3.0: Tests completed.") end ---@end-debug@ +--@end-debug@]===] setmetatable(LibDeformat, { __call = function(self, ...) return self.Deformat(...) end }) \ No newline at end of file