Refactor player state management and enhance unit handling

- Renamed `UpdatePlayerBlocks` to `RefreshPlayerState` for clarity.
- Consolidated player state updates into more descriptive functions.
- Introduced new files for handling boss, group, player, and target unit states.
- Implemented functions for refreshing boss unit states and group member health.
- Enhanced player state management with dedicated functions for various player attributes.
- Added comprehensive handling for target and focus units, including health and reaction states.
- Improved readability and maintainability of the codebase by organizing related functionalities.
This commit is contained in:
waynebian01
2026-08-29 13:23:36 +08:00
parent f7a7309085
commit e6ed9d2b8d
12 changed files with 478 additions and 353 deletions

View File

@@ -1,7 +1,7 @@
## Interface: 120100
## Title: Fuyutsui
## Version: 1.2.1.13
## Version: 1.2.1.14
## Author: Wayne Bian
## IconTexture: Interface\AddOns\Fuyutsui\core\Spell_Misc_EmotionHappy.blp
## OptionalDeps: LibRangeCheck-3.0
@@ -51,9 +51,10 @@ class/Druid.lua
class/DemonHunter.lua
class/Evoker.lua
core/player.lua
unit/player.lua
core/spells.lua
core/target.lua
core/group.lua
unit/target.lua
unit/group.lua
unit/boss.lua
core/events.lua
main.lua

View File

