Quantcast

Misson Completion

Alar of Daggerspine [02-01-15 - 23:50]
Misson Completion

Signed-off-by: Alar of Daggerspine <alar@aspide.it>
Filename
GarrisonCommander.lua
doc.txt
diff --git a/GarrisonCommander.lua b/GarrisonCommander.lua
index 8708f31..2377511 100644
--- a/GarrisonCommander.lua
+++ b/GarrisonCommander.lua
@@ -45,6 +45,23 @@ local pin=false
 local baseHeight
 local minHeight
 if (LibDebug) then LibDebug() end
+local backdrop = {
+		--bgFile="Interface\\TutorialFrame\\TutorialFrameBackground",
+		bgFile="Interface\\DialogFrame\\UI-DialogBox-Background-Dark",
+		edgeFile="Interface\\Tooltips\\UI-Tooltip-Border",
+		tile=true,
+		tileSize=16,
+		edgeSize=16,
+		insets={bottom=7,left=7,right=7,top=7}
+}
+local dialog = {
+	bgFile="Interface\\DialogFrame\\UI-DialogBox-Background",
+	edgeFile="Interface\\DialogFrame\\UI-DialogBox-Border",
+	tile=true,
+	tileSize=32,
+	edgeSize=32,
+	insets={bottom=5,left=5,right=5,top=5}
+}
 local function tcopy(obj, seen)
 	if type(obj) ~= 'table' then return obj end
 	if seen and seen[obj] then return seen[obj] end
@@ -58,7 +75,7 @@ end
 -----------------------------------------------------------------
 -- Recycling function from ACE3

-
+local missionautocompleting

 local new, del, copy
 do
@@ -253,10 +270,10 @@ if (LibDebug) then LibDebug() end
 --
 -- Forces a table to countain other tables,
 local t1={
-	__index=function(t,k) rawset(t,k,{}) return t[k] end
+	__index=function(t,k) if k then rawset(t,k,{}) return t[k] end end
 }
 local t2={
-	__index=function(t,k) rawset(t,k,setmetatable({},t1)) return t[k] end
+	__index=function(t,k) if k then rawset(t,k,setmetatable({},t1)) return t[k] end end
 }
 local followersCache={}
 local followersCacheIndex={}
@@ -267,7 +284,7 @@ local db
 local n=setmetatable({},{
 	__index = function(t,k)
 		local name=addon:GetFollowerData(k,'fullname')
-		if (name) then rawset(t,k,name) return name else return k end
+		if (name and k) then rawset(t,k,name) return name else return k end
 	end
 })

@@ -288,8 +305,9 @@ local backdrop = {
 	edgeSize=16,
 	insets={bottom=7,left=7,right=7,top=7}
 }
-local function addBackdrop(f)
+local function addBackdrop(f,color)
 	f:SetBackdrop(backdrop)
+	f:SetBackdropBorderColor(C[color or 'Yellow']())
 end

 --generic table scan
@@ -552,6 +570,8 @@ end
 function addon:OnInitialized()
 --@debug@
 	xprint("OnInitialized")
+	self.evdebug=CreateFrame("Frame")
+	self.evdebug:SetScript("OnEvent",function(...) return print('|cffff2020event|r',...) end)
 --@end-debug@
 	for _,b in ipairs(GMFMissionsListScrollFrame.buttons) do
 		local scale=0.8
@@ -574,6 +594,7 @@ 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"],
@@ -587,7 +608,7 @@ function addon:OnInitialized()
 	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:AddPrivateAction("ShowMissionControl",L["Mission control"],L["You can choose some criteria and have GC autosumbit missions for you"])
+	--self:AddPrivateAction("ShowMissionControl",L["Mission control"],L["You can choose some criteria and have GC autosumbit missions for you"])
 --@debug@
 	self:AddLabel("Developers options")
 	self:AddToggle("DBG",false, "Enable Debug")
@@ -966,37 +987,62 @@ function addon:CompleteParty(missionID,mission,skipBusy,skipMaxed)
 	local candidateRank=10000
 	local candidateQuality=9999
 	if (dbg) then
-		print("Attemptin to fill party, so far:")
+		print("Attemptin to fill party, so far perc is ",perc, "and party is")
 		dumpParty()
 	end
+	local stash={}
 	for x=1,roomInParty() do
 		local candidate
 		local candidatePerc=perc
