the combat log speaks, and the swim line follows your native form
- the client synthesises its combat-log chat lines: 44 chat types over 34 GlobalString families from 7 packets, the reference's own four hops (classify both endpoints → chat type → string key → format), text resolved out of the player's own GlobalStrings — so damage meters and Quiver's TranqAnnouncer have something to parse; wow-re's byte round corrected six gates (owner is charmed-by then created-by, "party" is your subgroup, friend-or-foe is CanAttack, the range gate, the miss defaults, the damage-shield chat type) - the collision prism follows the NATIVE display, not the rendered one: a druid in bear form keeps the druid's swim, splash and wade lines and a morph keeps the human's — worst divergence on shipped data 0.72 yd (tauren moonkin), the sign flipping by form - the creature swim gate is on both legs: a unit that loses its flag mid-water is driven out of swim at any depth, as the reference drops a charmed creature to the seabed on the next tick Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -44,6 +44,14 @@ pub struct AttackerState {
|
||||
pub resist: i32,
|
||||
/// `BlockedAmount` — the trailing blocked-damage word.
|
||||
pub blocked: u32,
|
||||
/// The **first** sub-damage block's school (`SpellSchools`: 0 physical … 6 arcane; vmangos
|
||||
/// writes `GetFirstSchoolInMask(subDamage->damageSchoolMask)`), `0` when the swing carried no
|
||||
/// sub-damage at all.
|
||||
///
|
||||
/// It exists for the combat log's wording: a non-physical swing takes the `…SCHOOL` template
|
||||
/// ("You hit X for 5 fire damage.") and physical takes the plain one. The floating text has
|
||||
/// never needed it, which is why the field was read and dropped until B297.
|
||||
pub school: u8,
|
||||
}
|
||||
|
||||
/// Read `SMSG_ATTACKERSTATEUPDATE` (byte-verified order, attacker **PackGUID first** — settled by
|
||||
@@ -59,9 +67,15 @@ pub(super) fn read_attacker_state(r: &mut impl Read) -> io::Result<AttackerState
|
||||
let subs = read_u8(r)?;
|
||||
let mut absorb = 0u32;
|
||||
let mut resist = 0i32;
|
||||
for _ in 0..subs {
|
||||
// school, damage f32, damage u32 — folded into TotalDamage above; absorb/resist summed.
|
||||
let _school = read_u32_le(r)?;
|
||||
let mut school = 0u8;
|
||||
for i in 0..subs {
|
||||
// damage f32 + damage u32 are folded into TotalDamage above; absorb/resist are summed. The
|
||||
// school is kept from the FIRST block only — the wording takes one word, and vmangos's
|
||||
// extra blocks are the off-school splits of the same swing.
|
||||
let block_school = read_u32_le(r)?;
|
||||
if i == 0 {
|
||||
school = u8::try_from(block_school).unwrap_or(0);
|
||||
}
|
||||
let _damage_f = read_f32_le(r)?;
|
||||
let _damage = read_u32_le(r)?;
|
||||
absorb += read_u32_le(r)?;
|
||||
@@ -80,6 +94,7 @@ pub(super) fn read_attacker_state(r: &mut impl Read) -> io::Result<AttackerState
|
||||
absorb,
|
||||
resist,
|
||||
blocked,
|
||||
school,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -101,6 +101,18 @@ const FIELD_UNIT_BOUNDINGRADIUS: u16 = 129;
|
||||
const FIELD_UNIT_COMBATREACH: u16 = 130;
|
||||
const FIELD_UNIT_BASE_MANA: u16 = 162;
|
||||
const FIELD_UNIT_DISPLAYID: u16 = 131;
|
||||
/// `UNIT_FIELD_NATIVEDISPLAYID` (`OBJECT_END(6) + 0x7E` = 132, PUBLIC — vmangos
|
||||
/// `UpdateFields_1_12_1.h:77`; it is the index between DISPLAYID (131) and MOUNTDISPLAYID (133),
|
||||
/// both of which are independently pinned above). The unit's **unshifted** appearance: the server
|
||||
/// writes it once at spawn/login and leaves it alone through every transform — a druid form
|
||||
/// (`Aura::HandleAuraModShapeshift` sets DISPLAYID and restores it *from* this field), a GM
|
||||
/// `.modify morph`, a polymorph. `UNIT_FIELD_DISPLAYID` is what you see; this is what the unit is.
|
||||
///
|
||||
/// The client reads it for exactly one thing benilla cares about: the **mover collision prism**
|
||||
/// (`0x60b270` fetches its DBC row at `[unit+0x110]+0x1f8`, while its sibling `0x60ae10` uses
|
||||
/// `+0x1f4` = DISPLAYID against the same array) — so a shapeshift does *not* resize the collision
|
||||
/// box (wow-re `mover-collision-scalars.md`, `remote-swim-decision.md` §4; decision 1574).
|
||||
const FIELD_UNIT_NATIVEDISPLAYID: u16 = 132;
|
||||
/// `UNIT_FIELD_MOUNTDISPLAYID` (`OBJECT_END(6) + 0x7F` = 133, PUBLIC — vmangos
|
||||
/// `UpdateFields_1_12_1.h:78`; byte-verified client-side at `[unit+0x110]+0x1fc` = index 0x85,
|
||||
/// wow-re `rf39-field-index-map.md`/`d1.md`, HARD). A raw `CreatureDisplayInfo` id: the mount the
|
||||
|
||||
@@ -56,6 +56,13 @@ impl ObjectFields {
|
||||
pub fn unit_displayid(&self) -> Option<i32> {
|
||||
self.get_i32(FIELD_UNIT_DISPLAYID)
|
||||
}
|
||||
/// `UNIT_FIELD_NATIVEDISPLAYID` (units + players) — the unit's **unshifted** appearance, which
|
||||
/// no transform touches. The collision prism is derived from *this*, not from
|
||||
/// [`Self::unit_displayid`]: a druid in bear form keeps the druid's swim/splash/foam lines
|
||||
/// (decision 1574). `None` when absent — the caller falls back to the render display.
|
||||
pub fn unit_native_displayid(&self) -> Option<i32> {
|
||||
self.get_i32(FIELD_UNIT_NATIVEDISPLAYID)
|
||||
}
|
||||
/// `UNIT_FIELD_MOUNTDISPLAYID` — the `CreatureDisplayInfo` id of the mount this unit rides;
|
||||
/// `0` (or absent) = not mounted. The one and only mounted signal on the wire (decision 0441).
|
||||
pub fn unit_mount_display_id(&self) -> u32 {
|
||||
|
||||
Reference in New Issue
Block a user