forked from LudiusMaximus/CameraOverShoulderFix
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcorrection.lua
More file actions
472 lines (344 loc) · 16.4 KB
/
correction.lua
File metadata and controls
472 lines (344 loc) · 16.4 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
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
local folderName = ...
local cosFix = LibStub("AceAddon-3.0"):GetAddon(folderName)
local _G = _G
local pairs = _G.pairs
local strsplit = _G.strsplit
local tonumber = _G.tonumber
local C_MountJournal_GetMountInfoByID = _G.C_MountJournal.GetMountInfoByID
local C_MountJournal_GetMountIDs = _G.C_MountJournal.GetMountIDs
local GetShapeshiftFormID = _G.GetShapeshiftFormID
local IsMounted = _G.IsMounted
local UnitBuff = _G.UnitBuff
local UnitClass = _G.UnitClass
local UnitInVehicle = _G.UnitInVehicle
local UnitGUID = _G.UnitGUID
local UnitName = _G.UnitName
local UnitOnTaxi = _G.UnitOnTaxi
local UnitRace = _G.UnitRace
local UnitSex = _G.UnitSex
local dynamicCamLoaded = IsAddOnLoaded("DynamicCam")
local DynamicCam = _G.DynamicCam
-- Frame to check what player model is active.
if not cosFix.modelFrame then
cosFix.modelFrame = CreateFrame("PlayerModel")
end
function cosFix:GetShoulderOffset(idType, id)
-- If setFactorFrame is open for id, it overrides everything.
local f = self.setFactorFrame
if f and f:IsShown() and f.idType == idType and f.id == id then
return f.offsetFactor
end
-- Next priority is given to custom factors.
if customOffsetFactors[idType][id] then
return customOffsetFactors[idType][id]["factor"]
end
-- Next priority is given to hardcoded factors.
if self.hardcodedOffsetFactors[idType][id] then
return self.hardcodedOffsetFactors[idType][id]
end
-- Otherwise the id is not yet known.
if idType == "vehicleId" then
local vehicleName = cosFix.vehicleIdToName[id] or UnitName("vehicle")
if not vehicleName then
self:DebugPrintUnknownModel("Vehicle with ID " .. id .. " not yet known. |cffff9900|Hitem:cosFix:vehicleId:".. id .."|h[Click here to define it!]|h|r")
else
self:DebugPrintUnknownModel("Vehicle '" .. vehicleName .. "' (" .. id .. ") not yet known. |cffff9900|Hitem:cosFix:vehicleId:".. id .."|h[Click here to define it!]|h|r")
end
elseif idType == "mountId" then
local creatureName = C_MountJournal_GetMountInfoByID(id)
self:DebugPrintUnknownModel("Mount '" .. creatureName .. "' (" .. id .. ") not yet known. |cffff9900|Hitem:cosFix:mountId:".. id .. "|h[Click here to define it!]|h|r")
elseif idType == "modelId" then
-- Provide id of last spellcast!
if cosFix.lastSpellId and GetTime() - cosFix.lastSpellTime < 0.2 then
local spellName = GetSpellInfo(cosFix.lastSpellId)
self:DebugPrintUnknownModel("Model with ID " .. id .. " (" .. spellName .. " ?) not yet known. |cffff9900|Hitem:cosFix:modelId:" .. id .. ":spellId:" .. cosFix.lastSpellId .. "|h[Click here to define it!]|h|r")
else
self:DebugPrintUnknownModel("Model with ID " .. id .. " not yet known. Perform form change again to get the responsible spell.")
end
end
return 0
end
-- Returns the mount ID of the currently active mount if any.
function cosFix:GetCurrentMount()
-- To skip the iteration through all mounts trying to find the active one,
-- we store the last active mount to be checked first.
-- This variable is also used when C_MountJournal_GetMountInfoByID() cannot
-- identify the active mount even though isMounted() returns true. This
-- happens when porting somewhere while being mounted or when in the Worgen
-- "Running wild" state.
if self.db.char.lastActiveMount then
-- print("Last active mount: " .. self.db.char.lastActiveMount)
local _, _, _, active = C_MountJournal_GetMountInfoByID(self.db.char.lastActiveMount)
if active then
return self.db.char.lastActiveMount
end
end
-- This looks horribly ineffective, but apparently there is no way of getting the
-- currently active mount's id directly...
for k, v in pairs (C_MountJournal_GetMountIDs()) do
local _, _, _, active = C_MountJournal_GetMountInfoByID(v)
if active then
-- Store current mount as last active mount.
self.db.char.lastActiveMount = v
return v
end
end
return nil
end
function cosFix:GetCurrentModelId()
-- print("GetCurrentModelId()")
self.modelFrame:SetUnit("player")
local modelId = self.modelFrame:GetModelFileID()
if modelId == nil then
-- If it exists, use the lastModelId.
if self.db.char.lastModelId ~= nil then
modelId = self.db.char.lastModelId
-- Otherwise, if possible use the standard for the player's race and gender.
else
local _, raceFile = UnitRace("player")
-- In case of unknown player races.
if self.raceAndGenderToModelId[raceFile] ~= nil then
modelId = self.raceAndGenderToModelId[raceFile][UnitSex("player")]
else
self:DebugPrint("RaceFile " .. raceFile .. " not in raceAndGenderToModelId...")
end
end
-- Try again later to find the correct modelId.
self:SetLastModelId()
-- If this is a known normal (no shapeshift) modelId, store it in lastModelId.
elseif self.playerModelOffsetFactors[modelId] ~= nil then
self.db.char.lastModelId = modelId
end
-- print("modelId", modelId)
return modelId
end
-- When the model id cannot be determined, we start a timer to call SetLastModelId() again.
-- Due to several events at the same time, it may happen that several calls happen at the same time.
-- We only want one timer running at a time.
cosFix.lastModelIdTimerId = nil
function cosFix:SetLastModelId()
-- print("SetLastModelId()")
self.modelFrame:SetUnit("player")
local modelId = self.modelFrame:GetModelFileID()
-- print(modelId)
if modelId == nil then
if (self.lastModelIdTimerId == nil) or (self.lastModelIdTimerId and self:TimeLeft(self.lastModelIdTimerId) < 0) then
-- print("Restarting!")
self.lastModelIdTimerId = self:ScheduleTimer("SetLastModelId", 0.01)
-- else
-- print("Timer already running!")
end
else
-- print("SetLastModelId determined", modelId)
self.lastModelIdTimerId = nil
-- Only store and apply known normal modelIds.
if self.playerModelOffsetFactors[modelId] ~= nil then
self.db.char.lastModelId = modelId
self.currentModelFactor = self.playerModelOffsetFactors[modelId]
-- Set the shoulder offset again!
if not dynamicCamLoaded or (not DynamicCam.LibCamera:ZoomInProgress() and not self.easeShoulderOffsetInProgress) then
local correctedShoulderOffset = self:GetCurrentShoulderOffset() * self:GetShoulderOffsetZoomFactor(GetCameraZoom()) * self.currentModelFactor
SetCVar("test_cameraOverShoulder", correctedShoulderOffset)
end
end
end
end
-- Switch lastModelId of a Worgen without having to care about gender.
function cosFix:GetOppositeLastWorgenModelId()
-- No lastModelId.
if self.db.char.lastModelId == nil then
return self.playerModelOffsetFactors[self.raceAndGenderToModelId["Worgen"][UnitSex("player")]]
elseif self.playerModelOffsetFactors[self.db.char.lastModelId] == nil then
self:DebugPrint("SHOULD NEVER HAPPEN!")
return self.playerModelOffsetFactors[self.raceAndGenderToModelId["Worgen"][UnitSex("player")]]
-- Normal case.
elseif self.db.char.lastModelId == self.raceAndGenderToModelId["Human"][UnitSex("player")] then
return self.raceAndGenderToModelId["Worgen"][UnitSex("player")]
elseif self.db.char.lastModelId == self.raceAndGenderToModelId["Worgen"][UnitSex("player")] then
return self.raceAndGenderToModelId["Human"][UnitSex("player")]
-- Valid last lastModelId but neither Worgen nor Human.
else
return self.playerModelOffsetFactors[self.raceAndGenderToModelId["Worgen"][UnitSex("player")]]
end
end
-- WoW interprets the test_cameraOverShoulder variable differently depending on the current player model.
-- If we want the camera to always have the same shoulder offset relative to the player's center,
-- we need to adjust the test_cameraOverShoulder value depending on the current player model.
-- Arguments:
-- enteringVehicleGuid (optional) When CorrectShoulderOffset is called while entering a vehicle
-- we pass the vehicle's GUID to determine the test_cameraOverShoulder adjustment.
-- This is necessary because while entering the vehicle, UnitInVehicle("player") will
-- still return 'false' while the camera is already regarding the vehicle's model.
function cosFix:CorrectShoulderOffset(enteringVehicleGuid)
-- print("CorrectShoulderOffset")
-- self.modelFrame:SetUnit("player")
-- local modelId = self.modelFrame:GetModelFileID()
-- print("Current modelId", modelId)
local returnValue = 1
-- Is the player entering a vehicle or already in a vehicle?
if enteringVehicleGuid or UnitInVehicle("player") then
-- print("You are entering or on a vehicle.")
local vehicleGuid = ""
if enteringVehicleGuid then
vehicleGuid = enteringVehicleGuid
-- print("Entering vehicle.", enteringVehicleGuid)
else
vehicleGuid = UnitGUID("vehicle")
-- print("Already in vehicle.", vehicleGuid)
end
-- TODO: Could also be "Player-...." if you mount a player in druid travel form.
-- TODO: Or what if you mount another player's "double-seater" mount?
local _, _, _, _, _, vehicleId = strsplit("-", vehicleGuid)
vehicleId = tonumber(vehicleId)
returnValue = self:GetShoulderOffset("vehicleId", vehicleId)
-- Is the player mounted?
elseif IsMounted() then
-- print("You are mounted.")
-- No idea why this is necessary when mounted; seems to be a persistent bug on Blizzard's side!
local mountedFactor = 1
if cosFix:GetCurrentShoulderOffset() < 0 then
mountedFactor = mountedFactor / 10
end
-- Is the player really mounted and not on a "taxi"?
if not UnitOnTaxi("player") then
local mountId = self:GetCurrentMount()
-- print(mountId)
-- Right after logging in while on a mount it happens that "IsMounted()" returns true,
-- but C_MountJournal_GetMountInfoByID() is not yet able to determine that the mount is active.
-- Furthermore, when in Worgen "Running wild" state, you get isMounted() without a mount.
if mountId == nil then
-- print("Mounted but no mount")
-- Check for special buffs.
local specialBuffActive = false
for i = 1, 40 do
local name, _, _, _, _, _, _, _, _, spellId = UnitBuff("player", i)
-- print (name, spellId)
if spellId == 87840 then
-- print("Running wild")
-- This is actually only needed for the unlikely case that at any point
-- "Running wild" would be used by a non-Worgen model.
local modelId = self:GetCurrentModelId()
-- If an unknown modelId is returned, assume that we are Worgen (more likely than any other model).
if (modelId == nil) or (self.playerModelOffsetFactors[modelId] == nil) then
returnValue = mountedFactor * self.playerModelOffsetFactors[self.raceAndGenderToModelId["Worgen"][UnitSex("player")]] * 10
else
-- This would also work for "Running wild" with any other model in playerModelOffsetFactors.
returnValue = mountedFactor * self.playerModelOffsetFactors[modelId] * 10
end
specialBuffActive = true
break
elseif spellId == 40212 then
-- print("Dragonmaw Nether Drake")
returnValue = mountedFactor * 2.5
specialBuffActive = true
break
end
end
if not specialBuffActive then
-- Should only happen when logging in mounted with a character after purging of SavedVariables.
if self.db.char.lastActiveMount == nil then
returnValue = mountedFactor * 6
-- Use the last active mount.
else
mountId = self.db.char.lastActiveMount
returnValue = self:GetShoulderOffset("mountId", mountId)
end
end
-- mountId not nil
else
returnValue = self:GetShoulderOffset("mountId", mountId)
end
else
-- print("You are on a taxi!")
-- Flag to remember that you are on a taxi, because the shoulder offset change while
-- leaving a taxi (PLAYER_MOUNT_DISPLAY_CHANGED) needs special treatment...
self.db.char.isOnTaxi = true
-- Works all right for Wind Riders.
-- TODO: This should probably also be done individually for all taxi models in the game.
returnValue = mountedFactor * 2.5
end
-- Is the player shapeshifted?
-- Shapeshift form (id 30) is stealth and should be treated like normal.
elseif (GetShapeshiftFormID(true) ~= nil) and (GetShapeshiftFormID(true) ~= 30) then
-- print("You are shapeshifted.")
local _, englishClass = UnitClass("player")
local formId = GetShapeshiftFormID(true)
if englishClass == "DRUID" then
local _, raceFile = UnitRace("player")
if self.druidFormIdToShoulderOffsetFactor[raceFile] then
local genderCode = UnitSex("player")
if self.druidFormIdToShoulderOffsetFactor[raceFile][genderCode] then
if self.druidFormIdToShoulderOffsetFactor[raceFile][genderCode][formId] then
returnValue = self.druidFormIdToShoulderOffsetFactor[raceFile][genderCode][formId]
else
self:DebugPrint(raceFile .. " " .. ((genderCode == 2) and "male" or "female") .. " druid form factor for form id " .. formId .. " not yet known...")
returnValue = 1
end
else
self:DebugPrint(raceFile .. " " .. ((genderCode == 2) and "male" or "female") .. " druid form factors not yet known...")
returnValue = 1
end
else
self:DebugPrint(raceFile .. " druid form factors not yet known...")
returnValue = 1
end
elseif formId == 16 then
-- print("...Ghostwolf")
returnValue = self.shamanGhostwolfToShoulderOffsetFactor[formId]
else
self:DebugPrint("Shapeshift form '" .. formId .. "' not yet known...")
end
-- Is the player "normal"?
else
-- print("You are normal ...")
local _, englishClass = UnitClass("player")
local _, raceFile = UnitRace("player")
local genderCode = UnitSex("player")
-- print(englishClass, raceFile, genderCode)
-- Check for Demon Hunter Metamorphosis.
local metamorphosis = false
if englishClass == "DEMONHUNTER" then
for i = 1, 40 do
local name, _, _, _, _, _, _, _, _, spellId = UnitBuff("player", i)
-- print(name, spellId)
if spellId == 162264 then
-- print("Demon Hunter Metamorphosis Havoc")
if self.demonhunterFormToShoulderOffsetFactor[raceFile][genderCode]["Havoc"] then
returnValue = self.demonhunterFormToShoulderOffsetFactor[raceFile][genderCode]["Havoc"]
else
self:DebugPrint(raceFile .. " " .. ((genderCode == 2) and "male" or "female") .. " Demonhunter form factor for 'Havoc' not yet known...")
returnValue = 1
end
metamorphosis = true
break
elseif spellId == 187827 then
-- print("Demon Hunter Metamorphosis Vengeance")
if self.demonhunterFormToShoulderOffsetFactor[raceFile][genderCode]["Vengeance"] then
returnValue = self.demonhunterFormToShoulderOffsetFactor[raceFile][genderCode]["Vengeance"]
else
self:DebugPrint(raceFile .. " " .. ((genderCode == 2) and "male" or "female") .. " Demonhunter form factor for 'Vengeance' not yet known...")
returnValue = 1
end
metamorphosis = true
break
end
end
end
if not metamorphosis then
-- print("No Metamorphosis ...")
local modelId = self:GetCurrentModelId()
if modelId == nil then
-- We did all we can in GetCurrentModelId()...
returnValue = -1
-- If we have a hardcoded player model offset, use it!
elseif self.playerModelOffsetFactors[modelId] then
-- print("Hardcoded player id")
returnValue = self.playerModelOffsetFactors[modelId]
else
returnValue = self:GetShoulderOffset("modelId", modelId)
end
end
end
-- print("returnValue", returnValue)
return returnValue
end