+		if (dbg) then print("            Perc to beat",perc, "Going for spot ",roomInParty()) end
 		local totFollowers=#followersCache
 		for i=1,totFollowers do
 			local data=followersCache[i]
 			local followerID=data.followerID
-			if (not isPartyIgnored(followerID) and not isInParty(followerID) and not self:IsIgnored(followerID,missionID) and not(skipMaxed and data.maxed and mission.xpOnly) and not isInParty(followerID) and self:GetFollowerStatusForMission(followerID,skipBusy)) then
+			if (dbg) then print("evaluating",data.fullname) end
+			repeat
+				if isPartyIgnored(followerID) then
+					if (dbg) then print("Skipped due to party ignored") end
+					break
+				end
+				if isInParty(followerID) then
+					if (dbg) then print("Skipped due to already in party") end
+					break
+				end
+				if self:IsIgnored(followerID,missionID) then
+					if (dbg) then print("Skipped due to ignored") end
+					break
+				end
+				if (skipMaxed and data.maxed and mission.xpOnly) then
+					if (dbg) then print("Skipped due to maxed",skipMaxed,mission.xpOnly) end
+					break
+				end
+				if (not self:IsFollowerAvailableForMission(followerID,skipBusy)) then
+					if (dbg) then print("Skipped due to busy") end
+					break
+				end
 				local missions=#followerMissions[followerID]
 				local rank=data.rank
 				local quality=data.quality
-				repeat
-					perc=tonumber(perc) or 0
-					if ((perc) <100) then
-						pushFollower(followerID)
-						local newperc=tonumber(select(4,G.GetPartyMissionInfo(missionID))) or 0
-						removeFollower(followerID)
-						if (newperc > candidatePerc) then
-							candidatePerc=newperc
-							candidate=followerID
-							candidateMissions=missions
-							candidateRank=rank
-							candidateQuality=quality
-							break -- continue
-						elseif (newperc < candidatePerc) then
-							break --continue
-						end
+				perc=tonumber(perc) or 0
+				if ((perc) <100) then
+					pushFollower(followerID)
+					local newperc=select(4,G.GetPartyMissionInfo(missionID))
+					newperc=tonumber(newperc) or 0
+					removeFollower(followerID)
+					if (newperc > candidatePerc) then
+						candidatePerc=newperc
+						candidate=followerID
+						candidateMissions=missions
+						candidateRank=rank
+						candidateQuality=quality
+						break -- continue
+					elseif (newperc <= candidatePerc) then
+						if (dbg) then print("Stashed ",n[followerID]) end
+						tinsert(stash,followerID)
+						break --continue
 					end
+				else
 					-- This candidate is not improving success chance or we are already at 100%, minimize
 					if (i < totFollowers  and data.maxed) then
 						break  -- Pointless using a maxed follower if we  have more follower to try
@@ -1022,26 +1068,41 @@ function addon:CompleteParty(missionID,mission,skipBusy,skipMaxed)
 						candidateRank=rank
 						candidateQuality=quality
 					end
-				until true -- A poor man continue implementation using break
-			end
+				end
+			until true -- A poor man continue implementation using break
 		end
 		if (candidate) then
+			if (dbg) then print("Attempting to add to party") end
 			pushFollower(candidate)
 			if (dbg) then
 				print("Added member to party")
 				dumpParty()
 			end
 			perc=select(4,G.GetPartyMissionInfo(missionID))
+			if (dbg) then print("New perc is",perc) end
 		end
 	end
+	for i=1,#stash do
+		if roomInParty()==0 then break end
+		if (dbg) then print("Tring stashed ",n[stash[i]]) end
+		pushFollower(stash[i])
+	end
 end
-function addon:MatchMaker(missionID,mission,party)
+function addon:TestMission(missionID)
+	local party=new()
+	_G.MW=missionID
+	self:MatchMaker(missionID)
+	_G.MW=nil
+
+end
+
+function addon:MatchMaker(missionID,mission,party,fromMissionControl)
 	if (GMFRewardSplash:IsShown()) then return end
 	if (not mission) then mission=self:GetMissionData(missionID) end
 	if (not party) then party=parties[missionID] end
 	local skipBusy=self:GetBoolean("IGM")
 	local skipMaxed=self:GetBoolean("IGP")
