Overview
New
- Game settings: checkboxes with a slider or a dropdown (for example "Max foreground FPS"), buttons, the "Graphics quality" block and the colorblind settings can now be operated; they used to read "not supported".
- Game settings: number values start with an "Enter value" entry (text box), digits filter the value list, and the values carry the game's own labels ("60 FPS", "150%").
- Game settings: dropdowns say "(recommended)" and "(not available)" like the game, greyed-out rows say "(disabled)", and subcategories of addon settings are shown.
Changes
- Game error messages (for example "You have no target") are read only once while you hammer a key. The same message is announced again only after you have left the key alone for about two and a half seconds, or when a different error message came in between.
- Turn to beacon, waypoint or unit: the turn now lands equally precisely on every machine and is much faster. At 20 frames per second a half turn took almost half a second and every fourth key press was lost; now a quarter of a second, and hardly any press is lost. On fast machines big turns land within about one degree instead of three to five. The self-calibration from v43.7 is gone.
Bugfixes
- Speech: since v43.7 the same line queued up again on every key press and was read many times in a row, even after a more important announcement. Fixed.
- Menu: pressing a key (End, Home, arrow) right after "menu open" still got you the first main-menu entry ("Target menu") read out after the new entry. Fixed.
Speech: a line no longer queues up behind itself
Simple: Since v43.7 a message that was triggered several times in quick succession could enter the queue any number of times. If you hammered a key that raises an error, you then heard "You have no target" ten or twenty times, and after a target announcement cut in, the message came once more. Now: if the same text is already waiting or is being spoken right now, the new copy is discarded. Menu lines and other announcements you explicitly ask for again with a key are not affected.
Technically: SkuVoice:OutputStringBTtts (Libs/SkuVoice-1.0). The "is exactly this being spoken" check used to run at the handover to the client. Since the v43.7 client gate a copy only reaches the handover once its predecessor has FINISHED - the check never matched any more (log: queue 35 x the same line). Lines without a queuereset are now checked when they are ENQUEUED, against mSkuVoiceQueueBTTS and
mSkuVoiceQueueBTTS_Speaking; log tag "BTTS ENQUEUE-DUP". New harness scenario "errspam" (dev/rework-docs/voice-harness).
Menu: the first entry was still spoken late after a quick key press
Simple: When the menu opens, Sku says "menu open" and then the first entry. If you pressed a key while "menu open" was still speaking, you heard the new entry - and after it "Target menu", the first entry, which was no longer the current one. It depended only on how fast you pressed, not on the key or the menu. Now the old first entry is dropped as soon as another menu entry is announced.
Technically: Two causes. (1) The v43.7 rule "keep a waiting line without a reset behind the new overwrite line" (meant for chat that a warning cuts into) also applied to menu lines. The keep loop in SkuVoice (queuereset scan, Libs/SkuVoice-1.0) now drops a waiting line whose scope equals the scope of the new overwrite line: a scope is one position in one UI, only its newest line is true. (2) The two lines spoken at open ("Menu;open" and SkuOptions.Menu[1].name, SkuZOptions/Core.lua) called OutputStringBTtts directly WITHOUT the "menu" scope that VocalizeCurrentMenuName gives every other menu line - so the scope comparison had nothing to compare. Both carry "menu" now; as a side effect EndScope("menu") drops both when the menu is closed again at once. Log before: "BTTS queuereset kept 1 waiting line(s) behind the overwrite".
Error messages: announced only when they newly appear
Simple: Sku now follows the rule the game applies for sighted players. There an error message stays on screen for about two and a half seconds; if the same message comes again during that time, it only flashes briefly and stays longer instead of appearing anew. Accordingly Sku reads an error message when it appears and stays quiet while it is still "on screen". Every further key press extends that time. The game's click sound still tells you on every press that it is not working yet. If you leave the key alone for about two and a half seconds and then press again, the message is announced again. A DIFFERENT error message is always read at once, and after it the first one counts as new again: error A, error B, error A are three announcements. This affects spoken errors only, not the sound and voice hints.
Technically: UIErrors:OutputError (SkuCore/UIErrors.lua), TTS branch. Only the LAST spoken error is remembered: tSpokenKey plus tSpokenShownUntil = GetTime() + 2.5 (displayDuration 2 + fadeDuration 0.5 from UIErrorsFrame.xml). Every repeat sets the time again, like ResetMessageFadeByID; any other error, including a sound or voice hint, replaces or clears tSpokenKey. The first version kept one time stamp PER text - so error A stayed silent although error B had come in between. Deliberately a time stamp and not a read of UIErrorsFrame: Blizzard throttles only about 20 message types, for the rest a new line is added per press, and the order of the two UI_ERROR_MESSAGE handlers is not defined.
Game settings: every control of the Blizzard settings
Simple: In the menu Settings, Game settings many entries only read "(not supported)", for example "Max foreground FPS". They can be operated now. A checkbox with a slider becomes two entries: the switch and "... value". Number values are a value list with the game's own labels ("60 FPS", "150%"); digits filter the list, and the first entry "Enter value" opens the text box. Dropdowns mark the recommendation with "(recommended)" and values this machine cannot run with "(not available)". Buttons such as "Reset chat position" run their action. The "Graphics quality" block is a submenu with "Raid and battleground". Key bindings link to Sku's own menu. A setting the game currently greys out says "(disabled)". Also, graphics, display and UI scale settings used to be staged only and never applied - they take effect immediately now.
Technically: SkuCore/gameOptions.lua now dispatches on the initializer's frame template (Blizzard_SettingControls.lua) instead of the value type: Checkbox, Slider, Dropdown, CheckboxSlider (cbSetting/sliderSetting), CheckboxDropdown, CheckboxWithButton, Button, AdvancedQualitySection (its option lists are closures inside the frame; Sku derives them from a table per cvar and asks IsGraphicsSettingValueSupported), ColorblindSelector, keybinding sections. setting:SetValue(v) without the second argument only stores a pendingValue on settings carrying CommitFlag.Apply, which only the panel's Apply button writes - Sku never opens the panel, hence SetValue(v, true) now, plus RestartGx / UpdateWindow / SaveBindings by commit flag. GetAllCategories returns top-level categories only; GetSubcategories is walked recursively. ShouldShow false = row skipped, GetModifyPredicates false = suffix "(disabled)". Value labels come from options.formatters[Label.Right]; typed input is mapped back linearly through the formatter (percent, quality slider 1..10). Every write logs "gameOptions: set". An offline harness against fake Setting objects passed; verified in game: the FPS switch and value (log: PROXY_FOREGROUND_FPS = 20, TurnCal fps 20).
Turn to beacon: frame-exact instead of time-based
Simple: Until now Sku rotated the camera for a computed time and then stopped it. The game only moves the camera once per frame, and a timer hits the frame boundary only roughly - at low frame rates it misses. On a slow machine (20 frames per second, reproduced in the test with the FPS limit) every turn over 15 degrees therefore took almost half a second, small turns fell a third short, every fourth key press hit the busy window and was lost, and mounted you circled close waypoints again. Now Sku counts the frames and uses their real duration: the turn speed is chosen so the angle is a whole number of frame steps, and if the last step would overshoot, it is shortened. Result at 20 frames per second: a half turn in a quarter of a second, every turn within two degrees, hardly any lost presses, no circling. At 80 to 120 frames: big turns with about one degree of error instead of three to five, small ones under half a degree. The self-calibration from v43.7 is gone - it learned values that are the same on every machine. /skuturn now only shows whether the fast gear works on this machine; /skuturn reset clears that check.
Technically: GameWorldObjects:TurnToWorldPosition (SkuCore/gameWorldObjects.lua). Measured on about 400 turns at 20 and 77 to 125 fps (residual 0.5 ms): the camera steps once per frame by speed times the REAL frame duration; the frame whose OnUpdate issues the stop no longer steps; the frame duration measured in an OnUpdate is exactly the next step's. Planner: n = ceil(angle / (1440 * f)) steps, v = angle / (n * f), CVar at most 360, the rest as the MoveView factor. The stop comes from an OnUpdate counter that accumulates the real frame durations and stops as soon as the sum reaches the motion time angle/v; if the last step would overshoot, cameraYawMoveSpeed is scaled to the remainder for that one frame and the stop follows in the next - the CVar takes effect at once (54 trimmed turns: error 0.5 degrees instead of the 5.3 a dead CVar would have given). C_Timer was the cause of the old scatter: it only fires on frame boundaries and slips a whole frame at 2 percent frame jitter. The camera "glide" of v43.7 was this one idle frame, not momentum. The calibration (scale and latency per gear, store v4/v5) learned 1.00 and one frame with a spread of 0.01 and was removed; store turnCal v6 only keeps noGear2 (factor has no effect: median real/asked speed under 0.7 over 6+ fast turns). Busy window after the stop 2 frames or 50 ms instead of 3 or 100. Log "TurnCal" per press with n, m, mt, trim, dts (all frame durations), fest/fact/fmax, rest_land, lead_shift; analysis script pattern an4.py in the scratchpad. Lessons for WowVision: dev/rework-docs/TURN-TO-BEACON-LESSONS.md.