Skip to content

mora-kid: activate trait predicates (Plan 8b)#47

Merged
halgari merged 12 commits intomasterfrom
m3-plan8b-trait-predicates
Apr 21, 2026
Merged

mora-kid: activate trait predicates (Plan 8b)#47
halgari merged 12 commits intomasterfrom
m3-plan8b-trait-predicates

Conversation

@halgari
Copy link
Copy Markdown
Owner

@halgari halgari commented Apr 21, 2026

Summary

Plan 8b of the Rust + KID pivot: activate KID trait predicate evaluation for Weapon and Armor records. Previously the distributor logged-and-skipped any rule with traits; it now evaluates them against fully-parsed record data.

  • mora-esp — extended WeaponRecord with DATA (value/weight/damage), DNAM (animation_type, speed, reach), EITM (enchantment), CNAM (template weapon); extended ArmorRecord with DATA (armor_rating × 100, value, weight), DNAM (armor_type), BOD2/BODT (body_slots), EITM (enchantment), TNAM (template armor — note: TNAM, not CNAM like WEAP).
  • mora-kid — added filter::evaluate_weapon_traits + evaluate_armor_traits; distributor now calls them instead of log-and-skip.
  • tests — 6 end-to-end trait_predicates.rs integration tests covering each new predicate bucket.

Total suite now at 206 tests (up from 181).

Scope

Plan 8b intentionally covers WEAP + ARMO only. The other 17 KID-supported record types remain log-and-skip for now; each will get its own plan once we have a real-game golden-test baseline (M4).

Test plan

  • cargo test --workspace → 206/206
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo fmt --check
  • cargo xwin check --target x86_64-pc-windows-msvc --workspace
  • CI green on this PR

halgari added 12 commits April 21, 2026 06:45
Completes KID filter grammar coverage for Weapon + Armor rules by
activating trait predicates (OneHandSword, HEAVY, -E, D(min max),
AR(min max), body slots, etc.).

Extends mora-esp's WeaponRecord + ArmorRecord with DATA/DNAM/EITM/
CNAM/TNAM/BOD2/BODT subrecord parsing. Adds WeaponAnimType +
ArmorType + BipedObject types. mora-kid gains
evaluate_weapon_traits + evaluate_armor_traits helpers that the
distributor calls in place of the previous log-and-skip stubs.

11 tasks across 10 phases. ~14 new tests (9 subrecord units + 6
trait integration). Target test total ~195.

Note: ARMO template is TNAM, not CNAM like WEAP — common bug
caught during research.
Appends byte-layout tables for WEAP DATA/DNAM/EITM/CNAM and
ARMO DATA/DNAM/EITM/TNAM/BOD2/BODT. Animation-type + armor-type
enum values. Body-slot bitmask conventions. Cited by every
parser task in Plan 8b.
Signature consts: DNAM, EITM, CNAM, TNAM, BOD2, BODT. Shared
subrecords::form_id_ref::parse returns the raw u32 for later
remapping by EspWorld::resolve_in_plugin. Used by EITM (enchant
refs), CNAM (weapon template), TNAM (armor template).
weapon_data.rs: Parse 10-byte WEAP DATA (value + weight + damage).
weapon_dnam.rs: Parse WEAP DNAM prefix (anim_type + speed + reach).
WeaponAnimType enum maps u8 wire values (0-9) to animation types
(HandToHandMelee...Crossbow). Both parsers tested.
WeaponRecord now exposes animation_type, speed, reach, value,
weight, damage, enchantment (resolved FormId), template_weapon
(resolved FormId) in addition to the existing editor_id + keywords.
Existing integration tests still pass since all new fields default
to None when the corresponding subrecords aren't present.
ArmorData { value, weight } (8 bytes). ArmorDnam { armor_rating }
decodes from the i32-stored-as-display-times-100 format into a
display-scale f32. BipedObject { slots_bitmask, armor_type }
parses BOD2 (8 bytes, SSE primary) or BODT (12 bytes, legacy);
slot_numbers() decodes the bitmask into slot numbers 30..=61.
ArmorType enum for LightArmor/HeavyArmor/Clothing.

9 unit tests covering DATA layout, DNAM display-scaling,
BOD2 parsing, BODT padding-skip, multi-slot decode, unknown
armor type.
ArmorRecord gains armor_type, body_slots (Vec<u8> of slot numbers),
armor_rating, value, weight, enchantment, template_armor. BOD2 is
preferred over BODT when both are present (SSE should not have
both; defensive against old LE plugins). TNAM (not CNAM — ARMO
uses a different signature than WEAP) carries the template armor
reference.
Maps WeaponTraits fields against WeaponRecord subrecord data.
- anim_types: OR — at least one must match
- require_enchanted / require_template: Some(true/false) enforces
  presence / absence of EITM / CNAM
- damage_range / weight_range: inclusive; records without DATA fail
  the predicate (matches KID's 'no data to check = fails filter')
Maps ArmorTraits fields against ArmorRecord subrecord data.
- armor_types: OR across Heavy/Light/Clothing
- require_enchanted / require_template: EITM / TNAM presence
- ar_range / weight_range: inclusive; missing data fails predicate
- body_slots: OR; at least one listed slot must be occupied
Previous Plan 6 implementation log-and-skipped trait predicates
because WeaponRecord/ArmorRecord didn't expose the required
subrecord fields. Now that mora-esp parses DATA/DNAM/EITM/CNAM/
TNAM/BOD2/BODT, wire the filter::evaluate_weapon_traits and
evaluate_armor_traits calls into both the WEAP and ARMO loops.
Trait-mismatch items increment rejected_by_filter.
6 end-to-end tests against synthetic plugins:
  weapon_animation_type_filter, weapon_damage_range_filter,
  weapon_enchanted_predicate, armor_type_filter,
  armor_body_slot_filter, armor_ar_range_filter.
Exercises the full Plan 8b pipeline: mora-esp parses the new
subrecords, mora-kid's evaluate_*_traits helpers gate emissions.

Note: plan listed the INI trait field as field index 3 (|||traits)
but the actual format is field index 2 (||traits); corrected here.
Clippy collapsed two nested if-lets in filter.rs via autofix.
Fmt normalized whitespace. No functional changes.
@halgari halgari merged commit 183e23a into master Apr 21, 2026
6 checks passed
@halgari halgari deleted the m3-plan8b-trait-predicates branch April 21, 2026 13:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant