Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Confused about mix of CamelCase and_underscores?
- -- Camel case comes from copypasta of how Blizzard calls returns/fields in their code and deriveates
- -- Underscore are my own variables
- local dump = DevTools_Dump
- local tinsert = table.insert
- local wipe = wipe
- local pairs = pairs
- local GARRISON_CURRENCY = GARRISON_CURRENCY
- local GarrisonMissionFrame = GarrisonMissionFrame
- local GarrisonLandingPage = GarrisonLandingPage
- local GarrisonRecruitSelectFrame = GarrisonRecruitSelectFrame
- local MissionPage = GarrisonMissionFrame.MissionTab.MissionPage
- local AddFollowerToMission = C_Garrison.AddFollowerToMission
- local GetPartyMissionInfo = C_Garrison.GetPartyMissionInfo
- local RemoveFollowerFromMission = C_Garrison.RemoveFollowerFromMission
- local NUM_OPTIONS = 3
- local buttons = {}
- function GMM_dumpl(pattern, ...)
- local names = { strsplit(",", pattern) }
- for idx = 1, select('#', ...) do
- local name = names[idx]
- if name then name = name:gsub("^%s+", ""):gsub("%s+$", "") end
- print(GREEN_FONT_COLOR_CODE, idx, name, FONT_COLOR_CODE_CLOSE)
- dump(select(idx, ...))
- end
- end
- local xp_to_level = {[90]=400, [91]=800, [92]=1200, [93]=1600, [94]=2000,
- [95]=3000, [96]=3500, [97]=4000,
- [98]=5400, [99]=6000}
- local xp_to_upgrade = {[2]=60000, [3]=120000}
- local function follower_progress(mission_level, follower, xp)
- local progress = 0
- if follower.level >= 100 and follower.quality >= 4 then return 0 end -- epic followers at max level cannot gain xp
- -- express follower xp as a percentage of next level/upgrade
- if follower.level < 100 then
- progress = xp / xp_to_level[follower.level] * 100
- else
- progress = xp / xp_to_upgrade[follower.quality] * 100
- end
- -- scale follower xp by level delta
- local level_delta = mission_level - follower.level
- if level_delta <= 0 then return progress end -- normal xp gain
- if level_delta <= 2 then return progress / 2 end -- slightly underlevel followers gain half xp
- return progress / 10 -- very underlevel followers gain 10% xp
- end
- local _, _, garrison_currency_texture = GetCurrencyInfo(GARRISON_CURRENCY)
- garrison_currency_texture = "|T" .. garrison_currency_texture .. ":0|t"
- local time_texture = "|TInterface\\Icons\\spell_holy_borrowedtime:0|t"
- local function FindBestFollowersForMission(mission, followers)
- local min, max = {}, {}
- local top = {}
- for i = 1, NUM_OPTIONS do tinsert(top, {}) end
- local followers_count = #followers
- local slots = mission.numFollowers
- if slots > followers_count then return top end
- GarrisonMissionFrame:UnregisterEvent("GARRISON_FOLLOWER_LIST_UPDATE")
- GarrisonLandingPage:UnregisterEvent("GARRISON_FOLLOWER_LIST_UPDATE")
- GarrisonRecruitSelectFrame:UnregisterEvent("GARRISON_FOLLOWER_LIST_UPDATE")
- if FollowerLocationInfoFrame then FollowerLocationInfoFrame:UnregisterEvent("GARRISON_FOLLOWER_LIST_UPDATE") end
- local mission_id = mission.missionID
- if C_Garrison.GetNumFollowersOnMission(mission_id) > 0 then
- for idx = 1, #followers do
- RemoveFollowerFromMission(mission_id, followers[idx].followerID)
- end
- end
- for idx = 1, slots do
- max[idx] = followers_count - slots + idx
- min[idx] = nil
- end
- for idx = slots+1, 3 do
- max[idx] = followers_count + 1
- min[idx] = followers_count + 1
- end
- local mission_level = C_Garrison.GetBasicMissionInfo(mission_id).level
- local _, baseXP = C_Garrison.GetMissionInfo(mission_id)
- local successXP = 0
- local successResources = 0
- local successItem = nil
- for _, reward in pairs(mission.rewards) do
- if reward.currencyID == GARRISON_CURRENCY then successResources = successResources + reward.quantity end
- if reward.followerXP then successXP = successXP + reward.followerXP end
- if reward.itemID and reward.itemID ~= 120205 then successItem = reward.itemID end -- itemID 120205 is player XP reward
- end
- for i1 = 1, max[1] do
- local follower1 = followers[i1]
- local follower1_id = follower1.followerID
- for i2 = min[2] or (i1 + 1), max[2] do
- local follower2 = followers[i2]
- local follower2_id = follower2 and follower2.followerID
- for i3 = min[3] or (i2 + 1), max[3] do
- local follower3 = followers[i3]
- local follower3_id = follower3 and follower3.followerID
- -- Assign followers to mission
- if not AddFollowerToMission(mission_id, follower1_id) then --[[ error handling! ]] end
- if follower2 and not AddFollowerToMission(mission_id, follower2_id) then --[[ error handling! ]] end
- if follower3 and not AddFollowerToMission(mission_id, follower3_id) then --[[ error handling! ]] end
- -- Calculate result
- local totalTimeString, totalTimeSeconds, isMissionTimeImproved, successChance, partyBuffs, isEnvMechanicCountered, xpBonus, materialMultiplier = GetPartyMissionInfo(mission_id)
- local baseProgress = 0
- if follower1 then baseProgress = baseProgress + follower_progress(mission_level, follower1, baseXP + xpBonus) end
- if follower2 then baseProgress = baseProgress + follower_progress(mission_level, follower2, baseXP + xpBonus) end
- if follower3 then baseProgress = baseProgress + follower_progress(mission_level, follower3, baseXP + xpBonus) end
- local successProgress = 0
- -- TODO: how does bonusXP apply to success rewards?
- if follower1 then successProgress = successProgress + follower_progress(mission_level, follower1, successXP) end
- if follower2 then successProgress = successProgress + follower_progress(mission_level, follower2, successXP) end
- if follower3 then successProgress = successProgress + follower_progress(mission_level, follower3, successXP) end
- local expectedResources = successResources * materialMultiplier * successChance / 100
- local expectedProgress = baseProgress + (successProgress * successChance / 100)
- for idx = 1, NUM_OPTIONS do
- local best = top[idx]
- local found
- repeat -- Checking if new candidate for top is better than any top already stored
- if not best[1] then found = true break end
- -- prioritize expected garrison resources above all else
- if best.expectedResources < expectedResources then found = true break end
- if best.expectedResources > expectedResources then break end
- if not successItem then
- -- prioritize expected xp gain
- if best.expectedProgress < expectedProgress then found = true break end
- if best.expectedProgress > expectedProgress then break end
- end
- -- prioritize winning an item
- if best.successChance < successChance then found = true break end
- if best.successChance > successChance then break end
- -- prioritize mission speed
- if best.totalTimeSeconds > totalTimeSeconds then found = true break end
- if best.totalTimeSeconds < totalTimeSeconds then break end
- break
- until true
- if found then
- local new = {}
- new[1] = follower1
- new[2] = follower2
- new[3] = follower3
- new.successChance = successChance
- new.expectedResources = expectedResources
- new.expectedProgress = expectedProgress
- new.totalTimeSeconds = totalTimeSeconds
- new.isMissionTimeImproved = isMissionTimeImproved
- tinsert(top, idx, new)
- tremove(top, NUM_OPTIONS + 1)
- break
- end
- end
- -- Unasssign
- RemoveFollowerFromMission(mission_id, follower1_id)
- if follower2 then RemoveFollowerFromMission(mission_id, follower2_id) end
- if follower3 then RemoveFollowerFromMission(mission_id, follower3_id) end
- end
- end
- end
- -- dump(top[1])
- GarrisonMissionFrame:RegisterEvent("GARRISON_FOLLOWER_LIST_UPDATE")
- GarrisonLandingPage:RegisterEvent("GARRISON_FOLLOWER_LIST_UPDATE")
- GarrisonRecruitSelectFrame:RegisterEvent("GARRISON_FOLLOWER_LIST_UPDATE")
- if FollowerLocationInfoFrame then FollowerLocationInfoFrame:RegisterEvent("GARRISON_FOLLOWER_LIST_UPDATE") end
- -- dump(top)
- -- local location, xp, environment, environmentDesc, environmentTexture, locPrefix, isExhausting, enemies = C_Garrison.GetMissionInfo(missionID);
- -- /run GMM_dumpl("location, xp, environment, environmentDesc, environmentTexture, locPrefix, isExhausting, enemies", C_Garrison.GetMissionInfo(GarrisonMissionFrame.MissionTab.MissionPage.missionInfo.missionID))
- -- /run GMM_dumpl("totalTimeString, totalTimeSeconds, isMissionTimeImproved, successChance, partyBuffs, isEnvMechanicCountered, xpBonus, materialMultiplier", GetPartyMissionInfo(GarrisonMissionFrame.MissionTab.MissionPage.missionInfo.missionID))
- return top
- end
- -- TODO: don't update list if it is not dirty
- local filtered_followers = {}
- local filtered_followers_count
- local function GetFilteredFollowers()
- local followers = C_Garrison.GetFollowers()
- wipe(filtered_followers)
- filtered_followers_count = 0
- for idx = 1, #followers do
- local follower = followers[idx]
- repeat
- if not follower.isCollected then break end
- local status = follower.status
- if status then break end
- filtered_followers_count = filtered_followers_count + 1
- filtered_followers[filtered_followers_count] = follower
- until true
- end
- -- dump(filtered_followers)
- return filtered_followers, filtered_followers_count
- end
- local available_missions = {}
- local function BestForCurrentSelectedMission()
- local missionInfo = MissionPage.missionInfo
- local mission_id = missionInfo.missionID
- -- print("Mission ID:", mission_id)
- local filtered_followers, filtered_followers_count = GetFilteredFollowers()
- C_Garrison.GetAvailableMissions(available_missions)
- local mission
- for idx = 1, #available_missions do
- if available_missions[idx].missionID == mission_id then
- mission = available_missions[idx]
- break
- end
- end
- -- dump(mission)
- local top = FindBestFollowersForMission(mission, filtered_followers)
- if not buttons['MissionPage1'] then ButtonsInit() end
- for idx = 1, 3 do
- local button = buttons['MissionPage' .. idx]
- local top_entry = top[idx]
- button[1] = top_entry[1] and top_entry[1].followerID or nil
- button[2] = top_entry[2] and top_entry[2].followerID or nil
- button[3] = top_entry[3] and top_entry[3].followerID or nil
- if top_entry.successChance then
- button:SetFormattedText(
- "%d%%\n%s%s%s",
- top_entry.successChance,
- top_entry.expectedResources > 0 and string.format("%.1f", top_entry.expectedResources) .. garrison_currency_texture or "",
- top_entry.expectedProgress > 0 and string.format("%.2f", top_entry.expectedProgress) .. " |TInterface\\Icons\\XPBonus_Icon:0|t" or "",
- top_entry.isMissionTimeImproved and time_texture or ""
- )
- else
- button:SetText("")
- end
- end
- end
- local function PartyButtonOnClick(self)
- if self[1] then
- local MissionPageFollowers = GarrisonMissionFrame.MissionTab.MissionPage.Followers
- for idx = 1, #MissionPageFollowers do
- GarrisonMissionPage_ClearFollower(MissionPageFollowers[idx])
- end
- for idx = 1, #MissionPageFollowers do
- local followerFrame = MissionPageFollowers[idx]
- local follower = self[idx]
- if follower then
- local followerInfo = C_Garrison.GetFollowerInfo(follower)
- GarrisonMissionPage_SetFollower(followerFrame, followerInfo)
- end
- end
- end
- GarrisonMissionPage_UpdateMissionForParty()
- end
- -- Add more data to mission list over Blizzard's own
- -- GarrisonMissionList_Update
- local function GarrisonMissionList_Update_More()
- local self = GarrisonMissionFrame.MissionTab.MissionList
- if (self.showInProgress) then return end
- local missions = self.availableMissions
- local numMissions = #missions
- if (numMissions == 0) then return end
- local missions = self.availableMissions
- local scrollFrame = self.listScroll
- local offset = HybridScrollFrame_GetOffset(scrollFrame)
- local buttons = scrollFrame.buttons
- local numButtons = #buttons
- local filtered_followers, filtered_followers_count = GetFilteredFollowers()
- for i = 1, numButtons do
- local button = buttons[i]
- local alpha = 1
- local index = offset + i
- if index <= numMissions then
- local mission = missions[index]
- -- dump(mission)
- if mission.numFollowers > filtered_followers_count then
- alpha = 0.3
- else
- -- buttons will be added here
- end
- end
- button:SetAlpha(alpha)
- end
- end
- -- hooksecurefunc("GarrisonMissionList_Update", GarrisonMissionList_Update_More)
- local function ButtonsInit()
- local prev
- for idx = 1, NUM_OPTIONS do
- if not buttons['MissionPage' .. idx] then
- local set_followers_button = CreateFrame("Button", nil, GarrisonMissionFrame.MissionTab.MissionPage, "UIPanelButtonTemplate")
- set_followers_button:SetText(idx)
- set_followers_button:SetWidth(100)
- set_followers_button:SetHeight(50)
- if not prev then
- set_followers_button:SetPoint("TOPLEFT", GarrisonMissionFrame.MissionTab.MissionPage, "TOPRIGHT", 0, 0)
- else
- set_followers_button:SetPoint("TOPLEFT", prev, "BOTTOMLEFT", 0, 0)
- end
- set_followers_button:SetScript("OnClick", PartyButtonOnClick)
- set_followers_button:Show()
- prev = set_followers_button
- buttons['MissionPage' .. idx] = set_followers_button
- end
- end
- end
- ButtonsInit()
- hooksecurefunc("GarrisonMissionPage_ShowMission", BestForCurrentSelectedMission)
- -- local count = 0
- -- hooksecurefunc("GarrisonFollowerList_UpdateFollowers", function(self) count = count + 1 print("GarrisonFollowerList_UpdateFollowers", count, self:GetName(), self:GetParent():GetName()) end)
- -- Globals deliberately exposed for people outside
- function GMM_Click(button_name)
- local button = buttons[button_name]
- if button then button:Click() end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement