Quantcast

First batch of shipyard features

Alar of Daggerspine [07-11-15 - 22:52]
First batch of shipyard features

Signed-off-by: Alar of Daggerspine <alar@aspide.it>
Filename
CHANGELOG.txt
Debug.lua
FollowerCache.lua
GarrisonCommander-Broker/ldb.lua
GarrisonCommander.lua
Init.lua
MissionCache.lua
MissionCompletion.lua
ShipYard.lua
Widgets.lua
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 20fbbd4..c20e6e9 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,5 +1,10 @@
 *GarrisonCommander helps you when choosing the right follower for the right mission*

+* *2.6.6*
+Feature: Quick mission completion enabled for shipyard
+Feature: In Ship missions mission expire time added
+Fix: Sometimes interacting with shipyard raised a protection issue
+More shipyard feature incoming
 * *2.6.5*
 Feature: Garrison Broker is now aware of enhanced Garrison Cache sizes (750 and 1000)
 Feature: Ship list enhanced with "xp to go"
diff --git a/Debug.lua b/Debug.lua
index 34d52fe..7eb3e2c 100644
--- a/Debug.lua
+++ b/Debug.lua
@@ -80,6 +80,7 @@ function m:AddRow(text,...)
 	self:AddChild(l)
 	return l
 end
+--[[
 function m:AddIconText(icon,text,qt)
 	local l=AceGUI:Create("InteractiveLabel")
 	l:SetFontObject(GameFontNormalSmall)
@@ -104,6 +105,7 @@ function m:AddItem(itemID,qt)
 		return self:AddIconText(itemtexture,itemlink)
 	end
 end
+--]]
 function addon:GetScroller(title,type,h,w)
 	h=h or 800
 	w=w or 400
diff --git a/FollowerCache.lua b/FollowerCache.lua
index bd163b2..980bf3b 100644
--- a/FollowerCache.lua
+++ b/FollowerCache.lua
@@ -204,6 +204,13 @@ function cache:GetFollowersWithCounterFor(threat)
 end

 -- Addon level proxies
+function addon:GetAnyData(followerType,...)
+	if followerType== LE_FOLLOWER_TYPE_GARRISON_6_0 then
+		return self:GetFollowerData(...)
+	else
+		return self:GetShipData(...)
+	end
+end
 function addon:GetFollowerData(followerID,key,default)
 	return module.followerCache:GetFollowerData(followerID,key,default)
 end
diff --git a/GarrisonCommander-Broker/ldb.lua b/GarrisonCommander-Broker/ldb.lua
index 8e232d7..c919a06 100644
--- a/GarrisonCommander-Broker/ldb.lua
+++ b/GarrisonCommander-Broker/ldb.lua
@@ -15,7 +15,6 @@ local print=print
 --[===[@non-debug@
 print=function() end
 --@end-non-debug@]===]
-print("Garrison-Broker")
 local L=LibStub("AceLocale-3.0"):GetLocale(me,true)
 --local addon=LibStub("AceAddon-3.0"):NewAddon(me,"AceTimer-3.0","AceEvent-3.0","AceConsole-3.0") --#addon
 local addon=LibStub("LibInit"):NewAddon(me,"AceTimer-3.0","AceEvent-3.0","AceConsole-3.0","AceHook-3.0") --#addon
@@ -289,9 +288,7 @@ function addon:SetDbDefaults(default)
 		cachesize={["*"]=false},
 		dbversion=1
 	}
-	default.profile={
-		allowedWorkOrders={["*"]=true}
-	}
+	default.profile['allowedWorkOrders']={["*"]=true}
 end
 function addon:OnInitialized()
 	if dbversion>self.db.realm.dbversion then
@@ -319,17 +316,16 @@ function addon:OnInitialized()
 	self:RegisterEvent("ZONE_CHANGED_NEW_AREA")
 	self:RegisterEvent("SHIPMENT_CRAFTER_INFO")
 	self:RegisterEvent("SHOW_LOOT_TOAST")
-	self:RegisterEvent("QUEST_AUTOCOMPLETE",print)
-	self:RegisterEvent("QUEST_COMPLETE",print)
-	self:RegisterEvent("QUEST_FINISH",print)
-	self:RegisterEvent("QUEST_TURNED_IN",print)
+	--self:RegisterEvent("QUEST_AUTOCOMPLETE",print)
+	--self:RegisterEvent("QUEST_COMPLETE",print)
+	--self:RegisterEvent("QUEST_FINISH",print)
+	self:RegisterEvent("QUEST_TURNED_IN")
 	--self:RegisterEvent("SHIPMENT_CRAFTER_REAGENT_UPDATE",print)
 	self:AddLabel(GARRISON_NUM_COMPLETED_MISSIONS)
 	self:AddToggle("OLDINT",false,L["Use old interface"],L["Uses the old, more intrusive interface"])
 	self:AddToggle("SHOWNEXT",false,L["Show next toon"],L["Show the next toon whicg will complete a mission"])
 	self:AddSlider("FREQUENCY",5,1,60,L["Update frequency"])
 	frequency=self:GetNumber("FREQUENCY",5)
-	print("OnInitialized")
 	self:ScheduleTimer("DelayedInit",5)
 end
 function addon:ApplyFREQUENCY(value)
@@ -374,7 +370,6 @@ function addon:GetImprovedCacheSize()
 end

 function addon:OnEnabled()
-	print("OnEnabled")
 	self:ScheduleTimer("DelayedInit",5)
 end
 function addon:Gradient(perc)
