Skip to content

Add portable held_item.trigger and native effect-read contracts - #165

Closed
Roxas2712 wants to merge 50 commits into
UNDERdecoded:mainfrom
Roxas2712:codex/portable-held-item-trigger
Closed

Roxas2712 wants to merge 50 commits into
UNDERdecoded:mainfrom
Roxas2712:codex/portable-held-item-trigger

Conversation

@Roxas2712

@Roxas2712 Roxas2712 commented Oct 24, 2026 •

Copy link
Copy Markdown

Mods currently need private held-item readers to suppress or substitute effects. Add the native held_item.trigger(next, ctx) producer for Gen2/3 hosts, using the shared HELD_* names and public byte-odds contract. GB/DS report unavailable.

The context carries the actual opaque battle, holder Pokemon, item/definition, effect, parameter and comparison reason. API 3 normalizes item/Pokemon identities. Constructors, external/link battlers, replacements and side synchronization bind the correct controller. Native code continues to own rolls, HP, messages, consumption and queues. No subscriber means no hook dispatch or context construction; error recovery and two-result API-3 replay are retained.

Wire actual priority, damage/crit/type/stat, accuracy, endurance, flinch, confusion, cure, PP and residual reads, plus GBA Macho Brace, Shell Bell, escape and entry prize/White Herb paths. Preserve the reference's scalar definition transactions: Gold edits persist on the live item definition; GBA edits remain temporary. Invalid transactional metadata edits cannot partially commit Pokemon changes.

Native integration tests also exposed and fix Gold's disconnected Focus Band damage path (including 1 HP), Gold Berry's strict-below-half threshold and GBA's nominal-100% accuracy shortcut bypassing item penalties. Source-catalog scanning now tolerates multiline calls so formatting cannot hide the producer.

Dependency and remaining native gap

Stacked on #164 and its prerequisites. The incremental change is 1ce83fa; compare against #164.

This establishes the read/steering contract and the tested native consumers, not universal mod or complete battle equivalence. The source GBA residual scheduler performs extra after-action item scans: a hook granting a 7-HP Berry even to empty hands heals 35 HP in the reference versus 7 in the host. The checker records that raw native_policy, prints the gap and excludes it from equal observations. --require-native-schedule-parity deliberately rejects it. The unchanged public consumer defaults to requiring an actual item, so consumption ends its override. Full GBA scheduling, Choice Band locking and other native rules remain separate work.

Includes docs, public consumer, shared/native suites, imported-data driver and a pinned CI workflow. No ROM, generated cartridge cache, save or private mod is distributed.

Validation

At feature ref 1ce83faf4b980584be9d747eee82efc530ede09f:

  • Public/native contract 5,511/5,511; ownership/metadata authority 290/290; existing Gen2 held-item regressions 51/51.
  • 40 isolated workers / 1,706 paired observations, real SDKs on Gold/Silver/Crystal and FireRed/Emerald in four SDK modes. Source pinned clean at 79ea62f45fb2ea8f65d081a109431e4eb1bbdb36. Uses native readers, actual moves/order/entry/escape and registered residual handlers; all 66 GBA enums round-trip through the real item-data fallback reader. Raw scheduling differences are recorded separately.
  • Full feature run: 122/132 engine suites, SDK 3/3, B30 passed. Exactly the same ten pre-existing failures as Add portable battle.field_residual and native cross-engine contracts #164; all 26 FAIL lines match. Repairs are in test: repair Gen2 updater asset fixtures #128–134.
  • Imported Red regressions: battle 468/468, save conversion 95/95, parity J 73/73, K 22/22; no external binary save fixture supplied.
  • Negative controls: the unchanged Add portable battle.field_residual and native cross-engine contracts #164 engine reports unavailable, dispatches zero callbacks and cannot suppress native Leftovers; the strict schedule checker rejects the real FireRed discrepancy.
  • StyLua, actionlint, Python compile and diff whitespace checks passed.

Combined testfork runtime 3d6bfceeaf25b97d7a7ce708ada8fe3306e0357d:

  • 177/177 engine suites, SDK 3/3, B30 passed; shared four-mode matrix rerun.
  • Native LÖVE 11.5 on imported Gold/FireRed/Emerald: actual FIGHT/move input and result queues, public IDs, suppression/substitution, HP/consumption, delegated Leftovers, one-HP endurance, GBA entry White Herb and RUN menu, unsubscribe. Isolated identity and in-memory New Game/constructed battles; stops before battle finish/afterBattle/SAVE processing. Bounded smoke, not full playthrough or cross-engine pixel parity.

All 26 hosted PR workflows report action_required pending maintainer approval. The new held-item workflow has zero jobs and has not executed. Local results above are separate.

# Conflicts:
#	src/mods/Loader.lua
# Conflicts:
#	docs/modding.md
#	src/mods/Loader.lua
#	src/world/WorldAPI.lua
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