- 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>
55 lines
2.6 KiB
Rust
55 lines
2.6 KiB
Rust
//! The pet bar's `WorldWriter` sends — mirroring [`crate::messages::pet`] (decisions 0982, 0988).
|
|
//!
|
|
//! Three verbs, and the thing to know about them is that **the server answers none of them**.
|
|
//! Every one is an intent the client has already applied to its own state before sending
|
|
//! (wow-re §10.1/§10.2: the reaction, command and autocast paths all write `[0xb71468]` or the
|
|
//! slot word and fire `PET_BAR_UPDATE` *before* the packet leaves). The bar's contents change only
|
|
//! when a fresh `SMSG_PET_SPELLS` arrives — a summon, a swap, a learned spell — never as a reply
|
|
//! to one of these.
|
|
//!
|
|
//! Every one carries the pet's guid: the server re-checks ownership on each
|
|
//! (`PetHandler.cpp`'s `GetCharmerOrOwnerGuid` gate) and silently drops anything naming a unit we
|
|
//! don't control.
|
|
|
|
use anyhow::Result;
|
|
|
|
use crate::messages::{self, opcode};
|
|
|
|
use super::WorldWriter;
|
|
|
|
impl WorldWriter {
|
|
/// Press one pet bar slot (`CMSG_PET_ACTION`, layout in [`messages::pet_action`]) — the one
|
|
/// verb behind all three slot classes, because the server dispatches on the **type byte inside
|
|
/// the word we echo**: a command token runs `HandlePetCommand`, a reaction token sets the react
|
|
/// state, a spell casts. `target` is the unit the action should aim at, or `0`.
|
|
pub fn pet_action(&mut self, pet_guid: u64, packed: u32, target_guid: u64) -> Result<()> {
|
|
self.send(
|
|
opcode::CMSG_PET_ACTION,
|
|
&messages::pet_action(pet_guid, packed, target_guid),
|
|
)
|
|
}
|
|
|
|
/// Call the pet off its target (`CMSG_PET_STOP_ATTACK`, layout in
|
|
/// [`messages::pet_stop_attack`]) — the Attack button's second press.
|
|
pub fn pet_stop_attack(&mut self, pet_guid: u64) -> Result<()> {
|
|
self.send(
|
|
opcode::CMSG_PET_STOP_ATTACK,
|
|
&messages::pet_stop_attack(pet_guid),
|
|
)
|
|
}
|
|
|
|
/// Write one or two pet bar slots (`CMSG_PET_SET_ACTION`, layout — and the reason this one
|
|
/// opcode carries two different verbs — in [`messages::pet_set_action`]).
|
|
///
|
|
/// **The autocast toggle is this send**, with one entry: the pressed slot and its word with
|
|
/// bit 30 flipped. The drag is the same send with one or two. Unlike the player bar's
|
|
/// [`WorldWriter::set_action_button`], a swap here IS atomic — the server tells the forms
|
|
/// apart by body size and applies both entries together.
|
|
pub fn pet_set_action(&mut self, pet_guid: u64, entries: &[(u32, u32)]) -> Result<()> {
|
|
self.send(
|
|
opcode::CMSG_PET_SET_ACTION,
|
|
&messages::pet_set_action(pet_guid, entries),
|
|
)
|
|
}
|
|
}
|