local me, ns = ... local toc=select(4,GetBuildInfo()) local pp=print ns.Configure() local _G=_G local HD=false local tremove=tremove local setmetatable=setmetatable local getmetatable=getmetatable local type=type local GetAddOnMetadata=GetAddOnMetadata local CreateFrame=CreateFrame local wipe=wipe local format=format local tostring=tostring local collectgarbage=collectgarbage --@debug@ --local collectgarbage=function() end --@end-debug@ local GMM=false local MP=false local MPGoodGuy=false local MPSwitch local dbg=false local trc=false local pin=false local baseHeight local minHeight local addon=addon --#addon 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 LE_GARRISON_TYPE_6_0=_G.LE_GARRISON_TYPE_6_0 local LE_GARRISON_TYPE_6_2=_G.LE_GARRISON_TYPE_6_2 ns.bigscreen=true local tprint=print local backdrop = { --bgFile="Interface\\TutorialFrame\\TutorialFrameBackground", bgFile="Interface\\DialogFrame\\UI-DialogBox-Background-Dark", edgeFile="Interface\\Tooltips\\UI-Tooltip-Border", tile=true, tileSize=16, edgeSize=16, insets={bottom=7,left=7,right=7,top=7} } local dialog = { bgFile="Interface\\DialogFrame\\UI-DialogBox-Background", edgeFile="Interface\\DialogFrame\\UI-DialogBox-Border", tile=true, tileSize=32, edgeSize=32, insets={bottom=5,left=5,right=5,top=5} } local function tcopy(obj, seen) if type(obj) ~= 'table' then return obj end if seen and seen[obj] then return seen[obj] end local s = seen or {} local res = setmetatable({}, getmetatable(obj)) s[obj] = res for k, v in pairs(obj) do res[tcopy(k, s)] = tcopy(v, s) end return res end local widgetsForKey={} local parties local missionCompleteOrder=122514 local lastTab local new, del, copy =ns.new,ns.del,ns.copy local function capitalize(s) s=tostring(s) return strupper(s:sub(1,1))..strlower(s:sub(2)) 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_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"; --local GARRISON_PARTY_NOT_FULL_TOOLTIP=GARRISON_PARTY_NOT_FULL_TOOLTIP -- "You do not have enough followers on this mission." --local GARRISON_MISSION_CHANCE=GARRISON_MISSION_CHANCE -- Chanche --local GARRISON_FOLLOWER_BUSY_COLOR=GARRISON_FOLLOWER_BUSY_COLOR --local GARRISON_FOLLOWER_INACTIVE_COLOR=GARRISON_FOLLOWER_INACTIVE_COLOR --local GARRISON_CURRENCY=GARRISON_CURRENCY --824 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 GARRISON_FOLLOWER_MAX_UPGRADE_QUALITY=GARRISON_FOLLOWER_MAX_UPGRADE_QUALITY[LE_FOLLOWER_TYPE_GARRISON_6_0] --local GARRISON_FOLLOWER_MAX_LEVEL=GARRISON_FOLLOWER_MAX_LEVEL -- 100 local GARRISON_CURRENCY=GARRISON_CURRENCY local GetMoneyString=GetMoneyString local SHORTDATE=SHORTDATE.. " %s" local LEVEL=LEVEL -- Level local MISSING=ADDON_MISSING local NOT_COLLECTED=NOT_COLLECTED -- not collected local GMF=GMF local GSF=GSF -- Frames shortcut local GMFRewardPage= GMF.MissionComplete local GMFMissions= GMF.MissionTab.MissionList local GMFRewardSplash= GMF.MissionTab.MissionList.CompleteDialog local GMFMissionsListScrollFrame= GMF.MissionTab.MissionList.listScroll local GMFMissionListButtons= GMF.MissionTab.MissionList.listScroll.buttons local GMFMissionsListScrollFrameScrollChild= GMF.MissionTab.MissionList.listScroll.scrollChild local GMFFollowers= GMF.FollowerList local GMFMissionFrameFollowers= GMFFollowers local GMFFollowersListScrollFrame= GMFFollowers.listScroll local GMFFollowersListScrollFrameScrollChild= GMFFollowers.listScroll.scrollChild local GMFMissionPage= GMF.MissionTab.MissionPage --dictionary local IGNORE_UNAIVALABLE_FOLLOWERS=IGNORE.. ' ' .. UNAVAILABLE local IGNORE_UNAIVALABLE_FOLLOWERS_DETAIL= GARRISON_FOLLOWER_ON_MISSION ..',' .. GARRISON_FOLLOWER_WORKING .. ' ' .. GARRISON_FOLLOWERS .. '. ' .. GARRISON_FOLLOWER_INACTIVE .. " are always ignored" local PARTY=PARTY -- "Party" local SPELL_TARGET_TYPE1_DESC=capitalize(SPELL_TARGET_TYPE1_DESC) -- any local SPELL_TARGET_TYPE4_DESC=capitalize(SPELL_TARGET_TYPE4_DESC) -- party member local ANYONE='('..SPELL_TARGET_TYPE1_DESC..')' local UNKNOWN_CHANCE=GARRISON_MISSION_PERCENT_CHANCE:gsub('%%d%%%%',UNKNOWN) IGNORE_UNAIVALABLE_FOLLOWERS=capitalize(IGNORE_UNAIVALABLE_FOLLOWERS) IGNORE_UNAIVALABLE_FOLLOWERS_DETAIL=capitalize(IGNORE_UNAIVALABLE_FOLLOWERS_DETAIL) local UNKNOWN=UNKNOWN -- Unknown local TYPE=TYPE -- Type local ALL=ALL -- All local MAXMISSIONS=8 local MINPERC=20 local BUSY_MESSAGE_FORMAT=L["Only first %1$d missions with over %2$d%% chance of success are shown"] local BUSY_MESSAGE=format(BUSY_MESSAGE_FORMAT,MAXMISSIONS,MINPERC) 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 GarrisonFollowerPortrait_Set=GarrisonFollowerPortrait_Set if not GarrisonFollowerPortrait_Set then GarrisonFollowerPortrait_Set=function(portrait, iconFileID) if (iconFileID == nil or iconFileID == 0) then -- unknown icon file ID; use the default silhouette portrait portrait:SetTexture("Interface\\Garrison\\Portraits\\FollowerPortrait_NoPortrait"); else portrait:SetToFileData(iconFileID); end end end local function splitFormat(base) local i,s=base:find("|4.*:.*;") if (not i) then return base,base end local m0,m1=base:match("|4(.*):(.*);") local G=base local G1=G:sub(1,i-1)..m0..G:sub(s+1) local G2=G:sub(1,i-1)..m1..G:sub(s+1) return G1,G2 end local function ShowTT(this) GameTooltip:SetOwner(this, "ANCHOR_TOPRIGHT") GameTooltip:SetText(this.tooltip) GameTooltip:Show() end local function FadeTT(this) GameTooltip:Fade() end local function HideTT(this) GameTooltip:Hide() end local GARRISON_DURATION_DAY,GARRISON_DURATION_DAYS=splitFormat(GARRISON_DURATION_DAYS) -- "%d |4day:days;"; local GARRISON_DURATION_DAY_HOURS,GARRISON_DURATION_DAYS_HOURS=splitFormat(GARRISON_DURATION_DAYS_HOURS) -- "%d |4day:days; %d hr"; local GARRISON_DURATION_HOURS=GARRISON_DURATION_HOURS -- "%d hr"; local GARRISON_DURATION_HOURS_MINUTES=GARRISON_DURATION_HOURS_MINUTES -- "%d hr %d min"; local GARRISON_DURATION_MINUTES=GARRISON_DURATION_MINUTES -- "%d min"; local GARRISON_DURATION_SECONDS=GARRISON_DURATION_SECONDS -- "%d sec"; local AGE_HOURS="Expires in " .. GARRISON_DURATION_HOURS_MINUTES local AGE_DAYS="Expires in " .. GARRISON_DURATION_DAYS_HOURS -- Panel sizes local BIGSIZEW=1220 local BIGSIZEH=662 local SIZEW=950 local SIZEH=662 local SIZEV local GCSIZE=700 local FLSIZE=400 local BIGBUTTON=BIGSIZEW-GCSIZE local SMALLBUTTON=BIGSIZEW-GCSIZE local GCF local GCFMissions local GCFBusyStatus local GameTooltip=GameTooltip -- Want to know what I call!! 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:GetQualityColor(n) local c=ITEM_QUALITY_COLORS[n] if c then return c.r,c.g,c.b,1 else return 1,1,1,1 end end function addon:GetDifficultyColor(perc,usePurple) if(perc >90) then return QuestDifficultyColors['standard'] elseif (perc >74) then return QuestDifficultyColors['difficult'] elseif(perc>49) then return QuestDifficultyColors['verydifficult'] elseif(perc >20) then return QuestDifficultyColors['impossible'] else return not usePurple and C.Silver or C.Fuchsia end end ----- Local variables -- -- Forces a table to countain other tables, local t1={ __index=function(t,k) if k then rawset(t,k,{}) return t[k] end end } local t2={ __index=function(t,k) if k then rawset(t,k,setmetatable({},t1)) return t[k] end end } local followersCache={} local followersCacheIndex={} local dirty=false local chardb local db local n=setmetatable({},{ __index = function(t,k) local name=addon:GetFollowerData(k,'fullname') if (name and k) then rawset(t,k,name) return name else return k end end }) -- Counter system local function cleanicon(stringa) return (stringa:lower():gsub("%.blp$","")) end local counters=setmetatable({},t2) local counterThreatIndex=setmetatable({},t2) local counterFollowerIndex=setmetatable({},t2) --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 local Current_Sorter local sortKeys={} local nop=function() end local sorters={ Garrison_SortMissions_Original=nop, Garrison_SortMissions_Chance=function(mission) local p=addon:GetParty(mission.missionID) if not p.full then return 0 end return -p.perc or 0 end, Garrison_SortMissions_Level=function(mission) return -mission.level * 1000 - (mission.iLevel or 0) end, Garrison_SortMissions_Age=function(mission) return addon:GetMissionData(mission.missionID,'offerEndTime',0) end, Garrison_SortMissions_Xp=function(mission) return -addon:GetMissionData(mission.missionID,'globalXp',0) end, Garrison_SortMissions_HourlyXp=function(mission) return sorters.Garrison_SortMissions_Xp(mission) / addon:GetMissionData(mission.missionID,'improvedDurationSeconds',1) end, Garrison_SortMissions_Duration=function(mission) return addon:GetMissionData(mission.missionID,'improvedDurationSeconds',0) end, Garrison_SortMissions_Class=function(mission) return addon:GetMissionData(mission.missionID,'class','other') end, Garrison_SortMissions_Followers=function(mission) return addon:GetMissionData(mission.missionID,'numFollowers',1) end, } local function sortfuncProgress(a,b) return a.timeLeftSeconds < b.timeLeftSeconds end local function sortfuncAvailable(a,b) if sortKeys[a.missionID] ~= sortKeys[b.missionID] then return sortKeys[a.missionID] < sortKeys[b.missionID] else return strcmputf8i(a.name, b.name) < 0 end end local pcall=pcall local sort=table.sort function addon:SortMissions() --@debug@ addon:Print(C("SortMissions","Orange"),Current_Sorter) --@end-debug@ if GMFMissions.inProgress then pcall(sort,GMFMissions.inProgressMissions,sortfuncProgress) else if Current_Sorter=="Garrison_SortMissions_Original" then return end local f=sorters[Current_Sorter] for _,mission in pairs(GMFMissions.availableMissions) do local rc,result =pcall(f,mission) sortKeys[mission.missionID]=rc and result or 0 --@debug@ if not rc then self:Print("Sort error",mission.name,mission.missionID,result) end --@end-debug@ end sort(GMFMissions.availableMissions,sortfuncAvailable) end end function addon.Garrison_SortMissions_Chance(missionsList) addon:RefreshParties() table.sort(missionsList, sorters.Chance); end function addon.Garrison_SortMissions_Age(missionsList) --addon:RefreshParties() table.sort(missionsList, sorters.Age); end function addon.Garrison_SortMissions_Duration(missionsList) addon:RefreshParties() table.sort(missionsList, sorters.Duration); end function addon.Garrison_SortMissions_Followers(missionsList) addon:RefreshParties() table.sort(missionsList, sorters.Followers); end function addon.Garrison_SortMissions_Xp(missionsList) addon:RefreshParties() table.sort(missionsList, sorters.Xp); end function addon.Garrison_SortMissions_Class(missionsList) --addon:RefreshParties() table.sort(missionsList, sorters.Class); end function addon:ApplyMSORT(value) Current_Sorter=value GMFMissions:UpdateMissions() end function addon:GetMain() return GMF end function addon:GetMissions() return GMFMissions end function addon:GetBigScreen() return ns.bigscreen end function addon:GetMissionModule(followertype) return ns.custom[followertype] end function addon:OnInitialized() --@debug@ print("Initialize") --@end-debug@ -- ns.custom={ [LE_FOLLOWER_TYPE_GARRISON_6_0]=addon, [LE_FOLLOWER_TYPE_SHIPYARD_6_2]=self:GetModule("ShipYard"), } self:SafeRegisterEvent("GARRISON_MISSION_COMPLETE_RESPONSE") self:SafeRegisterEvent("GARRISON_MISSION_NPC_CLOSED") self:SafeRegisterEvent("GARRISON_MISSION_STARTED") self:SafeRegisterEvent("QUEST_TURNED_IN") for _,b in ipairs(GMF.MissionTab.MissionList.listScroll.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) b:RegisterForClicks("LeftButtonUp","RightButtonUp") addon:SafeSecureHookScript(b,"OnEnter","ScriptGarrisonMissionButton_OnEnter") addon:SafeRawHookScript(b,"OnClick","ScriptGarrisonMissionButton_OnClick") end self:CreatePrivateDb() db=self.db.global db.seen=nil -- Removed in 2.6.9 db.abilities=nil -- Removed in 2.6.9 db.lifespan=nil -- Removed in 2.6.9 db.traits=nil -- Removed in 2.6.9 db.types=nil -- Removed in 2.6.9 chardb.missions=nil -- Removed chardb.followers=nil chardb.running=nil chardb.runningIndex=nil if type(dbGAC)== "table " and type(dbGAC.namespaces)=="table" then dbGAC.namespaces.missionscache=nil -- Removed in 2.6.9 dbGAC.namespaces=nil end self:AddLabel(L["Garrison Appearance"]) --self:AddToggle("MOVEPANEL",true,L["Unlock Panel"],L["Makes main mission panel movable"]) self:AddToggle("BIGSCREEN",true,L["Big screen"],L["Disabling this will give you the interface from 1.1.8, given or taken. Need to reload interface"]) self:AddToggle("PIN",true,L["Show Garrison Commander menu"],L["Disable if you dont want the full Garrison Commander Header."]) self:AddLabel(L["Mission Panel"]) self:AddToggle("IGM",true,IGNORE_UNAIVALABLE_FOLLOWERS,IGNORE_UNAIVALABLE_FOLLOWERS_DETAIL) self:AddToggle("IGP",true,L['Ignore "maxed"'],L["Level 100 epic followers are not used for xp only missions."]) self:AddToggle("NOFILL",false,L["No mission prefill"],L["Disables automatic population of mission page screen. You can also press control while clicking to disable it for a single mission"]) self:AddSelect("MSORT","Garrison_SortMissions_Original", { Garrison_SortMissions_Original=L["Original method"], Garrison_SortMissions_Chance=L["Success Chance"], Garrison_SortMissions_Followers=L["Number of followers"], Garrison_SortMissions_Age=L["Expiration Time"], Garrison_SortMissions_Xp=L["Global approx. xp reward"], Garrison_SortMissions_HourlyXp=L["Global approx. hourly xp reward"], Garrison_SortMissions_Duration=L["Duration Time"], Garrison_SortMissions_Class=L["Reward type"], }, 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("USEFUL",true,L["Enhance tooltip"],L["Adds a list of other useful followers to tooltip"]) self:AddToggle("NOTOOLTIP",false,L["No tooltips"],L["Totally removes mission tooltips"]) self:AddToggle("MAXRES",true,L["Maximize result"],L["Allows a lower success percentage for resource missions. Change via Minimum needed chance slider"]) self:AddSlider("MAXRESCHANCE",80,50,100,L["Minimum needed chance"],L["Applied when 'maximize result' is enabled. Default is 80%"],1) ns.bigscreen=self:GetBoolean("BIGSCREEN") self:AddLabel(L["Followers Panel"]) self:AddSlider("MAXMISSIONS",5,1,8,L["Mission shown"],L["Mission shown for follower"],1) self:AddSlider("MINPERC",50,0,100,L["Minimun chance"],L["Minimun chance success under which ignore missions"],5) self:AddToggle("ILV",true,L["Show itemlevel"],L["When checked, show on each follower button weapon and armor level for maxed followers"]) self:AddToggle("IXP",true,L["Show xp"],L["When checked, show on each follower button missing xp to next level"]) self:AddToggle("UPG",true,L["Show upgrades"],L["Only meaningful upgrades are shown"]) self:AddToggle("NOCONFIRM",true,L["No confirmation"],L["If checked, clicking an upgrade icon will consume the item and upgrade the follower\n|cFFFF0000NO QUESTION ASKED|r"]) self:AddToggle("SWAPBUTTONS",false,L["Swap upgrades positions"],L["IF checked, shows armors on the left and weapons on the right "]) if not ns.bigscreen then self:AddToggle("FOLLOWERMISSIONLIST",true,L["Missionlist"],L["Affects only little screen mode, hiding the per follower mission list if not checked"]) end self:AddLabel("Buildings Panel") self:AddToggle("HF",false,L["Hide followers"],L["Do not show follower icon on plots"]) --@debug@ 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") --@debug@ -- 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@ self:SafeSecureHookScript("GarrisonMissionFrame","OnShow","Setup") local tabCO=CreateFrame("Button",nil,UIParent,"GarrisonCommanderUpgradeButton,SecureActionbuttonTemplate") ns.tabCO=tabCO tabCO.tooltip=L["Complete in progress mission"] tabCO:SetNormalTexture("Interface\\ICONS\\Ability_Skyreach_Empowered.blp") tabCO:SetPushedTexture("Interface\\ICONS\\Ability_Skyreach_Empowered.blp") tabCO:Show() tabCO.Quantity:Show() tabCO.Quantity:SetFormattedText("%d",GetItemCount(missionCompleteOrder)) tabCO:SetAttribute("type","item") tabCO:SetAttribute("item",select(2,GetItemInfo(missionCompleteOrder))) self:loadHelp() --return true end function addon:showdata(fullargs,action,missionid) self:Print(fullargs,",",missionid) missionid=tonumber(missionid) if missionid then if action=="score" then self:Print(self:GetMissionData(missionid,'name'),self:MissionScore(self:GetMissionData(missionid))) elseif action=="mission" then self:DumpMission(missionid) elseif action=="match" then self:TestMission(missionid) end end end function addon:CheckMP() if (IsAddOnLoaded("MasterPlan")) then MP=true ns.MP=true MPSwitch=true end end function addon:CheckGMM() if (IsAddOnLoaded("GarrisonMissionManager")) then GMM=true self:RefreshParties() self:RefreshMissions() end end function addon:ApplyIGM(value) if not GMF:IsVisible() then return end self:RefreshParties() self:RefreshMissions() end function addon:ApplyMAXRES(value) if not GMF:IsVisible() then return end self:RefreshParties() self:RefreshMissions() end function addon:ApplyCKMP(value) if (MasterPlanMissionList) then if (value) then MasterPlanMissionList:Hide() else MasterPlanMissionList:Show() end end self:RefreshMissions() end function addon:ApplyDBG(value) dbg=value end function addon:ApplyPIN(value) pin=value end function addon:ApplyTRC(value) trc=value end function addon:ApplyBIGSCREEN(value) if (value) then wipe(chardb.ignored) -- we no longer have an interface to change this settings end self:Popup(L["Must reload interface to apply"],0, function(this) pp("BIGSCREEN",value,this) print("BIGSCREEN",value,this) addon:SetBoolean("BIGSCREEN",value) ReloadUI() end, function(this) pp("BIGSCREEN",value,this) print("BIGSCREEN",value,this) addon:SetBoolean("BIGSCREEN",not value) widgetsForKey['BIGSCREEN']:SetValue(not value) end ) end function addon:ApplyIGP(value) if not GMF:IsVisible() then return end self:RefreshParties() self:RefreshMissions() end function addon:ApplyMAXMISSIONS(value) MAXMISSIONS=value BUSY_MESSAGE=format(BUSY_MESSAGE_FORMAT,MAXMISSIONS,MINPERC) if ns.bigscreen and GMF.FollowerTab:IsVisible() then end end function addon:ApplyMINPERC(value) MINPERC=value BUSY_MESSAGE=format(BUSY_MESSAGE_FORMAT,MAXMISSIONS,MINPERC) end function addon:ApplyFOLLOWERMISSIONLIST(value) if GMF.FollowerTab:IsVisible() or (GMF.SummaryTab and GMF.SummaryTab:IsVisible()) then self:RenderFollowerPageMissionList(nil,GMF.FollowerTab.followerID) end end function addon:ApplyIXP(value) print(value) end function addon:ApplyILV(value) print(value) end function addon:IsIgnored(followerID,missionID) if (chardb.ignored[missionID][followerID]) then return true end if (chardb.totallyignored[followerID]) then return true end end function addon:GetAllCounters(missionID,threat,table) wipe(table) if type(counterThreatIndex[missionID]) == "table" then local index=counterThreatIndex[missionID][cleanicon(tostring(threat))] if (type(index)=="table") then for i=1,#index do tinsert(table,counters[missionID][index[i]].followerID) end end end end function addon:GetCounterBias(missionID,threat) local bias=-1 local who="" local index=counterThreatIndex[missionID] local data=counters[missionID] if (type(index)=="table" and type(counters)=="table") then index=index[cleanicon(tostring(threat))] if (type(index) == "table") then local members=self:GetParty(missionID,'members',empty) for i=1,#index do local follower=data[index[i]] if ((tonumber(follower.bias) or -1) > bias) then if (tContains(members,follower.followerID)) then if (dbg) then --@debug@ print(" Choosen",self:GetFollowerData(follower.followerID,'fullname')) --@end-debug@ end bias=follower.bias who=follower.name end end end end end return bias,who end function addon:AddLine(name,status) local r2,g2,b2=C.Red() if (status==AVAILABLE) then r2,g2,b2=C.Green() elseif (status==GARRISON_FOLLOWER_WORKING) then r2,g2,b2=C.Orange() end GameTooltip:AddDoubleLine(name, status,nil,nil,nil,r2,g2,b2) end function addon:SetThreatColor(obj,threat) if type(threat)=="string" then local _,_,bias,follower,name=strsplit(":",threat) local color=self:GetBiasColor(tonumber(bias) or -1,nil,"Green") local c=C[color] obj.Border:SetVertexColor(c()) return (tonumber(bias)or -1)>-1 else obj.Border:SetVertexColor(C.red()) end end function addon:AddIconsToFollower(missionID,useful,followers,members,followerTypeID) for followerID,icons in pairs(followers) do if self:GetFollowerType(followerID) == followerTypeID then if not tContains(members,followerID) then local bias=self:GetBiasColor(followerID,missionID) if (not useful[followerID]) then local rank=self:GetAnyData(followerTypeID,followerID,'rank') if rank then useful[followerID]=format("%04d%s %s ", 1000-rank, C(rank,bias), self:GetAnyData(followerTypeID,followerID,'coloredname') ) end end for i=1,#icons do if (useful[followerID]) then useful[followerID]=format("%s |T%s:0|t",useful[followerID],icons[i].icon) end end end end end end function addon:AddFollowersToTooltip(missionID,followerTypeID) --local f=GarrisonMissionListTooltipThreatsFrame -- Adding All available followers if not GMF:IsVisible() and not GSF:IsVisible() then return end local party=self:GetParty(missionID) local cost=self:GetMissionData(missionID,'cost') local currency=self:GetMissionData(missionID,'costCurrencyTypesID') if cost and currency then local _,available,texture=GetCurrencyInfo(currency) GameTooltip:AddDoubleLine(TABARDVENDORCOST,format("%d |T%s:0|t",cost,texture),nil,nil,nil,C[cost>available and 'Red' or 'Green']()) end local members=party.members if followerTypeID == LE_FOLLOWER_TYPE_SHIPYARD_6_2 then GameTooltip:AddLine(GARRISON_FOLLOWER_IN_PARTY) for _,followerID in ipairs(members) do GameTooltip:AddLine(self:GetShipData(followerID,'fullname')) end end if self:GetBoolean("USEFUL") then local useful=new() local traited=G.GetFollowersTraitsForMission(missionID) local buffed=G.GetBuffedFollowersForMission(missionID,true) if (type(traited)=='table') then self:AddIconsToFollower(missionID,useful,traited,members,followerTypeID) end if (type(buffed)=='table') then self:AddIconsToFollower(missionID,useful,buffed,members,followerTypeID) end if next(useful) then table.sort(useful) GameTooltip:AddDoubleLine(L["Other useful followers"],L["(Ignores low bias ones)"]) local inactive=C(GARRISON_FOLLOWER_INACTIVE,'Red') for followerID,data in pairs(useful) do local status=self:GetFollowerStatus(followerID,true,true) if status ~=inactive then GameTooltip:AddDoubleLine(data:sub(5),status) end end end del(useful) end local perc=party.perc local q=self:GetDifficultyColor(perc) GameTooltip:AddDoubleLine(GARRISON_MISSION_SUCCESS,format(GARRISON_MISSION_PERCENT_CHANCE,perc),nil,nil,nil,q.r,q.g,q.b) for _,i in pairs (chardb.ignored[missionID]) do GameTooltip:AddLine(L["You have ignored followers"],C.Orange()) break; end if party.goldMultiplier>1 and party.class=='gold' then GameTooltip:AddDoubleLine(L["Gold incremented!"],party.goldMultiplier..'x',C.Green()) end if type(party.materialMultiplier)=="table" then for k,v in pairs(party.materialMultiplier) do GameTooltip:AddDoubleLine((GetCurrencyInfo(k)),v..'x',C.Green()) end end if party.xpBonus>0 then GameTooltip:AddDoubleLine(L["Xp incremented!"],'+'..party.xpBonus,C.Green()) end if party.isMissionTimeImproved then GameTooltip:AddLine(L["Mission time reduced!"],C.Green()) end if (chardb.history[missionID]) then local tot,success=0,0 for d,r in pairs(chardb.history[missionID]) do tot,success=tot+1,success + (r.success and 1 or 0) end if (tot > 0) then local ratio=floor(success/tot*100) GameTooltip:AddDoubleLine(format(L["You performed this mission %d times with a win ratio of"],tot),ratio..'%',0,1,0,self:GetDifficultyColors(ratio)) return end end GameTooltip:AddLine(L["You never performed this mission"],1,0,0) end local function switch(flag) if (GCF[flag]) then local b=GCF[flag] if (b:GetChecked()) then b.text:SetTextColor(C.Green()) else b.text:SetTextColor(C.Silver()) end end end function addon:RefreshParties() if true then addon:OnAllGarrisonMissions(function(missionID) addon:MatchMaker(missionID)end) else self:coroutineExecute(0.001,function() addon:OnAllGarrisonMissions(function(missionID) addon:MatchMaker(missionID) coroutine.yield(true) end) end ) end end function addon:RefreshMissions(missionID) self:GetMissions():UpdateMissions() end --[[ GARRISON_DURATION_DAYS = "%d |4day:days;"; changed to dual form GARRISON_DURATION_DAYS_HOURS = "%d |4day:days; %d hr"; changed to dual form GARRISON_DURATION_HOURS = "%d hr"; GARRISON_DURATION_HOURS_MINUTES = "%d hr %d min"; GARRISON_DURATION_MINUTES = "%d min"; GARRISON_DURATION_SECONDS = "%d sec"; --]] local function GarrisonTimeStringToSeconds(text) local s = D.Deformat(text,GARRISON_DURATION_SECONDS) if (s) then return s end local m = D.Deformat(text,GARRISON_DURATION_MINUTES) if m then return m end local h,m= D.Deformat(text,GARRISON_DURATION_HOURS_MINUTES) if (h) then return h*3600+m*60 end local h= D.Deformat(text,GARRISON_DURATION_HOURS) if (h) then return h*3600 end local d,h=D:Deformat(GARRISON_DURATION_DAY_HOURS) if (d) then return d*3600*24 + h*3600 end local d,h=D:Deformat(GARRISON_DURATION_DAYS_HOURS) if (d) then return d*3600*24 + h*3600 end local d=D:Deformat(GARRISON_DURATION_DAYS) if (d) then return d*3600*24 end local d=D:Deformat(GARRISON_DURATION_DAY) if (d) then return d*3600*24 end return 3600*24 end function addon:SetDbDefaults(default) default.global=default.global or {} default.global["*"]={} default.profile=default.profile or {} default.profile.blacklist={} default.profile.missionControl={ version=1, allowedRewards = { ['*']=true, }, rewardChance={ ['*']=100, }, rewardList={}, useOneChance=true, minimumChance = 100, minDuration = 0, maxDuration = 24, epicExp = false, skipRare=true, skipEpic=not addon:HasSalvageYard(), minLevel=540, minUpgrade=600 } default.profile.shipControl={ version=1, allowedRewards = { ['*']=true, }, rewardChance={ ['*']=100, }, rewardList={}, useOneChance=true, minimumChance = 100, minDuration = 0, maxDuration = 24, epicExp = false, skipRare=true, skipEpic=true, minLevel=540, minUpgrade=600 } end function addon:CreatePrivateDb() self.privatedb=self:RegisterDatabase( GetAddOnMetadata(me,"X-Database")..'perChar', { profile={ ignored={ ["*"]={ } }, totallyignored={ }, history={ ['*']={ } }, missionControl={ blacklist={}, version=3, allowedRewards = { ['*']=true, }, rewardChance={ ['*']=100, }, rewardList={}, useOneChance=true, minimumChance = 100, minDuration = 0, maxDuration = 24, epicExp = false, skipRare=true, skipEpic=not addon:HasSalvageYard(), minLevel=540, minUpgrade=600 } } }, true) chardb=self.privatedb.profile end function addon:SetClean() dirty=false end function addon:HasSalvageYard() local buildings=G.GetBuildings(LE_GARRISON_TYPE_6_0) for i =1,#buildings do local building=buildings[i] if building.texPrefix=="GarrBuilding_SalvageYard_1_A" then return true end end end function addon:WipeMission(missionID) counters[missionID]=nil parties[missionID]=nil --collectgarbage("step") end function addon:EventGARRISON_MISSION_NPC_CLOSED(event,...) --@debug@ self:Print(event,...) --@end-debug@ if (GCF) then self:RemoveMenu() GCF:Hide() end end --- --@param #string event GARRISON_MISSION_STARTED --@param #number missionID Numeric mission id -- After this events fires also GARRISON_MISSION_LIST_UPDATE and GARRISON_FOLLOWER_LIST_UPDATE function addon:EventGARRISON_MISSION_STARTED(event,missionType,missionID,...) --@debug@ print(event,missionType,missionID,...) --@end-debug@ self:RefreshFollowerStatus() if (not GMF:IsVisible()) then -- Shipyard return end wipe(chardb.ignored[missionID]) local party=self:GetParty(missionID) wipe(party.members) -- I remove preset party, so PartyCache will refill it with the ones from the actual mission if GMF:IsVisible() then self:RefreshParties() self:RefreshMissions() end end --- --@param #string event GARRISON_MISSION_FINISHED --@param #number missionID Numeric mission id -- Thsi is just a notification, nothing get really changed -- GetMissionINfo still returns data -- but GetPartyMissionInfo does no longer return followers. -- Also timeleft is false -- --- --@param #number missionID mission identifier --@param #boolean completed I suppose it always be true... --@param #boolean success Mission was succesfull --Mission complete Sequence is: --GARRISON_MISSION_COMPLETE_RESPONSE --GARRISON_MISSION_BONUS_ROLL_LOOT missionID true --GARRISON_FOLLOWER_XP_CHANGED (1 or more times --GARRISON_MISSION_NPC_OPENED ?? --GARRISON_MISSION_BONUS_ROLL_LOOY missionID nil -- function addon:EventGARRISON_MISSION_COMPLETE_RESPONSE(event,missionID,completed,rewards,...) --@debug@ print(event,missionID,completed,rewards,...) --@end-debug@ chardb.history[missionID][time()]={result=100,success=rewards} end ----------------------------------------------------- -- Coroutines data and clock management ----------------------------------------------------- local coroutines={ Timers={ func=false, elapsed=60, interval=60, paused=false }, } function addon:ActivateButton(button,OnClick,Tooltiptext,persistent) button:SetScript("OnClick",function(...) self[OnClick](self,...) end ) if (Tooltiptext) then button.tooltip=Tooltiptext button:SetScript("OnEnter",ShowTT) if persistent then button:SetScript("OnLeave",HideTT) else button:SetScript("OnLeave",HideTT) end else button:SetScript("OnEnter",nil) button:SetScript("OnLeave",nil) end end function addon:Shrink(button) local f=button.Toggle local name=f:GetName() or "Unnamed" if (f:GetHeight() > 200) then f.savedHeight=f:GetHeight() f:SetHeight(200) else f:SetHeight(f.savedHeight) end end do local s=setmetatable({},{__index=function(t,k) return 0 end}) local FOLLOWER_STATUS_FORMAT=(ns.bigscreen and L["Followers status "] or "" ).. C(AVAILABLE..':%d ','green') .. C(GARRISON_FOLLOWER_WORKING .. ":%d ",'cyan') .. C(GARRISON_FOLLOWER_ON_MISSION .. ":%d ",'red') .. C(GARRISON_FOLLOWER_INACTIVE .. ":%d","silver") function addon:RefreshFollowerStatus() wipe(s) for _,followerID in self:GetFollowersIterator() do local status=self:GetFollowerStatus(followerID) s[status]=s[status]+1 end if (GMF.FollowerStatusInfo) then GMF.FollowerStatusInfo:SetWidth(0) GMF.FollowerStatusInfo:SetFormattedText( FOLLOWER_STATUS_FORMAT, s[AVAILABLE], s[GARRISON_FOLLOWER_WORKING], s[GARRISON_FOLLOWER_ON_MISSION], s[GARRISON_FOLLOWER_INACTIVE] ) end end function addon:GetTotFollowers(status) if not status then return s[AVAILABLE]+ s[GARRISON_FOLLOWER_WORKING]+ s[GARRISON_FOLLOWER_ON_MISSION] else return s[status] or 0 end end end local helpwindow -- pseudo static function addon:ShowHelpWindow(button) addon:Help() end function addon:Toggle(button) local f=button.Toggle local name=f:GetName() or "Unnamed" --@debug@ print(name,f:IsShown()) --@end-debug@ if (f:IsShown()) then f:Hide() else f:Show() end if (button.SetChecked) then button:SetChecked(f:IsShown()) end end function addon:CreateOptionsLayer(...) local o=AceGUI:Create("SimpleGroup") -- a transparent frame o:SetLayout("Flow") o:SetCallback("OnClose",function(widget) widget:Release() end) local totsize=0 wipe(widgetsForKey) for i=1,select('#',...) do totsize=totsize+self:AddOptionToOptionsLayer(o,select(i,...)) end return o,totsize end function addon:AddOptionToOptionsLayer(o,flag,maxsize) maxsize=tonumber(maxsize) or 160 if (not flag) then return 0 end local info=addon:GetVarInfo(flag) if (info) then local data={option=info} local widget if (info.type=="toggle") then widget=AceGUI:Create("CheckBox") local value=addon:GetBoolean(flag) widget:SetValue(value) local color=value and "Green" or "Silver" widget:SetLabel(C(info.name,color)) widget:SetWidth(min(widget.text:GetStringWidth()+40,maxsize)) elseif(info.type=="select") then widget=AceGUI:Create("Dropdown") widget:SetValue(addon: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) elseif (info.type=="range") then local value=addon:GetNumber(flag) widget=AceGUI:Create("Slider") widget:SetLabel(info.name) widget:SetValue(value) widget:SetSliderValues(info.min,info.max,info.step) 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 local color=value and "Green" or "Silver" widget:SetLabel(C(info.name,color)) end self[info.set](self,data,value) end) widget:SetCallback("OnEnter",function(widget) GameTooltip:SetOwner(widget.frame,"ANCHOR_CURSOR") GameTooltip:AddLine(info.desc) GameTooltip:Show() end) widget:SetCallback("OnLeave",function(widget) GameTooltip:FadeOut() end) o:AddChildren(widget) widgetsForKey[flag]=widget end return maxsize end function addon:GetMain() return GMF end function addon:CreateHeader(module,MOVEPANEL,PIN) if not module then module=self end -- Main Garrison Commander Header local GCF=CreateFrame("Frame","GCF",UIParent,"GarrisonCommanderTitle") local signature=me .. " " .. self.version GCF.Signature:SetText(signature) local _,minor=LibStub("LibInit") local LL=LibStub("AceLocale-3.0"):GetLocale("LibInit" .. minor,true) self:MarkAsNew(GCF,self:NumericVersion(),LL["Release notes"] .. ' ' .. self.version,"Help") --@alpha@ GCF.Warning:SetText("Alpha Version") --@end-alpha@ -- Removing wood corner. I do it here to not derive an xml frame. This shoud play better with ui extensions GCF.CloseButton:Hide() for _,f in pairs({GCF.GarrCorners:GetRegions()}) do if (f:GetObjectType()=="Texture" and f:GetAtlas()=="Garr_WoodFrameCorner") then f:Hide() end end local main=module:GetMain() GCF:SetFrameStrata(main:GetFrameStrata()) GCF:SetFrameLevel(max(0,main:GetFrameLevel()-2)) if module == self then GCF:SetHeight(130) end baseHeight=GCF:GetHeight() minHeight=47 GCF.CloseButton:SetScript("OnClick",nil) GCF.Pin:SetAllPoints(GCF.CloseButton) GCF:SetWidth(BIGSIZEW) GCF:SetPoint("TOP",UIParent,0,-60) if (self:GetBoolean(PIN)) then GCF.Pin:SetChecked(true) GCF:SetHeight(baseHeight) else GCF.Pin:SetChecked(false) GCF:SetHeight(minHeight) end do local baseHeight=baseHeight local minHeight=minHeight local baseStrata=GCF:GetFrameStrata() local baseLevel=GCF:GetFrameStrata() local speed=3 local GCF=GCF local module=module local MOVEPANEL=MOVEPANEL local PIN=PIN local function shrink(this) module:RemoveMenu() this:SetScript("OnUpdate",function(me,ts) local h=me:GetHeight() if (h<=45) then me:SetHeight(45) me:SetScript("OnUpdate",nil) GCF.tooltip=L["You can open the menu clicking on the icon in top right corner"] else me:SetHeight(h-2) end end) end local function grow(this) this:SetScript("OnUpdate",function(me,ts) local h=me:GetHeight() if (h>=baseHeight) then me:SetScript("OnUpdate",nil) me:SetHeight(baseHeight) if (not me.Menu) then module:AddMenu() end GCF.tooltip=nil me.Menu:DoLayout() else me:SetHeight(h+2) end end) end GCF.Pin.tooltip=L["Toggles Garrison Commander Menu Header on/off"] GCF.Pin:SetScript("OnEnter",ShowTT) GCF.Pin:SetScript("OnClick",function(this) local value=this:GetChecked() addon:SetBoolean(PIN,value) if (value) then grow(GCF) else shrink(GCF) end end) end GCF:EnableMouse(true) GCF:SetMovable(true) --GCF:RegisterForDrag("LeftButton") --[===[@non-debug@ GCF:SetScript("OnDragStart",function(frame) print(MOVEPANEL,self:GetBoolean(MOVEPANEL)) if self:GetBoolean(MOVEPANEL) then frame:StartMoving() end end) --@end-non-debug@]===] --@debug@ GCF:SetScript("OnDragStart",function(frame) print(self,MOVEPANEL,self:GetBoolean(MOVEPANEL)) frame:StartMoving() end) --@end-debug@ GCF:SetScript("OnDragStop",function(frame) frame:StopMovingOrSizing() end) GCF:Show() return GCF end function addon:ScriptTrace(hook,frame,...) --@debug@ print("Triggered " .. C(hook,"red").." script on",C(frame,"Azure"),...) --@end-debug@ end function addon:IsProgressMissionPage() return GMF:IsVisible() and GMF.MissionTab and GMF.MissionTab.MissionList.showInProgress end function addon:IsAvailableMissionPage() return GMF:IsVisible() and GMF.MissionTab:IsVisible() and not GMF.MissionTab.MissionList.showInProgress end function addon:IsFollowerList() return GMF:IsVisible() and GMFFollowers:IsVisible() end --GMFMissions.CompleteDialog function addon:IsRewardPage() return GMF:IsVisible() and GMFMissions.CompleteDialog:IsVisible() end function addon:IsMissionPage() return GMF:IsVisible() and GMFMissionPage:IsVisible() end --- function addon:HookedGarrisonFollowerTooltipTemplate_SetGarrisonFollower(...) if not self:IsMissionPage() then local g=GameTooltip g:SetOwner(GarrisonFollowerTooltip, "ANCHOR_NONE") g:SetPoint("TOPLEFT",GarrisonFollowerTooltip,"BOTTOMLEFT") g:AddLine(L["Left Click to see available missions"],C.Green()) g:SetWidth(GarrisonFollowerTooltip:GetWidth()) g:Show() end end function addon:HookedGarrisonFollowerButton_UpdateCounters(...) return self:RenderFollowerPageFollowerButton(select(2,...)) end function addon:RenderFollowerPageFollowerButton(frame,follower,showCounters) if not frame.GCWep then frame.GCWep=frame:CreateFontString(nil,"ARTWORK","GameFontHighlightSmall") frame.GCWep:SetPoint("LEFT",frame.ILevel,"RIGHT",5,0) frame.GCArm=frame:CreateFontString(nil,"ARTWORK","GameFontHighlightSmall") frame.GCArm:SetPoint("LEFT",frame.GCWep,"RIGHT",5,0) frame.GCXp=frame:CreateFontString(nil,"ARTWORK","GameFontHighlightSmall") frame.GCXp:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-5,5) end if not follower.isCollected or type(follower.followerID)=="number" or follower.isTroop then frame.GCXp:Hide() frame.GCWep:Hide() frame.GCArm:Hide() return end if self:GetToggle("IXP") and (follower.level < GARRISON_FOLLOWER_MAX_LEVEL or follower.quality < GARRISON_FOLLOWER_MAX_UPGRADE_QUALITY) and tonumber(follower.levelXP) and tonumber(follower.xp) then frame.GCXp:SetFormattedText(L["To go: %d"],tonumber(follower.levelXP,follower.xp)-follower.xp) frame.GCXp:Show() else frame.GCXp:Hide() end if self:GetToggle("ILV") then if follower.isMaxLevel then local c1=ITEM_QUALITY_COLORS[self:GetAnyData(follower.followerTypeID,follower.followerID,"weaponQuality" ,1)] local c2=ITEM_QUALITY_COLORS[self:GetAnyData(follower.followerTypeID,follower.followerID,"armorQuality" ,1)] frame.GCWep:SetFormattedText("W:%3d",self:GetAnyData(follower.followerTypeID,follower.followerID,"weaponItemLevel",600)) frame.GCArm:SetFormattedText("A:%3d",self:GetAnyData(follower.followerTypeID,follower.followerID,"armorItemLevel",600)) frame.GCWep:SetTextColor(c1.r,c1.g,c1.b) frame.GCArm:SetTextColor(c2.r,c2.g,c2.b) frame.GCWep:Show() frame.GCArm:Show() else frame.GCWep:Hide() frame.GCArm:Hide() end else frame.GCWep:Hide() frame.GCArm:Hide() end end function addon:HookedGarrisonFollowerListButton_OnClick(frame,button) --@debug@ print("Click") --@end-debug@ if (button=="LeftButton") then if (frame and frame.info and frame.info.followerID) then self:HookedGarrisonFollowerPage_ShowFollower(frame.info,frame.info.followerID) end end if (frame.info.isCollected) then self:ScheduleTimer("HookedGarrisonFollowerButton_UpdateCounters",0.2,GMF,frame,frame.info,false) end self:GetModule("FollowerPage"):ShowUpgradeButtons() end -- Shamelessly stolen from Blizzard Code -- Appears when hovering on menaces in mission button function addon.ClonedGarrisonMissionMechanic_OnEnter(this) --@debug@ print(this) --@end-debug@ local tip=GameTooltip local button=this:GetParent() tip:SetOwner(button, "ANCHOR_CURSOR_RIGHT"); tip:AddLine(this.Name,C.White()) tip:AddTexture(this.texture) tip:AddLine(this.Description,C.Orange()) if (this.countered) then if this.IsEnv then local t=G.GetFollowersTraitsForMission(this.missionID) for followerID,k in pairs(t) do for i=1,#k do if k[i].icon==this.texture then tip:AddDoubleLine(addon:GetFollowerData(followerID,'fullname'),this.Name) end end end else local t=G.GetBuffedFollowersForMission(this.missionID,true) for followerID,k in pairs(t) do for i=1,#k do if k[i].name==this.Name then tip:AddDoubleLine(addon:GetFollowerData(followerID,'fullname'),k[i].counterName) end end end end end tip:Show() end local function removeAllFollowers(missionID) local x=G.GetBasicMissionInfo(missionID) if x then for i=1,#x.followers do G.RemoveFollowerFromMission(missionID,x.followers[i]) end end end function addon:HookedGarrisonFollowerPage_ShowFollower(frame,followerID,force) return self:RenderFollowerPageMissionList(frame,followerID,force) end do local Busystatusmessage local lastFollowerID="" local ml=nil local mh=nil local tContains=tContains local function MissionOnClick(this,method,frame,button) local m=GMF.MissionTab.MissionPage.missionInfo if m and m.missionID then holdEvents() local rc,message=pcall(removeAllFollowers,m.missionID) if not rc then --@debug@ print(message) --@end-debug@ end releaseEvents() end if button=="RightButton" then return addon:ScriptGarrisonMissionButton_OnClick(this.frame,button) end GMF:OnClickMission(this.frame.info,button) if (PanelTemplates_GetSelectedTab(GMF) ~= 1) then addon:OpenMissionsTab() end --addon:ScriptGarrisonMissionButton_OnClick(this.frame,button) addon:FillMissionPage(this.frame.info) lastTab=2 end function addon:RenderFollowerPageMissionList(dummy,followerID,force) print(ns.bigscreen,GMFFollowers:IsVisible()) --if not ns.bigscreen then return end if not ns.bigscreen and not self:GetBoolean("FOLLOWERMISSIONLIST") then if mh then mh:Hide() end return end if not GMFFollowers:IsVisible() then return end -- Mission list on follower panels if not mh then mh=CreateFrame("Frame","GCFMissions",GMFFollowers,"GarrisonCommanderFollowerMissionList") GCFMissions=mh local fs=mh:CreateFontString(nil, "BACKGROUND", "GameFontNormalHugeBlack") if (ns.bigscreen) then mh:SetPoint("TOPLEFT",GMFFollowers,"TOPRIGHT") fs:SetPoint("TOPLEFT",GMFFollowers,"TOPRIGHT") else mh:SetPoint("BOTTOMRIGHT",GMF,"TOPLEFT") fs:SetPoint("TOPRIGHT",GMFFollowers,"TOPLEFT") mh.Header:ClearAllPoints() mh.Header:SetPoint("BOTTOMRIGHT") end mh:SetHeight(60) fs:SetText(AVAILABLE) fs:SetWidth(250) fs:Show() GCFBusyStatus=fs end if (not ml) then --@debug@ print("Building MissionList Widget") --@end-debug@ ml=AceGUI:Create("GMCLayer") ml:SetTitle("Ninso") ml:SetTitleColor(C.Orange()) ml:SetTitleHeight(40) ml:SetParent(mh) ml:Show() ml:ClearAllPoints() ml:SetWidth(200) ml:SetHeight(600) ml:SetPoint("TOP",mh,"BOTTOM") if ns.bigscreen then ml:SetPoint("LEFT",GMFFollowers,"RIGHT") ml:SetPoint("RIGHT",GMF.FollowerTab,"LEFT") else ml:SetPoint("RIGHT",GMF,"LEFT") ml:SetWidth(300) end ml:SetPoint("BOTTOM",GMF,0,ns.bigscreen and 25 or 0) end ml:ClearChildren() if type(followerID)=="number" then ml:SetTitle(NOT_COLLECTED) ml:SetTitleColor(C.Silver()) mh.Header:Hide() return end mh.Header:Show() local status=self:GetFollowerStatus(followerID,true) self:RenderFollowerButton(mh.Header,followerID) mh:Show() ml:Show() ml:SetTitle(status) if (status==GARRISON_FOLLOWER_WORKING) then ml:SetTitleColor(C.Cyan()) return elseif (status==AVAILABLE) then ml:SetTitleColor(C.Green()) else ml:SetTitleColor(C.Red()) return end local partyIndex=new() local parties=self:GetParty() for missionID,party in pairs(parties) do if (tContains(party.members,followerID)) then tinsert(partyIndex,missionID) end end table.sort(partyIndex,function(a,b) return parties[a].perc > parties[b].perc end) for i=1,#partyIndex do local missionID=partyIndex[i] local party=parties[missionID] local mission=self:GetMissionData(missionID) if mission and party and #party.members >= G.GetMissionMaxFollowers(missionID) then local mb=AceGUI:Create("GMCMissionButton") mb:SetScale(0.6) mb:SetFullWidth(true) ml:PushChild(mb,missionID) mb:SetMission(mission,party,false,"followers") mb:SetCallback("OnClick",MissionOnClick) end end del(partyIndex) end end --- --Initial one time setup function addon:Setup(...) --@debug@ print("Setup") --@end-debug@ SIZEV=GMF:GetHeight() self:CheckMP() if MP then self:AddToggle("CKMP",true,L["Use GC Interface"],L["Switch between Garrison Commander and Master Plan interface for missions"]) local t= G.GetCompleteMissions(LE_FOLLOWER_TYPE_GARRISON_6_0) if #t > 0 then C_Timer.After(0.4,function() GarrisonMissionFrameMissions.CompleteDialog:Show() end) end end self:CheckGMM() GCF=self:CreateHeader(self,"MOVEPANEL","PIN") local tabMC=CreateFrame("CheckButton",nil,GMF,"SpellBookSkillLineTabTemplate") GMF.tabMC=tabMC tabMC.tooltip=L["Open Garrison Commander Mission Control"] tabMC:SetNormalTexture("Interface\\ICONS\\ACHIEVEMENT_GUILDPERK_WORKINGOVERTIME.blp") tabMC:SetScript("OnClick",function(this,...) addon:OpenMissionControlTab() end) tabMC:Show() tabMC:SetPoint('TOPLEFT',GCF,'TOPRIGHT',0,-110) GMF.FollowerStatusInfo=GMF:CreateFontString(nil, "BORDER", "GameFontNormal") GMF.FollowerStatusInfo:SetPoint("TOPRIGHT",-30,-5) local tabCF=CreateFrame("Button",nil,GMF,"SpellBookSkillLineTabTemplate") GMF.tabCF=tabCF tabCF.tooltip=L["Open Garrison Commander Configuration Screen"] tabCF:SetNormalTexture("Interface\\ICONS\\Trade_Engineering.blp") tabCF:SetPushedTexture("Interface\\ICONS\\Trade_Engineering.blp") tabCF:Show() tabCF:SetPoint('TOPLEFT',GCF,'TOPRIGHT',0,-60) tabCF:SetScript("OnClick",function(this,...) GMF:Hide() addon:Gui() end) local tabHP=CreateFrame("Button",nil,GMF,"SpellBookSkillLineTabTemplate") GMF.tabHP=tabHP tabHP.tooltip=L["Open Garrison Commander Help"] tabHP:SetNormalTexture("Interface\\ICONS\\INV_Misc_QuestionMark.blp") tabHP:SetPushedTexture("Interface\\ICONS\\INV_Misc_QuestionMark.blp") tabHP:Show() tabHP:SetPoint('TOPLEFT',GCF,'TOPRIGHT',0,-10) tabHP:SetScript("OnClick",function(this,button) addon:ShowHelpWindow(this,button) end) -- retrieving release notes localization from LibInit local tabQ=CreateFrame("Button",nil,GMF,"SpellBookSkillLineTabTemplate") GMF.tabQ=tabQ tabQ.tooltip=L["Automatically process completed missions and schedules new ones."].."\n".. format(L["Check %s in mission control in order to be also logged out"],L["Auto Logout"]) .. "\n" .. C(format(L["Keep pressed %s while opening table to automate processing"],CTRL_KEY),"green") tabQ:SetNormalTexture("Interface\\ICONS\\Ability_Rogue_Sprint.blp") tabQ:SetPushedTexture("Interface\\ICONS\\Ability_Rogue_Sprint.blp") tabQ:Show() tabQ:SetScript("OnClick",function(this,button) addon:RunQuick() end) tabQ:SetPoint('TOPLEFT',GCF,'TOPRIGHT',0,-210) local ref=GMFMissions.CompleteDialog.BorderFrame.ViewButton local bt = CreateFrame('BUTTON','GarrisonCommanderQuickMissionComplete', ref, 'UIPanelButtonTemplate') bt:SetWidth(300) bt:SetText(L["Garrison Comander Quick Mission Completion"]) bt:SetPoint("CENTER",0,-50) bt.missionType=LE_FOLLOWER_TYPE_GARRISON_6_0 addon:ActivateButton(bt,"MissionComplete",L["Complete all missions without confirmation"]) self:SafeSecureHookScript("GarrisonMissionFrame","OnShow") self:SafeSecureHookScript("GarrisonMissionFrame","OnHide") self:Trigger("MSORT") local parties=self:GetParties() if #parties==0 then addon:OnAllGarrisonMissions(function(missionID) addon:MatchMaker(missionID) end) end return self:ScriptGarrisonMissionFrame_OnShow() --collectgarbage("step",10) --/Interface/FriendsFrame/UI-Toast-FriendOnlineIcon end function addon:RefreshConfig(event,settings,oldsettings,classlist,class2order,followerType) if #settings.rewardList==0 and oldsettings and #oldsettings.rewardList>0 then clone(oldsettings,settings) end --self:ShowList() -- 1) Check for removed category local validKeys={} for _,v in ipairs(addon:GetRewardClasses(followerType)) do validKeys[v.key]=true end local good=new() for index=1,#classlist do local key=classlist[index] if key then if validKeys[key] then tinsert(good,key) end end end if #good > 0 then wipe(classlist) for i=1,#good do tinsert(classlist,good[i]) end end del(good) wipe(class2order) for index,key in ipairs(classlist) do class2order[key]=index end -- 2) Check for added categories if #classlist < #addon:GetRewardClasses(followerType) then self:Print("Check for additions") for _,v in ipairs(addon:GetRewardClasses(followerType)) do if not rawget(class2order,v.key) then tinsert(classlist,v.key) end end wipe(class2order) for index,key in ipairs(classlist) do class2order[key]=index end end end local function frametoname(m) if m==GMF.MissionTab then return "MissionTab" elseif m==GMF.FollowerTab then return "FollowerTab" elseif m==GMF.SummaryTab then return "Summary" elseif m==GMF.MissionContrlTab then return "MissionControl" end return "none" end function addon:RefreshMenu() if not GCF then return end -- This could be called befaur header is built self:RemoveMenu() self:AddMenu() end function addon:AddMenu() if GCF.Menu then return end local menu,size if GMF.MissionTab:IsVisible() then self.currentmenu=GMF.MissionTab menu,size=self:CreateOptionsLayer(MP and 'CKMP' or nil,'BIGSCREEN','MSORT','MAXRES','MAXRESCHANCE','IGM','IGP','NOFILL','USEFUL','NOTOOLTIP','MOVEPANEL') elseif GMF.FollowerTab:IsVisible() then local missionlist=ns.bigscreen or self:GetBoolean("FOLLOWERMISSIONLIST") self.currentmenu=GMF.FollowerTab menu,size=self:CreateOptionsLayer('BIGSCREEN',ns.bigscreen and nil or 'FOLLOWERMISSIONLIST',missionlist and 'MAXMISSIONS' or nil,missionlist and 'MINPERC' or nil,'ILV','IXP','UPG','NOCONFIRM','SWAPBUTTONS','MOVEPANEL') self:RenderFollowerPageMissionList(nil,GMF.FollowerTab.followerID) elseif GMF.SummaryTab and GMF.SummaryTab:IsVisible() then local missionlist=ns.bigscreen or self:GetBoolean("FOLLOWERMISSIONLIST") self.currentmenu=GMF.SummaryTab menu,size=self:CreateOptionsLayer('BIGSCREEN',ns.bigscreen and nil or 'FOLLOWERMISSIONLIST',missionlist and 'MAXMISSIONS' or nil,missionlist and 'MINPERC' or nil,'ILV','IXP','UPG','NOCONFIRM','SWAPBUTTONS','MOVEPANEL') self:RenderFollowerPageMissionList(nil,GMF.FollowerTab.followerID) elseif GMF.MissionControlTab:IsVisible() then self.currentmenu=GMF.MissionControlTab menu,size=self:CreateOptionsLayer('BIGSCREEN','GCMINLEVEL','GCMINUPGRADE','MINXPLEVEL','MINGOLD','GCSKIPRARE','GCSKIPEPIC','USEFUL','NOTOOLTIP') else self.currentmenu=nil menu,size=self:CreateOptionsLayer('BIGSCREEN') end --@debug@ self:AddOptionToOptionsLayer(menu,'DBG') self:AddOptionToOptionsLayer(menu,'TRC') --@end-debug@ local frame=menu.frame frame:Show() frame:SetParent(GCF) frame:SetFrameStrata(GCF:GetFrameStrata()) frame:SetFrameLevel(GCF:GetFrameLevel()+2) menu:ClearAllPoints() menu:SetPoint("TOPLEFT",GCF,"TOPLEFT",25,-18) menu:SetWidth(GCF:GetWidth()-50) menu:SetHeight(GCF:GetHeight()-50) menu:DoLayout() GCF.Menu=menu end function addon:RemoveMenu() if (GCF.Menu) then local rc,message=pcall(GCF.Menu.Release,GCF.Menu) GCF.Menu=nil end end function addon:AddMissionId(b) if (b.info and b.info.missionID) then GameTooltip:AddDoubleLine("MissionID",b.info.missionID) GameTooltip:Show() end end function addon:ScriptGarrisonMissionFrame_OnHide() self:Unhook(GMFMissions,"UpdateMissions") end --- -- Additional setup -- This method is called every time garrison mission panel is open because -- when it closes, I remove most of used hooks function addon:ScriptGarrisonMissionFrame_OnShow(...) --@debug@ print("GMF OnShow") --@end-debug@ self:GrowPanel() if (self:GetBoolean("PIN")) then GCF:SetHeight(baseHeight) self:AddMenu() else GCF:SetHeight(minHeight) end self:PermanentEvents() ns.tabCO:ClearAllPoints() ns.tabCO:SetParent(GMF) ns.tabCO:SetPoint('TOPRIGHT',GMF,'TOPLEFT',0,0) --self:SafeSecureHook("GarrisonMissionButton_AddThreatsToTooltip") self:SafeSecureHook("GarrisonFollowerListButton_OnClick") -- used both to update follower mission list and itemlevel display if (ns.bigscreen) then self:SafeSecureHook("GarrisonFollowerTooltipTemplate_SetGarrisonFollower") end for i =1,9 do local hook="GarrisonMissionFrameTab" ..i if (_G[hook]) then self:SafeHookScript(hook,"OnClick","HookedClickOnTabs") end end -- Mission management self:SafeHookScript(GMF.MissionComplete.NextMissionButton,"OnClick","OnClick_GarrisonMissionFrame_MissionComplete_NextMissionButton",true) self:SafeHookScript(GMFMissions.CompleteDialog,"OnShow","RaiseCompleteDialog") if (GMFMissions.CompleteDialog:IsVisible()) then self:RaiseCompleteDialog() end self:RefreshFollowerStatus() self:Trigger("MSORT") self:Trigger("CKMP") if IsControlKeyDown() then self:ScheduleTimer("RunQuick",0.1,true) end self:RawHook(GMFMissions,"UpdateMissions","OnUpdateMissions",true) GMFMissions:Update() return self:RefreshMissions() end function addon:RaiseCompleteDialog() local f=GMFMissions.CompleteDialog if f:GetFrameLevel() < 80 then f:SetFrameLevel(80) end print("Dialog:",GMFMissions.CompleteDialog:GetFrameLevel()) --C_Timer.After(0.1,function() local f=GMFMissions.CompleteDialog print("Dialog:",f:GetFrameLevel()) if f:GetFrameLevel() < 45 then f:SetFrameLevel(45) end print("Dialog:",f:GetFrameLevel()) end) end local newsframes={} function addon:MarkAsNew(obj,key,message,method) --@debug@ db.news[key]=false --@end-debug@ if (not db.news[key]) then local f=CreateFrame("Button",nil,obj,"GarrisonCommanderWhatsNew") f.tooltip=message f.texture:ClearAllPoints() f.texture:SetAllPoints() f:SetPoint("TOPLEFT",obj,"TOPLEFT") f:SetFrameStrata("HIGH") f:Show() if method then f:SetScript("OnClick",function(frame) self[method](self,frame) self:MarkAsSeen(key) end) else f:SetScript("OnClick",function(frame) self:MarkAsSeen(key) end) end newsframes[key]=f end end function addon:MarkAsSeen(key) db.news[key]=true if newsframes[key] then newsframes[key]:Hide() end end function addon:PermanentEvents() -- Follower button enhancement in follower list self:SafeSecureHook("GarrisonFollowerButton_UpdateCounters") end function addon:checkHandler(handler) assert (type(handler)=='function' or type(self[handler])=='function',format("Unable to validate handler '%s'",tostring(handler))) end function addon:SafeRegisterEvent(event,handler) handler=handler or "Event"..event self:checkHandler(handler) return self:RegisterEvent(event,handler) end function addon:SafeRawHook(object,method,handler) return self:SafeHook(object,method,handler or 'raw','raw') end function addon:SafeSecureHook(object,method,handler) return self:SafeHook(object,method,handler or 'secure','secure') end function addon:SafeHook(object,method,handler,hookType) if (self:IsHooked(object,method)) then return end if type(object) == "string" then method, handler, hookType , object = object, method, handler,nil end handler=handler or "Hooked"..method self:checkHandler(handler) if hookType=="post" or hookType=="secure" then self:SecureHook(object,method,handler) elseif hookType=="raw" then self:RawHook(object,method,handler,true) else self:Hook(object,method,handler) end end function addon:SafeSecureHookScript(frame,method,handler) return self:SafeHookScript(frame,method,handler,"secure") end function addon:SafeRawHookScript(frame,method,handler) return self:SafeHookScript(frame,method,handler,"raw") end function addon:SafeHookScript(frame,method,handler,hookType) local name="Unknown" if (type(frame)=="string") then name=frame frame=_G[frame] else if (frame and frame.GetName) then name=frame:GetName() end end if (frame) then if not handler then handler=format('Script%s_%s',name,method) elseif type(handler)=="boolean" then --@debug@ do local method=method handler=function(...) print(name,method,...) end end --@end-debug@ --[===[@non-debug@ return -- Trace only hook are not for public --@end-non-debug@]===] end self:checkHandler(handler) if hookType and type(hookType)=="boolean" then hookType="post" end --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 hookType=="post" or hookType=="secure" then self:SecureHookScript(frame,method,handler) elseif (hookType=="raw") then self:RawHookScript(frame,method,handler) else self:HookScript(frame,method,handler) end end end local converter=CreateFrame("Frame"):CreateTexture() local shipconv=CreateFrame("Frame",nil,nil,"GarrisonShipMissionCompleteFollowerTemplate") function addon:GetFollowerTexture(followerID,followerType) local follower=type(followerID)=="table" and followerID or nil followerType=followerType or LE_FOLLOWER_TYPE_GARRISON_6_0 if not follower then follower=self:GetAnyData(followerType,follower) end if toc >=70000 then local iconID=follower and follower.portraitIconID or nil print(followerType,followerID,iconID,self:GetAnyData(followerType,followerID)) if iconID then return iconID end else if follower and follower.followerID then followerType=follower.followerTypeID if followerType==LE_FOLLOWER_TYPE_GARRISON_6_0 then local iconID=follower.portraitIconID if iconID then converter:SetToFileData(iconID) return converter:GetTexture() end elseif followerType==LE_FOLLOWER_TYPE_SHIPYARD_6_2 then local texPrefix=follower.texPrefix if texPrefix then shipconv.Portrait:SetAtlas(texPrefix.."-List") return shipconv.Portrait:GetTexture() end 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() --@debug@ print("Cleaning up") --@end-debug@ self:RemoveMenu() if (GarrisonFollowerTooltip.fs) then GarrisonFollowerTooltip.fs:Hide() end GMFMissions.CompleteDialog:Hide() self:GetModule("MissionCompletion"):CloseReport() --collectgarbage("collect") end function addon:IsFollowerAvailableForMission(followerID,skipbusy) if self:GMCBusy(followerID) then return false end if (not skipbusy) then return self:GetFollowerStatus(followerID) ~= GARRISON_FOLLOWER_WORKING else return self:GetFollowerStatus(followerID) == AVAILABLE end end function addon:GetFollowerStatus(followerID,withTime,colored) --C_Garrison.GetFollowerMissionTimeLeftSeconds(follower.followerID) if (not followerID) then return UNAVAILABLE end local rc,status=pcall(G.GetFollowerStatus,followerID) if (not rc) then --@debug@ print("WARNING:",followerID,status) ns.raised=true --@end-debug@ return UNAVAILABLE end ns.raised=nil if (status and status== GARRISON_FOLLOWER_ON_MISSION and withTime) then status=G.GetFollowerMissionTimeLeft(followerID) end -- The only case a follower appears in party is after a refused mission due to refresh triggered before GARRISON_FOLLOWER_LIST_UPDATE if (status and status~=GARRISON_FOLLOWER_IN_PARTY) then return colored and C(status,"Red") or status else return colored and C(AVAILABLE,"Green") or AVAILABLE end end local GARRISON_MISSION_AVAILABILITY1=GARRISON_MISSION_AVAILABILITY..'\n %s' local GARRISON_MISSION_AVAILABILITY2=GARRISON_MISSION_ENVIRONMENT:sub(1,10)..GARRISON_MISSION_AVAILABILITY..':|r %s' local GARRISON_MISSION_ID=GARRISON_MISSION_ENVIRONMENT:sub(1,10)..'MissionID:|r |cffffffff%s|r' local fakeinfo={followerID=false} local fakeframe={} local mainframes={ [LE_FOLLOWER_TYPE_GARRISON_6_0]="GarrisonMissionFrame", [LE_FOLLOWER_TYPE_SHIPYARD_6_2]="GarrisonShipyardFrame", } function addon:FillMissionPage(missionInfo) if type(missionInfo)=="number" then missionInfo=self:GetMissionData(missionInfo) end if not missionInfo then return end local missionType=missionInfo.followerTypeID if missionType==LE_FOLLOWER_TYPE_SHIPYARD_6_2 then if not missionInfo.canStart then return end end local main=_G[mainframes[missionType]] if not main then return end local missionpage=main:GetMissionPage() local stage=main.MissionTab.MissionPage.Stage local missionenv=stage.MissionInfo.MissionEnv if not stage.MissionSeen then if not stage.expires then stage.expires=stage:CreateFontString() stage.expires:SetFontObject(missionenv:GetFontObject()) stage.expires:SetDrawLayer(missionenv:GetDrawLayer()) stage.expires:SetPoint("TOPLEFT",missionenv,"BOTTOMLEFT") end stage.expires:SetFormattedText(GARRISON_MISSION_AVAILABILITY2,missionInfo.offerTimeRemaining or "") stage.expires:SetTextColor(self:GetAgeColor(missionInfo.offerEndTime)) else stage.expires=stage.MissionSeen -- In order to anchor missionId end --@debug@ if not stage.missionid then stage.missionid=stage:CreateFontString() stage.missionid:SetFontObject(missionenv:GetFontObject()) stage.missionid:SetDrawLayer(missionenv:GetDrawLayer()) stage.missionid:SetPoint("TOPLEFT",stage.expires,"BOTTOMLEFT") end stage.missionid:SetFormattedText(GARRISON_MISSION_ID,missionInfo.missionID) --@end-debug@ if( IsShiftKeyDown()) then self:Print("Shift key, ignoring mission prefill") return end if (self:GetBoolean("NOFILL")) then return end local missionID=missionInfo.missionID --holdEvents() main:ClearParty() local party=self:GetParty(missionID) if (party) then local members=party.members for i=1,missionInfo.numFollowers do local followerframe=missionpage.Followers[i] local followerID=members[i] if followerID then main:AssignFollowerToMission(followerframe,self:GetAnyData(missionInfo.followerTypeID,followerID)) end end else --@debug@ print("No martini no party") --@end-debug@ end main:UpdateMissionParty(main.MissionTab.MissionPage.Followers) main:UpdateMissionData(main.MissionTab.MissionPage) --self:Dump(GMF.MissionTab.MissionPage.Followers,"Selected followers") --GarrisonMissionPage_UpdateEmptyString() --releaseEvents() end local firstcall=true ---@function GrowPanel -- Enforce the new panel sizes -- function addon:GrowPanel() GCF:Show() if (ns.bigscreen) then -- GMF:ClearAllPoints() -- GMF:SetPoint("TOPLEFT",GCF,"BOTTOMLEFT") -- GMF:SetPoint("TOPRIGHT",GCF,"BOTTOMRIGHT") GMFRewardSplash:ClearAllPoints() GMFRewardSplash:SetPoint("TOPLEFT",GCF,"BOTTOMLEFT") GMFRewardSplash:SetPoint("TOPRIGHT",GCF,"BOTTOMRIGHT") GMFRewardPage:ClearAllPoints() GMFRewardPage:SetPoint("TOPLEFT",GCF,"BOTTOMLEFT") GMFRewardPage:SetPoint("TOPRIGHT",GCF,"BOTTOMRIGHT") GMF:SetHeight(BIGSIZEH) GMFMissions:SetPoint("BOTTOMRIGHT",GMF,-25,35) GMFFollowers:SetPoint("BOTTOMLEFT",GMF,-35,65) GMFMissionsListScrollFrameScrollChild:ClearAllPoints() GMFMissionsListScrollFrameScrollChild:SetPoint("TOPLEFT",GMFMissionsListScrollFrame) GMFMissionsListScrollFrameScrollChild:SetPoint("BOTTOMRIGHT",GMFMissionsListScrollFrame) GMFFollowersListScrollFrameScrollChild:SetPoint("BOTTOMLEFT",GMFFollowersListScrollFrame,-35,35) GMF.MissionCompleteBackground:SetWidth(BIGSIZEW) else GCF:SetWidth(GMF:GetWidth()) -- GMF:ClearAllPoints() -- GMF:SetPoint("TOPLEFT",GCF,"BOTTOMLEFT",0,-25) -- GMF:SetPoint("TOPRIGHT",GCF,"BOTTOMRIGHT",0,-25) end GMF:ClearAllPoints() GMF:SetPoint("TOPLEFT",GCF,"BOTTOMLEFT",0,23) GMF:SetPoint("TOPRIGHT",GCF,"BOTTOMRIGHT",0,23) end ---@function -- Return bias color for follower and mission -- @param #number bias bias as returned by blizzard interface [optional] -- @param #string followerID -- @param #number missionID function addon:GetBiasColor(followerID,missionID,goodcolor) goodcolor=goodcolor or "White" local bias=followerID or 0 if (missionID) then local rc,followerBias = pcall(G.GetFollowerBiasForMission,missionID,followerID) if (not rc) then return goodcolor else bias=followerBias end end if not tonumber(bias) then return "Yellow" end if (bias==-1) then return "Red" elseif (bias < 0) then return "Orange" end return goodcolor end function addon:RenderFollowerButton(frame,followerID,missionID,b,t) if (not frame) then return end if (frame.Threats) then for i=1,#frame.Threats do if (frame.Threats[i]) then frame.Threats[i]:Hide() end end frame.NotFull:Hide() end if (not followerID) then if (frame.Name) then frame.PortraitFrame.Empty:Show() frame.Name:Hide() frame.Class:Hide() frame.Status:Hide() else frame.PortraitFrame.Empty:Hide() frame.PortraitFrame.Portrait:Show() frame.PortraitFrame.LevelBorder:SetAtlas("GarrMission_PortraitRing_iLvlBorder"); frame.PortraitFrame.LevelBorder:SetWidth(70); frame.PortraitFrame.Level:SetText(MISSING) frame.PortraitFrame.Level:SetTextColor(1,0,0,0.7) end frame.PortraitFrame.LevelBorder:SetAtlas("GarrMission_PortraitRing_LevelBorder"); frame.PortraitFrame.LevelBorder:SetWidth(58); GarrisonFollowerPortrait_Set(frame.PortraitFrame.Portrait) frame.PortraitFrame.PortraitRingQuality:SetVertexColor(C.Silver()); frame.PortraitFrame.LevelBorder:SetVertexColor(C.Silver()); frame.info=nil return end frame:EnableMouse(true) frame.PortraitFrame.Level:SetTextColor(1,1,1,1) frame.PortraitFrame.Portrait:Show() local info=self:GetAnyData(0,followerID) if (not info) then --@debug@ print("Unable to find follower",followerID) --@end-debug@ return end frame.info=info frame.missionID=missionID if (frame.Name) 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); end frame.PortraitFrame.Empty:Hide(); local showItemLevel; if (info.level == GMF.followerMaxLevel ) then frame.PortraitFrame.LevelBorder:SetAtlas("GarrMission_PortraitRing_iLvlBorder"); frame.PortraitFrame.LevelBorder:SetWidth(70); showItemLevel = true; else frame.PortraitFrame.LevelBorder:SetAtlas("GarrMission_PortraitRing_LevelBorder"); frame.PortraitFrame.LevelBorder:SetWidth(58); showItemLevel = false; end GMF:SetFollowerPortrait(frame.PortraitFrame, info, false) -- Counters icon if (frame.Name and frame.Threats) then if (missionID and not GMFMissions.showInProgress) then local tohide=1 if b and b[followerID] then for i=1,#b[followerID] do local th=frame.Threats[tohide] th.Icon:SetTexture(b[followerID][i].icon) th:Show() tohide=tohide+1 end end if t and t[followerID] then for i=1,#t[followerID] do if tohide>#frame.Threats then break end local th=frame.Threats[tohide] th.Icon:SetTexture(t[followerID][i].icon) th:Show() tohide=tohide+1 end end else frame.Status:Hide() end end end -- pseudo static local scale=0.9 function addon:BuildFollowersButtons(button,bg,limit,bigscreen) if (bg.Party) then return end bg.Party={} for numMembers=1,3 do local f=CreateFrame("Button",nil,bg,bigscreen and "GarrisonCommanderMissionPageFollowerTemplate" or "GarrisonCommanderMissionPageFollowerTemplateSmall" ) if (numMembers==1) then f:SetPoint("BOTTOMLEFT",button.Rewards[1],"BOTTOMRIGHT",10,0) else if (bigscreen) then f:SetPoint("LEFT",bg.Party[numMembers-1],"RIGHT",10,0) else f:SetPoint("LEFT",bg.Party[numMembers-1],"LEFT",65,0) end end tinsert(bg.Party,f) f:EnableMouse(true) f.missionID=button.info.missionID f:RegisterForClicks("AnyUp") f:SetScript("OnClick",function(...) self:OnClick_PartyMember(...) end) 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 end end for i=1,3 do bg.Party[i]:SetScale(0.9) end -- Making room for both GC and MP if (button.Expire) then button.Expire:ClearAllPoints() button.Expire:SetPoint("TOPRIGHT") end if (button.Threats and button.Threats[1]) then button.Threats[1]:ClearAllPoints() button.Threats[1]:SetPoint("TOPLEFT",165,0) end end function addon:BuildExtraButton(button,bigscreen) end function addon:OnShow_FollowerPage(frame) if not GCFMissions then return end if type(GCFMissions.Header.info)=="table" then GCFMissions.Header.missionInfo=GCFMissions.Header.info self:HookedGarrisonFollowerPage_ShowFollower(frame,GCFMissions.Header.info.followerID,true) -- local s =self:GetScroller("GFCMissions.Header") -- self:cutePrint(s,GCFMissions.Header) end end --function addon:GarrisonMissionButtHeaderon_SetRewards(button,rewards,numrewards) --end do local menuFrame = CreateFrame("Frame", "GCFollowerDropDOwn", nil, "UIDropDownMenuTemplate") local func=function(...) addon:IgnoreFollower(...) end local func2=function(...) addon:UnignoreFollower(...) end local menu= { { text=L["Follower"], notClickable=true,notCheckable=true,isTitle=true }, { text=L["Ignore for this mission"],checked=false, func=func, arg1=0, arg2="none"}, -- { text=L["Ignore for all missions"],checked=false, func=func, arg1=0, arg2="none"}, { text=L["Consider again"], notClickable=true,notCheckable=true,isTitle=true }, { text=CLOSE, notClickable=true,notCheckable=true,isTitle=true }, } function addon:OnClick_PartyMember(frame,button,down,...) --if not GMF:IsVisible() then return end local followerID=frame.info and frame.info.followerID or nil local missionID=frame.missionID if (not followerID) then return end if (addon:IsRewardPage()) then return end if (button=="LeftButton") then self:OpenFollowersTab() GMF.selectedFollower=followerID if (GMF.FollowerTab) then GMFFollowers:ShowFollower(followerID) end else menu[1].text=frame.info.name menu[2].arg1=missionID menu[2].arg2=followerID --menu[3].arg2=followerID local i=3 for k,r in pairs(chardb.ignored[missionID]) do if (r) then i=i+1 local v=menu[i] or {} v.text=self:GetFollowerData(k,'name') v.func=func2 v.arg1=missionID v.arg2=k v.notCheckable=nil v.notClickable=nil v.checked=false v.isTitle=nil menu[i]=v else chardb.ignored[missionID][k]=nil end end if (i>3) then i=i+1 menu[i]={text=ALL,func=func2,arg1=missionID,arg2='all'} end i=i+1 if not menu[i] then menu[i]={ text=CLOSE,func=function() end, notCheckable=true } else menu[i].text=CLOSE menu[i].notCheckable=true menu[i].notClickable=nil menu[i].func=function() end end for x=#menu,i+1,-1 do tremove(menu) end EasyMenu(menu,menuFrame,"cursor",0,0,"MENU",5) end end end function addon:IgnoreFollower(table,missionID,followerID,flag) if (missionID==0) then chardb.totallyignored[followerID]=true else chardb.ignored[missionID][followerID]=true end -- full ignore disabled for now chardb.totallyignored[followerID]=nil self:RefreshMissions(missionID) end function addon:UnignoreFollower(table,missionID,followerID,flag) if (followerID=='all') then wipe(chardb.ignored[missionID]) else chardb.ignored[missionID][followerID]=nil end self:RefreshMissions(missionID) end function addon:OpenLastTab() lastTab=lastTab or PanelTemplates_GetSelectedTab(GMF) if lastTab then if GMF.MissionControlTab:IsVisible() then GMF.MissionControlTab:Hide() GMF.tabMC:SetChecked(false) if lastTab==2 then GMF.FollowerTab:Show() GMF.FollowerList:Show() self:RefreshFollowerStatus() else GMF.MissionTab:Show() end end GMF:SelectTab(lastTab) else return self:OpenMissionsTab() end end function addon:OpenFollowersTab() lastTab=2 return self:OpenLastTab() end function addon:OpenMissionsTab() lastTab=1 return self:OpenLastTab() end function addon:OpenProgressTab() lastTab=3 return self:OpenLastTab() end function addon:OpenMissionControlTab() if (not GMF.MissionControlTab:IsVisible()) then lastTab=PanelTemplates_GetSelectedTab(GMF) GMF.FollowerTab:Hide() GMF.FollowerList:Hide() GMF.MissionTab:Hide() GMF.TitleText:SetText(L["Garrison Commander Mission Control"]) GMF.MissionControlTab:Show() GMF.MissionControlTab.startButton:Click() GMF.tabMC:SetChecked(true) else GMF.tabMC:SetChecked(false) self:OpenLastTab() end self:RefreshMenu() end function addon:OnClick_GarrisonMissionFrame_MissionComplete_NextMissionButton(this,button) local frame = GMF.MissionComplete if (not frame:IsVisible()) then self:Trigger("MSORT") self:RefreshFollowerStatus() end end function addon:ScriptGarrisonMissionButton_OnClick(tab,button) --@debug@ print(tab,button) --@end-debug@ lastTab=1 if (GMF.MissionTab.MissionList.showInProgress) then self.hooks[tab].OnClick(tab,button) ns.tabCO.Quantity:SetFormattedText("%d",GetItemCount(missionCompleteOrder)) return end if (type(tab.info)~="table") then return end if (button~="RightButton") then self.hooks[tab].OnClick(tab,button) self:FillMissionPage(tab.info) else blacklist[tab.info.missionID]=not blacklist[tab.info.missionID] if blacklist[tab.info.missionID] then tab.Title:SetTextColor(0,0,0) else tab.Title:SetTextColor(1,1,1) end GameTooltip:Hide() addon:ScriptGarrisonMissionButton_OnEnter(tab,button) end end function addon:OnClick_GCMissionButton(frame,button) if (button=="RightButton") then self:HookedGarrisonMissionButton_SetRewards(frame:GetParent(),{},0) else frame.button:Click() end end --[[ addon.oldSetUp=addon.SetUp function addon:ExperimentalSetUp() end addon.SetUp=addon.ExperimentalSetUp --]] function addon:HookedGarrisonMissionPageFollowerFrame_OnEnter(frame) if not frame.info then return; end GarrisonFollowerTooltip:ClearAllPoints(); GarrisonFollowerTooltip:SetPoint("TOPLEFT", frame, "BOTTOMRIGHT"); GarrisonFollowerTooltip_Show(frame.info.garrFollowerID, frame.info.isCollected, C_Garrison.GetFollowerQuality(frame.info.followerID), C_Garrison.GetFollowerLevel(frame.info.followerID), C_Garrison.GetFollowerXP(frame.info.followerID), C_Garrison.GetFollowerLevelXP(frame.info.followerID), C_Garrison.GetFollowerItemLevelAverage(frame.info.followerID), C_Garrison.GetFollowerAbilityAtIndex(frame.info.followerID, 1), C_Garrison.GetFollowerAbilityAtIndex(frame.info.followerID, 2), C_Garrison.GetFollowerAbilityAtIndex(frame.info.followerID, 3), C_Garrison.GetFollowerAbilityAtIndex(frame.info.followerID, 4), C_Garrison.GetFollowerTraitAtIndex(frame.info.followerID, 1), C_Garrison.GetFollowerTraitAtIndex(frame.info.followerID, 2), C_Garrison.GetFollowerTraitAtIndex(frame.info.followerID, 3), C_Garrison.GetFollowerTraitAtIndex(frame.info.followerID, 4), true, C_Garrison.GetFollowerBiasForMission(frame.missionID, frame.info.followerID) < 0.0 ); end function deleteGarrisonMissionFrame_SetFollowerPortrait(portraitFrame, followerInfo, forMissionPage) local color = ITEM_QUALITY_COLORS[followerInfo.quality]; portraitFrame.PortraitRingQuality:SetVertexColor(color.r, color.g, color.b); portraitFrame.LevelBorder:SetVertexColor(color.r, color.g, color.b); if ( forMissionPage ) then local boosted = false; local followerLevel = followerInfo.level; if ( MISSION_PAGE_FRAME.mentorLevel and MISSION_PAGE_FRAME.mentorLevel > followerLevel ) then followerLevel = MISSION_PAGE_FRAME.mentorLevel; boosted = true; end if ( MISSION_PAGE_FRAME.showItemLevel and followerLevel == GarrisonMissionFrame.followerMaxLevel ) then local followerItemLevel = followerInfo.iLevel; if ( MISSION_PAGE_FRAME.mentorItemLevel and MISSION_PAGE_FRAME.mentorItemLevel > followerItemLevel ) then followerItemLevel = MISSION_PAGE_FRAME.mentorItemLevel; boosted = true; end portraitFrame.Level:SetFormattedText(GARRISON_FOLLOWER_ITEM_LEVEL, followerItemLevel); portraitFrame.LevelBorder:SetAtlas("GarrMission_PortraitRing_iLvlBorder"); portraitFrame.LevelBorder:SetWidth(70); else portraitFrame.Level:SetText(followerLevel); portraitFrame.LevelBorder:SetAtlas("GarrMission_PortraitRing_LevelBorder"); portraitFrame.LevelBorder:SetWidth(58); end local followerBias = C_Garrison.GetFollowerBiasForMission(MISSION_PAGE_FRAME.missionInfo.missionID, followerInfo.followerID); if ( followerBias == -1 ) then portraitFrame.Level:SetTextColor(1, 0.1, 0.1); elseif ( followerBias < 0 ) then portraitFrame.Level:SetTextColor(1, 0.5, 0.25); elseif ( boosted ) then portraitFrame.Level:SetTextColor(0.1, 1, 0.1); else portraitFrame.Level:SetTextColor(1, 1, 1); end portraitFrame.Caution:SetShown(followerBias < 0); else portraitFrame.Level:SetText(followerInfo.level); end if ( followerInfo.displayID ) then GarrisonFollowerPortrait_Set(portraitFrame.Portrait, followerInfo.portraitIconID); end end function addon:GarrisonMissionPageOnClose() GMF:ClearParty() GarrisonMissionFrame.MissionTab.MissionPage:Hide(); GarrisonMissionFrame.followerCounters = nil; GarrisonMissionFrame.MissionTab.MissionPage.missionInfo = nil; if (lastTab) then if lastTab==1 then addon:OpenMissionsTab() else addon:OpenFollowersTab() end end -- I hooked this handler, so I dont want it to be called in the middle of cleanup operations GarrisonMissionFrame.MissionTab.MissionList:Show(); end function addon:AddRewards(frame, rewards, numRewards) numRewards=numRewards or #rewards if (numRewards and numRewards > 0) then local index = 1; local party=frame.party local mission=frame.info local missionID=mission.missionID local moreClasses=self:GetMissionData(missionID,'moreClasses') local bestItemID=self:GetMissionData(missionID,'bestItemID') local pseudoGold local extraItem local rw=new() for _, reward in pairs(rewards) do tinsert(rw,reward) end if bestItemID then numRewards=numRewards+1 extraItem=new() extraItem.itemID=bestItemID extraItem.best=true extraItem.quantity=1 extraItem.auction=self:GetMissionData(missionID,'bestItemIDAuction') tinsert(rw,extraItem) end if moreClasses and moreClasses.gold then numRewards=numRewards+1 pseudoGold=new() pseudoGold.quantity=self:GetMissionData(missionID,'gold') pseudoGold.currencyID=0 pseudoGold.pseudogold=true tinsert(rw,pseudoGold) end for id, reward in ipairs(rw) do if (not frame.Rewards[index]) then frame.Rewards[index] = CreateFrame("Frame", nil, frame, "GarrisonMissionListButtonRewardTemplate"); frame.Rewards[index]:SetPoint("RIGHT", frame.Rewards[index-1], "LEFT", 15, 0); end local Reward = frame.Rewards[index]; if not Reward.ScriptHooked then Reward.ScriptHooked=true self:SafeSecureHookScript(Reward,"OnEnter",function(base) addon:AddRewardExtraTooltip(base,true) end) self:SafeSecureHookScript(Reward,"OnLeave",function(base) addon:AddRewardExtraTooltip(base,false) end) end Reward.Quantity:Hide(); Reward.itemID = nil; Reward.currencyID = nil; Reward.tooltip = nil; Reward.Quantity:SetTextColor(C.White()) if (reward.itemID) then Reward.itemID = reward.itemID GarrisonMissionFrame_SetItemRewardDetails(Reward); if ( reward.quantity > 1 ) then Reward.Quantity:SetText(reward.quantity); Reward.Quantity:Show(); elseif reward.itemID==120205 then Reward.Quantity:SetText(frame.info.xp); 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); else Reward.Quantity:SetText(iLevel==1 and level or iLevel); end Reward.Quantity:SetTextColor(ITEM_QUALITY_COLORS[quality].r,ITEM_QUALITY_COLORS[quality].g,ITEM_QUALITY_COLORS[quality].b) Reward.Quantity:Show(); end end else if reward.pseudogold then Reward.Icon:SetTexture('Interface/ICONS/INV_Misc_Coin_02') Reward.title=L['Estimated gold value of mission'] else Reward.Icon:SetTexture(reward.icon); Reward.title = reward.title end if (reward.currencyID and reward.quantity) then local multi=1 if type(party.materialMultiplier)=="table" then if party.materialMultiplier[reward.currencyID] then multi=party.materialMultiplier[reward.currencyID] end else multi=party.materialMultiplier or 1 end if (reward.currencyID == 0) then local multi=party.goldMultiplier or 1 Reward.tooltip = GetMoneyString(reward.quantity); if reward.pseudogold then multi=1 end Reward.Quantity:SetText(BreakUpLargeNumbers(floor(reward.quantity *multi / COPPER_PER_GOLD))); -- Reward.Quantity:SetText(math.floor(reward.quantity/10000) * multi); Reward.Quantity:Show(); if multi >1 then Reward.Quantity:SetTextColor(C:Green()) elseif reward.pseudogold then Reward.Quantity:SetTextColor(C:Orange()) elseif Reward.auction then Reward.Quantity:SetTextColor(C:Cyan()) else Reward.Quantity:SetTextColor(C:Gold()) end else Reward.Quantity:SetText(reward.quantity * multi); Reward.Quantity:Show(); if multi >1 then Reward.Quantity:SetTextColor(C:Green()) else Reward.Quantity:SetTextColor(C:Gold()) end end else if reward.followerXP then Reward.Quantity:SetText(reward.followerXP); Reward.Quantity:Show(); if party.xpBonus and party.xpBonus > 0 then Reward.Quantity:SetTextColor(C:Green()) else Reward.Quantity:SetTextColor(C:Gold()) end end Reward.tooltip = reward.tooltip; end end Reward:Show(); index = index + 1; end if pseudoGold then del(pseudoGold) end if extraItem then del(extraItem) end del(rw) end for i = (numRewards + 1), #frame.Rewards do frame.Rewards[i]:Hide(); end return numRewards end local savedUpdate function addon:AddRewardExtraTooltip(this,enter) local tip=GameTooltip if (enter and not savedUpdate) then savedUpdate=tip:GetScript("OnUpdate") tip:SetScript("OnUpdate",function() end) end if (not enter and savedUpdate) then tip:SetScript("OnUpdate",savedUpdate) savedUpdate=nil end local itemID=tostring(this.itemID) if itemID and this.best then local _1,l,_3,_4,_5,_6,_7,_8,_9,_10,buy=GetItemInfo(this.itemID) local value,auction=self:GetMarketValue(l) tip:AddDoubleLine(SELL_PRICE,GetMoneyString(buy)) if auction then tip:AddLine(TOKEN_CURRENT_AUCTION_VALUE:format(value)) end elseif itemID then local creates=self:GetContainedItems(itemID) if creates then tip:AddLine(REWARDS,C:Green()) local total=0 for k,v in pairs(creates) do local c,k=strsplit('@',v) c=tonumber(c) or 1 total=total+(tonumber(c) or 1) end for _,v in pairs(creates) do local c,k=strsplit('@',v) c=tonumber(c) or 1 k=tonumber(k) local _1,l,_3,_4,_5,_6,_7,_8,_9,t=GetItemInfo(k) local buy,source=self:GetMarketValue(l or k) if l then tip:AddDoubleLine(format("|T%s:16|t %s %3.2f%%",t,l,c/total*100), --tip:AddDoubleLine(format("link:%s %s",t,l), GetMoneyString(buy) .. ' ' .. source) else tip:AddDoubleLine(format("%s (%s) %3.2f%%",UNKNOWN,k,c/total*100), --tip:AddDoubleLine(format("link:%s %s",t,l), GetMoneyString(buy) .. ' ' .. source) end end tip:AddDoubleLine(L["Drop rate updated"],date("%Y-%m-%d %H:%M:%S",tonumber(ns.wowhead_update))) end else return end if not self.AuctionPrices then tip:AddLine(L["Using vendor prices\nInstall an auction management addon to get auction prices"],C:Red()) end tip:Show() end function addon:HookedGarrisonMissionPageFollowerFrame_OnEnter(frame) if not frame.info then return; end if (addon:IsRewardPage()) then return end GarrisonFollowerTooltip:ClearAllPoints(); GarrisonFollowerTooltip:SetPoint("TOPLEFT", frame, "BOTTOMRIGHT"); GarrisonFollowerTooltip_Show(frame.info.garrFollowerID, frame.info.isCollected, C_Garrison.GetFollowerQuality(frame.info.followerID), C_Garrison.GetFollowerLevel(frame.info.followerID), C_Garrison.GetFollowerXP(frame.info.followerID), C_Garrison.GetFollowerLevelXP(frame.info.followerID), C_Garrison.GetFollowerItemLevelAverage(frame.info.followerID), C_Garrison.GetFollowerAbilityAtIndex(frame.info.followerID, 1), C_Garrison.GetFollowerAbilityAtIndex(frame.info.followerID, 2), C_Garrison.GetFollowerAbilityAtIndex(frame.info.followerID, 3), C_Garrison.GetFollowerAbilityAtIndex(frame.info.followerID, 4), C_Garrison.GetFollowerTraitAtIndex(frame.info.followerID, 1), C_Garrison.GetFollowerTraitAtIndex(frame.info.followerID, 2), C_Garrison.GetFollowerTraitAtIndex(frame.info.followerID, 3), C_Garrison.GetFollowerTraitAtIndex(frame.info.followerID, 4), true, frame.missionID and frame.info.followerID and C_Garrison.GetFollowerBiasForMission(frame.missionID, frame.info.followerID) < 0.0 or false ); end function addon:ScriptGarrisonMissionButton_OnEnter(this, button) if self:GetBoolean("NOTOOLTIP") then return end if (this.info == nil) then return; end if (addon:IsRewardPage()) then return end collectgarbage("step",100) if(this.info.inProgress) then --GarrisonMissionButton_SetInProgressTooltip(this.info); else if not this.info.isRare then GameTooltip:AddLine(GARRISON_MISSION_AVAILABILITY); GameTooltip:AddLine(this.info.offerTimeRemaining, 1, 1, 1); end if (blacklist[this.info.missionID]) then GameTooltip:AddDoubleLine(L["Blacklisted"],L["Right-Click to remove from blacklist"],1,0.125,0.125,C:Green()) GameTooltip:AddLine(L["Blacklisted missions are ignored in Mission Control"]) else GameTooltip:AddDoubleLine(L["Not blacklisted"],L["Right-Click to blacklist"],0.125,1.0,0.125,C:Red()) end addon:AddFollowersToTooltip(this.info.missionID,LE_FOLLOWER_TYPE_GARRISON_6_0) if not C_Garrison.IsOnGarrisonMap() and not GMF:IsVisible() then GameTooltip:AddLine(" "); GameTooltip:AddLine(GARRISON_MISSION_TOOLTIP_RETURN_TO_START, nil, nil, nil, 1); end end --@debug@ GameTooltip:AddLine("----------------------------------------------") GameTooltip:AddDoubleLine("MissionID",this.info.missionID) GameTooltip:AddDoubleLine("Class",this.info.class) GameTooltip:AddDoubleLine(this.info.class,this.info[this.info.class]) GameTooltip:AddDoubleLine("TitleLen",this.Title:GetStringWidth()) GameTooltip:AddDoubleLine("SummaryLen",this.Summary:GetStringWidth()) GameTooltip:AddDoubleLine("Reward",this.Rewards[1]:GetWidth()) GameTooltip:AddDoubleLine("Button",this:GetWidth()) GameTooltip:AddDoubleLine("Button Scale",this:GetScale()) --@end-debug@ GameTooltip:Show(); end ---@function -- Main mission button draw routine. -- @param source GarrisonMissionFrameMissions or nil. -- @param button scrolllist element -- @param progressing true if at second iteration of progress page -- @param bigscreen enlarge button or not function addon:DrawSingleButton(source,frame,progressing,bigscreen) if type(source)=="table" then source="blizzard" end frame:SetAlpha(1.0) local mission=frame.info if mission then local missionID=mission.missionID self:AddStandardDataToButton(source,frame,mission,missionID,bigscreen) self:AddIndicatorToButton(frame,mission,missionID,bigscreen) local numRewards=self:AddRewards(frame, mission.rewards, mission.numRewards); self:AddFollowersToButton(frame,mission,missionID,bigscreen,numRewards) if source=="blizzard" and not self:IsRewardPage() and not progressing then self:AddThreatsToButton(frame,mission,missionID,bigscreen) end if progressing then if frame.Env then frame.Env:Hide() end if frame.GcThreats then for i=1,#frame.GcThreats do frame.GcThreats[i]:Hide() end end end if (blacklist[missionID]) then frame.Title:SetTextColor(0,0,0) else frame.Title:SetTextColor(1,1,1) end frame:Show(); else frame:Hide(); frame.info=nil end end function addon:DrawSlimButton(source,frame,progressing,bigscreen) source=source or "Followers" local mission=frame.info if mission then local missionID=mission.missionID self:AddStandardDataToButton(false,frame,mission,missionID,bigscreen) local numRewards=self:AddRewards(frame, mission.rewards, mission.numRewards); if mission.followerTypeID==LE_FOLLOWER_TYPE_GARRISON_6_0 then self:AddFollowersToButton(frame,mission,missionID,bigscreen,numRewards) elseif mission.followerTypeID==LE_FOLLOWER_TYPE_SHIPYARD_6_2 then self:AddShipsToButton(frame,mission,missionID,bigscreen,numRewards) 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) frame.Summary:ClearAllPoints() frame.Summary:SetPoint("TOPLEFT",frame.Title,"BOTTOMLEFT",0,-10) frame:Show(); else frame:Hide(); frame.info=nil end end function addon:AddStandardDataToButton(source,button,mission,missionID,bigscreen) if (bigscreen) then button.Rewards[1]:SetPoint("RIGHT",button,"RIGHT",-500 - (GMM and 40 or 0),0) local width=GMF.MissionTab.MissionList.showInProgress and BIGBUTTON or SMALLBUTTON button:SetWidth(width+600) button.Rewards[1]:SetPoint("RIGHT",button,"RIGHT",-500 - (GMM and 40 or 0),0) end button.MissionType:SetAtlas(mission.typeAtlas); if source=="blizzard" then return end if (mission.isRare) then button.RareOverlay:Show(); button.RareText:Show(); button.IconBG:SetVertexColor(0, 0.012, 0.291, 0.4) else button.RareOverlay:Hide(); button.RareText:Hide(); button.IconBG:SetVertexColor(0, 0, 0, 0.4) end if (mission.inProgress) then button.Overlay:Show(); button.Summary:SetText(mission.timeLeft.." "..RED_FONT_COLOR_CODE..GARRISON_MISSION_IN_PROGRESS..FONT_COLOR_CODE_CLOSE); else button.Overlay:Hide(); end button.Title:SetWidth(0); button.Title:SetText(mission.name) local seconds=self:GetMissionData(missionID,'improvedDurationSeconds') local duration=SecondsToTime(seconds) if ( seconds >= GARRISON_LONG_MISSION_TIME ) then button.Summary:SetFormattedText(PARENS_TEMPLATE, format(GARRISON_LONG_MISSION_TIME_FORMAT,duration)) elseif (seconds allowed) then button.Title:SetPoint("TOPLEFT",button,"TOPLEFT",150,ns.bigscreen and -15 or -5) button.Summary:ClearAllPoints() button.Summary:SetPoint("TOPLEFT",button.Title,"BOTTOMLEFT",0,-15) return end elseif source=="followers" then button.Title:SetPoint("TOPLEFT",button,"TOPLEFT",155,-5) button.Summary:Hide() return elseif source=="report" then if GMF:IsVisible() then local extra=80*(button.info.numRewards-1) + 70 * (button.info.numFollowers-1) local allowed=350- extra local needed=button.Title:GetStringWidth()+5+button.Summary:GetStringWidth() if (needed > allowed) then button.Title:SetPoint("TOPLEFT",button,"TOPLEFT",160,-10) button.Summary:ClearAllPoints() button.Summary:SetPoint("TOPLEFT",button.Title,"BOTTOMLEFT",0,-5) return end end end button.Title:SetPoint("TOPLEFT",button,"TOPLEFT",160,-30) end function addon:AddLevel(source,button,mission,missionID,bigscreen) button.Level:SetPoint("CENTER", button, "TOPLEFT", 40, -36); local level= (mission.level == GARRISON_FOLLOWER_MAX_LEVEL and mission.iLevel > 0) and mission.iLevel or mission.level local quality=1 if level >=645 then quality=4 elseif level >=630 then quality=3 elseif level>100 then quality=2 end button.Level:SetText(level) button.Level:SetTextColor(self:GetQualityColor(quality)) button.ItemLevel:Hide(); end function addon:AddThreatsToButton(button,mission,missionID,bigscreen) local threatIndex=1 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 button.Env.missionID=missionID local party=button.party if not mission.typeIcon then mission.typeIcon=select(5,G.GetMissionInfo(missionID)) end if mission.typeIcon then button.Env.IsEnv=true button.Env:Show() button.Env.Icon:SetTexture(mission.typeIcon) button.Env.texture=mission.typeIcon button.Env.countered=type(party.isEnvMechanicCountered)=="table" and party.isEnvMechanicCountered.environmentMechanicCountered or false if (button.Env.countered) then button.Env.Border:SetVertexColor(C.Green()) else button.Env.Border:SetVertexColor(C.Red()) end button.Env.Description=mission.typeDesc button.Env.Name=mission.type button.Env:SetScript("OnEnter",addon.ClonedGarrisonMissionMechanic_OnEnter) button.Env:SetScript("OnLeave",function() GameTooltip:Hide() end) else button.Env:SetScript("OnEnter",nil) button.Env:Hide() end local enemies=mission.enemies or select(8,G.GetMissionInfo(missionID)) local threats=self:GetParty(missionID,'threats') for i,enemy in ipairs(enemies) do for mechanicID, mechanic in pairs(enemy.mechanics) do local th=button.GcThreats[threatIndex] if (not th) then th=CreateFrame("Frame",nil,button,"GarrisonAbilityCounterTemplate") th:SetWidth(20) th:SetHeight(20) th:SetPoint("BOTTOMLEFT",button,165 + 35 * threatIndex,8) button.GcThreats[threatIndex]=th end th.countered=self:SetThreatColor(th,threats[threatIndex]) th.Icon:SetTexture(mechanic.icon) th.texture=mechanic.icon th.Name=mechanic.name th.Description=mechanic.description th.missionID=missionID --GarrisonMissionButton_CheckTooltipThreat(th,missionID,mechanicID,counteredThreats) th:Show() th:SetScript("OnEnter",addon.ClonedGarrisonMissionMechanic_OnEnter) th:SetScript("OnLeave",function() GameTooltip:Hide() end) threatIndex=threatIndex+1 end end end if (button.GcThreats) then for i=threatIndex,#button.GcThreats do button.GcThreats[i]:Hide() end end end function addon:GetAgeColor(age) age=tonumber(age) or 0 if age>GetTime() then age=age-GetTime() end if age < 0 then age=0 end local hours=floor(age/3600) local q=self:GetDifficultyColor(hours+20,true) return q.r,q.g,q.b end function addon:AddIndicatorToButton(button,mission,missionID,bigscreen) if not button.gcINDICATOR then local indicators=CreateFrame("Frame",nil,button,"GarrisonCommanderIndicators") indicators:SetPoint("LEFT",70,0) button.gcINDICATOR=indicators end local panel=button.gcINDICATOR local perc=select(4,G.GetPartyMissionInfo(missionID)) or 0 if button.party and type(button.party.perc)=="number" and button.party.perc > perc then perc=button.party.perc end if button.party.full then panel.Percent:SetFormattedText(GARRISON_MISSION_PERCENT_CHANCE,perc) panel.Percent:SetTextColor(self:GetDifficultyColors(perc)) else panel.Percent:SetText("N/A") panel.Percent:SetTextColor(C:Silver()) end panel.Percent:SetWidth(80) panel.Percent:Show() if (GMFMissions.showInProgress) then panel.Percent:SetJustifyV("CENTER") panel.Percent:SetJustifyH("RIGHT") panel.Age:Hide() else panel.Percent:SetJustifyV("BOTTOM") panel.Percent:SetJustifyH("RIGHT") panel.Age:SetFormattedText("Expires in \n%s",mission.offerTimeRemaining) panel.Age:SetTextColor(self:GetAgeColor(mission.offerEndTime)) panel.Age:Show() end -- XP display if (not GMFMissions.showInProgress) then if (not button.xp) then button.xp=button:CreateFontString(nil, "ARTWORK", "QuestMaprewardsFont") button.xp:SetPoint("TOP",button.Rewards[1],"TOP") button.xp:SetJustifyH("CENTER") end button.xp:SetWidth(0) local xp=(self:GetMissionData(missionID,'xp',0)+self:GetMissionData(missionID,'xpBonus',0)+self:GetParty(missionID,'xpBonus',0) )*button.info.numFollowers button.xp:SetFormattedText("Xp: %d",xp) button.xp:SetTextColor(self:GetDifficultyColors(xp/3000*100)) button.xp:Show() else if button.xp then button.xp:Hide() end end end function addon:AddShipsToButton(button,mission,missionID,bigscreen) if (not button.gcPANEL) then local bg=CreateFrame("Button",nil,button,"GarrisonCommanderMissionButton") bg:SetPoint("RIGHT") bg.button=button bg:RegisterForClicks("AnyUp") bg:SetScript("OnClick",function(...) self:OnClick_GCMissionButton(...) end) button.gcPANEL=bg if (not bg.Party) then self:BuildFollowersButtons(button,bg,3,bigscreen) end end for i=1,3 do local frame=button.gcPANEL.Party[i] frame:Hide() end end function addon:AddFollowersToButton(button,mission,missionID,bigscreen,numRewards) if (not button.gcPANEL) then local bg=CreateFrame("Button",nil,button,"GarrisonCommanderMissionButton") bg:SetPoint("RIGHT") bg.button=button bg:RegisterForClicks("AnyUp") bg:SetScript("OnClick",function(...) self:OnClick_GCMissionButton(...) end) button.gcPANEL=bg if (not bg.Party) then self:BuildFollowersButtons(button,bg,3,bigscreen) end end local missionInfo=button.info local missionID=missionInfo.missionID local mission=missionInfo if not mission then --@debug@ print("Non ho la missione") return -- something went wrong while refreshing --@end-debug@ end if (not bigscreen) then local index=mission.numFollowers+numRewards-3 local position=(index * -65) - 130 button.gcPANEL.Party[1]:ClearAllPoints() button.gcPANEL.Party[1]:SetPoint("BOTTOMLEFT",button.Rewards[1],"BOTTOMLEFT", position,0) end local party=button.party local t,b if not GMFMissions.showInProgress then --GarrisonFollowerOptions[LE_FOLLOWER_TYPE_GARRISON_6_0].displayCounterAbilityInPlaceOfMechanic) b=G.GetBuffedFollowersForMission(missionID,false) t=G.GetFollowersTraitsForMission(missionID) end for i=1,3 do local frame=button.gcPANEL.Party[i] if (i>mission.numFollowers) then frame:Hide() else if (mission.inProgress and mission.followers[i]) then self:RenderFollowerButton(frame,mission.followers[i],missionID,b,t) if (frame.NotFull) then frame.NotFull:Hide() end elseif (party.members[i]) then self:RenderFollowerButton(frame,party.members[i],missionID,b,t) if (frame.NotFull) then frame.NotFull:Hide() end else self:RenderFollowerButton(frame,false) if (frame.NotFull) then frame.NotFull:Show() end end frame:Show() end end end -- Switchs between active and availabla missions depending on tab object function addon:HookedGarrisonMissionList_SetTab(tab) --@debug@ print("Click su",tab:GetID()) --@end-debug@ -- I dont actually care wich page we are showing, I know I must redraw missions addon:RefreshFollowerStatus() for i=1,#GMFMissionListButtons do GMFMissionListButtons.lastMissionID=nil end addon:RefreshMenu() if (HD) then addon:ResetSinks() end end function addon:HookedClickOnTabs(tab) --@debug@ print(tab,tab:GetID()) --@end-debug@ lastTab=tab self:RefreshMenu() end function addon:GarrisonMissionFrame_SelectTab(frame,tab) --@debug@ print(frame,tab) --@end-debug@ addon:RefreshFollowerStatus() for i=1,#GMFMissionListButtons do GMFMissionListButtons.lastMissionID=nil end lastTab=tab if (HD) then addon:ResetSinks() end if GMF.tabMC then GMF.tabMC:SetChecked(false) GMF.MissionControlTab:Hide() end self:RefreshMenu() end function addon:HookedGarrisonMissionButton_SetRewards(frame,rewards,numRewards) collectgarbage("step",300) local mission=frame.info local module=self:GetMissionModule(mission.followerTypeID) if not module then return end local main=module:GetMain() if not main or not main:IsVisible() then return end local Missions=module:GetMissions() local bigscreen=module:GetBigScreen() if frame.info then if Missions.showInProgress then frame.Title:SetPoint("TOPLEFT",frame,"TOPLEFT",160,-25) else local extra=80*(numRewards-1) if not bigscreen then extra = extra + 70 * (frame.info.numFollowers-1) end local allowed=bigscreen and 350- extra or 480 - extra local needed=frame.Title:GetStringWidth()+5+frame.Summary:GetStringWidth() if (needed > allowed) then frame.Title:SetPoint("TOPLEFT",frame,"TOPLEFT",160,-5) frame.Summary:ClearAllPoints() frame.Summary:SetPoint("TOPLEFT",frame.Title,"BOTTOMLEFT",0,-5) else frame.Title:SetPoint("TOPLEFT",frame,"TOPLEFT",160,-15) end end frame.MissionType:SetPoint("TOPLEFT",5,-2) frame.MissionType:SetAlpha(0.5) module:AddLevel(GMF,frame,frame.info,frame.info.missionID,bigscreen) if Missions.showInProgress and frame.lastID and frame.lastID == frame.info.missionID and frame.lastProgress then return end frame.lastID = frame.info.missionID frame.lastProgress = frame.info.inProgress frame.party=self:GetParty(frame.info.missionID) if not Missions.showInProgress then self:MatchMaker(frame.info.missionID,frame.party) end --@debug@ if not main:IsVisible() then pp(debugstack()) end --@end-debug@ self:DrawSingleButton(GMF,frame,GMFMissions.showInProgress,bigscreen) end end function addon:HookedGMFMissionsListScroll_update(frame) if frame:GetParent().showInProgress then self:HookedGarrisonMissionList_Update(frame,true) else self:HookedGarrisonMissionList_Update(frame,false) end end function addon:GarrisonMissionPageFollowerFrame_OnEnter(this) local f=this:GetParent() if f then --@debug@ print(f:GetName(),f.missionInfo) --@end-debug@ if not f.missionInfo then f.missionInfo={missionID=0} end end local rc,message=pcall(GarrisonMissionPageFollowerFrame_OnEnter,this) --@debug@ if not rc then print("Error:",message) end --@end-debug@ end function addon:HallSort() self:AddSelect("MHSORT","Garrison_SortMissions_Original", { Garrison_SortMissions_Original=L["Original method"], Garrison_SortMissions_Chance=L["Success Chance"], Garrison_SortMissions_Followers=L["Number of followers"], Garrison_SortMissions_Age=L["Expiration Time"], Garrison_SortMissions_Xp=L["Global approx. xp reward"], Garrison_SortMissions_Duration=L["Duration Time"], Garrison_SortMissions_Class=L["Reward type"], }, 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)"]) end do local lasttime=0 function addon:HookedGarrisonMissionList_Update(t,...) collectgarbage('step',200) local this=self if not this.showInProgress then addon.hooks.GarrisonMissionList_Update(this,t,...) lasttime=0 else local missions=this.inProgressMissions local now=time() local delay=120 if t then lasttime=0 else if (missions[1]) then delay=missions[1].missionEndTime-now else delay=0 end end if (now-lasttime) > ((delay>65) and 30 or 0) then --@debug@ print("Aggiornamento",now,lasttime,delay,now-lasttime) --@end-debug@ addon.hooks.GarrisonMissionList_Update(this,t,...) lasttime=now end end end end function addon:OnUpdateMissions() local UpdateShow=true --@debug@ local start=debugprofilestop() addon:Print(C("OnUpdateMissions","GREEN"),GMFMissions:IsVisible(),GMFRewardSplash:IsVisible()) --@end-debug@ self:SecureHook("Garrison_SortMissions","SortMissions") self.hooks[GMFMissions].UpdateMissions(GMFMissions) self:Unhook("Garrison_SortMissions") --@debug@ addon:Print(C("OnPostUpdateMissions","RED"),debugprofilestop()-start) --@end-debug@ collectgarbage("collect") end --addon:SafeRawHook(GMF.MissionTab.MissionList.listScroll,"update","HookedGMFMissionsListScroll_update") addon.hooks=addon.hooks or {} addon.hooks.GarrisonMissionList_Update=GMF.MissionTab.MissionList.Update GMF.MissionTab.MissionList.Update=addon.HookedGarrisonMissionList_Update addon.hooks.GarrisonMissionList_SetTab=GMF.MissionTab.MissionList.SetTab GMF.MissionTab.MissionList.SetTab=addon.HookedGarrisonMissionList_SetTab addon:SafeSecureHook("GarrisonMissionButton_SetRewards") --addon:SafeSecureHook("GarrisonMissionButton_OnEnter","ScriptGarrisonMissionButton_OnEnter") --addon:SecureHook("GarrisonMissionButton_OnEnter","ScriptGarrisonMissionButton_OnEnter") addon:SafeSecureHook(GMF,"SelectTab","GarrisonMissionFrame_SelectTab") addon:SafeRawHookScript(GMF.MissionTab.MissionPage.CloseButton,"OnClick","GarrisonMissionPageOnClose") _G.GarrisonCommander=addon _G.GAC=addon