Quantcast

Rdesigned UI with a single big button, integrated mission control

Alar of Daggerspine [01-03-15 - 22:49]
Rdesigned UI with a single big button, integrated mission control
Filename
GarrisonCommander.lua
GarrisonCommander.xml
diff --git a/GarrisonCommander.lua b/GarrisonCommander.lua
index 099af30..588c226 100644
--- a/GarrisonCommander.lua
+++ b/GarrisonCommander.lua
@@ -1,14 +1,23 @@
 local me, ns = ...
 local _G=_G
+--@debug@
+	LoadAddOn("Blizzard_DebugTools")
+--@end-debug@
 local addon=LibStub("LibInit"):NewAddon(me,'AceHook-3.0','AceTimer-3.0','AceEvent-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 xprint=function(...) print("DBG",...) end
 local trace=addon:Wrap("Trace")
-local xprint=function() end
+--@debug@
+local xprint=function(...) print("DBG",...) end
+local xdump=function(d,t) print(t) DevTools_Dump(d) end
+local xtrace=trace
+xprint=function() end
+xdump=function() end
+xtrace=function() end
+--@end-debug@
 local pairs=pairs
 local select=select
 local next=next
@@ -87,71 +96,21 @@ local function capitalize(s)
 	s=tostring(s)
 	return strupper(s:sub(1,1))..strlower(s:sub(2))
 end
--- Name is here just for doc, I will be using the localized one
-
-local _abilities={
-	{
-		["name"] = "Wild Aggression",
-		["icon"] = "Interface\\ICONS\\Spell_Nature_Reincarnation.blp",
-	}, -- [1]
-	{
-		["name"] = "Massive Strike",
-		["icon"] = "Interface\\ICONS\\Ability_Warrior_SavageBlow.blp",
-	}, -- [2]
-	{
-		["name"] = "Group Damage",
-		["icon"] = "Interface\\ICONS\\Spell_Fire_SelfDestruct.blp",
-	}, -- [3]
-	{
-		["name"] = "Magic Debuff",
-		["icon"] = "Interface\\ICONS\\Spell_Shadow_ShadowWordPain.blp",
-	}, -- [4]
-	nil, -- [5]
-	{
-		["name"] = "Danger Zones",
-		["icon"] = "Interface\\ICONS\\spell_Shaman_Earthquake.blp",
-	}, -- [6]
-	{
-		["name"] = "Minion Swarms",
-		["icon"] = "Interface\\ICONS\\Spell_DeathKnight_ArmyOfTheDead.blp",
-	}, -- [7]
-	{
-		["name"] = "Powerful Spell",
-		["icon"] = "Interface\\ICONS\\Spell_Shadow_ShadowBolt.blp",
-	}, -- [8]
-	{
-		["name"] = "Deadly Minions",
-		["icon"] = "Interface\\ICONS\\Achievement_Boss_TwinOrcBrutes.blp",
-	}, -- [9]
-	{
-		["name"] = "Timed Battle",
-		["icon"] = "Interface\\ICONS\\SPELL_HOLY_BORROWEDTIME.BLP",
-	}, -- [10]
-}
-local abilities={}
-
-local function getAbilityName(texture)
-	for i=1,#abilities do
-		if (abilities[i] and abilities[i].icon==texture) then
-			return abilities[i].name
-		end
-	end
-	return "unknown"
-end
 --- upvalues
+--
 local AVAILABLE=AVAILABLE -- "Available"
 local BUTTON_INFO=GARRISON_MISSION_TOOLTIP_NUM_REQUIRED_FOLLOWERS.. " " .. GARRISON_MISSION_PERCENT_CHANCE
 local ENVIRONMENT_SUBHEADER=ENVIRONMENT_SUBHEADER -- "Environment"
 local G=C_Garrison
-local GARRISON_BUILDING_SELECT_FOLLOWER_TITLE=GARRISON_BUILDING_SELECT_FOLLOWER_TITLE -- "Select a Follower";
-local GARRISON_BUILDING_SELECT_FOLLOWER_TOOLTIP=GARRISON_BUILDING_SELECT_FOLLOWER_TOOLTIP -- "Click here to assign a Follower";
-local GARRISON_FOLLOWERS=GARRISON_FOLLOWERS -- "Followers"
-local GARRISON_FOLLOWER_CAN_COUNTER=GARRISON_FOLLOWER_CAN_COUNTER -- "This follower can counter:"
-local GARRISON_FOLLOWER_EXHAUSTED=GARRISON_FOLLOWER_EXHAUSTED -- "Recovering (1 Day)"
-local GARRISON_FOLLOWER_INACTIVE=GARRISON_FOLLOWER_INACTIVE --"Inactive"
-local GARRISON_FOLLOWER_IN_PARTY=GARRISON_FOLLOWER_IN_PARTY
-local GARRISON_FOLLOWER_ON_MISSION=GARRISON_FOLLOWER_ON_MISSION -- "On Mission"
-local GARRISON_FOLLOWER_WORKING=GARRISON_FOLLOWER_WORKING -- "Working
+--local GARRISON_BUILDING_SELECT_FOLLOWER_TITLE=GARRISON_BUILDING_SELECT_FOLLOWER_TITLE -- "Select a Follower";
+--local GARRISON_BUILDING_SELECT_FOLLOWER_TOOLTIP=GARRISON_BUILDING_SELECT_FOLLOWER_TOOLTIP -- "Click here to assign a Follower";
+--local GARRISON_FOLLOWERS=GARRISON_FOLLOWERS -- "Followers"
+--local GARRISON_FOLLOWER_CAN_COUNTER=GARRISON_FOLLOWER_CAN_COUNTER -- "This follower can counter:"
+--local GARRISON_FOLLOWER_EXHAUSTED=GARRISON_FOLLOWER_EXHAUSTED -- "Recovering (1 Day)"
+--local GARRISON_FOLLOWER_INACTIVE=GARRISON_FOLLOWER_INACTIVE --"Inactive"
+--local GARRISON_FOLLOWER_IN_PARTY=GARRISON_FOLLOWER_IN_PARTY
+--local GARRISON_FOLLOWER_ON_MISSION=GARRISON_FOLLOWER_ON_MISSION -- "On Mission"
+--local GARRISON_FOLLOWER_WORKING=GARRISON_FOLLOWER_WORKING -- "Working
 local GARRISON_MISSION_PERCENT_CHANCE="%d%%"-- GARRISON_MISSION_PERCENT_CHANCE
 local GARRISON_MISSION_SUCCESS=GARRISON_MISSION_SUCCESS -- "Success"
 local GARRISON_MISSION_TOOLTIP_NUM_REQUIRED_FOLLOWERS=GARRISON_MISSION_TOOLTIP_NUM_REQUIRED_FOLLOWERS -- "%d Follower mission";
@@ -236,6 +195,8 @@ local FLSIZE=400
 local BIGBUTTON=BIGSIZEW-GCSIZE
 local SMALLBUTTON=BIGSIZEW-GCSIZE
 local GCF
+local GMC
+local GMCUsedFollowers={}
 local GCFMissions
 local GCFBusyStatus
 local GameTooltip=GameTooltip
@@ -250,6 +211,10 @@ local GarrisonMissionButton_SetRewards=GarrisonMissionButton_SetRewards
 local GetItemInfo=GetItemInfo
 local type=type
 local ITEM_QUALITY_COLORS=ITEM_QUALITY_COLORS
+function addon:GetDifficultyColors(perc,usePurple)
+	local q=self:GetDifficultyColor(perc,usePurple)
+	return q.r,q.g,q.b
+end
 function addon:GetDifficultyColor(perc,usePurple)
 	if(perc >90) then
 		return QuestDifficultyColors['standard']
@@ -317,6 +282,39 @@ local function genIteratorByThreat(missionID,threat,tbl)
 	end
 end

+--- Quick backdrop
+--
+local function addBackdrop(f)
+	local backdrop = {
+		bgFile="Interface\\TutorialFrame\\TutorialFrameBackground",
+		edgeFile="Interface\\Tooltips\\UI-Tooltip-Border",
+		tile=true,
+		tileSize=16,
+		edgeSize=16,
+		insets={bottom=7,left=7,right=7,top=7}
+	}
+	f:SetBackdrop(backdrop)
+end
+
+--generic table scan
+
+local function inTable(table, value)
+	if (type(table)~='table') then return false end
+	if (#table > 0) then
+		for i=1,#table do
+			if (value==table[i]) then return true end
+		end
+	else
+		for k,v in pairs(table) do
+			if v == value then
+				return true
+			end
+		end
+	end
+	return false
+end
+
+
 --- Parties storage
 --
 --
@@ -324,12 +322,7 @@ local parties=setmetatable({},{
 	__index=function(t,k) rawset(t,k,{members={},perc=0,full=false}) return t[k] end
 })
 local function inParty(missionID,followerID)
-	local members=parties[missionID].members
-	if (dbg) then print("Party check",missionID) end
-	for i=1,#members do
-		if (dbg) then print("Checking",members[i],"against",followerID) end
-		if (members[i]==followerID) then return true end
-	end
+	return inTable(parties[missionID].members,followerID)
 end
 --- Follower Missions Info
 --
@@ -343,7 +336,7 @@ local openParty,isInParty,pushFollower,removeFollower,closeParty,roomInParty,sto

 do
 	local ID,frames,members,maxFollowers=0,{},{},1
-	---@function [parent=#local] openParty
+	---@function [parent=#party] openParty
 	function openParty(missionID,followers)
 		if (#frames > 0 or #members > 0) then
 			error(format("Unbalanced openParty/closeParty %d %d",#frames,#members))
@@ -355,28 +348,26 @@ do
 		end
 		ID=missionID
 	end
-	---@function [parent=#local] isInParty
+	---@function [parent=#party] isInParty
 	function isInParty(followerID)
-		for i=1,maxFollowers do
-			if (followerID==members[i]) then return true end
-		end
+		return inTable(members,followerID)
 	end

-	---@function [parent=#local] roomInParty
+	---@function [parent=#party] roomInParty
 	function roomInParty()
 		return maxFollowers-#members
 	end

-	---@function [parent=#local] dumpParty
+	---@function [parent=#party] dumpParty
 	function dumpParty()
 		for i=1,3 do
 			if (members[i]) then
-				print(i,addob:GetFollowerData(members[i],'fullname'))
+				print(i,addon:GetFollowerData(members[i],'fullname'))
 			end
 		end
 	end

-	---@function [parent=#local] pushFollower
+	---@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
@@ -391,7 +382,7 @@ do
 			end
 		end
 	end
-	---@function [parent=#local] removeFollowers
+	---@function [parent=#party] removeFollowers
 	function removeFollower(followerID)
 		for i=1,maxFollowers do
 			if (followerID==members[i]) then
@@ -404,7 +395,7 @@ do
 		end
 	end

-	---@function [parent=#local] storeFollowers
+	---@function [parent=#party] storeFollowers
 	function storeFollowers(table)
 		wipe(table)
 		for i=1,#members do
@@ -413,7 +404,7 @@ do
 		return #table
 	end

-	---@function [parent=#local] closeParty
+	---@function [parent=#party] closeParty
 	function closeParty()
 		local perc=select(4,G.GetPartyMissionInfo(ID))
 		for i=1,3 do
@@ -508,13 +499,34 @@ function addon.Garrison_SortMissions_Followers(missionsList)
 	end
 	table.sort(missionsList, comparison);
 end
+function addon.Garrison_SortMissions_Xp(missionsList)
+	local comparison
+	do
+		function comparison(mission1, mission2)
+			local p1=addon:GetMissionData(mission1.missionID,'globalXp')
+			local p2=addon:GetMissionData(mission2.missionID,'globalXp')
+			if (p1==p2) then
+				return strcmputf8i(mission1.name, mission2.name) < 0
+			else
+				return p2 < p1
+			end
+		end
+	end
+	table.sort(missionsList, comparison);
+end

 function addon:OnInitialized()
 --@debug@
 	xprint("OnInitialized")
-	LoadAddOn("Blizzard_DebugTools")
 	self:DebugEvents()
 --@end-debug@
+	for _,b in ipairs(GMFMissionsListScrollFrame.buttons) do
+		local scale=0.8
+		local f,h,s=b.Title:GetFont()
+		b.Title:SetFont(f,h*scale,s)
+		local f,h,s=b.Summary:GetFont()
+		b.Summary:SetFont(f,h*scale,s)
+	end
 	self:CreatePrivateDb()
 	self:SafeRegisterEvent("GARRISON_MISSION_STARTED")
 	self:SafeRegisterEvent("GARRISON_MISSION_BONUS_ROLL_COMPLETE")
@@ -530,12 +542,14 @@ function addon:OnInitialized()
 		Garrison_SortMissions_Chance=L["Success Chance"],
 		Garrison_SortMissions_Followers=L["Number of followers"],
 		Garrison_SortMissions_Age=L["Days since first seen"],
+		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)"])
 	self:AddToggle("BIGSCREEN",true,L["Use big screen"],L["Disabling this will give you the interface from 1.1.8, given or taken. Need to reload interface"])
 	bigscreen=self:GetBoolean("BIGSCREEN")
 	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:Trigger("MSORT")
 	return true
 end
@@ -973,7 +987,7 @@ function addon:MatchMaker(missionID,mission,party)
 	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=addon:GetBoolean("IGM")
+	local skipBusy=self:GetBoolean("IGM")
 	local skipMaxed=self:GetBoolean("IGP")
 	dbg=missionID==(tonumber(_G.MW) or 0)
 	local slots=mission.slots
@@ -1276,23 +1290,49 @@ function addon:BuildMissionCache(id,data)
 			mission.name=G.GetMissionName(id)
 			mission.numFollowers=G.GetMissionMaxFollowers(id)
 			mission.durationSeconds=select(5,G.GetMissionTimers(id))
+			mission.cost=10
 		else
 			mission.name=data.name
 			mission.numFollowers=data.numFollowers
 			mission.durationSeconds=data.durationSeconds
+			mission.cost=data.cost
 		end
+		local _,xp,type,typeDesc,typeIcon,locPrefix,_,enemies=G.GetMissionInfo(id)
 		mission.rank=mission.level < 100 and mission.level or mission.iLevel
-		mission.xp=true
-		mission.resources=false
+		mission.xp=xp
+		mission.xpBonus=0
+		mission.resources=0
+		mission.gold=0
+		mission.followerUpgrade=0
+		mission.itemLevel=0
 		for k,v in pairs(G.GetMissionRewardInfo(id)) do
-			if (not v.followerXP) then mission.xp=false end
-			if (v.currencyID and v.currencyID==GARRISON_CURRENCY) then mission.resource=false end
+			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=1
+						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
-		local _,xp,type,typeDesc,typeIcon,locPrefix,_,enemies=G.GetMissionInfo(id)
 		mission.locPrefix=locPrefix
 		if (not type) then
 --@debug@
-			print("No type",id,data.name)
+			xprint("No type",id,data.name)
 --@end-debug@
 		else
 			self.db.global.types[type]={name=type,description=typeDesc,icon=typeIcon}
@@ -1343,6 +1383,13 @@ function addon:CreatePrivateDb()
 				},
 				runningIndex={
 					["*"]=0
+				},
+				missionControl={
+					allowedRewards = {},
+					itemPrio = {},
+					minimumChance = 75,
+					maxDuration = 24,
+					epicExp = false
 				}
 			}
 		},
@@ -1376,12 +1423,7 @@ end
 function addon:SetClean()
 	dirty=false
 end
-function addon:wipe(i)
---@debug@
-	DevTools_Dump(i)
-	self.privatedb:ResetDB()
---@end-debug@
-end
+
 function addon:WipeMission(missionID)
 	cache.missions[missionID]=nil
 	counters[missionID]=nil
@@ -1400,13 +1442,13 @@ function addon:EventGARRISON_MISSION_NPC_OPENED(event,...)
 --@debug@
 	xprint(event,...)
 --@end-debug@
-	GCF:Show()
+	if (GCF) then GCF:Show() end
 end
 function addon:EventGARRISON_MISSION_NPC_CLOSED(event,...)
 --@debug@
 	xprint(event,...)
 --@end-debug@
-	GCF:Hide()
+	if (GCF) then GCF:Hide() end
 end
 ---
 --@param #string event GARRISON_MISSION_STARTED
@@ -1451,10 +1493,19 @@ end
 function addon:EventGARRISON_MISSION_FINISHED(event,missionID,...)
 --@debug@
 	xprint(event,missionID,...)
-	DevTools_Dump(G.GetPartyMissionInfo(missionID))
+	xdump(G.GetPartyMissionInfo(missionID))
 --@end-debug@
 end

+function addon:EventGARRISON_FOLLOWER_ADDED(event)
+	wipe(followersCache)
+	wipe(followersCacheIndex)
+end
+function addon:EventGARRISON_FOLLOWER_REMOVED(event)
+	wipe(followersCache)
+	wipe(followersCacheIndex)
+end
+
 function addon:EventGARRISON_MISSION_BONUS_ROLL_COMPLETE(event,missionID,completed,success)
 --@debug@
 	xprint(event,missionID,completed,success)
@@ -1578,6 +1629,14 @@ function addon:Shrink(button)
 		f:SetHeight(f.savedHeight)
 	end
 end
+function addon:ShowMissionControl()
+	GarrisonMissionFrame_SelectTab(999)
+	GarrisonMissionFrame.FollowerTab:Hide()
+	GarrisonMissionFrame.FollowerList:Hide()
+	GarrisonMissionFrame.MissionTab:Hide()
+	GarrisonMissionFrame.TitleText:SetText("Garrison Commander Mission Control")
+	GMC:Show()
+end
 local helpwindow -- pseudo static
 function addon:ShowHelpWindow(button)
 	if (not helpwindow) then
@@ -1641,6 +1700,11 @@ Since 2.0.2, the "big screen" mode became optional. If you choosed to disable it
  * Quick selection of which follower ignore for match making<br/>
  * Quick mission list order selection<br/>
 </p>
+<h2>Mission Control:</h2>
+<p>Thanks to Motig which donated the code, we have an auto lancher for mission<br/>
+You specify some criteina mission should satisfy (success chance, rewards type etc) and matching missions will be autosubmitted<br/>
+BE WARNED, feature is |cffff0000EXPERIMENTAL|r</p>
+</br>
 ]]
 if (MP) then
 text=text..[[
@@ -1727,7 +1791,8 @@ function addon:CreateOptionsLayer(...)
 	function frame:Show() self.frame:Show() end
 	return frame
 end
-function addon:AddOptionToOptionsLayer(o,flag)
+function addon:AddOptionToOptionsLayer(o,flag,maxsize)
+	maxsize=tonumber(maxsize) or 120
 	if (not flag) then return end
 	local info=self:GetVarInfo(flag)
 	if (info) then
@@ -1739,13 +1804,25 @@ function addon:AddOptionToOptionsLayer(o,flag)
 			widget:SetValue(value)
 			local color=value and "Green" or "Silver"
 			widget:SetLabel(C(info.name,color))
-			widget:SetWidth(max(widget.text:GetStringWidth(),120))
+			widget:SetWidth(max(widget.text:GetStringWidth(),maxsize))
 		elseif(info.type=="select") then
 			widget=AceGUI:Create("Dropdown")
 			widget:SetValue(self:GetVar(flag))
 			widget:SetLabel(info.name)
 			widget:SetText(info.values[self:GetVar(flag)])
 			widget:SetList(info.values)
+			widget:SetWidth(maxsize)
+		elseif (info.type=="execute") then
+			widget=AceGUI:Create("Button")
+			widget:SetText(info.name)
+			widget:SetWidth(maxsize)
+			widget:SetCallback("OnClick",function(widget,event,value)
+				self[info.func](self,data,value)
+			end)
+		else
+			widget=AceGUI:Create("Label")
+			widget:SetText(info.name)
+			widget:SetWidth(maxsize)
 		end
 		widget:SetCallback("OnValueChanged",function(widget,event,value)
 			if (type(value=='boolean')) then
@@ -1771,7 +1848,7 @@ function addon:Options()
 	GCF=base
 	GCF:SetWidth(BIGSIZEW)
 	GCF:SetPoint("TOP",UIParent,0,-60)
-	base:SetHeight(40)
+	base:SetHeight(bigscreen and 40 or 80)
 	base:EnableMouse(true)
 	GCF:SetMovable(true)
 	GCF:RegisterForDrag("LeftButton")
@@ -1830,6 +1907,11 @@ end
 function addon:IsMissionPage()
 	return GMF:IsShown() and GMFMissionPage:IsShown() and GMFFollowers:IsShown()
 end
+function addon:HookedGarrisonMissionFrame_SelectTab()
+	GMC:Hide()
+	wipe(GMCUsedFollowers)
+
+end
 function addon:HookedGarrisonMissionFrame_HideCompleteMissions()
 	self:BuildMissionsCache(true,true)
 end
@@ -1989,13 +2071,39 @@ function addon:ClonedGarrisonMissionButton_SetRewards(rewards, numRewards)
 end

 local Busystatusmessage
+function addon:BuildMiniMissionButton(frame,i,mission,scale,perc)
+	scale=scale or 0.6
+	local panel=frame.Missions[i]
+	if (not panel) then
+		panel=CreateFrame("Button",nil,frame,"GarrisonCommanderMissionListButtonTemplate")
+		if (i==1) then
+			panel:SetPoint("TOPLEFT",frame.Header,"BOTTOMLEFT")
+		else
+			panel:SetPoint("TOPLEFT",frame.Missions[i-1],"BOTTOMLEFT")
+			panel:SetPoint("TOPRIGHT",frame.Missions[i-1],"BOTTOMRIGHT")
+		end
+		tinsert(frame.Missions,panel)
+		--Creo una riga nuova
+		panel:SetScale(scale)
+		panel.LocBG:SetPoint("LEFT")
+	end
+	panel.info=mission
+	--panel.id=index[missionID]
+	self:FillMissionButton(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:HookedGarrisonFollowerPage_ShowFollower(frame,followerID)
 	local i=0
 	if (not self:IsFollowerList()) then return end
 	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
-	--DevTools_Dump(table.Counters)
+	--xdump(table.Counters)
 	local followerName=self:GetFollowerData(followerID,'name')
 	repeat -- a poor man goto
 		if (type(frame.followerID)=="number") then
@@ -2085,7 +2193,7 @@ function addon:HookedGarrisonFollowerPage_ShowFollower(frame,followerID)
 					panel.LocBG:SetPoint("LEFT")
 				end
 				panel.info=mission
-				panel.id=index[missionID]
+				--panel.id=index[missionID]
 				self:FillMissionButton(panel)
 				local q=self:GetDifficultyColor(perc)
 				panel.Percent:SetFormattedText(GARRISON_MISSION_PERCENT_CHANCE,perc)
@@ -2117,6 +2225,7 @@ function addon:SetUp(...)
 	self:CheckMP()
 	self:CheckGMM()
 	self:Options()
+	self:GMCBuildPanel()
 	self:StartUp()
 end
 local function restore()
@@ -2136,15 +2245,12 @@ function addon:StartUp(...)
 --@end-debug@
 	self:Unhook(GMF,"OnShow")
 	self:PermanentEvents()
-	GCF.Menu=self:CreateOptionsLayer(MP and 'CKMP' or nil,'BIGSCREEN','MOVEPANEL','IGM','IGP','NOFILL','MSORT')
+	GCF.Menu=self:CreateOptionsLayer(MP and 'CKMP' or nil,'BIGSCREEN','MOVEPANEL','IGM','IGP','NOFILL')
+	self:AddOptionToOptionsLayer(GCF.Menu,'MSORT',200)
+	self:AddOptionToOptionsLayer(GCF.Menu,'ShowMissionControl',200)
 	GCF.Menu:SetParent(GCF)
 	GCF.Menu.frame:SetScale(0.6)
-	if (bigscreen) then
-		GCF.Menu:SetPoint("TOPLEFT",GCF.Signature,"TOPRIGHT",10,10)
-	else
-		GCF:SetHeight(60)
-		GCF.Menu:SetPoint("TOPLEFT",GCF,"TOPLEFT",0,-24)
-	end
+	GCF.Menu:SetPoint("TOPLEFT",GCF.Signature,"TOPRIGHT",10,10)
 	GCF.Menu:SetPoint("BOTTOMRIGHT",GCF,"BOTTOMRIGHT",-16,0)
 	GCF.Menu:Show()
 	self:GrowPanel()
@@ -2160,6 +2266,8 @@ function addon:StartUp(...)
 	self:SafeSecureHook("GarrisonMissionFrame_HideCompleteMissions")	-- Mission reward completed
 	self:SafeSecureHook("GarrisonMissionPage_ShowMission")
 	self:SafeSecureHook("GarrisonMissionList_UpdateMissions")
+	self:SafeSecureHook("GarrisonMissionFrame_SelectTab")
+
 	self:SafeHookScript(GMFMissions,"OnShow")--,"GrowPanel")
 	self:SafeHookScript(GMFFollowers,"OnShow")--,"GrowPanel")
 	self:SafeHookScript(GCF,"OnHide","CleanUp",true)
@@ -2344,6 +2452,9 @@ function addon:GetMissionData(missionID,subkey)
 	return missionCache
 end
 function addon:GetFollowerStatusForMission(followerID,skipbusy)
+	if (GMCUsedFollowers[followerID]) then
+		return false
+	end
 	if (not skipbusy) then
 		return true
 	else
@@ -2370,7 +2481,7 @@ function addon:FillMissionPage(missionInfo)
 --@debug@
 	xprint("UpdateMissionPage for",missionID,missionInfo.name,missionInfo.numFollowers)
 --@end-debug@
-	--DevTools_Dump(missionInfo)
+	--xdump(missionInfo)
 	--self:BuildMissionData(missionInfo.missionID.missionInfo)
 	GarrisonMissionPage_ClearParty()
 	local party=parties[missionID]
@@ -2452,15 +2563,19 @@ function addon:GetBiasColor(followerID,missionID,goodcolor)
 end
 function addon:FillFollowerButton(frame,followerID,missionID)
 	if (not frame) then return end
-	for i=1,#frame.Threats do
-		if (frame.Threats[i]) then frame.Threats[i]:Hide() end
+	if (bigscreen) then
+		for i=1,#frame.Threats do
+			if (frame.Threats[i]) then frame.Threats[i]:Hide() end
+		end
+		frame.NotFull:Hide()
 	end
-	frame.NotFull:Hide()
 	if (not followerID) then
 		frame.PortraitFrame.Empty:Show()
-		frame.Name:Hide()
-		frame.Class:Hide()
-		frame.Status:Hide()
+		if (bigscreen) then
+			frame.Name:Hide()
+			frame.Class:Hide()
+			frame.Status:Hide()
+		end
 		frame.PortraitFrame.LevelBorder:SetAtlas("GarrMission_PortraitRing_LevelBorder");
 		frame.PortraitFrame.LevelBorder:SetWidth(58);
 		frame.PortraitFrame.Level:SetText("")
@@ -2472,12 +2587,14 @@ function addon:FillFollowerButton(frame,followerID,missionID)
 	--local info=followers[ID]
 	frame.info=info
 	frame.missionID=missionID
-	frame.Name:Show();
-	frame.Name:SetText(info.name);
-	local color=missionID and self:GetBiasColor(followerID,missionID,"White") or "Yellow"
-	frame.Name:SetTextColor(C[color]())
-	frame.Status:SetText(self:GetFollowerStatus(followerID,true,true))
-	frame.Status:Show()
+	if (bigscreen) then
+		frame.Name:Show()
+		frame.Name:SetText(info.name);
+		local color=missionID and self:GetBiasColor(followerID,missionID,"White") or "Yellow"
+		frame.Name:SetTextColor(C[color]())
+		frame.Status:SetText(self:GetFollowerStatus(followerID,true,true))
+		frame.Status:Show()
+	end
 	if (frame.Class) then
 		frame.Class:Show();
 		frame.Class:SetAtlas(info.classAtlas);
@@ -2496,22 +2613,24 @@ function addon:FillFollowerButton(frame,followerID,missionID)
 	end
 	GarrisonMissionFrame_SetFollowerPortrait(frame.PortraitFrame, info, showItemLevel);
 	-- Counters icon
-	if (missionID and not GMF.MissionTab.MissionList.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 (bigscreen) then
+		if (missionID and not GMF.MissionTab.MissionList.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
+			end
+		else
+			frame.Status:Hide()
 		end
-	else
-		frame.Status:Hide()
 	end
 end
 -- pseudo static
@@ -2520,9 +2639,9 @@ function addon:BuildFollowersButtons(button,bg,limit)
 	if (bg.Party) then return end
 	bg.Party={}
 	for numMembers=1,3 do
-		local f=CreateFrame("Button",nil,bg,"GarrisonCommanderMissionPageFollowerTemplate")
+		local f=CreateFrame("Button",nil,bg,bigscreen and "GarrisonCommanderMissionPageFollowerTemplate" or "GarrisonCommanderMissionPageFollowerTemplateSmall" )
 		if (numMembers==1) then
-			f:SetPoint("BOTTOMLEFT",bg.Percent,"BOTTOMRIGHT",10,0)
+			f:SetPoint("BOTTOMLEFT",button.Rewards[1],"BOTTOMRIGHT",10,0)
 		else
 			f:SetPoint("LEFT",bg.Party[numMembers-1],"RIGHT",10,0)
 		end
@@ -2532,14 +2651,16 @@ function addon:BuildFollowersButtons(button,bg,limit)
 		f:SetScript("OnLeave",GarrisonMissionPageFollowerFrame_OnLeave)
 		f:RegisterForClicks("AnyUp")
 		f:SetScript("OnClick",function(...) self:OnClick_PartyMember(...) end)
-		for numThreats=1,4 do
-			local threatFrame =f.Threats[numThreats];
-			if ( not threatFrame ) then
-				threatFrame = CreateFrame("Frame", nil, f, "GarrisonAbilityCounterTemplate");
-				threatFrame:SetPoint("LEFT", f.Threats[numThreats - 1], "RIGHT", 10, 0);
-				tinsert(f.Threats, threatFrame);
+		if (bigscreen) then
+			for numThreats=1,4 do
+				local threatFrame =f.Threats[numThreats];
+				if ( not threatFrame ) then
+					threatFrame = CreateFrame("Frame", nil, f, "GarrisonAbilityCounterTemplate");
+					threatFrame:SetPoint("LEFT", f.Threats[numThreats - 1], "RIGHT", 10, 0);
+					tinsert(f.Threats, threatFrame);
+				end
+				threatFrame:Hide()
 			end
-			threatFrame:Hide()
 		end
 	end
 	for i=1,3 do bg.Party[i]:SetScale(0.9) end
@@ -2552,9 +2673,6 @@ function addon:BuildFollowersButtons(button,bg,limit)
 		button.Threats[1]:ClearAllPoints()
 		button.Threats[1]:SetPoint("TOPLEFT",165,0)
 	end
-
-
-
 end
 function addon:RenderExtraButton(button,numRewards)
 	local panel=button.gcPANEL
@@ -2577,15 +2695,14 @@ function addon:RenderExtraButton(button,numRewards)
 					frame:Hide()
 				end
 			end
-			if ( missionInfo.locPrefix ) then
-				panel.LocBG:Show();
-				panel.LocBG:SetAtlas(missionInfo.locPrefix.."-List");
-			else
-				panel.LocBG:Hide();
-			end
 		end
 		return
 	end
+	if (not bigscreen) then
+		local position=(numRewards * -65) - 180
+		panel.Party[1]:ClearAllPoints()
+		panel.Party[1]:SetPoint("BOTTOMLEFT",button.Rewards[1],"BOTTOMLEFT", position,0)
+	end
 	local mission=self:GetMissionData(missionID)
 	local party=parties[missionID]
 	if (#party.members==0) then
@@ -2595,27 +2712,19 @@ function addon:RenderExtraButton(button,numRewards)
 	local perc=party.perc
 	local age=tonumber(dbcache.seen[missionID])
 	local notFull=false
-	if (bigscreen) then
-		for i=1,3 do
-			local frame=button.gcPANEL.Party[i]
-			if (i>mission.numFollowers) then
-				frame:Hide()
+	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:FillFollowerButton(frame,party.members[i],missionID)
+				if (bigscreen) then frame.NotFull:Hide() end
 			else
-				if (party.members[i]) then
-					self:FillFollowerButton(frame,party.members[i],missionID)
-					frame.NotFull:Hide()
-				else
-					self:FillFollowerButton(frame,false)
-					frame.NotFull:Show()
-				end
-				frame:Show()
+				self:FillFollowerButton(frame,false)
+				if (bigscreen) then frame.NotFull:Show() end
 			end
-		end
-		if ( mission.locPrefix ) then
-			panel.LocBG:Show();
-			panel.LocBG:SetAtlas(mission.locPrefix.."-List");
-		else
-			panel.LocBG:Hide();
+			frame:Show()
 		end
 	end
 	panel.Percent:SetFormattedText(GARRISON_MISSION_PERCENT_CHANCE,perc)
@@ -2641,34 +2750,18 @@ function addon:RenderExtraButton(button,numRewards)
 	end
 	panel.Age:Show()
 	panel.Percent:Show()
-	if (not bigscreen) then
-		panel:SetPoint("TOPRIGHT",numRewards *-75 - (GMM and 65 or 0),0)
-		panel.Followers:SetFormattedText(GARRISON_MISSION_TOOLTIP_NUM_REQUIRED_FOLLOWERS,mission.numFollowers)
-	end
 end
 function addon:BuildExtraButton(button)
-	if (bigscreen) then
-		local bg=CreateFrame("Button",nil,button,"GarrisonCommanderMissionButton")
-		bg:SetPoint("TOPLEFT",button,"TOPRIGHT")
-		bg:SetPoint("RIGHT",GarrisonMissionFrameMissionsListScrollFrame,"RIGHT",-25,0)
-		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) end
-	else
-		local bg=button.GC
-		if (not bg) then
-			bg=CreateFrame("Button",nil,button,"GarrisonCommanderMissionInfo")
-			bg:SetHeight(button:GetHeight())
-			button.gcPANEL=bg
-			bg.button=button
-			bg:SetScript("OnEnter",function(this) GarrisonMissionButton_OnEnter(this.button,"LeftUp") end)
-			bg:SetScript("OnLeave",function(this) GameTooltip:FadeOut() end)
-		end
-	end
+	local bg=CreateFrame("Button",nil,button,"GarrisonCommanderMissionButton")
+	bg:SetPoint("TOPLEFT",button,"TOPLEFT",0,0)
+	bg:SetPoint("RIGHT",GarrisonMissionFrameMissionsListScrollFrame,"RIGHT",-25,0)
+	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) end
 end
 --function addon:GarrisonMissionButton_SetRewards(button,rewards,numrewards)
 --end
@@ -2754,15 +2847,18 @@ function addon:OnClick_GarrisonMissionFrame_MissionComplete_NextMissionButton(th
 	end
 end
 function addon:OnClick_GarrisonMissionButton(tab,button)
+	if (GMF.MissionTab.MissionList.showInProgress) then
+		return
+	end
 --@debug@
-	trace("Clicked")
+	xtrace("Clicked")
 --@end-debug@
 	if (tab.fromFollowerPage) then
 		GarrisonMissionFrame_SelectTab(1)
 		self:FillMissionPage(tab.info)
 	else
 --@debug@
-		DevTools_Dump(tab.info)
+		xdump(tab.info)
 --@end-debug@
 		self:FillMissionPage(tab.info)
 	end
@@ -2787,69 +2883,84 @@ function addon:RenderButton(button,rewards,numRewards)
 		return
 --@end-debug@
 	end
-	--if (self:IsRewardPage()) then return end
+	local missionID=button.info.missionID
 	if (bigscreen) then
 		local width=GMF.MissionTab.MissionList.showInProgress and BIGBUTTON or SMALLBUTTON
-		button:SetWidth(width)
-		button.LocBG:SetPoint("LEFT")
-	end
-	local tw=button:GetWidth()-165 - (GMM and 65 or 0)
-	if ( button.Title:GetWidth() + button.Summary:GetWidth() + 8 < tw - numRewards * 65 ) then
-		button.Title:SetPoint("LEFT", 165, 5);
+		button:SetWidth(width+600)
+		button.Rewards[1]:SetPoint("RIGHT",button,"RIGHT",-500 - (GMM and 40 or 0),0)
+	end
+	local tw=button:GetWidth() - 165 - 2  + select(4,button.Rewards[1]:GetPoint(1))
+	if (not button.xp) then
+		button.xp=button:CreateFontString(nil, "ARTWORK", "QuestMaprewardsFont")
+		button.xp:SetPoint("TOPRIGHT",button.Rewards[1],"TOPRIGHT")
+		button.xp:SetJustifyH("RIGHT")
+		button.xp:Show()
+
+	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))
+	end
+	--button.Title:SetText("123456789012345678901234567890123456789012345678901234567890") -- Used for design
+	if (button.Title:GetWidth() + button.Summary:GetWidth() + button.xp:GetWidth() < tw - numRewards * 65 ) then
+		button.Title:SetPoint("LEFT", 165, bigscreen and 20 or 30);
 		button.Summary:ClearAllPoints();
 		button.Summary:SetPoint("BOTTOMLEFT", button.Title, "BOTTOMRIGHT", 8, 0);
 	else
-		button.Title:SetPoint("LEFT", 165, 25);
+		button.Title:SetPoint("LEFT", 165, 30);
 		button.Title:SetWidth(tw - numRewards * 65);
 		button.Summary:ClearAllPoints();
 		button.Summary:SetPoint("TOPLEFT", button.Title, "BOTTOMLEFT", 0, -4);
 	end
-	local missionID=button.info.missionID
-	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')
-		local threatIndex=1
-		if (not GMF.MissionTab.MissionList.showInProgress) then
-			button.Env:Show()
-			dbg=missionID==(tonumber(_G.MW) or 0)
-			if (dbg) then self:DumpParty(missionID) end
-			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",GarrisonMissionMechanic_OnEnter)
-					button.Env:SetScript("OnLeave",function() GarrisonMissionMechanicTooltip:Hide() end)
-				else
-					local th=button.GcThreats[threatIndex]
-					if (not th) then
-						th=CreateFrame("Frame",nil,button,"GarrisonAbilityCounterTemplate")
-						th:SetWidth(20)
-						th:SetHeight(20)
-						button.GcThreats[threatIndex]=th
-						th:SetPoint("BOTTOMLEFT",button,165 + 35 * threatIndex,8)
-						th.info=slot
-						th:SetScript("OnEnter",GarrisonMissionMechanic_OnEnter)
-						th:SetScript("OnLeave",function() GarrisonMissionMechanicTooltip:Hide() end)
+	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')
+			local threatIndex=1
+			if (not GMF.MissionTab.MissionList.showInProgress) then
+				button.Env:Show()
+				dbg=missionID==(tonumber(_G.MW) or 0)
+				if (dbg) then self:DumpParty(missionID) end
+				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",GarrisonMissionMechanic_OnEnter)
+						button.Env:SetScript("OnLeave",function() GarrisonMissionMechanicTooltip:Hide() end)
+					else
+						local th=button.GcThreats[threatIndex]
+						if (not th) then
+							th=CreateFrame("Frame",nil,button,"GarrisonAbilityCounterTemplate")
+							th:SetWidth(20)
+							th:SetHeight(20)
+							button.GcThreats[threatIndex]=th
+							th:SetPoint("BOTTOMLEFT",button,165 + 35 * threatIndex,8)
+							th.info=slot
+							th:SetScript("OnEnter",GarrisonMissionMechanic_OnEnter)
+							th:SetScript("OnLeave",function() GarrisonMissionMechanicTooltip:Hide() end)
+						end
+						threatIndex=threatIndex+1
+						th.Icon:SetTexture(slot.icon)
+						self:SetThreatColor(th,missionID)
+						th:Show()
 					end
-					threatIndex=threatIndex+1
-					th.Icon:SetTexture(slot.icon)
-					self:SetThreatColor(th,missionID)
-					th:Show()
 				end
+			else
+				button.Env:Hide()
+			end
+			for i=threatIndex,#button.GcThreats do
+				button.GcThreats[i]:Hide()
 			end
-		else
-			button.Env:Hide()
-		end
-		for i=threatIndex,#button.GcThreats do
-			button.GcThreats[i]:Hide()
 		end
 	end
 	if (numRewards > 0) then
@@ -2863,6 +2974,9 @@ function addon:RenderButton(button,rewards,numRewards)
 			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'))
+				Reward.Quantity:Show()
 			elseif (reward.itemID and reward.quantity==1) then
 				local _,_,q,i=GetItemInfo(reward.itemID)
 				local c=ITEM_QUALITY_COLORS[q]
@@ -2887,6 +3001,7 @@ function addon:RenderButton(button,rewards,numRewards)
 	end
 	self:RenderExtraButton(button,numRewards)
 end
+
 --@do-not-package@
 _G.GAC=addon
 --[[
@@ -3231,3 +3346,490 @@ function addon:GMF_OnDragStop(frame)
 end

 --@end-do-not-package@
+-- Courtesy of Motig
+-- Concept and interface reused with permission
+-- Mission building rewritten from scratch
+local GMC_G = {}
+--GMC_G.frame = CreateFrame('FRAME')
+local aMissions={}
+local aMissionsIndex={}
+
+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) then
+				xprint(missionID,"discarded due to len",mission.durationSeconds /3600)
+				break
+			end -- Mission too long, out of here
+			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]
+			xprint("Checking",criterium)
+			if (criterium) then
+				xprint(i1,i2,"Sorting on ",criterium,m1[criterium] , m2[criterium])
+				if (m1[criterium] ~= m2[criterium]) then
+					xprint(i1,i2,"Sorted on ",criterium,m1[criterium] , m2[criterium])
+					return m1[criterium] > m2[criterium]
+				end
+			end
+		end
+		xprint(i1,i2,"Sorted on level",m1.level , m2.level)
+		return m1.level > m2.level
+	end
+	table.sort(workList,msort)
+end
+
+
+---@function [parent=#GMC] runMission
+local function runMission(missionID)
+	xprint("Asked to start mission",missionID)
+	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
+			local b=GMC.ml.Missions[i]
+			b:Disable()
+			b:SetAlpha(0.5)
+			b:SetScript("OnClick",nil)
+			if (party.full) then
+				for j=1,#party.members do
+					G.AddFollowerToMission(party.missionID, party.members[j])
+				end
+				G.StartMission(party.missionID)
+				PlaySound("UI_Garrison_CommandTable_MissionStart")
+			end
+		end
+	end
+end
+local timeElapsed=0
+local done=false
+local co=false
+function addon:GMCMissionPerformer(this,elapsed)
+	timeElapsed = timeElapsed + elapsed
+	if (#aMissions == 0 ) then
+		if timeElapsed >= 2 then
+			self:Unhook(GMC,"OnUpdate")
+			this.progressText:SetText(READY)
+			this.progressText:SetTextColor(C.Green())
+		end
+		return
+	end
+	if (timeElapsed >=0.25) then
+		if (not co) then
+			co=coroutine.wrap(self.GMCMissionAssign)
+		end
+		local rc,currentmission=pcall(co,self,this)
+		if (not rc) then
+			xprint("Coroutine error",currentmission)
+		end
+		if (currentmission and type(currentmission)=='number') then
+			this.progressText:SetFormattedText("Processing mission %d of %d",currentmission,#aMissions)
+			xprint("Coroutine returned",currentmission)
+		else
+			co=nil
+			xprint("Unhooking")
+			self:Unhook(GMC,"OnUpdate")
+			xdump(GMC.ml.parties)
+		end
+		timeElapsed=0
+	end
+end
+function addon:GMCMissionAssign(...)
+	local x=0
+	for i=1,#aMissions do
+		local missionID=aMissions[i]
+		local party={members={},perc=0}
+		local mission=GMF.MissionTab.MissionList.availableMissions[aMissionsIndex[missionID]]
+		addon:MatchMaker(missionID,nil,party) -- I need my mission data
+		if ( party.full and party.perc >= GMC.settings.minimumChance) then
+			x=x+1
+			local b=self:BuildMiniMissionButton(GMC.ml,x,mission,bigscreen and 1 or 0.9,party.perc)
+			b:SetScript("OnClick",function(...) runMission(missionID) end)
+			b:Enable()
+			b:SetAlpha(1)
+			for i=1,#party.members do
+				GMCUsedFollowers[party.members[i]]=true
+			end
+			party.missionID=missionID
+			GMC.ml.Parties[x]=party
+		end
+		coroutine.yield(i)
+	end
+end
+
+function addon:GMCBuildPanel()
+	GMC = CreateFrame('FRAME', 'GMCOptions', GarrisonMissionFrame)
+	GMC.settings=dbcache.missionControl
+	GMC:SetPoint('CENTER')
+	GMC:SetSize(GarrisonMissionFrame:GetWidth(), GarrisonMissionFrame:GetHeight())
+	GMC:Hide()
+	GMC.startButton = CreateFrame('BUTTON', 'GarrisonMissionControl_Start', GMC, 'GameMenuButtonTemplate')
+	GMC.startButton:SetText('Calculate')
+	GMC.startButton:SetWidth(148)
+	GMC.startButton:SetPoint('BOTTOMLEFT', 40,50)
+	GMC.startButton:SetScript('OnClick', function()
+		addon:GMCCreateMissionList(aMissions)
+		wipe(GMCUsedFollowers)
+		wipe(GMC.ml.Parties)
+		for i=1,#GMC.ml.Missions do GMC.ml.Missions[i]:Hide() end
+		if (#aMissions>0) then
+			GMC.progressText:SetFormattedText(L["Processing mission %d of %d"],1,#aMissions)
+			-- Preparo l'indice
+			local list=GMF.MissionTab.MissionList.availableMissions
+			for j=1,#list do
+				aMissionsIndex[list[j].missionID]=j
+			end
+		else
+			GMC.progressText:SetText("No mission matches your criteria")
+			GMC.progressText:SetTextColor(C.Red())
+		end
+		self:RawHookScript(GMC,'OnUpdate',"GMCMissionPerformer")
+		GMC.progressText:Show()
+	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', 'GarrisonMissionControl_Start', GMC, 'GameMenuButtonTemplate')
+	GMC.runButton:SetText('Send all mission at once')
+	GMC.runButton:SetWidth(148)
+	GMC.runButton:SetPoint('BOTTOMLEFT', 240,50)
+	GMC.runButton:SetScript('OnClick', runMission)
+	GMC.runButton:Disable()
+	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",10,-10)
+	rewards:SetPoint("TOPLEFT",priorities,"TOPRIGHT",bigscreen and 50 or 10,0)
+	list:SetPoint("TOPLEFT",chance,"TOPRIGHT",bigscreen and 50 or 10,0)
+	list:SetPoint("RIGHT",GMF,-25,0)
+	self:GMCupdateOptions()
+end
+function addon:GMCBuildChance()
+	--Chance
+	GMC.cf = CreateFrame('FRAME', nil, GMC)
+	GMC.cf:SetSize(256, 180)
+
+	GMC.cp = GMC.cf:CreateTexture(nil, 'BACKGROUND')
+	GMC.cp:SetTexture('Interface\\Garrison\\GarrisonMissionUI2.blp')
+	GMC.cp:SetAtlas('GarrMission-AllianceChest')
+	GMC.cp:SetSize(209-(209*0.25), 155-(155*0.25))
+	GMC.cp:SetPoint('CENTER', 0, 0)
+
+	GMC.cc = GMC.cf:CreateFontString()
+	GMC.cc:SetFontObject('GameFontNormalHuge')
+	GMC.cc:SetText('Success Chance')
+	GMC.cc:SetPoint('TOP', 0, -10)
+	GMC.cc:SetTextColor(1, 1, 1)
+
+	GMC.ct = GMC.cf:CreateFontString()
+	GMC.ct:SetFontObject('ZoneTextFont')
+	GMC.ct:SetText('50%')
+	GMC.ct:SetPoint('CENTER', 0, 0)
+	GMC.ct:SetTextColor(0, 1, 0)
+
+	GMC.cs = CreateFrame('Slider', 'GMC_Succes_Slider', GMC.cf, 'OptionsSliderTemplate')
+	GMC.cs:SetWidth(128)
+	GMC.cs:SetHeight(20)
+	GMC.cs:SetOrientation('HORIZONTAL')
+	GMC.cs:SetPoint('BOTTOM', 0, 0)
+	GMC.cs:SetMinMaxValues(0, 100)
+	--f.cs:SetValue(32)
+	GMC.cs:SetValueStep(1)
+	_G[GMC.cs:GetName() .. 'Low']:SetText('0')
+	_G[GMC.cs:GetName() .. 'High']:SetText('100')
+	_G[GMC.cs:GetName() .. 'Text']:SetText('Minimum chance to start mission.')
+	GMC.cs:SetScript('OnValueChanged', function(self, value)
+			local value = math.floor(value)
+			GMC.ct:SetText(value..'%')
+			GMC.settings.minimumChance = value
+	end)
+	return GMC.cf
+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.cf = GMC.tf:CreateTexture(nil, 'BACKGROUND')
+	--bb:SetTexture('Interface\\Timer\\Challenges-Logo.blp')
+	--bb:SetTexture('dungeons\\textures\\devices\\mm_clockface_01.blp')
+	GMC.cf:SetTexture('World\\Dungeon\\Challenge\\clockRunes.blp')
+	GMC.cf:SetSize(110, 110)
+	GMC.cf:SetPoint('CENTER', 0, 0)
+	GMC.cf:SetBlendMode('ADD')
+
+	GMC.mdt = GMC.tf:CreateFontString()
+	GMC.mdt:SetFontObject('GameFontNormalHuge')
+	GMC.mdt:SetText('Mission Duration')
+	GMC.mdt:SetPoint('TOP', 0, -10)
+	GMC.mdt:SetTextColor(1, 1, 1)
+
+	GMC.mt = GMC.tf:CreateFontString()
+	GMC.mt:SetFontObject('ZoneTextFont')
+	GMC.mt:SetText('24h')
+	GMC.mt:SetPoint('CENTER', 0, 0)
+	GMC.mt:SetTextColor(1, 1, 1)
+
+	GMC.ms = CreateFrame('Slider', 'GMC_Time_Slider', GMC.tf, 'OptionsSliderTemplate')
+	GMC.ms:SetWidth(128)
+	GMC.ms:SetHeight(20)
+	GMC.ms:SetOrientation('HORIZONTAL')
+	GMC.ms:SetPoint('BOTTOM', 0, 0)
+	GMC.ms:SetMinMaxValues(1, 24)
+	--f.ms:SetValue(24)
+	GMC.ms:SetValueStep(1)
+	_G[GMC.ms:GetName() .. 'Low']:SetText('1')
+	_G[GMC.ms:GetName() .. 'High']:SetText('24')
+	_G[GMC.ms:GetName() .. 'Text']:SetText('Maximum mission duration.')
+	GMC.ms:SetScript('OnValueChanged', function(self, value)
+			local value = math.floor(value)
+			local c = 1-(value*(1/24))
+			if c < 0.3 then c = 0.3 end
+			GMC.mt:SetTextColor(1, c, c)
+			GMC.mt:SetText(value..'h')
+			GMC.settings.maxDuration = value
+	end)
+	return GMC.tf
+end
+function addon:GMCBuildRewards()
+	--Allowed rewards
+	GMC.aif = CreateFrame('FRAME', nil, GMC)
+	GMC.aif:SetSize(256, 180)
+	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:SetPoint('BOTTOM', 0, 0)
+	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'}
+	}
+
+	GMC.ignoreFrames = {}
+	local y=14
+	for i = 1, 5 do
+			local x = -44 + (i-1) %3 *44
+			if i == 4 then y = -28 end
+			local frame = CreateFrame('BUTTON', nil, GMC.aif, 'ItemButtonTemplate')
+			frame:SetScale(1.5, 1.5)
+			frame:SetPoint('CENTER', x, y)
+			frame.icon:SetTexture(t[i].i)
+			frame.key=t[i].key
+			frame.tooltil=t[i].t
+			frame:SetScript('OnClick', function(self)
+				if not self.icon:IsDesaturated() then
+					self.icon:SetDesaturated(true)
+					GMC.settings.allowedRewards[self.key] = false
+				else
+					self.icon:SetDesaturated(false)
+					GMC.settings.allowedRewards[self.key]=true
+				end
+			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
+	end
+	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
+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
+	)
+	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
+end
+
+
+
+
+function addon:GMCupdateOptions()
+	GMC.cs:SetValue(GMC.settings.minimumChance)
+	GMC.ms:SetValue(GMC.settings.maxDuration)
+
+	for i = 1, 5 do
+		local icon=GMC.ignoreFrames[i]
+		if (not GMC.settings.allowedRewards[icon.key]) then
+			icon.icon:SetDesaturated(true)
+		end
+	end
+	prioRefresh()
+end
diff --git a/GarrisonCommander.xml b/GarrisonCommander.xml
index 032901c..f19ca17 100644
--- a/GarrisonCommander.xml
+++ b/GarrisonCommander.xml
@@ -102,7 +102,7 @@
 		</Layers>
 	</Frame>
 	<Frame name="GarrisonCommanderTitle" inherits="GarrisonCommanderBackground" virtual="true">
-		<Size x="150" y="32"/>
+		<Size x="150" y="70"/>
 		<Frames>
 			<Button parentKey="help" inherits="UIPanelInfoButton">
 				<Anchors>
@@ -120,7 +120,7 @@
 					<TexCoords left="0" right="0.5" top="0.5" bottom="1"/>
 				</Texture>
 				<FontString parentKey="Signature" inherits="QuestTitleFontBlackShadow" justifyH="LEFT" justifyV="TOP" text="Garrison Commander" >
-					<Size x="200" y="32"/>
+					<Size x="100" y="64"/>
 					<Anchors>
 						<Anchor point="TOPLEFT" relativeKey="$parent.Shield" relativePoint="TOPRIGHT" x="5" y="0"/>
 					</Anchors>
@@ -128,6 +128,16 @@
 			</Layer>
 		</Layers>
 	</Frame>
+	<Button name="GarrisonCommanderMissionPageFollowerTemplateSmall" virtual="true">
+		<Size x="70" y="58"/>
+		<Frames>
+			<Frame parentKey="PortraitFrame" inherits="GarrisonFollowerMissionPortraitTemplate">
+				<Anchors>
+					<Anchor point="LEFT"/>
+				</Anchors>
+			</Frame>
+		</Frames>
+	</Button>
 	<Button name="GarrisonCommanderMissionPageFollowerTemplate" inherits="GarrisonMissionPageFollowerTemplate" virtual="true">
 		<Size x="170" y="58"/>
 		<Layers>
@@ -195,21 +205,24 @@
 			</Layer>
 		</Layers>
 	</Frame>
-	<Button name="GarrisonCommanderMissionButton" inherits="GarrisonCommanderBackground" virtual="true">
-		<Size x="600" y="80"/>
+	<!--
+	inherits="GarrisonCommanderBackground"
+	-->
+	<Button name="GarrisonCommanderMissionButton"  virtual="true">
+		<Size x="1120" y="80"/>
 		<Layers>
 			<Layer level="ARTWORK">
 				<FontString parentKey="Age" inherits="GameFontHighlightSmall" justifyH="CENTER" justifyV="TOP" >
 					<Size x="60" y="70"/>
 					<Anchors>
-						<Anchor point="TOPLEFT" relativeKey="$parent" relativePoint="TOPLEFT" x="10" y="-5"/>
+						<Anchor point="TOPLEFT" relativeKey="$parent" relativePoint="TOPLEFT" x="70" y="-5"/>
 					</Anchors>
 					<Color r="0.698" g="0.941" b="1" a="1"/>
 				</FontString>
 				<FontString parentKey="Percent" inherits="NumberFontNormalHuge" justifyH="RIGHT" justifyV="BOTTOM" >
 					<Size x="60" y="70"/>
 					<Anchors>
-						<Anchor point="BOTTOMLEFT" relativeKey="$parent" relativePoint="BOTTOMLEFT" x="0" y="10"/>
+						<Anchor point="BOTTOMLEFT" relativeKey="$parent" relativePoint="BOTTOMLEFT" x="60" y="10"/>
 					</Anchors>
 				</FontString>
 			</Layer>