the bank is the reference's own window, and far sight freezes your body
- the bank window is the reference's own `BankFrame.xml` run off the player's chain — our 890-line copy is deleted whole; putting bags into the bank's bag slots works (the two verbs its buttons are wired to now exist), the purse is a real `SmallMoneyFrameTemplate` splitting 987654321 copper into three coin buttons instead of one string, `BANKFRAME_OPENED` loses the argument the real client never fires, and the bank stops auto-opening your bags while the vendor and mailbox keep doing it; the empty-slot click still plays the bag sound, because the reference's own line plays it on every click the cursor did not consume — named as faithful rather than quietly fixed - underneath it, the bank's inventory band is a VIEW over the container feed, not a second copy — inventory ids 40..69 had answered nil because the doll array stops at 24, so the stock file swapped in would have drawn an empty bank; the six bank bag slots become real inventory slots (64..=69) fed off the player descriptor, the three bag verbs are carved from the binary (`PutItemInBackpack` IS `PutItemInBag(0xFF)` through a ten-byte thunk, the occupied-by-an-ordinary-item leg auto-stores with no destination slot at all, and the return is the Lua number 1 or nil — the nil being the whole reason a plain left-click opens a bag), and the swap caught `BankButtonIDToInvSlotID`'s bag arm six slots wrong: it took a bag number 1..6 where the reference passes the button's own id, which is the container id - far sight freezes your own body while the view is out — the fifth conjunct of the movement predicates' shared precondition, joining the health term so the walk, the turn and the follow teardown go down together; both halves are load-bearing: the `IsActivePlayer` half is what keeps a Mind Control victim walking (possession rides the same PLAYER_FARSIGHT field), and the latch half is the RESOLVED engage rather than the raw field — and the camera is untouched, you still look around freely, which is the whole point of the spell - the reset offer no longer outlives the character that earned it — log out after walking out of the Deadmines and your next character was offered a reset the first one had earned — and the one lockout leg no probe can ever reach (vmangos writes a last-instance map only from raid binds, which the client's handler discards as not-a-party-dungeon) is now covered end to end through the real system, its module doc saying plainly: tested and never observed Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -124,6 +124,68 @@ pub(super) fn drain_container_autoequips(
|
||||
}
|
||||
}
|
||||
|
||||
/// Drain the auto-stores `PutItemInBag`/`PutItemInBackpack` queued (`benilla_ui`'s
|
||||
/// `cursor::bag_verbs`) and send them on the wire.
|
||||
///
|
||||
/// **The destination is a BAG, not a slot** — that is the finding this drain exists to carry
|
||||
/// (wow-re `bag-verbs-law.md`): `CMSG_AUTOSTORE_BAG_ITEM` names `(srcbag, srcslot, dstbag)` and
|
||||
/// the server picks where inside it the item lands, which is why an ordinary item dropped on a
|
||||
/// bag BUTTON goes in the bag rather than swapping with it. The destination bag byte is
|
||||
/// [`wire_pos`]'s own answer for that container's first slot (255 for the backpack, the bag's
|
||||
/// player-array slot 19..22 / 63..68 for an equipped or bank bag), so one map serves both ends.
|
||||
///
|
||||
/// A **split carry** takes `CMSG_SPLIT_ITEM` instead — the reference's own fork on `[0xb4b40c]`
|
||||
/// — with the literal `0xFF` where a destination slot would go, because that wire has a slot
|
||||
/// field and this one does not.
|
||||
///
|
||||
/// No pending-lock recording, matching [`drain_container_autoequips`]'s own precedent for the same
|
||||
/// class of send: the destination is not a slot, so there is no second end to lock.
|
||||
pub(super) fn drain_bag_autostores(
|
||||
script: Option<NonSendMut<UiScript>>,
|
||||
commands: Res<NetCommands>,
|
||||
) {
|
||||
let Some(mut script) = script else {
|
||||
return;
|
||||
};
|
||||
for a in script.take_bag_autostores() {
|
||||
let (Some((src_bag, src_slot)), Some((dst_bag, _))) =
|
||||
(wire_pos(a.src_bag, a.src_slot), wire_pos(a.dst_bag, 1))
|
||||
else {
|
||||
debug!("ui_items: bag autostore {a:?} out of range — ignored");
|
||||
continue;
|
||||
};
|
||||
match a.count {
|
||||
None => {
|
||||
debug!(
|
||||
"ui_items: autostore lua {}/{} → bag {} (wire {src_bag}/{src_slot} → {dst_bag})",
|
||||
a.src_bag, a.src_slot, a.dst_bag
|
||||
);
|
||||
let _ = commands.0.send(ClientCommand::AutoStoreBagItem {
|
||||
src_bag,
|
||||
src_slot,
|
||||
dst_bag,
|
||||
});
|
||||
}
|
||||
Some(n) => {
|
||||
let count = n.min(u32::from(u8::MAX)) as u8;
|
||||
debug!(
|
||||
"ui_items: autostore split lua {}/{} → bag {} × {count} (wire {src_bag}/{src_slot} → {dst_bag})",
|
||||
a.src_bag, a.src_slot, a.dst_bag
|
||||
);
|
||||
let _ = commands.0.send(ClientCommand::SplitItem {
|
||||
src_bag,
|
||||
src_slot,
|
||||
dst_bag,
|
||||
// `0xFF` — the reference's own literal for "no destination slot"; the split
|
||||
// wire has the field, the verb has no value for it.
|
||||
dst_slot: 0xFF,
|
||||
count,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Drain the inventory-slot ids `UseInventoryItem` queued (decision 0208 phase 1b: the doll
|
||||
/// slot's right-click) and route the equipped position (bag 255 plus the 0-based wire slot —
|
||||
/// `HandleUseItemOpcode` takes equipped positions the same as bag ones, vmangos `ItemHandler.cpp`)
|
||||
|
||||
@@ -53,8 +53,8 @@ pub(crate) mod feed;
|
||||
|
||||
pub(crate) use drain::send_auto_equip;
|
||||
use drain::{
|
||||
drain_container_autoequips, drain_container_destroys, drain_container_moves,
|
||||
drain_container_uses, drain_inventory_uses,
|
||||
drain_bag_autostores, drain_container_autoequips, drain_container_destroys,
|
||||
drain_container_moves, drain_container_uses, drain_inventory_uses,
|
||||
};
|
||||
use feed::{
|
||||
feed_containers, feed_item_sets, feed_item_stats, feed_player_req, feed_random_properties,
|
||||
@@ -1112,6 +1112,7 @@ impl Plugin for UiItemsPlugin {
|
||||
drain_container_destroys.after(UiInput),
|
||||
// AutoEquipCursorItem's queue (decision 0208 phase 1b) → CMSG_AUTOEQUIP_ITEM.
|
||||
drain_container_autoequips.after(UiInput),
|
||||
drain_bag_autostores.after(UiInput),
|
||||
// UseInventoryItem's queue (decision 0208 phase 1b) → CMSG_USE_ITEM against
|
||||
// the equipped position.
|
||||
drain_inventory_uses.after(UiInput),
|
||||
|
||||
Reference in New Issue
Block a user