-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathCombatMode.lua
More file actions
373 lines (317 loc) · 12 KB
/
CombatMode.lua
File metadata and controls
373 lines (317 loc) · 12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
-- IMPORTS
-- _G is a global variable that holds the global environment.
-- Comprehensive framework for WoW AddOn development to streamline many of the common tasks in developing addons
local AceAddon = _G.LibStub("AceAddon-3.0")
-- Offers profile management, smart defaults and child-databases for modules.
local AceDB = _G.LibStub("AceDB-3.0")
-- Manages localization in addons, allowing for multiple locale to be registered with fallback to the base locale for untranslated strings.
local AceLocale = _G.LibStub("AceLocale-3.0")
local L = LibStub("AceLocale-3.0"):GetLocale("CombatMode") -- When making a locale var, replace the string with "L[VARIABLE_NAME_HERE]".
if not L then
error("[CombatMode] Localization failed!")
return
end
-- Provides an API to register an options table with the config registry, as well as associate it with a slash command.
local AceConfig = _G.LibStub("AceConfig-3.0")
-- Generates AceGUI-3.0 based windows based on option tables.
local AceConfigDialog = _G.LibStub("AceConfigDialog-3.0")
-- Handles access to an options table through the "command line" interface via the ChatFrames.
local AceConfigCmd = _G.LibStub("AceConfigCmd-3.0")
-- Shared handling of media data (fonts, sounds, textures, ...) between addons.
local LibSharedMedia = _G.LibStub("LibSharedMedia-3.0")
-- DEVELOPER NOTE
-- You can access the global CM store in any file by calling _G.GetGlobalStore() on a localized CM.
-- Each additional file has its own object within the CM store. Follow this pattern when making changes.
-- Properties from the main CombatMode.lua file are assigned directly to the CM obj.
-- Ex: You can get CustomCVarValues from Constants.lua by referencing the CM.Constants.CustomCVarValues
-- INSTANTIATING ADDON & CREATING FRAME
local CM = AceAddon:NewAddon("CombatMode", "AceConsole-3.0", "AceEvent-3.0")
local CrosshairFrame = _G.CreateFrame("Frame", "CombatModeCrosshairFrame", _G.UIParent)
local CrosshairTexture = CrosshairFrame:CreateTexture(nil, "OVERLAY")
-- INITIAL STATE VARIABLES
local isCursorLocked = false
local lastStateUpdateTime = 0
local debugMode = true
-- UTILITY FUNCTIONS
function _G.GetGlobalStore()
return AceAddon:GetAddon("CombatMode")
end
function CM.DebugPrint(statement)
if debugMode then
print("|cffff0000Combat Mode:|r " .. statement)
end
end
function CM.LoadReticleTargetCVars()
for name, value in pairs(CM.Constants.CustomCVarValues) do
_G.SetCVar(name, value)
end
CM.DebugPrint("Reticle Target CVars LOADED")
end
function CM.LoadBlizzardDefaultCVars()
for name, value in pairs(CM.Constants.BlizzardCVarValues) do
_G.SetCVar(name, value)
end
CM.DebugPrint("Reticle Target CVars RESET")
end
local function CreateTargetMacros()
local doesClearTargetMacroExist = _G.GetMacroInfo("CM_ClearTarget")
if not doesClearTargetMacroExist then
_G.CreateMacro("CM_ClearTarget", "INV_MISC_QUESTIONMARK", "/stopmacro [noexists]\n/cleartarget", false);
end
local doesClearFocusMacroExist = _G.GetMacroInfo("CM_ClearFocus")
if not doesClearFocusMacroExist then
_G.CreateMacro("CM_ClearFocus", "INV_MISC_QUESTIONMARK", "/clearfocus", false);
end
end
-- CROSSHAIR STATE HANDLING FUNCTIONS
local function HandleCrosshairAppearance(state)
if state == "base" then
CrosshairTexture:SetTexture(CM.Constants.CrosshairTexture)
CrosshairTexture:SetVertexColor(1, 1, 1, .5)
elseif state == "hostile" then
CrosshairTexture:SetTexture(CM.Constants.CrosshairActiveTexture)
CrosshairTexture:SetVertexColor(1, .2, 0.3, 1)
elseif state == "friendly" then
CrosshairTexture:SetTexture(CM.Constants.CrosshairActiveTexture)
CrosshairTexture:SetVertexColor(0, 1, 0.3, .8)
else
print("Invalid state")
end
end
function CM.ShowCrosshair()
CrosshairTexture:Show()
end
function CM.HideCrosshair()
CrosshairTexture:Hide()
end
local function CreateCrosshair()
CrosshairTexture:SetAllPoints(CrosshairFrame)
CrosshairFrame:SetPoint("CENTER", 0, CM.DB.global.crosshairY or 100)
CrosshairFrame:SetSize(CM.DB.global.crosshairSize or 64, CM.DB.global.crosshairSize or 64)
CrosshairFrame:SetAlpha(CM.DB.global.crosshairOpacity or 1.0)
HandleCrosshairAppearance("base")
if CM.DB.global.crosshair then
CM.ShowCrosshair()
else
CM.HideCrosshair()
end
end
function CM.UpdateCrosshair()
if CM.DB.global.crosshairY then
CrosshairFrame:SetPoint("CENTER", 0, CM.DB.global.crosshairY)
end
if CM.DB.global.crosshairSize then
CrosshairFrame:SetSize(CM.DB.global.crosshairSize, CM.DB.global.crosshairSize)
end
if CM.DB.global.crosshairOpacity then
CrosshairFrame:SetAlpha(CM.DB.global.crosshairOpacity)
end
end
local function HandleCrosshairReactionToTarget(target)
local isTargetVisible = _G.UnitIsVisible(target)
local isTargetHostile = _G.UnitReaction("player", target) and _G.UnitReaction("player", target) <= 4
if isTargetVisible then
if isTargetHostile then
HandleCrosshairAppearance("hostile")
else
HandleCrosshairAppearance("friendly")
end
else
HandleCrosshairAppearance("base")
end
end
-- FRAME WATCHING
local function CursorUnlockFrameVisible(frameArr)
local allowFrameWatching = CM.DB.global.frameWatching
if not allowFrameWatching then
return false
end
for _, frameName in pairs(frameArr) do
local curFrame = _G.getglobal(frameName)
if curFrame and curFrame.IsVisible and curFrame:IsVisible() then
-- CM.DebugPrint(frameName .. " is visible, enabling cursor")
return true
end
end
end
local function CursorUnlockFrameGroupVisible(frameNameGroups)
for _, frameNames in pairs(frameNameGroups) do
if CursorUnlockFrameVisible(frameNames) then
return true
end
end
end
local function SuspendingCursorLock()
return CursorUnlockFrameVisible(CM.Constants.FramesToCheck) or CursorUnlockFrameVisible(CM.DB.global.watchlist) or
CursorUnlockFrameGroupVisible(CM.Constants.WildcardFramesToCheck) or _G.SpellIsTargeting()
end
-- FRAME WATCHING FOR SERIALIZED FRAMES (Ex: Opie rings)
local function InitializeWildcardFrameTracking(frameArr)
CM.DebugPrint("Looking for wildcard frames...")
-- Initialise the table by going through ALL available globals once and keeping the ones that match
for _, frameNameToFind in pairs(frameArr) do
CM.Constants.WildcardFramesToCheck[frameNameToFind] = {}
for frameName in pairs(_G) do
if string.match(frameName, frameNameToFind) then
CM.DebugPrint("Matched " .. frameNameToFind .. " to frame " .. frameName)
local frameGroup = CM.Constants.WildcardFramesToCheck[frameNameToFind]
frameGroup[#frameGroup + 1] = frameName
end
end
end
CM.DebugPrint("Wildcard frames initialized")
end
-- OVERRIDE BUTTONS
function CM.SetNewBinding(buttonSettings)
if not buttonSettings.enabled then
return
end
local valueToUse
if buttonSettings.value == "CUSTOMACTION" then
valueToUse = buttonSettings.customAction
elseif buttonSettings.value == "CLEARTARGET" then
valueToUse = "MACRO CM_ClearTarget"
elseif buttonSettings.value == "CLEARFOCUS" then
valueToUse = "MACRO CM_ClearFocus"
else
valueToUse = buttonSettings.value
end
_G.SetMouselookOverrideBinding(buttonSettings.key, valueToUse)
CM.DebugPrint(buttonSettings.key .. "'s override binding is now " .. valueToUse)
end
local function OverrideDefaultButtons()
for _, button in pairs(CM.Constants.ButtonsToOverride) do
CM.SetNewBinding(CM.DB.profile.bindings[button])
end
end
function CM.ResetBindingOverride(buttonSettings)
_G.SetMouselookOverrideBinding(buttonSettings.key, nil)
CM.DebugPrint(buttonSettings.key .. "'s override binding is now cleared")
end
-- Matches the bindable actions values defined in Constants.ActionsToProcess with more readable names for the UI
local function RenameBindableActions()
for _, bindingAction in pairs(CM.Constants.ActionsToProcess) do
local bindingUiName = _G["BINDING_NAME_" .. bindingAction]
CM.Constants.OverrideActions[bindingAction] = bindingUiName or bindingAction
end
end
-- FREE LOOK STATE HANDLING
local function LockFreeLook()
if not _G.IsMouselooking() or not SuspendingCursorLock() then
_G.MouselookStart()
if CM.DB.global.crosshair then
CM.ShowCrosshair()
end
CM.DebugPrint("Free Look Enabled")
end
end
local function UnlockFreeLook()
if _G.IsMouselooking() then
_G.MouselookStop()
if CM.DB.global.crosshair then
CM.HideCrosshair()
end
CM.DebugPrint("Free Look Disabled")
end
end
local function ToggleFreeLook()
if not _G.IsMouselooking() then
LockFreeLook()
elseif _G.IsMouselooking() then
UnlockFreeLook()
end
end
-- Relocking Free Look & setting CVars after reload/portal
local function Rematch()
local isReticleTargetingActive = CM.DB.global.reticleTargeting
if isReticleTargetingActive then
CM.LoadReticleTargetCVars()
end
ToggleFreeLook()
end
-- UpdateState will be fired when changes in game state happen
-- Responsible for unlocking Free Look when opening frames & casting targeting spells
local function UpdateState()
-- Calling this without the delay so we don't add latency to player actions
if _G.SpellIsTargeting() then
UnlockFreeLook()
isCursorLocked = false
return
end
local currentTime = _G.GetTime()
if currentTime - lastStateUpdateTime < .15 then
return
end
lastStateUpdateTime = currentTime
if SuspendingCursorLock() then
UnlockFreeLook()
isCursorLocked = false
elseif not isCursorLocked then
LockFreeLook()
isCursorLocked = true
end
end
-- CREATING /CM CHAT COMMAND
function CM:OpenConfigCMD(input)
ToggleFreeLook()
if not input or input:trim() == "" then
AceConfigDialog:Open("Combat Mode")
else
AceConfigCmd.HandleCommand(self, "mychat", "Combat Mode", input)
end
end
-- INITIALIZING DEFAULT CONFIG
function CM:OnInitialize()
self.DB = AceDB:New("CombatModeDB")
AceConfig:RegisterOptionsTable("Combat Mode", CM.Options.ConfigOptions)
self.OPTIONS = AceConfigDialog:AddToBlizOptions("Combat Mode", "Combat Mode")
self:RegisterChatCommand("cm", "OpenConfigCMD")
self:RegisterChatCommand("combatmode", "OpenConfigCMD")
self.DB = AceDB:New("CombatModeDB", CM.Options.DatabaseDefaults, true)
end
-- LOADING ADDON IN
function CM:OnEnable()
RenameBindableActions()
OverrideDefaultButtons()
InitializeWildcardFrameTracking(CM.Constants.WildcardFramesToMatch)
CreateCrosshair()
CreateTargetMacros()
-- Registering Blizzard Events from Constants.lua
for _, event in pairs(CM.Constants.BLIZZARD_EVENTS) do
self:RegisterEvent(event, _G.CombatMode_OnEvent)
end
end
-- FIRES WHEN SPECIFIC EVENTS HAPPEN IN GAME
function _G.CombatMode_OnEvent(event)
if not SuspendingCursorLock() then
if event == "PLAYER_SOFT_ENEMY_CHANGED" then
HandleCrosshairReactionToTarget("target")
end
if event == "PLAYER_SOFT_INTERACT_CHANGED" then
HandleCrosshairReactionToTarget("softInteract")
end
end
if event == "PLAYER_ENTERING_WORLD" then
Rematch()
print("|cffff0000Combat Mode:|r |cff909090 Type |cff69ccf0/cm|r or |cff69ccf0/combatmode|r for settings |r")
end
end
-- FIRES WHEN GAME STATE CHANGES HAPPEN
function _G.CombatMode_OnUpdate()
UpdateState()
end
-- FIRES WHEN ADDON IS LOADED
function _G.CombatMode_OnLoad()
CM.DebugPrint("ADDON LOADED")
end
-- FUNCTIONS CALLED FROM BINDINGS.XML
function _G.CombatModeToggleKey()
ToggleFreeLook()
end
function _G.CombatModeHoldKey(keystate)
if keystate == "down" then
UnlockFreeLook()
else
LockFreeLook()
end
end