@@ -26,7 +26,6 @@ Fuyutsui.ClassBlocks = {
"施法技能",
"施法目标",
"敌人数量",
},
["能量"] = {
"法力值",
@@ -47,7 +46,6 @@ Fuyutsui.ClassBlocks = {
"施法(正计时)",
"施法可打断",
"驱散类型",
},
["鼠标"] = {
"类型",
@@ -145,9 +143,6 @@ Fuyutsui.ClassBlocks = {
"难度",
"施法技能",
"施法目标",
"救赎之魂1",
"救赎之魂2",
},
["能量"] = {
"法力值",

View File

@@ -80,13 +80,13 @@ function Fuyutsui:OnInitialize()
Fuyutsui:SlashCommand(msg, editbox)
end
self:GetCharacterInfo()
self:InitializeCharacterState()
end
function Fuyutsui:OnEnable()
self:GetCharacterSpecInfo()
self:InitializeSpecializationState()
self:UpdateSpellKnown()
self:UpdatePlayerBlocks()
self:RefreshPlayerState()
self:ReadKeybindings()
self:HookChatFrameEditBox()
@@ -164,14 +164,23 @@ Fuyutsui.state = {
className = className,
classFilename = classFilename,
}
local function CreateUnitState()
return {
casting = false,
channeling = false,
empowering = false,
}
end
Fuyutsui.blocks = {}
Fuyutsui.target = {}
Fuyutsui.focus = {}
Fuyutsui.mouseover = {}
Fuyutsui.pet = {}
Fuyutsui.target = CreateUnitState()
Fuyutsui.focus = CreateUnitState()
Fuyutsui.mouseover = CreateUnitState()
Fuyutsui.pet = CreateUnitState()
Fuyutsui.boss = {}
for index = 1, 5 do
Fuyutsui.boss["boss" .. index] = {}
Fuyutsui.boss["boss" .. index] = CreateUnitState()
end
Fuyutsui.nameplate = {}
Fuyutsui.group = {}

View File

@@ -42,6 +42,14 @@ function Fuyutsui:CreatePowerCurve(powerType)
end
Fuyutsui.powerCurves = powerCurves
-- 队伍生命曲线必须在进入战斗前创建。战斗中只选择既有曲线,
-- 避免首次施放对应治疗法术时临时调用 C_CurveUtil.CreateColorCurve。
Fuyutsui.curve100 = Fuyutsui:CreateColorCurveScaling(100)
Fuyutsui.groupHealthCurves = {
default = Fuyutsui.curve100,
incoming15 = Fuyutsui:CreateColorCurveScaling(115),
incoming40 = Fuyutsui:CreateColorCurveScaling(140),
}
Fuyutsui.curve255 = Fuyutsui:CreateColorCurve(255, 255)
Fuyutsui.castCurve = Fuyutsui:CreateColorCurve(25.5, 255)

View File

@@ -3,7 +3,6 @@ local addon, ns = ...
local isSec = issecretvalue
local state = Fuyutsui.state
local target = Fuyutsui.target
local nameplate = Fuyutsui.nameplate
function Fuyutsui:RefreshZoneState()
@@ -29,64 +28,64 @@ function Fuyutsui:PLAYER_ENTERING_WORLD()
self:UpdateVampiricStrike(206930)
self:UpdateReaverGlaive(204157)
self:UpdateHeroTalent()
self:GetMountsInfo()
self:UpdateChargedComboPoints()
self:CacheCollectedMountSpells()
self:RefreshChargedComboPoints()
C_Timer.After(3, function()
self:UpdateGroup()
self:RebuildGroupRoster()
self:LoadPlayerMacros()
end)
end
function Fuyutsui:PLAYER_TALENT_UPDATE()
self:UpdatePlayerSpecInfo()
self:UpdateGroup()
self:UpdateChargedComboPoints()
self:RebuildSpecializationState()
self:RebuildGroupRoster()
self:RefreshChargedComboPoints()
end
function Fuyutsui:RefreshPlayerDeathValid()
function Fuyutsui:RefreshPlayerDeathAndValidity()
self.state.isDead = UnitIsDeadOrGhost("player")
self:UpdatePlayerValid()
self:RefreshPlayerValidity()
end
function Fuyutsui:PLAYER_DEAD()
self:RefreshPlayerDeathValid()
self:RefreshPlayerDeathAndValidity()
end
function Fuyutsui:PLAYER_ALIVE()
self:RefreshPlayerDeathValid()
self:RefreshPlayerDeathAndValidity()
end
function Fuyutsui:PLAYER_UNGHOST()
self:RefreshPlayerDeathValid()
self:RefreshPlayerDeathAndValidity()
end
function Fuyutsui:PLAYER_MOUNT_DISPLAY_CHANGED()
self:UpdatePlayerMounted()
self:RefreshPlayerMountedState()
end
function Fuyutsui:UNIT_PET(_, unit)
if unit == "player" then
self:UpdatePlayerPet()
self:RefreshPlayerPetState()
end
end
function Fuyutsui:PLAYER_REGEN_DISABLED()
self:UpdateTargetCanAttack()
self:RefreshTargetReactionState()
state.combat = true
state.combatStartTime = GetTime()
end
function Fuyutsui:PLAYER_REGEN_ENABLED()
self:UpdateTargetCanAttack()
self:RefreshTargetReactionState()
state.combat = false
end
function Fuyutsui:PLAYER_STARTED_MOVING()
self:UpdatePlayerMoving(true)
self:SetPlayerMoving(true)
end
function Fuyutsui:PLAYER_STOPPED_MOVING()
self:UpdatePlayerMoving(false)
self:SetPlayerMoving(false)
end
function Fuyutsui:UNIT_SPELLCAST_SENT(_, unitTarget, targetName, castGUID, spellID)
@@ -103,97 +102,105 @@ function Fuyutsui:UNIT_SPELLCAST_SENT(_, unitTarget, targetName, castGUID, spell
end
end
function Fuyutsui:UNIT_SPELLCAST_START(_, unitTarget, castGUID, spellID, castBarID)
if unitTarget == "player" then
state.casting = true
self:ApplyIncomingHealsCurve(spellID)
self:UpdatePlayerCasting(spellID)
self:UpdateMountCasting(spellID, true)
local function SetUnitCastState(self, unit, stateField, isActive)
if not self:SetTrackedUnitCastState(unit, stateField, isActive) then return false end
if isActive then return true end
if unit == "player" then
if stateField == "casting" then
self:RefreshPlayerCastingStateBlocks()
elseif stateField == "channeling" then
self:RefreshPlayerChannelStateBlock()
elseif stateField == "empowering" then
self:RefreshPlayerEmpowerStateBlocks()
end
else
self:ClearUnitCastStateBlocks(unit, stateField)
end
if unitTarget == "target" then
target.casting = true
return true
end
local function ClearPlayerCastTarget(self)
state.castTargetUnit = nil
state.castTargetName = nil
state.castTargetIndex = 0
self:SetPlayerCastingSpell(0)
end
function Fuyutsui:UNIT_SPELLCAST_START(_, unitTarget, castGUID, spellID, castBarID)
SetUnitCastState(self, unitTarget, "casting", true)
if unitTarget == "player" then
self:RecordIncomingHealEstimate(spellID)
self:SetPlayerCastingSpell(spellID)
self:SetMountSpellCasting(spellID, true)
end
end
function Fuyutsui:UNIT_SPELLCAST_STOP(_, unitTarget, castGUID, spellID, castBarID)
SetUnitCastState(self, unitTarget, "casting", false)
if unitTarget == "player" then
self:UpdateAllIncomingHealsCurves()
state.casting = false
state.castTargetUnit = nil
state.castTargetName = nil
state.castTargetIndex = 0
self:UpdatePlayerCasting(0)
self:UpdateMountCasting(spellID, false)
elseif unitTarget == "target" then
target.casting = false
self:ClearIncomingHealEstimates()
ClearPlayerCastTarget(self)
self:SetMountSpellCasting(spellID, false)
end
end
function Fuyutsui:UNIT_SPELLCAST_INTERRUPTED(_, unitTarget, castGUID, spellID, castBarID)
SetUnitCastState(self, unitTarget, "casting", false)
if unitTarget == "player" then
self:UpdateMountCasting(spellID, false)
self:ClearIncomingHealEstimates()
ClearPlayerCastTarget(self)
self:SetMountSpellCasting(spellID, false)
end
end
function Fuyutsui:UNIT_SPELLCAST_CHANNEL_START(_, unitTarget, castGUID, spellID, castBarID)
SetUnitCastState(self, unitTarget, "channeling", true)
if unitTarget == "player" then
state.channeling = true
state.channelingSpellID = spellID
self:UpdatePlayerCasting(spellID)
elseif unitTarget == "target" then
target.channeling = true
self:SetPlayerCastingSpell(spellID)
end
end
function Fuyutsui:UNIT_SPELLCAST_CHANNEL_STOP(_, unitTarget, castGUID, spellID, castBarID)
SetUnitCastState(self, unitTarget, "channeling", false)
if unitTarget == "player" then
state.channeling = false
state.castTargetUnit = nil
state.castTargetName = nil
state.castTargetIndex = 0
self:UpdatePlayerCasting(0)
elseif unitTarget == "target" then
target.channeling = false
state.channelingSpellID = nil
ClearPlayerCastTarget(self)
end
end
function Fuyutsui:UNIT_SPELLCAST_EMPOWER_START(_, unitTarget, castGUID, spellID, castBarID)
SetUnitCastState(self, unitTarget, "empowering", true)
if unitTarget == "player" then
state.empowering = true
state.empoweringSpellID = spellID
self:UpdatePlayerCasting(spellID)
elseif unitTarget == "target" then
target.empowering = true
self:SetPlayerCastingSpell(spellID)
end
end
function Fuyutsui:UNIT_SPELLCAST_EMPOWER_STOP(_, unitTarget, castGUID, spellID, complete, interruptedBy, castBarID)
SetUnitCastState(self, unitTarget, "empowering", false)
if unitTarget == "player" then
state.empowering = false
state.castTargetUnit = nil
state.castTargetName = nil
state.castTargetIndex = 0
self:UpdatePlayerCasting(0)
elseif unitTarget == "target" then
target.empowering = false
state.empoweringSpellID = nil
ClearPlayerCastTarget(self)
end
end
function Fuyutsui:UNIT_SPELLCAST_SUCCEEDED(_, unitTarget, castGUID, spellID, castBarID)
if unitTarget ~= "player" or isSec(spellID) then return end
self:UpdateDrinkStatus(spellID)
self:RefreshDrinkStatus(spellID)
self:UpdateInsertSpellBySuccess(spellID)
if spellID == 384255 then
self:ClearAllFuyutsuiBars()
print("切换天赋")
C_Timer.After(1, function()
self:UpdatePlayerSpecInfo()
self:RebuildSpecializationState()
end)
elseif spellID == 200749 then
self:ClearAllFuyutsuiBars()
print("切换专精")
C_Timer.After(1, function()
self:UpdatePlayerSpecInfo()
self:RebuildSpecializationState()
end)
end
end
@@ -204,7 +211,7 @@ function Fuyutsui:SPELL_UPDATE_COOLDOWN(_, spellID, baseSpellID)
if spellID == 25771 then
self:UpdatePlayerForbearance()
end
self:UpdateKnightStatus(spellID)
self:RecordKnightSpellState(spellID)
end
local potions = {
@@ -242,23 +249,23 @@ function Fuyutsui:UNIT_HEALTH(_, unit)
self:UpdatePlayerStagger()
end
if self.group[unit] then
self:UpdateUnitHealthInfo(unit)
self:UpdateUnitDeath(unit, "health")
self:RefreshGroupMemberHealth(unit)
self:RefreshGroupMemberDeath(unit, "health")
end
if unit == "target" then
self:UpdateTargetHealth()
self:RefreshTargetHealthState()
end
if unit == "focus" then
self:UpdateFocusHealth()
self:RefreshFocusHealthState()
end
if unit == "mouseover" then
self:UpdateMouseoverHealth()
self:RefreshMouseoverHealthState()
end
if unit == "pet" then
self:UpdateUnitHealthBlock(unit)
self:RefreshUnitHealthState(unit)
end
if unit and unit:match("^boss[1-5]$") then
self:UpdateUnitHealthBlock(unit)
if self:IsBossUnit(unit) then
self:RefreshUnitHealthState(unit)
end
end
@@ -267,17 +274,17 @@ function Fuyutsui:UNIT_MAXHEALTH(_, unit)
self:UpdatePlayerHealth()
end
if self.group[unit] then
self:UpdateUnitHealthInfo(unit)
self:UpdateUnitDeath(unit, "health")
self:RefreshGroupMemberHealth(unit)
self:RefreshGroupMemberDeath(unit, "health")
end
if unit == "mouseover" then
self:UpdateMouseoverHealth()
self:RefreshMouseoverHealthState()
end
if unit == "pet" then
self:UpdateUnitHealthBlock(unit)
self:RefreshUnitHealthState(unit)
end
if unit and unit:match("^boss[1-5]$") then
self:UpdateUnitHealthBlock(unit)
if self:IsBossUnit(unit) then
self:RefreshUnitHealthState(unit)
end
end
@@ -286,8 +293,8 @@ function Fuyutsui:UNIT_HEAL_ABSORB_AMOUNT_CHANGED(_, unit)
self:UpdatePlayerHealth()
end
if self.group[unit] then
self:UpdateUnitHealthInfo(unit)
self:UpdateUnitDeath(unit, "health")
self:RefreshGroupMemberHealth(unit)
self:RefreshGroupMemberDeath(unit, "health")
end
end
@@ -296,8 +303,8 @@ function Fuyutsui:UNIT_HEAL_PREDICTION(_, unit)
self:UpdatePlayerHealth()
end
if self.group[unit] then
self:UpdateUnitHealthInfo(unit)
self:UpdateUnitDeath(unit, "health")
self:RefreshGroupMemberHealth(unit)
self:RefreshGroupMemberDeath(unit, "health")
end
end
@@ -306,7 +313,7 @@ function Fuyutsui:UNIT_POWER_UPDATE(_, unit, powerType)
self:UpdatePlayerPower(powerType)
if powerType == "COMBO_POINTS" then
C_Timer.After(0, function()
self:UpdateChargedComboPoints()
self:RefreshChargedComboPoints()
end)
end
end
@@ -314,7 +321,7 @@ end
function Fuyutsui:UNIT_POWER_POINT_CHARGE(_, unit)
if unit ~= "player" then return end
C_Timer.After(0, function()
self:UpdateChargedComboPoints()
self:RefreshChargedComboPoints()
end)
end
@@ -336,16 +343,16 @@ function Fuyutsui:GROUP_ROSTER_UPDATE()
rosterTimer:Cancel()
end
rosterTimer = C_Timer.NewTimer(1, function()
self:UpdateGroup()
self:UpdateGroupCount()
self:UpdateGroupType()
self:RebuildGroupRoster()
self:RefreshGroupCountState()
self:RefreshGroupTypeState()
rosterTimer = nil
end)
end
function Fuyutsui:UNIT_DIED(_, unitGUID)
if not isSec(unitGUID) then
self:UpdateUnitDeath(unitGUID, "guid")
self:RefreshGroupMemberDeath(unitGUID, "guid")
end
end
@@ -357,7 +364,7 @@ end
function Fuyutsui:UI_ERROR_MESSAGE(_, errorType, message)
if message == "目标不在视野中" then
self:UpdateUnitInSight(state.castTargetUnit)
self:MarkGroupMemberTemporarilyOutOfSight(state.castTargetUnit)
end
end
@@ -378,17 +385,17 @@ function Fuyutsui:ACTIONBAR_HIDEGRID()
end
function Fuyutsui:PLAYER_TARGET_CHANGED()
self:UpdateTargetFullInfo()
self:RefreshTargetState()
self:UpdateUnitAuraContainer("target")
end
function Fuyutsui:PLAYER_FOCUS_CHANGED()
self:UpdateFocusFullInfo()
self:RefreshFocusState()
self:UpdateUnitAuraContainer("focus")
end
function Fuyutsui:UPDATE_MOUSEOVER_UNIT()
self:UpdateMouseoverFullInfo()
self:RefreshMouseoverState()
end
--- 过场/影片结束后重绑 spellId 过滤(槽位否则会落到排序第一的光环)
@@ -405,52 +412,48 @@ function Fuyutsui:STOP_MOVIE()
end
function Fuyutsui:NAME_PLATE_UNIT_ADDED(_, unit)
self:AddNameplate(unit)
self:UpdateTargetCanAttack()
for index = 1, 5 do
local boss = "boss" .. index
self:UpdateUnitCanAttack(boss)
self:UpdateUnitRangeBlock(boss)
end
self:CacheNameplateUnit(unit)
self:RefreshTargetReactionState()
self:RefreshBossReactionAndRangeStates()
end
function Fuyutsui:NAME_PLATE_UNIT_REMOVED(_, unit)
nameplate[unit] = nil
self:UpdateTargetCanAttack()
self:RefreshTargetReactionState()
end
function Fuyutsui:UNIT_THREAT_SITUATION_UPDATE(_, unitTarget)
if nameplate[unitTarget] then
self:UpdateNameplateThreat(unitTarget)
self:UpdateThreatEnemyCounts()
self:RefreshNameplateThreat(unitTarget)
self:RefreshThreatEnemyCounts()
return
end
if unitTarget ~= "player" then return end
for unit in pairs(nameplate) do
self:UpdateNameplateThreat(unit)
self:RefreshNameplateThreat(unit)
end
self:UpdateThreatEnemyCounts()
self:RefreshThreatEnemyCounts()
end
function Fuyutsui:RefreshShapeshiftAndMount()
self:UpdateShapeshiftForm()
self:UpdatePlayerMounted()
function Fuyutsui:RefreshShapeshiftAndMountStates()
self:RefreshShapeshiftFormState()
self:RefreshPlayerMountedState()
end
function Fuyutsui:UPDATE_SHAPESHIFT_FORM()
self:RefreshShapeshiftAndMount()
self:RefreshShapeshiftAndMountStates()
end
function Fuyutsui:UPDATE_SHAPESHIFT_FORMS()
self:RefreshShapeshiftAndMount()
self:RefreshShapeshiftAndMountStates()
end
function Fuyutsui:ENCOUNTER_START(_, encounterID, encounterName, difficultyID, groupSize)
self:UpdateEncounterID(encounterID, difficultyID)
self:SetEncounterState(encounterID, difficultyID)
end
function Fuyutsui:ENCOUNTER_END(_, encounterID, encounterName, difficultyID, groupSize, success)
self:UpdateEncounterID(0, 0)
self:SetEncounterState(0, 0)
end
function Fuyutsui:ENCOUNTER_TIMELINE_EVENT_ADDED(_, eventInfo)
@@ -475,35 +478,57 @@ end
Fuyutsui.timeElapsed = 0
Fuyutsui.timeElapsed1 = 0
local updateErrorTimes = {}
local UPDATE_ERROR_THROTTLE_SECONDS = 10
local function RunUpdateSafely(self, methodName, ...)
local method = self[methodName]
if type(method) ~= "function" then return end
local errorKey = methodName
local context = select(1, ...)
if type(context) == "string" then
errorKey = methodName .. "(" .. context .. ")"
end
local success, errorMessage = pcall(method, self, ...)
if success then return end
local now = GetTime()
local lastErrorTime = updateErrorTimes[errorKey]
if not lastErrorTime or now - lastErrorTime >= UPDATE_ERROR_THROTTLE_SECONDS then
updateErrorTimes[errorKey] = now
print("Fuyutsui OnUpdate error [" .. errorKey .. "]: " .. tostring(errorMessage))
end
end
function Fuyutsui:OnUpdate(elapsed)
self:UpdateGroupInRangeAndHealth()
RunUpdateSafely(self, "RefreshNextGroupMemberState")
self.timeElapsed = self.timeElapsed + elapsed
if self.timeElapsed > 0.2 then
self:UpdateSpellCooldown()
self:UpdatePlayerAssistant()
self:UpdateRune()
self:UpdateTargetRangeBlock()
self:UpdateFocusRangeBlock()
self:UpdateMouseoverRangeBlock()
RunUpdateSafely(self, "UpdateSpellCooldown")
RunUpdateSafely(self, "RefreshAssistedCombatSuggestion")
RunUpdateSafely(self, "UpdateRune")
RunUpdateSafely(self, "RefreshTargetRangeState")
RunUpdateSafely(self, "RefreshFocusRangeState")
RunUpdateSafely(self, "RefreshMouseoverRangeState")
self:UpdateEnemyCount()
self:UpdateItemCooldown()
RunUpdateSafely(self, "RefreshEnemyCounts")
RunUpdateSafely(self, "UpdateItemCooldown")
self.timeElapsed = 0
end
self.timeElapsed1 = self.timeElapsed1 + elapsed
if self.timeElapsed1 >= 1 then
self:UpdatePlayerCombatTime()
self:UpdateKnightStatusCount()
RunUpdateSafely(self, "RefreshPlayerCombatDuration")
RunUpdateSafely(self, "RefreshActiveKnightCount")
self.timeElapsed1 = 0
end
self:UpdatePlayerCastBlocks()
self:UpdateUnitCastingOrChannelingInfo("target")
self:UpdateUnitCastingOrChannelingInfo("focus")
self:UpdateUnitCastingOrChannelingInfo("mouseover")
for index = 1, 5 do
self:UpdateUnitCastingOrChannelingInfo("boss" .. index)
end
RunUpdateSafely(self, "RefreshPlayerCastStateBlocks")
RunUpdateSafely(self, "RefreshUnitCastStateBlocks", "target")
RunUpdateSafely(self, "RefreshUnitCastStateBlocks", "focus")
RunUpdateSafely(self, "RefreshUnitCastStateBlocks", "mouseover")
RunUpdateSafely(self, "RefreshBossCastStateBlocks", RunUpdateSafely)
end

View File

@@ -272,6 +272,11 @@ local stateBlockGetters = {
["宠物"] = {
["存在"] = function() return pet.exists or 0 end,
["生命值"] = function() return pet.healthPercent or 0 end,
["施法(倒计时)"] = function(self) return self:GetUnitCastPixel("pet", "cast") end,
["施法(正计时)"] = function(self) return self:GetUnitCastPixel("pet", "castElapsed") end,
["施法可打断"] = function(self) return self:GetUnitInterruptiblePixel("pet", "cast") end,
["引导"] = function(self) return self:GetUnitCastPixel("pet", "channel") end,
["引导可打断"] = function(self) return self:GetUnitInterruptiblePixel("pet", "channel") end,
},
}

View File

@@ -1,41 +1,38 @@
local addon, ns = ...
function Fuyutsui:UpdatePlayerBlocks()
function Fuyutsui:RefreshPlayerState()
self.isInitialized = false
self.state.isDead = UnitIsDeadOrGhost("player")
self.state.isChatOpen = false
self.state.drinkStatus = false
self.state.mountCasting = false
self:UpdatePlayerMounted()
self:UpdatePlayerPet()
self:UpdatePlayerCombat()
self:UpdatePlayerMoving(IsPlayerMoving())
self:UpdatePlayerCastBlocks()
self:RefreshPlayerMountedState()
self:RefreshPlayerPetState()
self:RefreshPlayerCombatState()
self:SetPlayerMoving(IsPlayerMoving())
self:RefreshPlayerCastStateBlocks()
self:UpdatePlayerHealth()
self:UpdatePlayerAssistant()
self:UpdateTargetType()
self:UpdateFocusType()
self:UpdateGroupType()
self:UpdateGroupCount()
self:RefreshAssistedCombatSuggestion()
self:RefreshTargetTypeState()
self:RefreshFocusTypeState()
self:RefreshGroupTypeState()
self:RefreshGroupCountState()
self:UpdateHeroTalent()
self:UpdatePlayerBarInfo()
self:UpdateShapeshiftForm()
self:RefreshPlayerBars()
self:RefreshShapeshiftFormState()
self:UpdatePlayerStagger()
self:UpdateRune()
self:UpdateTargetRangeBlock()
self:UpdateFocusRangeBlock()
self:UpdateTargetHealth()
self:UpdateFocusHealth()
for index = 1, 5 do
self:UpdateUnitFullInfo("boss" .. index)
self:UpdateUnitRangeBlock("boss" .. index)
end
self:UpdateEnemyCount()
self:UpdateGroup()
self:RefreshTargetRangeState()
self:RefreshFocusRangeState()
self:RefreshTargetHealthState()
self:RefreshFocusHealthState()
self:RefreshBossUnitStates()
self:RefreshEnemyCounts()
self:RebuildGroupRoster()
self:GetItemCount()
self:UpdatePlayerPowerType()
self:RefreshAllPlayerPowers()
C_Timer.After(1, function()
self:UpdatePlayerConfig()
self:RefreshPlayerConfigStateBlocks()
self.isInitialized = true
end)
end

45
Fuyutsui/unit/boss.lua Normal file
View File

@@ -0,0 +1,45 @@
local addon, ns = ...
local state = Fuyutsui.state
local BOSS_UNIT_COUNT = 5
function Fuyutsui:IsBossUnit(unit)
return type(unit) == "string" and unit:match("^boss[1-5]$") ~= nil
end
function Fuyutsui:RefreshBossUnitStates()
for index = 1, BOSS_UNIT_COUNT do
local unit = "boss" .. index
self:RefreshUnitState(unit)
self:RefreshUnitRangeState(unit)
end
end
function Fuyutsui:RefreshBossReactionAndRangeStates()
for index = 1, BOSS_UNIT_COUNT do
local unit = "boss" .. index
self:RefreshUnitReactionState(unit)
self:RefreshUnitRangeState(unit)
end
end
function Fuyutsui:RefreshBossCastStateBlocks(refreshSafely)
for index = 1, BOSS_UNIT_COUNT do
local unit = "boss" .. index
if refreshSafely then
refreshSafely(self, "RefreshUnitCastStateBlocks", unit)
else
self:RefreshUnitCastStateBlocks(unit)
end
end
end
function Fuyutsui:SetEncounterState(encounterID, difficultyID)
state.encounterID = encounterID
local bossIndex = self.bossID and self.bossID[encounterID] or 0
state.bossID = bossIndex / 255
self:UpdateStateBlock("状态", "首领战")
state.difficultyID = difficultyID
self:UpdateStateBlock("状态", "难度")
end

View File

@@ -4,19 +4,20 @@ local EvaluateColorFromBoolean = C_CurveUtil.EvaluateColorFromBoolean
local state = Fuyutsui.state
local roleMap = Fuyutsui.roleMap
local groupHealthCurves = Fuyutsui.groupHealthCurves
local ColorValue0 = CreateColor(0, 0, 0, 1)
local updateIndex = 1
local GROUP_MAX_MEMBERS = 40
-- 施法治疗预估偏移(近似秒数/权重,写入生命曲线)
local helpfulSpells = {
[2061] = 15,
[1262763] = 15,
[82326] = 40,
[19750] = 15,
[8936] = 15,
[186263] = 40,
[77472] = 15,
-- 治疗法术直接选择登录时预创建的生命曲线,禁止在战斗中创建曲线。
local helpfulSpellCurves = {
[2061] = groupHealthCurves.incoming15,
[1262763] = groupHealthCurves.incoming15,
[82326] = groupHealthCurves.incoming40,
[19750] = groupHealthCurves.incoming15,
[8936] = groupHealthCurves.incoming15,
[186263] = groupHealthCurves.incoming40,
[77472] = groupHealthCurves.incoming15,
}
function Fuyutsui:IterateGroupMembers(reversed, forceParty)
@@ -35,27 +36,26 @@ function Fuyutsui:IterateGroupMembers(reversed, forceParty)
end
end
function Fuyutsui:UpdateUnitHealthInfo(unit)
function Fuyutsui:RefreshGroupMemberHealth(unit)
local blocks = self.blocks
local group = self.group
local obj = group[unit]
if not blocks or not blocks.groups or not obj then return end
local index = blocks.groups.start + (obj.index - 1) * blocks.groups.num + blocks.groups.healthPercent
obj.curve = self:CreateColorCurveScaling(100 + (obj.inComingHeals or 0))
local healthPercent = UnitHealthPercent(unit, false, obj.curve)
local healthPercent = UnitHealthPercent(unit, true, obj.curve or groupHealthCurves.default)
---@diagnostic disable-next-line: param-type-mismatch
local _, _, b = healthPercent:GetRGB()
obj.healthPercent = b
self:CreateTexture(index, obj.healthPercent)
end
function Fuyutsui:UpdateUnitValid(unit)
function Fuyutsui:RefreshGroupMemberValidity(unit)
local obj = self.group[unit]
if not obj then return end
obj.valid = not obj.isDead and obj.canAssist and obj.inSight
end
function Fuyutsui:UpdateGroupInRangeAndHealth()
function Fuyutsui:RefreshNextGroupMemberState()
local blocks = self.blocks
local group = self.group
local groupList = self.groupList
@@ -77,7 +77,6 @@ function Fuyutsui:UpdateGroupInRangeAndHealth()
return
end
self:UpdateUnitHealthInfo(unit)
local index = blocks.groups.start + (obj.index - 1) * blocks.groups.num + blocks.groups.role
obj.isDead = UnitIsDeadOrGhost(unit)
obj.canAssist = UnitCanAssist("player", unit)
@@ -97,13 +96,13 @@ function Fuyutsui:UpdateGroupInRangeAndHealth()
end
--- source: "guid" | "health" | nil
function Fuyutsui:UpdateUnitDeath(unitOrGuid, source)
function Fuyutsui:RefreshGroupMemberDeath(unitOrGuid, source)
local group = self.group
if source == "guid" then
for unit, data in pairs(group) do
if data.GUID == unitOrGuid then
data.isDead = true
self:UpdateUnitValid(unit)
self:RefreshGroupMemberValidity(unit)
end
end
return
@@ -112,10 +111,10 @@ function Fuyutsui:UpdateUnitDeath(unitOrGuid, source)
local obj = group[unitOrGuid]
if not obj then return end
obj.isDead = UnitIsDeadOrGhost(unitOrGuid)
self:UpdateUnitValid(unitOrGuid)
self:RefreshGroupMemberValidity(unitOrGuid)
end
function Fuyutsui:UpdateUnitInSight(unit)
function Fuyutsui:MarkGroupMemberTemporarilyOutOfSight(unit)
local obj = self.group[unit]
if not obj then return end
obj.inSight = false
@@ -126,29 +125,33 @@ function Fuyutsui:UpdateUnitInSight(unit)
obj.inSightTimer = C_Timer.NewTimer(1.5, function()
obj.inSight = true
obj.inSightTimer = nil
Fuyutsui:UpdateUnitValid(unit)
Fuyutsui:RefreshGroupMemberValidity(unit)
end)
self:UpdateUnitValid(unit)
self:RefreshGroupMemberValidity(unit)
end
function Fuyutsui:ApplyIncomingHealsCurve(spellID)
function Fuyutsui:RecordIncomingHealEstimate(spellID)
local unit = state.castTargetUnit
if not unit then return end
local obj = self.group[unit]
if not obj then return end
local isHelpfulSpell = helpfulSpells[spellID]
if isHelpfulSpell then
obj.inComingHeals = isHelpfulSpell
local curve = helpfulSpellCurves[spellID]
if curve then
obj.curve = curve
self:RefreshGroupMemberHealth(unit)
end
end
function Fuyutsui:UpdateAllIncomingHealsCurves()
for _, data in pairs(self.group) do
data.inComingHeals = 0
function Fuyutsui:ClearIncomingHealEstimates()
for unit, data in pairs(self.group) do
if data.curve ~= groupHealthCurves.default then
data.curve = groupHealthCurves.default
self:RefreshGroupMemberHealth(unit)
end
end
end
function Fuyutsui:ClearGroupBlocks()
function Fuyutsui:ClearGroupStateBlocks()
local blocks = self.blocks
local groups = blocks and blocks.groups or nil
if not groups or not groups.start or not groups.num then
@@ -161,8 +164,8 @@ function Fuyutsui:ClearGroupBlocks()
end
end
function Fuyutsui:UpdateGroup()
self:ClearGroupBlocks()
function Fuyutsui:RebuildGroupRoster()
self:ClearGroupStateBlocks()
updateIndex = 1
self.group = {}
self.groupList = {}
@@ -186,11 +189,10 @@ function Fuyutsui:UpdateGroup()
canAssist = UnitCanAssist("player", unit),
inSight = true,
inSightTimer = nil,
curve = self.curve100,
inComingHeals = 0,
curve = groupHealthCurves.default,
}
self:UpdateUnitValid(unit)
self:UpdateUnitHealthInfo(unit)
self:RefreshGroupMemberValidity(unit)
self:RefreshGroupMemberHealth(unit)
i = i + 1
end
if self.RefreshGroupAuraContainers then

View File

@@ -9,14 +9,14 @@ local spellsList = Fuyutsui.spellsList
local drinkStatusTimer = nil
function Fuyutsui:GetCharacterInfo()
function Fuyutsui:InitializeCharacterState()
self.db.char.level = UnitLevel("player")
self.state.name = UnitName("player")
self.state.GUID = UnitGUID("player")
self.state.classColor = RAID_CLASS_COLORS[self.state.classFilename].colorStr
end
function Fuyutsui:GetCharacterSpecInfo()
function Fuyutsui:InitializeSpecializationState()
self.state.specIndex = C_SpecializationInfo.GetSpecialization()
local specID, specName, _, _, role = C_SpecializationInfo.GetSpecializationInfo(self.state.specIndex)
self.state.specID = specID
@@ -27,12 +27,13 @@ function Fuyutsui:GetCharacterSpecInfo()
self.state.isChatOpen = false
self.state.casting = false
self.state.channeling = false
self.state.empowering = false
self.state.mountCasting = false
self:LoadPlayerBlocks(self.state.specIndex)
self:UpdateSpellKnown()
self:UpdatePlayerMounted()
self:UpdatePlayerPet()
self:UpdateGroup()
self:RefreshPlayerMountedState()
self:RefreshPlayerPetState()
self:RebuildGroupRoster()
-- 登录阶段其他插件可能稍后写入覆盖绑定;首次加载延后 5 秒,确保本插件最后绑定。
C_Timer.After(5, function()
self:LoadPlayerMacros()
@@ -42,7 +43,7 @@ function Fuyutsui:GetCharacterSpecInfo()
self:UpdateStateBlock("状态", "专精")
end
function Fuyutsui:UpdatePlayerSpecInfo()
function Fuyutsui:RebuildSpecializationState()
self:ClearAllTextures()
self.state.specIndex = C_SpecializationInfo.GetSpecialization()
local specID, specName, _, _, role = C_SpecializationInfo.GetSpecializationInfo(self.state.specIndex)
@@ -52,24 +53,24 @@ function Fuyutsui:UpdatePlayerSpecInfo()
self.state.specRange = self.rangeSpecID[specID]
self:LoadPlayerBlocks(self.state.specIndex)
self:UpdateSpellKnown()
self:UpdatePlayerBlocks()
self:RefreshPlayerState()
self:LoadPlayerMacros()
self:UpdateStateBlock("状态", "职业")
self:UpdateStateBlock("状态", "专精")
end
function Fuyutsui:UpdatePlayerValid()
function Fuyutsui:RefreshPlayerValidity()
local valid = not state.isDead and not state.mounted and not state.isChatOpen and not state.drinkStatus and
not state.mountCasting
state.valid = valid and 1 / 255 or 0
self:UpdateStateBlock("状态", "有效性")
end
function Fuyutsui:UpdatePlayerCombat()
function Fuyutsui:RefreshPlayerCombatState()
state.combat = UnitAffectingCombat("player")
end
function Fuyutsui:UpdatePlayerCombatTime()
function Fuyutsui:RefreshPlayerCombatDuration()
if state.combat then
local combatTime = GetTime() - state.combatStartTime
state.combatTime = math.min(1, combatTime / 255)
@@ -79,37 +80,41 @@ function Fuyutsui:UpdatePlayerCombatTime()
self:UpdateStateBlock("状态", "战斗时间")
end
function Fuyutsui:UpdatePlayerMoving(boolean)
function Fuyutsui:SetPlayerMoving(isMoving)
state.drinkStatus = false
self:UpdatePlayerValid()
state.moving = boolean and 1 / 255 or 0
self:RefreshPlayerValidity()
state.moving = isMoving and 1 / 255 or 0
self:UpdateStateBlock("状态", "移动")
end
function Fuyutsui:UpdatePlayerCastBlocks()
self:UpdateStateBlock("状态", "施法(正计时)")
self:UpdateStateBlock("状态", "施法(倒计时)")
self:UpdateStateBlock("状态", "引导")
self:UpdateStateBlock("状态", "蓄力")
self:UpdateStateBlock("状态", "蓄力层数")
function Fuyutsui:RefreshPlayerCastStateBlocks()
if state.casting then
self:RefreshPlayerCastingStateBlocks()
end
if state.channeling then
self:RefreshPlayerChannelStateBlock()
end
if state.empowering then
self:RefreshPlayerEmpowerStateBlocks()
end
end
function Fuyutsui:UpdatePlayerCastingInfo()
function Fuyutsui:RefreshPlayerCastingStateBlocks()
self:UpdateStateBlock("状态", "施法(正计时)")
self:UpdateStateBlock("状态", "施法(倒计时)")
end
function Fuyutsui:UpdatePlayerChannelingInfo()
function Fuyutsui:RefreshPlayerChannelStateBlock()
self:UpdateStateBlock("状态", "引导")
end
function Fuyutsui:UpdatePlayerEmpowerInfo()
function Fuyutsui:RefreshPlayerEmpowerStateBlocks()
self:UpdateStateBlock("状态", "蓄力")
self:UpdateStateBlock("状态", "蓄力层数")
end
function Fuyutsui:UpdatePlayerHealth()
local healthPercent = UnitHealthPercent("player", false, self.curve100)
local healthPercent = UnitHealthPercent("player", true, self.curve100)
---@diagnostic disable-next-line: param-type-mismatch
local _, _, b = healthPercent:GetRGB()
state.healthPercent = b
@@ -135,13 +140,13 @@ function Fuyutsui:UpdatePlayerPower(powerType)
end
end
function Fuyutsui:UpdateChargedComboPoints()
function Fuyutsui:RefreshChargedComboPoints()
local chargedPoints = GetUnitChargedPowerPoints("player")
state.chargedComboPoints = (chargedPoints and #chargedPoints or 0) / 255
self:UpdateStateBlock("能量", "增压层数")
end
function Fuyutsui:UpdatePlayerPowerType()
function Fuyutsui:RefreshAllPlayerPowers()
state.power = {}
for powerType in pairs(EnumPowerType) do
self:CreatePowerCurve(powerType)
@@ -160,7 +165,7 @@ local empowerSpellId = {
local assistantWasEmpower = false
local assistantSuppressUntil = 0
function Fuyutsui:UpdatePlayerAssistant()
function Fuyutsui:RefreshAssistedCombatSuggestion()
local spellId = C_AssistedCombat.GetNextCastSpell()
local now = GetTime()
@@ -198,7 +203,7 @@ function Fuyutsui:UpdatePlayerAssistant()
self:UpdateStateBlock("状态", "一键辅助")
end
function Fuyutsui:UpdateGroupType()
function Fuyutsui:RefreshGroupTypeState()
local index = 0
if UnitInRaid("player") then
index = UnitInRaid("player") or 0
@@ -209,25 +214,12 @@ function Fuyutsui:UpdateGroupType()
self:UpdateStateBlock("状态", "队伍类型")
end
function Fuyutsui:UpdateGroupCount()
function Fuyutsui:RefreshGroupCountState()
local count = GetNumGroupMembers()
state.groupCount = count / 255 or 0
self:UpdateStateBlock("状态", "队伍人数")
end
function Fuyutsui:UpdateEncounterID(encounterID, difficultyID)
state.encounterID = encounterID
local id = self.bossID and self.bossID[encounterID] or 0
if id then
state.bossID = id / 255 or 0
else
state.bossID = 0
end
self:UpdateStateBlock("状态", "首领战")
state.difficultyID = difficultyID
self:UpdateStateBlock("状态", "难度")
end
function Fuyutsui:UpdateHeroTalent()
if self.heroTalents then
C_Timer.After(1, function()
@@ -243,7 +235,7 @@ function Fuyutsui:UpdateHeroTalent()
end
end
function Fuyutsui:UpdatePlayerBarInfo()
function Fuyutsui:RefreshPlayerBars()
local blocks = self.blocks
if self.RefreshPlayerAuraContainers then
self:RefreshPlayerAuraContainers()
@@ -258,25 +250,25 @@ function Fuyutsui:UpdatePlayerBarInfo()
end
end
function Fuyutsui:UpdatePlayerPet()
self:UpdateUnitType("pet")
self:UpdateUnitHealthBlock("pet")
function Fuyutsui:RefreshPlayerPetState()
self:RefreshUnitTypeState("pet")
self:RefreshUnitHealthState("pet")
end
function Fuyutsui:UpdatePlayerMounted()
function Fuyutsui:RefreshPlayerMountedState()
state.mounted = IsMounted() or state.shapeshiftFormID == 27 or state.shapeshiftFormID == 3 or
state.shapeshiftFormID == 29
self:UpdatePlayerValid()
self:RefreshPlayerValidity()
end
function Fuyutsui:UpdatePlayerCasting(spellId)
function Fuyutsui:SetPlayerCastingSpell(spellId)
local castingSpell = spellsList[spellId] and spellsList[spellId].index or 0
state.castingSpell = castingSpell / 255 or 0
self:UpdateStateBlock("状态", "施法目标")
self:UpdateStateBlock("状态", "施法技能")
end
function Fuyutsui:UpdatePlayerConfig()
function Fuyutsui:RefreshPlayerConfigStateBlocks()
if not (self.db and self.db.char) then return end
local names = { "爆发开关", "AOE开关", "输出模式", "爆发药水开关" }
for i = 1, #names do
@@ -385,24 +377,24 @@ function Fuyutsui:UpdateRune()
self:UpdateBareStateBlock("符文", { "能量", "状态" })
end
function Fuyutsui:UpdateShapeshiftForm()
function Fuyutsui:RefreshShapeshiftFormState()
local shapeshiftFormID = GetShapeshiftFormID() or 0
state.shapeshiftFormID = shapeshiftFormID / 255
self:UpdateStateBlock("状态", "姿态")
end
function Fuyutsui:UpdateDrinkStatus(spellID)
function Fuyutsui:RefreshDrinkStatus(spellID)
local name = C_Spell.GetSpellName(spellID)
if name == "饮水" or name == "进食饮水" then
state.drinkStatus = true
self:UpdatePlayerValid()
self:RefreshPlayerValidity()
if drinkStatusTimer then
drinkStatusTimer:Cancel()
drinkStatusTimer = nil
end
drinkStatusTimer = C_Timer.NewTimer(20, function()
state.drinkStatus = false
self:UpdatePlayerValid()
self:RefreshPlayerValidity()
drinkStatusTimer = nil
end)
else
@@ -411,7 +403,7 @@ function Fuyutsui:UpdateDrinkStatus(spellID)
drinkStatusTimer = nil
end
state.drinkStatus = false
self:UpdatePlayerValid()
self:RefreshPlayerValidity()
end
end
@@ -430,7 +422,7 @@ local InactiveKnightSpells = {
}
local ActiveKnights = { false, false, false, false }
function Fuyutsui:UpdateKnightStatus(spellID)
function Fuyutsui:RecordKnightSpellState(spellID)
if ActiveKnightSpells[spellID] then
ActiveKnights[ActiveKnightSpells[spellID]] = true
end
@@ -449,7 +441,7 @@ local function GetActiveKnightsCount()
return count
end
function Fuyutsui:UpdateKnightStatusCount()
function Fuyutsui:RefreshActiveKnightCount()
state.knightCount = GetActiveKnightsCount() / 255
self:UpdateStateBlock("状态", "天启骑士数量")
end
@@ -460,11 +452,11 @@ function Fuyutsui:HookChatFrameEditBox()
if editBox then
editBox:HookScript("OnEditFocusGained", function()
state.isChatOpen = true
self:UpdatePlayerValid()
self:RefreshPlayerValidity()
end)
editBox:HookScript("OnEditFocusLost", function()
state.isChatOpen = false
self:UpdatePlayerValid()
self:RefreshPlayerValidity()
end)
end
end
@@ -473,7 +465,7 @@ end
local mounts = {}
local mountCastingTimer = nil
function Fuyutsui:GetMountsInfo()
function Fuyutsui:CacheCollectedMountSpells()
wipe(mounts)
local mountIDs = C_MountJournal.GetMountIDs()
for i = 1, #mountIDs do
@@ -484,15 +476,15 @@ function Fuyutsui:GetMountsInfo()
end
end
function Fuyutsui:UpdateMountCasting(spellID, casting)
if casting then
function Fuyutsui:SetMountSpellCasting(spellID, isCasting)
if isCasting then
if spellID and not issecretvalue(spellID) and mounts[spellID] then
if mountCastingTimer then
mountCastingTimer:Cancel()
mountCastingTimer = nil
end
state.mountCasting = true
self:UpdatePlayerValid()
self:RefreshPlayerValidity()
end
elseif state.mountCasting then
if mountCastingTimer then
@@ -500,7 +492,7 @@ function Fuyutsui:UpdateMountCasting(spellID, casting)
end
mountCastingTimer = C_Timer.NewTimer(0.1, function()
state.mountCasting = false
self:UpdatePlayerValid()
self:RefreshPlayerValidity()
mountCastingTimer = nil
end)
end

View File

@@ -10,7 +10,7 @@ local pet = Fuyutsui.pet
local boss = Fuyutsui.boss
local nameplate = Fuyutsui.nameplate
function Fuyutsui:GetUnitRange(unit)
function Fuyutsui:GetUnitRangeBounds(unit)
local minRange, maxRange = rc:GetRange(unit)
return minRange, maxRange
end
@@ -27,7 +27,8 @@ local unitZHMap = {
["boss5"] = "首领5",
}
local function GetUnitCache(unit)
local function GetUnitState(unit)
if unit == "player" then return state end
if unit == "target" then return target end
if unit == "focus" then return focus end
if unit == "mouseover" then return mouseover end
@@ -35,7 +36,30 @@ local function GetUnitCache(unit)
if boss and boss[unit] then return boss[unit] end
end
local function isSameUnit(unit1, unit2)
local castStateFields = {
casting = true,
channeling = true,
empowering = true,
}
function Fuyutsui:SetTrackedUnitCastState(unit, stateField, isActive)
local cache = GetUnitState(unit)
if not cache or not castStateFields[stateField] then return false end
cache[stateField] = isActive == true
return true
end
function Fuyutsui:ResetTrackedUnitCastState(unit)
local cache = GetUnitState(unit)
if not cache then return end
cache.casting = false
cache.channeling = false
cache.empowering = false
self:ClearUnitCastStateBlocks(unit, "casting")
self:ClearUnitCastStateBlocks(unit, "channeling")
end
local function AreSameUnits(unit1, unit2)
local isSame = UnitIsUnit(unit1, unit2)
if issecretvalue(isSame) then
return false
@@ -43,27 +67,27 @@ local function isSameUnit(unit1, unit2)
return isSame
end
local function getUnitTypeIndex(unit)
local function GetUnitIdentityIndex(unit)
if IsInRaid() then
for index = 1, 40 do
if isSameUnit(unit, "raid" .. index) then
if AreSameUnits(unit, "raid" .. index) then
return index
end
end
elseif UnitInParty("player") then
for index = 1, 4 do
if isSameUnit(unit, "party" .. index) then
if AreSameUnits(unit, "party" .. index) then
return 41 + index
end
end
end
if isSameUnit(unit, "player") then
if AreSameUnits(unit, "player") then
return 41
end
for index = 1, 5 do
if isSameUnit(unit, "boss" .. index) then
if AreSameUnits(unit, "boss" .. index) then
return 45 + index
end
end
@@ -71,22 +95,22 @@ local function getUnitTypeIndex(unit)
return 51
end
local function getUnitType(unit)
local function EncodeUnitType(unit)
if not UnitExists(unit) then return 0 end
local canAttack = UnitCanAttack("player", unit)
local canAssist = UnitCanAssist("player", unit)
if not canAttack and not canAssist then return 0 end
local index = getUnitTypeIndex(unit)
local index = GetUnitIdentityIndex(unit)
if canAssist then
index = index + 100
end
return index / 255
end
function Fuyutsui:UpdateUnitType(unit)
local cache = GetUnitCache(unit)
function Fuyutsui:RefreshUnitTypeState(unit)
local cache = GetUnitState(unit)
local category = unitZHMap[unit]
if not cache or not category then return end
@@ -104,14 +128,14 @@ function Fuyutsui:UpdateUnitType(unit)
local unitType = 0
if not cache.isDead then
unitType = getUnitType(unit)
unitType = EncodeUnitType(unit)
end
cache.type = unitType
self:UpdateStateBlock(category, "类型")
end
function Fuyutsui:UpdateUnitCanAttack(unit)
local cache = GetUnitCache(unit)
function Fuyutsui:RefreshUnitReactionState(unit)
local cache = GetUnitState(unit)
if not cache then return end
cache.canAttack = UnitCanAttack("player", unit)
if boss and boss[unit] then
@@ -119,50 +143,71 @@ function Fuyutsui:UpdateUnitCanAttack(unit)
else
cache.canAssist = UnitCanAssist("player", unit)
end
self:UpdateUnitType(unit)
self:RefreshUnitTypeState(unit)
end
function Fuyutsui:UpdateUnitRangeBlock(unit)
local cache = GetUnitCache(unit)
function Fuyutsui:RefreshUnitRangeState(unit)
local cache = GetUnitState(unit)
local category = unitZHMap[unit]
if not cache or not category then return end
local minRange, maxRange = self:GetUnitRange(unit)
local minRange, maxRange = self:GetUnitRangeBounds(unit)
cache.minRange = minRange
cache.maxRange = maxRange
if cache.canAttack then
if cache.maxRange and self.state.specRange then
cache.inRange = cache.maxRange <= self.state.specRange
self:UpdateUnitType(unit)
self:RefreshUnitTypeState(unit)
end
elseif cache.canAssist then
if cache.maxRange then
cache.inRange = cache.maxRange <= 40
self:UpdateUnitType(unit)
self:RefreshUnitTypeState(unit)
end
end
self:UpdateStateBlock(category, "距离")
end
function Fuyutsui:UpdateUnitCastingOrChannelingInfo(unit)
local obj = unitZHMap[unit]
if obj then
self:UpdateStateBlock(obj, "施法(倒计时)")
self:UpdateStateBlock(obj, "施法(正计时)")
self:UpdateStateBlock(obj, "施法可打断")
self:UpdateStateBlock(obj, "引导")
self:UpdateStateBlock(obj, "引导可打断")
function Fuyutsui:RefreshUnitCastStateBlocks(unit)
local cache = GetUnitState(unit)
local category = unitZHMap[unit]
if not cache or not category or not UnitExists(unit) then return end
if cache.casting then
self:UpdateStateBlock(category, "施法(倒计时)")
self:UpdateStateBlock(category, "施法(正计时)")
self:UpdateStateBlock(category, "施法可打断")
end
if cache.channeling or cache.empowering then
self:UpdateStateBlock(category, "引导")
self:UpdateStateBlock(category, "引导可打断")
end
end
function Fuyutsui:UpdateUnitDeathStatus(unit)
local cache = GetUnitCache(unit)
if not cache then return end
cache.isDead = UnitIsDeadOrGhost(unit)
self:UpdateUnitType(unit)
function Fuyutsui:ClearUnitCastStateBlocks(unit, stateField)
local cache = GetUnitState(unit)
local category = unitZHMap[unit]
if not cache or not category then return end
if stateField == "casting" then
self:UpdateStateBlock(category, "施法(倒计时)")
self:UpdateStateBlock(category, "施法(正计时)")
self:UpdateStateBlock(category, "施法可打断")
elseif (stateField == "channeling" or stateField == "empowering")
and not cache.channeling and not cache.empowering then
self:UpdateStateBlock(category, "引导")
self:UpdateStateBlock(category, "引导可打断")
end
end
function Fuyutsui:UpdateUnitHealthBlock(unit)
local cache = GetUnitCache(unit)
function Fuyutsui:RefreshUnitDeathState(unit)
local cache = GetUnitState(unit)
if not cache then return end
cache.isDead = UnitIsDeadOrGhost(unit)
self:RefreshUnitTypeState(unit)
end
function Fuyutsui:RefreshUnitHealthState(unit)
local cache = GetUnitState(unit)
local category = unitZHMap[unit]
if not cache or not category then return end
if not UnitExists(unit) then
@@ -177,89 +222,90 @@ function Fuyutsui:UpdateUnitHealthBlock(unit)
self:UpdateStateBlock(category, "生命值")
end
function Fuyutsui:UpdateUnitFullInfo(unit)
self:UpdateUnitCanAttack(unit)
self:UpdateUnitDeathStatus(unit)
self:UpdateUnitHealthBlock(unit)
function Fuyutsui:RefreshUnitState(unit)
self:ResetTrackedUnitCastState(unit)
self:RefreshUnitReactionState(unit)
self:RefreshUnitDeathState(unit)
self:RefreshUnitHealthState(unit)
end
-- 目标兼容包装
function Fuyutsui:UpdateTargetType()
self:UpdateUnitType("target")
function Fuyutsui:RefreshTargetTypeState()
self:RefreshUnitTypeState("target")
end
function Fuyutsui:UpdateTargetCanAttack()
self:UpdateUnitCanAttack("target")
function Fuyutsui:RefreshTargetReactionState()
self:RefreshUnitReactionState("target")
end
function Fuyutsui:UpdateTargetRangeBlock()
self:UpdateUnitRangeBlock("target")
function Fuyutsui:RefreshTargetRangeState()
self:RefreshUnitRangeState("target")
end
function Fuyutsui:UpdateTargetDeath()
self:UpdateUnitDeathStatus("target")
function Fuyutsui:RefreshTargetDeathState()
self:RefreshUnitDeathState("target")
end
function Fuyutsui:UpdateTargetHealth()
self:UpdateUnitHealthBlock("target")
function Fuyutsui:RefreshTargetHealthState()
self:RefreshUnitHealthState("target")
end
function Fuyutsui:UpdateTargetFullInfo()
self:UpdateUnitFullInfo("target")
function Fuyutsui:RefreshTargetState()
self:RefreshUnitState("target")
end
-- 焦点包装
function Fuyutsui:UpdateFocusType()
self:UpdateUnitType("focus")
function Fuyutsui:RefreshFocusTypeState()
self:RefreshUnitTypeState("focus")
end
function Fuyutsui:UpdateFocusCanAttack()
self:UpdateUnitCanAttack("focus")
function Fuyutsui:RefreshFocusReactionState()
self:RefreshUnitReactionState("focus")
end
function Fuyutsui:UpdateFocusRangeBlock()
self:UpdateUnitRangeBlock("focus")
function Fuyutsui:RefreshFocusRangeState()
self:RefreshUnitRangeState("focus")
end
function Fuyutsui:UpdateFocusDeath()
self:UpdateUnitDeathStatus("focus")
function Fuyutsui:RefreshFocusDeathState()
self:RefreshUnitDeathState("focus")
end
function Fuyutsui:UpdateFocusHealth()
self:UpdateUnitHealthBlock("focus")
function Fuyutsui:RefreshFocusHealthState()
self:RefreshUnitHealthState("focus")
end
function Fuyutsui:UpdateFocusFullInfo()
self:UpdateUnitFullInfo("focus")
function Fuyutsui:RefreshFocusState()
self:RefreshUnitState("focus")
end
-- 鼠标指向包装
function Fuyutsui:UpdateMouseoverType()
self:UpdateUnitType("mouseover")
function Fuyutsui:RefreshMouseoverTypeState()
self:RefreshUnitTypeState("mouseover")
end
function Fuyutsui:UpdateMouseoverCanAttack()
self:UpdateUnitCanAttack("mouseover")
function Fuyutsui:RefreshMouseoverReactionState()
self:RefreshUnitReactionState("mouseover")
end
function Fuyutsui:UpdateMouseoverRangeBlock()
self:UpdateUnitRangeBlock("mouseover")
function Fuyutsui:RefreshMouseoverRangeState()
self:RefreshUnitRangeState("mouseover")
end
function Fuyutsui:UpdateMouseoverDeath()
self:UpdateUnitDeathStatus("mouseover")
function Fuyutsui:RefreshMouseoverDeathState()
self:RefreshUnitDeathState("mouseover")
end
function Fuyutsui:UpdateMouseoverHealth()
self:UpdateUnitHealthBlock("mouseover")
function Fuyutsui:RefreshMouseoverHealthState()
self:RefreshUnitHealthState("mouseover")
end
function Fuyutsui:UpdateMouseoverFullInfo()
self:UpdateUnitFullInfo("mouseover")
function Fuyutsui:RefreshMouseoverState()
self:RefreshUnitState("mouseover")
end
function Fuyutsui:AddNameplate(unit)
local minRange, maxRange = self:GetUnitRange(unit)
function Fuyutsui:CacheNameplateUnit(unit)
local minRange, maxRange = self:GetUnitRangeBounds(unit)
nameplate[unit] = {
name = GetUnitName(unit, true),
GUID = UnitGUID(unit),
@@ -272,7 +318,7 @@ function Fuyutsui:AddNameplate(unit)
}
end
function Fuyutsui:UpdateNameplateThreat(unit)
function Fuyutsui:RefreshNameplateThreat(unit)
local data = nameplate[unit]
if not data then return end
data.threatStatus = UnitThreatSituation("player", unit)
@@ -290,7 +336,7 @@ local function IsCountedEnemy(self, data, inTestMap, inTestEncounter)
and (data.affectingCombat or inTestMap or inTestEncounter)
end
function Fuyutsui:UpdateThreatEnemyCounts()
function Fuyutsui:RefreshThreatEnemyCounts()
local noThreatCount = 0
local threatCount = 0
local inTestMap = state.mapID and testMap[state.mapID]
@@ -310,12 +356,12 @@ function Fuyutsui:UpdateThreatEnemyCounts()
self:UpdateStateBlock("状态", "敌人数-有仇恨")
end
function Fuyutsui:UpdateEnemyCount()
function Fuyutsui:RefreshEnemyCounts()
local count = 0
local inTestMap = state.mapID and testMap[state.mapID]
local inTestEncounter = state.encounterID and testEncounter[state.encounterID]
for unit, data in pairs(nameplate) do
local minRange, maxRange = self:GetUnitRange(unit)
local minRange, maxRange = self:GetUnitRangeBounds(unit)
data.minRange = minRange
data.maxRange = maxRange
data.affectingCombat = UnitAffectingCombat(unit)
@@ -325,5 +371,5 @@ function Fuyutsui:UpdateEnemyCount()
end
state.enemyCount = count / 255 or 0
self:UpdateStateBlock("状态", "敌人数量")
self:UpdateThreatEnemyCounts()
self:RefreshThreatEnemyCounts()
end

View File

@@ -9,9 +9,9 @@
<AssemblyName>Shigure</AssemblyName>
<RootNamespace>Shigure</RootNamespace>
<Company>Arasaka Corporation</Company>
<Version>1.2.1.13</Version>
<AssemblyVersion>1.2.1.13</AssemblyVersion>
<FileVersion>1.2.1.13</FileVersion>
<Version>1.2.1.14</Version>
<AssemblyVersion>1.2.1.14</AssemblyVersion>
<FileVersion>1.2.1.14</FileVersion>
<ApplicationIcon>Assets\arasaka-icon.ico</ApplicationIcon>
<ApplicationHighDpiMode>PerMonitorV2</ApplicationHighDpiMode>
</PropertyGroup>