-	dbg=dbg or missionID==(tonumber(_G.MW) or 0)
+	dbg=missionID==(tonumber(_G.MW) or 0)
 	local slots=mission.slots
 	local missionCounters=counters[missionID]
 	local ct=counterThreatIndex[missionID]
@@ -1057,11 +1118,11 @@ function addon:MatchMaker(missionID,mission,party)
 				if (self:IsIgnored(followerID,missionID)) then
 					if (dbg) then print("Skipped",n[followerID],"due to ignored" ) end
 					partyIgnore(followerID,true)
-				elseif not addon:GetFollowerStatusForMission(followerID,skipBusy) then
+				elseif not addon:IsFollowerAvailableForMission(followerID,skipBusy) then
 					if (dbg) then print("Skipped",n[followerID],"due to busy" ) end
 					partyIgnore(followerID)
 				elseif (skipMaxed and mission.xpOnly and self:GetFollowerData(followerID,'maxed')) then
-					if (dbg) then print("Skipped",n[followerID],"due to busy" ) end
+					if (dbg) then print("Skipped",n[followerID],"due to maxed" ) end
 					partyIgnore(followerID,true)
 				end
 			end
@@ -1071,12 +1132,20 @@ function addon:MatchMaker(missionID,mission,party)
 				local threat=cleanicon(slots[i].icon)
 				local candidates=ct[threat]
 				local choosen
+				if (dbg) then print("Checking ",threat) end
 				for i=1,#candidates do
 					local followerID=missionCounters[candidates[i]].followerID
+					if isInParty(followerID) then
+						if dbg then print("Countered by",n[followerID],"which is already in party") end
+						choosen=nil
+						break
+					end
 					if followerID then
 						if(not isPartyIgnored(followerID)) then
 							choosen=best(choosen,candidates[i],missionCounters)
 							if (dbg) then print("Taken",n[missionCounters[choosen].followerID]) end
+						else
+							if (dbg) then print("Party Ignored",n[followerID]) end
 						end
 					end
 				end
@@ -1084,6 +1153,7 @@ function addon:MatchMaker(missionID,mission,party)
 					if (type(missionCounters[choosen]) ~="table") then
 						trace(format("%s %s %d %d",mission.name,threat,missionID,tonumber(choosen) or 0))
 					end
+					if dbg then print("Adding to party",n[missionCounters[choosen].followerID]," still need ",roomInParty()) end
 					pushFollower(missionCounters[choosen].followerID)
 				end
 				if (roomInParty()==0) then
@@ -1096,6 +1166,9 @@ function addon:MatchMaker(missionID,mission,party)
 		if roomInParty() > 0 then self:AddTraitsToParty(missionID,mission) end
 	end
 	if roomInParty() > 0 then self:CompleteParty(missionID,mission,skipBusy,skipMaxed) end
+	if (not fromMissionControl and not isPartyEmpty()) then
+		if roomInParty() > 0 then self:CompleteParty(missionID,mission,skipBusy,false) end
+	end
 	storeFollowers(party.members)
 	party.full= roomInParty()==0
 	party.perc=closeParty()
@@ -1633,8 +1706,7 @@ end

 function addon:EventGARRISON_MISSION_BONUS_ROLL_COMPLETE(event,missionID,completed,success)
 --@debug@
-	xprint(event,missionID,completed,success)
-	self:MissionAutoComplete(event,missionID,completed,success)
+	xprint('evt',event,missionID,completed,success)
 --@end-debug@
 	self:RefreshFollowerStatus()
 end
@@ -1651,8 +1723,7 @@ end
 --
 function addon:EventGARRISON_MISSION_COMPLETE_RESPONSE(event,missionID,completed,rewards)
 --@debug@
-	xprint(event,missionID,completed,rewards)
-	self:MissionAutoComplete(event,missionID,completed,rewards)
+	xprint('evt',event,missionID,completed,rewards)
 --@end-debug@
 	dbcache.history[missionID][time()]={result=100,success=success}
 	dbcache.seen[missionID]=nil
@@ -1810,6 +1881,7 @@ do
 	end
 end
 function addon:ShowMissionControl()
+	if missionautocompleting then return end
 	if (not GMC:IsShown()) then
 		GarrisonMissionFrame_SelectTab(999)
 		GMF.FollowerTab:Hide()
@@ -1828,23 +1900,6 @@ end
 local helpwindow -- pseudo static
 function addon:ShowHelpWindow(button)
 	if (not helpwindow) then
