app+ui: the trinket cooldown — and a stock verb that always said "cold"
Built: GetTrinketCooldown, UseTrinket, GetSpellRangeData, SetLocalRaidTargetIndex, GetQuestLogQuestIds, GetQuestDialogQuestId, CombatLogFlush. The find on the way through is not a nampower verb. **`GetInventoryItemCooldown` is a stock 1.12 verb and it answered `(0, 0, 1)` unconditionally** — right shape, always "cold", so nothing errored and no worn trinket ever drew its cooldown swirl on the character pane. Stock PaperDollFrame.lua:691 calls it on every slot update. Feeding an equipped slot's cooldown for GetTrinketCooldown fixes that one off the same column, and the test runs `CooldownFrame_SetTimer`'s own arithmetic against it. The feed keys its query on the (use spell, item entry) pair exactly as the bag feed does, so one trinket reads the same cooldown from the doll and from a bag. **The risk was the gate, and my first test for it was vacuous.** `feed_char` sits behind a change gate and no descriptor moves when a cooldown is armed, so `Cooldowns::feed_epoch` had to become a gate input. The first test passed with that input deleted: `run_system_once` builds a fresh system each call, so the gate's `Local` memo resets and `vm_reset` opens the gate every time. A test for a gate input has to run the system the way the schedule does. Rewritten with `add_systems` + `update`, it fails with the input removed — verified by probe, and the reason is written at the test. `feed_char` also hit Bevy's sixteen-parameter ceiling, which was a fair signal its parameters wanted grouping by what they are for: `ItemCooldownInputs` and `RepairInputs` replace six. Two decisions recorded at the code: - `GetSpellRangeData(rangeIndex)` answers three values, not a table. Every table-returning verb in this DLL has its key names in the string pool and this row's are not there. `flags` bit 0 is the melee family, where the engine takes the combat-reach sum instead of the authored pair — a caller ignoring the bit reads 0..5 for every melee ability. - `CombatLogFlush()` is a deliberate no-op. Upstream buffers its combat-log writes and this empties the buffer, so what an addon asks for is "my lines are on disk now" — and `ui_chat/logging.rs` writes each line to an unbuffered File as the window shows it, so that holds at all times. Defining it is the honest answer: the capability is present, and a missing global makes `HasFeature` report it absent. Also fed, both one wire column each: `QuestState::quest_id` (the wire names the quest on all three giver panels and 1.12's Lua names it nowhere — a title is not a key) and `SpellDisplay::stack_amount`'s neighbour work from the previous commit. Five names stay out, each now with the field list that makes it a decision rather than a shrug — `GetUnitData` (80 raw descriptor columns, read off the pool, zero call sites, and a partial answer is worse than none), `GetRaidTargets` (the reference keeps a board; this client feeds the mark per unit, and a scan over named tokens would silently omit a marked unit), `DisenchantAll` (a server-paced sequencer, which is the queue), `GetSpellPower`, `StartItemExport` (writes a file — it belongs with the withheld seven). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
This commit is contained in:
@@ -1375,6 +1375,9 @@ fn the_bar_bag_buttons_name_themselves_on_hover() {
|
||||
// inventory slot 20.
|
||||
let mut inv: benilla_ui::script::InventorySlots = Default::default();
|
||||
inv[20] = Some(benilla_ui::script::InvSlotView {
|
||||
cooldown: None,
|
||||
cooldown_legs: Default::default(),
|
||||
use_spell_id: 0,
|
||||
duration_ms: None,
|
||||
already_bound: false,
|
||||
bar_placeable: true,
|
||||
|
||||
@@ -52,6 +52,9 @@ fn combat_stats() -> UnitCombatStats {
|
||||
fn inventory_with_head_item() -> InventorySlots {
|
||||
let mut slots: InventorySlots = Default::default();
|
||||
slots[1] = Some(InvSlotView {
|
||||
cooldown: None,
|
||||
cooldown_legs: Default::default(),
|
||||
use_spell_id: 0,
|
||||
duration_ms: None,
|
||||
already_bound: false,
|
||||
bar_placeable: true,
|
||||
|
||||
@@ -288,6 +288,14 @@ fn install_spell_catalog_probe(world: &World, script: &mut UiScript) {
|
||||
// mechanic *name* needs it, so a missing or unreadable one costs exactly that name — not
|
||||
// the duration, the cost and the icon id beside it, which was the case while this whole
|
||||
// block sat inside `if let Some(mechanics)`.
|
||||
// nampower's `GetSpellRangeData(rangeIndex)`: `SpellRange.dbc` by row index, which no
|
||||
// other verb here reaches — `IsSpellInRange` answers the verdict, never the yards.
|
||||
{
|
||||
let ranges = spells.ranges.clone();
|
||||
script.set_spell_range_probe(Box::new(move |index| {
|
||||
ranges.get(index).map(|r| (r.min, r.max, r.flags))
|
||||
}));
|
||||
}
|
||||
install_spell_extras_probes(
|
||||
script,
|
||||
&spells.catalog,
|
||||
|
||||
@@ -73,6 +73,9 @@ fn harness_with_bags() -> UiScript {
|
||||
fn seed_items(s: &mut UiScript) {
|
||||
let mut inv: InventorySlots = Default::default();
|
||||
inv[1] = Some(InvSlotView {
|
||||
cooldown: None,
|
||||
cooldown_legs: Default::default(),
|
||||
use_spell_id: 0,
|
||||
duration_ms: None,
|
||||
already_bound: false,
|
||||
bar_placeable: true,
|
||||
@@ -194,6 +197,9 @@ fn doll_hover_renders_the_live_instance() {
|
||||
// A broken helm: instance pair (0, 40), the template at full.
|
||||
let mut inv: InventorySlots = Default::default();
|
||||
inv[1] = Some(InvSlotView {
|
||||
cooldown: None,
|
||||
cooldown_legs: Default::default(),
|
||||
use_spell_id: 0,
|
||||
duration_ms: None,
|
||||
already_bound: false,
|
||||
bar_placeable: true,
|
||||
|
||||
Reference in New Issue
Block a user