├── .gitignore
├── .pkgmeta
├── Core.lua
├── DefaultSettings.lua
├── DynamicCam-Cata.toc
├── DynamicCam-Classic.toc
├── DynamicCam-Wrath.toc
├── DynamicCam.toc
├── LICENSE
├── Libs
└── LICENSE.md
├── Locales
├── Locales.xml
├── deDE.lua
├── enUS.lua
├── esES.lua
├── esMX.lua
├── frFR.lua
├── itIT.lua
├── koKR.lua
├── ptBR.lua
├── ruRU.lua
├── zhCN.lua
└── zhTW.lua
├── MouseZoom.lua
├── Options.lua
├── Presets.lua
├── README.md
├── Sharing.lua
├── SituationManager.lua
├── UiHideModule.lua
└── embeds.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | Libs/
2 | /release.bat
3 | /.release
4 |
--------------------------------------------------------------------------------
/.pkgmeta:
--------------------------------------------------------------------------------
1 | package-as: DynamicCam
2 |
3 | externals:
4 | Libs/AceAddon-3.0:
5 | url: https://repos.wowace.com/wow/ace3/trunk/AceAddon-3.0
6 | Libs/AceConfig-3.0:
7 | url: https://repos.wowace.com/wow/ace3/trunk/AceConfig-3.0
8 | Libs/AceConsole-3.0:
9 | url: https://repos.wowace.com/wow/ace3/trunk/AceConsole-3.0
10 | Libs/AceDB-3.0:
11 | url: https://repos.wowace.com/wow/ace3/trunk/AceDB-3.0
12 | Libs/AceDBOptions-3.0:
13 | url: https://repos.wowace.com/wow/ace3/trunk/AceDBOptions-3.0
14 | Libs/AceEvent-3.0:
15 | url: https://repos.wowace.com/wow/ace3/trunk/AceEvent-3.0
16 | Libs/AceGUI-3.0:
17 | url: https://repos.wowace.com/wow/ace3/trunk/AceGUI-3.0
18 | Libs/AceHook-3.0:
19 | url: https://repos.wowace.com/wow/ace3/trunk/AceHook-3.0
20 | Libs/AceLocale-3.0:
21 | url: https://repos.wowace.com/wow/ace3/trunk/AceLocale-3.0
22 | Libs/AceTimer-3.0:
23 | url: https://repos.wowace.com/wow/ace3/trunk/AceTimer-3.0
24 | Libs/AceSerializer-3.0:
25 | url: https://repos.wowace.com/wow/ace3/trunk/AceSerializer-3.0
26 | Libs/CallbackHandler-1.0:
27 | url: https://repos.wowace.com/wow/callbackhandler/trunk/CallbackHandler-1.0
28 | Libs/LibStub:
29 | url: https://repos.wowace.com/wow/libstub/trunk
30 | Libs/LibCamera:
31 | url: https://github.com/Mpstark/LibCamera.git
32 | Libs/LibEasing:
33 | url: https://github.com/Mpstark/LibEasing.git
34 | Libs/LibCompress:
35 | url: https://repos.wowace.com/wow/libcompress/trunk
36 |
--------------------------------------------------------------------------------
/DefaultSettings.lua:
--------------------------------------------------------------------------------
1 | local folderName = ...
2 | local DynamicCam = LibStub("AceAddon-3.0"):GetAddon(folderName)
3 | local L = LibStub("AceLocale-3.0"):GetLocale("DynamicCam")
4 |
5 |
6 |
7 | DynamicCam.situationDefaults = {
8 |
9 | name = "",
10 |
11 | enabled = false,
12 |
13 | executeOnInit = "",
14 |
15 | priority = 0,
16 | events = {},
17 |
18 | condition = "return false",
19 |
20 | executeOnEnter = "",
21 | executeOnExit = "",
22 |
23 | delay = 0,
24 |
25 |
26 | viewZoom = {
27 | enabled = false,
28 | viewZoomType = "zoom",
29 |
30 | zoomTransitionTime = 1,
31 | zoomType = "set",
32 | zoomValue = 10,
33 | zoomMin = 5,
34 | zoomMax = 15,
35 | zoomTimeIsMax = false,
36 |
37 | viewNumber = 2,
38 | viewRestore = true,
39 | viewInstant = false,
40 | restoreDefaultViewNumber = 1,
41 | },
42 |
43 | rotation = {
44 | enabled = false,
45 | rotationType = "continuous",
46 |
47 | rotationTime = 1,
48 | rotationSpeed = 10,
49 |
50 | yawDegrees = 0,
51 | pitchDegrees = 0,
52 |
53 | rotateBack = true,
54 | rotateBackTime = 1,
55 | },
56 |
57 | hideUI = {
58 | enabled = false,
59 |
60 | fadeOpacity = 0.6,
61 | fadeOutTime = 1,
62 | fadeInTime = 1,
63 |
64 | emergencyShowEscEnabled = true,
65 |
66 | hideEntireUI = false,
67 | keepFrameRate = false,
68 |
69 | keepAlertFrames = true,
70 | keepTooltip = true,
71 | keepMinimap = false,
72 | keepChatFrame = false,
73 | keepPartyRaidFrame = false,
74 | keepTrackingBar = false,
75 | keepEncounterBar = false,
76 |
77 | keepCustomFrames = false,
78 | customFramesToKeep = {
79 | AuctionHouseFrame = true,
80 | BankFrame = true,
81 | BagnonBankFrame1 = true,
82 | BuffFrame = true,
83 | ClassTrainerFrame = true,
84 | DebuffFrame = true,
85 | GossipFrame = true,
86 | MerchantFrame = true,
87 | PetStableFrame = true,
88 | QuestFrame = true,
89 | StaticPopup1 = true,
90 | WardrobeFrame = true,
91 | },
92 |
93 | },
94 |
95 |
96 | situationSettings = {
97 | cvars = {},
98 | },
99 | }
100 |
101 |
102 |
103 |
104 | DynamicCam.defaults = {
105 | profile = {
106 |
107 | -- Global settings.
108 |
109 | zoomRestoreSetting = "adaptive",
110 | reactiveZoomEnhancedMinZoom = false,
111 | settingsPanelIgnoreParentAlpha = true,
112 |
113 | -- Standard settings (for when no situation is overriding them).
114 | standardSettings = {
115 |
116 | reactiveZoomEnabled = true,
117 | reactiveZoomAddIncrementsAlways = 1,
118 | reactiveZoomAddIncrements = 2.5,
119 | reactiveZoomIncAddDifference = 1.2,
120 | reactiveZoomMaxZoomTime = 0.1,
121 |
122 | shoulderOffsetZoomEnabled = true,
123 | shoulderOffsetZoomLowerBound = 2,
124 | shoulderOffsetZoomUpperBound = 7,
125 |
126 | -- cvars
127 | cvars = {
128 | cameraDistanceMaxZoomFactor = tonumber(GetCVarDefault("cameraDistanceMaxZoomFactor")),
129 | cameraZoomSpeed = tonumber(GetCVarDefault("cameraZoomSpeed")),
130 |
131 | cameraYawMoveSpeed = tonumber(GetCVarDefault("cameraYawMoveSpeed")),
132 | cameraPitchMoveSpeed = tonumber(GetCVarDefault("cameraPitchMoveSpeed")),
133 |
134 | test_cameraOverShoulder = tonumber(GetCVarDefault("test_cameraOverShoulder")),
135 |
136 | test_cameraDynamicPitch = tonumber(GetCVarDefault("test_cameraDynamicPitch")),
137 | test_cameraDynamicPitchBaseFovPad = tonumber(GetCVarDefault("test_cameraDynamicPitchBaseFovPad")),
138 | test_cameraDynamicPitchBaseFovPadFlying = tonumber(GetCVarDefault("test_cameraDynamicPitchBaseFovPadFlying")),
139 | test_cameraDynamicPitchBaseFovPadDownScale = tonumber(GetCVarDefault("test_cameraDynamicPitchBaseFovPadDownScale")),
140 | test_cameraDynamicPitchSmartPivotCutoffDist = tonumber(GetCVarDefault("test_cameraDynamicPitchSmartPivotCutoffDist")),
141 |
142 | test_cameraTargetFocusEnemyEnable = tonumber(GetCVarDefault("test_cameraTargetFocusEnemyEnable")),
143 | test_cameraTargetFocusEnemyStrengthYaw = tonumber(GetCVarDefault("test_cameraTargetFocusEnemyStrengthYaw")),
144 | test_cameraTargetFocusEnemyStrengthPitch = tonumber(GetCVarDefault("test_cameraTargetFocusEnemyStrengthPitch")),
145 | test_cameraTargetFocusInteractEnable = tonumber(GetCVarDefault("test_cameraTargetFocusInteractEnable")),
146 | test_cameraTargetFocusInteractStrengthYaw = tonumber(GetCVarDefault("test_cameraTargetFocusInteractStrengthYaw")),
147 | test_cameraTargetFocusInteractStrengthPitch = tonumber(GetCVarDefault("test_cameraTargetFocusInteractStrengthPitch")),
148 |
149 | test_cameraHeadMovementStrength = tonumber(GetCVarDefault("test_cameraHeadMovementStrength")),
150 | test_cameraHeadMovementStandingStrength = tonumber(GetCVarDefault("test_cameraHeadMovementStandingStrength")),
151 | test_cameraHeadMovementStandingDampRate = tonumber(GetCVarDefault("test_cameraHeadMovementStandingDampRate")),
152 | test_cameraHeadMovementMovingStrength = tonumber(GetCVarDefault("test_cameraHeadMovementMovingStrength")),
153 | test_cameraHeadMovementMovingDampRate = tonumber(GetCVarDefault("test_cameraHeadMovementMovingDampRate")),
154 | test_cameraHeadMovementFirstPersonDampRate = tonumber(GetCVarDefault("test_cameraHeadMovementFirstPersonDampRate")),
155 | test_cameraHeadMovementRangeScale = tonumber(GetCVarDefault("test_cameraHeadMovementRangeScale")),
156 | test_cameraHeadMovementDeadZone = tonumber(GetCVarDefault("test_cameraHeadMovementDeadZone")),
157 | },
158 |
159 | -- Currently not changeable through UI.
160 | reactiveZoomEasingFunc = "OutQuad",
161 | easingZoom = "InOutQuad",
162 | easingYaw = "InOutQuad",
163 | easingPitch = "InOutQuad",
164 |
165 | },
166 |
167 |
168 | situations = {
169 |
170 | ["001"] = {
171 | name = L["City"],
172 | events = {"PLAYER_UPDATE_RESTING"},
173 | priority = 1,
174 | condition = "return IsResting()",
175 | },
176 | ["002"] = {
177 | name = L["City (Indoors)"],
178 | events = {"PLAYER_UPDATE_RESTING", "ZONE_CHANGED_INDOORS", "ZONE_CHANGED", "SPELL_UPDATE_USABLE"},
179 | priority = 11,
180 | condition = "return IsResting() and IsIndoors()",
181 | },
182 | ["004"] = {
183 | name = L["World"],
184 | events = {"PLAYER_UPDATE_RESTING", "ZONE_CHANGED_NEW_AREA"},
185 | priority = 0,
186 | condition = "return not IsResting() and not IsInInstance()",
187 | },
188 | ["005"] = {
189 | name = L["World (Indoors)"],
190 | events = {"PLAYER_UPDATE_RESTING", "ZONE_CHANGED_INDOORS", "ZONE_CHANGED", "ZONE_CHANGED_NEW_AREA", "SPELL_UPDATE_USABLE"},
191 | priority = 10,
192 | condition = "return not IsResting() and not IsInInstance() and IsIndoors()",
193 | },
194 | ["006"] = {
195 | name = L["World (Combat)"],
196 | events = {"PLAYER_REGEN_DISABLED", "PLAYER_REGEN_ENABLED", "ZONE_CHANGED_NEW_AREA"},
197 | priority = 50,
198 | condition = "return not IsInInstance() and UnitAffectingCombat(\"player\")",
199 | },
200 | ["020"] = {
201 | name = L["Dungeon/Scenerio"],
202 | events = {"ZONE_CHANGED_NEW_AREA"},
203 | priority = 2,
204 | condition = [[local isInstance, instanceType = IsInInstance()
205 | return isInstance and (instanceType == "party" or instanceType == "scenario")]],
206 | },
207 | ["021"] = {
208 | name = L["Dungeon/Scenerio (Outdoors)"],
209 | events = {"ZONE_CHANGED_INDOORS", "ZONE_CHANGED", "ZONE_CHANGED_NEW_AREA", "SPELL_UPDATE_USABLE"},
210 | priority = 12,
211 | condition = [[local isInstance, instanceType = IsInInstance()
212 | return isInstance and (instanceType == "party" or instanceType == "scenario") and IsOutdoors()]],
213 | },
214 | ["023"] = {
215 | name = L["Dungeon/Scenerio (Combat, Boss)"],
216 | events = {"PLAYER_REGEN_DISABLED", "PLAYER_REGEN_ENABLED", "ZONE_CHANGED_NEW_AREA", "ENCOUNTER_START", "ENCOUNTER_END", "INSTANCE_ENCOUNTER_ENGAGE_UNIT"},
217 | priority = 302,
218 | condition = [[local isInstance, instanceType = IsInInstance()
219 | return isInstance and (instanceType == "party" or instanceType == "scenario") and UnitAffectingCombat("player") and IsEncounterInProgress()]],
220 | },
221 | ["024"] = {
222 | name = L["Dungeon/Scenerio (Combat, Trash)"],
223 | events = {"PLAYER_REGEN_DISABLED", "PLAYER_REGEN_ENABLED", "ZONE_CHANGED_NEW_AREA", "ENCOUNTER_START", "ENCOUNTER_END", "INSTANCE_ENCOUNTER_ENGAGE_UNIT"},
224 | priority = 202,
225 | condition = [[local isInstance, instanceType = IsInInstance()
226 | return isInstance and (instanceType == "party" or instanceType == "scenario") and UnitAffectingCombat("player") and not IsEncounterInProgress()]],
227 | },
228 | ["030"] = {
229 | name = L["Raid"],
230 | events = {"ZONE_CHANGED_NEW_AREA"},
231 | priority = 3,
232 | condition = [[local isInstance, instanceType = IsInInstance()
233 | return isInstance and instanceType == "raid"]],
234 | },
235 | ["031"] = {
236 | name = L["Raid (Outdoors)"],
237 | events = {"ZONE_CHANGED_INDOORS", "ZONE_CHANGED", "ZONE_CHANGED_NEW_AREA", "SPELL_UPDATE_USABLE"},
238 | priority = 13,
239 | condition = [[local isInstance, instanceType = IsInInstance()
240 | return isInstance and instanceType == "raid" and IsOutdoors()]],
241 | },
242 | ["033"] = {
243 | name = L["Raid (Combat, Boss)"],
244 | events = {"PLAYER_REGEN_DISABLED", "PLAYER_REGEN_ENABLED", "ZONE_CHANGED_NEW_AREA", "ENCOUNTER_START", "ENCOUNTER_END", "INSTANCE_ENCOUNTER_ENGAGE_UNIT"},
245 | priority = 303,
246 | condition = [[local isInstance, instanceType = IsInInstance()
247 | return isInstance and instanceType == "raid" and UnitAffectingCombat("player") and IsEncounterInProgress()]],
248 | },
249 | ["034"] = {
250 | name = L["Raid (Combat, Trash)"],
251 | events = {"PLAYER_REGEN_DISABLED", "PLAYER_REGEN_ENABLED", "ZONE_CHANGED_NEW_AREA", "ENCOUNTER_START", "ENCOUNTER_END", "INSTANCE_ENCOUNTER_ENGAGE_UNIT"},
252 | priority = 203,
253 | condition = [[local isInstance, instanceType = IsInInstance()
254 | return isInstance and instanceType == "raid" and UnitAffectingCombat("player") and not IsEncounterInProgress()]],
255 | },
256 | ["050"] = {
257 | name = L["Arena"],
258 | events = {"ZONE_CHANGED_NEW_AREA"},
259 | priority = 3,
260 | condition = [[local isInstance, instanceType = IsInInstance()
261 | return isInstance and instanceType == "arena"]],
262 | },
263 | ["051"] = {
264 | name = L["Arena (Combat)"],
265 | events = {"PLAYER_REGEN_DISABLED", "PLAYER_REGEN_ENABLED", "ZONE_CHANGED_NEW_AREA"},
266 | priority = 203,
267 | condition = [[local isInstance, instanceType = IsInInstance()
268 | return isInstance and instanceType == "arena" and UnitAffectingCombat("player")]],
269 | },
270 | ["060"] = {
271 | name = L["Battleground"],
272 | events = {"ZONE_CHANGED_NEW_AREA"},
273 | priority = 3,
274 | condition = [[local isInstance, instanceType = IsInInstance()
275 | return isInstance and instanceType == "pvp"]],
276 | },
277 | ["061"] = {
278 | name = L["Battleground (Combat)"],
279 | events = {"PLAYER_REGEN_DISABLED", "PLAYER_REGEN_ENABLED", "ZONE_CHANGED_NEW_AREA"},
280 | priority = 203,
281 | condition = [[local isInstance, instanceType = IsInInstance()
282 | return isInstance and instanceType == "pvp" and UnitAffectingCombat("player")]],
283 | },
284 |
285 |
286 | ["100"] = {
287 | name = L["Mounted (any)"],
288 | events = {"PLAYER_MOUNT_DISPLAY_CHANGED", "UNIT_AURA"},
289 | priority = 100,
290 | condition = "return IsMounted() and not UnitOnTaxi(\"player\")",
291 | },
292 |
293 | ["101"] = {
294 | name = L["Mounted (only flying-mount)"],
295 | events = {"PLAYER_MOUNT_DISPLAY_CHANGED", "UNIT_AURA"},
296 | priority = 101,
297 | condition = "return IsMounted() and not UnitOnTaxi(\"player\") and DynamicCam:CurrentMountCanFly()",
298 | },
299 |
300 | ["102"] = {
301 | name = L["Mounted (only flying-mount + airborne)"],
302 | events = {"PLAYER_MOUNT_DISPLAY_CHANGED", "UNIT_AURA"},
303 | priority = 102,
304 | condition = "return IsMounted() and not UnitOnTaxi(\"player\") and DynamicCam:CurrentMountCanFly() and IsFlying()",
305 | },
306 |
307 | ["103"] = {
308 | name = L["Mounted (only flying-mount + airborne + Skyriding)"],
309 | events = {"PLAYER_MOUNT_DISPLAY_CHANGED", "UNIT_AURA"},
310 | priority = 103,
311 | condition = "return IsMounted() and not UnitOnTaxi(\"player\") and DynamicCam:CurrentMountCanFly() and IsFlying() and DynamicCam:SkyridingOn()",
312 | },
313 |
314 | ["104"] = {
315 | name = L["Mounted (only flying-mount + Skyriding)"],
316 | events = {"PLAYER_MOUNT_DISPLAY_CHANGED", "UNIT_AURA"},
317 | priority = 102,
318 | condition = "return IsMounted() and not UnitOnTaxi(\"player\") and DynamicCam:CurrentMountCanFly() and DynamicCam:SkyridingOn()",
319 | },
320 |
321 | ["105"] = {
322 | name = L["Mounted (only airborne)"],
323 | events = {"PLAYER_MOUNT_DISPLAY_CHANGED", "UNIT_AURA"},
324 | priority = 101,
325 | condition = "return IsMounted() and not UnitOnTaxi(\"player\") and IsFlying()",
326 | },
327 |
328 | ["106"] = {
329 | name = L["Mounted (only airborne + Skyriding)"],
330 | events = {"PLAYER_MOUNT_DISPLAY_CHANGED", "UNIT_AURA"},
331 | priority = 102,
332 | condition = "return IsMounted() and not UnitOnTaxi(\"player\") and IsFlying() and DynamicCam:SkyridingOn()",
333 | },
334 |
335 | ["107"] = {
336 | name = L["Mounted (only Skyriding)"],
337 | events = {"PLAYER_MOUNT_DISPLAY_CHANGED", "UNIT_AURA"},
338 | priority = 101,
339 | condition = "return IsMounted() and not UnitOnTaxi(\"player\") and DynamicCam:SkyridingOn()",
340 | },
341 |
342 | ["115"] = {
343 | name = L["Druid Travel Form"],
344 | events = {"UPDATE_SHAPESHIFT_FORM"},
345 | executeOnInit = [[this.travelFormIds = {
346 | [3] = true, -- Travel
347 | [4] = true, -- Aquatic
348 | [27] = true, -- Swift Flight
349 | [29] = true, -- Flight
350 | }]],
351 | priority = 100,
352 | condition = [[local formId = GetShapeshiftFormID()
353 | if formId and this.travelFormIds[formId] then
354 | return true
355 | else
356 | return false
357 | end]],
358 | },
359 |
360 | ["120"] = {
361 | name = L["Dracthyr Soar"],
362 | events = {"UNIT_AURA"},
363 | priority = 100,
364 | condition = [[if C_UnitAuras.GetPlayerAuraBySpellID(430747) ~= nil then return true end
365 | return false]],
366 | },
367 |
368 | ["130"] = {
369 | name = L["Skyriding Race"],
370 | events = {"UNIT_AURA"},
371 | -- Get all "Race Starting" buff IDs with the copy ID button here:
372 | -- https://www.wowhead.com/spells/uncategorized/name:race+starting
373 | -- (Use the "copy" icon, then select ID. Sorting must be done afterwards.)
374 | executeOnInit = [[-- "Race Starting" buffs.
375 | local raceBuffList = {369893, 370014, 370326, 370329, 370419, 370426, 372239, 373495, 373571, 373578, 373851, 373857, 374088, 374091, 374143, 374144, 374182, 374183, 374244, 374246, 374412, 374414, 374592, 374593, 374825, 375236, 375261, 375262, 375356, 375358, 375477, 375479, 375810, 376062, 376195, 376366, 376805, 376817, 377025, 377026, 377692, 377745, 378415, 378430, 378753, 378775, 379036, 379397, 381978, 382000, 382632, 382652, 382717, 382755, 383473, 383474, 383596, 383597, 386211, 386331, 387548, 387563, 392228, 395088, 396688, 396710, 396712, 396714, 396934, 396943, 396960, 396977, 396984, 396997, 397050, 397129, 397131, 397141, 397143, 397147, 397151, 397155, 397157, 397175, 397179, 397182, 397187, 397189, 398027, 398034, 398049, 398054, 398100, 398107, 398113, 398116, 398120, 398123, 398141, 398213, 398228, 398264, 398309, 398326, 398408, 398428, 403192, 403205, 403502, 403533, 403679, 403729, 403746, 403784, 403795, 403830, 403884, 403898, 403934, 403992, 404002, 404558, 404640, 404644, 406234, 406257, 406294, 406297, 406398, 406400, 406401, 406420, 406421, 406422, 406438, 406439, 406440, 406506, 406507, 406508, 406696, 406697, 406698, 406766, 406767, 406768, 406799, 406800, 406801, 406923, 406924, 406925, 406943, 406944, 406945, 407214, 407215, 407216, 407529, 407530, 407531, 407593, 407594, 407595, 407619, 407620, 407621, 407717, 407718, 407719, 407756, 407757, 407758, 409713, 409738, 409758, 409759, 409760, 409761, 409762, 409763, 409766, 409768, 409774, 409775, 409778, 409780, 409782, 409783, 409786, 409787, 409791, 409792, 409793, 409794, 409796, 409797, 409799, 409800, 409801, 409802, 409803, 409804, 409807, 409808, 409811, 409812, 409814, 409815, 409817, 409818, 409820, 409821, 409855, 409857, 409859, 409860, 409861, 409862, 409863, 409864, 409865, 409866, 409867, 409868, 410748, 410749, 410750, 410751, 410752, 410753, 410754, 410755, 410756, 410757, 410758, 410759, 410853, 410854, 410855, 410856, 410857, 410858, 410859, 410860, 410861, 410862, 410863, 410864, 411311, 411312, 411314, 411315, 411316, 411317, 411318, 411319, 411320, 411322, 411323, 411325, 411326, 411327, 411329, 411330, 411331, 411332, 411333, 411334, 411335, 411336, 411337, 411338, 411339, 411340, 411341, 411342, 411343, 411345, 411346, 411347, 413655, 413690, 413695, 413778, 413779, 413780, 413851, 413852, 413854, 413940, 413941, 413942, 413966, 413967, 413968, 414016, 414017, 414018, 414349, 414350, 414351, 414368, 414372, 414374, 414616, 414617, 414618, 414740, 414741, 414742, 414751, 414755, 414756, 414773, 414774, 414775, 414829, 414830, 414831, 414891, 414892, 414893, 415587, 417042, 417043, 417044, 417226, 417230, 417231, 417604, 417605, 417606, 417758, 417760, 417761, 417869, 417870, 417871, 417948, 417949, 417950, 418026, 418027, 418028, 418142, 418143, 418144, 418287, 418288, 418289, 418461, 418465, 418466, 419432, 419433, 419434, 419679, 419680, 419681, 420157, 420158, 420159, 420742, 420917, 420965, 420975, 420988, 421060, 421437, 421438, 421439, 421451, 421452, 422015, 422017, 422018, 422020, 422021, 422174, 422175, 422176, 422178, 422179, 422400, 422401, 422402, 422403, 422404, 423378, 423380, 423381, 423382, 423383, 423562, 423568, 423577, 423579, 423580, 425090, 425091, 425092, 425333, 425334, 425335, 425449, 425450, 425452, 425597, 425598, 425601, 425740, 425741, 425742, 426038, 426039, 426040, 426109, 426110, 426111, 426347, 426348, 426349, 426583, 426584, 426585, 427231, 427234, 427235, 431833, 431834, 431835, 431898, 431899, 431900, 439233, 439234, 439235, 439236, 439238, 439239, 439241, 439243, 439244, 439245, 439246, 439247, 439248, 439249, 439250, 439251, 439252, 439254, 439257, 439258, 439260, 439261, 439262, 439263, 439265, 439266, 439267, 439268, 439269, 439270, 439271, 439272, 439273, 439274, 439275, 439276, 439277, 439278, 439281, 439282, 439283, 439284, 439286, 439287, 439288, 439289, 439290, 439291, 439292, 439293, 439294, 439295, 439296, 439298, 439300, 439301, 439302, 439303, 439304, 439305, 439307, 439308, 439309, 439310, 439311, 439313, 439316, 439317, 439318, 439319, 439320, 439321}
376 |
377 | -- For faster lookups:
378 | this.raceBuffs = {}
379 | for _, v in pairs(raceBuffList) do
380 | this.raceBuffs[v] = true
381 | end
382 | ]],
383 | priority = 103,
384 | condition = [[-- Check for "Racing" buff first, which is the most common one.
385 | if C_UnitAuras.GetPlayerAuraBySpellID(369968) ~= nil then return true end
386 | for i = 1, 40 do
387 | local aura = C_UnitAuras.GetBuffDataByIndex("player", i)
388 | if aura and aura.spellId and this.raceBuffs[aura.spellId] then
389 | return true
390 | end
391 | end
392 | return false]],
393 | },
394 |
395 | ["160"] = {
396 | name = L["Taxi"],
397 | events = {"PLAYER_CONTROL_LOST", "PLAYER_CONTROL_GAINED"},
398 | priority = 1000,
399 | condition = "return UnitOnTaxi(\"player\")",
400 | },
401 | ["170"] = {
402 | name = L["Vehicle"],
403 | events = {"UNIT_ENTERED_VEHICLE", "UNIT_EXITED_VEHICLE"},
404 | priority = 1000,
405 | condition = "return UnitUsingVehicle(\"player\")",
406 | },
407 |
408 | ["200"] = {
409 | name = L["Hearth/Teleport"],
410 | events = {"UNIT_SPELLCAST_START", "UNIT_SPELLCAST_STOP", "UNIT_SPELLCAST_SUCCEEDED", "UNIT_SPELLCAST_CHANNEL_START", "UNIT_SPELLCAST_CHANNEL_STOP", "UNIT_SPELLCAST_CHANNEL_UPDATE", "UNIT_SPELLCAST_INTERRUPTED"},
411 | executeOnInit = [[local teleportSpellList = {
412 | 556, -- Astral Recall
413 | 3561, -- Teleport: Stormwind
414 | 3562, -- Teleport: Ironforge
415 | 3563, -- Teleport: Undercity
416 | 3565, -- Teleport: Darnassus
417 | 3566, -- Teleport: Thunder Bluff
418 | 3567, -- Teleport: Orgrimmar
419 | 8690, -- Hearthstone
420 | 18960, -- Teleport: Moonglade
421 | 23442, -- Everlook Transporter
422 | 23453, -- Gnomish Transporter
423 | 26373, -- Lunar Festival Invitation
424 | 32271, -- Teleport: Exodar
425 | 32272, -- Teleport: Silvermoon
426 | 33690, -- Teleport: Shattrath
427 | 35715, -- Teleport: Shattrath
428 | 36890, -- Area52 Transporter
429 | 36941, -- Toshley's Station Transporter
430 | 41234, -- Teleport: Black Temple
431 | 49358, -- Teleport: Stonard
432 | 49359, -- Teleport: Theramore
433 | 49844, -- Using Direbrew's Remote
434 | 50977, -- Death Gate
435 | 53140, -- Teleport: Dalaran - Northrend
436 | 54406, -- Teleport: Dalaran
437 | 66238, -- Argent Crusader's Tabard
438 | 67833, -- Wormhole Generator: Northrend
439 | 73324, -- Jaina's Locket
440 | 75136, -- Ethereal Portal
441 | 88342, -- Teleport: Tol Barad
442 | 88344, -- Teleport: Tol Barad
443 | 89157, -- Teleport: Stormwind (Guild Cloaks)
444 | 89158, -- Teleport: Orgrimmar (Guild Cloaks)
445 | 89597, -- Baradin's Wardens Tabard
446 | 89598, -- Hellscream's Reach Tabard
447 | 94719, -- The Innkeeper's Daughter
448 | 120145, -- Ancient Teleport: Dalaran
449 | 126755, -- Wormhole Generator: Pandaria
450 | 132621, -- Teleport: Vale of Eternal Blossoms
451 | 132627, -- Teleport: Vale of Eternal Blossoms
452 | 136508, -- Dark Portal
453 | 140295, -- Kirin Tor Beacon
454 | 147985, -- Curious Bronze Timepiece
455 | 163830, -- Wormhole Centrifuge
456 | 168487, -- Home Away from Home
457 | 168499, -- Home Away from Home
458 | 171253, -- Garrison Hearthstone
459 | 175608, -- Relic of Karabor
460 | 176242, -- Teleport: Warspear
461 | 176248, -- Teleport: Stormshield
462 | 189838, -- Teleport to Shipyard
463 | 192084, -- Jump to Skyhold
464 | 192085, -- Jump to Skyhold
465 | 193669, -- Basic Dimensional Rifting
466 | 193753, -- Dreamwalk
467 | 193759, -- Teleport: Hall of the Guardian
468 | 196079, -- Recall (to the sanctuary of Frostwolf Keep)
469 | 196080, -- Recall (to the sanctuary of Dun Baldar)
470 | 216016, -- Jump to Skyhold
471 | 222695, -- Dalaran Hearthstone
472 | 223352, -- Khadgar's Beacon (Teleport to Dalaran)
473 | 223805, -- Advanced Dimensional Rifting
474 | 224869, -- Teleport: Dalaran - Broken Isles
475 | 225428, -- Town Portal: Shala'nir
476 | 225434, -- Town Portal: Sashj'tar
477 | 225435, -- Town Portal: Kal'delar
478 | 225436, -- Town Portal: Faronaar
479 | 225440, -- Town Portal: Lian'tril
480 | 227334, -- Flight Master's Whistle
481 | 231504, -- [Tome of] Town Portal
482 | 231505, -- [Scroll of] Town Portal
483 | 248906, -- Vindicaar Teleport Beacon
484 | 250796, -- Wormhole Generator: Argus
485 | 262100, -- Recall (to your Great Hall)
486 | 278244, -- Greatfather Winter's Hearthstone
487 | 278559, -- Headless Horseman's Hearthstone
488 | 281403, -- Teleport: Boralus
489 | 281404, -- Teleport: Dazar'alor
490 | 285362, -- Lunar Elder's Hearthstone
491 | 285424, -- Peddlefeet's Lovely Hearthstone
492 | 286031, -- Noble Gardener's Hearthstone
493 | 286331, -- Fire Eater's Hearthstone
494 | 286353, -- Brewfest Reveler's Hearthstone
495 | 291981, -- Ultrasafe Transporter: Mechagon
496 | 292764, -- Returning (BfA Quest)
497 | 293840, -- Teleport: Moonglade (back)
498 | 298068, -- Holographic Digitalization Hearthstone
499 | 299083, -- Wormhole Generator: Kul Tiras
500 | 299084, -- Wormhole Generator: Zandalar
501 | 308742, -- Eternal Traveler's Hearthstone
502 | 311643, -- Hearth to Faol's Rest
503 | 311681, -- Tirisfal Camp Scroll
504 | 311749, -- Hearth to Uther's Tomb
505 | 312372, -- Return to Camp
506 | 324031, -- Wormhole Generator: Shadowlands
507 | 325624, -- Cypher of Relocation
508 | 326064, -- Night Fae Hearthstone
509 | 335671, -- Scroll of Teleport: Theater of Pain
510 | 340200, -- Necrolord Hearthstone
511 | 340767, -- Chromie's Teleportation Scroll
512 | 342122, -- Venthyr Sinstone
513 | 344587, -- Teleport: Oribos
514 | 345393, -- Kyrian Hearthstone
515 | 346167, -- Attendant's Pocket Portal: Bastion
516 | 346168, -- Attendant's Pocket Portal: Oribos
517 | 346170, -- Attendant's Pocket Portal: Ardenweald
518 | 346171, -- Attendant's Pocket Portal: Maldraxxus
519 | 346173, -- Attendant's Pocket Portal: Revendreth
520 | 363799, -- Dominated Hearthstone
521 | 366945, -- Enlightened Hearthstone
522 | 367013, -- Broker Translocation Matrix
523 | 368788, -- Hearth to Brill
524 | 375357, -- Timewalker's Hearthstone
525 | 386379, -- Wyrmhole Generator: Dragon Isles
526 | 391042, -- Ohn'ir Windsage's Hearthstone
527 | 395277, -- Teleport: Valdrakken
528 | 398099, -- Thrall's Hearthstone (Orc Heritage Campaign)
529 | 401802, -- Stone of the Hearth
530 | 410148, -- Lost Dragonscale
531 | 412555, -- Path of the Naaru
532 | 418549, -- Teleporting to the Vindicaar
533 | 420418, -- Deepdweller's Earthen Hearthstone
534 | 422284, -- Hearthstone of the Flame
535 | 426620, -- Spare Hologem (Draenei Heritage Quest)
536 | 438606, -- Draenic Hologem (Hearthstone)
537 | 441154, -- Nostwin's Voucher (Pandaria Remix)
538 | 446540, -- Teleport: Dornogal
539 | 448126, -- Wormhole Generator: Khaz Algar
540 | 449508, -- Nostwin's Return Service (Pandaria Remix)
541 | 450410, -- Dalaran Hearthstone (Dark Heart Quest)
542 | 460271, -- Teleporting to Silithus
543 | 463481, -- Notorious Thread's Hearthstone
544 | 1221356, -- Teleport: Orgrimmar (Guild Cloaks)
545 | 1221357, -- Teleport: Orgrimmar (Guild Cloaks)
546 | 1221359, -- Teleport: Stormwind (Guild Cloaks)
547 | 1221360, -- Teleport: Stormwind (Guild Cloaks)
548 |
549 | }
550 |
551 | -- For faster lookups:
552 | this.teleportSpells = {}
553 | for _, v in pairs(teleportSpellList) do
554 | this.teleportSpells[v] = true
555 | end
556 | ]],
557 | priority = 130,
558 | condition = [[local _, _, _, _, _, _, _, _, spellId = UnitCastingInfo("player")
559 | if this.teleportSpells[spellId] then return true end
560 | return false]],
561 | executeOnEnter = [[local _, _, _, startTime, endTime = UnitCastingInfo("player")
562 | this.transitionTime = (endTime - startTime)/1000
563 | this.rotationTime = this.transitionTime]],
564 | },
565 | ["201"] = {
566 | name = L["Annoying Spells"],
567 | events = {"UNIT_AURA"},
568 | executeOnInit = [[local annoyingSpellList = {
569 | 46924, -- Bladestorm
570 | 51690, -- Killing Spree
571 | 188499, -- Blade Dance
572 | 210152, -- Death Sweep
573 | }
574 |
575 | -- For faster lookups:
576 | this.annoyingSpells = {}
577 | for _, v in pairs(annoyingSpellList) do
578 | this.annoyingSpells[v] = true
579 | end
580 | ]],
581 | priority = 1000,
582 | condition = [[for i = 1, 40 do
583 | local spellId = nil
584 | if UnitBuff then -- Classic
585 | _, _, _, _, _, _, _, _, _, spellId = UnitBuff("player", i)
586 | else -- Retail
587 | local aura = C_UnitAuras.GetBuffDataByIndex("player", i)
588 | if aura then spellId = aura.spellId end
589 | end
590 |
591 | if this.annoyingSpells[spellId] then return true end
592 | end
593 | return false]],
594 | },
595 | ["300"] = {
596 | name = L["NPC Interaction"],
597 | events = {"AUCTION_HOUSE_CLOSED", "AUCTION_HOUSE_SHOW", "BANKFRAME_CLOSED", "BANKFRAME_OPENED", "CLOSE_TABARD_FRAME", "GOSSIP_CLOSED", "GOSSIP_SHOW", "GUILD_REGISTRAR_CLOSED", "GUILD_REGISTRAR_SHOW", "MERCHANT_CLOSED", "MERCHANT_SHOW", "OPEN_TABARD_FRAME", "PET_STABLE_CLOSED", "PET_STABLE_SHOW", "PLAYER_INTERACTION_MANAGER_FRAME_HIDE", "PLAYER_INTERACTION_MANAGER_FRAME_SHOW", "PLAYER_TARGET_CHANGED", "QUEST_COMPLETE", "QUEST_DETAIL", "QUEST_FINISHED", "QUEST_GREETING", "QUEST_PROGRESS", "SHIPMENT_CRAFTER_CLOSED", "SHIPMENT_CRAFTER_OPENED", "TRAINER_CLOSED", "TRAINER_SHOW", "TRANSMOGRIFY_CLOSE", "TRANSMOGRIFY_OPEN"},
598 | executeOnInit = [[this.frames = {"AuctionHouseFrame", "BagnonBankFrame1", "BankFrame", "ClassTrainerFrame", "GarrisonCapacitiveDisplayFrame", "GossipFrame", "GuildRegistrarFrame", "ImmersionFrame", "MerchantFrame", "PetStableFrame", "QuestFrame", "TabardFrame", "WardrobeFrame"}
599 |
600 | this.excludedFrames = {"FlightMapFrame"}
601 |
602 | this.mountVendors = {
603 | ["62821"] = 460, -- Grand Expedition Yak
604 | ["62822"] = 460, -- Grand Expedition Yak
605 | ["227773"] = 2237, -- Grizzly Hills Packmaster
606 | ["227774"] = 2237, -- Grizzly Hills Packmaster
607 | ["231085"] = 2265, -- Trader's Gilded Brutosaur
608 | -- Add more npcId and mountId pairs here.
609 | -- To find them, uncomment print command in condition script.
610 | }
611 | ]],
612 | priority = 110,
613 | condition = [[-- Don't want to apply this to my own mount vendors while mounted.
614 | if IsMounted() then
615 | local npcGUID = UnitGUID("npc")
616 | if npcGUID then
617 | local _, _, _, _, _, npcId = strsplit("-", npcGUID)
618 | -- Uncomment this to find out npcId and mountId pairs.
619 | -- print("NPC Condition: Current npc", npcId, "current mount", DynamicCam:GetCurrentMount())
620 | if this.mountVendors[npcId] and this.mountVendors[npcId] == DynamicCam:GetCurrentMount() then
621 | return false
622 | end
623 | end
624 | end
625 |
626 | local shown = false
627 | for _, v in pairs(this.frames) do
628 | if (_G[v] and _G[v]:IsShown()) then
629 | shown = true
630 | break
631 | end
632 | end
633 |
634 | for _, v in pairs(this.excludedFrames) do
635 | if (_G[v] and _G[v]:IsShown()) then
636 | shown = false
637 | break
638 | end
639 | end
640 |
641 | return shown and UnitExists("npc")]],
642 | },
643 | ["301"] = {
644 | name = L["Mailbox"],
645 | events = {"MAIL_SHOW", "PLAYER_INTERACTION_MANAGER_FRAME_SHOW", "PLAYER_INTERACTION_MANAGER_FRAME_HIDE", "MAIL_CLOSED", "GOSSIP_CLOSED"},
646 | priority = 110,
647 | condition = [[
648 | -- Exclude Trader's Gilded Brutosaur Mailbox.
649 | if IsMounted() then
650 | local npcGUID = UnitGUID("npc")
651 | if npcGUID then
652 | local _, _, _, _, _, npcId = strsplit("-", npcGUID)
653 | -- print("Mailbox Condition: Current npc", npcId, "current mount", DynamicCam:GetCurrentMount())
654 | if npcId == "231086" and DynamicCam:GetCurrentMount() == 2265 then
655 | return false
656 | end
657 | end
658 | end
659 |
660 | return MailFrame and MailFrame:IsShown()
661 | ]],
662 | },
663 | ["302"] = {
664 | name = L["Fishing"],
665 | events = {"UNIT_SPELLCAST_START", "UNIT_SPELLCAST_STOP", "UNIT_SPELLCAST_SUCCEEDED", "UNIT_SPELLCAST_CHANNEL_START", "UNIT_SPELLCAST_CHANNEL_STOP", "UNIT_SPELLCAST_CHANNEL_UPDATE", "UNIT_SPELLCAST_INTERRUPTED"},
666 | priority = 20,
667 | condition = [[if GetSpellInfo then -- Classic
668 | return UnitChannelInfo("player") == GetSpellInfo(7620)
669 | else -- Retail
670 | return UnitChannelInfo("player") == C_Spell.GetSpellName(7620)
671 | end]],
672 | delay = 1,
673 | },
674 | ["320"] = {
675 | name = L["Gathering"],
676 | events = {"UNIT_SPELLCAST_START", "UNIT_SPELLCAST_STOP", "UNIT_SPELLCAST_SUCCEEDED", "UNIT_SPELLCAST_CHANNEL_START", "UNIT_SPELLCAST_CHANNEL_STOP", "UNIT_SPELLCAST_CHANNEL_UPDATE", "UNIT_SPELLCAST_INTERRUPTED"},
677 | executeOnInit = [[this.spells = {
678 | -- https://www.wowhead.com/spells/professions/mining/name:mining
679 | 2575, 2576, 2656, 3564, 10248, 29354, 50310, 74517, 102161, 158754, 195122, 265837, 265839, 265841, 265843, 265845, 265847, 265849, 265851, 265853, 309835, 366260, 423341,
680 | -- https://www.wowhead.com/spells/professions/skinning/name:skinning
681 | 8613, 8617, 8618, 10768, 32678, 50305, 74522, 102216, 158756, 194174, 195125, 205243, 265855, 265857, 265859, 265861, 265863, 265865, 265867, 265869, 265871, 308569, 366259, 392440, 392445, 423342,
682 | -- https://www.wowhead.com/spells/professions/herbalism/name:gathering
683 | 2366, 2368, 3570, 11993, 28695, 50300, 74519, 110413, 158745, 195114, 265819, 265821, 265823, 265825, 265827, 265829, 265831, 265834, 265835, 309780, 366252, 441327,
684 | }]],
685 | priority = 120,
686 | condition = [[local name, _, _, _, _, _, _, _, spellId = UnitCastingInfo("player")
687 | -- Uncomment this to find out more spell IDs.
688 | -- print(name, spellId)
689 | for _, v in pairs(this.spells) do
690 | if v == spellId then return true end
691 | end
692 | return false]]
693 | },
694 | ["303"] = {
695 | name = L["AFK"],
696 | events = {"PLAYER_FLAGS_CHANGED"},
697 | priority = 120,
698 | condition = "return UnitIsAFK(\"player\")",
699 | },
700 | ["310"] = {
701 | name = L["Pet Battle"],
702 | events = {"PET_BATTLE_OPENING_START", "PET_BATTLE_CLOSE"},
703 | priority = 130,
704 | condition = "return C_PetBattles.IsInBattle()",
705 | },
706 | },
707 |
708 | },
709 | }
710 |
711 |
712 | -- Special modifications for classic.
713 | if WOW_PROJECT_ID ~= WOW_PROJECT_MAINLINE then
714 |
715 | -- No pet battles before mists.
716 | DynamicCam.defaults.profile.situations["310"] = nil
717 |
718 | DynamicCam.defaults.profile.situations["103"] = nil -- Mounted (only flying-mount + airborne + Skyriding)
719 | DynamicCam.defaults.profile.situations["104"] = nil -- Mounted (only flying-mount + Skyriding)
720 | DynamicCam.defaults.profile.situations["106"] = nil -- Mounted (only airborne + Skyriding)
721 | DynamicCam.defaults.profile.situations["107"] = nil -- Mounted (only Skyriding)
722 |
723 | DynamicCam.defaults.profile.situations["120"] = nil -- Dracthyr Soar
724 | DynamicCam.defaults.profile.situations["130"] = nil -- Dragon Racing
725 |
726 |
727 |
728 | if WOW_PROJECT_ID == WOW_PROJECT_CLASSIC then
729 |
730 | -- Cannot have SHIPMENT_CRAFTER_CLOSED, SHIPMENT_CRAFTER_OPENED, TRANSMOGRIFY_CLOSE, TRANSMOGRIFY_OPEN.
731 | -- In classic also not PLAYER_INTERACTION_MANAGER_FRAME_HIDE and PLAYER_INTERACTION_MANAGER_FRAME_SHOW.
732 | DynamicCam.defaults.profile.situations["300"].events = {"AUCTION_HOUSE_CLOSED", "AUCTION_HOUSE_SHOW", "BANKFRAME_CLOSED", "BANKFRAME_OPENED", "CLOSE_TABARD_FRAME", "GOSSIP_CLOSED", "GOSSIP_SHOW", "GUILD_REGISTRAR_CLOSED", "GUILD_REGISTRAR_SHOW", "MERCHANT_CLOSED", "MERCHANT_SHOW", "OPEN_TABARD_FRAME", "PET_STABLE_CLOSED", "PET_STABLE_SHOW", "PLAYER_TARGET_CHANGED", "QUEST_COMPLETE", "QUEST_DETAIL", "QUEST_FINISHED", "QUEST_GREETING", "QUEST_PROGRESS", "TRAINER_CLOSED", "TRAINER_SHOW", "TAXIMAP_OPENED", "TAXIMAP_CLOSED"}
733 |
734 | DynamicCam.defaults.profile.situations["301"].events = {"MAIL_SHOW", "MAIL_CLOSED", "GOSSIP_CLOSED"}
735 |
736 |
737 | -- No flying in classic.
738 | DynamicCam.defaults.profile.situations["101"] = nil
739 | DynamicCam.defaults.profile.situations["102"] = nil
740 | DynamicCam.defaults.profile.situations["105"] = nil
741 |
742 |
743 | -- No vehicles before wrath.
744 | DynamicCam.defaults.profile.situations["170"] = nil
745 |
746 |
747 | -- Currently Wrath classic.
748 | else
749 |
750 | -- Cannot have "SHIPMENT_CRAFTER_CLOSED", "SHIPMENT_CRAFTER_OPENED", "TRANSMOGRIFY_CLOSE", "TRANSMOGRIFY_OPEN
751 | DynamicCam.defaults.profile.situations["300"].events = {"AUCTION_HOUSE_CLOSED", "AUCTION_HOUSE_SHOW", "BANKFRAME_CLOSED", "BANKFRAME_OPENED", "CLOSE_TABARD_FRAME", "GOSSIP_CLOSED", "GOSSIP_SHOW", "GUILD_REGISTRAR_CLOSED", "GUILD_REGISTRAR_SHOW", "MERCHANT_CLOSED", "MERCHANT_SHOW", "OPEN_TABARD_FRAME", "PET_STABLE_CLOSED", "PET_STABLE_SHOW", "PLAYER_INTERACTION_MANAGER_FRAME_HIDE", "PLAYER_INTERACTION_MANAGER_FRAME_SHOW", "PLAYER_TARGET_CHANGED", "QUEST_COMPLETE", "QUEST_DETAIL", "QUEST_FINISHED", "QUEST_GREETING", "QUEST_PROGRESS", "TRAINER_CLOSED", "TRAINER_SHOW"}
752 |
753 |
754 | -- No way to filter for flying mounts in Wrath classic.
755 | DynamicCam.defaults.profile.situations["101"] = nil
756 | DynamicCam.defaults.profile.situations["102"] = nil
757 |
758 | end
759 |
760 | end
761 |
762 |
763 |
764 |
765 | -- Copy the defaults into each situation.
766 | for _, situation in pairs(DynamicCam.defaults.profile.situations) do
767 | for k, v in pairs(DynamicCam.situationDefaults) do
768 | -- But only if the situation does not have a custom setting.
769 | if not situation[k] then
770 | situation[k] = v
771 | end
772 | end
773 | end
774 |
775 |
776 |
777 |
778 | -- With DC 2.0, some default values changed. As AceDB does not store default values,
779 | -- non-existent entries may have to be set to the old default when modernizing a profile.
780 | DynamicCam.oldDefaults = {
781 |
782 | shoulderOffsetZoom = {
783 | enabled = true,
784 | lowerBound = 2,
785 | upperBound = 8,
786 | },
787 |
788 | reactiveZoom = {
789 | enabled = false,
790 | addIncrementsAlways = 1,
791 | addIncrements = 3,
792 | maxZoomTime = .25,
793 | incAddDifference = 4,
794 | },
795 |
796 | defaultCvars = {
797 | cameraDistanceMaxZoomFactor = 2.6,
798 | cameraZoomSpeed = 20,
799 |
800 | test_cameraOverShoulder = 0,
801 |
802 | test_cameraDynamicPitch = 0,
803 | test_cameraDynamicPitchBaseFovPad = .35,
804 | test_cameraDynamicPitchBaseFovPadFlying = .75,
805 | test_cameraDynamicPitchBaseFovPadDownScale = .25,
806 | test_cameraDynamicPitchSmartPivotCutoffDist = 10,
807 |
808 | test_cameraTargetFocusEnemyEnable = 0,
809 | test_cameraTargetFocusEnemyStrengthYaw = 0.5,
810 | test_cameraTargetFocusEnemyStrengthPitch = 0.4,
811 | test_cameraTargetFocusInteractEnable = 0,
812 | test_cameraTargetFocusInteractStrengthYaw = 1.0,
813 | test_cameraTargetFocusInteractStrengthPitch = 0.75,
814 |
815 | test_cameraHeadMovementStrength = 0,
816 | test_cameraHeadMovementStandingStrength = 0.3,
817 | test_cameraHeadMovementStandingDampRate = 10,
818 | test_cameraHeadMovementMovingStrength = 0.5,
819 | test_cameraHeadMovementMovingDampRate = 10,
820 | test_cameraHeadMovementFirstPersonDampRate = 20,
821 | test_cameraHeadMovementRangeScale = 5,
822 | test_cameraHeadMovementDeadZone = 0.015,
823 | },
824 |
825 | situations = {
826 |
827 | enabled = true,
828 |
829 | cameraActions = {
830 | transitionTime = 0.75,
831 | timeIsMax = true,
832 |
833 | rotate = false,
834 | rotateSetting = "continuous",
835 | rotateSpeed = 20,
836 | yawDegrees = 0,
837 | pitchDegrees = 0,
838 | rotateBack = false,
839 |
840 | zoomSetting = "off",
841 | zoomValue = 10,
842 | zoomMin = 5,
843 | zoomMax = 15,
844 | },
845 | view = {
846 | enabled = false,
847 | viewNumber = 5,
848 | restoreView = false,
849 | instant = false,
850 | },
851 | extras = {
852 | hideUI = false,
853 | hideUIFadeOpacity = 0,
854 | actuallyHideUI = true,
855 | keepMinimap = false,
856 | },
857 | },
858 |
859 | -- AFK was the only situation in DC pre-2.0 that had other defaults.
860 | afkSituation = {
861 | cameraActions = {
862 | transitionTime = 1,
863 | rotateSpeed = 3,
864 | zoomValue = 9,
865 | rotate = true,
866 | zoomSetting = "out",
867 | },
868 | extras = {
869 | hideUI = true,
870 | },
871 |
872 | }
873 |
874 | }
875 |
876 |
--------------------------------------------------------------------------------
/DynamicCam-Cata.toc:
--------------------------------------------------------------------------------
1 | ## Interface: 40402
2 | ## Version: @project-version@
3 | ## Title: DynamicCam
4 | ## Author: mpstark, LudiusMaximus
5 | ## Notes: A more dynamic camera.
6 | ## Notes-zhCN: 智能动态相机镜头。
7 |
8 | ## OptionalDeps: Ace3, LibCamera, LibEasing, LibCompress, Bartender4, GW2_UI, Immersion, Immersion_ExtraFade
9 | ## SavedVariables: DynamicCamDB, minZoomValues
10 |
11 | ## X-Curse-Project-ID: 101120
12 | ## X-WoWI-ID: 25570
13 | ## X-Wago-ID: b6XVoOGp
14 |
15 | ## X-Donate: PayPal:ludiusmaximus@gmail.com
16 | ## X-License: The MIT License (MIT)
17 |
18 |
19 | embeds.xml
20 |
21 |
22 | UiHideModule.lua
23 |
24 |
25 | Core.lua
26 |
27 | MouseZoom.lua
28 | SituationManager.lua
29 |
30 | DefaultSettings.lua
31 |
32 | Sharing.lua
33 | Presets.lua
34 | Options.lua
35 |
--------------------------------------------------------------------------------
/DynamicCam-Classic.toc:
--------------------------------------------------------------------------------
1 | ## Interface: 11507
2 | ## Version: @project-version@
3 | ## Title: DynamicCam
4 | ## Author: mpstark, LudiusMaximus
5 | ## Notes: A more dynamic camera.
6 | ## Notes-zhCN: 智能动态相机镜头。
7 |
8 | ## OptionalDeps: Ace3, LibCamera, LibEasing, LibCompress, Bartender4, GW2_UI, Immersion, Immersion_ExtraFade
9 | ## SavedVariables: DynamicCamDB, minZoomValues
10 |
11 | ## X-Curse-Project-ID: 101120
12 | ## X-WoWI-ID: 25570
13 | ## X-Wago-ID: b6XVoOGp
14 |
15 | ## X-Donate: PayPal:ludiusmaximus@gmail.com
16 | ## X-License: The MIT License (MIT)
17 |
18 |
19 | embeds.xml
20 |
21 |
22 | UiHideModule.lua
23 |
24 |
25 | Core.lua
26 |
27 | MouseZoom.lua
28 | SituationManager.lua
29 |
30 | DefaultSettings.lua
31 |
32 | Sharing.lua
33 | Presets.lua
34 | Options.lua
35 |
--------------------------------------------------------------------------------
/DynamicCam-Wrath.toc:
--------------------------------------------------------------------------------
1 | ## Interface: 30403
2 | ## Version: @project-version@
3 | ## Title: DynamicCam
4 | ## Author: mpstark, LudiusMaximus
5 | ## Notes: A more dynamic camera.
6 | ## Notes-zhCN: 智能动态相机镜头。
7 |
8 | ## OptionalDeps: Ace3, LibCamera, LibEasing, LibCompress, Bartender4, GW2_UI, Immersion, Immersion_ExtraFade
9 | ## SavedVariables: DynamicCamDB, minZoomValues
10 |
11 | ## X-Curse-Project-ID: 101120
12 | ## X-WoWI-ID: 25570
13 | ## X-Wago-ID: b6XVoOGp
14 |
15 | ## X-Donate: PayPal:ludiusmaximus@gmail.com
16 | ## X-License: The MIT License (MIT)
17 |
18 |
19 | embeds.xml
20 |
21 |
22 | UiHideModule.lua
23 |
24 |
25 | Core.lua
26 |
27 | MouseZoom.lua
28 | SituationManager.lua
29 |
30 | DefaultSettings.lua
31 |
32 | Sharing.lua
33 | Presets.lua
34 | Options.lua
35 |
--------------------------------------------------------------------------------
/DynamicCam.toc:
--------------------------------------------------------------------------------
1 | ## Interface: 110105
2 | ## Version: @project-version@
3 | ## Title: DynamicCam
4 | ## Author: mpstark, LudiusMaximus
5 | ## Notes: A more dynamic camera.
6 | ## Notes-zhCN: 智能动态相机镜头。
7 |
8 | ## OptionalDeps: Ace3, LibCamera, LibEasing, LibCompress, LibHideUI, Bartender4, GW2_UI, Immersion, Immersion_ExtraFade
9 | ## SavedVariables: DynamicCamDB, minZoomValues
10 |
11 | ## X-Curse-Project-ID: 101120
12 | ## X-WoWI-ID: 25570
13 | ## X-Wago-ID: b6XVoOGp
14 |
15 | ## X-Donate: PayPal:ludiusmaximus@gmail.com
16 | ## X-License: The MIT License (MIT)
17 |
18 |
19 | embeds.xml
20 |
21 |
22 | UiHideModule.lua
23 |
24 |
25 | Core.lua
26 |
27 | MouseZoom.lua
28 | SituationManager.lua
29 |
30 | DefaultSettings.lua
31 |
32 | Sharing.lua
33 | Presets.lua
34 | Options.lua
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017-2020 Michael P. Starkweather (mpstark), 2020-2025 LudiusMaximus
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Libs/LICENSE.md:
--------------------------------------------------------------------------------
1 | All library code contained in this directory ("Libs") is owned and licensed by their respective owners.
2 |
--------------------------------------------------------------------------------
/Locales/Locales.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Locales/zhCN.lua:
--------------------------------------------------------------------------------
1 | local L = LibStub("AceLocale-3.0"):NewLocale("DynamicCam", "zhCN")
2 | if not L then return end
3 |
4 | -- Options
5 | L["Reset"] = "重置"
6 | L["Reset to global default:"] = "重置为全局默认值:"
7 | L["(To restore the settings of a specific profile, restore the profile in the \"Profiles\" tab.)"] = "(要恢复为特定配置文件的设置,请在“配置文件”标签页中选择该配置文件后操作。)"
8 | L["Currently overridden by the active situation \""] = "当前设置为情境: \""
9 | L["Override Standard Settings"] = "覆盖标准情境"
10 | L[""] = "勾选这个复选框,允许你在激活当前情境时,覆盖标准情境。取消勾选将删除此类型的情境设置。"
11 | L["Custom:"] = "自定义:"
12 | L["(modified)"] = "(已修改)"
13 | L["Priority:"] = "优先级:"
14 | L["Standard Settings"] = "标准设置"
15 | L["Situation Settings"] = "情境设置"
16 | L[""] = "当没有任何情境处于激活状态,或者激活的情境没有设置覆盖标准设置的情境设置时,将应用这些标准设置。"
17 | L[""] = "绿色的类型表示目前被激活的情境覆盖。因此,在覆盖情境激活时,绿色类型的标准设置不会生效。"
18 | L["These Situation Settings can override the Standard Settings when the respective situation is active."] = "当相应的情境激活时,这些情境设置将覆盖标准设置。"
19 | L["Mouse Zoom"] = "鼠标缩放"
20 | L["Maximum Camera Distance"] = "最大镜头距离"
21 | L["How many yards the camera can zoom away from your character."] = "镜头镜头可以从你的角色拉远多少码的距离。"
22 | L["Camera Zoom Speed"] = "镜头缩放速度"
23 | L["How fast the camera can zoom."] = "镜头镜头缩放的速度。"
24 | L["Zoom Increments"] = "镜头缩放增量"
25 | L["How many yards the camera should travel for each \"tick\" of the mouse wheel."] = "每次鼠标滚轮镜头应该移动多少码。"
26 | L["Use Reactive Zoom"] = "使用响应缩放"
27 | L["Quick-Zoom Additional Increments"] = "快速缩放额外增量"
28 | L["How many yards per mouse wheel tick should be added when quick-zooming."] = "当快速缩放时,每次鼠标滚轮滚动应该增加多少码。"
29 | L["Quick-Zoom Enter Threshold"] = "快速缩放阈值"
30 | L["How many yards the \"Reactive Zoom Target\" and the \"Actual Zoom Value\" have to be apart to enter quick-zooming."] = "\"响应缩放目标\"与\"实际缩放值\"之间至少需要多少码的距离,才能触发快速缩放功能。"
31 | L["Maximum Zoom Time"] = "最大缩放时间"
32 | L["The maximum time the camera should take to make \"Actual Zoom Value\" equal to \"Reactive Zoom Target\"."] = "镜头会在这个时间内将\"实际缩放值\"调整到\"响应缩放目标\"。"
33 | L["Help"] = "帮助"
34 | L["Toggle Visual Aid"] = "视觉辅助开关"
35 | L[""] = "使用 DynamicCam 的响应缩放功能,鼠标滚轮控制\"响应缩放目标\"。每当\"响应缩放目标\"与\"实际缩放值\"不同时,DynamicCam 会改变\"实际缩放值\",直到他再次与\"响应缩放目标\"相同。\n\n这种缩放变化的速度取决于\"镜头缩放速度\"和 \"最大缩放时间\"。如果\"最大缩放时间\"设置的比较短,无论\"镜头缩放速度\"如何设置,缩放总会很快执行。要实现舒缓的缩放变化,你必须将\"最大缩放时间\"设置得更长,同时把\"镜头缩放速度\"设置为较低的值。\n\n为了实现随着鼠标滚轮快速滚动更快地缩放镜头,请使用\"快速缩放功能\":如果\"响应缩放目标\"与\"实际缩放值\"的偏差超过了\"快速缩放阈值\",每次鼠标滚轮的滚动都会增加\"快速缩放额外增量\"。\n\n为了感受这些功能是如何工作的,你可以在寻找合适设置的同时,开启视觉辅助。你也可以通过左键拖弋操作来自动移动这个图表。右键点击可以关闭它。"
36 | L["Enhanced minimal zoom-in"] = "强化最小视角"
37 | L[""] = "响应缩放允许你把镜头放大到比最近还近。你可以通过在第一人称视角时再次滚动鼠标实现这一点。\n\n启用\"强化最小视角\"后,我们会强制镜头在放大时也停留在这个视角上,而不是立即切换回第一人称视角。你也可以把此理解为\"狙击模式\"。\n\n|cFFFF0000启用\"强化最小视角\"可能会在CPU受限的情境下导致帧率下降15%。|r"
38 | L["/reload of the UI required!"] = "需要使用 /reload 重载界面!"
39 | L["Mouse Look"] = "鼠标视角"
40 | L["Horizontal Speed"] = "水平速度"
41 | L["How much the camera yaws horizontally when in mouse look mode."] = "在鼠标视角模式下,镜头的水平移动速度是多少。"
42 | L["Vertical Speed"] = "垂直速度"
43 | L["How much the camera pitches vertically when in mouse look mode."] = "鼠标视角模式下,镜头的垂直移动速度是多少。"
44 | L[""] = "当你在\"鼠标视角\"模式下移动鼠标时,镜头移动的幅度。\n\n在《魔兽世界》的默认界面设置中,\"鼠标视角移动速度\"滑块同时控制水平和垂直速度,并且自动将水平速度设置为垂直速度的2倍。DynamicCam 覆盖了这一设置,允许你进行更加个性化的设置。"
45 | L["Horizontal Offset"] = "水平偏移"
46 | L["Camera Over Shoulder Offset"] = "越肩视角偏移"
47 | L["Positions the camera left or right from your character."] = "调整镜头在角色左侧或者右侧的位置。"
48 | L[""] = "要使这个设置生效,DynamicCam 会自动临时禁用游戏中的晕动症设置。因此,如果你需要使用晕动症设置,请不要使用水平偏移。\n\n当你选中自己的角色时,《魔兽世界》会自动切换到偏移量为0。我们无法对此进行更改。我们也无法解决镜头和墙壁发生碰撞时可能出现的偏移抖动问题。一个可能的解决方法是在室内时使用很小或不使用偏移。\n\n此外,《魔兽世界》会根据玩家模型或坐骑不同,奇怪地应用不同的偏移量。如果你希望有一个恒定的偏移量,Ludius(插件开发者)正在开发另一个插件 CameraOverShoulder 来解决这个问题。"
49 | L["Adjust shoulder offset according to zoom level"] = "根据缩放调整越肩偏移"
50 | L["Enable"] = "启用"
51 | L["Reset to global defaults:"] = "重置为全局默认值:"
52 | L["and"] = "和"
53 | L["(To restore the settings of a specific profile, restore the profile in the \"Profiles\" tab.)"] = "(要恢复特定配置文件的设置,请在“配置文件”标签中恢复该配置文件。)"
54 | L["No offset when below this zoom level:"] = "当缩放级别低于此值时无偏移:"
55 | L["When the camera is closer than this zoom level, the offset has reached zero."] = "当镜头比此缩放级别更近时,偏移量已达到零。"
56 | L["Real offset when above this zoom level:"] = "当缩放级别高于此值时的真实偏移:"
57 | L["When the camera is further away than this zoom level, the offset has reached its set value."] = "当镜头比此缩放级别更远时,偏移量已达到其设定值。"
58 | L[""] = "在缩放时使肩部偏移量逐渐过渡到零。两个滑块定义了此过渡发生的缩放级别范围。此设置是全局的,不特定于情境。"
59 | L["Vertical Pitch"] = "垂直俯仰"
60 | L["Pitch (on ground)"] = "俯仰(在地面上)"
61 | L["Pitch (flying)"] = "俯仰(飞行中)"
62 | L["Down Scale"] = "向下缩放"
63 | L["Smart Pivot Cutoff Distance"] = "智能转动停止距离"
64 | L[""] = "如果镜头向上俯仰(“俯仰”值较低),“向下缩放”设置决定了在从上方看角色时这种效果的影响程度。将“向下缩放”设置为0可以抵消从上方看时向上俯仰的效果。相反,当你不是从上方看,或者如果镜头向下俯仰(“俯仰”值较大)时,“向下缩放”设置几乎没有效果。\n\n因此,你应该首先找到从背后看你角色时喜欢的“俯仰”设置。之后,如果你选择了向上俯仰,从上方看时找到你喜欢“向下缩放”设置。\n\n当镜头与地面碰撞时,它通常会在镜头到地面碰撞点进行向上俯仰。另一种选择是镜头在执行这种俯仰时更靠近角色的脚。“智能转动截止距离”设置决定了镜头必须在多远的距离内才能执行后者。将其设置为0则从不移动镜头(WoW的默认设置),而将其设置为最大缩放距离39则总是移动镜头。\n\n"
65 | L["Target Focus"] = "目标焦点"
66 | L["Enemy Target"] = "敌方目标"
67 | L["Horizontal Strength"] = "水平强度"
68 | L["Vertical Strength"] = "垂直强度"
69 | L["Interaction Target (NPCs)"] = "交互目标(NPC)"
70 | L[""] = "如果启用,镜头会自动尝试将目标拉近屏幕中心。强度决定了这种效果的强度。\n\n如果“敌方目标焦点”和“交互目标焦点”都启用,后者似乎有一个奇怪的错误:当首次与NPC交互时,镜头会像预期的那样平滑移动到新角度。但是当你退出交互时,它会立即跳转到之前的角度。然后当你再次开始交互时,它再次跳转到新角度。这在与新NPC交谈时是可重复的:只有第一次过渡是平滑的,所有后续的都是立即的。\n如果你想要同时使用“敌方目标焦点”和“交互目标焦点”,一个变通方法是只在需要它且不太可能发生NPC交互的DynamicCam情境下激活“敌方目标焦点”(比如战斗)。"
71 | L["Head Tracking"] = "头部追踪"
72 | L[""] = "(这也可以作为一个0到1之间的连续值,但它只是分别乘以站立强度和移动强度。所以真的不需要另一个滑块。)"
73 | L["Strength (standing)"] = "强度(站立)"
74 | L["Inertia (standing)"] = "惯性(站立)"
75 | L["Strength (moving)"] = "强度(移动)"
76 | L["Inertia (moving)"] = "惯性(移动)"
77 | L["Inertia (first person)"] = "惯性(第一人称)"
78 | L["Range Scale"] = "范围缩放"
79 | L["Camera distance beyond which head tracking is reduced or disabled. (See explanation below.)"] = "超过此镜头距离时减少或禁用头部追踪。(见下文解释。)"
80 | L["(slider value transformed)"] = "(滑块值转换)"
81 | L["Dead Zone"] = "死区"
82 | L["Radius of head movement not affecting the camera. (See explanation below.)"] = "头部移动不影响镜头的半径。(见下文解释。)"
83 | L["(slider value devided by 10)"] = "(滑块值 / 10)"
84 | L["Requires /reload to come into effect!"] = "需要/reload才能生效!"
85 | L[""] = "启用头部追踪后,镜头会跟随角色头部的移动。(虽然这可能有助于沉浸感,但如果你对晕动症敏感,也可能导致恶心。)\n\n“强度”设置决定了这种效果的强度。将其设置为0可以禁用头部追踪。“惯性”设置决定了镜头对头部移动的反应速度。将其设置为0也可以禁用头部追踪。“站立”、“移动”和“第一人称”三种情境可以单独设置。“第一人称”没有“强度”设置,因为它分别假设“站立”和“移动”的“强度”设置。如果你想单独启用或禁用“第一人称”,请使用“惯性”滑块来禁用不需要的情境。\n\n“范围缩放”设置可以设置超过此镜头距离时减少或禁用头部追踪。例如,将滑块设置为30,当镜头距离角色超过30码时,将没有头部追踪。但是,从完全头部追踪到没有头部追踪有一个逐渐过渡,从滑块值的三分之一开始。例如,将滑块值设置为30,当镜头距离小于10码时,有完全头部追踪。超过10码时,头部追踪逐渐减少,直到在30码外完全消失。因此,滑块的最大值是117,允许在最大镜头距离39码时有完全头部追踪。(提示:使用我们的“鼠标缩放”视觉辅助工具在设置时检查当前镜头距离。)\n\n“死区”设置可以用来忽略较小的头部移动。将其设置为0可以让镜头跟随每一个微小的头部移动,而将其设置为更大的值则只跟随较大的移动。请注意,更改此设置只有在重新加载UI(在控制台中输入/reload)后才生效。"
86 | L["Situations"] = "情境"
87 | L["Select a situation to setup"] = "选择一个情境来设置"
88 | L[""] = "\n|cffffcc00颜色代码:|r\n|cFF808A87- 禁用的情境。|r\n- 启用的情境。\n|cFF00FF00- 启用且当前激活的情境。|r\n|cFF63B8FF- 启用且条件满足但优先级低于当前激活情境的情境。|r\n|cFFFF6600- 修改过的预设“情境控制”(建议重置)。|r\n|cFFEE0000- 错误的“情境控制”(需要更改)。|r"
89 | L["If this box is checked, DynamicCam will enter the situation \""] = "如果选中此框,DynamicCam将在其条件满足且没有其他优先级更高的情境激活时进入情境 \""
90 | L["\" whenever its condition is fulfilled and no other situation with higher priority is active."] = "\"。"
91 | L["Delete custom situation \""] = "删除自定义情境 \""
92 | L["\".\n(There will be no 'Are you sure?' prompt!)"] = "\"。\n(不会有'你确定吗?'的提示!)"
93 | L["Create a new custom situation."] = "创建一个新的自定义情境。"
94 | L["Situation Actions"] = "情境指令"
95 | L["Setup stuff to happen while in a situation or when entering/exiting it."] = "设置在情境中或进入/退出时要执行的操作。"
96 | L["Zoom/View"] = "缩放/视角"
97 | L["Zoom to a certain zoom level or switch to a saved camera view when entering this situation."] = "在进入这个情境时,调整到特定的缩放级别或切换到保存的镜头视角。"
98 | L["Reset to global defaults!\n(To restore the settings of a specific profile, restore the profile in the \"Profiles\" tab.)"] = "重置为全局默认值!\n(要恢复特定配置文件的设置,请在“配置文件”选项卡中恢复配置文件。)"
99 | L["Set Zoom or Set View"] = "设置缩放或设置视角"
100 | L["Zoom Type"] = "缩放模式"
101 | L[""] = "设置缩放:调整到给定的缩放级别,并有过渡时间和缩放条件的高级选项。\n\n设置视角:切换到包含固定缩放级别和镜头角度的保存的镜头视角。"
102 | L["Set Zoom"] = "设置缩放"
103 | L["Set View"] = "设置视角"
104 | L["Set view to saved view:"] = "设置视角为保存视角:"
105 | L["Select the saved view to switch to when entering this situation."] = "选择进入此情境时要切换的保存视角。"
106 | L["Instant"] = "立即"
107 | L["Make view transitions instant."] = "使视角转换立即发生。"
108 | L["Restore view when exiting"] = "退出时恢复视角"
109 | L["When exiting the situation restore the camera position to what it was at the time of entering the situation."] = "退出情境时,将镜头恢复到进入情境时的位置。"
110 | L["cameraSmoothNote"] = [[|cFFEE0000注意:|r 您正在使用WoW的“镜头跟随风格”,它会自动将镜头放置在玩家后面。这在您处于自定义视角时不起作用。您可以在不需要镜头跟随的情境中使用自定义保存视角(例如,NPC互动)。但在退出情境后,您必须返回到非自定义的默认视角,以便再次使镜头跟随工作。]]
111 | L["Restore to default view:"] = "恢复为默认视角:"
112 | L[""] = [[选择退出此情境时返回的默认视角。
113 |
114 | 视角1:缩放0,俯仰0
115 | 视角2:缩放5.5,俯仰10
116 | 视角3:缩放5.5,俯仰20
117 | 视角4:缩放13.8,俯仰30
118 | 视角5:缩放13.8,俯仰10]]
119 | L["WARNING"] = "警告"
120 | L["You are using the same view as saved view and as restore-to-default view. Using a view as restore-to-default view will reset it. Only do this if you really want to use it as a non-customized saved view."] = "您正在使用相同的视角作为保存视角和恢复为默认视角。用作恢复为默认视角将会重置它。只有在您确实想将其用作非自定义保存视角时才这样做。"
121 | L["is used as saved view in the situations:"] = "在以下情境中被用作保存视角:"
122 | L["and as restore-to-default view in the situations:"] = "并且在以下情境中被用作默认视角:"
123 | L[""] = [[魔兽世界允许保存最多5个自定义镜头视角。视角1由DynamicCam使用,用于保存进入情境时的镜头位置,以便在退出情境时可以恢复,如果您在上面勾选了“恢复”。这对于短暂的情境(如与NPC互动)特别有用,允许在与NPC对话时切换到一个视角,然后回到镜头之前的位置。这就是为什么视角1不能在上述保存视角的下拉菜单中选择。
124 |
125 | 视角2、3、4和5可以用来保存自定义的镜头位置。要保存一个视角,只需将镜头调整到所需的缩放和角度。然后在控制台中输入以下命令(其中#是编号2、3、4或5):
126 |
127 | /saveView #
128 |
129 | 或简写为:
130 |
131 | /sv #
132 |
133 | 请注意,保存的视角由魔兽世界存储。DynamicCam只存储使用哪些视角编号。因此,当您导入新的DynamicCam情境配置文件和视角时,您可能需要在之后设置并保存相应的视角。
134 |
135 |
136 | DynamicCam还提供了一个控制台命令,用于无论进入还是退出情境都切换到视角:
137 |
138 | /setView #
139 |
140 | 要使视角转换立即发生,请在视角编号后添加一个“i”。例如,要立即切换到保存的视角3,请输入:
141 |
142 | /setView 3 i
143 |
144 | ]]
145 | L["Zoom Transition Time"] = "缩放过渡时间"
146 | L[""] = "过渡到新缩放值所需的时间(以秒为单位)。\n\n如果设置的值低于可能的最低值,过渡速度将尽可能快,以当前镜头缩放速度为准(可在DynamicCam的“鼠标缩放”设置中调整)。\n\n如果某个情境在其进入脚本中分配了变量“this.transitionTime”(参见“情境控制”),这里的设置将被覆盖。例如,在“炉石/传送”情境中这样做,以便为施法持续时间允许一个过渡时间。"
147 | L[""] = "\n设置:始终将缩放设置为此值。\n\n拉远:仅当镜头当前比此值更近时,才设置缩放。\n\n推近:仅当镜头当前比此值更远时,才设置缩放。\n\n范围:如果比给定的最大值更远,则放大;如果比给定的最小值更近,则缩小。如果当前缩放在[min, max]范围内,则不执行任何操作。"
148 | L["Set"] = "设置"
149 | L["Out"] = "拉远"
150 | L["In"] = "推近"
151 | L["Range"] = "范围"
152 | L["Don't slow"] = "不要减速"
153 | L["Zoom transitions may be executed faster (but never slower) than the specified time above, if the \"Camera Zoom Speed\" (see \"Mouse Zoom\" settings) allows."] = "如果“镜头缩放速度”(参见“鼠标缩放”设置)允许,缩放过渡可能会比上述指定时间更快(但不会减速)。"
154 | L["Zoom Value"] = "缩放值"
155 | L["Zoom to this zoom level."] = "缩放到这个缩放级别。"
156 | L["Zoom out to this zoom level, if the current zoom level is less than this."] = "如果当前缩放级别小于此值,则缩小到这个缩放级别。"
157 | L["Zoom in to this zoom level, if the current zoom level is greater than this."] = "如果当前缩放级别大于此值,则放大到这个缩放级别。"
158 | L["Zoom Min"] = "最小缩放"
159 | L["Zoom out to this zoom level, if the current zoom level is less than this."] = "如果当前缩放级别小于此值,则缩小到这个缩放级别。"
160 | L["Zoom Max"] = "最大缩放"
161 | L["Zoom in to this zoom level, if the current zoom level is greater than this."] = "如果当前缩放级别大于此值,则放大到这个缩放级别。"
162 | L["Restore Zoom"] = "恢复缩放"
163 | L[""] = "当您退出一个情境(或退出没有活跃情境的默认状态)时,当前的缩放级别会被临时保存,以便下次进入此情境时可以恢复。在这里,您可以选择如何处理。\n\n此设置对所有情境都是全局的。"
164 | L["Restore Zoom Mode"] = "恢复缩放模式"
165 | L[""] = "\n从不:进入情境时,应用进入情境的实际缩放设置(如果有)。不考虑保存的缩放。\n\n总是:进入情境时,使用此情境上次保存的缩放。其实际设置仅在登录后首次进入情境时考虑。\n\n自适应:仅在某些情况下使用保存的缩放。例如,只有当返回到您来自的相同情境,或者保存的缩放满足情境的“推近”、“拉远”或“范围”缩放设置的标准时。"
166 | L["Never"] = "从不"
167 | L["Always"] = "总是"
168 | L["Adaptive"] = "自适应"
169 | L[""] = [[要确定当前的缩放级别,您可以使用“视觉辅助”(在DynamicCam的“鼠标缩放”设置中切换)或使用控制台命令:
170 |
171 | /zoomInfo
172 |
173 | 或者简写为:
174 |
175 | /zi]]
176 | L["Rotation"] = "转动"
177 | L["Start a camera rotation when this situation is active."] = "当此情境激活时开始镜头转动。"
178 | L["Reset to global defaults!\n(To restore the settings of a specific profile, restore the profile in the \"Profiles\" tab.)"] = "重置为全局默认值!\n(要恢复特定配置文件的设置,请在“配置文件”选项卡中恢复配置文件。)"
179 | L["Rotation Type"] = "转动方式"
180 | L[""] = "\n持续转动:当此情境激活时,镜头会持续水平转动。这只建议用于不使用鼠标移动摄像机的情况;例如,传送法术施放、飞行或离开。无法持续垂直转动,因为它会在向上或向下垂直视角时停止。\n\n按度数转动:进入情境后,根据给定的度数改变当前摄像机的水平偏转(yaw)和/或垂直俯仰(pitch)。"
181 | L["Continuously"] = "持续转动"
182 | L["By Degrees"] = "按角度转动"
183 | L["Acceleration Time"] = "加速时间"
184 | L["Rotation Time"] = "转动时间"
185 | L[""] = "如果您在这里设置的时间大于0,持续转动不会立即以全速开始,而是会花费这段时间来加速。(只有在相对较高的转动速度下才会明显感知。)"
186 | L[""] = "需要多长时间来调整到新的摄像机角度。如果这里给出的值太小,摄像机可能会转动过头,因为我们每渲染一帧时只检查一次是否达到了期望的角度。\n\n如果某个情境在其进入脚本中分配了变量“this.rotationTime”(参见“情境控制”),这里的设置将被覆盖。例如,在“炉石/传送”情境中这样做,以便为施法时间内塞入一个转动时间。"
187 | L["Rotation Speed"] = "转动速度"
188 | L["Speed at which to rotate in degrees per second. You can manually enter values between -900 and 900, if you want to get yourself really dizzy..."] = "每秒转动的度数。如果您想让自己真的头晕目眩,可以手动输入-900到900之间的值..."
189 | L["Yaw (-Left/Right+)"] = "偏转(-左/右+)"
190 | L["Degrees to yaw (left or right)."] = "偏转的度数(左或右)。"
191 | L["Pitch (-Down/Up+)"] = "俯仰(-下/上+)"
192 | L["Degrees to pitch (up or down). There is no going beyond the perpendicular upwards or downwards view."] = "俯仰的度数(上或下)。无法超过向上或向下的垂直视角。"
193 | L["Rotate Back"] = "转动返回"
194 | L[""] = "退出情境时,按进入情境后转动的度数(360)反向转动。这实际上会将您带回进入前的摄像机位置,除非您在此过程中用鼠标改变了视角。\n\n如果您正在进入一个自带转动设置的新情境,那么退出情境的“转动返回”将被忽略。"
195 | L["Rotate Back Time"] = "转动返回时间"
196 | L[""] = "转动返回所需的时间。如果这里给出的值太小,摄像机可能会转动过头,因为我们每渲染一帧时只检查一次是否达到了期望的角度。"
197 | L["Fade Out UI"] = "渐隐界面"
198 | L["Fade out or hide (parts of) the UI when this situation is active."] = "当此情境激活时,渐隐或隐藏(部分)用户界面。"
199 | L["Reset to global defaults!\n(To restore the settings of a specific profile, restore the profile in the \"Profiles\" tab.)"] = "重置为全局默认值!\n(要恢复特定配置文件的设置,请在“配置文件”选项卡中恢复配置文件。)"
200 | L["Adjust to Immersion"] = "调整以适应沉浸"
201 | L[""] = "许多人将Immersion插件与DynamicCam结合使用。Immersion在NPC互动期间有一些自己的隐藏UI特性。在某些情况下,DynamicCam的隐藏界面会覆盖Immersion的设置。为了防止这种情况,您可以在DynamicCam中进行所需的设置。点击此按钮使用与Immersion相同的渐显和渐隐时间。想要更多选项,请查看Ludius的另一个插件“Immersion ExtraFade”。"
202 | L["Fade Out Time"] = "渐隐时间"
203 | L["Seconds it takes to fade out the UI when entering the situation."] = "进入情境时,界面渐隐所需的秒数。"
204 | L["Fade In Time"] = "渐显时间"
205 | L[""] = "退出情境时,UI渐隐所需的秒数。\n\n当您在进入另一个情境的同时退出一个情境时,进入情境的渐隐时间将用于过渡。"
206 | L["Hide entire UI"] = "隐藏整个界面"
207 | L[""] = "“隐藏”的界面和“只是渐隐”的界面之间有区别:“渐隐”的界面元素的不透明度为0,但仍然可以与之交互。从DynamicCam 2.0开始,如果界面元素的不透明度为0,我们会自动隐藏大多数界面元素。因此,渐隐后隐藏整个界面的选项更像是一个遗留物。仍然使用它的原因可能是为了避免不希望的交互(例如鼠标悬停提示)DynamicCam仍然没有正确隐藏的界面元素。\n\n隐藏界面的不透明度当然是0,所以你不能选择不同的不透明度,也不能保留任何界面元素可见(除了FPS指示器)。\n\n在战斗中我们不能改变受保护的界面元素的隐藏状态。"
208 | L["Keep FPS indicator"] = "保留FPS指示器"
209 | L["Do not fade out or hide the FPS indicator (the one you typically toggle with Ctrl + R)."] = "不要渐隐或隐藏FPS指示器(通常用 Ctrl+R 切换的那个)。"
210 | L["Fade Opacity"] = "渐隐不透明度"
211 | L["Fade the UI to this opacity when entering the situation."] = "进入情境时将用户界面渐隐到这种不透明度。"
212 | L["Excluded UI elements"] = "排除的用户界面元素"
213 | L["Keep Alerts"] = "保留警告"
214 | L["Still show alert popups from completed achievements, Covenant Renown, etc."] = "仍然显示来自完成成就、盟约声望等的警告弹出窗口。"
215 | L["Keep Tooltip"] = "保留提示"
216 | L["Still show the game tooltip, which appears when you hover your mouse cursor over UI or world elements."] = "仍然显示游戏提示,当你将鼠标光标悬停在用户界面或世界元素上时出现。"
217 | L["Keep Minimap"] = "保留小地图"
218 | L[""] = "不要渐隐小地图。\n\n请注意,我们不能减少小地图上“光点”的不透明度。当用户界面渐隐到0不透明度时,这些只能与整个小地图一起隐藏。"
219 | L["Keep Chat Box"] = "保留聊天框"
220 | L["Do not fade out the chat box."] = "不要渐隐聊天框。"
221 | L["Keep Tracking Bar"] = "保留追踪条"
222 | L["Do not fade out the tracking bar (XP, AP, reputation)."] = "不要渐隐追踪条(经验值、能力点、声望)。"
223 | L["Keep Party/Raid"] = "保留小队/团队框架"
224 | L["Do not fade out the Party/Raid frame."] = "不要渐隐小队/团队框架"
225 | L["Keep Encounter Frame (Dragonriding Vigor)"] = "保留遭遇框架(驭空术条)"
226 | L["Do not fade out the Encounter Frame, which while dragonriding is the Vigor display."] = "不要渐隐遭遇框架,在驭空术时是能量显示。"
227 | L["Keep additional frames"] = "保留额外框架"
228 | L[""] = "下面的文本框允许你定义在NPC交互期间想要保留的任何框架。\n\n使用控制台命令/fstack来了解框架的名称。\n\n例如,你可能想要保留小地图旁边的增益图标,以便在NPC交互期间通过点击适当的图标来取消骑乘。"
229 | L["Custom frames to keep"] = "自定义保留框架"
230 | L["Separated by commas."] = "用逗号分隔。"
231 | L["Emergency Fade In"] = "紧急渐显"
232 | L["Pressing Esc fades the UI back in."] = "按下Esc键将用户界面渐显回来。"
233 | L[""] = [[有时你可能希望在常态隐藏界面的情况下显示界面。在旧版本的 DynamicCam 中有个规则,允许你在按下ESC键时显示界面。但这样做有个缺点,当ESC键用于其他作用,比如关闭窗口、取消施法等时,界面也会显示。取消勾选上面的复选框可以禁用此功能。
234 |
235 | 但请注意,这样可能会导致无法访问界面!ESC键更好的替代方案是使用以下的控制台命令,它们会根据当前设置的“渐隐界面”设置显示或隐藏界面:
236 |
237 | /showUI
238 | /hideUI
239 |
240 | 为了更加快捷的实现渐隐界面,将 /showUI 放入宏命令中,并在"bindings-cache.wtf"文件中为其分配一个按键。例如:
241 |
242 | bind ALT+F11 MACRO 你的宏名称
243 |
244 | 如果你不想编辑"bindings-cache.wtf"文件,可以使用类似"BindPad"这样的按键绑定插件。
245 |
246 | 使用 /showUI 或者 /hideUI 而不带任何参数将采用当前情境的渐显和渐隐时间。但你也可以使用参数提供不同的过渡时间。例如:
247 |
248 | /showUI 0
249 |
250 | 来实现立即显示界面,没有任何延迟。]]
251 | L[""] = "在设置你期望的界面渐隐效果时,如果这个“界面”设置框也一起渐隐,可能会很烦人。如果选中这个框,它将不会被渐隐。\n\n此设置适用于所有情况。"
252 | L["Do not fade out this \"Interface\" settings frame."] = "不要渐隐这个“界面”设置框。"
253 | L["Situation Controls"] = "情境控制"
254 | L[""] = "在这里,你控制何时激活一个情境。可能需要了解WoW UI API。如果你对DynamicCam的默认情况感到满意,只需忽略此部分。但如果你想创建自定义情况,可以在这里检查默认情境。你也可以修改它们,但请注意:即使DynamicCam的未来版本引入了重要更新,你更改的设置也会保留。\n\n"
255 | L["Priority"] = "优先级"
256 | L["The priority of this situation.\nMust be a number."] = "此情境的优先级。\n必须是一个数字。"
257 | L["Restore stock setting"] = "恢复默认设置"
258 | L["Your \"Priority\" deviates from the stock setting for this situation ("] = "你的“优先级”与此情境的默认设置不符("
259 | L["). Click here to restore it."] = ")。点击这里恢复它。"
260 | L[""] = "如果多个不同的DynamicCam情境的条件同时满足,将进入优先级最高的情境。例如,每当“世界室内”的条件满足时,“世界”的条件也会满足。但由于“世界室内”的优先级高于“世界”,因此会优先选择。你还可以在上方的下拉菜单中看到所有情境的优先级。\n\n"
261 | L["Error message:"] = "错误信息:"
262 | L["Events"] = "事件"
263 | L["Separated by commas."] = "用逗号分隔。"
264 | L["Your \"Events\" deviate from the default for this situation. Click here to restore them."] = "你的“事件”与此情境的默认设置不同。点击这里恢复它们。"
265 | L[""] = [[在这里,你可以定义所有游戏中的事件,DynamicCam应该检查这些事件的条件,以确定是否进入或退出当前情境。
266 |
267 | 你可以通过WoW的事件日志了解游戏中的事件。
268 | 要打开它,请在控制台中输入以下命令:
269 |
270 | /eventtrace
271 |
272 | 所有可能的事件列表也可以在这里找到:
273 | https://warcraft.wiki.gg/wiki/Events
274 |
275 | ]]
276 | L["Initialisation"] = "初始化"
277 | L["Initialisation Script"] = "初始化脚本"
278 | L["Lua code using the WoW UI API."] = "使用WoW UI API的Lua代码。"
279 | L["Your \"Initialisation Script\" deviates from the stock setting for this situation. Click here to restore it."] = "你的“初始化脚本”与此情境的默认设置不同。点击这里恢复它。"
280 | L[""] = [[一个情境的初始化脚本在 DynamicCam 加载时(以及情境被修改时)运行一次。你通常会在其中放入你希望在其他任何脚本(条件、进入、退出)中应用的内容。这可以使这些脚本更短一些。
281 |
282 | 例如,“炉石/传送”情境的初始化脚本定义了表格“this.spells”,其中包含了传送法术的法术ID。然后,条件脚本每次执行时都可以简单地访问“this.spells”。
283 |
284 | 像这个例子一样,你可以通过将数据对象放入“this”表格中,在情境的脚本之间共享任何数据对象。
285 |
286 | ]]
287 | L["Condition"] = "条件"
288 | L["Condition Script"] = "条件脚本"
289 | L["Lua code using the WoW UI API.\nShould return \"true\" if and only if the situation should be active."] = "使用WoW UI API的Lua代码。\n只有在情境应该激活时才返回“true”。"
290 | L["Your \"Condition Script\" deviates from the stock setting for this situation. Click here to restore it."] = "你的“条件脚本”与此情境的默认设置不同。点击这里恢复它。"
291 | L[""] = [[条件脚本在每次触发此情境的游戏内事件时运行。如果且仅当此情境应该处于活动状态时,脚本应返回“true”。
292 |
293 | 例如,“城市”情境的条件脚本使用WoW API函数“IsResting()”来检查你是否目前在休息区域:
294 |
295 | return IsResting()
296 |
297 | 同样,“城市-室内”情境的条件脚本也使用WoW API函数“IsIndoors()”来检查你是否在室内:
298 |
299 | return IsResting() and IsIndoors()
300 |
301 | 可以在此处找到WoW API函数的列表:
302 | https://warcraft.wiki.gg/wiki/World_of_Warcraft_API
303 |
304 | ]]
305 | L["Entering"] = "进入时"
306 | L["On-Enter Script"] = "进入时脚本"
307 | L["Your \"On-Enter Script\" deviates from the stock setting for this situation. Click here to restore it."] = "你的“进入时脚本”与此情境的默认设置不同。点击此处恢复默认设置。"
308 | L[""] = [[情境带有的进入时脚本在每次进入该情境时执行。
309 |
310 | 这方面的例子是“炉石/传送”情境,我们使用WoW API函数"UnitCastingInfo()"来确定当前施法的持续时间。然后我们将这个值赋给变量"this.transitionTime"和"this.rotationTime",这样缩放或转动(见“情境指令”)可以精确地与施法时间一样长。(不是所有传送法术的施法时间都相同。)
311 |
312 | ]]
313 | L["Exiting"] = "退出时"
314 | L["On-Exit Script"] = "退出时脚本"
315 | L["Your \"On-Exit Script\" deviates from the stock setting for this situation. Click here to restore it."] = "你的“退出时脚本”与此情境的默认设置不同。点击此处恢复默认设置。"
316 | L["Exit Delay"] = "退出延迟"
317 | L["Wait for this many seconds before exiting this situation."] = "在退出此情境前等待多少秒。"
318 | L["Your \"Exit Delay\" deviates from the stock setting for this situation. Click here to restore it."] = "你的“退出延迟”与此情境的默认设置不同。点击此处恢复默认设置。"
319 | L[""] = [[情境带有的退出时脚本在每次退出该情境时运行。到目前为止,还没有情境使用这个功能。
320 |
321 | 延迟决定了在退出情境前需要等待多少秒。目前,唯一的例子是“钓鱼”情境,其中的延迟给你时间重新抛出鱼竿,而不会退出该情境。
322 |
323 | ]]
324 | L["Export"] = "导出"
325 | L["Coming soon(TM)."] = "即将推出。"
326 | L["Import"] = "导入"
327 | L[""] = [[我们很高兴你来到这里,并希望你能享受这个插件带来的乐趣。
328 |
329 | DynamicCam(DC)由mpstark于2016年5月开始开发,当时暴雪的魔兽世界开发团队引入了实验性的ActionCam功能。DC的主要目的是为用户提供ActionCam设置的用户界面。在游戏内,ActionCam仍被标记为“实验性”,并且没有迹象表明暴雪会进一步开发它。 虽然存在一些不足,但我们应该感激ActionCam被保留在游戏中,让我们这些爱好者能够使用。:-) DC不仅允许你更改ActionCam设置,还能够根据不同的游戏情况设置不同的设置。与ActionCam无关,DC还提供了关于镜头缩放和界面渐隐的功能。
330 |
331 | mpstark对DC的工作一直持续到2018年8月。虽然大多数功能对大量用户都运作良好,但mpstark一直认为DC处于测试阶段,由于他对WoW的兴趣逐渐减退,最终没有恢复工作。那时,Ludius已经开始为自己调整DC,这被Weston(aka dernPerkins)注意到,他在2020年初设法联系到mpstark,牵头让Ludius接管了开发工作。第一个非测试版本1.0于2020年5月发布,包括了Ludius到那时为止的调整。之后,Ludius开始对DC进行大修,使得2.0版本在2022年秋季发布。
332 |
333 | 在mpstark初始开发DC时,他的重点是使大多数自定义设置都能在游戏内完成,而不需要更改源代码。这使得在不同的游戏情境下进行实验变得更加容易。从2.0版本开始,这些高级设置已经被移到一个名为“情境控制”的特殊部分。大多数用户可能永远也不需要它,但对于“高级用户”来说,它仍然可用。在那里进行更改的风险是,保存的用户设置总是覆盖DC的默认设置,即使新版本的DC带来了更新的默认设置。因此,每当你激活的情境有修改过的“情境控制”时,本页面顶部会显示一个警告。
334 |
335 | 如果你认为DC的某个默认情境应该被修改,你可以随时创建一个带有你个人色彩的副本。欢迎导出这个新情境并在DC的curseforge页面上发布。我们可能会将其添加为一个新的默认情境。你也可以导出并发布你的整个DC配置文件,因为我们总是在寻找新的配置预设,这可以让新用户更容易地开始使用DC。如果你发现问题或想要提出建议,请在curseforge评论中留言,当然更好的是使用GitHub上的Issues。如果你想贡献代码,也欢迎在那里打开一个拉取请求。
336 |
337 | 以下是一些方便的命令:
338 |
339 | `/dynamiccam` 或 `/dc` 打开这个页面。
340 | `/zoominfo` 或 `/zi` 输出当前的缩放级别。
341 |
342 | `/zoom #1 #2` 在 #2 秒内缩放到 #1 缩放级别。
343 | `/yaw #1 #2` 在 #2 秒内使镜头偏转 #1 度(负 #1 偏航到右边)。
344 | `/pitch #1 #2` 使镜头俯仰 #1 度(负 #1 向上俯仰)。
345 |
346 |
347 | ]]
348 | L["About"] = "关于"
349 | L["The following game situations have \"Situation Controls\" deviating from DynamicCam's stock settings.\n\n"] = "以下游戏情境的“情境控制”与DynamicCam的默认设置不同。\n\n"
350 | L[""] = "\n如果你是刻意为之的,那没有问题。只是要注意,DynamicCam开发者对这些设置的任何更新总是会被你修改过的(可能过时的)版本覆盖。你可以查看每种情境的“情境控制”标签以获取详细信息。如果你没有意识到任何来自你的“情境控制”修改,并且只是想恢复所有情境的默认控制设置,请点击这个按钮:"
351 | L["Restore all stock Situation Controls"] = "恢复所有默认情境控制"
352 | L["Hello and welcome to DynamicCam!"] = "你好,欢迎来到DynamicCam!"
353 | L["Profiles"] = "配置文件"
354 | L["Manage Profiles"] = "管理配置文件"
355 | L[""] = "像许多插件一样,DynamicCam使用“AceDB-3.0”库来管理配置文件。你需要明白的是,这里没有“保存配置文件”这样的操作。你只能创建新的配置文件,并且你可以从另一个配置文件复制设置到当前激活的配置文件中。你对当前激活的配置文件所做的任何更改都会立即保存!这里没有“取消”或“放弃更改”的操作。“重置配置文件”按钮只会重置为全局默认配置文件。\n\n所以如果你喜欢你的DynamicCam设置,你应该创建另一个配置文件,并将这些设置复制进去作为备份。当你不使用这个备份配置文件作为你的激活配置文件时,你可以随意尝试更改设置,并随时通过在“从...复制”框中选择你的备份配置文件来恢复到你原来的配置文件。\n\n如果你想通过宏来切换配置文件,你可以使用以下代码:\n/run DynamicCam.db:SetProfile(\"配置文件名\")\n\n"
356 | L["Profile presets"] = "预设配置文件"
357 | L["Import / Export"] = "导入/导出"
358 | L["DynamicCam"] = "DynamicCam"
359 | L["Disabled"] = "禁用"
360 | L["Your DynamicCam addon lets you adjust horizontal and vertical mouse look speed individually! Just go to the \"Mouse Look\" settings of DynamicCam to make the adjustments there."] = "你的DynamicCam插件允许你单独调整水平和垂直鼠标视角速度!只需前往DynamicCam的“鼠标视角”设置中进行调整。"
361 | L["Attention"] = "注意"
362 | L["The \""] = "这个\""
363 | L["\" setting is disabled by DynamicCam, while you are using the horizontal camera over shoulder offset."] = "\"设置被DynamicCam禁用,当你使用水平镜头肩部偏移时。"
364 | L["While you are using horizontal camera offset, DynamicCam prevents CameraKeepCharacterCentered!"] = "当你使用水平镜头偏移时,DynamicCam会阻止CameraKeepCharacterCentered起效!"
365 | L["While you are using vertical camera pitch, DynamicCam prevents CameraKeepCharacterCentered!"] = "当你使用垂直镜头俯仰时,DynamicCam会阻止CameraKeepCharacterCentered起效!"
366 | L["While you are using horizontal camera offset, DynamicCam prevents CameraReduceUnexpectedMovement!"] = "当你使用水平镜头偏移时,DynamicCam会阻止CameraReduceUnexpectedMovement起效!"
367 | L["cameraView ="] = "镜头视角 ="
368 | L["prevented by DynamicCam!"] = "被DynamicCam阻止!"
369 |
370 | -- MouseZoom
371 | L["Actual\nZoom\nValue"] = "实际\n缩放值"
372 | L["Reactive\nZoom\nTarget"] = "响应\n缩放目标"
373 |
374 | -- Core
375 | L["Enter name for custom situation:"] = "输入自定义情境的名称:"
376 | L["Create"] = "创建"
377 | L["Cancel"] = "取消"
378 |
379 | -- DefaultSettings
380 | L["City"] = "城市"
381 | L["City (Indoors)"] = "城市(室内)"
382 | L["World"] = "世界"
383 | L["World (Indoors)"] = "世界(室内)"
384 | L["World (Combat)"] = "世界(战斗)"
385 | L["Dungeon/Scenerio"] = "地下城/场景战役"
386 | L["Dungeon/Scenerio (Outdoors)"] = "地下城/场景战役(户外)"
387 | L["Dungeon/Scenerio (Combat, Boss)"] = "地下城/场景战役(战斗,首领)"
388 | L["Dungeon/Scenerio (Combat, Trash)"] = "地下城/场景战役(战斗,小怪)"
389 | L["Raid"] = "团队副本"
390 | L["Raid (Outdoors)"] = "团队副本(户外)"
391 | L["Raid (Combat, Boss)"] = "团队副本(战斗,首领)"
392 | L["Raid (Combat, Trash)"] = "团队副本(战斗,小怪)"
393 | L["Arena"] = "竞技场"
394 | L["Arena (Combat)"] = "竞技场(战斗)"
395 | L["Battleground"] = "战场"
396 | L["Battleground (Combat)"] = "战场(战斗)"
397 | L["Mounted (any)"] = "骑乘(任意)"
398 | L["Mounted (only flying-mount)"] = "骑乘(仅限飞行坐骑)"
399 | L["Mounted (only flying-mount + airborne)"] = "骑乘(仅限飞行坐骑 + 空中)"
400 | L["Mounted (only flying-mount + airborne + Skyriding)"] = "骑乘(仅限飞行坐骑 + 空中 + 驭空术)"
401 | L["Mounted (only flying-mount + Skyriding)"] = "骑乘(仅限飞行坐骑 + 驭空术)"
402 | L["Mounted (only airborne)"] = "骑乘(仅限空中)"
403 | L["Mounted (only airborne + Skyriding)"] = "骑乘(仅限空中 + 驭空术)"
404 | L["Mounted (only Skyriding)"] = "骑乘(仅限驭空术)"
405 | L["Druid Travel Form"] = "德鲁伊旅行形态"
406 | L["Dracthyr Soar"] = "驭龙术"
407 | L["Skyriding Race"] = "驭空竞速"
408 | L["Taxi"] = "出租车(飞行点交通)"
409 | L["Vehicle"] = "载具"
410 | L["Hearth/Teleport"] = "炉石/传送"
411 | L["Annoying Spells"] = "烦人的技能"
412 | L["NPC Interaction"] = "与NPC互动"
413 | L["Mailbox"] = "邮箱"
414 | L["Fishing"] = "钓鱼"
415 | L["Gathering"] = "采集"
416 | L["AFK"] = "暂离"
417 | L["Pet Battle"] = "宠物对战"
418 |
419 |
--------------------------------------------------------------------------------
/Locales/zhTW.lua:
--------------------------------------------------------------------------------
1 | local L = LibStub("AceLocale-3.0"):NewLocale("DynamicCam", "zhTW")
2 | if not L then return end
3 |
4 | -- Options
5 | L["Reset"] = "重置"
6 | L["Reset to global default:"] = "重置為全域預設值:"
7 | L["(To restore the settings of a specific profile, restore the profile in the \"Profiles\" tab.)"] = "(要恢復為特定設定檔的設置,請在“設定檔”標籤頁中選擇該設定檔後操作。)"
8 | L["Currently overridden by the active situation \""] = "當前設置為情境: \""
9 | L["Override Standard Settings"] = "覆蓋標準情境"
10 | L[""] = "勾選這個核取方塊,允許你在啟動當前情境時,覆蓋標準情境。取消勾選將刪除此類型的情境設置。"
11 | L["Custom:"] = "自訂:"
12 | L["(modified)"] = "(已修改)"
13 | L["Priority:"] = "優先順序:"
14 | L["Standard Settings"] = "標準設定"
15 | L["Situation Settings"] = "情境設定"
16 | L[""] = "當沒有任何情境處於啟動狀態,或者啟動的情境沒有設置覆蓋標準設定的情境設置時,將應用這些標準設定。"
17 | L[""] = "綠色的類型表示目前被啟動的情境覆蓋。因此,在覆蓋情境啟動時,綠色類型的標準設定不會生效。"
18 | L["These Situation Settings can override the Standard Settings when the respective situation is active."] = "當相應的情境啟動時,這些情境設置將覆蓋標準設定。"
19 | L["Mouse Zoom"] = "滑鼠縮放"
20 | L["Maximum Camera Distance"] = "最大鏡頭距離"
21 | L["How many yards the camera can zoom away from your character."] = "鏡頭鏡頭可以從你的角色拉遠多少碼的距離。"
22 | L["Camera Zoom Speed"] = "鏡頭縮放速度"
23 | L["How fast the camera can zoom."] = "鏡頭鏡頭縮放的速度。"
24 | L["Zoom Increments"] = "鏡頭縮放增量"
25 | L["How many yards the camera should travel for each \"tick\" of the mouse wheel."] = "每次滑鼠滾輪鏡頭應該移動多少碼。"
26 | L["Use Reactive Zoom"] = "使用回應縮放"
27 | L["Quick-Zoom Additional Increments"] = "快速縮放額外增量"
28 | L["How many yards per mouse wheel tick should be added when quick-zooming."] = "當快速縮放時,每次滑鼠滾輪滾動應該增加多少碼。"
29 | L["Quick-Zoom Enter Threshold"] = "快速縮放閾值"
30 | L["How many yards the \"Reactive Zoom Target\" and the \"Actual Zoom Value\" have to be apart to enter quick-zooming."] = "\"響應縮放目標\"與\"實際縮放值\"之間至少需要多少碼的距離,才能觸發快速縮放功能。"
31 | L["Maximum Zoom Time"] = "最大縮放時間"
32 | L["The maximum time the camera should take to make \"Actual Zoom Value\" equal to \"Reactive Zoom Target\"."] = "鏡頭會在這個時間內將\"實際縮放值\"調整到\"響應縮放目標\"。"
33 | L["Help"] = "幫助"
34 | L["Toggle Visual Aid"] = "視覺輔助開關"
35 | L[""] = "使用 DynamicCam 的響應縮放功能,滑鼠滾輪控制\"響應縮放目標\"。每當\"響應縮放目標\"與\"實際縮放值\"不同時,DynamicCam 會改變\"實際縮放值\",直到他再次與\"響應縮放目標\"相同。\n\n這種縮放變化的速度取決於\"鏡頭縮放速度\"和 \"最大縮放時間\"。如果\"最大縮放時間\"設置的比較短,無論\"鏡頭縮放速度\"如何設置,縮放總會很快執行。要實現舒緩的縮放變化,你必須將\"最大縮放時間\"設置得更長,同時把\"鏡頭縮放速度\"設置為較低的值。\n\n為了實現隨著滑鼠滾輪快速滾動更快地縮放鏡頭,請使用\"快速縮放功能\":如果\"響應縮放目標\"與\"實際縮放值\"的偏差超過了\"快速縮放閾值\",每次滑鼠滾輪的滾動都會增加\"快速縮放額外增量\"。\n\n為了感受這些功能是如何工作的,你可以在尋找合適設置的同時,開啟視覺輔助。你也可以通過左鍵拖弋操作來自動移動這個圖表。右鍵點擊可以關閉它。"
36 | L["Enhanced minimal zoom-in"] = "強化最小視角"
37 | L[""] = "回應縮放允許你把鏡頭放大到比最近還近。你可以通過在第一人稱視角時再次滾動滑鼠實現這一點。\n\n啟用\"強化最小視角\"後,我們會強制鏡頭在放大時也停留在這個視角上,而不是立即切換回第一人稱視角。你也可以把此理解為\"狙擊模式\"。\n\n|cFFFF0000啟用\"強化最小視角\"可能會在CPU受限的情境下導致幀率下降15%。|r"
38 | L["/reload of the UI required!"] = "需要使用 /reload 重載介面!"
39 | L["Mouse Look"] = "滑鼠視角"
40 | L["Horizontal Speed"] = "水準速度"
41 | L["How much the camera yaws horizontally when in mouse look mode."] = "在滑鼠視角模式下,鏡頭的水準移動速度是多少。"
42 | L["Vertical Speed"] = "垂直速度"
43 | L["How much the camera pitches vertically when in mouse look mode."] = "滑鼠視角模式下,鏡頭的垂直移動速度是多少。"
44 | L[""] = "當你在\"滑鼠視角\"模式下移動滑鼠時,鏡頭移動的幅度。\n\n在《魔獸世界》的預設介面設置中,\"滑鼠視角移動速度\"滑塊同時控制水準和垂直速度,並且自動將水準速度設置為垂直速度的2倍。DynamicCam 覆蓋了這一設置,允許你進行更加個性化的設置。"
45 | L["Horizontal Offset"] = "水準偏移"
46 | L["Camera Over Shoulder Offset"] = "越肩視角偏移"
47 | L["Positions the camera left or right from your character."] = "調整鏡頭在角色左側或者右側的位置。"
48 | L[""] = "要使這個設置生效,DynamicCam 會自動臨時禁用遊戲中的暈動症設置。因此,如果你需要使用暈動症設置,請不要使用水準偏移。\n\n當你選中自己的角色時,《魔獸世界》會自動切換到偏移量為0。我們無法對此進行更改。我們也無法解決鏡頭和牆壁發生碰撞時可能出現的偏移抖動問題。一個可能的解決方法是在室內時使用很小或不使用偏移。\n\n此外,《魔獸世界》會根據玩家模型或坐騎不同,奇怪地應用不同的偏移量。如果你希望有一個恒定的偏移量,Ludius(外掛程式開發者)正在開發另一個外掛程式 CameraOverShoulder 來解決這個問題。"
49 | L["Adjust shoulder offset according to zoom level"] = "根據縮放調整越肩偏移"
50 | L["Enable"] = "啟用"
51 | L["Reset to global defaults:"] = "重置為全域預設值:"
52 | L["and"] = "和"
53 | L["(To restore the settings of a specific profile, restore the profile in the \"Profiles\" tab.)"] = "(要恢復特定設定檔的設置,請在“設定檔”標籤中恢復該設定檔。)"
54 | L["No offset when below this zoom level:"] = "當縮放級別低於此值時無偏移:"
55 | L["When the camera is closer than this zoom level, the offset has reached zero."] = "當鏡頭比此縮放級別更近時,偏移量已達到零。"
56 | L["Real offset when above this zoom level:"] = "當縮放級別高於此值時的真實偏移:"
57 | L["When the camera is further away than this zoom level, the offset has reached its set value."] = "當鏡頭比此縮放級別更遠時,偏移量已達到其設定值。"
58 | L[""] = "在縮放時使肩部偏移量逐漸過渡到零。兩個滑塊定義了此過渡發生的縮放級別範圍。此設置是全域的,不特定於情境。"
59 | L["Vertical Pitch"] = "垂直俯仰"
60 | L["Pitch (on ground)"] = "俯仰(在地面上)"
61 | L["Pitch (flying)"] = "俯仰(飛行中)"
62 | L["Down Scale"] = "向下縮放"
63 | L["Smart Pivot Cutoff Distance"] = "智能轉動停止距離"
64 | L[""] = "如果鏡頭向上俯仰(“俯仰”值較低),“向下縮放”設置決定了在從上方看角色時這種效果的影響程度。將“向下縮放”設置為0可以抵消從上方看時向上俯仰的效果。相反,當你不是從上方看,或者如果鏡頭向下俯仰(“俯仰”值較大)時,“向下縮放”設置幾乎沒有效果。\n\n因此,你應該首先找到從背後看你角色時喜歡的“俯仰”設置。之後,如果你選擇了向上俯仰,從上方看時找到你喜歡“向下縮放”設置。\n\n當鏡頭與地面碰撞時,它通常會在鏡頭到地面碰撞點進行向上俯仰。另一種選擇是鏡頭在執行這種俯仰時更靠近角色的腳。“智慧轉動截止距離”設置決定了鏡頭必須在多遠的距離內才能執行後者。將其設置為0則從不移動鏡頭(WoW的默認設置),而將其設置為最大縮放距離39則總是移動鏡頭。\n\n"
65 | L["Target Focus"] = "目標焦點"
66 | L["Enemy Target"] = "敵方目標"
67 | L["Horizontal Strength"] = "水準強度"
68 | L["Vertical Strength"] = "垂直強度"
69 | L["Interaction Target (NPCs)"] = "交互目標(NPC)"
70 | L[""] = "如果啟用,鏡頭會自動嘗試將目標拉近螢幕中心。強度決定了這種效果的強度。\n\n如果“敵方目標焦點”和“交互目標焦點”都啟用,後者似乎有一個奇怪的錯誤:當首次與NPC交互時,鏡頭會像預期的那樣平滑移動到新角度。但是當你退出交互時,它會立即跳轉到之前的角度。然後當你再次開始交互時,它再次跳轉到新角度。這在與新NPC交談時是可重複的:只有第一次過渡是平滑的,所有後續的都是立即的。\n如果你想要同時使用“敵方目標焦點”和“交互目標焦點”,一個變通方法是只在需要它且不太可能發生NPC交互的DynamicCam情境下啟動“敵方目標焦點”(比如戰鬥)。"
71 | L["Head Tracking"] = "頭部追蹤"
72 | L[""] = "(這也可以作為一個0到1之間的連續值,但它只是分別乘以站立強度和移動強度。所以真的不需要另一個滑塊。)"
73 | L["Strength (standing)"] = "強度(站立)"
74 | L["Inertia (standing)"] = "慣性(站立)"
75 | L["Strength (moving)"] = "強度(移動)"
76 | L["Inertia (moving)"] = "慣性(移動)"
77 | L["Inertia (first person)"] = "慣性(第一人稱)"
78 | L["Range Scale"] = "範圍縮放"
79 | L["Camera distance beyond which head tracking is reduced or disabled. (See explanation below.)"] = "超過此鏡頭距離時減少或禁用頭部追蹤。(見下文解釋。)"
80 | L["(slider value transformed)"] = "(滑塊值轉換)"
81 | L["Dead Zone"] = "死區"
82 | L["Radius of head movement not affecting the camera. (See explanation below.)"] = "頭部移動不影響鏡頭的半徑。(見下文解釋。)"
83 | L["(slider value devided by 10)"] = "(滑塊值 / 10)"
84 | L["Requires /reload to come into effect!"] = "需要/reload才能生效!"
85 | L[""] = "啟用頭部追蹤後,鏡頭會跟隨角色頭部的移動。(雖然這可能有助於沉浸感,但如果你對暈動症敏感,也可能導致噁心。)\n\n“強度”設置決定了這種效果的強度。將其設置為0可以禁用頭部追蹤。“慣性”設置決定了鏡頭對頭部移動的反應速度。將其設置為0也可以禁用頭部追蹤。“站立”、“移動”和“第一人稱”三種情境可以單獨設置。“第一人稱”沒有“強度”設置,因為它分別假設“站立”和“移動”的“強度”設置。如果你想單獨啟用或禁用“第一人稱”,請使用“慣性”滑塊來禁用不需要的情境。\n\n“範圍縮放”設置可以設置超過此鏡頭距離時減少或禁用頭部追蹤。例如,將滑塊設置為30,當鏡頭距離角色超過30碼時,將沒有頭部追蹤。但是,從完全頭部追蹤到沒有頭部追蹤有一個逐漸過渡,從滑塊值的三分之一開始。例如,將滑塊值設置為30,當鏡頭距離小於10碼時,有完全頭部追蹤。超過10碼時,頭部追蹤逐漸減少,直到在30碼外完全消失。因此,滑塊的最大值是117,允許在最大鏡頭距離39碼時有完全頭部追蹤。(提示:使用我們的“滑鼠縮放”視覺輔助工具在設置時檢查當前鏡頭距離。)\n\n“死區”設置可以用來忽略較小的頭部移動。將其設置為0可以讓鏡頭跟隨每一個微小的頭部移動,而將其設置為更大的值則只跟隨較大的移動。請注意,更改此設置只有在重新載入UI(在控制台中輸入/reload)後才生效。"
86 | L["Situations"] = "情境"
87 | L["Select a situation to setup"] = "選擇一個情境來設置"
88 | L[""] = "\n|cffffcc00顏色代碼:|r\n|cFF808A87- 禁用的情境。|r\n- 啟用的情境。\n|cFF00FF00- 啟用且當前啟動的情境。|r\n|cFF63B8FF- 啟用且條件滿足但優先順序低於當前啟動情境的情境。|r\n|cFFFF6600- 修改過的預設“情境控制”(建議重置)。|r\n|cFFEE0000- 錯誤的“情境控制”(需要更改)。|r"
89 | L["If this box is checked, DynamicCam will enter the situation \""] = "如果選中此框,DynamicCam將在其條件滿足且沒有其他優先順序更高的情境啟動時進入情境 \""
90 | L["\" whenever its condition is fulfilled and no other situation with higher priority is active."] = "\"。"
91 | L["Delete custom situation \""] = "刪除自訂情境 \""
92 | L["\".\n(There will be no 'Are you sure?' prompt!)"] = "\"。\n(不會有'你確定嗎?'的提示!)"
93 | L["Create a new custom situation."] = "創建一個新的自訂情境。"
94 | L["Situation Actions"] = "情境指令"
95 | L["Setup stuff to happen while in a situation or when entering/exiting it."] = "設置在情境中或進入/退出時要執行的操作。"
96 | L["Zoom/View"] = "縮放/視角"
97 | L["Zoom to a certain zoom level or switch to a saved camera view when entering this situation."] = "在進入這個情境時,調整到特定的縮放級別或切換到保存的鏡頭視角。"
98 | L["Reset to global defaults!\n(To restore the settings of a specific profile, restore the profile in the \"Profiles\" tab.)"] = "重置為全域預設值!\n(要恢復特定設定檔的設置,請在“設定檔”選項卡中恢復設定檔。)"
99 | L["Set Zoom or Set View"] = "設置縮放或設置視角"
100 | L["Zoom Type"] = "縮放模式"
101 | L[""] = "設置縮放:調整到給定的縮放級別,並有過渡時間和縮放條件的高級選項。\n\n設置視角:切換到包含固定縮放級別和鏡頭角度的保存的鏡頭視角。"
102 | L["Set Zoom"] = "設置縮放"
103 | L["Set View"] = "設置視角"
104 | L["Set view to saved view:"] = "設置視角為保存視角:"
105 | L["Select the saved view to switch to when entering this situation."] = "選擇進入此情境時要切換的保存視角。"
106 | L["Instant"] = "立即"
107 | L["Make view transitions instant."] = "使視角轉換立即發生。"
108 | L["Restore view when exiting"] = "退出時恢復視角"
109 | L["When exiting the situation restore the camera position to what it was at the time of entering the situation."] = "退出情境時,將鏡頭恢復到進入情境時的位置。"
110 | L["cameraSmoothNote"] = [[|cFFEE0000注意:|r 您正在使用WoW的“鏡頭跟隨風格”,它會自動將鏡頭放置在玩家後面。這在您處於自訂視角時不起作用。您可以在不需要鏡頭跟隨的情境中使用自訂保存視角(例如,NPC互動)。但在退出情境後,您必須返回到非自訂的預設視角,以便再次使鏡頭跟隨工作。]]
111 | L["Restore to default view:"] = "恢復為預設視角:"
112 | L[""] = [[選擇退出此情境時返回的預設視角。
113 |
114 | 視角1:縮放0,俯仰0
115 | 視角2:縮放5.5,俯仰10
116 | 視角3:縮放5.5,俯仰20
117 | 視角4:縮放13.8,俯仰30
118 | 視角5:縮放13.8,俯仰10]]
119 | L["WARNING"] = "警告"
120 | L["You are using the same view as saved view and as restore-to-default view. Using a view as restore-to-default view will reset it. Only do this if you really want to use it as a non-customized saved view."] = "您正在使用相同的視角作為保存視角和恢復為預設視角。用作恢復為預設視角將會重置它。只有在您確實想將其用作非自訂保存視角時才這樣做。"
121 | L["is used as saved view in the situations:"] = "在以下情境中被用作保存視角:"
122 | L["and as restore-to-default view in the situations:"] = "並且在以下情境中被用作預設視角:"
123 | L[""] = [[魔獸世界允許保存最多5個自訂鏡頭視角。視角1由DynamicCam使用,用於保存進入情境時的鏡頭位置,以便在退出情境時可以恢復,如果您在上面勾選了“恢復”。這對於短暫的情境(如與NPC互動)特別有用,允許在與NPC對話時切換到一個視角,然後回到鏡頭之前的位置。這就是為什麼視角1不能在上述保存視角的下拉式功能表中選擇。
124 |
125 | 視角2、3、4和5可以用來保存自訂的鏡頭位置。要保存一個視角,只需將鏡頭調整到所需的縮放和角度。然後在控制台中輸入以下命令(其中#是編號2、3、4或5):
126 |
127 | /saveView #
128 |
129 | 或簡寫為:
130 |
131 | /sv #
132 |
133 | 請注意,保存的視角由魔獸世界存儲。DynamicCam只存儲使用哪些視角編號。因此,當您導入新的DynamicCam情境設定檔和視角時,您可能需要在之後設置並保存相應的視角。
134 |
135 |
136 | DynamicCam還提供了一個控制台命令,用於無論進入還是退出情境都切換到視角:
137 |
138 | /setView #
139 |
140 | 要使視角轉換立即發生,請在視角編號後添加一個“i”。例如,要立即切換到保存的視角3,請輸入:
141 |
142 | /setView 3 i
143 |
144 | ]]
145 | L["Zoom Transition Time"] = "縮放過渡時間"
146 | L[""] = "過渡到新縮放值所需的時間(以秒為單位)。\n\n如果設置的值低於可能的最低值,過渡速度將盡可能快,以當前鏡頭縮放速度為准(可在DynamicCam的“滑鼠縮放”設置中調整)。\n\n如果某個情境在其進入腳本中分配了變數“this.transitionTime”(參見“情境控制”),這裡的設置將被覆蓋。例如,在“爐石/傳送”情境中這樣做,以便為施法持續時間允許一個過渡時間。"
147 | L[""] = "\n設置:始終將縮放設置為此值。\n\n拉遠:僅當鏡頭當前比此值更近時,才設置縮放。\n\n推近:僅當鏡頭當前比此值更遠時,才設置縮放。\n\n範圍:如果比給定的最大值更遠,則放大;如果比給定的最小值更近,則縮小。如果當前縮放在[min, max]範圍內,則不執行任何操作。"
148 | L["Set"] = "設置"
149 | L["Out"] = "拉遠"
150 | L["In"] = "推近"
151 | L["Range"] = "範圍"
152 | L["Don't slow"] = "不要減速"
153 | L["Zoom transitions may be executed faster (but never slower) than the specified time above, if the \"Camera Zoom Speed\" (see \"Mouse Zoom\" settings) allows."] = "如果“鏡頭縮放速度”(參見“滑鼠縮放”設置)允許,縮放過渡可能會比上述指定時間更快(但不會減速)。"
154 | L["Zoom Value"] = "縮放值"
155 | L["Zoom to this zoom level."] = "縮放到這個縮放級別。"
156 | L["Zoom out to this zoom level, if the current zoom level is less than this."] = "如果當前縮放級別小於此值,則縮小到這個縮放級別。"
157 | L["Zoom in to this zoom level, if the current zoom level is greater than this."] = "如果當前縮放級別大於此值,則放大到這個縮放級別。"
158 | L["Zoom Min"] = "最小縮放"
159 | L["Zoom out to this zoom level, if the current zoom level is less than this."] = "如果當前縮放級別小於此值,則縮小到這個縮放級別。"
160 | L["Zoom Max"] = "最大縮放"
161 | L["Zoom in to this zoom level, if the current zoom level is greater than this."] = "如果當前縮放級別大於此值,則放大到這個縮放級別。"
162 | L["Restore Zoom"] = "恢復縮放"
163 | L[""] = "當您退出一個情境(或退出沒有活躍情境的預設狀態)時,當前的縮放級別會被臨時保存,以便下次進入此情境時可以恢復。在這裡,您可以選擇如何處理。\n\n此設置對所有情境都是全域的。"
164 | L["Restore Zoom Mode"] = "恢復縮放模式"
165 | L[""] = "\n從不:進入情境時,應用進入情境的實際縮放設置(如果有)。不考慮保存的縮放。\n\n總是:進入情境時,使用此情境上次保存的縮放。其實際設置僅在登錄後首次進入情境時考慮。\n\n自我調整:僅在某些情況下使用保存的縮放。例如,只有當返回到您來自的相同情境,或者保存的縮放滿足情境的“推近”、“拉遠”或“範圍”縮放設置的標準時。"
166 | L["Never"] = "從不"
167 | L["Always"] = "總是"
168 | L["Adaptive"] = "自我調整"
169 | L[""] = [[要確定當前的縮放級別,您可以使用“視覺輔助”(在DynamicCam的“滑鼠縮放”設置中切換)或使用控制台命令:
170 |
171 | /zoomInfo
172 |
173 | 或者簡寫為:
174 |
175 | /zi]]
176 | L["Rotation"] = "轉動"
177 | L["Start a camera rotation when this situation is active."] = "當此情境啟動時開始鏡頭轉動。"
178 | L["Reset to global defaults!\n(To restore the settings of a specific profile, restore the profile in the \"Profiles\" tab.)"] = "重置為全域預設值!\n(要恢復特定設定檔的設置,請在“設定檔”選項卡中恢復設定檔。)"
179 | L["Rotation Type"] = "轉動方式"
180 | L[""] = "\n持續轉動:當此情境啟動時,鏡頭會持續水準轉動。這只建議用於不使用滑鼠移動攝像機的情況;例如,傳送法術施放、飛行或離開。無法持續垂直轉動,因為它會在向上或向下垂直視角時停止。\n\n按度數轉動:進入情境後,根據給定的度數改變當前攝像機的水準偏轉(yaw)和/或垂直俯仰(pitch)。"
181 | L["Continuously"] = "持續轉動"
182 | L["By Degrees"] = "按角度轉動"
183 | L["Acceleration Time"] = "加速時間"
184 | L["Rotation Time"] = "轉動時間"
185 | L[""] = "如果您在這裡設置的時間大於0,持續轉動不會立即以全速開始,而是會花費這段時間來加速。(只有在相對較高的轉動速度下才會明顯感知。)"
186 | L[""] = "需要多長時間來調整到新的攝像機角度。如果這裡給出的值太小,攝像機可能會轉動過頭,因為我們每渲染一幀時只檢查一次是否達到了期望的角度。\n\n如果某個情境在其進入腳本中分配了變數“this.rotationTime”(參見“情境控制”),這裡的設置將被覆蓋。例如,在“爐石/傳送”情境中這樣做,以便為施法時間內塞入一個轉動時間。"
187 | L["Rotation Speed"] = "轉動速度"
188 | L["Speed at which to rotate in degrees per second. You can manually enter values between -900 and 900, if you want to get yourself really dizzy..."] = "每秒轉動的度數。如果您想讓自己真的頭暈目眩,可以手動輸入-900到900之間的值..."
189 | L["Yaw (-Left/Right+)"] = "偏轉(-左/右+)"
190 | L["Degrees to yaw (left or right)."] = "偏轉的度數(左或右)。"
191 | L["Pitch (-Down/Up+)"] = "俯仰(-下/上+)"
192 | L["Degrees to pitch (up or down). There is no going beyond the perpendicular upwards or downwards view."] = "俯仰的度數(上或下)。無法超過向上或向下的垂直視角。"
193 | L["Rotate Back"] = "轉動返回"
194 | L[""] = "退出情境時,按進入情境後轉動的度數(360)反向轉動。這實際上會將您帶回進入前的攝像機位置,除非您在此過程中用滑鼠改變了視角。\n\n如果您正在進入一個自帶轉動設置的新情境,那麼退出情境的“轉動返回”將被忽略。"
195 | L["Rotate Back Time"] = "轉動返回時間"
196 | L[""] = "轉動返回所需的時間。如果這裡給出的值太小,攝像機可能會轉動過頭,因為我們每渲染一幀時只檢查一次是否達到了期望的角度。"
197 | L["Fade Out UI"] = "漸隱介面"
198 | L["Fade out or hide (parts of) the UI when this situation is active."] = "當此情境啟動時,漸隱或隱藏(部分)使用者介面。"
199 | L["Reset to global defaults!\n(To restore the settings of a specific profile, restore the profile in the \"Profiles\" tab.)"] = "重置為全域預設值!\n(要恢復特定設定檔的設置,請在“設定檔”選項卡中恢復設定檔。)"
200 | L["Adjust to Immersion"] = "調整以適應沉浸"
201 | L[""] = "許多人將Immersion外掛程式與DynamicCam結合使用。Immersion在NPC互動期間有一些自己的隱藏UI特性。在某些情況下,DynamicCam的隱藏介面會覆蓋Immersion的設置。為了防止這種情況,您可以在DynamicCam中進行所需的設置。點擊此按鈕使用與Immersion相同的漸顯和漸隱時間。想要更多選項,請查看Ludius的另一個外掛程式“Immersion ExtraFade”。"
202 | L["Fade Out Time"] = "漸隱時間"
203 | L["Seconds it takes to fade out the UI when entering the situation."] = "進入情境時,介面漸隱所需的秒數。"
204 | L["Fade In Time"] = "漸顯時間"
205 | L[""] = "退出情境時,UI漸隱所需的秒數。\n\n當您在進入另一個情境的同時退出一個情境時,進入情境的漸隱時間將用於過渡。"
206 | L["Hide entire UI"] = "隱藏整個介面"
207 | L[""] = "“隱藏”的介面和“只是漸隱”的介面之間有區別:“漸隱”的介面元素的不透明度為0,但仍然可以與之交互。從DynamicCam 2.0開始,如果介面元素的不透明度為0,我們會自動隱藏大多數介面元素。因此,漸隱後隱藏整個介面的選項更像是一個遺留物。仍然使用它的原因可能是為了避免不希望的交互(例如滑鼠懸停提示)DynamicCam仍然沒有正確隱藏的介面元素。\n\n隱藏介面的不透明度當然是0,所以你不能選擇不同的不透明度,也不能保留任何介面元素可見(除了FPS指示器)。\n\n在戰鬥中我們不能改變受保護的介面元素的隱藏狀態。"
208 | L["Keep FPS indicator"] = "保留FPS指示器"
209 | L["Do not fade out or hide the FPS indicator (the one you typically toggle with Ctrl + R)."] = "不要漸隱或隱藏FPS指示器(通常用 Ctrl+R 切換的那個)。"
210 | L["Fade Opacity"] = "漸隱不透明度"
211 | L["Fade the UI to this opacity when entering the situation."] = "進入情境時將使用者介面漸隱到這種不透明度。"
212 | L["Excluded UI elements"] = "排除的使用者介面元素"
213 | L["Keep Alerts"] = "保留警告"
214 | L["Still show alert popups from completed achievements, Covenant Renown, etc."] = "仍然顯示來自完成成就、盟約聲望等的警告快顯視窗。"
215 | L["Keep Tooltip"] = "保留提示"
216 | L["Still show the game tooltip, which appears when you hover your mouse cursor over UI or world elements."] = "仍然顯示遊戲提示,當你將滑鼠游標懸停在使用者介面或世界元素上時出現。"
217 | L["Keep Minimap"] = "保留小地圖"
218 | L[""] = "不要漸隱小地圖。\n\n請注意,我們不能減少小地圖上“光點”的不透明度。當使用者介面漸隱到0不透明度時,這些只能與整個小地圖一起隱藏。"
219 | L["Keep Chat Box"] = "保留聊天框"
220 | L["Do not fade out the chat box."] = "不要漸隱聊天框。"
221 | L["Keep Tracking Bar"] = "保留追蹤條"
222 | L["Do not fade out the tracking bar (XP, AP, reputation)."] = "不要漸隱追蹤條(經驗值、能力點、聲望)。"
223 | L["Keep Party/Raid"] = "保留小隊/團隊框架"
224 | L["Do not fade out the Party/Raid frame."] = "不要漸隱小隊/團隊框架"
225 | L["Keep Encounter Frame (Dragonriding Vigor)"] = "保留遭遇框架(馭空術條)"
226 | L["Do not fade out the Encounter Frame, which while dragonriding is the Vigor display."] = "不要漸隱遭遇框架,在馭空術時是能量顯示。"
227 | L["Keep additional frames"] = "保留額外框架"
228 | L[""] = "下面的文字方塊允許你定義在NPC交互期間想要保留的任何框架。\n\n使用控制台命令/fstack來瞭解框架的名稱。\n\n例如,你可能想要保留小地圖旁邊的增益圖示,以便在NPC交互期間通過點擊適當的圖示來取消騎乘。"
229 | L["Custom frames to keep"] = "自訂保留框架"
230 | L["Separated by commas."] = "用逗號分隔。"
231 | L["Emergency Fade In"] = "緊急漸顯"
232 | L["Pressing Esc fades the UI back in."] = "按下Esc鍵將使用者介面漸顯回來。"
233 | L[""] = [[有時你可能希望在常態隱藏介面的情況下顯示介面。在舊版本的 DynamicCam 中有個規則,允許你在按下ESC鍵時顯示介面。但這樣做有個缺點,當ESC鍵用於其他作用,比如關閉視窗、取消施法等時,介面也會顯示。取消勾選上面的核取方塊可以禁用此功能。
234 |
235 | 但請注意,這樣可能會導致無法訪問介面!ESC鍵更好的替代方案是使用以下的控制台命令,它們會根據當前設置的“漸隱介面”設置顯示或隱藏介面:
236 |
237 | /showUI
238 | /hideUI
239 |
240 | 為了更加快捷的實現漸隱介面,將 /showUI 放入巨集命令中,並在"bindings-cache.wtf"檔中為其分配一個按鍵。例如:
241 |
242 | bind ALT+F11 MACRO 你的宏名稱
243 |
244 | 如果你不想編輯"bindings-cache.wtf"檔,可以使用類似"BindPad"這樣的按鍵綁定外掛程式。
245 |
246 | 使用 /showUI 或者 /hideUI 而不帶任何參數將採用當前情境的漸顯和漸隱時間。但你也可以使用參數提供不同的過渡時間。例如:
247 |
248 | /showUI 0
249 |
250 | 來實現立即顯示介面,沒有任何延遲。]]
251 | L[""] = "在設置你期望的介面漸隱效果時,如果這個“介面”設置框也一起漸隱,可能會很煩人。如果選中這個框,它將不會被漸隱。\n\n此設置適用於所有情況。"
252 | L["Do not fade out this \"Interface\" settings frame."] = "不要漸隱這個“介面”設置框。"
253 | L["Situation Controls"] = "情境控制"
254 | L[""] = "在這裡,你控制何時啟動一個情境。可能需要瞭解WoW UI API。如果你對DynamicCam的預設情況感到滿意,只需忽略此部分。但如果你想創建自訂情況,可以在這裡檢查默認情境。你也可以修改它們,但請注意:即使DynamicCam的未來版本引入了重要更新,你更改的設置也會保留。\n\n"
255 | L["Priority"] = "優先順序"
256 | L["The priority of this situation.\nMust be a number."] = "此情境的優先順序。\n必須是一個數字。"
257 | L["Restore stock setting"] = "恢復默認設置"
258 | L["Your \"Priority\" deviates from the stock setting for this situation ("] = "你的“優先順序”與此情境的默認設置不符("
259 | L["). Click here to restore it."] = ")。點擊這裡恢復它。"
260 | L[""] = "如果多個不同的DynamicCam情境的條件同時滿足,將進入優先順序最高的情境。例如,每當“世界室內”的條件滿足時,“世界”的條件也會滿足。但由於“世界室內”的優先順序高於“世界”,因此會優先選擇。你還可以在上方的下拉式功能表中看到所有情境的優先順序。\n\n"
261 | L["Error message:"] = "錯誤資訊:"
262 | L["Events"] = "事件"
263 | L["Separated by commas."] = "用逗號分隔。"
264 | L["Your \"Events\" deviate from the default for this situation. Click here to restore them."] = "你的“事件”與此情境的默認設置不同。點擊這裡恢復它們。"
265 | L[""] = [[在這裡,你可以定義所有遊戲中的事件,DynamicCam應該檢查這些事件的條件,以確定是否進入或退出當前情境。
266 |
267 | 你可以通過WoW的事件日誌瞭解遊戲中的事件。
268 | 要打開它,請在控制台中輸入以下命令:
269 |
270 | /eventtrace
271 |
272 | 所有可能的事件列表也可以在這裡找到:
273 | https://warcraft.wiki.gg/wiki/Events
274 |
275 | ]]
276 | L["Initialisation"] = "初始化"
277 | L["Initialisation Script"] = "初始化腳本"
278 | L["Lua code using the WoW UI API."] = "使用WoW UI API的Lua代碼。"
279 | L["Your \"Initialisation Script\" deviates from the stock setting for this situation. Click here to restore it."] = "你的“初始化腳本”與此情境的默認設置不同。點擊這裡恢復它。"
280 | L[""] = [[一個情境的初始化腳本在 DynamicCam 載入時(以及情境被修改時)運行一次。你通常會在其中放入你希望在其他任何腳本(條件、進入、退出)中應用的內容。這可以使這些腳本更短一些。
281 |
282 | 例如,“爐石/傳送”情境的初始化腳本定義了表格“this.spells”,其中包含了傳送法術的法術ID。然後,條件腳本每次執行時都可以簡單地訪問“this.spells”。
283 |
284 | 像這個例子一樣,你可以通過將資料物件放入“this”表格中,在情境的腳本之間共用任何資料物件。
285 |
286 | ]]
287 | L["Condition"] = "條件"
288 | L["Condition Script"] = "條件腳本"
289 | L["Lua code using the WoW UI API.\nShould return \"true\" if and only if the situation should be active."] = "使用WoW UI API的Lua代碼。\n只有在情境應該啟動時才返回“true”。"
290 | L["Your \"Condition Script\" deviates from the stock setting for this situation. Click here to restore it."] = "你的“條件腳本”與此情境的默認設置不同。點擊這裡恢復它。"
291 | L[""] = [[條件腳本在每次觸發此情境的遊戲內事件時運行。如果且僅當此情境應該處於活動狀態時,腳本應返回“true”。
292 |
293 | 例如,“城市”情境的條件腳本使用WoW API函數“IsResting()”來檢查你是否目前在休息區域:
294 |
295 | return IsResting()
296 |
297 | 同樣,“城市-室內”情境的條件腳本也使用WoW API函數“IsIndoors()”來檢查你是否在室內:
298 |
299 | return IsResting() and IsIndoors()
300 |
301 | 可以在此處找到WoW API函數的清單:
302 | https://warcraft.wiki.gg/wiki/World_of_Warcraft_API
303 |
304 | ]]
305 | L["Entering"] = "進入時"
306 | L["On-Enter Script"] = "進入時腳本"
307 | L["Your \"On-Enter Script\" deviates from the stock setting for this situation. Click here to restore it."] = "你的“進入時腳本”與此情境的默認設置不同。點擊此處恢復默認設置。"
308 | L[""] = [[情境帶有的進入時腳本在每次進入該情境時執行。
309 |
310 | 這方面的例子是“爐石/傳送”情境,我們使用WoW API函數"UnitCastingInfo()"來確定當前施法的持續時間。然後我們將這個值賦給變數"this.transitionTime"和"this.rotationTime",這樣縮放或轉動(見“情境指令”)可以精確地與施法時間一樣長。(不是所有傳送法術的施法時間都相同。)
311 |
312 | ]]
313 | L["Exiting"] = "退出時"
314 | L["On-Exit Script"] = "退出時腳本"
315 | L["Your \"On-Exit Script\" deviates from the stock setting for this situation. Click here to restore it."] = "你的“退出時腳本”與此情境的默認設置不同。點擊此處恢復默認設置。"
316 | L["Exit Delay"] = "退出延遲"
317 | L["Wait for this many seconds before exiting this situation."] = "在退出此情境前等待多少秒。"
318 | L["Your \"Exit Delay\" deviates from the stock setting for this situation. Click here to restore it."] = "你的“退出延遲”與此情境的默認設置不同。點擊此處恢復默認設置。"
319 | L[""] = [[情境帶有的退出時腳本在每次退出該情境時運行。到目前為止,還沒有情境使用這個功能。
320 |
321 | 延遲決定了在退出情境前需要等待多少秒。目前,唯一的例子是“釣魚”情境,其中的延遲給你時間重新拋出魚竿,而不會退出該情境。
322 |
323 | ]]
324 | L["Export"] = "匯出"
325 | L["Coming soon(TM)."] = "即將推出。"
326 | L["Import"] = "導入"
327 | L[""] = [[我們很高興你來到這裡,並希望你能享受這個外掛程式帶來的樂趣。
328 |
329 | DynamicCam(DC)由mpstark於2016年5月開始開發,當時暴雪的魔獸世界開發團隊引入了實驗性的ActionCam功能。DC的主要目的是為使用者提供ActionCam設置的使用者介面。在遊戲內,ActionCam仍被標記為“實驗性”,並且沒有跡象表明暴雪會進一步開發它。 雖然存在一些不足,但我們應該感激ActionCam被保留在遊戲中,讓我們這些愛好者能夠使用。:-) DC不僅允許你更改ActionCam設置,還能夠根據不同的遊戲情況設置不同的設置。與ActionCam無關,DC還提供了關於鏡頭縮放和介面漸隱的功能。
330 |
331 | mpstark對DC的工作一直持續到2018年8月。雖然大多數功能對大量用戶都運作良好,但mpstark一直認為DC處於測試階段,由於他對WoW的興趣逐漸減退,最終沒有恢復工作。那時,Ludius已經開始為自己調整DC,這被Weston(aka dernPerkins)注意到,他在2020年初設法聯繫到mpstark,牽頭讓Ludius接管了開發工作。第一個非測試版本1.0於2020年5月發佈,包括了Ludius到那時為止的調整。之後,Ludius開始對DC進行大修,使得2.0版本在2022年秋季發佈。
332 |
333 | 在mpstark初始開發DC時,他的重點是使大多數自訂設置都能在遊戲內完成,而不需要更改原始程式碼。這使得在不同的遊戲情境下進行實驗變得更加容易。從2.0版本開始,這些高級設置已經被移到一個名為“情境控制”的特殊部分。大多數使用者可能永遠也不需要它,但對於“高級用戶”來說,它仍然可用。在那裡進行更改的風險是,保存的用戶設置總是覆蓋DC的默認設置,即使新版本的DC帶來了更新的默認設置。因此,每當你啟動的情境有修改過的“情境控制”時,本頁面頂部會顯示一個警告。
334 |
335 | 如果你認為DC的某個默認情境應該被修改,你可以隨時創建一個帶有你個人色彩的副本。歡迎匯出這個新情境並在DC的curseforge頁面上發佈。我們可能會將其添加為一個新的默認情境。你也可以匯出並發佈你的整個DC設定檔,因為我們總是在尋找新的配置預設,這可以讓新用戶更容易地開始使用DC。如果你發現問題或想要提出建議,請在curseforge評論中留言,當然更好的是使用GitHub上的Issues。如果你想貢獻代碼,也歡迎在那裡打開一個拉取請求。
336 |
337 | 以下是一些方便的命令:
338 |
339 | `/dynamiccam` 或 `/dc` 打開這個頁面。
340 | `/zoominfo` 或 `/zi` 輸出當前的縮放級別。
341 |
342 | `/zoom #1 #2` 在 #2 秒內縮放到 #1 縮放級別。
343 | `/yaw #1 #2` 在 #2 秒內使鏡頭偏轉 #1 度(負 #1 偏航到右邊)。
344 | `/pitch #1 #2` 使鏡頭俯仰 #1 度(負 #1 向上俯仰)。
345 |
346 |
347 | ]]
348 | L["About"] = "關於"
349 | L["The following game situations have \"Situation Controls\" deviating from DynamicCam's stock settings.\n\n"] = "以下遊戲情境的“情境控制”與DynamicCam的默認設置不同。\n\n"
350 | L[""] = "\n如果你是刻意為之的,那沒有問題。只是要注意,DynamicCam開發者對這些設置的任何更新總是會被你修改過的(可能過時的)版本覆蓋。你可以查看每種情境的“情境控制”標籤以獲取詳細資訊。如果你沒有意識到任何來自你的“情境控制”修改,並且只是想恢復所有情境的默認控制設置,請點擊這個按鈕:"
351 | L["Restore all stock Situation Controls"] = "恢復所有默認情境控制"
352 | L["Hello and welcome to DynamicCam!"] = "你好,歡迎來到DynamicCam!"
353 | L["Profiles"] = "設定檔"
354 | L["Manage Profiles"] = "管理設定檔"
355 | L[""] = "像許多外掛程式一樣,DynamicCam使用“AceDB-3.0”庫來管理設定檔。你需要明白的是,這裡沒有“保存設定檔”這樣的操作。你只能創建新的設定檔,並且你可以從另一個設定檔複製設置到當前啟動的設定檔中。你對當前啟動的設定檔所做的任何更改都會立即保存!這裡沒有“取消”或“放棄更改”的操作。“重置設定檔”按鈕只會重置為全域默認設定檔。\n\n所以如果你喜歡你的DynamicCam設置,你應該創建另一個設定檔,並將這些設置複製進去作為備份。當你不使用這個備份設定檔作為你的啟動設定檔時,你可以隨意嘗試更改設置,並隨時通過在“從...複製”框中選擇你的備份設定檔來恢復到你原來的設定檔。\n\n如果你想通過宏來切換設定檔,你可以使用以下代碼:\n/run DynamicCam.db:SetProfile(\"設定檔名\")\n\n"
356 | L["Profile presets"] = "預設設定檔"
357 | L["Import / Export"] = "導入/匯出"
358 | L["DynamicCam"] = "DynamicCam"
359 | L["Disabled"] = "禁用"
360 | L["Your DynamicCam addon lets you adjust horizontal and vertical mouse look speed individually! Just go to the \"Mouse Look\" settings of DynamicCam to make the adjustments there."] = "你的DynamicCam外掛程式允許你單獨調整水準和垂直滑鼠視角速度!只需前往DynamicCam的“滑鼠視角”設置中進行調整。"
361 | L["Attention"] = "注意"
362 | L["The \""] = "這個\""
363 | L["\" setting is disabled by DynamicCam, while you are using the horizontal camera over shoulder offset."] = "\"設置被DynamicCam禁用,當你使用水準鏡頭肩部偏移時。"
364 | L["While you are using horizontal camera offset, DynamicCam prevents CameraKeepCharacterCentered!"] = "當你使用水準鏡頭偏移時,DynamicCam會阻止CameraKeepCharacterCentered起效!"
365 | L["While you are using horizontal camera offset, DynamicCam prevents CameraReduceUnexpectedMovement!"] = "當你使用水準鏡頭偏移時,DynamicCam會阻止CameraReduceUnexpectedMovement起效!"
366 | L["While you are using vertical camera pitch, DynamicCam prevents CameraKeepCharacterCentered!"] = "當你使用垂直鏡頭俯仰時,DynamicCam會阻止CameraKeepCharacterCentered起效!"
367 | L["cameraView ="] = "鏡頭視角 ="
368 | L["prevented by DynamicCam!"] = "被DynamicCam阻止!"
369 |
370 | -- MouseZoom
371 | L["Actual\nZoom\nValue"] = "實際\n縮放值"
372 | L["Reactive\nZoom\nTarget"] = "響應\n縮放目標"
373 |
374 | -- Core
375 | L["Enter name for custom situation:"] = "輸入自訂情境的名稱:"
376 | L["Create"] = "創建"
377 | L["Cancel"] = "取消"
378 |
379 | -- DefaultSettings
380 | L["City"] = "城市"
381 | L["City (Indoors)"] = "城市(室內)"
382 | L["World"] = "世界"
383 | L["World (Indoors)"] = "世界(室內)"
384 | L["World (Combat)"] = "世界(戰鬥)"
385 | L["Dungeon/Scenerio"] = "地下城/場景戰役"
386 | L["Dungeon/Scenerio (Outdoors)"] = "地下城/場景戰役(戶外)"
387 | L["Dungeon/Scenerio (Combat, Boss)"] = "地下城/場景戰役(戰鬥,首領)"
388 | L["Dungeon/Scenerio (Combat, Trash)"] = "地下城/場景戰役(戰鬥,小怪)"
389 | L["Raid"] = "團隊副本"
390 | L["Raid (Outdoors)"] = "團隊副本(戶外)"
391 | L["Raid (Combat, Boss)"] = "團隊副本(戰鬥,首領)"
392 | L["Raid (Combat, Trash)"] = "團隊副本(戰鬥,小怪)"
393 | L["Arena"] = "競技場"
394 | L["Arena (Combat)"] = "競技場(戰鬥)"
395 | L["Battleground"] = "戰場"
396 | L["Battleground (Combat)"] = "戰場(戰鬥)"
397 | L["Mounted (any)"] = "騎乘(任意)"
398 | L["Mounted (only flying-mount)"] = "騎乘(僅限飛行坐騎)"
399 | L["Mounted (only flying-mount + airborne)"] = "騎乘(僅限飛行坐騎 + 空中)"
400 | L["Mounted (only flying-mount + airborne + Skyriding)"] = "騎乘(僅限飛行坐騎 + 空中 + 馭空術)"
401 | L["Mounted (only flying-mount + Skyriding)"] = "騎乘(僅限飛行坐騎 + 馭空術)"
402 | L["Mounted (only airborne)"] = "騎乘(僅限空中)"
403 | L["Mounted (only airborne + Skyriding)"] = "騎乘(僅限空中 + 馭空術)"
404 | L["Mounted (only Skyriding)"] = "騎乘(僅限馭空術)"
405 | L["Druid Travel Form"] = "德魯伊旅行形態"
406 | L["Dracthyr Soar"] = "馭龍術"
407 | L["Skyriding Race"] = "馭空競速"
408 | L["Taxi"] = "計程車(飛行點交通)"
409 | L["Vehicle"] = "載具"
410 | L["Hearth/Teleport"] = "爐石/傳送"
411 | L["Annoying Spells"] = "煩人的技能"
412 | L["NPC Interaction"] = "與NPC互動"
413 | L["Mailbox"] = "郵箱"
414 | L["Fishing"] = "釣魚"
415 | L["Gathering"] = "採集"
416 | L["AFK"] = "暫離"
417 | L["Pet Battle"] = "寵物對戰"
418 |
419 |
--------------------------------------------------------------------------------
/MouseZoom.lua:
--------------------------------------------------------------------------------
1 | local LibCamera = LibStub("LibCamera-1.0")
2 | local LibEasing = LibStub("LibEasing-1.0")
3 | local L = LibStub("AceLocale-3.0"):GetLocale("DynamicCam")
4 |
5 |
6 | ------------
7 | -- LOCALS --
8 | ------------
9 |
10 | local function Round(num, numDecimalPlaces)
11 | local mult = 10^(numDecimalPlaces or 0)
12 | return math.floor(num * mult + 0.5) / mult
13 | end
14 |
15 |
16 |
17 |
18 | -------------------------
19 | -- Minimal Zoom-Level --
20 | -------------------------
21 |
22 |
23 | -- When zooming in, the mimimal third person zoom value depends on the current model.
24 | -- We store this in a SaveVariable.
25 |
26 | -- Initialize the SaveVariable if it does not yet exist.
27 | if not minZoomValues then
28 | minZoomValues = {}
29 | end
30 |
31 |
32 | local function SetMinZoom(zoom)
33 | if not DynamicCam.modelFrame then return end
34 |
35 | DynamicCam.modelFrame:SetUnit("player")
36 | -- print("Storing", zoom, "for", DynamicCam.modelFrame:GetModelFileID())
37 | minZoomValues[DynamicCam.modelFrame:GetModelFileID()] = zoom
38 | end
39 |
40 | local function GetMinZoom()
41 | if IsMounted() then
42 | -- For mounted we just take a default instead of storing the value for each mount and player-model.
43 | return 1.5
44 | else
45 |
46 | if not DynamicCam.modelFrame then return 0.5 end
47 |
48 | -- If we have already stored the minimum value, return it. Else use a default.
49 | DynamicCam.modelFrame:SetUnit("player")
50 | return minZoomValues[DynamicCam.modelFrame:GetModelFileID()] or 1.5
51 | end
52 | end
53 |
54 | -- Set to true when zooming out from first person, such that the next zoom is stored as min value.
55 | local storeMinZoom = false
56 |
57 |
58 |
59 |
60 |
61 | -----------------------
62 | -- NON-REACTIVE ZOOM --
63 | -----------------------
64 |
65 |
66 | -- To indicate if a non-reactive zoom is in progress.
67 | -- This is needed to correct reactiveZoomTarget in case the target is missed.
68 | local nonReactiveZoomStarted = false
69 | local nonReactiveZoomInProgress = false
70 | local nonReactiveZoomStartValue = GetCameraZoom()
71 |
72 |
73 | local OldCameraZoomIn = CameraZoomIn
74 | local OldCameraZoomOut = CameraZoomOut
75 |
76 |
77 |
78 | -- Notice: The feature of zooming to the smallest third person zoom level does only work good for ReactiveZoom.
79 | -- In NonReactiveZoom it only works if you set the zoom speed to max.
80 | -- That's why we are not doing it for NonReactiveZoom.
81 | local function NonReactiveZoom(zoomIn, increments)
82 | -- print("NonReactiveZoom", zoomIn, increments, GetCameraZoom())
83 |
84 | -- Stop zooming that might currently be in progress from a situation change.
85 | LibCamera:StopZooming(true)
86 |
87 | -- If we are not using this from within ReactiveZoom, we can also use the increment multiplier here.
88 | if not DynamicCam:GetSettingsValue(DynamicCam.currentSituationID, "reactiveZoomEnabled") then
89 | increments = increments + DynamicCam:GetSettingsValue(DynamicCam.currentSituationID, "reactiveZoomAddIncrementsAlways")
90 |
91 | else
92 | -- print("NonReactiveZoom starting", GetCameraZoom(), GetTime())
93 | nonReactiveZoomStarted = true
94 | nonReactiveZoomInProgress = false
95 | nonReactiveZoomStartValue = GetCameraZoom()
96 | end
97 |
98 | if zoomIn then
99 | OldCameraZoomIn(increments)
100 | else
101 | OldCameraZoomOut(increments)
102 | end
103 | end
104 |
105 |
106 | local function NonReactiveZoomIn(increments)
107 | -- No idea, why WoW does in-out-in-out with increments 0 after each mouse wheel turn.
108 | if increments == 0 then return end
109 | NonReactiveZoom(true, increments)
110 | end
111 |
112 | local function NonReactiveZoomOut(increments)
113 | -- No idea, why WoW does in-out-in-out with increments 0 after each mouse wheel turn.
114 | if increments == 0 then return end
115 |
116 | if storeMinZoom then
117 | -- print("User zoomed out again before reaching min value. Interrupting store process.")
118 | storeMinZoom = false
119 | end
120 |
121 | NonReactiveZoom(false, increments)
122 | end
123 |
124 |
125 |
126 |
127 | -------------------
128 | -- REACTIVE ZOOM --
129 | -------------------
130 |
131 | local reactiveZoomTarget = nil
132 |
133 | -- We have to be able to set this to nil whenever
134 | -- SetZoom() or SetView() happens. Otherwise, the
135 | -- next scroll wheel turn will scroll back
136 | -- to the last zoom position.
137 | function DynamicCam:ResetReactiveZoomTarget()
138 | reactiveZoomTarget = nil
139 | end
140 |
141 |
142 |
143 |
144 | -- This is needed to correct reactiveZoomTarget in case the target is missed.
145 | local lastZoomForCorrection = GetCameraZoom()
146 |
147 | local function ReactiveZoomTargetCorrectionFunction(_, elapsed)
148 |
149 | if not DynamicCam:GetSettingsValue(DynamicCam.currentSituationID, "reactiveZoomEnabled") then return end
150 |
151 | local currentZoom = GetCameraZoom()
152 |
153 | if nonReactiveZoomStarted and nonReactiveZoomStartValue ~= currentZoom then
154 | -- print("NonReactiveZoom just Started", nonReactiveZoomStartValue, GetTime())
155 | nonReactiveZoomInProgress = true
156 | nonReactiveZoomStarted = false
157 | elseif nonReactiveZoomInProgress and lastZoomForCorrection == currentZoom then
158 | -- print("NonReactiveZoom finished", GetTime())
159 | nonReactiveZoomInProgress = false
160 | end
161 |
162 | if not LibCamera:IsZooming() and not nonReactiveZoomStarted and not nonReactiveZoomInProgress and reactiveZoomTarget ~= currentZoom then
163 | -- print("Correcting reactiveZoomTarget", reactiveZoomTarget, "to", currentZoom, GetTime())
164 | reactiveZoomTarget = currentZoom
165 |
166 | if storeMinZoom then
167 | SetMinZoom(currentZoom)
168 | storeMinZoom = false
169 | end
170 | end
171 |
172 | lastZoomForCorrection = currentZoom
173 | end
174 |
175 | local reactiveZoomTargetCorrectionFrame = CreateFrame("Frame")
176 |
177 |
178 |
179 |
180 | local function ReactiveZoom(zoomIn, increments)
181 | -- print("ReactiveZoom", zoomIn, increments, reactiveZoomTarget)
182 |
183 | increments = increments or 1
184 |
185 | -- If this is a "mouse wheel" CameraZoomIn/CameraZoomOut, increments is 1.
186 | -- Unlike a CameraZoomIn/CameraZoomOut from within LibCamera.SetZoomUsingCVar().
187 | if increments == 1 then
188 | local currentZoom = GetCameraZoom()
189 |
190 | local addIncrementsAlways = DynamicCam:GetSettingsValue(DynamicCam.currentSituationID, "reactiveZoomAddIncrementsAlways")
191 | local addIncrements = DynamicCam:GetSettingsValue(DynamicCam.currentSituationID, "reactiveZoomAddIncrements")
192 | local maxZoomTime = DynamicCam:GetSettingsValue(DynamicCam.currentSituationID, "reactiveZoomMaxZoomTime")
193 | local incAddDifference = DynamicCam:GetSettingsValue(DynamicCam.currentSituationID, "reactiveZoomIncAddDifference")
194 | local easingFunc = DynamicCam:GetSettingsValue(DynamicCam.currentSituationID, "reactiveZoomEasingFunc")
195 |
196 |
197 | -- scale increments up
198 | increments = increments + addIncrementsAlways
199 |
200 | if reactiveZoomTarget and math.abs(reactiveZoomTarget - currentZoom) > incAddDifference then
201 | increments = increments + addIncrements
202 | end
203 |
204 |
205 |
206 | -- if we've changed directions, make sure to reset
207 | if zoomIn then
208 | if reactiveZoomTarget and reactiveZoomTarget > currentZoom then
209 | reactiveZoomTarget = nil
210 | end
211 | else
212 | if reactiveZoomTarget and reactiveZoomTarget < currentZoom then
213 | reactiveZoomTarget = nil
214 | end
215 | end
216 |
217 | -- if there is already a target zoom, base off that one, or just use the current zoom
218 | reactiveZoomTarget = reactiveZoomTarget or currentZoom
219 |
220 |
221 | -- Always stop at closest third person zoom level.
222 | local minZoom = GetMinZoom()
223 |
224 | if zoomIn then
225 |
226 | if reactiveZoomTarget - increments < minZoom then
227 |
228 | if reactiveZoomTarget > minZoom then
229 | -- print("go to minZoom", minZoom)
230 | reactiveZoomTarget = minZoom
231 |
232 | -- Also update the increments if we need to make a NonReactiveZoom below,
233 | -- in case of "zoomTime < secondsPerFrame".
234 | increments = currentZoom - minZoom
235 | else
236 | -- print("go to 0")
237 | reactiveZoomTarget = 0
238 |
239 | -- No need to update increments because any zoom target below minZoom
240 | -- will result in 0 automatically.
241 | end
242 |
243 | else
244 | reactiveZoomTarget = math.max(0, reactiveZoomTarget - increments)
245 | end
246 |
247 |
248 | -- zoom out
249 | else
250 |
251 | -- From first person go directly into closest third person.
252 | if currentZoom == 0 then
253 | -- print("Giving this to non-reactive zoom")
254 | NonReactiveZoomOut(0.05)
255 |
256 | -- When this zoom is finished, store the minimal zoom distance,
257 | -- such that we can also use it while zooming in.
258 | if not IsMounted() then
259 | storeMinZoom = true
260 | end
261 |
262 | return
263 | else
264 | reactiveZoomTarget = math.min(GetCVar("cameraDistanceMaxZoomFactor")*15, reactiveZoomTarget + increments)
265 | end
266 | end
267 |
268 |
269 | -- if we don't need to zoom because we're at the max limits, then don't
270 | if (reactiveZoomTarget == DynamicCam.cameraDistanceMaxZoomFactor_max and currentZoom == DynamicCam.cameraDistanceMaxZoomFactor_max) or (reactiveZoomTarget == 0 and currentZoom == 0) then
271 | return
272 | end
273 |
274 |
275 | -- get the current time to zoom if we were going linearly or use maxZoomTime, if that's too high
276 | local zoomTime = math.min(maxZoomTime, math.abs(reactiveZoomTarget - currentZoom) / tonumber(GetCVar("cameraZoomSpeed")) )
277 |
278 |
279 | -- print ("Want to get from", currentZoom, "to", reactiveZoomTarget, "in", zoomTime, "with one frame being", DynamicCam.secondsPerFrame)
280 | if zoomTime < DynamicCam.secondsPerFrame then
281 | -- print("No easing for you", zoomTime, DynamicCam.secondsPerFrame, increments)
282 |
283 | if zoomIn then
284 | NonReactiveZoomIn(increments)
285 | else
286 | NonReactiveZoomOut(increments)
287 | end
288 | else
289 | -- print("REACTIVE ZOOM start", GetTime())
290 | -- LibCamera:SetZoom(reactiveZoomTarget, zoomTime, LibEasing[easingFunc], function() print("REACTIVE ZOOM end", GetTime()) end)
291 | LibCamera:SetZoom(reactiveZoomTarget, zoomTime, LibEasing[easingFunc])
292 | end
293 |
294 | else
295 | -- Called from within LibCamera.SetZoomUsingCVar(), through SetZoom() when the target zoom was missed.
296 | -- print("...this is no mouse wheel call!", increments)
297 |
298 | if zoomIn then
299 | NonReactiveZoomIn(increments)
300 | else
301 | NonReactiveZoomOut(increments)
302 | end
303 | end
304 | end
305 |
306 |
307 | local function ReactiveZoomIn(increments)
308 | -- No idea, why WoW does in-out-in-out with increments 0 after each mouse wheel turn.
309 | if increments == 0 then return end
310 | ReactiveZoom(true, increments)
311 | end
312 |
313 | local function ReactiveZoomOut(increments)
314 | -- No idea, why WoW does in-out-in-out with increments 0 after each mouse wheel turn.
315 | if increments == 0 then return end
316 |
317 | if storeMinZoom then
318 | -- print("User zoomed out again before reaching min value. Interrupting store process.")
319 | storeMinZoom = false
320 | end
321 |
322 | ReactiveZoom(false, increments)
323 | end
324 |
325 |
326 | function DynamicCam:ReactiveZoomOn()
327 | -- print("ReactiveZoomOn()")
328 | if CameraZoomIn == ReactiveZoomIn then
329 | -- print("already on")
330 | return
331 | end
332 |
333 | CameraZoomIn = ReactiveZoomIn
334 | CameraZoomOut = ReactiveZoomOut
335 |
336 | reactiveZoomTarget = GetCameraZoom()
337 | reactiveZoomTargetCorrectionFrame:SetScript("OnUpdate", ReactiveZoomTargetCorrectionFunction)
338 | end
339 |
340 | function DynamicCam:ReactiveZoomOff()
341 | -- print("ReactiveZoomOff()")
342 | if CameraZoomIn == NonReactiveZoomIn then
343 | -- print("already off")
344 | return
345 | end
346 |
347 | CameraZoomIn = NonReactiveZoomIn
348 | CameraZoomOut = NonReactiveZoomOut
349 |
350 | reactiveZoomTarget = nil
351 | reactiveZoomTargetCorrectionFrame:SetScript("OnUpdate", nil)
352 | end
353 |
354 |
355 | function DynamicCam:ReactiveZoomIsOn()
356 | return CameraZoomIn == ReactiveZoomIn
357 | end
358 |
359 |
360 |
361 | ------------------------------------
362 | -- ReactiveZoom Visual Aid (RZVA) --
363 | ------------------------------------
364 |
365 | local function DrawLine(f, startRelativeAnchor, startOffsetX, startOffsetY,
366 | endRelativeAnchor, endOffsetX, endOffsetY,
367 | thickness, r, g, b, a)
368 |
369 | local line = f:CreateLine()
370 | line:SetThickness(thickness)
371 | line:SetColorTexture(r, g, b, a)
372 | line:SetStartPoint(startRelativeAnchor, f, startOffsetX, startOffsetY)
373 | line:SetEndPoint(endRelativeAnchor, f, endOffsetX, endOffsetY)
374 |
375 | end
376 |
377 |
378 | local function SetFrameBorder(f, thickness, r, g, b, a)
379 | -- Bottom line.
380 | DrawLine(f, "BOTTOMLEFT", 0, 0, "BOTTOMRIGHT", 0, 0, thickness, r, g, b, a)
381 | -- Top line.
382 | DrawLine(f, "TOPLEFT", 0, 0, "TOPRIGHT", 0, 0, thickness, r, g, b, a)
383 | -- Left line.
384 | DrawLine(f, "BOTTOMLEFT", 0, 0, "TOPLEFT", 0, 0, thickness, r, g, b, a)
385 | -- Right line.
386 | DrawLine(f, "BOTTOMRIGHT", 0, 0, "TOPRIGHT", 0, 0, thickness, r, g, b, a)
387 | end
388 |
389 |
390 | local rzvaWidth = 120
391 | local rzvaHeight = 200
392 | local rzvaHalfWidth = rzvaWidth/2
393 |
394 | local rzvaFrame = nil
395 |
396 | local lastReactiveZoomTarget = reactiveZoomTarget
397 | local reactiveZoomGraphUpdateFrame = CreateFrame("Frame")
398 |
399 |
400 | local function ReactiveZoomGraphUpdateFunction()
401 |
402 | rzvaFrame.zm:ClearAllPoints()
403 | rzvaFrame.zm:SetPoint("BOTTOMRIGHT", 0, rzvaFrame:GetHeight() - (rzvaFrame:GetHeight() * GetCameraZoom() / DynamicCam.cameraDistanceMaxZoomFactor_max) )
404 | rzvaFrame.cameraZoomValue:SetText(Round(GetCameraZoom(), 3))
405 |
406 | if DynamicCam:GetSettingsValue(DynamicCam.currentSituationID, "reactiveZoomEnabled") then
407 |
408 | if not rzvaFrame.rzt:IsShown() then
409 | rzvaFrame.rzt:Show()
410 | rzvaFrame.rzi:Show()
411 | rzvaFrame.reactiveZoomTargetLabel:SetTextColor(.3, .3, 1, 1)
412 | rzvaFrame.reactiveZoomTargetValue:SetTextColor(.3, .3, 1, 1)
413 | end
414 |
415 | rzvaFrame.rzt:ClearAllPoints()
416 | if reactiveZoomTarget then
417 | rzvaFrame.rzt:SetPoint("BOTTOMLEFT", 0, rzvaFrame:GetHeight() - (rzvaFrame:GetHeight()* reactiveZoomTarget / DynamicCam.cameraDistanceMaxZoomFactor_max) )
418 |
419 | rzvaFrame.reactiveZoomTargetValue:SetText(Round(reactiveZoomTarget, 3))
420 |
421 | if lastReactiveZoomTarget then
422 |
423 | local step = lastReactiveZoomTarget - reactiveZoomTarget
424 |
425 | if step > 0 then
426 | rzvaFrame.rzi:SetHeight(rzvaFrame:GetHeight() * step / DynamicCam.cameraDistanceMaxZoomFactor_max)
427 | rzvaFrame.rzi:Show()
428 | elseif step < 0 then
429 | rzvaFrame.rzi:SetHeight(rzvaFrame:GetHeight() * step / DynamicCam.cameraDistanceMaxZoomFactor_max)
430 | rzvaFrame.rzi:Show()
431 | else
432 | rzvaFrame.rzi:Hide()
433 | end
434 |
435 | end
436 |
437 | lastReactiveZoomTarget = reactiveZoomTarget
438 |
439 | else
440 | rzvaFrame.rzi:Hide()
441 | rzvaFrame.rzt:Hide()
442 | rzvaFrame.reactiveZoomTargetValue:SetText("---")
443 | end
444 |
445 | else
446 | if rzvaFrame.rzt:IsShown() then
447 | rzvaFrame.rzt:Hide()
448 | rzvaFrame.rzi:Hide()
449 | rzvaFrame.reactiveZoomTargetLabel:SetTextColor(.3, .3, .3, 1)
450 | rzvaFrame.reactiveZoomTargetValue:SetTextColor(.3, .3, .3, 1)
451 | rzvaFrame.reactiveZoomTargetValue:SetText("---")
452 | end
453 | end
454 | end
455 |
456 |
457 |
458 | function DynamicCam:ToggleRZVA()
459 |
460 | if not rzvaFrame then
461 |
462 | rzvaFrame = CreateFrame("Frame", "reactiveZoomVisualAid", UIParent)
463 | rzvaFrame:SetFrameStrata("TOOLTIP")
464 | rzvaFrame:SetMovable(true)
465 | rzvaFrame:EnableMouse(true)
466 | rzvaFrame:RegisterForDrag("LeftButton")
467 | rzvaFrame:SetScript("OnDragStart", rzvaFrame.StartMoving)
468 | rzvaFrame:SetScript("OnDragStop", rzvaFrame.StopMovingOrSizing)
469 | rzvaFrame:SetClampedToScreen(true)
470 |
471 | -- Closes with right button.
472 | rzvaFrame:SetScript("OnMouseDown", function(self, button)
473 | if button == "RightButton" then
474 | self:Hide()
475 | end
476 | end)
477 |
478 |
479 | rzvaFrame:SetWidth(rzvaWidth)
480 | rzvaFrame:SetHeight(rzvaHeight)
481 | rzvaFrame:ClearAllPoints()
482 | rzvaFrame:SetPoint("BOTTOMLEFT", SettingsPanel.Container, "BOTTOMLEFT", 45, 35)
483 |
484 | rzvaFrame.t = rzvaFrame:CreateTexture()
485 | rzvaFrame.t:SetAllPoints()
486 | rzvaFrame.t:SetTexture("Interface/BUTTONS/WHITE8X8")
487 | rzvaFrame.t:SetColorTexture(1, 1, 1, .1)
488 |
489 | SetFrameBorder(rzvaFrame, 2, 1, 1, 1, 1)
490 |
491 |
492 | rzvaFrame.cameraZoomLabel = rzvaFrame:CreateFontString()
493 | rzvaFrame.cameraZoomLabel:SetWidth(rzvaHalfWidth)
494 | rzvaFrame.cameraZoomLabel:SetJustifyH("CENTER")
495 | rzvaFrame.cameraZoomLabel:SetJustifyV("MIDDLE")
496 | rzvaFrame.cameraZoomLabel:SetPoint("BOTTOMRIGHT", rzvaFrame, "TOPRIGHT", 0, 19)
497 | rzvaFrame.cameraZoomLabel:SetFont("Fonts/FRIZQT__.TTF", 12)
498 | rzvaFrame.cameraZoomLabel:SetTextColor(1, .3, .3, 1)
499 | rzvaFrame.cameraZoomLabel:SetText(L["Actual\nZoom\nValue"])
500 |
501 | rzvaFrame.cameraZoomValue = rzvaFrame:CreateFontString()
502 | rzvaFrame.cameraZoomValue:SetWidth(rzvaHalfWidth)
503 | rzvaFrame.cameraZoomValue:SetJustifyH("CENTER")
504 | rzvaFrame.cameraZoomValue:SetJustifyV("MIDDLE")
505 | rzvaFrame.cameraZoomValue:SetPoint("BOTTOMRIGHT", rzvaFrame, "TOPRIGHT", 0, 4)
506 | rzvaFrame.cameraZoomValue:SetFont("Fonts/FRIZQT__.TTF", 14)
507 | rzvaFrame.cameraZoomValue:SetTextColor(1, .3, .3, 1)
508 | rzvaFrame.cameraZoomValue:SetText(GetCameraZoom())
509 |
510 |
511 | rzvaFrame.reactiveZoomTargetLabel = rzvaFrame:CreateFontString()
512 | rzvaFrame.reactiveZoomTargetLabel:SetWidth(rzvaHalfWidth)
513 | rzvaFrame.reactiveZoomTargetLabel:SetJustifyH("CENTER")
514 | rzvaFrame.reactiveZoomTargetLabel:SetJustifyV("MIDDLE")
515 | rzvaFrame.reactiveZoomTargetLabel:SetPoint("BOTTOMLEFT", rzvaFrame, "TOPLEFT", 0, 19)
516 | rzvaFrame.reactiveZoomTargetLabel:SetFont("Fonts/FRIZQT__.TTF", 12)
517 | rzvaFrame.reactiveZoomTargetLabel:SetTextColor(.3, .3, 1, 1)
518 | rzvaFrame.reactiveZoomTargetLabel:SetText(L["Reactive\nZoom\nTarget"])
519 |
520 | rzvaFrame.reactiveZoomTargetValue = rzvaFrame:CreateFontString()
521 | rzvaFrame.reactiveZoomTargetValue:SetWidth(rzvaHalfWidth)
522 | rzvaFrame.reactiveZoomTargetValue:SetJustifyH("CENTER")
523 | rzvaFrame.reactiveZoomTargetValue:SetJustifyV("MIDDLE")
524 | rzvaFrame.reactiveZoomTargetValue:SetPoint("BOTTOMLEFT", rzvaFrame, "TOPLEFT", 0, 4)
525 | rzvaFrame.reactiveZoomTargetValue:SetFont("Fonts/FRIZQT__.TTF", 14)
526 | rzvaFrame.reactiveZoomTargetValue:SetTextColor(.3, .3, 1, 1)
527 |
528 |
529 |
530 | rzvaFrame.zm = CreateFrame("Frame", "cameraZoomMarker", rzvaFrame)
531 | rzvaFrame.zm:SetWidth(rzvaHalfWidth)
532 | rzvaFrame.zm:SetHeight(1)
533 | rzvaFrame.zm:Show()
534 | DrawLine(rzvaFrame.zm, "BOTTOMLEFT", 0, 0, "BOTTOMRIGHT", 0, 0, 5, 1, .3, .3, 1)
535 |
536 |
537 | rzvaFrame.rzt = CreateFrame("Frame", "reactiveZoomTargetMarker", rzvaFrame)
538 | rzvaFrame.rzt:SetWidth(rzvaHalfWidth)
539 | rzvaFrame.rzt:SetHeight(1)
540 | rzvaFrame.rzt:Show()
541 | DrawLine(rzvaFrame.rzt, "BOTTOMRIGHT", 0, 0, "BOTTOMLEFT", 0, 0, 5, .3, .3, 1, 1)
542 |
543 |
544 | rzvaFrame.rzi = CreateFrame("Frame", "reactiveZoomIncrementMarker", rzvaFrame)
545 | rzvaFrame.rzi:SetWidth(rzvaHalfWidth)
546 | -- Must set points here, otherwise the texture is not created...
547 | rzvaFrame.rzi:SetPoint("TOP", rzvaFrame.rzt, "BOTTOM", 0, 0)
548 | rzvaFrame.rzi.t = rzvaFrame.rzi:CreateTexture()
549 | rzvaFrame.rzi.t:SetAllPoints()
550 | rzvaFrame.rzi.t:SetTexture("Interface/BUTTONS/WHITE8X8")
551 | rzvaFrame.rzi.t:SetColorTexture(1, 1, 0, 1)
552 |
553 | rzvaFrame:Hide()
554 |
555 |
556 | rzvaFrame:HookScript("OnShow", function()
557 | reactiveZoomGraphUpdateFrame:SetScript("OnUpdate", ReactiveZoomGraphUpdateFunction)
558 | end)
559 |
560 | rzvaFrame:HookScript("OnHide", function()
561 | reactiveZoomGraphUpdateFrame:SetScript("OnUpdate", nil)
562 | end)
563 | end
564 |
565 | if not rzvaFrame:IsShown() then
566 | rzvaFrame:Show()
567 | else
568 | rzvaFrame:Hide()
569 | end
570 |
571 | end
572 |
573 |
574 |
--------------------------------------------------------------------------------
/Presets.lua:
--------------------------------------------------------------------------------
1 | -------------
2 | -- GLOBALS --
3 | -------------
4 | assert(DynamicCam)
5 |
6 |
7 | ------------
8 | -- LOCALS --
9 | ------------
10 | local presets = {
11 |
12 | ["Immersive"] = {
13 | author = "LudiusMaximus",
14 | description = "Some settings to make gameplay more immersive:\n-Slight shoulder offset, but not while in dungeons/raids.\n-Go to view 2 during NPC/Mailbox interaction.\n-Go to view 3 and start rotating when teleporting.\n\nNOTICE: You have to setup the views yourself! E.g. while interacting with an NPC, put the camera into a position you like, then type '/sv 2' into the console to store it. Similarly, find a good camera view facing your character from the right and type '/sv 3' to store it as the teleport start view.",
15 | importString = "dqZwjaGEQe7sjABujXmPskZgLUPOQUnQ2jk2lz3c9tG0FbPFlXqbkdxQehuuPJjkNtQKAHavlvQKSyalxXdLQ6PuEmv9CbtKkyQszYGA6qxei0HrUSQRljBKk0wPsTzPsTDL0NPI(gvsAAarFxQYWuQtlYObX4fvCsjLZsLuDnPIZlQYYKuTwGGNPewzQjRltP7e7vtg87MQyX(R0eutg(ac1t8pKd5fjEYdwc9qaNc3XYkyeSy2lDvz4diupX)qoKxK4jpyj0drmzYWhqOEI)HCiViXtEWsOhc4u4owwbJGDO0lAEI9Ijtg(ac1t8pKd5fjEYdwc9qmoniyP1c2VclD3TdPakMTm8beQN4FihYls8KhSe6HaofUJLvWiyhzZlfDkM9YUUJmpX)qGqPWTU8dlMoBHYw)esLOyQlBo5X06bHsHRMShja2dlWLrWW1I(58hXGyYw2rgNYbekfElXVy2lZKrWW1I(58hXqUS9O8cIzllf95cd7qQ7U)8O)IPUqzDNMa2vvrbilKWkctLyqnzl2lutOS9IfQj7rcG9WcqOSD9fQj7rcG9WcqOS92vut2Jea7HfGqzl21vt2Jea7HfGqz7fzQj7rcG9WcqOSSDMAYEKaypSaekBVRRMmpX)q9Dttqnz4diupX)qGU(XGuQyH)iMSL1fkZt8puUEmvIb1K5sPWDtSvxmDKHdfdjmvITe)IjBzhzyI)AH8PCeGmxkfUDetrNYsrHcLTxSvtMN4FO(UPjOMm8beQN4Fiqx)yqkvSWFeZwOqz76B1K5j(hQVBAcQjdFaH6j(hc01pgKsfl8hXSfk7rcG9WcqOSSDD1K9ibWEybiu2UZwnzEI)H67MMGAYWhqOEI)HaD9JbPuXc)rmBHcLvFNPMShja2dlaHYwSZut2A69ut2Jea7Hf4YwtVhtfh4JyQlBEalZDNEpbUqzEI)H67MMGAYWhqOEI)HaD9JbPuXc)rmzYWhqOEI)HA048OJfFvOwe)qEeeJea7ftMm8beQN4FOgnop6yXxfQfXpKhnCE0jcbSe6HiMmz4diupX)qnACE0XIVkulIFipA48OteIRt9etMqzEI)HY1JPsmOMmmXFTq(uocqOqzBxzRMmpX)q9Dttqnz4diupX)qGU(XGuQyH)iMTqHY2laPAYEKaypSaekBxptnzpsaShwacLT3GunzEI)H67MMGAYWhqOEI)HaD9JbPuXc)rmzl7iuMN4FOC9yQedQjZLsH7MyRUyYaPmCOyiHPsSL4xmzl7idt8xlKpLJaK5sPWTJyk6uwPcfku2ENPMmpX)q9Dttqnz4diupX)qGU(XGuQyH)iMSLDekZt8puUEmvIb1K5sPWDtSvxmzGugoumKWuj2s8lMSLDKHj(RfYNYraYCPu42rmfDkRuHcfkBxhKQj7rcG9WcqOSDNm1K9ibWEybiu22vYut2Jea7HfGqzl2B1KTMEp1K9ibWEybUS107XuXb(iM6YMhWYC3P3tGluMN4FOC9yQedQjdt8xlKpLJaekZt8puF30eutg(ac1t8peORFmiLkw4pIjBzhz4diupX)qnACE0XIVkulIFipcIrcG9Ijtg(ac1t8puJgNhDS4Rc1I4hYJgop6eHawc9qetMm8beQN4FOgnop6yXxfQfXpKhnCE0jcX1PEIjtOqz13B1KTMEp1K9ibWEybUS107XuXb(iMfYMhWYC3P3tGluMN4FOC9yQedQjdhkgsyQeBj(ftMmmXFTq(uocq2uqcVDetrNYGVZ5piZLsHBhXu0PSWrz5r9C4oN)GyQ7QBztbj8cCzUukC3eB1fdiL1Le6H4WDo)bXK1rOmpX)q9Dttqnz4diupX)qGU(XGuQyH)iMTqHYY2B1K9ibWEybiu2E3rnzEI)H67MMGAYWhqOEI)HaD9JbPuXc)rmzlRluMN4FOC9yQedQjZLsH7MyRUy6idhkgsyQeBj(ft2YoYWe)1c5t5iazUukC7iMIoLLIcfklBVqnzpsaShwacfkJGxPO)WcCHYW86YL5qFOG1vG6ynxdeLfj(LvJZ)esRxgvHqkJmxRcovfYNYjXRccLaa",
16 | },
17 |
18 | ["Shushudaa's preset"] = {
19 | author = "Shushudaa",
20 | description = "A zoomed-in experience with lots of rotations to make the most of ActionCam. Little to no head tracking.",
21 | importString = "da0czaWjQeKMLuYTOsKDjLAys1XeQLrqpJKAAeW1OsTnjX3ijghjPZjqEhvIk3JkbYbjqwij4HujnrkLlkGnsiJKa1jLqntQeOUPa1or0pLKAOi0sPsuEQOPsjxLkb1wjHwlvcO9Q8xQyWsWHrTykvpwLjJGld2SKKplfJwsDAQ61ujQA2c62iTBk(nrdxcXYv1Zj10HUUeTDs03LqA8uj05juRxiEpvcW9PsqSFH0lEwllYlRYhcZAjbOkUmeDvj)6zTebn6CmfE2Mydt9hrpE1kWAqKujrMWi7T7QUebn6CmfEwWatiyPsGcg0LXMgipoegPalrqJohtHNTj2Wu)r0JxDs5hj6vkrxlrzvvzZRXr2xIGgDoMcpBtSHP(JOhVAfynisQKitWMSOM84qyK9LiOrNJPWZ2eByQ)i6XREKXlrqJohtHNRwj8zTSmKa8JmUD8se0OZXu4zBInm1Fe94vRaRbrsLezcIcf7nnJS3wGklpMcp7cukPzraGWifg0WLkHx7LMrkCzv(xJUSsZSVu7Xsg9sJEwlv3vpRHlJ7QN1YJPWZc6qV0ON1s8zJ2JEPXYtHrgVmIustarVPzPSexgrkPkYHLWiJvpC5Xu4zxvKF9SwIGgDoMcpBtSHP(JOhVAfynisQKityK92QxIGgDoMcpBtSHP(JOhV6rgVebn6CmfEwWatiyPsGcgmXhmny9i7TfyjcA05yk8SnXgM6pIE8QvG1GiPsImbBYIAYJdHr2xIGgDoMcpBXFdGIKxPUydcpFyadBpegzFjcA05yk8Sf)naksEL6agGkoGHThcJSVebn6CmfEUALWN1YYqcWprQiS7wf3bjqxTkbju1U6vLl5w9se0OZXu4zBInm1Fe94vNu(rIELs01suwvv28ACKQ229WHl7cvpRLGHThceM9LhtHNf0HEPrpRLrKsQipsuQ9OxAgzL(YisjvKhTKnnHajtHIeYimfwgrkPjGO30SSkpUmIusdMDXrkSpC4YEVYSwEmfE2vf5xpRLiOrNJPWZ2eByQ)i6XRwbwdIKkjYegzVT7LiOrNJPWZvRe(Swwgsa(rg3w4se0OZXu4zbdmHGLkbkyWeFW0G1JS3UYse0OZXu4zl(BauK8k1bmavCadBpegzFjcA05yk8SnXgM6pIE8Qhz8se0OZXu4zBInm1Fe94vRaRbrsLezc2Kf1KhhcJS3wD8se0OZXu4zl(BauK8k1fBq45ddyy7HWi7lrqJohtHNTj2Wu)r0JxDs5hj6vkrxlrzvvzZRXrg3B7E4YJPWZc6qV0ON1s8zJ2JEPXYtHrg329Yisjny2fhzSalJiLurEKOu7rV0mYk9LrKsAWEZiJ7lJiLurE0vPb9gzPEkSmIustarVPzPgWHdxQUlCwlpMcplOd9sJEwlJiLuf5WsyKQSmIustarVPzPgWHlpMcp7QI8RN1se0OZXu4zBInm1Fe94vpY4LiOrNJPWZw83aOi5vQl2GWZhgWW2dHr2xIGgDoMcpBXFdGIKxPoGbOIdyy7HWi7dhUmUhpRLhtHNDvr(1ZAjcA05yk8Sf)naksEL6Ini88HbmS9qyK9LiOrNJPWZvRe(Swwgsa(rQUTQlrqJohtHNfmWecwQeOGbt8btdwpsHlrqJohtHNT4VbqrYRuhWauXbmS9qyK9HlpMcplOd9sJEwlJiL0eq0BAwQbC5lrgHPWYxImczraGWiJ7lJiLuf5WsyKXchUeCr8z9Sww7jaUWfpfgoCzxDFwlpMcp7QI8RN1se0OZXu4zl(BauK8k1fBq45ddyy7HWi7lrqJohtHNfmWecwQeOGbt8btdwpY(se0OZXu4zl(BauK8k1bmavCadBpegzFjcA05yk8SnXgM6pIE8QhzFjcA05yk8C1kHpRLLHeGFK9HllY7LVhfpYyH9LhtHNf0HEPrpRLrKsQICyjmsHQUmIustarVPzPgWHdx27cN1YJPWZUQi)6zTebn6CmfE2Mydt9hrpE1kWAqKujrMWi7TJJxIGgDoMcpBXFdGIKxPUydcpFyadBpegzFjcA05yk8Sf)naksEL6agGkoGHThcJSVebn6CmfE2Mydt9hrpE1kWAqKujrMGnzrn5XHWi7lrqJohtHNRwj8zTSmKa8JmUTWLiOrNJPWZ2eByQ)i6XREKXdxEmfEwqh6Lg9SwIpB0E0lnwEkmY42D3lJiL0eq0BAwQbCzePKQihwcJuDB3dhUSlSpRLhtHNDvr(1ZAjcA05yk8SnXgM6pIE8QvG1GiPsImHr2B7EjcA05yk8C1kHpRLLHeGFK9LiOrNJPWZcgycblvcuWGj(GPbRhzFjcA05yk8Sf)naksEL6agGkoGHThcJSVebn6CmfE2I)gafjVsDXgeE(Wag2EimY(se0OZXu4zBInm1Fe94vpY4HllY7LVhfpYyH9LhtHNf0HEPrpRLrKsQICyjmsHcxgrkPjGO30Sud4WHl7QJN1sWW2dbcZ(WLXDHZA5Xu4zxvKF9SwIGgDoMcpBXFdGIKxPUydcpFyadBpegzFjcA05yk8C1kHpRLLHeGFICjve2DRI7GeORwLGeQIkcxvUK7klrqJohtHNfmWecwQeOGbt8btdwpY(se0OZXu4zl(BauK8k1bmavCadBpegzF4YJPWZc6qV0ON1YisjvroSegzS7LrKsAci6nnlLL4WHl7U7ZAjyy7HaHzF4YExGzT8yk8SRkYVEwlrqJohtHNT4VbqrYRuxSbHNpmGHThcJSVebn6CmfEwWatiyPsGcgmXhmny9i7TfUebn6CmfE2Mydt9hrpE1kWAqKujrMGnzrn5XHWi7TRuzjcA05yk8SnXgM6pIE8QvG1GiPsImHr2BlWse0OZXu4zBInm1Fe94vpY4LiOrNJPWZ2eByQ)i6XRoP8Je9kLORLOSQQS514i7lrqJohtHNT4VbqrYRuhWauXbmS9qyK9LiOrNJPWZvRe(Swwgsa(rgVebn6CmfE2Mydt9hrpE1kWAqKujrMGOqXEtZi7TRuz4YJPWZc6qV0ON1s0tHI1bZU4SVmIustarVPzPgWLrKsAWEZiJ7lJiLuf5WsyKQUeF2O9OxAS8uyKXT7UhoCP6E8Swcg2Eiqy2hUS3DpRLhtHNDvr(1ZAjcA05yk8Sf)naksEL6Ini88HbmS9qyK9LiOrNJPWZvRe(Swwgsa(rg3w4se0OZXu4zbdmHGLkbkyWeFW0G1JS3w4se0OZXu4zl(BauK8k1bmavCadBpegzF4YJPWZc6qV0ON1s8zJ2JEPXYtHrg3oEzePKMaIEtZsVzzePKQihwcJuGHdx2vlWSwcg2Eiqy2hUuypEwlpMcp7QI8RN1se0OZXu4zBInm1Fe94vpY(se0OZXu4zbdmHGLkbkyWeFW0G1JSVebn6CmfE2I)gafjVsDadqfhWW2dHr2xIGgDoMcpBXFdGIKxPUydcpFyadBpegzFjcA05yk8C1kHpRLLHeGFK9Hdx2fgpRLhtHNDvr(1ZAjcA05yk8SnXgM6pIE8QvG1GiPsImHr2B7EjcA05yk8Sf)naksEL6Ini88HbmS9qyK9LiOrNJPWZcgycblvcuWGj(GPbRhzFjcA05yk8Sf)naksEL6agGkoGHThcJSVebn6CmfEUALWN1YYqcWpY(se0OZXu4zBInm1Fe94vpY4HllY7LVhfpYy19LhtHNf0HEPrpRLrKsQICyjmsHcxgrkPjGO30Sud4WHl794zT8yk8SRkYVEwlrqJohtHNRwj8zTSmKa8JmUTWLiOrNJPWZw83aOi5vQl2GWZhgWW2dHr2xIGgDoMcplyGjeSujqbdM4dMgSEK9LiOrNJPWZw83aOi5vQdyaQ4ag2EimY(WLhtHNf0HEPrpRL4ZgTh9sJLNcJmEzePKMaIEtZsnGlJiLuf5WsyKvgoCzxOaZAjyy7HaHzF5Xu4zbDOxA0ZAzePKkYJeLAp6LMrwPVmIusd2BgzCFzePKMaIEtZYQ84YisjvKhTKnnHajtHIeYimfgoCz3D8Swcg2Eiqy2hUSxjEwlbdBpeim7dxQU3N1YJPWZc6qV0ON1s8zJ2JEPXYtHr2B7E5lrgHeq0BAwsaAEa0lJiL0eq0BAw6nlfZf1g08aOhPljqF5lrgHPWYisjvroSegP62Ux(sKrqb(C5NcdxEmfE2vf5xpRLiOrNJPWZ2eByQ)i6XRwbwdIKkjYegz8se0OZXu45QvcFwlldja)iDP42QUebn6CmfEwWatiyPsGcgmXhmny9iJxIGgDoMcpBXFdGIKxPoGbOIdyy7HWi7lrqJohtHNTj2Wu)r0JxDs5hj6vkrxlrzvvzZRXr2xIGgDoMcpBtSHP(JOhVAfynisQKitWMSOM84qyKXlrqJohtHNTj2Wu)r0Jx9iJxIGgDoMcpBtSHP(JOhVAfynisQKitquOyVPzK92vQmC4sH9(SwEmfE2vf5xpRLiOrNJPWZvRe(Swwgsa(r2xIGgDoMcplyGjeSujqbdM4dMgSEK9LiOrNJPWZw83aOi5vQdyaQ4ag2EimY(se0OZXu4zl(BauK8k1fBq45ddyy7HWi7lrqJohtHNTj2Wu)r0Jx9i7dxcUiCLiuTPyJhxI1EDBDrGWqD0cUGIwWfGqHQOwTaTIwiwDf3DvBfTqSQbPQAvBfTGBbeOxPv0cbjGkXb1kAb3UR0kAH4kQkGQQ0kAH4kQkqqb1kAHyvIf6wDROfC3dsfvAfTGQvcQ3kAbHcfwji3TIwiwLyHUv3kAbHcfq1kb1kAb3QJfO3kAb1UR4Uv0cQfkuL4wrlehKAvChuROfu7UIWwrlO2DfvAfTGA1vcQ3kAb1Uvj2DROfuluOkcBfTGabP2TQTIwiwLkcfq1wrlO2DL4wrliqqQDhuROfu7UsLwrlOQQQfqyROfuvv1ciqROfu7UI6wrleRwyfHQ0kAHy1cRimUv0cXQurOacBfTqCqc7Q6Uv0cXbjSRQaTIwqyCLECLwrlehKAvCRUv0ccvrvHciGlexULhtHNf0HEPrpRL4ZgTh9sJLNcJ09Yisjnbe9MMLEZsXCrTbnpa6rQUsF5lrgHeq0BAwsaAEa0lFjYimfwgrkPkYHLWify4sWfXN1ZAzTNa4cx8uy4WLX9(SwEmfE2vf5xpRLiOrNJPWZ2eByQ)i6XRwbwdIKkjYegzVT6LiOrNJPWZvRe(Swwgsa(jsfHD3Q4oib6QvjiHQ2vVQCj3QxIGgDoMcplyGjeSujqbdM4dMgSEK92cSebn6CmfE2I)gafjVsDadqfhWW2dHr2xIGgDoMcpBtSHP(JOhV6rgVebn6CmfE2Mydt9hrpE1kWAqKujrMGnzrn5XHWi7lrqJohtHNT4VbqrYRuxSbHNpmGHThcJSVebn6CmfE2Mydt9hrpE1jLFKOxPeDTeLvvLnVghPQTDpC5Xu4zbDOxA0ZAj(Sr7rV0y5PWiJxgrkPjGO30SuwIlJiLuf5WsyKXchoCzVsFwlbdBpeim7dx2vREwlbdBpeim7dhUKjOKnhqykmCjkUiWsBU6q0LvTOIDbhyPHPWYSUuxxsGzxO6OfkYdAaxYLyT8xM1L66scmpCd",
22 | },
23 |
24 | ["Vanillalike"] = {
25 | author = "mpstark",
26 | description = "Almost no ActionCam, mostly just nicities for zoom.",
27 | importString = "dCt2maGEvzxiuABiumteqnBPCte1TvANkAVu7wu)ui0Wu43KUmyOcvnoeqA4ivhuiDyuhtQY5ecYcrKLkeulwfwUepeHQNsSmK45QQjkuzQsAYQOPdDreqCvPIupdj56iOnIu2kczZcrSDKuFwLoTGPje13LkIrkvu)vQQrlvA8cLtke4wcr6AiqNxQWRrawRurYJfz3Zvl0lAKeAGRwkaNWa1qNs11vlqMpAWPjz0YjejmHnKiO8dA2ZEw(bKqgdA(7QLbvu5QfiZhn40hws8cfoAcdA(7QLNQlTaw17TbtEb6ngbtYYt1LmhZtkdJgTmOqLRwGmF0GtFyjXlu4OjmO5VRwEQU0cyvV3gm5fO3yemjlpvxYCmpPmmA0YyqmUAbY8rdo9HLeVqHJMWGM)UA5P6kaIH81YhqJgTq1GIRws8cfM4eXLVRwq4J9t8cfoUoY8gsXhWuxs8hOPuhpF65Gyh9SGWh7N4fkCCDK5nKIpGPUE2ZccFSFIxOWrKAOiDvcBNqXZiThXsqli8X(jEHchxhzEdP4dyQlj(d0uQJNpJt7KSK4g45GyPIGgTK4fkC0eg083vlpvxbqmKVw(aA5P6slGv9EBWKxGEJrWKS8uDjZX8KYWshCNehCla89ms7nSuuKrqaed5RLt4wa4B5P6se3ie8KGwkkYiqIteGjz0OLbXmC1cK5JgC6dljEHchnHbn)D1Yt1LwaR692GjVa9gJGjz5P6sMJ5jLHrJwgdkUAjXlu4OjmO5VRwEQU0cyvV3gm5fO3yemjlpvxbqmKVwczlpvxI4gHGNeOwEQUK5yEszy0OLEJHRws8cfM4eXLVRwq4J9t8cfoUoY8gsXhWuxphwq4J9t8cfUZaFswPgwiJcwG8f765WccFSFIxOWrKAOiDvcBNqXZHrljEHchnHbn)D1Yt1LwaR692GjVa9gJGjz5P6kaIH81IsiA5P6se3ie8KkcA5P6sMJ5jLHrJwOmgUAjXluyItex(UAbHp2pXlu446iZBifFatD9CybHp2pXlu4od8jzLAyHmkybYxSRNdli8X(jEHchrQHI0vjSDcfphgTK4fkC0eg083vlpvxYCmpPmS8uDfaXq(AjKTGfo)dyqZ1WcE2ByPOiJGjz5P6se3ie8mYw6G7K4GBbGVNurmdlffzeeaXq(A5eUfa(wWWcrWNmhZhwEQU0cyvV3gm5fO3yemjJwGyyH)UAPB4e60rGjz0OLEdkUAjXluyItex(UAbHp2pXlu4isnuKUkHTtO45WccFSFIxOWDg4tYk1WczuWcKVyxphwq4J9t8cfoUoY8gsXhWuxphgTK4fkC0eg083vlpvxAbSQ3BdM8c0BmcMKLNQlzoMNuggnAzqWHRwGmF0GtFyjXlu4OjmO5VRwEQU0cyvV3gm5fO3yemjlpvxYCmpPmmA0YGQEUAbY8rdo9HLeVqHJMWGM)UA5P6slGv9EBWKxGEJrWKS8uDjZX8KYWOrlun65QfiZhn40hws8cfoAcdA(7QLNQlTaw17TbtEb6ngbtYYt1vaed5RLq2Yt1LiUri4zKT8uDjZX8KYWOrlJbbD1sIxOWrtyqZFxT8uDfaXq(AjKT8uDPfWQEVnyYlqVXiyswEQUK5yEszy0OLEJEUAjXluyItex(UAbHp2pXlu4od8jzLAyHmkybYxSRNdli8X(jEHchrQHI0vjSDcfphgTK4fkC0eg083vlpvxAbSQ3BdM8c0BmcMKLNQRaigYxlFaT8uDjIBecEsveYYt1LmhZtkdJgTqz0ZvljEHctCI4Y3vli8X(jEHchxhzEdP4dyQRNdli8X(jEHc3zGpjRudlKrblq(ID9CybHp2pXlu4isnuKUkHTtO45WOLeVqHJMWGM)UA5P6slGv9EBWKxGEJrWKS8uDjZX8KYWOrldIPNRwGmF0GtFyjXlu4OjmO5VRwEQU0cyvV3gm5fO3yemjlpvxYCmpPmmA0Yy0ZvljEHchnHbn)D1Yt1vaed5RLcNVGLNQl5q2ZEdlpvxAbSQ3BdM8c0BmcMKLNQlzoMNuggnAzqjYUAbY8rdo9HLeVqHJMWGM)UA5P6slGv9EBWKxGEJrWKS8uDjZX8KYWOrldc2ZvlqMpAWPpSK4fkC0eg083vlpvxAbSQ3BdM8c0BmcMKLNQlzoMNuggnAzmISRws8cfoAcdA(7QLNQRaigYxlfoFblpvxYHSN9iOLNQlTaw17TbtEb6ngbtYYt1LmhZtkdJgTq1y4QLeVqHjorC57Qfe(y)eVqHJRJmVHu8bm11ZEgTGC5cibwteGRwGmF0GttYIMBDefrora8rd8HLmVa9gJarHF4Ob(WOLeVqHJMWGM)UA5P6slGrqovGfY43ZbXsqlpvxbqmKVwIKaA5P6sMJ5jvdlpvxAbmE9hWGM9mcnS8uDjhYEsLLNQlrCJqWZiB5P6slGv9EBWKxGEJrWKmAbY8rdo9HrldkdxTaz(ObN(WsIxOWrtyqZFxT8uDPfWQEVnyYlqVXiyswEQUK5yEszy0OLbvdxTaz(ObN(WsIxOWrtyqZFxT8uDPfWQEVnyYlqVXiyswEQUK5yEszy0OLbvr2vlqMpAWPpSK4fkC0eg083vlpvxAbSQ3BdM8c0BmcMKLNQlzoMNuggnAzqPNRwGmF0GtFyjXlu4OjmO5VRwEQU0cyvV3gm5fO3yemjlpvxYCmpPmmA0Of(KAoNGttYOfSd6GL4iE)4JWrKweqGjqSK5fSqeNdTghPTabawycXUAXYs)JCHamAda",
28 | },
29 | }
30 |
31 |
32 | function DynamicCam:LoadPreset(defaultName)
33 | -- if there is a preset with this name, then load it into the current profile
34 | if presets[defaultName] then
35 | self:ImportIntoCurrentProfile(presets[defaultName].importString)
36 | end
37 | end
38 |
39 | function DynamicCam:GetPresets()
40 | local presetList = {}
41 |
42 | -- load a table full of the name (the key) and what we want the entry to read
43 | for name, tbl in pairs(presets) do
44 | local entry = string.format("%s (%s)", name, tbl.author)
45 | presetList[name] = entry
46 | end
47 | return presetList
48 | end
49 |
50 |
51 | function DynamicCam:GetPresetsSorting()
52 | local presetSortingList = {}
53 |
54 | local index = 1
55 | -- load a table full of the name (the key) and what we want the entry to read
56 | for name in pairs(presets) do
57 | presetSortingList[index] = name
58 | index = index + 1
59 | end
60 | return presetSortingList
61 | end
62 |
63 |
64 |
65 | function DynamicCam:GetPresetDescriptions()
66 | local descriptions = ""
67 | local sep = ""
68 |
69 | -- load a table full of the name (the key) and what we want the entry to read
70 | for name, tbl in pairs(presets) do
71 | local entry = string.format("%s|cFFFFFF00%s (%s):|r\n%s", sep, name, tbl.author, tbl.description)
72 | descriptions = descriptions..entry
73 | sep = "\n\n"
74 | end
75 |
76 | return descriptions
77 | end
78 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | DynamicCam
2 | ---
3 | DynamicCam automates camera transitions (and settings) between the many different 'situations' that your character can find themselves in. Using the new ActionCam settings reintroduced in 7.1, experience the game in a new way!
4 |
5 |
6 | Contributing
7 | ---
8 | * See a bug? Report it [here](https://github.com/Mpstark/DynamicCam/issues/new)!
9 | * New Feature? Request it [here](https://github.com/Mpstark/DynamicCam/issues/new)!
10 | * Always open to [pull requests](https://github.com/Mpstark/DynamicCam/pulls)!
11 |
--------------------------------------------------------------------------------
/Sharing.lua:
--------------------------------------------------------------------------------
1 | -------------
2 | -- GLOBALS --
3 | -------------
4 | assert(DynamicCam)
5 |
6 |
7 | ------------
8 | -- LOCALS --
9 | ------------
10 | local _
11 | local Compresser = LibStub:GetLibrary("LibCompress")
12 | local Serializer = LibStub:GetLibrary("AceSerializer-3.0")
13 |
14 | ---------------------
15 | -- TABLE TO STRING --
16 | ---------------------
17 | local bytetoB64 = {
18 | [0]="a","b","c","d","e","f","g","h",
19 | "i","j","k","l","m","n","o","p",
20 | "q","r","s","t","u","v","w","x",
21 | "y","z","A","B","C","D","E","F",
22 | "G","H","I","J","K","L","M","N",
23 | "O","P","Q","R","S","T","U","V",
24 | "W","X","Y","Z","0","1","2","3",
25 | "4","5","6","7","8","9","(",")"
26 | }
27 |
28 | local B64tobyte = {
29 | a = 0, b = 1, c = 2, d = 3, e = 4, f = 5, g = 6, h = 7,
30 | i = 8, j = 9, k = 10, l = 11, m = 12, n = 13, o = 14, p = 15,
31 | q = 16, r = 17, s = 18, t = 19, u = 20, v = 21, w = 22, x = 23,
32 | y = 24, z = 25, A = 26, B = 27, C = 28, D = 29, E = 30, F = 31,
33 | G = 32, H = 33, I = 34, J = 35, K = 36, L = 37, M = 38, N = 39,
34 | O = 40, P = 41, Q = 42, R = 43, S = 44, T = 45, U = 46, V = 47,
35 | W = 48, X = 49, Y = 50, Z = 51,["0"]=52,["1"]=53,["2"]=54,["3"]=55,
36 | ["4"]=56,["5"]=57,["6"]=58,["7"]=59,["8"]=60,["9"]=61,["("]=62,[")"]=63
37 | }
38 |
39 | local encodeB64Table = {}
40 | local function encodeB64(str)
41 | local B64 = encodeB64Table
42 | local remainder = 0
43 | local remainder_length = 0
44 | local encoded_size = 0
45 | local l=#str
46 | local code
47 |
48 | for i=1,l do
49 | code = string.byte(str, i)
50 | remainder = remainder + bit.lshift(code, remainder_length)
51 | remainder_length = remainder_length + 8
52 | while(remainder_length) >= 6 do
53 | encoded_size = encoded_size + 1
54 | B64[encoded_size] = bytetoB64[bit.band(remainder, 63)]
55 | remainder = bit.rshift(remainder, 6)
56 | remainder_length = remainder_length - 6
57 | end
58 | end
59 |
60 | if remainder_length > 0 then
61 | encoded_size = encoded_size + 1
62 | B64[encoded_size] = bytetoB64[remainder]
63 | end
64 |
65 | return table.concat(B64, "", 1, encoded_size)
66 | end
67 |
68 | local decodeB64Table = {}
69 | local function decodeB64(str)
70 | local bit8 = decodeB64Table
71 | local decoded_size = 0
72 | local ch
73 | local i = 1
74 | local bitfield_len = 0
75 | local bitfield = 0
76 | local l = #str
77 |
78 | while true do
79 | if bitfield_len >= 8 then
80 | decoded_size = decoded_size + 1
81 | bit8[decoded_size] = string.char(bit.band(bitfield, 255))
82 | bitfield = bit.rshift(bitfield, 8)
83 | bitfield_len = bitfield_len - 8
84 | end
85 | ch = B64tobyte[str:sub(i, i)]
86 | bitfield = bitfield + bit.lshift(ch or 0, bitfield_len)
87 | bitfield_len = bitfield_len + 6
88 | if i > l then
89 | break
90 | end
91 | i = i + 1
92 | end
93 |
94 | return table.concat(bit8, "", 1, decoded_size)
95 | end
96 |
97 | local function tableToString(tbl)
98 | -- serialize
99 | local serialized = Serializer:Serialize(tbl)
100 |
101 | -- compress
102 | local compressed = Compresser:CompressHuffman(serialized)
103 |
104 | -- encode and return
105 | return encodeB64(compressed)
106 | end
107 |
108 | local function stringToTable(str)
109 | -- some sanity checks
110 | if str == nil or str == '' then
111 | return
112 | end
113 |
114 | -- decode
115 | local decoded = decodeB64(str)
116 |
117 | -- decompress
118 | local decompressed, _ = Compresser:Decompress(decoded)
119 | if not decompressed then
120 | return
121 | end
122 |
123 | -- deserialize
124 | local success, deserialized = Serializer:Deserialize(decompressed)
125 | if not success then
126 | return
127 | end
128 |
129 | return deserialized
130 | end
131 |
132 | local function isTableEmpty(tbl)
133 | return next(tbl) == nil
134 | end
135 |
136 | local function removeEmptySubTables(tbl)
137 | for k, v in pairs(tbl) do
138 | if type(v) == "table" then
139 | if isTableEmpty(v) then
140 | tbl[k] = nil
141 | else
142 | removeEmptySubTables(v)
143 | end
144 | end
145 | end
146 | end
147 |
148 | local function minimizeTable(tbl, base)
149 | local minimized = {}
150 |
151 | -- go through all entries, only keep unique entries
152 | for key, value in pairs(tbl) do
153 | if type(value) == "table" and base[key] and type(base[key]) == "table" then
154 | -- child table with matching table in base, minimize it recursively
155 | minimized[key] = minimizeTable(value, base[key])
156 | else
157 | if tbl[key] ~= base[key] then
158 | minimized[key] = value
159 | end
160 | end
161 | end
162 |
163 | -- remove now empty tables from the minimized table
164 | removeEmptySubTables(minimized)
165 |
166 | return minimized
167 | end
168 |
169 | local function copyTable(src, dest)
170 | assert(type(src) == "table", "copyTable() called for non-table source!")
171 | for k, v in pairs(src) do
172 | if type(v) == "table" then
173 | if dest[k] == nil then
174 | print("The destination table does not have a field", k)
175 | else
176 | copyTable(v, dest[k])
177 | end
178 | else
179 | dest[k] = v
180 | end
181 | end
182 | end
183 |
184 |
185 | -------------------
186 | -- IMPORT/EXPORT --
187 | -------------------
188 | function DynamicCam:ExportProfile(name, author)
189 | if not name then
190 | self:Print("Cannot export a profile without a name!")
191 | return
192 | end
193 |
194 | -- add profile metadata
195 | local exportTable = {}
196 | exportTable.type = "DC_PROFILE"
197 | exportTable.name = name
198 | if author then
199 | exportTable.author = author
200 | end
201 |
202 | -- minimize the table, removing all default entries
203 | exportTable.profile = minimizeTable(self.db.profile, self.defaults.profile)
204 |
205 | -- minimize the situations further, by removing their prototype defaults
206 | for situationID, situation in pairs(exportTable.profile.situations) do
207 | exportTable.profile.situations[situationID] = minimizeTable(situation, self.defaults.profile.situations["**"])
208 | end
209 |
210 | return tableToString(exportTable)
211 | end
212 |
213 | function DynamicCam:ExportSituation(situationID)
214 | local exportTable = {}
215 | --exportTable.name = name
216 | --exportTable.author = author
217 | exportTable.version = self.db.profile.version
218 | exportTable.situationID = situationID
219 | exportTable.type = "DC_SITUATION"
220 |
221 | -- minimize the table, removing all default entries
222 | exportTable.situation = minimizeTable(self.db.profile.situations[situationID], self.defaults.profile.situations["**"])
223 |
224 | return tableToString(exportTable)
225 | end
226 |
227 | function DynamicCam:Import(importString)
228 | -- convert the import string into a table
229 | local imported = stringToTable(importString)
230 | if not imported then
231 | self:Print("Something went wrong with the import!")
232 | return
233 | end
234 |
235 | if imported.type == "DC_SITUATION" then
236 | -- modernize the situation, it could be from a previous version
237 | self:ModernizeSituation(imported.situation, imported.version)
238 |
239 | -- this is an imported situation
240 | if string.find(imported.situationID, "custom") then
241 | -- custom situation, so just create a new custom situation and bring everything into it
242 | local situation, situationID = self:CreateCustomSituation(imported.situation.name)
243 |
244 | -- Set/override all settings defined by the imported situation.
245 | copyTable(imported.situation, situation)
246 |
247 | self:UpdateSituation(situationID)
248 |
249 | self:Print("Successfully imported custom situation", imported.situation.name)
250 |
251 | else
252 |
253 | local situationID = imported.situationID
254 |
255 | -- not a custom situation, need to update the current situation
256 | if not self.defaults.profile.situations[situationID] then
257 | self:Print("You are trying to import a non-custom situation that does not exist.", imported.situation.name, situationID)
258 | end
259 |
260 | -- Restore default first.
261 | copyTable(self.defaults.profile.situations["**"], self.db.profile.situations[situationID])
262 | copyTable(self.defaults.profile.situations[situationID], self.db.profile.situations[situationID])
263 |
264 | -- Set/override all settings defined by the imported situation.
265 | copyTable(imported.situation, self.db.profile.situations[situationID])
266 |
267 | self:UpdateSituation(situationID)
268 |
269 | self:Print("Successfully imported situation", imported.situation.name)
270 |
271 | end
272 |
273 | elseif imported.type == "DC_PROFILE" then
274 | local name = imported.name or "Imported"
275 | -- this in an imported profile
276 | if DynamicCamDB.profiles[name] == nil then
277 | self:ModernizeProfile(imported.profile)
278 | DynamicCamDB.profiles[name] = imported.profile
279 | self:Print("Successfully imported profile:", name)
280 | else
281 | self:Print("Already have a profile of name:", name)
282 | self:Print("If you'd like to still import, delete the existing profile and then reimport.")
283 | end
284 | end
285 | end
286 |
287 | function DynamicCam:ImportIntoCurrentProfile(importString)
288 | -- convert the import string into a table
289 | local imported = stringToTable(importString)
290 | if not imported then
291 | self:Print("Something went wrong with loading the default!")
292 | return
293 | end
294 |
295 | -- load the imported string into the current profile
296 | if imported.type == "DC_PROFILE" then
297 | self:ModernizeProfile(imported.profile)
298 |
299 | self:Shutdown()
300 |
301 | -- Reset current profile to default.
302 | self.db:ResetProfile(nil, true)
303 | -- Override all settings defined by the imported profile.
304 | copyTable(imported.profile, self.db.profile)
305 |
306 | self:Startup()
307 |
308 | self:Print("Successfully imported into current profile")
309 | end
310 | end
311 |
312 |
--------------------------------------------------------------------------------
/UiHideModule.lua:
--------------------------------------------------------------------------------
1 | local folderName, Addon = ...
2 |
3 |
4 | -- For debugging:
5 | -- We have to work with frame name, because some frames do not exist yet at startup.
6 | -- local debugFrameName = "ClassTrainerFrame"
7 |
8 |
9 | -- Have to store uiHiddenTime and currentConfig globally,
10 | -- because several addons may use this module simultaneously.
11 | if not ludius_UiHideModule then
12 | ludius_UiHideModule = {}
13 |
14 | -- Flag indicating if the UI is currently faded out.
15 | ludius_UiHideModule.uiHiddenTime = 0
16 |
17 | -- Save for each addon separately whether they have hidden the UI.
18 | ludius_UiHideModule.addonsHiddenStatus = {}
19 |
20 | -- The current configuration passed by the addon calling HideUI.
21 | ludius_UiHideModule.currentConfig = nil
22 |
23 | -- Collect alert frames that are created.
24 | ludius_UiHideModule.collectedAlertFrames = {}
25 | end
26 |
27 | -- For quick access.
28 | local currentConfig = ludius_UiHideModule.currentConfig
29 | local collectedAlertFrames = ludius_UiHideModule.collectedAlertFrames
30 |
31 |
32 |
33 |
34 | -- Call Addon.HideUI(fadeOutTime, config) to hide UI keeping configured frames.
35 | -- Call Addon.ShowUI(fadeInTime, true) when entering combat while UI is hidden.
36 | -- This will show the actually hidden frames, that cannot be shown during combat,
37 | -- but the fade out state will remain. You only see tooltips of faded-out frames.
38 | -- Call Addon.ShowUI(fadeInTime, false) to show UI.
39 |
40 | -- Accepted options for config argument of HideUI():
41 | -- config.hideFrameRate
42 | -- config.keepAlertFrames
43 | -- config.keepTooltip
44 | -- config.keepMinimap
45 | -- config.keepChatFrame
46 | -- config.keepPartyRaidFrame
47 | -- config.keepTrackingBar
48 | -- config.keepEncounterBar
49 | -- config.keepCustomFrames
50 | -- config.customFramesToKeep
51 | -- config.UIParentAlpha (while faded out)
52 |
53 |
54 | -- Lua API
55 | local _G = _G
56 |
57 | local tonumber = tonumber
58 | local tinsert = tinsert
59 | local string_find = string.find
60 | local string_match = string.match
61 |
62 | local GetTime = _G.GetTime
63 | local InCombatLockdown = _G.InCombatLockdown
64 | local UnitInParty = _G.UnitInParty
65 |
66 |
67 | local CompactRaidFrameContainer = _G.CompactRaidFrameContainer
68 |
69 |
70 |
71 |
72 |
73 | -- The user can define custom frames to keep visible.
74 | -- To prevent these user settings from clashing with the other frames,
75 | -- we store the names of frames handled by the addon.
76 |
77 | -- Frames whose visibility is defined via explicit UI checkboxes/flags.
78 | local flagFrames = {
79 |
80 | -- config.hideFrameRate
81 | ["FramerateLabel"] = true,
82 | ["FramerateText"] = true,
83 |
84 | -- config.keepAlertFrames
85 | ["CovenantRenownToast"] = true,
86 |
87 |
88 | -- config.keepMinimap
89 | ["MinimapCluster"] = true,
90 | -- Minimap is needed, because Immersion sets it to IgnoreParentAlpha.
91 | ["Minimap"] = true,
92 |
93 | -- config.keepTooltip
94 | ["GameTooltip"] = true,
95 | ["AceGUITooltip"] = true,
96 | ["AceConfigDialogTooltip"] = true,
97 |
98 |
99 | -- config.keepTrackingBar
100 | -- Retail
101 | ["StatusTrackingBarManager"] = true,
102 | ["BT4BarStatus"] = true,
103 | -- Classic
104 | ["MainMenuExpBar"] = true,
105 | ["ReputationWatchBar"] = true,
106 | -- GW2 UI
107 | ["GwExperienceFrame"] = true,
108 |
109 |
110 | -- config.keepEncounterBar
111 | ["EncounterBar"] = true,
112 | }
113 |
114 |
115 |
116 | -- config.keepChatFrame
117 | for i = 1, 12, 1 do
118 | flagFrames["ChatFrame" .. i] = true
119 | flagFrames["ChatFrame" .. i .. "Tab"] = true
120 | flagFrames["ChatFrame" .. i .. "EditBox"] = true
121 | flagFrames["GwChatContainer" .. i] = true
122 | end
123 |
124 |
125 | -- config.keepPartyRaidFrame
126 | for i = 1, 4, 1 do
127 | flagFrames["PartyMemberFrame" .. i] = true
128 | flagFrames["PartyMemberFrame" .. i .. "NotPresentIcon"] = true
129 | end
130 |
131 |
132 |
133 | -- Frames which are hidden by default.
134 | local defaultHiddenFrames = {
135 | ["QuickJoinToastButton"] = true,
136 | ["PlayerFrame"] = true,
137 | ["PetFrame"] = true,
138 | ["TargetFrame"] = true,
139 | ["BuffFrame"] = true,
140 | ["DebuffFrame"] = true,
141 | ["ObjectiveTrackerFrame"] = true,
142 | -- TODO: Would have to fade every single 3D model separately.
143 | ["WardrobeFrame"] = true,
144 | ["CollectionsJournal"] = true,
145 | }
146 |
147 |
148 |
149 |
150 | if Bartender4 then
151 | defaultHiddenFrames["BT4Bar1"] = true
152 | defaultHiddenFrames["BT4Bar2"] = true
153 | defaultHiddenFrames["BT4Bar3"] = true
154 | defaultHiddenFrames["BT4Bar4"] = true
155 | defaultHiddenFrames["BT4Bar5"] = true
156 | defaultHiddenFrames["BT4Bar6"] = true
157 | defaultHiddenFrames["BT4Bar7"] = true
158 | defaultHiddenFrames["BT4Bar8"] = true
159 | defaultHiddenFrames["BT4Bar9"] = true
160 | defaultHiddenFrames["BT4Bar10"] = true
161 | defaultHiddenFrames["BT4Bar11"] = true
162 | defaultHiddenFrames["BT4Bar12"] = true
163 | defaultHiddenFrames["BT4Bar13"] = true
164 | defaultHiddenFrames["BT4Bar14"] = true
165 | defaultHiddenFrames["BT4Bar15"] = true
166 | defaultHiddenFrames["BT4BarBagBar"] = true
167 | defaultHiddenFrames["BT4BarMicroMenu"] = true
168 | defaultHiddenFrames["BT4BarStanceBar"] = true
169 | defaultHiddenFrames["BT4BarPetBar"] = true
170 | else
171 | defaultHiddenFrames["MainMenuBar"] = true
172 | defaultHiddenFrames["MultiBarLeft"] = true
173 | defaultHiddenFrames["MultiBarRight"] = true
174 | defaultHiddenFrames["MultiBarBottomLeft"] = true
175 | defaultHiddenFrames["MultiBarBottomRight"] = true
176 | defaultHiddenFrames["MultiBar5"] = true
177 | defaultHiddenFrames["MultiBar6"] = true
178 | defaultHiddenFrames["MultiBar7"] = true
179 | defaultHiddenFrames["MultiBar8"] = true
180 | defaultHiddenFrames["ExtraAbilityContainer"] = true
181 | defaultHiddenFrames["MainMenuBarVehicleLeaveButton"] = true
182 | defaultHiddenFrames["MicroButtonAndBagsBar"] = true
183 | defaultHiddenFrames["MultiCastActionBarFrame"] = true
184 | defaultHiddenFrames["StanceBar"] = true
185 | defaultHiddenFrames["PetActionBar"] = true
186 | defaultHiddenFrames["PossessBar"] = true
187 | end
188 |
189 |
190 | local keepDefaultHiddenFramesAsParent = {}
191 |
192 |
193 | -- We need a function to change a frame's alpha without automatically showing the frame
194 | -- (as done by the original UIFrameFade() defined in UIParent.lua).
195 |
196 | if not ludius_FADEFRAMES then ludius_FADEFRAMES = {} end
197 |
198 | local frameFadeManager = CreateFrame("FRAME")
199 |
200 | local function UIFrameFadeRemoveFrame(frame)
201 | tDeleteItem(ludius_FADEFRAMES, frame)
202 | end
203 |
204 |
205 |
206 | -- Changed this to work with GetTime() instead of "elapsed" argument.
207 | -- Because the first elapsed after login is always very long and we want
208 | -- to be able to start a smooth fade out beginning at the first update.
209 | local lastUpdate
210 | local function UIFrameFade_OnUpdate(self)
211 |
212 | local elapsed = 0
213 | if lastUpdate then
214 | elapsed = GetTime() - lastUpdate
215 | end
216 | lastUpdate = GetTime()
217 |
218 | local index = 1
219 | local frame, fadeInfo
220 | while ludius_FADEFRAMES[index] do
221 | frame = ludius_FADEFRAMES[index]
222 | fadeInfo = frame.fadeInfo
223 | -- Reset the timer if there isn't one, this is just an internal counter
224 | if not fadeInfo.fadeTimer then
225 | fadeInfo.fadeTimer = 0
226 | end
227 | fadeInfo.fadeTimer = fadeInfo.fadeTimer + elapsed
228 |
229 | -- If the fadeTimer is less then the desired fade time then set the alpha otherwise hold the fade state, call the finished function, or just finish the fade
230 | if tonumber(fadeInfo.fadeTimer) < tonumber(fadeInfo.timeToFade) then
231 | if fadeInfo.mode == "IN" then
232 | frame:SetAlpha((fadeInfo.fadeTimer / fadeInfo.timeToFade) * (fadeInfo.endAlpha - fadeInfo.startAlpha) + fadeInfo.startAlpha)
233 | elseif fadeInfo.mode == "OUT" then
234 | frame:SetAlpha(((fadeInfo.timeToFade - fadeInfo.fadeTimer) / fadeInfo.timeToFade) * (fadeInfo.startAlpha - fadeInfo.endAlpha) + fadeInfo.endAlpha)
235 | end
236 |
237 | -- if frame:GetName() == debugFrameName then print("UIFrameFade_OnUpdate", elapsed, frame:GetName(), fadeInfo.fadeTimer, fadeInfo.timeToFade, "Setting alpha", frame:GetAlpha()) end
238 |
239 | else
240 |
241 | -- if frame:GetName() == debugFrameName then print("Last call of UIFrameFade_OnUpdate.", frame:GetName(), "Setting endAlpha", fadeInfo.endAlpha) end
242 |
243 | frame:SetAlpha(fadeInfo.endAlpha)
244 | -- Complete the fade and call the finished function if there is one
245 | UIFrameFadeRemoveFrame(frame)
246 | if fadeInfo.finishedFunc then
247 | fadeInfo.finishedFunc(fadeInfo.finishedArg1, fadeInfo.finishedArg2, fadeInfo.finishedArg3, fadeInfo.finishedArg4)
248 | fadeInfo.finishedFunc = nil
249 | end
250 | end
251 |
252 | index = index + 1
253 | end
254 |
255 | if #ludius_FADEFRAMES == 0 then
256 | self:SetScript("OnUpdate", nil)
257 | lastUpdate = nil
258 | end
259 | end
260 |
261 | local function UIFrameFade(frame, fadeInfo)
262 | if not frame then return end
263 |
264 | -- We make sure that we always call this with mode, startAlpha and endAlpha.
265 | assert(fadeInfo.mode)
266 | assert(fadeInfo.startAlpha)
267 | assert(fadeInfo.endAlpha)
268 |
269 | -- if frame:GetName() == debugFrameName then print("UIFrameFade", frame:GetName(), fadeInfo.mode, fadeInfo.startAlpha, fadeInfo.endAlpha) end
270 |
271 | frame.fadeInfo = fadeInfo
272 | frame:SetAlpha(fadeInfo.startAlpha)
273 |
274 | local index = 1
275 | while ludius_FADEFRAMES[index] do
276 | -- If frame is already set to fade then return
277 | if ludius_FADEFRAMES[index] == frame then
278 | return
279 | end
280 | index = index + 1
281 | end
282 | tinsert(ludius_FADEFRAMES, frame)
283 |
284 | if #ludius_FADEFRAMES == 1 then
285 | frameFadeManager:SetScript("OnUpdate", UIFrameFade_OnUpdate)
286 | end
287 |
288 | end
289 |
290 |
291 |
292 | -- A function to set a frame's alpha depending on mouse over and
293 | -- whether we are fading/faded out or not.
294 | local function SetMouseOverAlpha(frame)
295 | -- Only do something to frames for which the hovering was activated.
296 | if frame.ludius_mouseOver == nil then return end
297 |
298 | -- Fading or faded out.
299 | if frame.ludius_fadeout then
300 |
301 | -- If the mouse is hovering over the status bar, show it with alpha 1.
302 | if frame.ludius_mouseOver then
303 | -- In case we are currently fading out,
304 | -- interrupt the fade out in progress.
305 | UIFrameFadeRemoveFrame(frame)
306 | frame.ludius_alreadyOnIt = nil
307 | frame:SetAlpha(1)
308 |
309 | -- Otherwise use the faded out alpha.
310 | else
311 | frame:SetAlpha(frame.ludius_alphaAfterFadeOut)
312 | end
313 |
314 | end
315 | end
316 |
317 |
318 |
319 | if WOW_PROJECT_ID == WOW_PROJECT_MAINLINE then
320 |
321 | local function SetMouseOverFading(barManager)
322 | -- Have to do this for the single bars.
323 | -- Otherwise the text does not pop up any more when hovering over the bars.
324 | -- It seems that OnEnter of a parent prevents the OnEnter of children to be triggered.
325 | -- But only the OnEnter of single bars shows the bar text.
326 | for _, frame in pairs(barManager.bars) do
327 | if not frame.ludius_hooked then
328 | frame:HookScript("OnEnter", function()
329 | StatusTrackingBarManager.ludius_mouseOver = true
330 | SetMouseOverAlpha(StatusTrackingBarManager)
331 | end)
332 | frame:HookScript("OnLeave", function()
333 | StatusTrackingBarManager.ludius_mouseOver = false
334 | SetMouseOverAlpha(StatusTrackingBarManager)
335 | end)
336 | frame.ludius_hooked = true
337 | end
338 | end
339 |
340 | end
341 | SetMouseOverFading(MainStatusTrackingBarContainer)
342 | SetMouseOverFading(SecondaryStatusTrackingBarContainer)
343 |
344 | else
345 |
346 | -- Dirty work around with global flag until fade UI has become a lib to share between addons.
347 | if not ludius_bars_hooked then
348 | for _, frame in pairs({ReputationWatchBar, MainMenuExpBar}) do
349 |
350 | frame:HookScript("OnEnter", function()
351 | ReputationWatchBar.IEF_tempAlpha = ReputationWatchBar:GetAlpha()
352 | ReputationWatchBar:SetAlpha(1)
353 | MainMenuExpBar.IEF_tempAlpha = MainMenuExpBar:GetAlpha()
354 | MainMenuExpBar:SetAlpha(1)
355 | end )
356 |
357 | frame:HookScript("OnLeave", function()
358 | if (ReputationWatchBar.IEF_tempAlpha ~= nil) then
359 | ReputationWatchBar:SetAlpha(ReputationWatchBar.IEF_tempAlpha)
360 | end
361 | if (MainMenuExpBar.IEF_tempAlpha ~= nil) then
362 | MainMenuExpBar:SetAlpha(MainMenuExpBar.IEF_tempAlpha)
363 | end
364 | end )
365 |
366 | end
367 | ludius_bars_hooked = true
368 |
369 | end
370 | end
371 |
372 |
373 |
374 | if C_AddOns.IsAddOnLoaded("GW2_UI") then
375 | -- GW2_UI seems to offer no way of hooking any of its functions.
376 | -- So we have to do it like this.
377 | local enterWorldFrame = CreateFrame("Frame")
378 | enterWorldFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
379 | enterWorldFrame:SetScript("OnEvent", function(_, event, isLogin, isReload)
380 | if not isLogin and not isReload then return end
381 |
382 | if GwExperienceFrame then
383 | GwExperienceFrame:HookScript("OnEnter", function()
384 | GwExperienceFrame.ludius_mouseOver = true
385 | SetMouseOverAlpha(GwExperienceFrame)
386 | end)
387 | GwExperienceFrame:HookScript("OnLeave", function()
388 | GwExperienceFrame.ludius_mouseOver = false
389 | SetMouseOverAlpha(GwExperienceFrame)
390 | end)
391 | end
392 | end)
393 | end
394 |
395 |
396 |
397 | -- To hide the tooltip of bag items.
398 | -- (While we are actually hiding other frames to suppress their tooltips,
399 | -- this is not practical for the bag, as opening may cause an annoying FPS drop.)
400 | local function GameTooltipHider(self)
401 |
402 | if ludius_UiHideModule.uiHiddenTime == 0 or not self then return end
403 |
404 | local ownerName = nil
405 | if self:GetOwner() then
406 | ownerName = self:GetOwner():GetName()
407 | end
408 | if ownerName == nil then return end
409 |
410 | if string_find(ownerName, "^ContainerFrame") or ownerName == "ChatFrameChannelButton" then
411 | self:Hide()
412 | -- else
413 | -- print(ownerName)
414 | end
415 | end
416 |
417 |
418 |
419 | if WOW_PROJECT_ID == WOW_PROJECT_MAINLINE then
420 | TooltipDataProcessor.AddTooltipPostCall(Enum.TooltipDataType.Item, GameTooltipHider)
421 | else
422 | GameTooltip:HookScript("OnTooltipSetItem", GameTooltipHider)
423 | end
424 | GameTooltip:HookScript("OnTooltipSetDefaultAnchor", GameTooltipHider)
425 | GameTooltip:HookScript("OnShow", GameTooltipHider)
426 |
427 |
428 |
429 | local function ConditionalHide(frame)
430 | if not frame then return end
431 |
432 | -- if frame:GetName() == debugFrameName then print("ConditionalHide", frame:GetName(), frame:GetParent():GetName(), frame:IsIgnoringParentAlpha()) end
433 |
434 | -- Checking for combat lockdown is not this function's concern.
435 | -- Functions calling it must make sure, it is not called in combat lockdown.
436 |
437 | -- TODO: What if the combat started while the fade out was already happening???
438 | if frame:IsProtected() and InCombatLockdown() then
439 | print("ERROR: Should not try to hide", frame:GetName(), "in combat lockdown!")
440 | end
441 |
442 | if frame.ludius_shownBeforeFadeOut == nil then
443 | -- if frame:GetName() == debugFrameName then print("Remember it was shown", frame:IsShown()) end
444 | frame.ludius_shownBeforeFadeOut = frame:IsShown()
445 | end
446 |
447 | if frame:IsShown() then
448 | frame:Hide()
449 | end
450 | end
451 |
452 |
453 | local function ConditionalShow(frame)
454 | if not frame or frame.ludius_shownBeforeFadeOut == nil then return end
455 |
456 | -- if frame:GetName() == debugFrameName then print("ConditionalShow", frame:GetName(), frame.ludius_shownBeforeFadeOut) end
457 |
458 | if frame:IsProtected() and InCombatLockdown() then
459 | print("ERROR: Should not try to show", frame:GetName(), "in combat lockdown!")
460 | end
461 |
462 |
463 | -- If the frame is already shown, we leave it be.
464 | if not frame:IsShown() then
465 |
466 | -- For party and raid member frames, we cannot rely on ludius_shownBeforeFadeOut,
467 | -- so some more complex checks are necessary.
468 |
469 | -- Party member frames.
470 | if string_find(frame:GetName(), "^PartyMemberFrame") then
471 |
472 | -- The NotPresentIcon is taken care of by PartyMemberFrame_UpdateNotPresentIcon below.
473 | -- So we only handle the actual PartyMemberFrame and do nothing otherwise.
474 | if string_find(frame:GetName(), "^PartyMemberFrame(%d+)$") then
475 |
476 | -- Only show the party member frames, if we are in a party that is not a raid.
477 | -- (Use CompactRaidFrameContainer:IsShown() instead of UnitInRaid("player") because people might use
478 | -- an addon like SoloRaidFrame to show the raid frame even while not in raid.)
479 | if UnitInParty("player") and not CompactRaidFrameContainer:IsShown() then
480 | -- Only for as many frames as there are party members.
481 | local numGroupMembers = GetNumGroupMembers()
482 | local frameNumber = tonumber(string_match(frame:GetName(), "^PartyMemberFrame(%d+)"))
483 | if frameNumber < numGroupMembers then
484 | frame:Show()
485 | PartyMemberFrame_UpdateNotPresentIcon(frame)
486 | -- The above functions set the alpha, but we want to do the fade in ourselves.
487 | frame:SetAlpha(0)
488 | frame.notPresentIcon:SetAlpha(0)
489 | end
490 | end
491 |
492 | end
493 |
494 |
495 | -- Only show the CompactRaidFrameContainer, if the player is still in a party.
496 | elseif frame == CompactRaidFrameContainer then
497 |
498 | -- (Again also use CompactRaidFrameContainer:IsShown() because people might use
499 | -- an addon like SoloRaidFrame to show the raid frame even while not in raid.)
500 | if UnitInParty("player") or CompactRaidFrameContainer:IsShown() then
501 | frame:Show()
502 | end
503 |
504 |
505 | elseif frame.ludius_shownBeforeFadeOut then
506 | -- if frame:GetName() == debugFrameName then print("Have to show it again!") end
507 | frame:Show()
508 | end
509 |
510 | end
511 |
512 | frame.ludius_shownBeforeFadeOut = nil
513 | end
514 |
515 |
516 |
517 |
518 | -- To prevent other addons (Immersion, I'm looking in your direction) from
519 | -- setting Minimap's and MinimapCluster's ignoreParentAlpha to false, when DynamicCam does not.
520 | local function ParentAlphaGuard(self, ignoreParentAlpha)
521 | -- print(self:GetName(), "SetIgnoreParentAlpha", ignoreParentAlpha, self.ludius_intendedIgnoreParentAlpha)
522 | if self.ludius_intendedIgnoreParentAlpha ~= nil and ignoreParentAlpha ~= self.ludius_intendedIgnoreParentAlpha then
523 | -- print("no")
524 | self:SetIgnoreParentAlpha(self.ludius_intendedIgnoreParentAlpha)
525 | -- else
526 | -- print("ok")
527 | end
528 | end
529 |
530 | hooksecurefunc(MinimapCluster, "SetIgnoreParentAlpha", ParentAlphaGuard)
531 | hooksecurefunc(Minimap, "SetIgnoreParentAlpha", ParentAlphaGuard)
532 |
533 |
534 |
535 |
536 | -- To restore frames to their pre-hide ignore-parent-alpha state,
537 | -- we remember it in the ludius_ignoreParentAlphaBeforeFadeOut variable.
538 | local function ConditionalSetIgnoreParentAlpha(frame, ignoreParentAlpha)
539 | -- if frame:GetName() == debugFrameName then print("ConditionalSetIgnoreParentAlpha", ignoreParentAlpha) end
540 |
541 | if not frame or ignoreParentAlpha == nil then return end
542 |
543 | if frame.ludius_ignoreParentAlphaBeforeFadeOut == nil then
544 | frame.ludius_ignoreParentAlphaBeforeFadeOut = frame:IsIgnoringParentAlpha()
545 | end
546 |
547 | if frame:IsIgnoringParentAlpha() ~= ignoreParentAlpha then
548 | frame.ludius_intendedIgnoreParentAlpha = ignoreParentAlpha
549 | frame:SetIgnoreParentAlpha(ignoreParentAlpha)
550 | end
551 | end
552 |
553 | local function ConditionalResetIgnoreParentAlpha(frame)
554 | -- if frame:GetName() == debugFrameName then print("ConditionalSetIgnoreParentAlpha", ignoreParentAlpha) end
555 |
556 | if not frame or frame.ludius_ignoreParentAlphaBeforeFadeOut == nil then return end
557 |
558 | if frame:IsIgnoringParentAlpha() ~= frame.ludius_ignoreParentAlphaBeforeFadeOut then
559 | frame.ludius_intendedIgnoreParentAlpha = frame.ludius_ignoreParentAlphaBeforeFadeOut
560 | frame:SetIgnoreParentAlpha(frame.ludius_ignoreParentAlphaBeforeFadeOut)
561 | end
562 | frame.ludius_ignoreParentAlphaBeforeFadeOut = nil
563 | end
564 |
565 |
566 |
567 |
568 | -- The alert frames have to be dealt with as they are created.
569 | -- https://www.wowinterface.com/forums/showthread.php?p=337803
570 | -- For testing:
571 | -- /run UIParent:SetAlpha(0.5)
572 | -- /run NewMountAlertSystem:ShowAlert("123") NewMountAlertSystem:ShowAlert("123")
573 | -- /run CovenantRenownToast:ShowRenownLevelUpToast(C_Covenants.GetActiveCovenantID(), 40)
574 |
575 |
576 | -- A flag for alert frames that are created/collected while the UI is hidden.
577 | local currentAlertFramesIgnoreParentAlpha = false
578 |
579 | local function AlertFramesSetIgnoreParentAlpha(ignoreParentAlpha)
580 | currentAlertFramesIgnoreParentAlpha = ignoreParentAlpha
581 | for _, v in pairs(collectedAlertFrames) do
582 | ConditionalSetIgnoreParentAlpha(v, ignoreParentAlpha)
583 | end
584 | end
585 |
586 | local function AlertFramesResetIgnoreParentAlpha()
587 | currentAlertFramesIgnoreParentAlpha = false
588 | for _, v in pairs(collectedAlertFrames) do
589 | ConditionalResetIgnoreParentAlpha(v)
590 | end
591 | end
592 |
593 |
594 | local function CollectAlertFrame(_, frame)
595 | -- print("CollectAlertFrame", frame, currentAlertFramesIgnoreParentAlpha, frame.ludius_collected)
596 |
597 | if frame and not frame.ludius_collected then
598 | tinsert(collectedAlertFrames, frame)
599 | frame.ludius_collected = true
600 | end
601 |
602 | if currentAlertFramesIgnoreParentAlpha and not frame:IsIgnoringParentAlpha() then
603 | ConditionalSetIgnoreParentAlpha(frame, currentAlertFramesIgnoreParentAlpha)
604 | end
605 | end
606 |
607 | for _, subSystem in pairs(AlertFrame.alertFrameSubSystems) do
608 | local pool = type(subSystem) == "table" and subSystem.alertFramePool
609 | if type(pool) == "table" and type(pool.resetterFunc) == "function" then
610 | hooksecurefunc(pool, "resetterFunc", CollectAlertFrame)
611 | end
612 | end
613 |
614 |
615 |
616 |
617 | -- targetIgnoreParentAlpha == true: frame ignores parent alpha, and itself fades to targetAlpha (maybe different from UIParent's alpha).
618 | -- targetIgnoreParentAlpha == false: frame adheres to parent alpha, but gets hidden, if targetAlpha (UIParent's alpha) is 0.
619 | --
620 | -- targetIgnoreParentAlpha == nil: Ignoring this frame!
621 | -- This is needed for example, if the keeping or fading of a frame should be governed by another addon.
622 | -- Like MinimapCluster is governed by Immersion and should therefore not be modified by IEF.
623 | -- FadeInFrame() will automatically ignore non-faded frames as it will not find our ludius_ flags.
624 | local function FadeOutFrame(frame, duration, targetIgnoreParentAlpha, targetAlpha)
625 |
626 | if not frame or targetIgnoreParentAlpha == nil then return end
627 |
628 |
629 |
630 | -- If another addon is already handling this, we don't touch it.
631 | if frame.ludius_alreadyOnIt ~= nil and frame.ludius_alreadyOnIt ~= folderName then
632 | return
633 | else
634 | frame.ludius_alreadyOnIt = folderName
635 | end
636 |
637 | assert(targetAlpha)
638 |
639 | -- Prevent callback functions of currently active timers.
640 | UIFrameFadeRemoveFrame(frame)
641 |
642 | -- if frame:GetName() == debugFrameName then print("FadeOutFrame", frame:GetName(), duration, targetIgnoreParentAlpha, frame:IsIgnoringParentAlpha(), targetAlpha, frame:GetAlpha()) end
643 |
644 |
645 | -- If a frame to be kept is not a direct child of UIParent,
646 | -- we have to make sure that the parent gets not hidden later.
647 | -- (e.g. In classic, the status tracking bars are children of MainMenuBar,
648 | -- which normally is in defaultHiddenFrames.)
649 | if targetIgnoreParentAlpha and targetAlpha > 0 then
650 | local currentParent = frame:GetParent()
651 | while currentParent and currentParent ~= UIParent and currentParrent ~= WorldFrame do
652 | keepDefaultHiddenFramesAsParent[currentParent] = true
653 | currentParent = currentParent:GetParent()
654 | end
655 | end
656 |
657 |
658 | -- ludius_alphaBeforeFadeOut is only set, if this is a fresh FadeOutFrame().
659 | -- It is set to nil after a FadeOutFrame() is completed.
660 | -- Otherwise, we might falsely asume a wrong ludius_alphaBeforeFadeOut
661 | -- value while a fade-in is still in progress.
662 | if frame.ludius_alphaBeforeFadeOut == nil then
663 | frame.ludius_alphaBeforeFadeOut = frame:GetAlpha()
664 | end
665 |
666 |
667 | -- To use UIFrameFade() which is the same as UIFrameFadeOut, but with a callback function.
668 | local fadeInfo = {}
669 | fadeInfo.mode = "OUT"
670 | fadeInfo.timeToFade = duration
671 | fadeInfo.finishedArg1 = frame
672 | fadeInfo.finishedArg2 = targetAlpha
673 | fadeInfo.finishedFunc = function(finishedArg1, finishedArg2)
674 | -- if finishedArg1:GetName() == debugFrameName then print("Fade out finished", finishedArg1:GetName(), finishedArg2) end
675 | if finishedArg2 == 0 and (not finishedArg1:IsProtected() or not InCombatLockdown()) and not keepDefaultHiddenFramesAsParent[finishedArg1] then
676 | -- if finishedArg1:GetName() == debugFrameName then print("...and hiding!", finishedArg2) end
677 | ConditionalHide(finishedArg1)
678 | end
679 |
680 | finishedArg1.ludius_alreadyOnIt = nil
681 | end
682 |
683 |
684 |
685 |
686 | -- Frame should henceforth ignore parent alpha.
687 | if targetIgnoreParentAlpha then
688 |
689 | -- This is to let SetMouseOverAlpha() know whether we are
690 | -- currently fading/faded in or fading/faded out.
691 | -- Notice that we cannot use ludius_alphaBeforeFadeOut or ludius_alphaAfterFadeOut as this flag,
692 | -- because ludius_fadeout is unset at the beginning of a fade out
693 | -- and ludius_alphaBeforeFadeOut is unset at the end of a fade out.
694 | -- For an OnEnable/OnLeave during fade out, we do not want the alpha to change.
695 | frame.ludius_fadeout = true
696 | -- This is to let SetMouseOverAlpha() know which
697 | -- alpha to go back to OnLeave while the frame is faded or fading out.
698 | frame.ludius_alphaAfterFadeOut = targetAlpha
699 | SetMouseOverAlpha(frame)
700 |
701 |
702 | -- Frame was adhering to parent alpha before.
703 | -- Start the fade with parent's current alpha.
704 | if not frame:IsIgnoringParentAlpha() then
705 | local parent = frame:GetParent()
706 | fadeInfo.startAlpha = parent and parent:GetAlpha() or 1
707 |
708 | -- Frame was already ignoring parent alpha before.
709 | else
710 | fadeInfo.startAlpha = frame:GetAlpha()
711 |
712 | end
713 | fadeInfo.endAlpha = targetAlpha
714 |
715 | ConditionalSetIgnoreParentAlpha(frame, true)
716 |
717 |
718 | -- Frame should henceforth adhere to parent alpha.
719 | else
720 |
721 | -- Frame was ignoring parent alpha before.
722 | -- Start the fade with the frame's alpha, fade to UIParent's target alpha
723 | -- and only then unset ignore parent alpha.
724 | -- Notice that the frame's alpha is not overriden by parent alpha but combined.
725 | -- So we have to set the child's alpha to 1 at the same time as we stop ignoring
726 | -- parent alpha.
727 | if frame:IsIgnoringParentAlpha() then
728 |
729 | fadeInfo.startAlpha = frame:GetAlpha()
730 | fadeInfo.endAlpha = targetAlpha
731 |
732 | fadeInfo.finishedFunc = function(finishedArg1, finishedArg2)
733 | -- if finishedArg1:GetName() == debugFrameName then print("Fade out finished", finishedArg1:GetName(), finishedArg2) end
734 | finishedArg1:SetAlpha(1)
735 | ConditionalSetIgnoreParentAlpha(finishedArg1, false)
736 | if finishedArg2 == 0 and (not finishedArg1:IsProtected() or not InCombatLockdown()) and not keepDefaultHiddenFramesAsParent[finishedArg1] then
737 | ConditionalHide(finishedArg1)
738 | end
739 |
740 | finishedArg1.ludius_alreadyOnIt = nil
741 | end
742 |
743 | -- Frame was already adhering to parent alpha.
744 | -- We are not changing it.
745 | else
746 |
747 | -- if frame:GetName() == debugFrameName then print("was already adhering to parent alpha") end
748 |
749 | fadeInfo.startAlpha = frame:GetAlpha()
750 | fadeInfo.endAlpha = frame:GetAlpha()
751 | end
752 |
753 | end
754 |
755 |
756 | -- Cannot rely on UIFrameFade to finish within the same frame.
757 | if duration == 0 then
758 | frame:SetAlpha(fadeInfo.endAlpha)
759 | fadeInfo.finishedFunc(frame, targetAlpha)
760 |
761 | -- This is for some frames to not being shown in between situations that are both hiding them.
762 | elseif (frame == MinimapCluster or frame == ObjectiveTrackerFrame) and targetAlpha == 0 and targetIgnoreParentAlpha == false and frame:GetParent():GetAlpha() == 0 and frame:IsShown() then
763 | fadeInfo.finishedFunc(frame, targetAlpha)
764 |
765 | else
766 | -- if frame:GetName() == debugFrameName then print("Starting fade with", fadeInfo.startAlpha, fadeInfo.endAlpha, fadeInfo.mode, fadeInfo.timeToFade) end
767 | UIFrameFade(frame, fadeInfo)
768 | end
769 |
770 | end
771 |
772 |
773 | local function FadeInFrame(frame, duration, enteringCombat)
774 |
775 | if not frame then return end
776 |
777 | -- If another addon is already handling this, we don't touch it.
778 | if frame.ludius_alreadyOnIt ~= nil and frame.ludius_alreadyOnIt ~= folderName then
779 | -- print(folderName, "not touching", frame:GetName())
780 | return
781 | else
782 | frame.ludius_alreadyOnIt = folderName
783 | end
784 |
785 |
786 | -- Prevent callback functions of currently active timers.
787 | UIFrameFadeRemoveFrame(frame)
788 |
789 | -- Only do something if we have touched this frame before.
790 | if frame.ludius_shownBeforeFadeOut == nil and frame.ludius_alphaBeforeFadeOut == nil and frame.ludius_ignoreParentAlphaBeforeFadeOut == nil then
791 | frame.ludius_alreadyOnIt = nil
792 | return
793 | end
794 |
795 | -- if frame:GetName() == debugFrameName then print("FadeInFrame", frame:GetName(), frame:IsIgnoringParentAlpha()) end
796 |
797 |
798 | if enteringCombat then
799 | -- When entering combat we have to show protected frames, which cannot be shown any more during combat.
800 | if frame:IsProtected() then
801 | ConditionalShow(frame)
802 | end
803 | frame.ludius_alreadyOnIt = nil
804 | -- But we do not yet do the fade in.
805 | return
806 | else
807 | ConditionalShow(frame)
808 | end
809 |
810 |
811 | -- To use UIFrameFade() which is the same as UIFrameFadeOut, but with a callback function.
812 | local fadeInfo = {}
813 | fadeInfo.mode = "IN"
814 | fadeInfo.timeToFade = duration
815 | fadeInfo.finishedArg1 = frame
816 | fadeInfo.finishedFunc = function(finishedArg1)
817 | finishedArg1.ludius_alphaBeforeFadeOut = nil
818 | finishedArg1.ludius_alphaAfterFadeOut = nil
819 | finishedArg1.ludius_alreadyOnIt = nil
820 | end
821 |
822 |
823 | -- Frame should henceforth ignore parent alpha.
824 | if frame.ludius_ignoreParentAlphaBeforeFadeOut == true then
825 |
826 | -- Frame was adhering to parent alpha before.
827 | -- Start the fade with parent's current alpha.
828 | if not frame:IsIgnoringParentAlpha() then
829 | fadeInfo.startAlpha = frame:GetParent():GetAlpha()
830 | -- Frame was already ignoring parent alpha before.
831 | else
832 | fadeInfo.startAlpha = frame:GetAlpha()
833 | end
834 | fadeInfo.endAlpha = frame.ludius_alphaBeforeFadeOut
835 |
836 | ConditionalResetIgnoreParentAlpha(frame)
837 |
838 | -- Frame should henceforth adhere to parent alpha.
839 | elseif frame.ludius_ignoreParentAlphaBeforeFadeOut == false then
840 |
841 | -- Frame was ignoring parent alpha before.
842 | -- Start the fade with the frame's alpha, fade to UIParent's target alpha
843 | -- (which is always 1 when we fade the UI back in) and only then unset
844 | -- ignore parent alpha.
845 | if frame:IsIgnoringParentAlpha() then
846 | fadeInfo.startAlpha = frame:GetAlpha()
847 | fadeInfo.endAlpha = 1
848 |
849 | fadeInfo.finishedFunc = function(finishedArg1)
850 | ConditionalResetIgnoreParentAlpha(finishedArg1)
851 | finishedArg1.ludius_alphaBeforeFadeOut = nil
852 | finishedArg1.ludius_alphaAfterFadeOut = nil
853 | finishedArg1.ludius_alreadyOnIt = nil
854 | end
855 |
856 | -- Frame was already adhering to parent alpha.
857 | -- We are not changing it.
858 | else
859 | fadeInfo.startAlpha = frame:GetAlpha()
860 | fadeInfo.endAlpha = frame:GetAlpha()
861 | end
862 |
863 | -- No stored value in ludius_ignoreParentAlphaBeforeFadeOut.
864 | else
865 | fadeInfo.startAlpha = frame:GetAlpha()
866 | fadeInfo.endAlpha = frame.ludius_alphaBeforeFadeOut or frame:GetAlpha()
867 | end
868 |
869 | -- if frame:GetName() == debugFrameName then print("Starting fade with", fadeInfo.startAlpha, fadeInfo.endAlpha, fadeInfo.mode) end
870 |
871 |
872 | -- Cannot rely on UIFrameFade to finish within the same frame.
873 | if duration == 0 then
874 | frame:SetAlpha(fadeInfo.endAlpha)
875 | fadeInfo.finishedFunc(frame)
876 | else
877 | UIFrameFade(frame, fadeInfo)
878 | end
879 |
880 | -- We can do this always when fading in.
881 | frame.ludius_fadeout = nil
882 | SetMouseOverAlpha(frame)
883 |
884 | end
885 |
886 |
887 | -- So the GameTooltip stays hidden while UI is faded.
888 | local hideGameTooltip = nil
889 | GameTooltip:HookScript("OnShow", function(self)
890 | if hideGameTooltip and self:GetOwner() == UIParent then
891 | self:Hide()
892 | end
893 | end)
894 |
895 |
896 | Addon.HideUI = function(fadeOutTime, config)
897 |
898 | -- print("HideUI", folderName, fadeOutTime, config.UIParentAlpha)
899 |
900 | keepDefaultHiddenFramesAsParent = {}
901 |
902 |
903 | -- Remember that the UI is faded.
904 | ludius_UiHideModule.uiHiddenTime = GetTime()
905 | ludius_UiHideModule.addonsHiddenStatus[folderName] = true
906 |
907 | currentConfig = config
908 |
909 | if config.hideFrameRate then
910 | -- The framerate label is a child of WorldFrame, while we just fade UIParent.
911 | -- That's why we have to set targetIgnoreParentAlpha to true.
912 | FadeOutFrame(FramerateLabel, fadeOutTime, true, config.UIParentAlpha)
913 | FadeOutFrame(FramerateText, fadeOutTime, true, config.UIParentAlpha)
914 | end
915 |
916 | AlertFramesSetIgnoreParentAlpha(config.keepAlertFrames)
917 | FadeOutFrame(CovenantRenownToast, fadeOutTime, config.keepAlertFrames, config.keepAlertFrames and 1 or config.UIParentAlpha)
918 |
919 | FadeOutFrame(MinimapCluster, fadeOutTime, config.keepMinimap, config.keepMinimap and 1 or config.UIParentAlpha)
920 | -- Minimap is needed, because Immersion sets it to IgnoreParentAlpha.
921 | FadeOutFrame(Minimap, fadeOutTime, config.keepMinimap, config.keepMinimap and 1 or config.UIParentAlpha)
922 |
923 | FadeOutFrame(GameTooltip, fadeOutTime, config.keepTooltip, config.keepTooltip and 1 or config.UIParentAlpha)
924 | C_Timer.After(fadeOutTime, function() hideGameTooltip = (config.keepTooltip == false) end)
925 | local shoppingTooltip1, shoppingTooltip2 = unpack(GameTooltip.shoppingTooltips)
926 | FadeOutFrame(shoppingTooltip1, fadeOutTime, config.keepTooltip, config.keepTooltip and 1 or config.UIParentAlpha)
927 | FadeOutFrame(shoppingTooltip2, fadeOutTime, config.keepTooltip, config.keepTooltip and 1 or config.UIParentAlpha)
928 |
929 | FadeOutFrame(AceGUITooltip, fadeOutTime, config.keepTooltip, config.keepTooltip and 1 or config.UIParentAlpha)
930 | FadeOutFrame(AceConfigDialogTooltip, fadeOutTime, config.keepTooltip, config.keepTooltip and 1 or config.UIParentAlpha)
931 |
932 |
933 | for i = 1, 12, 1 do
934 | if _G["ChatFrame" .. i] then
935 | FadeOutFrame(_G["ChatFrame" .. i], fadeOutTime, config.keepChatFrame, config.keepChatFrame and 1 or config.UIParentAlpha)
936 | FadeOutFrame(_G["ChatFrame" .. i .. "Tab"], fadeOutTime, config.keepChatFrame, config.keepChatFrame and 1 or config.UIParentAlpha)
937 | FadeOutFrame(_G["ChatFrame" .. i .. "EditBox"], fadeOutTime, config.keepChatFrame, config.keepChatFrame and 1 or config.UIParentAlpha)
938 | end
939 |
940 | if _G["GwChatContainer" .. i] then
941 | FadeOutFrame(_G["GwChatContainer" .. i], fadeOutTime, config.keepChatFrame, config.keepChatFrame and 1 or config.UIParentAlpha)
942 | end
943 | end
944 |
945 |
946 | -- Status tracking bars.
947 | -- Retail
948 | FadeOutFrame(StatusTrackingBarManager, fadeOutTime, config.keepTrackingBar, config.keepTrackingBar and config.trackingBarAlpha or config.UIParentAlpha)
949 | FadeOutFrame(BT4BarStatus, fadeOutTime, config.keepTrackingBar, config.keepTrackingBar and config.trackingBarAlpha or config.UIParentAlpha)
950 | -- Classic
951 | FadeOutFrame(MainMenuExpBar, fadeOutTime, config.keepTrackingBar, config.keepTrackingBar and config.trackingBarAlpha or config.UIParentAlpha)
952 | FadeOutFrame(ReputationWatchBar, fadeOutTime, config.keepTrackingBar, config.keepTrackingBar and config.trackingBarAlpha or config.UIParentAlpha)
953 | -- GW2 UI
954 | FadeOutFrame(GwExperienceFrame, fadeOutTime, config.keepTrackingBar, config.keepTrackingBar and config.trackingBarAlpha or config.UIParentAlpha)
955 |
956 |
957 | FadeOutFrame(EncounterBar, fadeOutTime, config.keepEncounterBar, config.keepEncounterBar and 1 or config.UIParentAlpha)
958 |
959 | FadeOutFrame(CompactRaidFrameContainer, fadeOutTime, config.keepPartyRaidFrame, config.keepPartyRaidFrame and 1 or config.UIParentAlpha)
960 |
961 |
962 |
963 | -- Non-configurable frames that we just want to hide in case UIParentAlpha is 0.
964 | for k in pairs(defaultHiddenFrames) do
965 | -- Using "not not" to convert nil to false.
966 | local keepFrame = not not config.keepCustomFrames and not not config.customFramesToKeep[k]
967 | FadeOutFrame(_G[k], fadeOutTime, keepFrame, keepFrame and 1 or config.UIParentAlpha)
968 | end
969 |
970 |
971 | -- Keep frames that are in config.customFramesToKeep but not in defaultHiddenFrames or flagFrames.
972 | if config.keepCustomFrames then
973 | for k in pairs(config.customFramesToKeep) do
974 | -- print(k, _G[k])
975 | if not defaultHiddenFrames[k] and not flagFrames[k] then
976 |
977 | -- If the frame does not exist yet (e.g. ClassTrainerFrame), try again after a short time.
978 | if not _G[k] then
979 | C_Timer.After(0.3, function() FadeOutFrame(_G[k], fadeOutTime, true, 1) end)
980 | else
981 | -- At the moment we are not supporting custom alphas for kept frames, so we set it to 1.
982 | FadeOutFrame(_G[k], fadeOutTime, true, 1)
983 | end
984 | end
985 | end
986 | end
987 |
988 | if Addon.frameShowTimer then LibStub("AceTimer-3.0"):CancelTimer(Addon.frameShowTimer) end
989 |
990 | end
991 |
992 |
993 |
994 |
995 | -- If enteringCombat we only show the hidden frames (which cannot be shown
996 | -- during combat lockdown). But we skip the SetIgnoreParentAlpha(false).
997 | -- This can be done when the intended ShowUI() is called.
998 | Addon.ShowUI = function(fadeInTime, enteringCombat)
999 |
1000 | -- Just to be on the safe side.
1001 | keepDefaultHiddenFramesAsParent = {}
1002 |
1003 | ludius_UiHideModule.addonsHiddenStatus[folderName] = false
1004 |
1005 | -- Only do something once per closing.
1006 | if ludius_UiHideModule.uiHiddenTime == 0 then return end
1007 |
1008 | -- print("ShowUI", folderName, fadeInTime, enteringCombat)
1009 |
1010 | if not enteringCombat then
1011 | ludius_UiHideModule.uiHiddenTime = 0
1012 | currentConfig = nil
1013 | end
1014 |
1015 | FadeInFrame(FramerateLabel, fadeInTime, enteringCombat)
1016 | FadeInFrame(FramerateText, fadeInTime, enteringCombat)
1017 |
1018 |
1019 | FadeInFrame(CompactRaidFrameContainer, fadeInTime, enteringCombat)
1020 |
1021 |
1022 | for k in pairs(defaultHiddenFrames) do
1023 | FadeInFrame(_G[k], fadeInTime, enteringCombat)
1024 | end
1025 |
1026 |
1027 | -- Fade in the (possibly only partially) faded status bar.
1028 | -- Retail.
1029 | FadeInFrame(StatusTrackingBarManager, fadeInTime, enteringCombat)
1030 | FadeInFrame(BT4BarStatus, fadeInTime, enteringCombat)
1031 | -- Classic
1032 | FadeInFrame(MainMenuExpBar, fadeInTime, enteringCombat)
1033 | FadeInFrame(ReputationWatchBar, fadeInTime, enteringCombat)
1034 | -- GW2 UI
1035 | FadeInFrame(GwExperienceFrame, fadeInTime, enteringCombat)
1036 |
1037 |
1038 | FadeInFrame(CovenantRenownToast, fadeInTime, enteringCombat)
1039 |
1040 | FadeInFrame(MinimapCluster, fadeInTime, enteringCombat)
1041 | FadeInFrame(Minimap, fadeInTime, enteringCombat)
1042 |
1043 | hideGameTooltip = false
1044 | FadeInFrame(GameTooltip, fadeInTime, enteringCombat)
1045 | local shoppingTooltip1, shoppingTooltip2 = unpack(GameTooltip.shoppingTooltips)
1046 | FadeInFrame(shoppingTooltip1, fadeInTime, enteringCombat)
1047 | FadeInFrame(shoppingTooltip2, fadeInTime, enteringCombat)
1048 |
1049 | FadeInFrame(AceGUITooltip, fadeInTime, enteringCombat)
1050 | FadeInFrame(AceConfigDialogTooltip, fadeInTime, enteringCombat)
1051 |
1052 |
1053 | for i = 1, 12, 1 do
1054 | if _G["ChatFrame" .. i] then
1055 | FadeInFrame(_G["ChatFrame" .. i], fadeInTime, enteringCombat)
1056 | FadeInFrame(_G["ChatFrame" .. i .. "Tab"], fadeInTime, enteringCombat)
1057 | FadeInFrame(_G["ChatFrame" .. i .. "EditBox"], fadeInTime, enteringCombat)
1058 | end
1059 |
1060 | if _G["GwChatContainer" .. i] then
1061 | FadeInFrame(_G["GwChatContainer" .. i], fadeInTime, enteringCombat)
1062 | end
1063 | end
1064 |
1065 |
1066 | FadeInFrame(EncounterBar, fadeInTime, enteringCombat)
1067 |
1068 |
1069 | -- Cancel timers that may still be in progress.
1070 | if Addon.frameShowTimer then LibStub("AceTimer-3.0"):CancelTimer(Addon.frameShowTimer) end
1071 |
1072 | if not enteringCombat then
1073 | -- Reset the IgnoreParentAlpha after the UI fade-in is finished.
1074 | Addon.frameShowTimer = LibStub("AceTimer-3.0"):ScheduleTimer(function()
1075 | AlertFramesResetIgnoreParentAlpha()
1076 | end, fadeInTime)
1077 | end
1078 |
1079 | end
1080 |
1081 |
1082 |
1083 | -- If party/raid members join/leave while the UI is faded, we prevent the frames from being shown again.
1084 | -- This code is similar to the respective part of HideUI(), see comments there.
1085 |
1086 | -- We have to do the OnShow hook, because the GROUP_ROSTER_UPDATE event comes too late.
1087 | for i = 1, 4, 1 do
1088 | if _G["PartyMemberFrame" .. i] then
1089 | _G["PartyMemberFrame" .. i]:HookScript("OnShow", function()
1090 | if not currentConfig or ludius_UiHideModule.uiHiddenTime == 0 then return end
1091 | FadeOutFrame(_G["PartyMemberFrame" .. i .. "NotPresentIcon"], 0, true, currentConfig.keepPartyRaidFrame and 1 or currentConfig.UIParentAlpha)
1092 | FadeOutFrame(_G["PartyMemberFrame" .. i], 0, currentConfig.keepPartyRaidFrame, currentConfig.keepPartyRaidFrame and 1 or currentConfig.UIParentAlpha)
1093 | end)
1094 | end
1095 | end
1096 |
1097 |
1098 |
1099 | -- The CompactRaidFrameContainer frame gets shown every time the raid roster changes.
1100 | -- While the UI is hidden, we have to hide it again.
1101 | CompactRaidFrameContainer:HookScript("OnShow", function()
1102 | if not currentConfig or ludius_UiHideModule.uiHiddenTime == 0 then return end
1103 | if currentConfig.keepPartyRaidFrame == false then
1104 | FadeOutFrame(CompactRaidFrameContainer, 0, false, currentConfig.UIParentAlpha)
1105 | end
1106 | end)
1107 |
1108 |
--------------------------------------------------------------------------------
/embeds.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------