pets get their action bar, macros arrive, and hunters draw the bow

- a hunter's or warlock's pet has its action bar now: attack, follow, stay, the pet's own spells with cooldowns and autocast sparkles
- the macro system lands: the macro window, the icon chooser, /cast and /macro, and macros dragged onto the action bar
- hunter shots look right at last: the bow draws and releases on the shot, and the arrow lays a spark trail its whole flight
- the options window re-dresses in 1.12's own art with the classic dialog look, and gets a working search box and clickable steppers

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Sam
2026-08-05 19:03:13 +07:00
co-authored by Claude Fable 5
parent 994be22f5c
commit 77dc8f8ead
98 changed files with 8922 additions and 1089 deletions
+6 -1
View File
@@ -16,7 +16,7 @@
use mlua::Lua;
use crate::script::action::{ACTION_KIND_ITEM, ACTION_KIND_SPELL};
use crate::script::action::{ACTION_KIND_ITEM, ACTION_KIND_MACRO, ACTION_KIND_SPELL};
use crate::script::{ActionSlot, Model};
use super::{queue_cursor_update, CursorAction, CursorPayload};
@@ -114,6 +114,11 @@ pub(crate) fn place_action(model: &mut Model, id: u32) -> bool {
CursorPayload::Action(a) => (a.kind, a.action, a.texture.clone()),
CursorPayload::Item(i) => (ACTION_KIND_ITEM, i.item_id, i.texture.clone()),
CursorPayload::Spell(s) => (ACTION_KIND_SPELL, s.spell_id, s.texture.clone()),
// Mode 8 — the one non-item/non-spell payload the reference's `PlaceAction` accepts
// (`action-item-slot.md` §5's payload table: pet actions and class abilities are refused,
// macros are not). It packs the bare macro id under the MACRO tag, exactly as the SPELL
// and ITEM arms pack theirs.
CursorPayload::Macro(m) => (ACTION_KIND_MACRO, m.index, m.texture.clone()),
};
let displaced = model.actions.insert(
id,
+3 -1
View File
@@ -101,7 +101,9 @@ pub(super) fn pickup_inventory_item(model: &mut Model, id: u32) -> bool {
queue_lock_changed(model, held.bag, held.slot);
true
}
Some(other @ (CursorPayload::Spell(_) | CursorPayload::Action(_))) => {
Some(
other @ (CursorPayload::Spell(_) | CursorPayload::Action(_) | CursorPayload::Macro(_)),
) => {
model.cursor = Some(other);
false
}