-		local backdrop = {
-				--bgFile="Interface\\TutorialFrame\\TutorialFrameBackground",
-				bgFile="Interface\\DialogFrame\\UI-DialogBox-Background-Dark",
-				edgeFile="Interface\\Tooltips\\UI-Tooltip-Border",
-				tile=true,
-				tileSize=16,
-				edgeSize=16,
-				insets={bottom=7,left=7,right=7,top=7}
-		}
-		local dialog = {
-			bgFile="Interface\\DialogFrame\\UI-DialogBox-Background",
-			edgeFile="Interface\\DialogFrame\\UI-DialogBox-Border",
-			tile=true,
-			tileSize=32,
-			edgeSize=32,
-			insets={bottom=5,left=5,right=5,top=5}
-		}
 		helpwindow=CreateFrame("Frame",nil,GCF)
 		helpwindow:EnableMouse(true)
 		helpwindow:SetBackdrop(backdrop)
@@ -1956,6 +2011,152 @@ 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()
+				print("Acquire")
+				self.frame:SetPoint("LEFT")
+				self.itemlink=nil
+			end
+			function m:Show()
+				self.frame:Show()
+			end
+			function m:Hide()
+				self.frame:Hide()
+				self:Release()
+			end
+			function m:AddMissionName(name)
+				local obj=self.scroll
+				local l=AceGUI:Create("Label")
+				l:SetFontObject(QuestTitleFontBlackShadow)
+				l:SetColor(C:Yellow())
+				l:SetText(name)
+				l:SetFullWidth(true)
+				obj:AddChild(l)
+			end
+			function m:AddRow(data,...)
+				local obj=self.scroll
+				local l=AceGUI:Create("Label")
+				l:SetFontObject(GameFontNormalLarge)
+				l:SetText(data)
+				l:SetColor(...)
+				l:SetFullWidth(true)
+				obj:AddChild(l)
+			end
+			function m:AddFollower(followerID,data)
+				if (data[1]==0) then
+					return self:AddRow(format("%s is already at maximum xp",addon:GetFollowerData(followerID,'fullname')))
+				end
+				local quality=G.GetFollowerQuality(followerID) or data[4]
+				local level=G.GetFollowerLevel(followerID) or data[3]
+				xprint(followerID,quality,level,data[3],data[4])
+				local levelup=((quality < data[4]) or (level < data[3]))
+				--local levelup=true
+				if levelup then
+					PlaySound("UI_Garrison_CommandTable_Follower_LevelUp");
+				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 ""))
+			end
+			function m:AddIconText(icon,text,qt)
+				local obj=self.scroll
+				local l=AceGUI:Create("InteractiveLabel")
+				l:SetCallback("OnEnter",onEnter)
+				l:SetCallback("OnLeave",function() GametTooltip:Hide() end)
+				l:SetFontObject(GameFontNormalLarge)
+				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()
+				print("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()
+	if generated then return end
+	generated=true
+	do
+		local Type="GCGUIContainer"
+		local Version=1
+		local m={}
+		function m:OnAcquire()
+			print("Acquire",Type)
+			self.frame:EnableMouse(true)
+			self:SetTitleColor(C.Yellow())
+			self.frame:SetFrameStrata("HIGH")
+			self.frame:SetFrameLevel(999)
+		end
+		function m:SetContentWidth(x)
+			self.content:SetWidth(x)
+		end
+		local function Constructor()
+			local frame=CreateFrame("Frame","XXX",nil,"GarrisonUITemplate")
+			local widget={frame=frame}
+			widget.type=Type
+			widget.SetTitle=function(self,...) self.frame.TitleText:SetText(...) end
+			widget.SetTitleColor=function(self,...) self.frame.TitleText:SetTextColor(...) end
+			for k,v in pairs(m) do widget[k]=v end
+			frame:SetScript("OnHide",function(self) self.obj:Fire('OnClose') end)
+			frame.obj=widget
+			--Container Support
+			local content = CreateFrame("Frame",nil,frame)
+			widget.content = content
+			--addBackdrop(content,'Green')
+			content.obj = widget
+			content:SetPoint("TOP",frame,"TOP",0,-25)
+			content:SetPoint("BOTTOM",frame,"BOTTOM",0,25)
+			content:SetWidth(400)
+			AceGUI:RegisterAsContainer(widget)
+			return widget
+		end
+		AceGUI:RegisterWidgetType(Type,Constructor,Version)
+	end
+end
+end
 function addon:GenerateMissionContainer()
 	do
 		local Type="GMCLayer"
@@ -1963,32 +2164,33 @@ function addon:GenerateMissionContainer()
 		local function OnRelease(self)
 			wipe(self.childs)
 		end
-		local function OnAcquire(self)
+		local m={}
+		function m:OnAcquire()
 			self.frame:SetParent(UIParent)
-			self.frame:SetFrameStrata("FULLSCREEN_DIALOG")
+			self.frame:SetFrameStrata("HIGH")
 			self.frame:SetHeight(50)
 			self.frame:SetWidth(100)
 			self.frame:Show()
 			self.frame:SetPoint("LEFT")
 		end
-		local function Show(self)
-			self.frame:Show()
+		function m:Show()
+			return self.frame:Show()
 		end
-		local function Hide(self)
+		function m:Hide()
 			self.frame:Hide()
 			self:Release()
 		end
-		local function SetScript(self,...)
-			self.frame:SetScript(...)
+		function m:SetScript(...)
+			return self.frame:SetScript(...)
 		end
-		local function SetParent(self,...)
-			self.frame:SetParent(...)
+		function m:SetParent(...)
+			return self.frame:SetParent(...)
 		end
-		local function PushChild(self,child,index)
+		function m:PushChild(child,index)
 			self.childs[index]=child
 			self.scroll:AddChild(child)
 		end
-		local function RemoveChild(self,index)
+		function m:RemoveChild(index)
 			local child=self.childs[index]
 			if (child) then
 				self.childs[index]=nil
@@ -1996,11 +2198,11 @@ function addon:GenerateMissionContainer()
 				self:DoLayout()
 			end
 		end
-		local function ClearChildren(self)
+		function m:ClearChildren()
 			wipe(self.childs)
 			self:AddScroll()
 		end
-		local function AddScroll(self)
+		function m:AddScroll()
 			if (self.scroll) then
 				self:ReleaseChildren()
 				self.scroll=nil
@@ -2035,12 +2237,7 @@ function addon:GenerateMissionContainer()
 			widget.SetTitleHeight=function(self,...) self.title:SetHeight(...) end
 			widget.frame=frame
 			frame.obj=widget
-			widget.OnAcquire=OnAcquire
-			widget.OnRelease=OnRelease
-			widget.Show=Show
-			widget.Hide=Hide
-			widget.SetScript=SetScript
-			widget.SetParent=SetParent
+			for k,v in pairs(m) do widget[k]=v end
 			frame:SetScript("OnHide",function(self) self.obj:Fire('OnClose') end)
 			--Container Support
 			local content = CreateFrame("Frame",nil,frame)
@@ -2049,10 +2246,6 @@ function addon:GenerateMissionContainer()
 			content:SetPoint("TOPLEFT",title,"BOTTOMLEFT")
 			content:SetPoint("BOTTOMRIGHT")
 			AceGUI:RegisterAsContainer(widget)
-			widget.PushChild=PushChild
-			widget.RemoveChild=RemoveChild
-			widget.ClearChildren=ClearChildren
-			widget.AddScroll=AddScroll
 			return widget
 		end
 		AceGUI:RegisterWidgetType(Type,Constructor,Version)
@@ -2912,6 +3105,11 @@ function addon:checkMethod(method,hook)
 	end
 end
 function addon:SafeRegisterEvent(event)
+--@debug@
+	if not self.evdebug:IsEventRegistered(event) then
+		self.evdebug:RegisterEvent(event)
+	end
+--@end-debug@
 	local method="Event"..event
 	if (self:checkMethod(method,event)) then
 		return self:RegisterEvent(event,method)
@@ -2996,49 +3194,55 @@ function addon:EventGARRISON_FOLLOWER_XP_CHANGED(event,followerID,iLevel,xp,leve
 	wipe(followersCache)
 	self:GetFollowerData(followerID)  -- triggering a full cache refresh
 end
-
-function addon:GetFollowerData(key,subkey)
-	local k=followersCacheIndex[key]
-	if (not followersCache[1]) then
-		xprint("Follower cache refresh")
-		followersCache=G.GetFollowers()
-		for i,follower in pairs(followersCache) do
-			if (not follower.isCollected) then
-				followersCache[i]=nil
-			else
-				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))
+do
+	local function followerRecalculate(follower)
+		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:GetFollowerData(key,subkey,refresh)
+		local k=followersCacheIndex[key]
+		if (not followersCache[1]) then
+			xprint("Follower cache refresh")
+			followersCache=G.GetFollowers()
+			for i,follower in pairs(followersCache) do
+				if (not follower.isCollected) then
+					followersCache[i]=nil
+				else
+					followerRecalculate(follower)
+				end
 			end