diff --git a/GarrisonCommander.lua b/GarrisonCommander.lua
index b148f58..1fe06e4 100644
--- a/GarrisonCommander.lua
+++ b/GarrisonCommander.lua
@@ -128,6 +128,7 @@ local BUSY_MESSAGE_FORMAT=L["Only first %1$d missions with over %2$d%% chance of
 local BUSY_MESSAGE=format(BUSY_MESSAGE_FORMAT,MAXMISSIONS,MINPERC)
 -- to be rmoved in 60200
 local LE_FOLLOWER_TYPE_GARRISON_6_0=_G.LE_FOLLOWER_TYPE_GARRISON_6_0
+local LE_FOLLOWER_TYPE_SHIPYARD_6_2=_G.LE_FOLLOWER_TYPE_SHIPYARD_6_2

 local function splitFormat(base)
 	local i,s=base:find("|4.*:.*;")
@@ -409,19 +410,19 @@ function addon:OnInitialized()
 	self:AddLabel("Developers options")
 	self:AddToggle("DBG",false, "Enable Debug")
 	self:AddToggle("TRC",false, "Enable Trace")
+	self:AddOpenCmd("show","showdata","Prints a mission score")
 --@end-debug@
 	self:Trigger("MSORT")
-	self:AddOpenCmd("show","showdata","Prints a mission score")
 	LoadAddOn("GarrisonCommander-Broker")
 --@debug@
-	print("Sanity checks")
-	print(self:GetAgeColor(1/0))
-	print(self:GetAgeColor(0/0))
-	print(self:GetAgeColor(GetTime()+100))
-	print(type(1/0))
-	print(type(0/0))
-	print(pcall(format,"%03d %03d",1/0,0/0))
-	print(pcall(format,"%03d %03d",tonumber(1/0) or 1,tonumber(0/0) or 2))
+	assert(self:GetAgeColor(1/0))
+	assert(self:GetAgeColor(0/0))
+	assert(self:GetAgeColor(GetTime()+100))
+	assert(type(1/0)==nil)
+	assert(type(0/0)==nil)
+	assert("stringa"~=nil)
+	assert("stringa"==nil or true)
+	assert(pcall(format,"%03d %03d",tonumber(1/0) or 1,tonumber(0/0) or 2))
 --@end-debug@

 	return true
@@ -1397,11 +1398,7 @@ function addon:HookedGarrisonFollowerListButton_OnClick(frame,button)
 				self:HookedGarrisonFollowerPage_ShowFollower(frame.info,frame.info.followerID)
 			end
 		end
-		if ns.toc <60200 then
-			self:ScheduleTimer("HookedGarrisonFollowerButton_UpdateCounters",0.2,frame,frame.info,false)
-		else
-			self:ScheduleTimer("HookedGarrisonFollowerButton_UpdateCounters",0.2,GMF,frame,frame.info,false)
-		end
+		self:ScheduleTimer("HookedGarrisonFollowerButton_UpdateCounters",0.2,GMF,frame,frame.info,false)
 		self:ShowUpgradeButtons()
 	end
 end
@@ -1638,12 +1635,12 @@ function addon:SetUp(...)
 	tabCF:SetPoint('TOPLEFT',GCF,'TOPRIGHT',0,-60)
 	tabMC:SetPoint('TOPLEFT',GCF,'TOPRIGHT',0,-110)
 	local ref=GMFMissions.CompleteDialog.BorderFrame.ViewButton
-	local bt = CreateFrame('BUTTON','GCQuickMissionCompletionButton', ref, 'UIPanelButtonTemplate')
+	local bt = CreateFrame('BUTTON',nil, ref, 'UIPanelButtonTemplate')
 	bt:SetWidth(300)
 	bt:SetText(L["Garrison Comander Quick Mission Completion"])
 	bt:SetPoint("CENTER",0,-50)
-	addon:ActivateButton(bt,"MissionComplete",L["Complete all missions without confirmation"])
 	bt.missionType=LE_FOLLOWER_TYPE_GARRISON_6_0
+	addon:ActivateButton(bt,"MissionComplete",L["Complete all missions without confirmation"])
 	return self:StartUp()
 	--collectgarbage("step",10)
 --/Interface/FriendsFrame/UI-Toast-FriendOnlineIcon
@@ -1770,43 +1767,38 @@ function addon:PermanentEvents()
 	-- Follower button enhancement in follower list
 	self:SafeSecureHook("GarrisonFollowerButton_UpdateCounters")
 end
-function addon:checkMethod(method,hook)
-	if (type(self[method])=="function") then
---@debug@
-		--print("Hooking ",hook,"to self:" .. method)
---@end-debug@
-		return true
---@debug@
-	else
-		--print("Hooking ",hook,"to print")
---@end-debug@
-	end
+function addon:checkHandler(handler)
+	return type(handler)=='function' or type(self[handler])=='function'
 end
 function addon:SafeRegisterEvent(event)
-	local method="Event"..event
-	if (self:checkMethod(method,event)) then
-		return self:RegisterEvent(event,method)
+	local handler="Event"..event
+	if (self:checkHandler(handler,event)) then
+		return self:RegisterEvent(event,handler)
 --@debug@
 	else
 		return self:RegisterEvent(event,print)
 --@end-debug@
 	end
 end
-function addon:SafeSecureHook(tobehooked,method)
-	if (self:IsHooked(tobehooked)) then return end
-	method=method or "Hooked"..tobehooked
-	if (self:checkMethod(method,tobehooked)) then
-		return self:SecureHook(tobehooked,method)
+function addon:SafeSecureHook(object,method,handler)
+	if (self:IsHooked(object,method)) then return end
+	if type(object) == "string" then
+		method, handler, object = object, method, nil
+	end
+	handler=handler or "Hooked"..method
+	if (self:checkHandler(handler)) then
+		return self:SecureHook(object,method,handler)
 --@debug@
 	else
+		print(object,method,handler)
 		do
-			local hooked=tobehooked
-			return self:SecureHook(tobehooked,function(...) print(hooked,...) end)
+			local hooked=method
+			return self:SecureHook(object,method,function(...) print(hooked,...) end)
 		end
 --@end-debug@
 	end
 end
-function addon:SafeHookScript(frame,hook,method,postHook)
+function addon:SafeHookScript(frame,method,handler,postHook)
 	local name="Unknown"
 	if (type(frame)=="string") then
 		name=frame
@@ -1817,35 +1809,48 @@ function addon:SafeHookScript(frame,hook,method,postHook)
 		end
 	end
 	if (frame) then
-		--This allow to change a hook, for example to substitute an one time init with the standard routine
-		if (self:IsHooked(frame,hook)) then self:Unhook(frame,hook)	end
-		if (method) then
+		--This allow to change a method, for example to substitute an one time init with the standard routine
+		if (self:IsHooked(frame,method)) then self:Unhook(frame,method)	end
+		if (handler) then
 			if (postHook) then
-				self:SecureHookScript(frame,hook,method)
+				self:SecureHookScript(frame,method,handler)
 			else
-				self:HookScript(frame,hook,method)
+				self:HookScript(frame,method,handler)
 			end
 		else
 			if (postHook) then
-				self:SecureHookScript(frame,hook,function(...) self:ScriptTrace(name,hook,...) end)
+				self:SecureHookScript(frame,method,function(...) self:ScriptTrace(name,method,...) end)
 			else
-				self:HookScript(frame,hook,function(...) self:ScriptTrace(name,hook,...) end)
+				self:HookScript(frame,method,function(...) self:ScriptTrace(name,method,...) end)
 			end
 		end
 	end
 end
 local converter=CreateFrame("Frame"):CreateTexture()
-function addon:GetFollowerTexture(followerID)
-	local rc,iconID=pcall(self.GetFollowerData,self,followerID,"portraitIconID")
-	if rc then
-		if iconID then
-			converter:SetToFileData(iconID)
-			return converter:GetTexture()
-		end
-		return "Interface\\Garrison\\Portraits\\FollowerPortrait_NoPortrait"
+local shipconv=CreateFrame("Frame",nil,nil,"GarrisonShipMissionCompleteFollowerTemplate")
+function addon:GetFollowerTexture(followerID,followerType)
+	followerType=followerType or LE_FOLLOWER_TYPE_GARRISON_6_0
+	if (followerType==LE_FOLLOWER_TYPE_GARRISON_6_0) then
+		local rc,iconID=pcall(self.GetAnyData,self,followerType,followerID,"portraitIconID")
+		if rc then
+			if iconID then
+				converter:SetToFileData(iconID)
+				return converter:GetTexture()
+			end
+		end
 	else
-		return "Interface\\Garrison\\Portraits\\FollowerPortrait_NoPortrait"
+		local rc,texPrefix=pcall(self.GetAnyData,self,followerType,followerID,"texPrefix")
+		print(rc,texPrefix)
+		if rc then
+			if texPrefix then
+				shipconv.Portrait:SetAtlas(texPrefix)
+				print(shipconv.Portrait:GetTexture())
+				return shipconv.Portrait:GetTexture()
+			end
+		end
 	end
+		return followerType==LE_FOLLOWER_TYPE_GARRISON_6_0 and "Interface\\Garrison\\Portraits\\FollowerPortrait_NoPortrait"
+				or "Interface\\Garrison\\Portraits\\Ships_CargoShip-Portrait"
 end

 function addon:CleanUp()
@@ -1856,7 +1861,7 @@ function addon:CleanUp()
 	self:UnhookAll()
 	self:CancelAllTimers()
 	self:RemoveMenu()
-	self:HookScript(GMF,"OnSHow","StartUp",true)
+	self:HookScript(GMF,"OnShow","StartUp",true)
 	self:PermanentEvents() -- Reattaching permanent events
 	if (GarrisonFollowerTooltip.fs) then
 		GarrisonFollowerTooltip.fs:Hide()
@@ -1925,7 +1930,8 @@ local GARRISON_MISSION_ID=GARRISON_MISSION_ENVIRONMENT:sub(1,10)..'MissionID:|r
 function addon:FillMissionPage(missionInfo)
 	if type(missionInfo)=="number" then missionInfo=self:GetMissionData(missionInfo) end
 	if not missionInfo then return end
-	local stage=GMF.MissionTab.MissionPage.Stage
+	local missionType=missionInfo.followerTypeID
+	local stage=missionType==LE_FOLLOWER_TYPE_GARRISON_6_0 and  GMF.MissionTab.MissionPage.Stage or GSF.MissionTab.MissionPage.Stage
 	if not stage.expires then
 		stage.expires=stage:CreateFontString()
 		stage.expires:SetFontObject(stage.MissionEnv:GetFontObject())
@@ -1945,6 +1951,10 @@ if not stage.missionid then
 --@end-debug@
 	if( IsControlKeyDown()) then self:Print("Shift key, ignoring mission prefill") return end
 	if (self:GetBoolean("NOFILL")) then return end
+	if missionType==LE_FOLLOWER_TYPE_SHIPYARD_6_2 then
+		print("SHip Mission",missionInfo)
+		return
+	end
 	local missionID=missionInfo.missionID
 --@debug@
 	print("UpdateMissionPage for",missionID,missionInfo.name,missionInfo.numFollowers)
@@ -2071,7 +2081,10 @@ function addon:RenderFollowerButton(frame,followerID,missionID,b,t)
 	frame.PortraitFrame.Level:SetTextColor(1,1,1,1)
 	frame.PortraitFrame.Portrait:Show()
 	local info=self:GetFollowerData(followerID)
-	if (not info) then return end
+	if (not info) then
+		print("Unable to find follower",followerID)
+	return
+	end
 	frame.info=info
 	frame.missionID=missionID
 	if (frame.Name) then
@@ -2099,9 +2112,9 @@ function addon:RenderFollowerButton(frame,followerID,missionID,b,t)
 		showItemLevel = false;
 	end
 	local rc,message= pcall(GarrisonMissionFrame_SetFollowerPortrait,frame.PortraitFrame, info, false);
---@debug@
+--@debug@
 	if not rc then print(message) end
---@end-debug@
+--@end-debug@
 	-- Counters icon
 	if (frame.Name and frame.Threats) then
 		if (missionID and not GMFMissions.showInProgress) then
@@ -2487,6 +2500,7 @@ function over.GarrisonMissionButton_SetRewards(self, rewards, numRewards)
 					Reward.Quantity:Show();
 				else
 					local name,link,quality,iLevel,level=GetItemInfo(reward.itemID)
+					iLevel=addon:GetTrueLevel(reward.itemID,iLevel)
 					if (name) then
 						if (iLevel<500 and reward.quantity) then
 							Reward.Quantity:SetText(reward.quantity);
@@ -2709,7 +2723,11 @@ function addon:DrawSingleSlimButton(page,button,progressing,bigscreen)
 		local frame=button
 		self:AddStandardDataToButton(page,button,mission,missionID,bigscreen)
 		over.GarrisonMissionButton_SetRewards(button, mission.rewards, mission.numRewards);
-		self:AddFollowersToButton(button,mission,missionID,bigscreen)
+		if mission.followerTypeID==LE_FOLLOWER_TYPE_GARRISON_6_0 then
+			self:AddFollowersToButton(button,mission,missionID,bigscreen)
+		else
+			self:AddShipsToButton(button,mission,missionID,bigscreen)
+		end
 		frame.Title:SetPoint("TOPLEFT",frame.Indicators,"TOPRIGHT",0,-5)
 		frame.Success:SetPoint("LEFT",frame.Indicators,"RIGHT",0,0)
 		frame.Failure:SetPoint("LEFT",frame.Indicators,"RIGHT",0,0)
@@ -2930,6 +2948,8 @@ function addon:AddIndicatorToButton(button,mission,missionID,bigscreen)
 		end
 	end
 end
+function addon:AddShipsToButton(button,mission,missionID,bigscreen)
+end
 function addon:AddFollowersToButton(button,mission,missionID,bigscreen)
 	if (not button.gcPANEL) then
 		local bg=CreateFrame("Button",nil,button,"GarrisonCommanderMissionButton")
diff --git a/Init.lua b/Init.lua
index 52141e3..fde050a 100644
--- a/Init.lua
+++ b/Init.lua
@@ -47,6 +47,7 @@ do
 	local newcount, delcount,createdcount,cached = 0,0,0
 	--@end-debug@
 	local pool = setmetatable({},{__mode="k"})
+	---@function [parent=#ns] new
 	function ns.new()
 	--@debug@
 		newcount = newcount + 1
@@ -62,6 +63,7 @@ do
 			return {}
 		end
 	end
+	---@function [parent=#ns] tCopy
 	function ns.tCopy(t)
 		local c = ns.new()
 		for k, v in pairs(t) do
@@ -69,6 +71,7 @@ do
 		end
 		return c
 	end
+	---@function [parent=#ns] del
 	function ns.del(t)
 	--@debug@
 		delcount = delcount + 1
@@ -77,6 +80,7 @@ do
 		pool[t] = true
 	end
 	--@debug@
+	---@function [parent=#ns] cached
 	function cached()
 		local n = 0
 		for k in pairs(pool) do
@@ -84,7 +88,7 @@ do
 		end
 		return n
 	end
-	function ns.addon:CacheStats()
+	function addon:CacheStats()
 		print("Created:",createdcount)
 		print("Aquired:",newcount)
 		print("Released:",delcount)
@@ -93,6 +97,8 @@ do
 	--@end-debug@
 end
 -- my implementation of tonumber which accounts for nan and inf
+---@function [parent=#ns] tonumber
+
 function ns.tonumber(value)
 	if value~=value then return nil
 	elseif value==math.huge then return nil
@@ -100,6 +106,7 @@ function ns.tonumber(value)
 	end
 end
 -- my implementation of type which accounts for nan and inf
+---@function [parent=#ns] type
 function ns.type(value)
 	if value~=value then return nil
 	elseif value==math.huge then return nil
@@ -118,7 +125,7 @@ function ns.override(blizfunc,...)
 		overrider=strjoin('_',overrider,...)
 	end
 	assert(type(over[overrider])=="function",overrider)
-	if (orig[overrider]) then return end
+	if (orig[overrider]) then return end -- already hooked
 	local code="local orig,over,overrider=... orig[overrider]=_G."..blizfunc.." _G."..blizfunc.."=over[overrider]"
 	assert(loadstring(code, "Executing " ..code))(orig,over,overrider)
 end
diff --git a/MissionCache.lua b/MissionCache.lua
index b919c11..218afdd 100644
--- a/MissionCache.lua
+++ b/MissionCache.lua
@@ -12,7 +12,148 @@ local wipe=wipe
 local GARRISON_CURRENCY=GARRISON_CURRENCY
 local GARRISON_SHIP_OIL_CURRENCY=GARRISON_SHIP_OIL_CURRENCY
 local GARRISON_FOLLOWER_MAX_LEVEL=GARRISON_FOLLOWER_MAX_LEVEL
+local LE_FOLLOWER_TYPE_GARRISON_6_0=_G.LE_FOLLOWER_TYPE_GARRISON_6_0
+local LE_FOLLOWER_TYPE_SHIPYARD_6_2=_G.LE_FOLLOWER_TYPE_SHIPYARD_6_2
+local newcache=true
+local cache={}
+-- Mission caching is a bit different fron follower caching mission appears and disappears on a regular basis
+local module=addon:NewSubClass('MissionCache') --#module
+function module:OnInitialized()
+	self:HookScript(GMF,"OnShow","PanelOpened",false)
+	self:HookScript(GMF,"OnHide","PanelClosed",false)
+	self:HookScript(GSF,"OnShow","PanelOpened",false)
+	self:HookScript(GSF,"OnHide","PanelOpened",fakse)
+end
+local function load(t,inProgress)
+	for i=1,#t do
+		local missionID=t[i].missionID
+		if type(cache[missionID]) ~="table" then
+			cache[missionID]={followerType=t[i].followerType,missionID=missionID}
+			module:AddExtraData(cache[missionID])
+		end
+		cache[missionID].index=i
+		cache[missionID].inProgress=inProgress
+	end
+end
+function module:PanelOpened(frame,...)
+	local followerType=LE_FOLLOWER_TYPE_SHIPYARD_6_2
+	if (frame:GetName()=="GarrisonMissionFrame") then
+		followerType=LE_FOLLOWER_TYPE_GARRISON_6_0
+		local t=new()
+		G.GetAvailableMissions(t,followerType)
+		load(t,false)
+		wipe(t)
+		G.GetInProgressMissions(t,followerType)
+		load(t,true)
+		del(t)
+	end
+end
+function module:PanelClosed(frame,...)
+
+end
+function addon:GetMission(id)
+	return cache[id]
+end
+function module:AddExtraData(mission)
+	local _
+	_,mission.xp,mission.type,mission.typeDesc,mission.typeIcon,mission.locPrefix,_,mission.enemies=G.GetMissionInfo(mission.missionID)
+	if mission.level then
+		mission.rank=mission.level < GARRISON_FOLLOWER_MAX_LEVEL and mission.level or mission.iLevel
+	end
+	mission.resources=0
+	mission.oil=0
+	mission.apexis=0
+	mission.seal=0
+	mission.gold=0
+	mission.followerUpgrade=0
+	mission.itemLevel=0
+	mission.xpBonus=0
+	mission.others=0
+	mission.xp=mission.xp or 0
+	mission.rush=0
+	mission.chanceCap=100
+	local numrewards=0
+	local rewards=mission.rewards
+	if not rewards then
+		rewards=G.GetMissionRewardInfo(mission.missionID)
+	end
+	for k,v in pairs(rewards) do
+		numrewards=numrewards+1
+		if k==615 and v.followerXP then mission.xpBonus=mission.xpBonus+v.followerXP end
+		if v.currencyID and v.currencyID==GARRISON_CURRENCY then mission.resources=v.quantity end
+		if v.currencyID and v.currencyID==GARRISON_SHIP_OIL_CURRENCY then mission.oil=v.quantity end
+		if v.currencyID and v.currencyID==823 then mission.apexis =mission.apexis+v.quantity end
+		if v.currencyID and v.currencyID==994 then mission.seal =mission.seal+v.quantity end
+		if v.currencyID and v.currencyID==0 then mission.gold =mission.gold+v.quantity/10000 end
+		if v.icon=="Interface\\Icons\\XPBonus_Icon" and v.followerXP then
+			mission.xpBonus=mission.xpBonus+v.followerXP
+		elseif (v.itemID) then
+			if v.itemID~=120205 then -- xp item
+				local itemName, itemLink, itemRarity, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount,itemEquipLoc, itemTexture, itemSellPrice = GetItemInfo(v.itemID)
+				if (not itemName or not itemTexture) then
+					mission.class="retry"
+					return
+				end
+				if itemTexture:lower()==rushOrders then
+					mission.rush=mission.rush+v.quantity
+				elseif itemName and (not v.quantity or v.quantity==1) and not v.followerXP then
+					itemLevel=addon:GetTrueLevel(v.itemID,itemLevel)
+					if mission.missionID==364 then print(4,itemLevel) end
+					if (addon:IsFollowerUpgrade(v.itemID)) then
+						mission.followerUpgrade=itemRarity
+					elseif itemLevel > 500 and itemMinLevel >=90 then
+						mission.itemLevel=itemLevel
+					else
+						mission.others=mission.others+v.quantity
+					end
+				else
+					mission.others=mission.others+v.quantity
+				end
+			end
+		end
+	end
+	mission.xpOnly=false
+	if mission.resources > 0 then
+		mission.class='resources'
+		mission.maxable=true
+		mission.mat=true
+	elseif mission.oil > 0 then
+		mission.class='oil'
+		mission.maxable=true
+		mission.mat=true
+	elseif mission.apexis > 0 then
+		mission.class='apexis'
+		mission.maxable=true
+		mission.mat=true
+	elseif mission.seal > 0 then
+		mission.class='seal'
+		mission.maxable=fase
+		mission.mat=false
+	elseif mission.gold >0 then
+		mission.class='gold'
+		mission.maxable=true
+		mission.mat=true
+	elseif mission.itemLevel >0 then
+		mission.class='itemLevel'
+	elseif mission.followerUpgrade>0 then
+		mission.class='followerUpgrade'
+	elseif mission.rush>0 then
+		mission.class='rush'
+	elseif mission.others >0 or numrewards > 1 then
+		mission.class='other'
+	else
+		mission.class='xp'
+		mission.xpOnly=true
+	end
+	if (mission.numFollowers) then
+		mission.globalXp=(mission.xp+mission.xpBonus+(addon:GetParty(mission.missionID)['xpBonus'] or 0) )*mission.numFollowers
+	end
+
+end
+
+
 local Mbase = GMFMissions
+
 -- self=Mbase
 --	C_Garrison.GetInProgressMissions(self.inProgressMissions);
 --	C_Garrison.GetAvailableMissions(self.availableMissions);
@@ -211,5 +352,3 @@ function addon:GetMissionIterator(func)
 		end
 	end,sorted,0
 end
-local GSF=GarrisonShipyardFrame
-
diff --git a/MissionCompletion.lua b/MissionCompletion.lua
index b48f1dc..6ac7afa 100644
--- a/MissionCompletion.lua
+++ b/MissionCompletion.lua
@@ -2,8 +2,10 @@ local me, ns = ...
 ns.Configure()
 local addon=addon --#addon
 local _G=_G
-local GMF=GarrisonMissionFrame
+local GMF=GMF
+local GSF=GSF
 local GMFMissions=GarrisonMissionFrameMissions
+local GSFMissions=GarrisonMissionFrameMissions
 local GARRISON_CURRENCY=GARRISON_CURRENCY
 local GARRISON_SHIP_OIL_CURRENCY=_G.GARRISON_SHIP_OIL_CURRENCY or 0
 local LE_FOLLOWER_TYPE_GARRISON_6_0=_G.LE_FOLLOWER_TYPE_GARRISON_6_0
@@ -38,6 +40,7 @@ function addon.ShowRewards()
 end
 --@end-debug@
 local missions={}
+local followerType=LE_FOLLOWER_TYPE_GARRISON_6_0
 local states={}
 local rewards={
 	items={},
@@ -64,20 +67,21 @@ local function startTimer(delay,event,...)
 	--@end-alpha@
 end
 function module:MissionsCleanup()
+	local f=followerType==LE_FOLLOWER_TYPE_GARRISON_6_0 and GMF or GSF
+	local fmissions=followerType==LE_FOLLOWER_TYPE_GARRISON_6_0 and GMFMissions or GSFMissions
+	local module=followerType==LE_FOLLOWER_TYPE_GARRISON_6_0 and addon or addon:GetModule("ShipYard")
 	self:Events(false)
 	stopTimer()
-	GMF.MissionTab.MissionList.CompleteDialog:Hide()
-	GMF.MissionComplete:Hide()
-	GMF.MissionCompleteBackground:Hide()
-	GMF.MissionComplete.currentIndex = nil
-	GMF.MissionTab:Show()
-	GarrisonMissionList_UpdateMissions()
+	f.MissionTab.MissionList.CompleteDialog:Hide()
+	f.MissionComplete:Hide()
+	f.MissionCompleteBackground:Hide()
+	f.MissionComplete.currentIndex = nil
+	f.MissionTab:Show()
 	-- Re-enable "view" button
-	GMFMissions.CompleteDialog.BorderFrame.ViewButton:SetEnabled(true)
-	addon:OpenLastTab()
-	if ns.toc < 60200 then
-		GarrisonMissionFrame_CheckCompleteMissions()
-	end
+	fmissions.CompleteDialog.BorderFrame.ViewButton:SetEnabled(true)
+	module:OpenLastTab()
+	f:UpdateMissions()
+	f:CheckCompleteMissions()
 end
 function module:Events(on)
 	if (on) then
@@ -93,13 +97,15 @@ function module:CloseReport()
 	if report then pcall(report.Close,report) report=nil end
 end
 function module:MissionComplete(this,button)
-	if ns.toc < 60200 then
-		missions=G.GetCompleteMissions()
-	else
-		missions=G.GetCompleteMissions(LE_FOLLOWER_TYPE_GARRISON_6_0)
+	print(this,button,this.missionType)
+	followerType=this.missionType
+	missions=G.GetCompleteMissions(followerType)
+	if followerType == LE_FOLLOWER_TYPE_SHIPYARD_6_2 then
+		missions={tremove(missions)}
 	end
 	if (missions and #missions > 0) then
 		GMFMissions.CompleteDialog.BorderFrame.ViewButton:SetEnabled(false) -- Disabling standard Blizzard Completion
+		GSFMissions.CompleteDialog.BorderFrame.ViewButton:SetEnabled(false) -- Disabling standard Blizzard Completion
 		report=self:GenerateMissionCompleteList("Missions' results")
 		wipe(rewards.followerBase)
 		wipe(rewards.followerXP)
@@ -107,7 +113,7 @@ function module:MissionComplete(this,button)
 		wipe(rewards.items)
 		for i=1,#missions do
 			for k,v in pairs(missions[i].followers) do
-				rewards.followerBase[v]=self:GetFollowerData(v,'qLevel')
+				rewards.followerBase[v]=self:GetAnyData(followerType,v,'qLevel',0)
 			end
 			for k,v in pairs(missions[i].rewards) do
 				if v.itemID then GetItemInfo(v.itemID) end -- tickling server
@@ -117,12 +123,8 @@ function module:MissionComplete(this,button)

 			local _
 			_,_,m.isMissionTimeImproved,m.successChance,_,_,m.xpBonus,m.resourceMultiplier,m.goldMultiplier=G.GetPartyMissionInfo(m.missionID)
-			if type(m.resourceMultiplier)=='table' then m.resourceMultiplier=m.resourceMultiplier[824] or 1 end

 		end
---@debug@
-		self:Dump("Completed missions",missions)
---@end-debug@
 		report:SetUserData('missions',missions)
 		report:SetUserData('current',1)
 		self:Events(true)
@@ -146,7 +148,7 @@ function module: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
 --@alpha@
-	print("evt",event,ID,arg1 or'',arg2 or '',arg3 or '')
+	--print("evt",event,ID,arg1 or'',arg2 or '',arg3 or '')
 --@end-alpha@
 	if event=="LOOT" then
 		return self:MissionsPrintResults()
@@ -238,16 +240,17 @@ function module:GetMissionResults(success,currentMission)
 		PlaySound("UI_Garrison_Mission_Complete_Encounter_Fail")
 	end
 	if success then
-		local resourceMultiplier=currentMission.resourceMultiplier or 1
+		local resourceMultiplier=currentMission.resourceMultiplier or {}
 		local goldMultiplier=currentMission.goldMultiplier or 1
 		for k,v in pairs(currentMission.rewards) do
 			v.quantity=v.quantity or 0
 			if v.currencyID then
 				rewards.currencies[v.currencyID].icon=v.icon
+				local multi=resourceMultiplier[v.currencyID]
 				if v.currencyID == 0 then
 					rewards.currencies[v.currencyID].qt=rewards.currencies[v.currencyID].qt+v.quantity * goldMultiplier
-				elseif v.currencyID == GARRISON_CURRENCY then
-					rewards.currencies[v.currencyID].qt=rewards.currencies[v.currencyID].qt+v.quantity * resourceMultiplier
+				elseif resourceMultiplier[v.currencyID] then
+					rewards.currencies[v.currencyID].qt=rewards.currencies[v.currencyID].qt+v.quantity * multi
 				else
 					rewards.currencies[v.currencyID].qt=rewards.currencies[v.currencyID].qt+v.quantity
 				end
@@ -259,18 +262,13 @@ function module:GetMissionResults(success,currentMission)
 end
 function module:MissionsPrintResults(success)
 	stopTimer()
---@debug@
-	--self:Dump("Ended Mission",rewards)
---@end-debug@
 	local reported
+	local followers
 	for k,v in pairs(rewards.currencies) do
 		reported=true
 		if k == 0 then
 			-- Money reward
 			report:AddIconText(v.icon,GetMoneyString(v.qt))
-		elseif k == GARRISON_CURRENCY then
-			-- Garrison currency reward
-			report:AddIconText(v.icon,GetCurrencyLink(k),v.qt)
 		else
 			-- Other currency reward
 			report:AddIconText(v.icon,GetCurrencyLink(k),v.qt)
@@ -292,9 +290,12 @@ function module:MissionsPrintResults(success)
 	del(items)
 	for k,v in pairs(rewards.followerXP) do
 		reported=true
-		report:AddFollower(k,v,self:GetFollowerData(k,'qLevel') > rewards.followerBase[k])
+		followers=true
+		report:AddFollower(self:GetAnyData(followerType,k),v,self:GetAnyData(followerType,k,'qLevel') > rewards.followerBase[k])
 	end
-	if (not reported) then
+	if not reported then
 		report:AddRow(L["Nothing to report"])
+	elseif not followers then
+		report:AddRow(L["No follower gained xp"])
 	end
 end
diff --git a/ShipYard.lua b/ShipYard.lua
index 715d9c5..24e4efa 100644
--- a/ShipYard.lua
+++ b/ShipYard.lua
@@ -3,23 +3,28 @@ ns.Configure()
 local addon=addon --#addon
 local over=over --#over
 local _G=_G
-local GSF=GarrisonShipyardFrame
+local GSF=GSF
 local G=C_Garrison
 local pairs=pairs
 local format=format
 local strsplit=strsplit
 local generated
 local GARRISON_FOLLOWER_MAX_UPGRADE_QUALITY=GARRISON_FOLLOWER_MAX_UPGRADE_QUALITY
+local GARRISON_CURRENCY=GARRISON_CURRENCY
+local GARRISON_SHIP_OIL_CURRENCY=GARRISON_SHIP_OIL_CURRENCY
+local GARRISON_FOLLOWER_MAX_LEVEL=GARRISON_FOLLOWER_MAX_LEVEL
+local LE_FOLLOWER_TYPE_GARRISON_6_0=LE_FOLLOWER_TYPE_GARRISON_6_0
+local LE_FOLLOWER_TYPE_SHIPYARD_6_2=LE_FOLLOWER_TYPE_SHIPYARD_6_2
 local module=addon:NewSubClass('ShipYard') --#Module
 function sprint(nome,this,...)
 	print(nome,this:GetName(),...)
 end
 function module:OnInitialize()
-	override("GarrisonFollowerButton_UpdateCounters")
+	self:SafeSecureHook("GarrisonFollowerButton_UpdateCounters")
 --@debug@
 	print("ShipYard Loaded")
-	override("GarrisonShipyardMapMission_SetTooltip")
-	override("GarrisonShipyardFrame","OnClickMission")
+	self:SafeSecureHook("GarrisonShipyardMapMission_SetTooltip")
+	self:SafeSecureHook(GSF,"OnClickMission","HookedGSF_OnClickMission")
 	self:SafeHookScript(GSF,"OnShow","Setup",true)
 	self:SafeHookScript(GSF.MissionTab.MissionList.CompleteDialog,"OnShow",function(... ) sprint("CompleteDialog",...) end,true)
 	self:SafeHookScript(GSF.MissionTab,"OnShow",function(... ) sprint("MissionTab",...) end,true)
@@ -29,6 +34,7 @@ function module:OnInitialize()
 	local ref=GSFMissions.CompleteDialog.BorderFrame.ViewButton
 	print(ref)
 	local bt = CreateFrame('BUTTON','GCQuickShipMissionCompletionButton', ref, 'UIPanelButtonTemplate')
+	bt.missionType=LE_FOLLOWER_TYPE_SHIPYARD_6_2
 	bt:SetWidth(300)
 	bt:SetText(L["Garrison Comander Quick Mission Completion"])
 	bt:SetPoint("CENTER",0,-50)
@@ -36,22 +42,11 @@ function module:OnInitialize()
 --@end-debug@
 end

-local over=over --#over
-function over.GarrisonShipyardFrame_OnClickMission(this,missionInfo)
-	-- this = GarrisonShipyardframe
-	local frame=GSF.MissionTab.MissionPage.Stage
-	orig.GarrisonShipyardFrame_OnClickMission(this,missionInfo)
---@debug@
-	if not frame.GCID then
-		frame.GCID=frame:CreateFontString(nil,"OVERLAY","GameFontHighlightSmall")
-		frame.GCID:SetPoint("TOPLEFT",frame.MissionTime,"TOPRIGHT",5,0)
-	end
-	frame.GCID:SetFormattedText("MissionID: %d",missionInfo.missionID)
-	frame.GCID:Show()
---@end-debug@
+function module:HookedGSF_OnClickMission(this,missionInfo)
+	self:FillMissionPage(missionInfo)
 end
-function over.GarrisonFollowerButton_UpdateCounters(gsf,frame,follower,showcounter,lastupdate)
-	orig.GarrisonFollowerButton_UpdateCounters(gsf,frame,follower,showcounter,lastupdate)
+function module:HookedGarrisonFollowerButton_UpdateCounters(gsf,frame,follower,showcounter,lastupdate)
+	if follower.followerTypeID~=LE_FOLLOWER_TYPE_SHIPYARD_6_2 then return end
 	if not frame.GCXp then
 		frame.GCXp=frame:CreateFontString(nil,"OVERLAY","GameFontHighlightSmall")
 	end
@@ -63,29 +58,57 @@ function over.GarrisonFollowerButton_UpdateCounters(gsf,frame,follower,showcount
 		frame.GCXp:Hide()
 	end
 --@debug@
-	print(follower)
+	--print(follower)
 --@end-debug@
 end

 function module:Setup(this,...)
 	print("Doing one time initialization for",this:GetName(),...)
 	self:SafeHookScript(GSF,"OnShow","OnShow",true)
+	GSF:EnableMouse(true)
 	GSF:SetMovable(true)
+	GSF:RegisterForDrag("LeftButton")
+	GSF:SetScript("OnDragStart",function(frame)if (self:GetBoolean("MOVEPANEL")) then frame:StartMoving() end end)
+	GSF:SetScript("OnDragStop",function(frame) frame:StopMovingOrSizing() end)
 end
 function module:OnShow()
 	print("Doing all time initialization")
 end
-function over.GarrisonShipyardMapMission_SetTooltip(info,inProgress)
-	orig.GarrisonShipyardMapMission_SetTooltip(info,inProgress)
+function module:HookedGarrisonShipyardMapMission_SetTooltip(info,inProgress)
 	local tooltipFrame = GarrisonShipyardMapMissionTooltip;
-	tooltipFrame.Name:SetText(info.name .. " " .. info.missionID);
 	tooltipFrame:SetHeight(tooltipFrame:GetHeight()+20)
 	if (not tooltipFrame.dbg) then
 		tooltipFrame.dbg=tooltipFrame:CreateFontString(nil,"OVERLAY","GameFontHighlightSmall")
-		tooltipFrame.dbg:SetPoint("BOTTOMLEFT")
+		tooltipFrame.dbg:SetPoint("BOTTOMLEFT",10,10)
 	end
 	tooltipFrame.dbg:Show()
 	tooltipFrame.dbg:SetFormattedText("Mission ID: %d" ,info.missionID);
 end

+function module:OpenLastTab()
+print("Should restore tab")
+end
+--[[
+displayHeight = 0.25
+followerTypeID = 2
+iLevel = 600
+isCollected = true
+classAtlas = Ships_TroopTransport-List
+garrFollowerID = 0x00000000000001E2
+displayScale = 95
+level = 100
+quality = 3
+portraitIconID = 0
+isFavorite = false
+xp = 1500
+texPrefix = Ships_TroopTransport
+className = Transport
+classSpec = 53
+name = Chen's Favorite Brew
+followerID = 0x00000000011E4D8F
+height = 0.30000001192093
+displayID = 63894
+scale = 110
+levelXP = 40000
+--]]
 --view mission button GSF.MissionTab.MissionList.CompleteDialog.BorderFrame.ViewButton
\ No newline at end of file
diff --git a/Widgets.lua b/Widgets.lua
index fad2d95..0a6ebf0 100644
--- a/Widgets.lua
+++ b/Widgets.lua
@@ -3,7 +3,20 @@ ns.Configure()
 local addon=addon
 local _G=_G
 local wipe=wipe
+local format=format
+local UNKNOWN=UNKNOWN
+local LE_FOLLOWER_TYPE_GARRISON_6_0=LE_FOLLOWER_TYPE_GARRISON_6_0
+local LE_FOLLOWER_TYPE_SHIPYARD_6_2=LE_FOLLOWER_TYPE_SHIPYARD_6_2
+
 local module=addon:NewSubModule("Widgets") --#module
+local function Constructor()
+	local widget= AceGUI:Create("Label")
+	widget.SetAtlas=function (atlasname)
+		widget.image:SetAtlas(atlasname)
+	end
+	widget.OnRelease=function() widget.image:SetAtlas(nil) end
+end
+AceGUI:RegisterWidgetType("AtlasLabel", Constructor, 1)
 --- Quick backdrop
 --
 local backdrop = {
@@ -95,10 +108,12 @@ local function GMCList()
 		obj:AddChild(l)

 	end
-	function m:AddFollower(followerID,xp,levelup)
-		local follower=addon:GetFollowerData(followerID)
+	function m:AddFollower(follower,xp,levelup)
+		print(follower)
+		local followerID=follower.followerID
+		local followerType=follower.followerTypeID
 		if follower.maxed and not levelup then
-			return self:AddIconText(addon:GetFollowerTexture(followerID),
+			return self:AddFollowerIcon(followerType,addon:GetFollowerTexture(followerID),
 								format("%s is already at maximum xp",addon:GetFollowerData(followerID,'fullname')))
 		end
 		local quality=G.GetFollowerQuality(followerID) or follower.quality
@@ -106,10 +121,28 @@ local function GMCList()
 		if levelup then
 			PlaySound("UI_Garrison_CommandTable_Follower_LevelUp");
 		end
-		return self:AddIconText(addon:GetFollowerTexture(followerID),
-		format("%s gained %d xp%s%s",addon:GetFollowerData(followerID,'fullname',true),xp,
-		levelup and " |cffffed1a*** Level Up ***|r ." or ".",
-		format(" %d to go.",addon:GetFollowerData(followerID,'levelXP')-addon:GetFollowerData(followerID,'xp'))))
+		return self:AddFollowerIcon(followerType,
+			addon:GetFollowerTexture(followerID,followerType),
+			format("%s gained %d xp%s%s",
+				addon:GetAnyData(followerType,followerID,'fullname',UNKNOWN),
+				xp,
+				levelup and " |cffffed1a*** Level Up ***|r ." or ".",
+				format(" %d to go.",addon:GetAnyData(followerType,followerID,'levelXP')-addon:GetAnyData(followerType,followerID,'xp')))
+		)
+	end
+	function m:AddFollowerIcon(followerType,icon,text)
+		local l=self:AddIconText(icon,text)
+		if followerType==LE_FOLLOWER_TYPE_GARRISON_6_0 then
+			l:SetImageSize(24,24)
+		else
+			local left,right,top,bottom
+			left=0
+			right=0.5
+			top=0
+			bottom=0.5
+			l:SetImage(icon,left,right,top,bottom)
+			l:SetImageSize(36,36)
+		end
 	end
 	function m:AddIconText(icon,text,qt)
 		local obj=self.scroll