From 3155f378e25b2de235eb307d5467d8fe75916042 Mon Sep 17 00:00:00 2001 From: Alar of Daggerspine Date: Fri, 13 Feb 2015 01:18:23 +0100 Subject: [PATCH 1/7] Started refactoring Signed-off-by: Alar of Daggerspine --- Debug.lua | 227 +++++++ GarrisonCommander-Broker/ldb.lua | 15 +- GarrisonCommander.lua | 1353 ++++---------------------------------- GarrisonCommander.toc | 13 + Init.lua | 100 +++ MissionControl.lua | 652 ++++++++++++++++++ PartyCache.lua | 117 ++++ 7 files changed, 1237 insertions(+), 1240 deletions(-) create mode 100644 Debug.lua create mode 100644 FollowerCache.lua create mode 100644 FollowerPage.lua create mode 100644 FollowerRecruiting.lua create mode 100644 Init.lua create mode 100644 MatchMaker.lua create mode 100644 MissionCache.lua create mode 100644 MissionCompletion.lua create mode 100644 MissionControl.lua create mode 100644 PartyCache.lua diff --git a/Debug.lua b/Debug.lua new file mode 100644 index 0000000..4afd57c --- /dev/null +++ b/Debug.lua @@ -0,0 +1,227 @@ +--@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) + +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..e69de29 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..46b94e1 100644 --- a/GarrisonCommander-Broker/ldb.lua +++ b/GarrisonCommander-Broker/ldb.lua @@ -9,7 +9,18 @@ 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 diff --git a/GarrisonCommander.lua b/GarrisonCommander.lua index 8c59f4d..34d14fc 100644 --- a/GarrisonCommander.lua +++ b/GarrisonCommander.lua @@ -1,27 +1,14 @@ 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 _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 @@ -73,63 +60,13 @@ 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) @@ -235,7 +172,6 @@ local BIGBUTTON=BIGSIZEW-GCSIZE local SMALLBUTTON=BIGSIZEW-GCSIZE local GCF local GMC -local GMCUsedFollowers={} local GCFMissions local GCFBusyStatus local GameTooltip=GameTooltip @@ -331,165 +267,7 @@ 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 - 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 - 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 - - ---@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 - - ---@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 -end -- --@debug@ local origGarrisonMissionButton_OnEnter = _G.GarrisonMissionButton_OnEnter @@ -579,10 +357,11 @@ end function addon:OnInitialized() --@debug@ - xprint("OnInitialized") + ns.xprint("OnInitialized") self.evdebug=CreateFrame("Frame") self.evdebug:SetScript("OnEvent",function(...) return print('|cffff2020event|r',...) end) --@end-debug@ + parties=self:GetParty() for _,b in ipairs(GMFMissionsListScrollFrame.buttons) do local scale=0.8 local f,h,s=b.Title:GetFont() @@ -835,7 +614,6 @@ function addon:FillCounters(missionID,mission) -- 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 @@ -848,7 +626,6 @@ function addon:FillCounters(missionID,mission) 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 @@ -966,7 +743,7 @@ local function best(fid1,fid2,counters,mission) 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 (P:IsIn(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 @@ -982,14 +759,14 @@ 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 + if (not party) then party=self:GetParty(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) + P:Open(missionID,mission.numFollowers) -- Preloading skipped ones in party table. if (dbg) then print(C("Matchmaking mission","Red"),missionID,mission.name) end if (missionCounters) then @@ -1000,13 +777,13 @@ function addon:MatchMaker(missionID,mission,party,fromMissionControl) else if (self:IsIgnored(followerID,missionID)) then if (dbg) then print("Skipped",n[followerID],"due to ignored" ) end - partyIgnore(followerID,true) + P:Ignore(followerID,true) elseif not self:IsFollowerAvailableForMission(followerID,skipBusy) then if (dbg) then print("Skipped",n[followerID],"due to busy" ) end - partyIgnore(followerID) + P:Ignore(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) + P:Ignore(followerID,true) end end end @@ -1018,13 +795,13 @@ function addon:MatchMaker(missionID,mission,party,fromMissionControl) if (dbg) then print("Checking ",threat) end for i=1,#candidates do local followerID=missionCounters[candidates[i]].followerID - if isInParty(followerID) then + if P:IsIn(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 + if(not P:IsIgnored(followerID)) then choosen=best(choosen,candidates[i],missionCounters,mission) if (dbg) then print("Taken",n[missionCounters[choosen].followerID]) end else @@ -1033,41 +810,38 @@ function addon:MatchMaker(missionID,mission,party,fromMissionControl) 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) + if dbg then print("Adding to party",n[missionCounters[choosen].followerID]," still need ",P:FreeSlots()) end + P:AddFollower(missionCounters[choosen].followerID) end - if (roomInParty()==0) then + if (P:FreeSlots()==0) then break end end else - xprint("Mission",missionID,"has no slots????") + ns.xprint("Mission",missionID,"has no slots????") end - if roomInParty() > 0 then self:AddTraitsToParty(missionID,mission) end + if P:FreeSlots() > 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 + if P:FreeSlots() > 0 then self:CompleteParty(missionID,mission,skipBusy,skipMaxed) end + if (not fromMissionControl and not P:IsEmpty()) then + if P:FreeSlots() > 0 then self:CompleteParty(missionID,mission,skipBusy,false) end end - storeFollowers(party.members) - party.full= roomInParty()==0 - party.perc=closeParty() + P:StoreFollowers(party.members) + party.full= P:FreeSlots()==0 + party.perc=P:Close() 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 (follower.trait and not P:IsIgnored(follower.followerID) and not P:IsIn(follower.followerID)) then if mission.resources > 0 and follower.name==scavengerTrait then - pushFollower(follower.followerID) + P:AddFollower(follower.followerID) elseif mission.xpOnly and (follower.name==extraTrainingTrait or follower.name==hearthStoneProTrait) then - pushFollower(follower.followerID) + P:AddFollower(follower.followerID) elseif mission.durationSeconds > GARRISON_LONG_MISSION_TIME and follower.name==epicMountTrait then - pushFollower(follower.followerID) + P:AddFollower(follower.followerID) end end end @@ -1080,24 +854,23 @@ function addon:CompleteParty(missionID,mission,skipBusy,skipMaxed) local candidateQuality=9999 if (dbg) then print("Attemptin to fill party, so far perc is ",perc, "and party is") - dumpParty() + P:Dump() end - local stash={} - for x=1,roomInParty() do + for x=1,P:FreeSlots() do local candidate local candidatePerc=perc - if (dbg) then print(" Perc to beat",perc, "Going for spot ",roomInParty()) end + if (dbg) then print(" Perc to beat",perc, "Going for spot ",P:FreeSlots()) 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 P:IsIgnored(followerID) then if (dbg) then print("Skipped due to party ignored") end break end - if isInParty(followerID) then + if P:IsIn(followerID) then if (dbg) then print("Skipped due to already in party") end break end @@ -1113,51 +886,37 @@ function addon:CompleteParty(missionID,mission,skipBusy,skipMaxed) 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) + P:AddFollower(followerID) local newperc=select(4,G.GetPartyMissionInfo(missionID)) newperc=tonumber(newperc) or 0 candidatePerc=tonumber(candidatePerc) or 0 - removeFollower(followerID) + P: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 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 @@ -1348,10 +1102,10 @@ function addon:BuildMissionsCache(fc,mm,OnEvent) --cache.missions --@debug@ local start=GetTime() - xprint("Start Full Cache Rebuild") + ns.xprint("Start Full Cache Rebuild") --@end-debug@ local t=new() - holdEvents() + self:holdEvents() G.GetAvailableMissions(t) for index=1,#t do local missionID=t[index].missionID @@ -1371,11 +1125,11 @@ function addon:BuildMissionsCache(fc,mm,OnEvent) dbcache.seen[k]=nil end end - releaseEvents() + self:releaseEvents() del(t) collectgarbage("step",10) --@debug@ - xprint("Done in",GetTime()-start) + ns.xprint("Done in",GetTime()-start) --@end-debug@ end --[[ @@ -1479,7 +1233,7 @@ function addon:BuildMissionCache(id,data) local mission=cache.missions[id] if (not mission) then --@dedbug@ - xprint("Generating new data for ",id) + ns.xprint("Generating new data for ",id) --@end-debug@ mission = data or G.GetBasicMissionInfo(id) if (not mission) then return end @@ -1521,7 +1275,7 @@ function addon:BuildMissionCache(id,data) mission.locPrefix=locPrefix if (not type) then --@debug@ - xprint("No type",id,data.name) + ns.xprint("No type",id,data.name) --@end-debug@ else if (not self.db.global.types[type]) then @@ -1620,13 +1374,13 @@ end function addon:EventGARRISON_MISSION_NPC_OPENED(event,...) --@debug@ - xprint(event,...) + ns.xprint(event,...) --@end-debug@ if (GCF) then GCF:Show() end end function addon:EventGARRISON_MISSION_NPC_CLOSED(event,...) --@debug@ - xprint(event,...) + ns.xprint(event,...) --@end-debug@ if (GCF) then self:RemoveMenu() @@ -1636,7 +1390,7 @@ 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={} @@ -1657,7 +1411,7 @@ end function addon:EventGARRISON_MISSION_STARTED(event,missionID,...) --@debug@ - xprint(event,missionID,...) + ns.xprint(event,missionID,...) --@end-debug@ -- running={ -- ["*"]={ @@ -1701,8 +1455,8 @@ end function addon:EventGARRISON_MISSION_FINISHED(event,missionID,...) --@debug@ - xprint(event,missionID,...) - xdump(G.GetPartyMissionInfo(missionID)) + ns.xprint(event,missionID,...) + ns.xdump(G.GetPartyMissionInfo(missionID)) --@end-debug@ end function addon:EventGARRISON_FOLLOWER_LIST_UPDATE(event) @@ -1710,12 +1464,12 @@ function addon:EventGARRISON_FOLLOWER_LIST_UPDATE(event) wipe(followersCache) wipe(followersCacheIndex) wipe(parties) - xprint("Follower cache cleaned") + ns.xprint("Follower cache cleaned") end function addon:EventGARRISON_MISSION_BONUS_ROLL_LOOT(event,missionID,completed,success) --@debug@ - xprint('evt',event,missionID,completed,success) + ns.xprint('evt',event,missionID,completed,success) --@end-debug@ self:RefreshFollowerStatus() end @@ -1732,7 +1486,7 @@ end -- function addon:EventGARRISON_MISSION_COMPLETE_RESPONSE(event,missionID,completed,rewards) --@debug@ - xprint('evt',event,missionID,completed,rewards) + ns.xprint('evt',event,missionID,completed,rewards) --@end-debug@ dbcache.history[missionID][time()]={result=100,success=rewards} dbcache.seen[missionID]=nil @@ -1778,25 +1532,29 @@ function addon:Clock() dbgFrame=AceGUI:Create("Window") dbgFrame:SetTitle("GC Performance") dbgFrame:SetPoint("LEFT") - dbgFrame:SetHeight(80) + dbgFrame:SetHeight(120) dbgFrame:SetWidth(350) - dbgFrame:SetLayout("fill") + dbgFrame:SetLayout("flow") dbgFrame.Text=AceGUI:Create("Label") - dbgFrame.Text:SetColor(1,0,0) + dbgFrame.Text:SetColor(1,1,0) + dbgFrame.Text:SetFullWidth(true) + dbgFrame.Text1=AceGUI:Create("Label") + dbgFrame.Text1:SetColor(1,1,0) + dbgFrame.Text1:SetFullWidth(true) dbgFrame:AddChild(dbgFrame.Text) + dbgFrame:AddChild(dbgFrame.Text1) 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), + dbgFrame.Text:SetText(format("Garrison Commander Mem %4.3fMB ", GetAddOnMemoryUsage("GarrisonCommander")/1024) ) - lastCPU=cpu + dbgFrame.Text1:SetText(format("Garrison Broker Mem %4.3fMB ", + GetAddOnMemoryUsage("GarrisonCommander-Broker")/1024) + ) --@end-debug@ dbcache.lastseen=time() if (not MP or MPGoodGuy) then return end @@ -1900,10 +1658,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 @@ -2069,7 +1827,7 @@ function addon:GenerateMissionCompleteList(title) 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]) + ns.xprint(followerID,quality,level,data[3],data[4]) local levelup=((quality > data[4]) or (level > data[3])) --local levelup=true if levelup then @@ -2555,7 +2313,7 @@ end function addon:ScriptTrace(hook,frame,...) --@debug@ - xprint("Triggered " .. C(hook,"red").." script on",C(frame,"Azure"),...) + ns.xprint("Triggered " .. C(hook,"red").." script on",C(frame,"Azure"),...) --@end-debug@ end function addon:IsProgressMissionPage() @@ -2579,9 +2337,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 @@ -2898,7 +2655,7 @@ do end end function addon:RenderFollowerPageMissionList(frame,followerID,force) - xprint("hook",followerID,force) + ns.xprint("hook",followerID,force) if (followerID==lastFollowerID and not force) then return end lastFollowerID=followerID local i=0 @@ -2906,8 +2663,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 @@ -2960,7 +2717,7 @@ do local missionID=partyIndex[z] if not(tonumber(missionID)) then --@debug@ - xprint("missionid not a number",missionID) + ns.xprint("missionid not a number",missionID) self:Dump("partyIndex table",partyIndex) --@end-debug@ perc=-1 --(lowering perc to ignore this mission @@ -3027,7 +2784,7 @@ end --Initial one time setup function addon:SetUp(...) --@debug@ - xprint("Setup") + ns.xprint("Setup") --@end-debug@ --@alpha@ if (not db.alfa.v220) then @@ -3041,23 +2798,25 @@ function addon:SetUp(...) self:CheckGMM() self:Options() self:GenerateMissionsWidgets() - self:GMCBuildPanel() + GMC=self:GMCBuildPanel(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") @@ -3113,7 +2872,7 @@ end -- when it closes, I remove most of used hooks function addon:StartUp(...) --@debug@ - xprint("Startup") + ns.xprint("Startup") --@end-debug@ self:GrowPanel() self:Unhook(GMF,"OnShow") @@ -3128,7 +2887,7 @@ function addon:StartUp(...) self:SafeSecureHook("GarrisonMissionButton_SetRewards") 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) + self:SafeSecureHook("GarrisonFollowerPage_ShowFollower")--,function(...) ns.xprint("GarrisonFollowerPage_ShowFollower",...) end) self:SafeSecureHook("GarrisonFollowerTooltipTemplate_SetGarrisonFollower") end self:SafeSecureHook("GarrisonMissionFrame_HideCompleteMissions") -- Mission reward completed @@ -3184,12 +2943,12 @@ end function addon:checkMethod(method,hook) if (type(self[method])=="function") then --@debug@ - --xprint("Hooking ",hook,"to self:" .. method) + --ns.xprint("Hooking ",hook,"to self:" .. method) --@end-debug@ return true --@debug@ else - --xprint("Hooking ",hook,"to print") + --ns.xprint("Hooking ",hook,"to print") --@end-debug@ end end @@ -3204,7 +2963,7 @@ function addon:SafeRegisterEvent(event) return self:RegisterEvent(event,method) --@debug@ else - return self:RegisterEvent(event,xprint) + return self:RegisterEvent(event,ns.xprint) --@end-debug@ end end @@ -3217,7 +2976,7 @@ function addon:SafeSecureHook(tobehooked,method) 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 @@ -3261,7 +3020,7 @@ function addon:CleanUp() end --collectgarbage("collect") --@debug@ - xprint("Cleaning up") + ns.xprint("Cleaning up") --@end-debug@ end function addon:EventGARRISON_FOLLOWER_XP_CHANGED(event,followerID,iLevel,xp,level,quality) @@ -3362,7 +3121,7 @@ function addon:GetMissionData(missionID,subkey) local missionCache=cache.missions[missionID] if (not missionCache) then --@debug@ - xprint("Found a new mission",missionID,"Refreshing it") + ns.xprint("Found a new mission",missionID,"Refreshing it") --@end-debug@ self:BuildMissionCache(missionID) self:FillCounters(missionID,cache.missions[missionID]) @@ -3375,7 +3134,7 @@ function addon:GetMissionData(missionID,subkey) return missionCache end function addon:IsFollowerAvailableForMission(followerID,skipbusy) - if (GMCUsedFollowers[followerID]) then + if self:GMCBusy(followerID) then return false end if (not skipbusy) then @@ -3406,15 +3165,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) + ns.xprint("UpdateMissionPage for",missionID,missionInfo.name,missionInfo.numFollowers) --@end-debug@ - --xdump(missionInfo) + --ns.xdump(missionInfo) --self:BuildMissionData(missionInfo.missionID.missionInfo) - holdEvents() + self:holdEvents() GarrisonMissionPage_ClearParty() local party=parties[missionID] if (party) then @@ -3426,7 +3185,7 @@ function addon:FillMissionPage(missionInfo) 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") + ns.xprint(followerID,self:GetFollowerData(followerID,"name"),"was already on mission") --@end-debug@ self:RemoveFromAllMissions(followerID) GarrisonMissionPage_AddFollower(followerID) @@ -3435,14 +3194,14 @@ 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() + self:releaseEvents() end local firstcall=true @@ -3742,7 +3501,7 @@ function addon:BuildExtraButton(button) 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") @@ -3838,7 +3597,7 @@ function addon:OnClick_GarrisonMissionButton(tab,button) end if (type(tab.info)~="table") then return end --@debug@ - xprint("Clicked GarrisonMissionButton") + ns.xprint("Clicked GarrisonMissionButton") --@end-debug@ if (tab.fromFollowerPage) then if (#tab.info.followers>0) then @@ -3859,7 +3618,12 @@ function addon:OnClick_GCMissionButton(frame,button) 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 + if GMF.MissionTab.MissionList.showInProgress and button.info.missionID==button.lastMissionID then +--[===[@non-debug@ + collectgarbage("step",50) +--@end-non-debug@]===] + return + end button.lastMissionID=button.info.missionID return self:RenderButton(button,rewards,numRewards) end @@ -3991,673 +3755,6 @@ function addon:RenderButton(button,rewards,numRewards) 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 - end - 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])) - 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@ - -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) - else - this.Text:SetText(value) - end - return value - 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 - 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 - 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 - 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) - 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 - 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) - 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() - --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 - 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 = '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 - 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 - 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=inTable(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 --[[ addon.oldSetUp=addon.SetUp function addon:ExperimentalSetUp() @@ -4839,9 +3936,9 @@ do v.quantity=v.quantity or 0 v.multiplier=v.multiplier or 1 --@debug@ --- xprint(format("Reward type: = %s",k)) +-- ns.xprint(format("Reward type: = %s",k)) -- for field,value in pairs(v) do --- xprint(format(" %s = %s",field,value),C.Silver()) +-- ns.xprint(format(" %s = %s",field,value),C.Silver()) -- end --@end-debug@ if v.currencyID then @@ -4879,9 +3976,7 @@ 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 @@ -4889,223 +3984,3 @@ function GarrisonMissionPage_Close(self) 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 - 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) - -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/GarrisonCommander.toc b/GarrisonCommander.toc index 896ea08..f381854 100644 --- a/GarrisonCommander.toc +++ b/GarrisonCommander.toc @@ -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..b036a73 --- /dev/null +++ b/Init.lua @@ -0,0 +1,100 @@ +local me, ns = ... +local _G=_G +local pp=print +--@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 addon=ns.addon --#addon +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(...) pp("|cffff9900DBG|r",...) end +ns.xdump=function(d,t) pp("|cffff9900DMP|r",t) DevTools_Dump(d) end +ns.xtrace=ns.trace +--@end-debug@ +local setmetatable=setmetatable +local next=next +local pairs=pairs +local wipe=wipe +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 diff --git a/MatchMaker.lua b/MatchMaker.lua new file mode 100644 index 0000000..e69de29 diff --git a/MissionCache.lua b/MissionCache.lua new file mode 100644 index 0000000..e69de29 diff --git a/MissionCompletion.lua b/MissionCompletion.lua new file mode 100644 index 0000000..e69de29 diff --git a/MissionControl.lua b/MissionControl.lua new file mode 100644 index 0000000..ba3144c --- /dev/null +++ b/MissionControl.lua @@ -0,0 +1,652 @@ +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 parties +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,mission in pairs(cache.missions) do + local discarded=false + repeat + if (mission.durationSeconds > settings.maxDuration * 3600 or mission.durationSeconds < settings.minDuration * 3600) then + ns.xprint(missionID,"discarded due to len",mission.durationSeconds /3600) + break + end -- Mission too long, out of here + if (mission.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 (mission[k] and mission[k]~=0) then -- we have a forbidden reward + discarded=true + break + end + 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@ + 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] + 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 + 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")) + this:Disable() + GMC.ml.widget:ClearChildren() + if (self:GetTotFollowers(AVAILABLE) == 0) then + self:Popup("All followers are busy",10) + this:Enable() + return + 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) + 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 + parties=self:GetParty() + 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 = '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 + 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 + 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=inTable(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..c47b693 --- /dev/null +++ b/PartyCache.lua @@ -0,0 +1,117 @@ +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={},perc=0,full=false}) 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=0,1,{},{} +function party:Open(missionID,followers) + maxFollowers=followers + ID=missionID + 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:FreeSlots() + return maxFollowers-#members +end +function party:IsEmpty() + return maxFollowers>0 and #members==0 +end + +function party:Dump() + for i=1,3 do + if (members[i]) then + ns.xprint(i,addon:GetFollowerData(members[i],'fullname')) + end + end +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 (rc and code) then + tinsert(members,followerID) + return true +--@debug@ + else + ns.xprint("Unable to add", G.GetFollowerName(followerID),"to",ID,code) +--@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 +function party:Close() + local perc=select(4,G.GetPartyMissionInfo(ID)) + 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) + return perc or 0 +end +function addon:GetParty(missionID) + if (missionID) then + return parties[missionID] + else + return parties + end +end \ No newline at end of file -- 1.7.9.5 From 3e7d82746cb8ada361b00e01de3184bb650351fd Mon Sep 17 00:00:00 2001 From: Alar of Daggerspine Date: Sat, 14 Feb 2015 00:58:25 +0100 Subject: [PATCH 2/7] Reimplemented mission cache to use less memory Signed-off-by: Alar of Daggerspine --- MissionCache.lua | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/MissionCache.lua b/MissionCache.lua index e69de29..b771bb2 100644 --- a/MissionCache.lua +++ b/MissionCache.lua @@ -0,0 +1,105 @@ +local me,ns=... +local addon=ns.addon --#addon +local holdEvents,releaseEvents=addon.holdEvents,addon.releaseEvents +local xprint=ns.xprint +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 tinser=tinsert +local GARRISON_CURRENCY=GARRISON_CURRENCY +local Mbase = GMF.MissionTab.MissionList +-- self=Mbase +-- C_Garrison.GetInProgressMissions(self.inProgressMissions); +-- C_Garrison.GetAvailableMissions(self.availableMissions); +local missionIndex={} +local AddExtraData +local function keyToIndex(key) + local idx=missionIndex[key] + if (idx and idx <= #Mbase.availableMissions) then + if Mbase.availableMissions[idx].missionID==key then + return idx + else + idx=nil + end + end + wipe(missionIndex) + for i=1,#Mbase.availableMissions do + missionIndex[Mbase.availableMissions[i].missionID]=i + if Mbase.availableMissions[i].missionID==key then + return i + end + end +end +function addon:GetMissionData(missionID,key) + local idx=keyToIndex(missionID) + xprint("Mission",missionID," is ",idx,"of",#Mbase.availableMissions) + local mission=Mbase.availableMissions[idx] + 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 < 100 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] + 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.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.slots={} + local slots=mission.slots + + for i=1,#mission.enemies do + local mechanics=mission.enemies[i].mechanics + for i,mechanic in pairs(mechanics) do + tinsert(slots,mechanic) + end + end + if (type) then + tinsert(slots,{name=TYPE,key=mission.type,icon=mission.typeIcon}) + end +end -- 1.7.9.5 From 8bb3aaae814e50a9a2fa65b1317a4549250b3bda Mon Sep 17 00:00:00 2001 From: Alar of Daggerspine Date: Sat, 14 Feb 2015 00:58:50 +0100 Subject: [PATCH 3/7] Moved mission completion routine to their own file Signed-off-by: Alar of Daggerspine --- MissionCompletion.lua | 221 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) diff --git a/MissionCompletion.lua b/MissionCompletion.lua index e69de29..13c3908 100644 --- a/MissionCompletion.lua +++ b/MissionCompletion.lua @@ -0,0 +1,221 @@ +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 +ns.missionautocompleting=false + +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 + 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) + 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 + 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@ +-- ns.xprint(format("Reward type: = %s",k)) +-- for field,value in pairs(v) do +-- ns.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) + else + -- Other currency reward + report:AddIconText(v.icon,GetCurrencyLink(v.currencyID),v.quantity ) + end + elseif v.itemID then + -- Item reward + report:AddItem(v.itemID,1) + currentMission.items[v.itemID]=nil + else + -- Follower XP reward + --report:AddIconText(v.icon,v.name) + 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 -- 1.7.9.5 From defa8efa997f02780dcffbc285a2115d97f47c60 Mon Sep 17 00:00:00 2001 From: Alar of Daggerspine Date: Sat, 14 Feb 2015 00:59:13 +0100 Subject: [PATCH 4/7] Moved temporary party management to its own file Signed-off-by: Alar of Daggerspine --- PartyCache.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/PartyCache.lua b/PartyCache.lua index c47b693..2b78b94 100644 --- a/PartyCache.lua +++ b/PartyCache.lua @@ -55,6 +55,7 @@ function party:Dump() ns.xprint(i,addon:GetFollowerData(members[i],'fullname')) end end + ns.xprint(G.GetPartyMissionInfo(ID)) end function party:AddFollower(followerID) -- 1.7.9.5 From 763218c3396a7d2283775d01843d70c5ad64c30b Mon Sep 17 00:00:00 2001 From: Alar of Daggerspine Date: Sat, 14 Feb 2015 00:59:42 +0100 Subject: [PATCH 5/7] Removed routinws which are now in their file Signed-off-by: Alar of Daggerspine --- GarrisonCommander.lua | 236 +++---------------------------------------------- 1 file changed, 10 insertions(+), 226 deletions(-) diff --git a/GarrisonCommander.lua b/GarrisonCommander.lua index 34d14fc..127d502 100644 --- a/GarrisonCommander.lua +++ b/GarrisonCommander.lua @@ -5,6 +5,7 @@ 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 @@ -64,7 +65,6 @@ end local parties -local missionautocompleting local lastTab=1 local new, del, copy =ns.new,ns.del,ns.copy @@ -284,7 +284,7 @@ end local origGarrison_SortMissions function addon.Garrison_SortMissions_Chance(missionsList) - + xprint("Sorting on chance") local comparison do function comparison(mission1, mission2) @@ -1001,13 +1001,6 @@ function addon:HookedGarrisonMissionButton_AddThreatsToTooltip(missionID) 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 local f=GarrisonMissionListTooltipThreatsFrame if (not f.Env) then f.Env=CreateFrame("Frame",nil,f,"GarrisonAbilityCounterTemplate") @@ -1098,7 +1091,7 @@ function addon:RefreshMission(missionID) end end -function addon:BuildMissionsCache(fc,mm,OnEvent) +function addon:BuildMissionsCacheRem(fc,mm,OnEvent) --cache.missions --@debug@ local start=GetTime() @@ -1229,7 +1222,7 @@ GetBasicInfo Table Format={ } --]] -function addon:BuildMissionCache(id,data) +function addon:BuildMissionCacheRem(id,data) local mission=cache.missions[id] if (not mission) then --@dedbug@ @@ -1441,7 +1434,7 @@ function addon:EventGARRISON_MISSION_STARTED(event,missionID,...) dbcache.seen[missionID]=nil counters[missionID]=nil parties[missionID]=nil - self:BuildMissionsCache(true,true) + --self:BuildMissionsCache(true,true) self:RefreshFollowerStatus() end --- @@ -1532,8 +1525,7 @@ function addon:Clock() dbgFrame=AceGUI:Create("Window") dbgFrame:SetTitle("GC Performance") dbgFrame:SetPoint("LEFT") - dbgFrame:SetHeight(120) - dbgFrame:SetWidth(350) + dbgFrame:SetWidth(300) dbgFrame:SetLayout("flow") dbgFrame.Text=AceGUI:Create("Label") dbgFrame.Text:SetColor(1,1,0) @@ -1649,7 +1641,7 @@ do end end function addon:ShowMissionControl() - if missionautocompleting then return end + if ns.missionautocompleting then return end if (not GMC:IsShown()) then GarrisonMissionFrame_SelectTab(999) GMF.FollowerTab:Hide() @@ -2911,8 +2903,8 @@ function addon:StartUp(...) self:ScheduleRepeatingTimer("Clock",1) --@end-debug@ end - self:BuildMissionsCache(true,true) - self:BuildRunningMissionsCache() + --self:BuildMissionsCache(true,true) + --self:BuildRunningMissionsCache() self:RefreshFollowerStatus() self:Trigger("MSORT") self:Trigger("CKMP") @@ -3117,7 +3109,7 @@ function addon:GetFollowerData(key,subkey,refresh) return nil end end -function addon:GetMissionData(missionID,subkey) +function addon:GetMissionDataRem(missionID,subkey) local missionCache=cache.missions[missionID] if (not missionCache) then --@debug@ @@ -3762,214 +3754,6 @@ 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 - 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@ --- ns.xprint(format("Reward type: = %s",k)) --- for field,value in pairs(v) do --- ns.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) - else - -- Other currency reward - report:AddIconText(v.icon,GetCurrencyLink(v.currencyID),v.quantity ) - end - elseif v.itemID then - -- Item reward - report:AddItem(v.itemID,1) - currentMission.items[v.itemID]=nil - else - -- Follower XP reward - --report:AddIconText(v.icon,v.name) - 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) -- 1.7.9.5 From 25b88502f0b4d18a82908aaf01132b1ca8427aa9 Mon Sep 17 00:00:00 2001 From: Alar of Daggerspine Date: Sat, 14 Feb 2015 00:59:54 +0100 Subject: [PATCH 6/7] New matchmaker wip Signed-off-by: Alar of Daggerspine --- MatchMaker.lua | 451 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 451 insertions(+) diff --git a/MatchMaker.lua b/MatchMaker.lua index e69de29..1b73738 100644 --- a/MatchMaker.lua +++ b/MatchMaker.lua @@ -0,0 +1,451 @@ +local me,ns=... +local xprint=ns.xprint +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 dbg +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 + xprint("Current",fid1,n[f1.followerID]," vs Candidate",fid2,n[f2.followerID]) + end + if (P:IsIn(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 +local function filter() + if (missionCounters) then + for i=1,#missionCounters do + local followerID=missionCounters[i].followerID + if (not followerID) then + if (dbg) then xprint("Trying to use [",followerID,"]") end + else + if (self:IsIgnored(followerID,missionID)) then + if (dbg) then xprint("Skipped",n[followerID],"due to ignored" ) end + P:Ignore(followerID,true) + elseif not self:IsFollowerAvailableForMission(followerID,skipBusy) then + if (dbg) then xprint("Skipped",n[followerID],"due to busy" ) end + P:Ignore(followerID) + elseif (skipMaxed and mission.xpOnly and self:GetFollowerData(followerID,'maxed')) then + if (dbg) then print("Skipped",n[followerID],"due to maxed" ) end + P:Ignore(followerID,true) + end + end + end + end +end +function addon:MissionScore(mission) + local totalTimeString, totalTimeSeconds, isMissionTimeImproved, successChance, partyBuffs, isEnvMechanicCountered, xpBonus, materialMultiplier = G.GetPartyMissionInfo(mission.missionID) + return format("%03d%01d%01d%01d",successChance,isEnvMechanicCountered and 1 or 0,materialMultiplier*mission.resources,#partyBuffs) +end +function addon:FollowerScore(mission) + local totalTimeString, totalTimeSeconds, isMissionTimeImproved, successChance, partyBuffs, isEnvMechanicCountered, xpBonus, materialMultiplier = G.GetPartyMissionInfo(mission.missionID) + return format("%03d%01d%02d%01d",successChance,isEnvMechanicCountered and 1 or 0,(mission.resources * (materialMultiplier-1)) , (isMissionTimeImproved and 1 or 0)) +end +local filters={} +function filters.Xp(data) + for k,_ in pairs(data) do + if (addon:GetFollowerData(k,'maxed')) then + data[k]=nil + end + end +end +function addon:MatchMakerEpic(missionID,mission,party,filter) + if (GMFRewardSplash:IsShown()) then return end + if (not mission) then mission=self:GetMissionData(missionID) end + if (not party) then party=self:GetParty(missionID) end + local skipBusy=self:GetBoolean("IGM") + local skipMaxed=self:GetBoolean("IGP") + local scores=new() + local traits=new() + dbg=missionID==(tonumber(_G.MW) or 0) + if (dbg) then xprint(C("Matchmaking mission","Red"),missionID,mission.name) end + local buffed=G.GetBuffedFollowersForMission(missionID) + if (filter) then + filters[filter](buffed) + end + 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("%s|%s",self:FollowerScore(mission),followerID)) + if (mission.numFollowers>1) then + for k,d in pairs(G.GetFollowersTraitsForMission(missionID)) do + if not buffed[k] then + traits[k]=d + end + end + end + P:RemoveFollower(followerID) + end + if (filter) then + filters[filter](traits) + end + for followerID,_ in pairs(traits) do + P:AddFollower(followerID) + tinsert(scores,format("%s|%s",self:FollowerScore(mission),followerID)) + xprint(G.GetFollowerName(followerID),scores[#scores]) + P:RemoveFollower(followerID) + end + table.sort(scores) + for i=#scores,1,-1 do + local score,followerID=strsplit('|',scores[i]) + xprint(score,G.GetFollowerName(followerID)) + end + local missionScore=self:MissionScore(mission) + for p=1,mission.numFollowers do + xprint("Slot",p) + local delete=0 + local candidate=nil + local candidateScore=nil + for i=#scores,1,-1 do + local score,followerID=strsplit('|',scores[i]) + P:AddFollower(followerID) + candidateScore=self:MissionScore(mission) + xprint(G.GetFollowerName(followerID),candidateScore,"pos",i) + if (p>1) then + if (missionScore0) then + xprint("scores contiene",#scores) + xprint("rimuovo",delete) + tremove(scores,delete) + xprint("scores contiene",#scores) + end + if candidate then + P:AddFollower(candidate) + xprint("Adding",G.GetFollowerName(candidate),candidateScore) + end + if P:FreeSlots()==0 then break end + end + P:Dump() + xprint("Final score",self:MissionScore(mission)) + P:StoreFollowers(party.members) + party.full= P:FreeSlots()==0 + party.perc=P:Close() +end + +function addon:MatchMakerOld(missionID,mission,party,fromMissionControl) + if (GMFRewardSplash:IsShown()) then return end + if (not mission) then mission=self:GetMissionData(missionID) end + if (not party) then party=self:GetParty(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] + P:Open(missionID,mission.numFollowers) + -- Preloading skipped ones in party table. + if (dbg) then xprint(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 xprint("Trying to use [",followerID,"]") end + else + if (self:IsIgnored(followerID,missionID)) then + if (dbg) then xprint("Skipped",n[followerID],"due to ignored" ) end + P:Ignore(followerID,true) + elseif not self:IsFollowerAvailableForMission(followerID,skipBusy) then + if (dbg) then xprint("Skipped",n[followerID],"due to busy" ) end + P:Ignore(followerID) + elseif (skipMaxed and mission.xpOnly and self:GetFollowerData(followerID,'maxed')) then + if (dbg) then print("Skipped",n[followerID],"due to maxed" ) end + P:Ignore(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 xprint("Checking ",threat) end + for i=1,#candidates do + local followerID=missionCounters[candidates[i]].followerID + if P:IsIn(followerID) then + if dbg then xprint("Countered by",n[followerID],"which is already in party") end + choosen=nil + break + end + if followerID then + if(not P:IsIgnored(followerID)) then + choosen=best(choosen,candidates[i],missionCounters,mission) + if (dbg) then xprint("Taken",n[missionCounters[choosen].followerID]) end + else + if (dbg) then xprint("Party Ignored",n[followerID]) end + end + end + end + if (choosen) then + if dbg then xprint("Adding to party",n[missionCounters[choosen].followerID]," still need ",P:FreeSlots()) end + P:AddFollower(missionCounters[choosen].followerID) + end + if (P:FreeSlots()==0) then + break + end + end + else + ns.xprint("Mission",missionID,"has no slots????") + end + if P:FreeSlots() > 0 then self:AddTraitsToParty(missionID,mission) end + end + if P:FreeSlots() > 0 then self:CompleteParty(missionID,mission,skipBusy,skipMaxed) end + if (not fromMissionControl and not P:IsEmpty()) then + if P:FreeSlots() > 0 then self:CompleteParty(missionID,mission,skipBusy,false) end + end + P:StoreFollowers(party.members) + party.full= P:FreeSlots()==0 + party.perc=P:Close() +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 P:IsIgnored(follower.followerID) and not P:IsIn(follower.followerID)) then + if mission.resources > 0 and follower.name==scavengerTrait then + P:AddFollower(follower.followerID) + elseif mission.xpOnly and (follower.name==extraTrainingTrait or follower.name==hearthStoneProTrait) then + P:AddFollower(follower.followerID) + elseif mission.durationSeconds > GARRISON_LONG_MISSION_TIME and follower.name==epicMountTrait then + P:AddFollower(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") + P:Dump() + end + for x=1,P:FreeSlots() do + local candidate + local candidatePerc=perc + if (dbg) then print(" Perc to beat",perc, "Going for spot ",P:FreeSlots()) 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 P:IsIgnored(followerID) then + if (dbg) then print("Skipped due to party ignored") end + break + end + if P:IsIn(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 rank=data.rank + local quality=data.quality + perc=tonumber(perc) or 0 + if ((perc) <100) then + P:AddFollower(followerID) + local newperc=select(4,G.GetPartyMissionInfo(missionID)) + newperc=tonumber(newperc) or 0 + candidatePerc=tonumber(candidatePerc) or 0 + P:RemoveFollower(followerID) + if (newperc > candidatePerc) then + candidatePerc=newperc + candidate=followerID + candidateRank=rank + candidateQuality=quality + 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(rank Date: Tue, 24 Feb 2015 16:34:01 +0100 Subject: [PATCH 7/7] 6.1.0 update Signed-off-by: Alar of Daggerspine --- Debug.lua | 7 +- FollowerCache.lua | 133 ++ GarrisonCommander-Broker/ldb.lua | 8 +- GarrisonCommander.lua | 2444 ++++++++++++------------------ GarrisonCommander.toc | 2 +- Init.lua | 62 +- MatchMaker.lua | 475 +++--- MissionCache.lua | 100 +- MissionCompletion.lua | 230 ++- MissionControl.lua | 102 +- PartyCache.lua | 169 ++- doc.txt | 151 ++ libs/LibDeformat-3.0/LibDeformat-3.0.lua | 4 +- 13 files changed, 1941 insertions(+), 1946 deletions(-) diff --git a/Debug.lua b/Debug.lua index 4afd57c..b8c6587 100644 --- a/Debug.lua +++ b/Debug.lua @@ -1,3 +1,4 @@ +if true then return end --@do-not-package@ local me, ns = ... local addon=ns.addon --#addon @@ -89,9 +90,9 @@ function addon:GetScroller(title,type,h,w) return scroll end function addon:AddRow(obj,text,...) ---@debug@ +--[===[@debug@ assert(obj) ---@end-debug@ +--@end-debug@]===] if (obj) then local l=AceGUI:Create("Label") l:SetText(text) @@ -172,7 +173,7 @@ 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')) diff --git a/FollowerCache.lua b/FollowerCache.lua index e69de29..ff9f9df 100644 --- a/FollowerCache.lua +++ 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/GarrisonCommander-Broker/ldb.lua b/GarrisonCommander-Broker/ldb.lua index 46b94e1..824735a 100644 --- a/GarrisonCommander-Broker/ldb.lua +++ b/GarrisonCommander-Broker/ldb.lua @@ -1,8 +1,8 @@ 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 @@ -103,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 127d502..09a1795 100644 --- a/GarrisonCommander.lua +++ b/GarrisonCommander.lua @@ -24,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 @@ -35,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", @@ -97,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 @@ -117,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 @@ -176,13 +181,6 @@ 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 @@ -269,99 +267,109 @@ 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() -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) - xprint("Sorting on chance") - 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 +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 + 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 - table.sort(missionsList, comparison); 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 +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 - table.sort(missionsList, comparison); 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 +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 - table.sort(missionsList, comparison); 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 +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 +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 - table.sort(missionsList, comparison); +end +function addon.Garrison_SortMissions_Chance(missionsList) + xprint("Sorting on chance") + addon:OnAllMissions(function(missionID) addon:MatchMaker(missionID) end) + table.sort(missionsList, sorters.Chance); +end +function addon.Garrison_SortMissions_Age(missionsList) + xprint("Sorting on age") + addon:OnAllMissions(function(missionID) addon:MatchMaker(missionID) end) + table.sort(missionsList, sorters.Age); +end +function addon.Garrison_SortMissions_Followers(missionsList) + xprint("Sorting on followers") + addon:OnAllMissions(function(missionID) addon:MatchMaker(missionID) end) + table.sort(missionsList, sorters.Followers); +end +function addon.Garrison_SortMissions_Xp(missionsList) + 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@ +--[===[@debug@ ns.xprint("OnInitialized") self.evdebug=CreateFrame("Frame") self.evdebug:SetScript("OnEvent",function(...) return print('|cffff2020event|r',...) end) ---@end-debug@ - parties=self:GetParty() +--@end-debug@]===] + --parties=self:GetParty() for _,b in ipairs(GMFMissionsListScrollFrame.buttons) do local scale=0.8 local f,h,s=b.Title:GetFont() @@ -383,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 @@ -428,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 @@ -444,7 +450,7 @@ function addon:ApplyCKMP(value) MasterPlanMissionList:Show() end end - self:RefreshMission() + self:RefreshMissions() end function addon:ApplyDBG(value) dbg=value @@ -467,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 @@ -478,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 @@ -491,458 +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="", - party1="" - }, - 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}) - 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 - 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 (P:IsIn(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=self:GetParty(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] - P:Open(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 - P:Ignore(followerID,true) - elseif not self:IsFollowerAvailableForMission(followerID,skipBusy) then - if (dbg) then print("Skipped",n[followerID],"due to busy" ) end - P:Ignore(followerID) - elseif (skipMaxed and mission.xpOnly and self:GetFollowerData(followerID,'maxed')) then - if (dbg) then print("Skipped",n[followerID],"due to maxed" ) end - P:Ignore(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 P:IsIn(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 P:IsIgnored(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 dbg then print("Adding to party",n[missionCounters[choosen].followerID]," still need ",P:FreeSlots()) end - P:AddFollower(missionCounters[choosen].followerID) - end - if (P:FreeSlots()==0) then - break - end - end - else - ns.xprint("Mission",missionID,"has no slots????") - end - if P:FreeSlots() > 0 then self:AddTraitsToParty(missionID,mission) end - end - if P:FreeSlots() > 0 then self:CompleteParty(missionID,mission,skipBusy,skipMaxed) end - if (not fromMissionControl and not P:IsEmpty()) then - if P:FreeSlots() > 0 then self:CompleteParty(missionID,mission,skipBusy,false) end - end - P:StoreFollowers(party.members) - party.full= P:FreeSlots()==0 - party.perc=P:Close() -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 P:IsIgnored(follower.followerID) and not P:IsIn(follower.followerID)) then - if mission.resources > 0 and follower.name==scavengerTrait then - P:AddFollower(follower.followerID) - elseif mission.xpOnly and (follower.name==extraTrainingTrait or follower.name==hearthStoneProTrait) then - P:AddFollower(follower.followerID) - elseif mission.durationSeconds > GARRISON_LONG_MISSION_TIME and follower.name==epicMountTrait then - P:AddFollower(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") - P:Dump() - end - for x=1,P:FreeSlots() do - local candidate - local candidatePerc=perc - if (dbg) then print(" Perc to beat",perc, "Going for spot ",P:FreeSlots()) 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 P:IsIgnored(followerID) then - if (dbg) then print("Skipped due to party ignored") end - break - end - if P:IsIn(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 rank=data.rank - local quality=data.quality - perc=tonumber(perc) or 0 - if ((perc) <100) then - P:AddFollower(followerID) - local newperc=select(4,G.GetPartyMissionInfo(missionID)) - newperc=tonumber(newperc) or 0 - candidatePerc=tonumber(candidatePerc) or 0 - P:RemoveFollower(followerID) - if (newperc > candidatePerc) then - candidatePerc=newperc - candidate=followerID - candidateRank=rank - candidateQuality=quality - 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(rank1 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 @@ -1081,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:BuildMissionsCacheRem(fc,mm,OnEvent) ---cache.missions ---@debug@ - local start=GetTime() - ns.xprint("Start Full Cache Rebuild") ---@end-debug@ - local t=new() - self: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 - self:releaseEvents() - del(t) - collectgarbage("step",10) ---@debug@ - ns.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 @@ -1153,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="", 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:BuildMissionCacheRem(id,data) - local mission=cache.missions[id] - if (not mission) then ---@dedbug@ - ns.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@ - ns.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["*"]={} @@ -1324,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 } } }, @@ -1366,15 +736,15 @@ end -- Fires after GarrisonMissionFrame OnShow. Pretty useless function addon:EventGARRISON_MISSION_NPC_OPENED(event,...) ---@debug@ +--[===[@debug@ ns.xprint(event,...) ---@end-debug@ +--@end-debug@]===] if (GCF) then GCF:Show() end end function addon:EventGARRISON_MISSION_NPC_CLOSED(event,...) ---@debug@ +--[===[@debug@ ns.xprint(event,...) ---@end-debug@ +--@end-debug@]===] if (GCF) then self:RemoveMenu() GCF:Hide() @@ -1386,15 +756,11 @@ function addon:EventGARRISON_MISSION_LIST_UPDATE(event) 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 --- @@ -1403,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@ +--[===[@debug@ ns.xprint(event,missionID,...) ---@end-debug@ +--@end-debug@]===] -- running={ -- ["*"]={ -- followers={}, @@ -1413,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] @@ -1430,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 --- @@ -1447,23 +813,19 @@ end -- function addon:EventGARRISON_MISSION_FINISHED(event,missionID,...) ---@debug@ +--[===[@debug@ ns.xprint(event,missionID,...) ns.xdump(G.GetPartyMissionInfo(missionID)) ---@end-debug@ +--@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) - ns.xprint("Follower cache cleaned") end function addon:EventGARRISON_MISSION_BONUS_ROLL_LOOT(event,missionID,completed,success) ---@debug@ +--[===[@debug@ ns.xprint('evt',event,missionID,completed,success) ---@end-debug@ +--@end-debug@]===] self:RefreshFollowerStatus() end --- @@ -1478,23 +840,13 @@ end --GARRISON_MISSION_BONUS_ROLL_LOOY missionID nil -- function addon:EventGARRISON_MISSION_COMPLETE_RESPONSE(event,missionID,completed,rewards) ---@debug@ +--[===[@debug@ ns.xprint('evt',event,missionID,completed,rewards) ---@end-debug@ +--@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 @@ -1508,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 @@ -1520,34 +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:SetWidth(300) - dbgFrame:SetLayout("flow") - dbgFrame.Text=AceGUI:Create("Label") - dbgFrame.Text:SetColor(1,1,0) - dbgFrame.Text:SetFullWidth(true) - dbgFrame.Text1=AceGUI:Create("Label") - dbgFrame.Text1:SetColor(1,1,0) - dbgFrame.Text1:SetFullWidth(true) - dbgFrame:AddChild(dbgFrame.Text) - dbgFrame:AddChild(dbgFrame.Text1) - end - local h,m=GetGameTime() - if (m~=lastmin) then - lastmin=m - end - UpdateAddOnMemoryUsage() - dbgFrame.Text:SetText(format("Garrison Commander Mem %4.3fMB ", - GetAddOnMemoryUsage("GarrisonCommander")/1024) - ) - dbgFrame.Text1:SetText(format("Garrison Broker Mem %4.3fMB ", - GetAddOnMemoryUsage("GarrisonCommander-Broker")/1024) - ) ---@end-debug@ dbcache.lastseen=time() if (not MP or MPGoodGuy) then return end MPShown=not self:GetBoolean("CKMP") @@ -1569,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 @@ -1584,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 ) @@ -1592,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) @@ -1614,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 @@ -1641,7 +962,9 @@ do end end function addon:ShowMissionControl() - if ns.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() @@ -1771,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] - ns.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() @@ -1894,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 @@ -2012,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" ) @@ -2095,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 @@ -2210,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) @@ -2270,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 @@ -2304,9 +1521,9 @@ function addon:Options() end function addon:ScriptTrace(hook,frame,...) ---@debug@ +--[===[@debug@ ns.xprint("Triggered " .. C(hook,"red").." script on",C(frame,"Azure"),...) ---@end-debug@ +--@end-debug@]===] end function addon:IsProgressMissionPage() return GMF:IsShown() and GMF.MissionTab and GMF.MissionTab.MissionList.showInProgress @@ -2319,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() @@ -2347,7 +1564,7 @@ do end end function addon:HookedGarrisonMissionFrame_HideCompleteMissions() - self:BuildMissionsCache(true,true) + xprint("Complete missions closed") end @@ -2388,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 @@ -2406,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)) @@ -2417,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); @@ -2468,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(); @@ -2510,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) @@ -2589,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") @@ -2625,28 +1791,26 @@ 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) + function addon:RenderFollowerPageMissionListOld(frame,followerID,force) ns.xprint("hook",followerID,force) if (followerID==lastFollowerID and not force) then return end lastFollowerID=followerID @@ -2708,10 +1872,10 @@ do for z = 1,#partyIndex do local missionID=partyIndex[z] if not(tonumber(missionID)) then - --@debug@ + --[===[@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 @@ -2775,9 +1939,10 @@ end --- --Initial one time setup function addon:SetUp(...) ---@debug@ - ns.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) @@ -2790,7 +1955,7 @@ function addon:SetUp(...) self:CheckGMM() self:Options() self:GenerateMissionsWidgets() - GMC=self:GMCBuildPanel(bigscreen) + GMC=self:GMCBuildPanel(ns.bigscreen) local tabMC=CreateFrame("CheckButton",nil,GMF,"SpellBookSkillLineTabTemplate") GMF.tabMC=tabMC tabMC.tooltip="Open Garrison Commander Mission Control" @@ -2825,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 @@ -2833,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) @@ -2863,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@ - ns.xprint("Startup") ---@end-debug@ +--[===[@debug@ + ns.dprint("Startup") +--@end-debug@]===] self:GrowPanel() self:Unhook(GMF,"OnShow") if (self:GetBoolean("PIN")) then @@ -2875,10 +2043,9 @@ 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 + if (ns.bigscreen) then self:SafeSecureHook("GarrisonFollowerPage_ShowFollower")--,function(...) ns.xprint("GarrisonFollowerPage_ShowFollower",...) end) self:SafeSecureHook("GarrisonFollowerTooltipTemplate_SetGarrisonFollower") end @@ -2898,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 @@ -2934,29 +2099,29 @@ function addon:PermanentEvents() end function addon:checkMethod(method,hook) if (type(self[method])=="function") then ---@debug@ +--[===[@debug@ --ns.xprint("Hooking ",hook,"to self:" .. method) ---@end-debug@ +--@end-debug@]===] return true ---@debug@ +--[===[@debug@ else --ns.xprint("Hooking ",hook,"to print") ---@end-debug@ +--@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,ns.xprint) ---@end-debug@ +--@end-debug@]===] end end function addon:SafeSecureHook(tobehooked,method) @@ -2964,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(...) ns.xprint(hooked,...) end) end ---@end-debug@ +--@end-debug@]===] end end function addon:SafeHookScript(frame,hook,method,postHook) @@ -3011,9 +2176,9 @@ function addon:CleanUp() GarrisonFollowerTooltip.fs:Hide() end --collectgarbage("collect") ---@debug@ +--[===[@debug@ ns.xprint("Cleaning up") ---@end-debug@ +--@end-debug@]===] end function addon:EventGARRISON_FOLLOWER_XP_CHANGED(event,followerID,iLevel,xp,level,quality) local i=followersCacheIndex[followerID] @@ -3031,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:GetMissionDataRem(missionID,subkey) - local missionCache=cache.missions[missionID] - if (not missionCache) then ---@debug@ - ns.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 self:GMCBusy(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 @@ -3160,14 +2252,12 @@ function addon:FillMissionPage(missionInfo) if( IsControlKeyDown()) then ns.xprint("Shift key, ignoring mission prefill") return end if (self:GetBoolean("NOFILL")) then return end local missionID=missionInfo.missionID ---@debug@ +--[===[@debug@ ns.xprint("UpdateMissionPage for",missionID,missionInfo.name,missionInfo.numFollowers) ---@end-debug@ - --ns.xdump(missionInfo) - --self:BuildMissionData(missionInfo.missionID.missionInfo) +--@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 @@ -3176,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@ +--[===[@debug@ ns.xprint(followerID,self:GetFollowerData(followerID,"name"),"was already on mission") ---@end-debug@ +--@end-debug@]===] self:RemoveFromAllMissions(followerID) GarrisonMissionPage_AddFollower(followerID) else @@ -3192,7 +2282,11 @@ function addon:FillMissionPage(missionInfo) end end end - GarrisonMissionPage_UpdateMissionForParty() + if ns.toc>=60100 then + GarrisonMissionPage_UpdateParty() + else + GarrisonMissionPage_UpdateMissionForParty() + end self:releaseEvents() end local firstcall=true @@ -3202,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") @@ -3254,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 @@ -3284,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) @@ -3314,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() @@ -3338,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 @@ -3354,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 @@ -3381,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] @@ -3477,19 +2490,8 @@ 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 @@ -3559,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 @@ -3567,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) @@ -3588,9 +2590,9 @@ function addon:OnClick_GarrisonMissionButton(tab,button) return end if (type(tab.info)~="table") then return end ---@debug@ +--[===[@debug@ ns.xprint("Clicked GarrisonMissionButton") ---@end-debug@ +--@end-debug@]===] if (tab.fromFollowerPage) then if (#tab.info.followers>0) then return @@ -3609,78 +2611,493 @@ 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 +--[[ +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 + portraitFrame.Level:SetText(followerInfo.level); + end + if ( followerInfo.displayID ) then + GarrisonFollowerPortrait_Set(portraitFrame.Portrait, followerInfo.portraitIconID); + end +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 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 + 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.currencyID = reward.currencyID; + Reward.Quantity:SetText(reward.quantity); + Reward.Quantity:Show(); + Reward.Quantity:SetTextColor(C:Gold()) + end + 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 + Reward:Show(); + index = index + 1; + end + end + + for i = (numRewards + 1), #self.Rewards do + self.Rewards[i]:Hide(); + end +end +do + 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 + collectgarbage("step",100) + lastcall=tick + return + end + table.sort(self.inProgressMissions,sorters.EndTime) + missions = self.inProgressMissions; + else + progressing=false + missions = self.availableMissions; + end + 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@ - collectgarbage("step",50) + return orig.GarrisonMissionButton_OnEnter(self,button) --@end-non-debug@]===] - return + 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 + if (self.info == nil) then + return; end - button.lastMissionID=button.info.missionID - return self:RenderButton(button,rewards,numRewards) + + 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 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@ +---@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: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: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 + if ( mission.locPrefix ) then + button.LocBG:Show(); + button.LocBG:SetAtlas(mission.locPrefix.."-List"); + else + button.LocBG:Hide(); + end + 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 + 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 + button.ItemLevel:Hide(); + end + if ( showingItemLevel and mission.isRare ) then + button.Level:SetPoint("CENTER", button, "TOPLEFT", 40, -22); + else + button.Level:SetPoint("CENTER", button, "TOPLEFT", 40, -36); + 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 - local missionID=button.info.missionID 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 - 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() - else - button.xp:Hide() + 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 - --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); + 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, 25); - button.Title:SetWidth(tw - offset); + 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 + button.MissionType:SetAtlas(mission.typeAtlas); +end +if ns.toc < 60100 then +function GarrisonMissionButton_CheckTooltipThreat() + --print("checktooltip placeholder") +end +end +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 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 - 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) + 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 + 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 + button.Env.Border:SetVertexColor(C.Red()) + end + 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 + 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") @@ -3689,45 +3106,17 @@ function addon:RenderButton(button,rewards,numRewards) 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) + 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",function(...) addon:ClonedGarrisonMissionMechanic_OnEnter(missionID,...) end) + th:SetScript("OnEnter",addon.ClonedGarrisonMissionMechanic_OnEnter) th:SetScript("OnLeave",function() GameTooltip:Hide() end) + threatIndex=threatIndex+1 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) - else - Reward.Quantity:SetTextColor(c.r,c.g,c.b) - end - Reward.Quantity:Show() - end - index=index+1 end end else @@ -3738,33 +3127,108 @@ function addon:RenderButton(button,rewards,numRewards) button.GcThreats[i]:Hide() end end - if (button.fromFollowerPage) then - return +end +function addon:CalculateAge(missionID) + return "Available in 6.1" +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 - if (not button.gcPANEL) then - self:BuildExtraButton(button) + 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 + 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 - return self:RenderExtraButton(button,numRewards) end - ---[[ -addon.oldSetUp=addon.SetUp -function addon:ExperimentalSetUp() - +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 + 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 + 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 + 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 end -addon.SetUp=addon.ExperimentalSetUp ---]] --- Need to overrid in order to stop events while cleaning missions -function GarrisonMissionPage_Close(self) +--hooksecurefunc("GarrisonMissionList_Update",function(...)print("Original GarrisonMissionList_Update",...)end) +override("GarrisonMissionPage_Close") +override("GarrisonMissionList_Update") +override("GarrisonMissionButton_SetRewards") +override("GarrisonMissionButton_OnEnter") +override("GarrisonMissionPageFollowerFrame_OnEnter") - GarrisonMissionFrame.MissionTab.MissionPage:Hide(); - GarrisonMissionFrame.MissionTab.MissionList:Show(); - GarrisonMissionPage_ClearParty(); - GarrisonMissionFrame.followerCounters = nil; - GarrisonMissionFrame.MissionTab.MissionPage.missionInfo = nil; - if (lastTab) then - GarrisonMissionFrame_SelectTab(lastTab) - end +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 -GMF.MissionTab.MissionPage.CloseButton:SetScript("OnClick",GarrisonMissionPage_Close) diff --git a/GarrisonCommander.toc b/GarrisonCommander.toc index f381854..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 diff --git a/Init.lua b/Init.lua index b036a73..99cb6d9 100644 --- a/Init.lua +++ b/Init.lua @@ -1,11 +1,26 @@ local me, ns = ... local _G=_G local pp=print ---@debug@ +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@ +--@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() @@ -16,32 +31,28 @@ ns.trace=ns.addon:Wrap("Trace") ns.xprint=function() end ns.xdump=function() end ns.xtrace=function() end ---@debug@ -ns.xprint=function(...) pp("|cffff9900DBG|r",...) end -ns.xdump=function(d,t) pp("|cffff9900DMP|r",t) DevTools_Dump(d) end -ns.xtrace=ns.trace ---@end-debug@ -local setmetatable=setmetatable -local next=next -local pairs=pairs -local wipe=wipe +--[===[@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@ + --[===[@debug@ local newcount, delcount,createdcount,cached = 0,0,0 - --@end-debug@ + --@end-debug@]===] local pool = setmetatable({},{__mode="k"}) function ns.new() - --@debug@ + --[===[@debug@ newcount = newcount + 1 - --@end-debug@ + --@end-debug@]===] local t = next(pool) if t then pool[t] = nil return t else - --@debug@ + --[===[@debug@ createdcount = createdcount + 1 - --@end-debug@ + --@end-debug@]===] return {} end end @@ -53,13 +64,13 @@ do return c end function ns.del(t) - --@debug@ + --[===[@debug@ delcount = delcount + 1 - --@end-debug@ + --@end-debug@]===] wipe(t) pool[t] = true end - --@debug@ + --[===[@debug@ function cached() local n = 0 for k in pairs(pool) do @@ -73,7 +84,7 @@ do ns.print("Released:",delcount) ns.print("Cached:",cached()) end - --@end-debug@ + --@end-debug@]===] end local stacklevel=0 @@ -98,3 +109,12 @@ function addon:releaseEvents() 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 index 1b73738..0d8f7dc 100644 --- a/MatchMaker.lua +++ b/MatchMaker.lua @@ -1,5 +1,4 @@ local me,ns=... -local xprint=ns.xprint local pp=print local addon=ns.addon --#addon local C=ns.C @@ -15,335 +14,224 @@ local format=format local tonumber=tonumber local tinsert=tinsert local tremove=tremove -local dbg +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 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 - xprint("Current",fid1,n[f1.followerID]," vs Candidate",fid2,n[f2.followerID]) +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 - if (P:IsIn(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 + + 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 - if (f2.quality < f1.quality or f2.rank < f1.rank) then return fid2 end end - return fid1 + 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 function filter() - if (missionCounters) then - for i=1,#missionCounters do - local followerID=missionCounters[i].followerID - if (not followerID) then - if (dbg) then xprint("Trying to use [",followerID,"]") end - else - if (self:IsIgnored(followerID,missionID)) then - if (dbg) then xprint("Skipped",n[followerID],"due to ignored" ) end - P:Ignore(followerID,true) - elseif not self:IsFollowerAvailableForMission(followerID,skipBusy) then - if (dbg) then xprint("Skipped",n[followerID],"due to busy" ) end - P:Ignore(followerID) - elseif (skipMaxed and mission.xpOnly and self:GetFollowerData(followerID,'maxed')) then - if (dbg) then print("Skipped",n[followerID],"due to maxed" ) end - P:Ignore(followerID,true) + +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 - end -end -function addon:MissionScore(mission) - local totalTimeString, totalTimeSeconds, isMissionTimeImproved, successChance, partyBuffs, isEnvMechanicCountered, xpBonus, materialMultiplier = G.GetPartyMissionInfo(mission.missionID) - return format("%03d%01d%01d%01d",successChance,isEnvMechanicCountered and 1 or 0,materialMultiplier*mission.resources,#partyBuffs) -end -function addon:FollowerScore(mission) - local totalTimeString, totalTimeSeconds, isMissionTimeImproved, successChance, partyBuffs, isEnvMechanicCountered, xpBonus, materialMultiplier = G.GetPartyMissionInfo(mission.missionID) - return format("%03d%01d%02d%01d",successChance,isEnvMechanicCountered and 1 or 0,(mission.resources * (materialMultiplier-1)) , (isMissionTimeImproved and 1 or 0)) -end -local filters={} -function filters.Xp(data) - for k,_ in pairs(data) do - if (addon:GetFollowerData(k,'maxed')) then - data[k]=nil + if candidate then + xprint(C(score,'yellow'),G.GetFollowerName(candidate),"assigned to slot",p+1) + P:AddFollower(candidate) + candidate=nil end end end -function addon:MatchMakerEpic(missionID,mission,party,filter) - if (GMFRewardSplash:IsShown()) then return end - if (not mission) then mission=self:GetMissionData(missionID) end - if (not party) then party=self:GetParty(missionID) end - local skipBusy=self:GetBoolean("IGM") - local skipMaxed=self:GetBoolean("IGP") +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 traits=new() - dbg=missionID==(tonumber(_G.MW) or 0) - if (dbg) then xprint(C("Matchmaking mission","Red"),missionID,mission.name) end local buffed=G.GetBuffedFollowersForMission(missionID) - if (filter) then - filters[filter](buffed) - end + 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("%s|%s",self:FollowerScore(mission),followerID)) - if (mission.numFollowers>1) then - for k,d in pairs(G.GetFollowersTraitsForMission(missionID)) do - if not buffed[k] then - traits[k]=d - end - end - end - P:RemoveFollower(followerID) - end - if (filter) then - filters[filter](traits) - end - for followerID,_ in pairs(traits) do - P:AddFollower(followerID) - tinsert(scores,format("%s|%s",self:FollowerScore(mission),followerID)) - xprint(G.GetFollowerName(followerID),scores[#scores]) + tinsert(scores,format("%010d1|%s",self:FollowerScore(mission,followerID),followerID)) P:RemoveFollower(followerID) + buffeds=buffeds+1 end - table.sort(scores) - for i=#scores,1,-1 do - local score,followerID=strsplit('|',scores[i]) - xprint(score,G.GetFollowerName(followerID)) + 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 - local missionScore=self:MissionScore(mission) - for p=1,mission.numFollowers do - xprint("Slot",p) - local delete=0 - local candidate=nil - local candidateScore=nil + 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]) - P:AddFollower(followerID) - candidateScore=self:MissionScore(mission) - xprint(G.GetFollowerName(followerID),candidateScore,"pos",i) - if (p>1) then - if (missionScore0) then - xprint("scores contiene",#scores) - xprint("rimuovo",delete) - tremove(scores,delete) - xprint("scores contiene",#scores) - end - if candidate then - P:AddFollower(candidate) - xprint("Adding",G.GetFollowerName(candidate),candidateScore) - end - if P:FreeSlots()==0 then break end - end - P:Dump() - xprint("Final score",self:MissionScore(mission)) - P:StoreFollowers(party.members) - party.full= P:FreeSlots()==0 - party.perc=P:Close() -end - -function addon:MatchMakerOld(missionID,mission,party,fromMissionControl) - if (GMFRewardSplash:IsShown()) then return end - if (not mission) then mission=self:GetMissionData(missionID) end - if (not party) then party=self:GetParty(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] - P:Open(missionID,mission.numFollowers) - -- Preloading skipped ones in party table. - if (dbg) then xprint(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 xprint("Trying to use [",followerID,"]") end - else - if (self:IsIgnored(followerID,missionID)) then - if (dbg) then xprint("Skipped",n[followerID],"due to ignored" ) end - P:Ignore(followerID,true) - elseif not self:IsFollowerAvailableForMission(followerID,skipBusy) then - if (dbg) then xprint("Skipped",n[followerID],"due to busy" ) end - P:Ignore(followerID) - elseif (skipMaxed and mission.xpOnly and self:GetFollowerData(followerID,'maxed')) then - if (dbg) then print("Skipped",n[followerID],"due to maxed" ) end - P:Ignore(followerID,true) - end + if firstmember then + P:AddFollower(firstmember) + if mission.numFollowers > 1 then + xprint(" AddMore 1") + AddMoreFollowers(self,mission,scores) 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 xprint("Checking ",threat) end - for i=1,#candidates do - local followerID=missionCounters[candidates[i]].followerID - if P:IsIn(followerID) then - if dbg then xprint("Countered by",n[followerID],"which is already in party") end - choosen=nil - break - end - if followerID then - if(not P:IsIgnored(followerID)) then - choosen=best(choosen,candidates[i],missionCounters,mission) - if (dbg) then xprint("Taken",n[missionCounters[choosen].followerID]) end - else - if (dbg) then xprint("Party Ignored",n[followerID]) end - end - end - end - if (choosen) then - if dbg then xprint("Adding to party",n[missionCounters[choosen].followerID]," still need ",P:FreeSlots()) end - P:AddFollower(missionCounters[choosen].followerID) - end - if (P:FreeSlots()==0) then - break - end - end - else - ns.xprint("Mission",missionID,"has no slots????") + 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 - if P:FreeSlots() > 0 then self:AddTraitsToParty(missionID,mission) end end - if P:FreeSlots() > 0 then self:CompleteParty(missionID,mission,skipBusy,skipMaxed) end - if (not fromMissionControl and not P:IsEmpty()) then - if P:FreeSlots() > 0 then self:CompleteParty(missionID,mission,skipBusy,false) 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) - party.full= P:FreeSlots()==0 - party.perc=P:Close() + P:Close(party) + del(buffed) 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 P:IsIgnored(follower.followerID) and not P:IsIn(follower.followerID)) then - if mission.resources > 0 and follower.name==scavengerTrait then - P:AddFollower(follower.followerID) - elseif mission.xpOnly and (follower.name==extraTrainingTrait or follower.name==hearthStoneProTrait) then - P:AddFollower(follower.followerID) - elseif mission.durationSeconds > GARRISON_LONG_MISSION_TIME and follower.name==epicMountTrait then - P:AddFollower(follower.followerID) - 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: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") - P:Dump() - end - for x=1,P:FreeSlots() do - local candidate - local candidatePerc=perc - if (dbg) then print(" Perc to beat",perc, "Going for spot ",P:FreeSlots()) 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 P:IsIgnored(followerID) then - if (dbg) then print("Skipped due to party ignored") end - break - end - if P:IsIn(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 rank=data.rank - local quality=data.quality - perc=tonumber(perc) or 0 - if ((perc) <100) then - P:AddFollower(followerID) - local newperc=select(4,G.GetPartyMissionInfo(missionID)) - newperc=tonumber(newperc) or 0 - candidatePerc=tonumber(candidatePerc) or 0 - P:RemoveFollower(followerID) - if (newperc > candidatePerc) then - candidatePerc=newperc - candidate=followerID - candidateRank=rank - candidateQuality=quality - 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(rank 1 ) then + 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 @@ -83,23 +99,49 @@ function AddExtraData(mission) 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 + 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 - mission.slots={} - local slots=mission.slots - - for i=1,#mission.enemies do - local mechanics=mission.enemies[i].mechanics - for i,mechanic in pairs(mechanics) do - tinsert(slots,mechanic) +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 - if (type) then - tinsert(slots,{name=TYPE,key=mission.type,icon=mission.typeIcon}) +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 index 13c3908..5cb7821 100644 --- a/MissionCompletion.lua +++ b/MissionCompletion.lua @@ -9,18 +9,149 @@ 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) + local function startTimer(delay,event) delay=delay or 0.2 - addon:ScheduleTimer("MissionAutoComplete",delay,"LOOP") + event=event or "LOOP" + addon:ScheduleTimer("MissionAutoComplete",delay,event) end local function stopTimer() timer=nil @@ -73,11 +204,13 @@ do 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 - 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')} + rewards.followerBase[v]=self:GetFollowerData(v,'qLevel') end end currentMission=tremove(missions) @@ -88,12 +221,16 @@ do 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@ + --[===[@debug@ print("evt",event,ID,arg1,arg2,agr3) - --@end-debug@ + --@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" @@ -102,16 +239,16 @@ do 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 + rewards.followerXP[ID]=rewards.followerXP[ID]+tonumber(arg1) or 0 end return -- GET_ITEM_INFO_RECEIVED: itemID elseif (event=="GET_ITEM_INFO_RECEIVED") then - currentMission.items[ID]=1 + rewards.items[format("%d:%s",currentMission.missionID,ID)]=1 return -- GET_ITEM_INFO_RECEIVED: itemID elseif (event=="GARRISON_MISSION_BONUS_ROLL_LOOT") then - currentMission.items[ID]=1 + rewards.items[format("%d:%s",currentMission.missionID,ID)]=1 return -- GARRISON_MISSION_COMPLETE_RESPONSE: missionID, requestCompleted, succeeded elseif (event=="GARRISON_MISSION_COMPLETE_RESPONSE") then @@ -122,7 +259,7 @@ do currentMission.state=1 else -- failure, just print results currentMission.state=2 - startTimer(0.6) + startTimer(0.1) return end startTimer(0.1) @@ -134,7 +271,7 @@ do currentMission.state=1 else currentMission.state=3 - startTimer(0.6) + startTimer(0.1) return end startTimer(0.1) @@ -146,15 +283,17 @@ do step=0 currentMission.state=0 local _ - _,_,_,currentMission.successChance,_,_,currentMission.xpBonus,currentMission.multiplier=G.GetPartyMissionInfo(currentMission.missionID) + _,_,_,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:MissionPrintResults(step==3) + self:GetMissionResults(step==3) self:RefreshFollowerStatus() currentMission=tremove(missions) startTimer() @@ -163,59 +302,62 @@ do currentMission.state=step else report:AddRow(DONE) + startTimer(0.3,"LOOT") end end end - function addon:MissionPrintResults(success) + function addon:GetMissionResults(success) stopTimer() - if (success) then - report:AddMissionName(currentMission.name,C(format("Succeeded. (Chance was: %s%%)", currentMission.successChance),"Green")) + 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") - 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 + print("Reward",k,v) v.quantity=v.quantity or 0 v.multiplier=v.multiplier or 1 ---@debug@ --- ns.xprint(format("Reward type: = %s",k)) --- for field,value in pairs(v) do --- ns.xprint(format(" %s = %s",field,value),C.Silver()) --- end ---@end-debug@ + v.golds=v.golds or 1 if v.currencyID then + rewards.currencies[v.currencyID].icon=v.icon if v.currencyID == 0 then - -- Money reward - report:AddIconText(v.icon,GetMoneyString(v.quantity)) + rewards.currencies[v.currencyID].qt=rewards.currencies[v.currencyID].qt+v.quantity * v.golds elseif v.currencyID == GARRISON_CURRENCY then - -- Garrison currency reward - report:AddIconText(v.icon,GetCurrencyLink(v.currencyID),v.quantity * v.multiplier) + rewards.currencies[v.currencyID].qt=rewards.currencies[v.currencyID].qt+v.quantity * v.multiplier else - -- Other currency reward - report:AddIconText(v.icon,GetCurrencyLink(v.currencyID),v.quantity ) + rewards.currencies[v.currencyID].qt=rewards.currencies[v.currencyID].qt+v.quantity end elseif v.itemID then - -- Item reward - report:AddItem(v.itemID,1) - currentMission.items[v.itemID]=nil - else - -- Follower XP reward - --report:AddIconText(v.icon,v.name) + rewards.items[format("%d:%s",currentMission.missionID,v.itemID)]=1 end end end - for k,v in pairs(currentMission.items) do - report:AddItem(k,v) + 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(currentMission.followers) do - report:AddFollower(v,currentMission.followerXp[v]) + 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 index ba3144c..804a92d 100644 --- a/MissionControl.lua +++ b/MissionControl.lua @@ -16,7 +16,6 @@ local aMissions={} local dbcache local cache local db -local parties local GMC local GMF=GarrisonMissionFrame local G=C_Garrison @@ -24,9 +23,9 @@ local GMCUsedFollowers={} local wipe=wipe local pairs=pairs local tinsert=tinsert ---@debug@ +--[===[@debug@ if LibDebug then LibDebug() end ---@end-debug@ +--@end-debug@]===] local dbg function addon:GMCBusy(followerID) return GMCUsedFollowers[followerID] @@ -36,20 +35,23 @@ function addon:GMCCreateMissionList(workList) local settings=self.privatedb.profile.missionControl local ar=settings.allowedRewards wipe(workList) - for missionID,mission in pairs(cache.missions) do + for _,missionID in self:GetMissionIterator() do local discarded=false repeat - if (mission.durationSeconds > settings.maxDuration * 3600 or mission.durationSeconds < settings.minDuration * 3600) then - ns.xprint(missionID,"discarded due to len",mission.durationSeconds /3600) + 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 (mission.isRare and settings.skipRare) then + 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 (mission[k] and mission[k]~=0) then -- we have a forbidden reward + if (self:GetMissionData(missionID,"class")==k) then -- we have a forbidden reward + ns.xprint(missionID,"discarded due to class == ", k) discarded=true break end @@ -60,24 +62,23 @@ function addon:GMCCreateMissionList(workList) end until true end + local parties=self:GetParty() 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] + if addon:GetMissionData(i1,criterium) ~= addon:GetMissionData(i2,criterium) then + return addon:GetMissionData(i1,criterium) > addon:GetMissionData(i2,criterium) end end end - if (parties[m1.missionID].perc and parties[m2.missionID].perc) then - return parties[m1.missionID].perc > parties[m2.missionID].perc + if (parties[i1].perc and parties[i2].perc) then + return parties[i1].perc > parties[i2].perc end - return m1.level > m2.level + return addon:GetMissionData(i1,'level') > addon:GetMissionData(i2,'level') end table.sort(workList,msort) - --@debug@ + --[===[@debug@ ns.xprint("Sorted list") local x=new() for i=1,#workList do @@ -92,7 +93,7 @@ function addon:GMCCreateMissionList(workList) local scroll=self:GetScroller("Sorted missions",nil,600,600) self:cutePrint(scroll,x) del(x) - --@end-debug@ + --@end-debug@]===] end --- This routine can be called both as coroutin and as a standard one @@ -160,27 +161,22 @@ do 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 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=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 + minimumChance=tonumber(GMC.settings.minimumChance) or 100 + else + minimumChance=tonumber(GMC.settings.rewardChance[checkprio]) or 100 end - if (dbg) then print ("Missionid",missionID,"Chance",minimumChance,"chance",party.perc) 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 - if (dbg) then print("Preparing button for",missionID) end + ns.xprint(" Mission accepted") local mb=AceGUI:Create("GMCMissionButton") for i=1,#party.members do GMCUsedFollowers[party.members[i]]=true @@ -189,7 +185,7 @@ do tinsert(GMC.ml.Parties,party) GMC.ml.widget:PushChild(mb,missionID) mb:SetFullWidth(true) - mb:SetMission(mission) + mb:SetMission(self:GetMissionData(missionID),party) mb:SetCallback("OnClick",function(...) addon:GMCRunMission(missionID) GMC.ml.widget:RemoveChild(missionID) @@ -222,13 +218,12 @@ function addon:GMC_OnClick_Run(this,button) end function addon:GMC_OnClick_Start(this,button) ns.xprint(C("-------------------------------------------------","Yellow")) - this:Disable() GMC.ml.widget:ClearChildren() if (self:GetTotFollowers(AVAILABLE) == 0) then - self:Popup("All followers are busy",10) - this:Enable() + GMC.ml.widget:SetTitle("All followers are busy") return end + this:Disable() addon:GMCCreateMissionList(aMissions) wipe(GMCUsedFollowers) wipe(GMC.ml.Parties) @@ -247,7 +242,6 @@ function addon:GMCBuildPanel(bigscreen) db=self.db.global dbcache=self.privatedb.profile cache=self.private.profile - parties=self:GetParty() chestTexture='GarrMission-'..UnitFactionGroup('player').. 'Chest' GMC = CreateFrame('FRAME', 'GMCOptions', GMF) GMC.settings=dbcache.missionControl @@ -444,15 +438,31 @@ function addon:GMCBuildRewards() 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'} + {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) @@ -505,9 +515,9 @@ local addPriorityRule,prioRefresh,removePriorityRule,prioMenu,prioTitles,prioChe do -- 1 = item, 2 = folitem, 3 = exp, 4 = money, 5 = resource prioTitles={ - itemLevel="Gear Items", - followerUpgrade="Upgrade Items", - xpBonus="Follower XP Bonus", + itemLevel="Equipment", + followerUpgrade="Followr Upgrade", + xp="Xp gain", gold="Gold Reward", resources="Resource Rewards" } @@ -613,7 +623,7 @@ function addon:GMCBuildPriorities() 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)}) + 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 diff --git a/PartyCache.lua b/PartyCache.lua index 2b78b94..e3c4305 100644 --- a/PartyCache.lua +++ b/PartyCache.lua @@ -14,7 +14,17 @@ local pcall=pcall -- -- Temporary party management local parties=setmetatable({},{ - __index=function(t,k) rawset(t,k,{members={},perc=0,full=false}) return t[k] end + __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) @@ -26,10 +36,15 @@ local followerMissions=setmetatable({},{ }) ns.party={} local party=ns.party --#party -local ID,maxFollowers,members,ignored=0,1,{},{} +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) @@ -42,6 +57,9 @@ end function party:IsIn(followerID) return tContains(members,followerID) end +function party:MaxSlots() + return maxFollowers +end function party:FreeSlots() return maxFollowers-#members end @@ -50,10 +68,9 @@ function party:IsEmpty() end function party:Dump() - for i=1,3 do - if (members[i]) then - ns.xprint(i,addon:GetFollowerData(members[i],'fullname')) - end + 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 @@ -62,13 +79,19 @@ 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@ +--[===[@debug@ else - ns.xprint("Unable to add", G.GetFollowerName(followerID),"to",ID,code) ---@end-debug@ + 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 @@ -77,9 +100,9 @@ function party:RemoveFollower(followerID) if (followerID==members[i]) then tremove(members,i) local rc,code=pcall(G.RemoveFollowerFromMission,ID,followerID) ---@debug@ +--[===[@debug@ if (not rc) then trace("Unable to remove", G.GetFollowerName(members[i]),"from",ID,code) end ---@end-debug@ +--@end-debug@]===] return true end end end @@ -91,14 +114,57 @@ function party:StoreFollowers(table) end return #table end -function party:Close() - local perc=select(4,G.GetPartyMissionInfo(ID)) +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@ +--[===[@debug@ if (not rc) then ns.xtrace("Unable to pop", G.GetFollowerName(members[i])," from ",ID,code) end ---@end-debug@ +--@end-debug@]===] else break @@ -107,12 +173,77 @@ function party:Close() releaseEvents() wipe(members) wipe(ignored) + wipe(threats) return perc or 0 end -function addon:GetParty(missionID) - if (missionID) then - return parties[missionID] +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 parties + 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 -- 1.7.9.5