+			refresh=false
 		end
-	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
+		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
 			end
 		end
-	end
-	if (k) then
-		if (subkey) then
-			return t[k][subkey]
+		if (k and type(t[k]=='table')) then
+			if (refresh) then followerRecalculate(t[k]) end
+			if (subkey) then
+				return t[k][subkey]
+			else
+				return t[k]
+			end
 		else
-			return t[k]
+			return nil
 		end
-	else
-		return nil
 	end
 end
 function addon:GetMissionData(missionID,subkey)
@@ -3057,7 +3261,7 @@ function addon:GetMissionData(missionID,subkey)
 	end
 	return missionCache
 end
-function addon:GetFollowerStatusForMission(followerID,skipbusy)
+function addon:IsFollowerAvailableForMission(followerID,skipbusy)
 	if (GMCUsedFollowers[followerID]) then
 		return false
 	end
@@ -3371,6 +3575,7 @@ function addon:RenderExtraButton(button,numRewards)
 	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
@@ -3390,6 +3595,9 @@ function addon:RenderExtraButton(button,numRewards)
 	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
@@ -3842,7 +4050,7 @@ do
 					if dbg then print ("NO data for",missionID) end
 					return
 				end
-				self:MatchMaker(missionID,mission,party) -- I need my mission data
+				self:MatchMaker(missionID,mission,party,true) -- I need my mission data
 				local minimumChance=0
 				if (GMC.settings.useOneChance) then
 					minimumChance=GMC.settings.minimumChance
