Nine more goldens, and four of them are realm features worth knowing
Second golden batch. Field counts were re-checked first and are still intact everywhere, so again these are the realm's data and not a misread column. Four are things grom would want to know about his own realm, not bookkeeping: - **The professions need no tools.** Mining (2575) carried the Mining Pick and Skinning (8613) the Skinning Knife in 1.12; both are `[0, 0]` here, as are Herbalism, Blacksmithing, Cooking and First Aid. You gather bare-handed, and the pre-send possession check (`0x6e4000`) has nothing to refuse. Read rather than assumed: 362 rows still carry a tool — Pick Lock still wants its thieves' tools (5060) — so it is six rows blanked in the data, and the reagent columns beside them are untouched, which Slow Fall's Light Feather shows. - **There is a shipped World channel**, row 27, flags `0x9` — global and auto-joined, with no `%s` in its pattern because there is one of it. 1.12 had no row at all; there "World" was a player-made channel like any other, which is exactly what the old test asserted. - **Thalassian is implemented.** Spell 813 was "Thalassian (NYI)" declaring Common in 1.12 and declares language 10 here, so nine player languages have both a declaring spell and a skill line where 1.12 had eight. It goes with a **tenth `ChrRaces` row**, which speaks Common and is therefore Alliance-side. - **Emote text ships five locales**, not four: ruRU arrived in column 5 — the column this very test used as its "unshipped" case. The dry-ladder case moved to 1/2/8 and the five that compose are asserted, so a column sliding under the ladder cannot pass unnoticed. The rest are counts and rows: `LockType` has a fourth cursor row (id 20, "Survival", reusing `PickLock`), `ItemBagFamily` has twelve rows with the realm's four profession bags (Meat, Fish, Leather, Mining Supplies), `EmotesText` 169 → 171, and a fourth spell carries `SPELL_ATTR_EX3_NO_CASTING_BAR_TEXT`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
This commit is contained in:
@@ -191,12 +191,21 @@ mod tests {
|
||||
(23, 0x10004, "WorldDefense", "WorldDefense"),
|
||||
(24, 0x00000, "LookingForGroup", "LookingForGroup"),
|
||||
(25, 0x20032, "GuildRecruitment - %s", "GuildRecruitment"),
|
||||
// The realm's own: a global **World** channel, which 1.12 had no row for at all —
|
||||
// there it was a player-made channel like any other. Flags `0x9` is
|
||||
// `0x1 | 0x8`, so it is auto-joined and global rather than zone-scoped, and its
|
||||
// pattern carries no `%s` because there is one of it.
|
||||
(27, 0x00009, "World", "World"),
|
||||
]
|
||||
);
|
||||
|
||||
// The auto-join set is the reference's `chat-cache.txt` `ZONECHANNELS` mask.
|
||||
// The auto-join set is the reference's `chat-cache.txt` `ZONECHANNELS` mask. World joins
|
||||
// itself too, so the mask gains bit 26.
|
||||
let mask: u32 = cat.auto_join_rows().map(|r| 1 << (r.id - 1)).sum();
|
||||
assert_eq!(mask, 0x0020_0003, "General + Trade + LocalDefense");
|
||||
assert_eq!(
|
||||
mask, 0x0420_0003,
|
||||
"General + Trade + LocalDefense + the realm's World"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -234,6 +243,17 @@ mod tests {
|
||||
assert_eq!(cat.zone_channel_id("General - Elwynn Forest"), 1);
|
||||
assert_eq!(cat.zone_channel_id("Trade - City"), 2);
|
||||
assert_eq!(cat.zone_channel_id("LocalDefense - Durotar"), 22);
|
||||
assert_eq!(cat.zone_channel_id("World"), 0, "a custom channel is 0");
|
||||
// "World" is a **shipped** channel here (row 27), not a player-made one, so it resolves.
|
||||
assert_eq!(
|
||||
cat.zone_channel_id("World"),
|
||||
27,
|
||||
"the realm's World channel"
|
||||
);
|
||||
// A genuinely player-made name still answers 0, which is what that check is for.
|
||||
assert_eq!(
|
||||
cat.zone_channel_id("GromsPartyChat"),
|
||||
0,
|
||||
"a custom channel is 0"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,7 +224,8 @@ mod tests {
|
||||
let data = crate::wow_data_or_skip!();
|
||||
let mut chain = Chain::open(&data).expect("open patch chain");
|
||||
let cat = load_emote_text_catalog(&mut chain).expect("load");
|
||||
assert_eq!(cat.len(), 169, "one form table per EmotesText row");
|
||||
// 171, where 1.12 shipped 169: the realm adds two emotes.
|
||||
assert_eq!(cat.len(), 171, "one form table per EmotesText row");
|
||||
|
||||
// ctx 0: someone else waves at someone else.
|
||||
assert_eq!(
|
||||
@@ -298,12 +299,41 @@ mod tests {
|
||||
}
|
||||
|
||||
/// An unshipped locale is empty everywhere, so the ladder runs dry: no line (`0x49b4bd`).
|
||||
///
|
||||
/// Which columns are shipped moved with the realm: it fills **five** locales where 1.12's
|
||||
/// enGB chain filled four. Column 5 (ruRU) is the one that arrived — this test used to use it
|
||||
/// as its empty case — so the dry ladder is now shown on 1, 2 or 8, and the five that compose
|
||||
/// are asserted so a column sliding under the ladder cannot pass unnoticed.
|
||||
#[test]
|
||||
fn an_unshipped_locale_composes_nothing() {
|
||||
let data = crate::wow_data_or_skip!();
|
||||
let mut chain = Chain::open(&data).expect("open patch chain");
|
||||
let cat = load_emote_text_catalog(&mut chain).expect("load");
|
||||
assert_eq!(cat.compose(WAVE, &line("Bob", "Jane", "Me"), 5), None);
|
||||
for empty in [1, 2, 8] {
|
||||
assert_eq!(
|
||||
cat.compose(WAVE, &line("Bob", "Jane", "Me"), empty),
|
||||
None,
|
||||
"locale {empty} ships nothing, so the ladder runs dry"
|
||||
);
|
||||
}
|
||||
for (loc, want) in [
|
||||
(0usize, "Bob waves at Jane."),
|
||||
(3, "Bob winkt Jane zu."),
|
||||
(5, "Bob машет Jane рукой."),
|
||||
(6, "Bob saluda con la mano a Jane."),
|
||||
(7, "Bob acena para Jane."),
|
||||
] {
|
||||
assert_eq!(
|
||||
cat.compose(WAVE, &line("Bob", "Jane", "Me"), loc)
|
||||
.as_deref(),
|
||||
Some(want),
|
||||
"locale {loc}"
|
||||
);
|
||||
}
|
||||
// zhCN composes too; its text is asserted apart from the Latin ones for legibility.
|
||||
assert!(cat
|
||||
.compose(WAVE, &line("Bob", "Jane", "Me"), 4)
|
||||
.is_some_and(|s| s.contains("Bob") && s.contains("Jane")));
|
||||
assert_eq!(cat.compose(9999, &line("Bob", "Jane", "Me"), 0), None);
|
||||
}
|
||||
|
||||
|
||||
@@ -84,6 +84,11 @@ mod tests {
|
||||
assert_eq!(cat.name(4), None);
|
||||
assert_eq!(cat.name(5), None);
|
||||
assert_eq!(cat.name(0), None, "family 0 must not render as \"NONE\"");
|
||||
assert_eq!(cat.len(), 8, "the whole shipped table");
|
||||
// The realm's four: the profession bags 1.12 never shipped a family row for.
|
||||
assert_eq!(cat.name(10), Some("Meat"));
|
||||
assert_eq!(cat.name(11), Some("Fish"));
|
||||
assert_eq!(cat.name(12), Some("Leather"));
|
||||
assert_eq!(cat.name(13), Some("Mining Supplies"));
|
||||
assert_eq!(cat.len(), 12, "the whole shipped table");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,8 +264,14 @@ mod tests {
|
||||
let mut chain = Chain::open(&data).expect("open patch chain");
|
||||
let langs = load_default_languages(&mut chain).expect("load");
|
||||
|
||||
// All nine `ChrRaces` rows resolve: the eight playable races and the Goblin.
|
||||
assert_eq!(langs.len(), 9, "one entry per ChrRaces row");
|
||||
// Ten `ChrRaces` rows resolve, where 1.12 had nine: the eight playable races, the Goblin,
|
||||
// and the realm's own tenth race, which speaks **Common** — so it is Alliance-side.
|
||||
assert_eq!(langs.len(), 10, "one entry per ChrRaces row");
|
||||
assert_eq!(
|
||||
langs.name(10, 0),
|
||||
Some("Common"),
|
||||
"the realm's tenth race is Alliance-side"
|
||||
);
|
||||
// Alliance speaks Common, Horde Orcish; the racial language would give Darnassian.
|
||||
for race in [1, 3, 4, 7] {
|
||||
assert_eq!(langs.name(race, 0), Some("Common"), "race {race}");
|
||||
|
||||
@@ -100,10 +100,14 @@ mod tests {
|
||||
assert_eq!(cat.cursor_name(13), None);
|
||||
assert_eq!(cat.cursor_name(19), None); // Fishing
|
||||
assert_eq!(cat.cursor_name(0), None); // an empty lock slot's index
|
||||
// A fourth row carries one now: id 20, "Survival", reusing the `PickLock` cursor. It is
|
||||
// the realm's own lock type, and the cursor is what a player sees on a skinnable corpse.
|
||||
assert_eq!(cat.cursor_name(20), Some("PickLock"));
|
||||
assert_eq!(cat.name(20), Some("Survival"));
|
||||
assert_eq!(
|
||||
cat.len(),
|
||||
3,
|
||||
"only three LockType rows carry a CursorName in 5875"
|
||||
4,
|
||||
"four LockType rows carry a CursorName on this realm, three in 5875"
|
||||
);
|
||||
|
||||
// A slip to `ResourceName` (field 10) would print "Requires Herbs".
|
||||
|
||||
@@ -217,7 +217,7 @@ fn real_spell_catalog_reads_open_lock_types() {
|
||||
);
|
||||
|
||||
// The cast bar shows no name for `AttributesEx3 & 0x4` (`SPELL_ATTR_EX3_NO_CASTING_BAR_TEXT`),
|
||||
// the one column separating 22810 from 6478; three shipped rows carry it.
|
||||
// the one column separating 22810 from 6478; four shipped rows carry it (three in 5875).
|
||||
assert!(cat.get(22810).unwrap().no_casting_bar_text());
|
||||
assert!(!cat.get(6478).unwrap().no_casting_bar_text());
|
||||
let silent: Vec<u32> = {
|
||||
@@ -231,21 +231,36 @@ fn real_spell_catalog_reads_open_lock_types() {
|
||||
};
|
||||
assert_eq!(
|
||||
silent,
|
||||
vec![6477, 22810, 26380],
|
||||
"6477 Opening / 22810 Opening - No Text / 26380 zzOLDSummon Mouth Tentacle Visual"
|
||||
vec![6477, 22810, 26380, 47405],
|
||||
"6477 Opening / 22810 Opening - No Text / 26380 zzOLDSummon Mouth Tentacle Visual, plus \
|
||||
one of the realm's own (47405) — four rows carry the attribute, three in 5875"
|
||||
);
|
||||
|
||||
// The tool and reagent columns the pre-send possession check reads (`0x6e4000`): totems at
|
||||
// columns 40-41, reagents at 42-49 with their counts at 50-57.
|
||||
// **The realm removed the professions' tool requirements.** Mining (2575) carried the Mining
|
||||
// Pick (2901) in 1.12 and Skinning (8613) the Skinning Knife (7005); both are `[0, 0]` here,
|
||||
// as are Herbalism, Blacksmithing, Cooking and First Aid. So you mine and skin bare-handed on
|
||||
// this realm, and the pre-send possession check (`0x6e4000`) has nothing to refuse.
|
||||
//
|
||||
// Read, not assumed: the column still works. 362 rows carry a tool — Pick Lock's thieves'
|
||||
// tools (`(1804, [5060, 0])`), the lockpicking trainer ranks, Rogue poisons at 11130 — so
|
||||
// this is six rows blanked in the data, not a column slip. The reagent columns beside them
|
||||
// are untouched, which `Slow Fall` below shows.
|
||||
assert_eq!(
|
||||
cat.get(2575).unwrap().totems,
|
||||
[2901, 0],
|
||||
"Mining requires the Mining Pick (2901)"
|
||||
[0, 0],
|
||||
"Mining needs no Mining Pick on this realm"
|
||||
);
|
||||
assert_eq!(
|
||||
cat.get(8613).unwrap().totems,
|
||||
[7005, 0],
|
||||
"Skinning requires the Skinning Knife (7005)"
|
||||
[0, 0],
|
||||
"Skinning needs no Skinning Knife on this realm"
|
||||
);
|
||||
assert_eq!(
|
||||
cat.get(1804).unwrap().totems,
|
||||
[5060, 0],
|
||||
"…while Pick Lock still wants its thieves' tools (5060), so the column is read"
|
||||
);
|
||||
let slow_fall = cat.get(130).unwrap();
|
||||
assert_eq!(
|
||||
@@ -1177,12 +1192,15 @@ fn the_language_declaring_spells_cover_nine_of_thirteen_languages() {
|
||||
|
||||
// (spell, declared language, SkillLine.dbc id): every SPELL_EFFECT_LANGUAGE row but 25674.
|
||||
const DECLARED: &[(u32, u32, u32)] = &[
|
||||
(668, 7, 98), // Common
|
||||
(669, 1, 109), // Orcish
|
||||
(670, 3, 115), // Taurahe
|
||||
(671, 2, 113), // Darnassian
|
||||
(672, 6, 111), // Dwarvish
|
||||
(813, 7, 137), // "Thalassian (NYI)", declaring Common
|
||||
(668, 7, 98), // Common
|
||||
(669, 1, 109), // Orcish
|
||||
(670, 3, 115), // Taurahe
|
||||
(671, 2, 113), // Darnassian
|
||||
(672, 6, 111), // Dwarvish
|
||||
// The realm **implemented** Thalassian: 1.12's row declared Common (7) because the
|
||||
// language was not in, and this one declares 10, the `Languages.dbc` Thalassian row. That
|
||||
// goes with its tenth playable race (see `languages.rs`).
|
||||
(813, 10, 137), // Thalassian, declaring Thalassian
|
||||
(814, 7, 138), // "Draconic (NYI)", declaring Common
|
||||
(815, 7, 139), // Demon Tongue, declaring Common
|
||||
(816, 7, 140), // "Titan (NYI)", declaring Common
|
||||
@@ -1224,8 +1242,9 @@ fn the_language_declaring_spells_cover_nine_of_thirteen_languages() {
|
||||
.collect();
|
||||
assert_eq!(
|
||||
understandable,
|
||||
[1, 2, 3, 6, 7, 13, 14, 33].into_iter().collect(),
|
||||
"only the eight player languages have both a declaring spell and a skill line"
|
||||
[1, 2, 3, 6, 7, 10, 13, 14, 33].into_iter().collect(),
|
||||
"nine player languages here, where 1.12 had eight: Thalassian (10) now has both a \
|
||||
declaring spell and a skill line, which is what implementing it means"
|
||||
);
|
||||
|
||||
// An ordinary ability declares nothing.
|
||||
|
||||
Reference in New Issue
Block a user