@@ -3938,8 +4146,7 @@ function addon:GMCBuildPanel()
 	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.skipRare=factory:Checkbox(GMC,GMC.settings.skipRare,L["Ignore rare missions"])
-	GMC.skipRare:SetPoint("TOPLEFT",priorities,"BOTTOMLEFT",0,-10)
+
 	GMC.startButton = CreateFrame('BUTTON',nil,  list.frame, 'GameMenuButtonTemplate')
 	GMC.startButton:SetText('Calculate')
 	GMC.startButton:SetWidth(148)
@@ -3960,6 +4167,12 @@ function addon:GMCBuildPanel()
 	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") )
@@ -4335,39 +4548,223 @@ end
 addon.SetUp=addon.ExperimentalSetUp
 do
 	local missions={}
-	local missionsIndex=1
-	local currentmission
+	local states={}
+	local currentMission
+	local scroller
+	local report
+	local timer
+	local function startTimer()
+		addon:AddRow(scroller,"StartTimer",C.Silver())
+		--timer=addon:ScheduleRepeatingTimer("MissionAutoComplete",0.2,"LOOP")
+		addon:ScheduleTimer("MissionAutoComplete",0.2,"LOOP")
+	end
+	local function stopTimer()
+		--addon:AddRow(scroller,"StopTimer",C.Silver())
+		--if timer then addon:CancelTimer(timer) end
+		timer=nil
+	end
+	function addon:MissionsCleanup()
+		stopTimer()
+		self:AddRow(scroller,"Final cleanup")
+		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)
+		print("MIssion events",start)
+		self:UnregisterEvent("GARRISON_MISSION_BONUS_ROLL_COMPLETE")
+		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_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_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
-			missionsIndex=1
+			self:DumpStatus("Prima")
+			missionautocompleting=true
+			scroller=self:GetScroller("Mission Results")
+			report=self:GenerateMissionCompleteList("Missions' results")
+			--report:SetPoint("TOPLEFT",GMFMissions.CompleteDialog.BorderFrame)
+			--report:SetPoint("BOTTOMRIGHT",GMFMissions.CompleteDialog.BorderFrame)
+			report:SetPoint("TOPLEFT",GMF,-2,2)
+			report:SetPoint("BOTTOMRIGHT",GMF,2,-2)
+			report:SetCallback("OnClose",function() return addon:MissionsCleanup() end)
+--@debug@
+			self:AddRow(scroller,"Auto completing " .. #missions .. " to complete")
 			print("We have " .. #missions .. " missions to complete")
+--@debug@
+			currentMission=tremove(missions)
+			self:MissionEvents(true)
 			self:MissionAutoComplete("LOOP")
 		end
 	end
-	function addon:MissionAutoComplete(event,missionID,completed,custom)
+	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
-
-		if (event=="GARRISON_MISSION_COMPLETE_RESPONSE") then
-			xprint(missionID,completed,"Mission result:", custom)
+		self:AddRow(scroller,strjoin(" ",tostringall(event,ID,arg1,arg2,arg3,arg4)),C.Silver())
+		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
+				self:AddRow(scroller,format("%s gained %d xp (%d to next level)",self:GetFollowerData(ID,'fullname'),arg1,arg2))
+				--report:AddFollower(ID,arg1,arg2)
+				currentMission.followerXp[ID][1]=currentMission.followerXp[ID][1]+arg1
+				xdump(currentMission.followerXp,'CM.followerxp')
+			end
+			return
+		-- GET_ITEM_INFO_RECEIVED: itemID
+		elseif (event=="GET_ITEM_INFO_RECEIVED") then
+			self:AddRow(scroller,format("Received %s",select(2,GetItemInfo(ID))))
+			report:AddItem(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
+				self:AddRow(scroller,"Changed currentMission.state to  " ..currentMission.state,C.Silver())
+			elseif (arg2) then -- success, we need to roll
+				currentMission.state=1
+				self:AddRow(scroller,"Changed currentMission.state to  " ..currentMission.state,C.Silver())
+			else -- failure, just print results
+				currentMission.state=2
+				self:AddRow(scroller,"Changed currentMission.state to  " ..currentMission.state,C.Silver())
+			end
+			startTimer()
+			return
+		-- GARRISON_MISSION_BONUS_ROLL_COMPLETE: missionID, requestCompleted; happens after C_Garrison.MissionBonusRoll
 		elseif (event=="GARRISON_MISSION_BONUS_ROLL_COMPLETE") then
-			xprint(missionID,completed,"Mission result:")
-			xdump(custom,"ROLL")
-			xdump(G.GetMissionPartyInfo(missionID),'partyinfo')
-			xdump(G.GetMissionInfo(missionID),'info')
+			if (not arg1) then
+				-- We need to call server again
+				currentMission.state=1
+			else
+				currentMission.state=3
+			end
+			startTimer()
+			return
 		else
-			local mission=missions[missionsIndex]
-			if (mission) then
-				missionID=mission.missionID
-				xprint(event,missionID)
-				xdump({G.GetPartyMissionInfo(missionID)},'PARTYINFO')
-				xdump({G.GetMissionInfo(missionID)},'INFO')
-				xdump(mission,"MISSION")
+			if (currentMission) then
+				local step=currentMission.state or -1
+				if (step<1) then
+--@debug
+					self:AddRow(scroller,"--------------------------------------------------------------------")
+					self:AddRow(scroller,currentMission.name,C.Yellow())
+					self:AddRow(scroller,format("ID: %d",currentMission.missionID))
+--@end-debug@
+					currentMission.followerXp={}
+					for k,v in pairs(currentMission.followers) do
+						self:AddRow(scroller,format("Before: %s xp: %d",self:GetFollowerData(v,'fullname'),self:GetFollowerData(v,'xp')))
+						currentMission.followerXp[v]={0,G.GetFollowerXP(v),self:GetFollowerData(v,'level'),self:GetFollowerData(v,'quality')}
+					end
+					step=0
+					currentMission.state=0
+					local _
+					_,_,_,currentMission.successChance,_,_,currentMission.xpBonus,currentMission.multiplier=G.GetPartyMissionInfo(currentMission.missionID)
+					currentMission.xp=select(2,G.GetMissionInfo(currentMission.missionID))
+					local s=self:GetScroller(currentMission.name)
+					self:cutePrint(s,currentMission)
+					report:AddMissionName(currentMission.name,currentMission.successChance,currentMission.xp)
+--@debug@
+					report:AddRow(format("Resource multiplier: %d Xp Bonus:%d",currentMission.multiplier,currentMission.xpBonus))
+					report:AddRow(format("ID: %d",currentMission.missionID))
+					self:cutePrint(scroller,currentMission)
+--@end-debug
+
+				end
+				if (step==0) then
+					self:AddRow(scroller,"Requesting " ..  currentMission.name .. " completion")
+					G.MarkMissionComplete(currentMission.missionID)
+				elseif (step==1) then
+					self:AddRow(scroller,"Requesting " ..  currentMission.name .. " roll")
+					G.MissionBonusRoll(currentMission.missionID)
+				elseif (step>=2) then
+					self:PrintResults(step==3)
+					self:RefreshFollowerStatus()
+					if true then return end
+					currentMission=tremove(missions)
+					startTimer()
+					return
+				end
+				currentMission.state=step
+			else
+				self:MissionsCleanup()
 			end
 		end
 	end
+	function addon:PrintResults(success)
+		stopTimer()
+--@debug@
+		self:AddRow(scroller,success and C("Mission succeeded","green") or C("Mission failed","red"))
+		self:AddRow(scroller,format("Succes chance was %d%%", currentMission.successChance))
+--@end-debug@
+		if (success) then
+			report:AddRow(format("Mission succeeded. Percent chance was: %d%%", currentMission.successChance),C.Green())
+		else
+			report:AddRow(format("Mission failed. Percent chance was: %d%%", currentMission.successChance),C.Red())
+		end
+		if success then
+			for k,v in pairs(currentMission.rewards) do
+				v.quantity=v.quantity or 0
+				v.multiplier=v.multiplier or 1
+--@debug@
+				self:AddRow(scroller,format("Reward type: = %s",k))
+				for field,value in pairs(v) do
+					self:AddRow(scroller,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)
+				else
+						-- Follower XP reward
+						report:AddIconText(v.icon,v.name)
+				end
+			end
+		end
+		for k,v in pairs(currentMission.followers) do
+			report:AddFollower(v,currentMission.followerXp[v])
+		end
+--@debug@
+		self:AddRow(scroller,"--------------------------------------------------------------------")
+--@end-debug@
+		self:DumpStatus("Dopo missione " .. currentMission.name)
+
+	end
 end

 --- Enable a trace for every function call. It's a VERY heavy debug
@@ -4446,6 +4843,7 @@ function addon:GetScroller(title,type,h,w)
 	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,...)
@@ -4480,7 +4878,15 @@ function addon:DumpFollower(name)
 		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 ..")"  )
@@ -4538,4 +4944,5 @@ function addon:DumpAgeDb()
 	del(t)
 end
 _G.GCF=GCF
+_G.MW=173
 --@end-do-not-package@
diff --git a/doc.txt b/doc.txt
index fb27416..83ed7f0 100644
--- a/doc.txt
+++ b/doc.txt
@@ -32,6 +32,12 @@ Pannelli utili:

 GMF.MissionTab.MissionList.CompleteDialog.BorderFrame.LoadingFrame Loading col tondino

+GMFMissions.CompleteDialog è il fondino nero dietro il pannello con la tipa con la benda
+GMFMissions.CompleteDialog.BorderFrame è il pannello con la tipa con la benda
+GMFMissions.CompleteDialog.BorderFrame.Stage  è lo sfondo colorato
+GMFMissions.CompleteDialog.BorderFrame.Model è la tipa con la benda
+
+

 Dump: value=C_Garrison.GetMissionRewardInfo(91)
 [1]={
@@ -252,3 +258,36 @@ Dump: value=table returned by GetFollowerInfo for a collected follower
 		else
 			HybridScrollFrame_CreateButtons(frame.FollowerList.listScroll, "GarrisonMissionFollowerButtonTemplate", 7, -7, nil, nil, nil, -6);
 		end
+
+
+Fonts:
+* GameFontNormal
+* GameFontNormalSmall
+* GameFontNormalLarge
+* GameFontHighlight
+* GameFontHighlightSmall
+* GameFontHighlightSmallOutline
+* GameFontHighlightLarge
+* GameFontDisable
+* GameFontDisableSmall
+* GameFontDisableLarge
+* GameFontGreen
+* GameFontGreenSmall
+* GameFontGreenLarge
+* GameFontRed
+* GameFontRedSmall
+* GameFontRedLarge
+* GameFontWhite
+* GameFontDarkGraySmall
+* NumberFontNormalYellow
+* NumberFontNormalSmallGray
+* QuestFontNormalSmall
+* DialogButtonHighlightText
+* ErrorFont
+* TextStatusBarText
+* CombatLogFont
+
+Xp bonus:
+570
+593
+