# Dispatching Item Effects

Lecture ID: lecture_w18_d01
Week 18, Day 1

## Objectives
- Identify the FireRed files, structs, functions, constants, data tables, and state variables that implement each major game system.
- Connect week 18 material to the overall course plan.

## Transcript
All right, let’s pick up from the bag work last week and move one layer deeper. Last time, we treated the bag mostly as a UI facade over item records, pockets, quantities, and menu state. Today I want you to stop thinking of “use item” as a single behavior. In FireRed architecture, “use item” is a dispatch problem. The item record says what category of behavior the item belongs to, the current context says whether we are in the field or in battle, and then the engine jumps into a handler that may open the party menu, mutate flags or variables, consume inventory, start a field effect, or simply tell the player, “now is not the time.”

So, if I were drawing this on the board, I would write: item data, selected item id, current context, dispatch function, continuation. And I would underline continuation twice. The dispatch itself is not the whole story. In a Game Boy Advance RPG, many item effects cannot complete synchronously in one C function. They have to fade the screen, close a menu, wait for weather fade-in, show a message, open a party menu, run an animation, or return to the overworld. That is why this lecture belongs right after our callback and task material from earlier in the course. You already know the runtime shell: `SetMainCallback2`, tasks, and per-frame dispatch. Now we are seeing the same architecture at a higher gameplay layer.

Let’s anchor this in the source. The contract starts in `pokefirered/include/item.h`, where the item record is not just name, price, pocket, and description. The `struct Item` contains `fieldUseFunc`, `battleUsage`, and `battleUseFunc`, all connected through the `ItemUseFunc` function pointer type; the same header also exposes accessors like `ItemId_GetFieldFunc`, `ItemId_GetBattleFunc`, `ItemId_GetType`, and `ItemId_GetPocket`, in `pokefirered/include/item.h` `chunk_fb46e889433f7a77` and `chunk_08d87cd0c6aa9c90`. That is the first architectural point: FireRed makes item behavior data-addressable. The item table can point at different code paths without every menu needing a giant handwritten switch over every item.

But now be careful. Data-addressable does not mean fully declarative. A potion is not implemented by a JSON-like effect object. A bicycle is not implemented by a tiny rule string. The item data record points to C behavior, and that behavior then coordinates the rest of the engine. That is a very FireRed pattern: tables route you to code, and code drives state machines. We saw the same shape with battle AI script predicates, but do not import the AI mental model too strongly here. AI scripts moved an instruction pointer through a specialized battle decision language. Item use is more mixed. It touches bag UI, party menu UI, field callbacks, battle return callbacks, event flags, variables, and inventory mutation.

Now look at the next contract boundary. In `pokefirered/include/party_menu.h`, FireRed exposes `gItemUseCB`, plus callbacks like `CB2_ShowPartyMenuForItemUse`, `ItemUseCB_Medicine`, `ItemUseCB_TryRestorePP`, `ItemUseCB_PPUp`, `ItemUseCB_RareCandy`, `ItemUseCB_SacredAsh`, and `ItemUseCB_EvolutionStone`, in `pokefirered/include/party_menu.h` `chunk_2dbef383980d4a01`. That global callback, `gItemUseCB`, is a very important bridge. It lets item-use code say, “I do not personally know which party slot the player will choose, but when the party menu gets control, here is the semantic operation it should perform.”

Let me say that again in a more concrete way. Suppose the player selects a Potion from the bag outside battle. The bag knows the selected item id, through the item menu state and `gSpecialVar_ItemId`. The item data routes to a field-use function for medicine. But the actual healing target has not been selected yet. So FireRed sets `gItemUseCB` to the medicine party-menu callback, then transitions into the party menu. The party menu later calls that callback once the player chooses a creature. This is not one monolithic “use potion” function. It is a handshake between the item menu and party menu.

In `pokefirered/src/item_use.c`, the field medicine family shows this plainly. `FieldUseFunc_Medicine` assigns `gItemUseCB = ItemUseCB_Medicine`; `FieldUseFunc_Ether` assigns `ItemUseCB_TryRestorePP`; `FieldUseFunc_PpUp` assigns `ItemUseCB_PPUp`; `FieldUseFunc_RareCandy` assigns `ItemUseCB_RareCandy`; and evolution stones assign `ItemUseCB_EvolutionStone`. The course packet’s item-use flow region for this is `pokefirered/src/item_use.c` `chunk_7e88bbaddbab5bb9`. So on the board, beside “Potion,” I would write: selected item id, field use function, set `gItemUseCB`, exit bag, show party, apply table-based effect to selected mon.

Check for understanding here. If I ask, “Where is the healing target chosen?” the answer is not “inside the item record.” It is also not simply “inside the bag.” The bag selected the item. The party menu selects the target. The medicine callback connects the two. That distinction matters because in your lab this week you will implement handlers for potion, escape rope, a key item, and a badge-gated field move. If you put all of that into one giant `UseItem` function, you will get something working, but you will miss the architecture we are studying.

Now let’s compare that with an item that does not need the party menu. Repel is a nice example because it touches progression-style variables without selecting a creature. In `FieldUseFunc_Repel`, FireRed checks `VarGet(VAR_REPEL_STEP_COUNT)`. If the count is zero, it plays the repel sound and moves the task function to `Task_UseRepel`. That continuation waits until the sound effect is finished, records a quest log event, sets `VAR_REPEL_STEP_COUNT` using `VarSet` and `ItemId_GetHoldEffectParam(gSpecialVar_ItemId)`, removes one item, recalculates pocket list state, formats the “player used” message, and returns to the bag. That logic is in `pokefirered/src/item_use.c` `chunk_ce2671932ba5ff71`.

Notice the shape. Repel is not party-targeted. It is world-state-targeted. The item’s effect becomes a variable in the event data system. The countdown can then be consumed elsewhere as the player walks. This is why week 18 is called item use, field effects, and progression unlocks, not merely “inventory.” The bag is only the entry point. The actual effect often lands in a state variable, a field effect, a flag, a party mutation, or a script-visible result.

Let’s connect that variable system. In `pokefirered/src/event_data.c`, FireRed keeps special variables like `gSpecialVar_0x8000` through `gSpecialVar_Result`, and it implements `GetVarPointer`, `VarGet`, and `VarSet`; the source region for event flags and vars support in the packet is `pokefirered/src/event_data.c` `chunk_bff5bbc2efc3008f`. The key idea is that item-use code and script code share a common vocabulary of variables and flags. When item-use code sets `VAR_REPEL_STEP_COUNT`, it is not setting some private bag-local field. It is writing into the same event-data layer that scripts and field systems can inspect.

This is a good moment to compare “quantity” with “effect state.” Last week, we cared about whether the bag had three Repels and which pocket they were in. Today, after use, we care that one Repel has been removed from the bag and that the world has a repel step count. Those are separate state changes. Inventory quantity is in the bag. The active repel effect is in event variables. If you conflate those in your clone architecture, you will have trouble when a key item creates an unlock without being consumed, or when a consumable creates a temporary field state after being consumed.

Now, Escape Rope gives us an even cleaner field-use example. It is consumable, it is map-gated, and it starts a field effect rather than opening the party menu. FireRed checks `CanUseEscapeRopeOnCurrMap`, which reads `gMapHeader.allowEscaping`; if escaping is allowed, `ItemUseOutOfBattle_EscapeRope` records the quest log event, assigns `sItemUseOnFieldCB = ItemUseOnFieldCB_EscapeRope`, and runs the field-use callback setup. The later callback resets overworld state after Dig or Escape Rope, removes the used item, displays the item-use message on the field, and then `Task_UseDigEscapeRopeOnField` starts the escape rope field effect. This is in `pokefirered/src/item_use.c` `chunk_8f5c0eba4013eb8a`.

So what is different from Repel? Repel mostly mutates a variable and returns to the bag. Escape Rope has to leave the menu and re-enter the overworld with a field effect queued. That is why the item-use file has this private `sItemUseOnFieldCB` continuation and field callback plumbing. Earlier in `item_use.c`, FireRed uses `gFieldCallback`, `gFieldCallback2`, `FieldCB_FadeInFromBlack`, and task functions such as `Task_WaitFadeIn_CallItemUseOnFieldCB` and `Task_ItemUseWaitForFade` to coordinate the menu-to-field transition. The visible action, the rope escape animation and warp behavior, happens only after the UI has safely yielded back to the field runtime. That same continuation style is part of the item-use support flow in `pokefirered/src/item_use.c` `chunk_ce2671932ba5ff71` and the field-use continuation region `chunk_8f5c0eba4013eb8a`.

Let’s do a board trace. I’m writing “Escape Rope” on the left. Under it: `gSpecialVar_ItemId`. Then an arrow to item record field-use function. Then an arrow to `CanUseEscapeRopeOnCurrMap`. Then two branches. If false, display Oak’s “not the time” style message. If true, record quest log, store `ItemUseOnFieldCB_EscapeRope` in `sItemUseOnFieldCB`, close the bag or field menu context, fade back, remove the item, start field effect. That trace contains data lookup, state check, UI transition, inventory mutation, and field-effect dispatch. That is the level of tracing I expect from you now. Week 17 homework already asked you to trace data records through globals, callbacks, tasks, scripts, structs, and source functions. Week 18 assumes you can do that and asks you to apply it to item effects.

Now let’s bring in battle use, but only enough to establish the contrast. In the item contract, an item has both field and battle behavior slots. In `include/item.h`, that is `fieldUseFunc` versus `battleUseFunc`, with `battleUsage` alongside them, again in `pokefirered/include/item.h` `chunk_fb46e889433f7a77`. In `include/item_use.h`, FireRed declares both families: `FieldUseFunc_Medicine`, `FieldUseFunc_Repel`, `ItemUseOutOfBattle_EscapeRope`, and also `BattleUseFunc_PokeBallEtc`, `BattleUseFunc_StatBooster`, `BattleUseFunc_Medicine`, `BattleUseFunc_Ether`, and `BattleUseFunc_PokeDoll`, in `pokefirered/include/item_use.h` `chunk_41dc26ccbf9f5b00` and `chunk_bef55b304c47a05a`.

Conceptually, field-use item dispatch asks, “Can this item operate in the overworld or from the bag, and if so what field, party, or event state does it manipulate?” Battle-use item dispatch asks, “Can this item operate under battle rules, and if so how do we get back to the battle controller after the bag or party selection?” Same selected item id, different context, different continuation target.

For example, a healing item outside battle sets `gItemUseCB` to `ItemUseCB_Medicine` and routes through the party menu for normal field item use. In battle, medicine uses the battle version of the party-menu callback path so that control returns to battle rather than the start menu. The source declares that split at the API level in `pokefirered/include/item_use.h` `chunk_41dc26ccbf9f5b00`, and the party-menu bridge is exposed in `pokefirered/include/party_menu.h` `chunk_2dbef383980d4a01`. That is a subtle but critical architectural difference: the item effect may be semantically similar, “heal this creature,” but the return path is different because the owning runtime is different.

Let me pause for a check. If I show you a Full Restore and ask, “Is this a field item or a battle item?” the advanced answer is, “It can have both field and battle use paths, and the selected context chooses which function pointer and continuation path are valid.” If I show you Escape Rope, the answer is, “It is an out-of-battle field item with a map-header gate.” If I show you Repel, the answer is, “It is a field-use consumable that writes an event variable representing temporary world state.” These distinctions are not vocabulary trivia. They tell you where to put state in your own engine.

Now, the other system we must connect today is script progression. We will spend more time on it next lecture with “Items as Scripted Unlock Inputs,” but the bridge starts here. FireRed’s script command layer can set and check variables and flags, add and remove items, check item possession, warp the player, and branch based on comparison results. In the provided packet, `pokefirered/src/scrcmd.c` `chunk_7609d397203c8536` covers progression-flow commands around weather, step callbacks, warps, and player/field state, while the surrounding `scrcmd.c` source includes commands such as `ScrCmd_setvar`, `ScrCmd_compare_var_to_value`, `ScrCmd_additem`, `ScrCmd_removeitem`, `ScrCmd_checkitem`, and `ScrCmd_checkitemtype`. The reason I mention this now is that item effects do not live in isolation. An NPC script may give the player an item, check whether the player has an item, or set a flag that later allows an item-like field move to work.

And that takes us to the badge-gated field move in your lab. Architecturally, a badge-gated field move is not “just another item” and not “just another script.” It is a coordination point. You need party state, because some creature must know the move. You need progression state, because a badge or flag must authorize field use. You need map or metatile state, because Surf, Cut, or similar moves require a valid target. And you need a callback continuation, because the action occurs in the overworld after menu interaction. FireRed distributes those responsibilities across item-use style dispatch, party menu callbacks, event flags and variables, and field effect code.

So the big idea for the first hour is this: item use is a controlled crossing between UI state and game-world state. The bag menu can select an item, but it should not own every consequence. The item record can point to behavior, but it should not store every transient effect. The party menu can select a target, but it should not decide whether Escape Rope is legal on a map. The event system can store progression, but it should not know every item animation. FireRed’s architecture works because each boundary is narrow enough to reason about: function pointers for dispatch, globals for selected item and callback handoff, tasks for asynchronous continuation, variables and flags for script-visible state, and field effects for overworld actions.

Keep that mental model active, because next we are going to walk through the dispatch path more mechanically: from the selected bag entry and `gSpecialVar_ItemId`, through field versus battle function lookup, through the item type exit callback, and finally into the continuation that decides whether the player sees a party screen, a message, a consumed item, or a changed overworld.

So, on the board, I’m going to write the path as a narrow pipeline: selected item, item data row, context lookup, use handler, continuation. That is the mechanical shape we care about.

The selected item is not, by itself, behavior. It is just an identifier. In FireRed, that identifier may be sitting in a bag menu cursor, or it may be copied into `gSpecialVar_ItemId` when the item interaction needs to cross into script-visible territory. The reason I want you to notice `gSpecialVar_ItemId` is that it is not “the item system.” It is a bridge variable. It lets a script or special routine ask, “Which item is being discussed right now?” without giving the script engine ownership of the bag UI.

Now connect that to the source packet. The anchor for this part of the lecture is `pokefirered/src/item_use.c`, especially `chunk_7e88bbaddbab5bb9`, which the packet identifies as the item-use flow, followed by `chunk_8f5c0eba4013eb8a` for the field item-use continuation, and `chunk_ce2671932ba5ff71` for support continuation. Those chunks are important because they show the item-use system as a callback pipeline, not as one large switch statement that knows the whole game.

Let’s do the simple case first. Suppose the player opens the Bag and selects a Potion outside battle. From last time, we are not going to re-teach pockets and quantities. You already know the Bag can locate the selected item record. Today the question is: once the item ID is known, who decides what happens?

The first decision is the context. Are we using this item in the field, in battle, from a party menu target, from a key item shortcut, or from a script? The item data record contains use-function information, and `item_use.c` dispatches through that information. That is the first big architectural lesson: item behavior is table-driven at the entry point, but not purely declarative. The data table says, “This item’s field-use function is over there,” and then C code takes over.

So for a Potion, the field-use function should not immediately mutate HP if the item requires a party target. It needs to hand off to the party selection interface. That means the item-use handler must set up state for a later continuation. The selected item has to survive the trip from Bag callback to party menu callback and then back into an item effect routine. That is why we keep seeing globals and callbacks in this part of the engine. It is not sloppy architecture; it is an embedded UI state machine.

Pause there. Check your understanding: why doesn’t the Bag just ask, “Which Pokémon do you want to heal?” and then directly change HP? Because the Bag is not the party UI, and because the healing action needs party validation, message display, item consumption, and return behavior. The Bag’s job is selection and pocket management. The item-use layer’s job is effect dispatch. The party menu’s job is target selection. If you collapse those, you make every later item harder.

Now, a Potion and an Escape Rope differ in an important way. Potion is target-mediated. Escape Rope is map-mediated. Potion asks, “Which party member?” Escape Rope asks, “Is this map state legal for escape?” That legality belongs near the field and map side of the engine. In the source packet, the item-use continuation chunks in `pokefirered/src/item_use.c`, `chunk_8f5c0eba4013eb8a` and `chunk_ce2671932ba5ff71`, are exactly the kind of area where you expect these asynchronous field decisions to continue after menus and messages. And when those decisions touch progression state, the neighboring authority is `pokefirered/src/event_data.c`, `chunk_bff5bbc2efc3008f`, because flags and variables are the script-visible record of what the world believes has happened.

Let me write a second board line: Potion dispatches to party selection; Escape Rope dispatches to field validation; a key item may dispatch to a field effect or a script-style check. Same selected-item pipeline, different owner at the effect boundary.

This is the point where advanced students sometimes overcorrect. They say, “Ah, so every item should just be a script.” No. That is not what FireRed is doing. Scripts are excellent for progression, NPC gates, cutscenes, and map-local logic. But an item such as a Potion has a dense mechanical relationship with party data, HP, status, item consumption, and menu feedback. Putting all of that in the script VM would make the script language responsible for creature internals. FireRed keeps that in C.

At the same time, scripts must be able to ask item questions. The packet calls out `pokefirered/src/scrcmd.c`, `chunk_7609d397203c8536`, for script commands in progression flow. That is where we conceptually place operations like checking, setting, and branching on progression conditions. The exact lesson is boundary placement: C item handlers perform mechanical item effects; script commands coordinate story and unlock flow; event data stores flags and variables that both sides can consult.

Now let’s make this concrete. Imagine a cave map where Escape Rope is allowed. The player selects Escape Rope. The item ID is resolved from the Bag. The item record points to a field-use function. That function checks whether the player is in a usable location. If legal, the system does not simply teleport by returning a value. It sets up a field transition: close menus, return to field, run the escape effect, update position or warp state, and redraw the overworld. That operation must pass through callbacks because the game cannot freeze the GBA and run a desktop-style blocking function. Every visible step happens across frames.

That frame-by-frame continuation is consistent with what we have been building since week 1. `AgbMain` starts the runtime shell, `SetMainCallback2` swaps the major mode, and `RunTasks` advances per-frame jobs. I am only recalling that for five seconds because it matters here: item use is not special magic. It is another client of the same callback-and-task architecture. The item system sets up the next callback or task, and then the engine keeps breathing.

Now compare that to using an item in battle. The same item data can have a battle-use function that differs from its field-use function. This is a crucial design choice. A Potion in the field and a Potion in battle both heal, but they live under different constraints. In battle, the action consumes a turn, interacts with battle controllers, may trigger messages in the battle script system, and must respect battle-side targeting rules. Outside battle, it is a menu operation with no turn economy. So the item record has separate field and battle behavior. `pokefirered/src/battle_util.c`, `chunk_9335e5727aa0657d`, supports this wider integration point because it pulls together battle headers, item constants, event data, battle scripts, controllers, and move-effect constants in the battle utility layer. That include pattern is a useful architectural clue: battle item effects are not just inventory effects; they are battle-state effects.

Let me say that another way. The item ID is shared. The semantics are context-sensitive. The dispatch table is the hinge.

That is why your lab this week asks for Potion, Escape Rope, a key item, and a badge-gated field move. Those four examples force you to touch four different boundaries. Potion touches party state. Escape Rope touches map legality and field transition. A key item touches inventory possession and special behavior. A badge-gated field move touches progression flags or variables, party capability, and overworld effect permission.

For the badge-gated case, be careful. The badge is not usually “used” like a Potion. It is a progression unlock that changes whether another action is legal. So the check flows differently. You might have a party member that knows a move. You might have a badge flag set. You might be facing a tile that supports the field action. Only if all three are true does the system allow the effect. That is not an item effect in the narrow sense, but it belongs in this week because the architecture is the same: inventory or progression state supplies an input; field code checks world context; script flags and variables describe progression; a continuation runs a visible effect.

Look at the source focus again. `event_data.c`, `chunk_bff5bbc2efc3008f`, is not there by accident. Event flags and variables are the game’s compact progression memory. `scrcmd.c`, `chunk_7609d397203c8536`, is the script-facing command layer that lets maps and NPCs branch on that memory. When an NPC blocks a path until you have a required item, or until a flag is set after receiving that item, the item system does not need to know the NPC. The script does the blocking. When an item needs to know whether the field allows use, the item handler asks the field or event state. That separation is what keeps the project expandable.

Let’s do a quick verbal trace, and I want you to listen for the owner at each step. Player selects item. Bag owns that. Item ID is looked up. Item data owns the mapping. Field or battle use function is selected. Item-use dispatch owns that. Party target is requested if needed. Party menu owns that. HP changes. Pokémon data routines own that. Item count decreases. Inventory owns that. Message displays. Menu or field message system owns that. Return callback resumes the prior mode. Main callback and task system own that.

If your clone architecture has one function called `useItem` doing all of those jobs, it may still work for a prototype. But at this level of the course, I want you to see why it will become brittle. The moment you add battle use, field use, script gates, key item registration, party target selection, and map transitions, “one useItem function” becomes a disguised engine.

Now, check for understanding. If I give you an item called “Ancient Pass” that opens a locked ferry route, where should the permanent “route is unlocked” state live? Not in the Bag menu. Not in the item icon. Not in the party menu. It should live in event flags or variables, because the ferry NPC, the map script, and maybe the overworld destination table need to agree about progression. The item may be the input that causes the flag to be set, but the flag is the world state.

Second check: if I give you an item called “Field Tonic” that heals the lead party member only outside battle, should its battle-use function point to the same handler as its field-use function? Probably not. You can reuse internal healing helpers, yes, but the dispatch entry should reflect that battle and field have different legality and continuation rules. If it cannot be used in battle, the battle-use side should route to a “cannot use” behavior or no battle usage, depending on the table design.

Now I want to point at one more supporting clue from the packet. `pokefirered/src/pokemon_summary_screen.c`, `chunk_e8e17a42bbf17d46`, includes item headers, party menu headers, constants for items, battle headers, and move constants. We are not studying the summary screen today, but that chunk reminds us that party-facing UI screens often sit at the intersection of creature data, item data, and battle-relevant information. So when a medicine item sends the player to party selection, it is entering a region of the engine that already understands Pokémon display, moves, held items, and battle-adjacent constraints. That is why FireRed can reuse party UI affordances instead of building a separate target screen for every item.

Let’s return to the board pipeline and add two annotations. Next to “handler,” write “may validate and may delegate.” Next to “continuation,” write “must restore mode.” These two phrases explain most of the code shape in `item_use.c`.

Handlers validate because an item being selected does not mean it is usable. You may select Escape Rope on a map where it is disallowed. You may select a medicine item when no party member can benefit. You may select a rod facing the wrong tile. You may select a key item in a context where its special behavior has no target. FireRed frequently responds with a message rather than an effect. That message is still part of the item-use flow.

Handlers delegate because they often do not have all required input yet. Potion delegates to party choice. Evolution stone delegates to party choice and compatibility logic. A rod delegates to field-facing tile and encounter logic. A registered key item may delegate through the overworld callback path. The handler starts the process; it does not necessarily finish it synchronously.

Continuations restore mode because the user must land somewhere coherent. After a Bag-originated item, do we return to the Bag? Return to the field? Open party? Close a message box? Consume the item and refresh quantity text? In a GBA game, those are not incidental details. They are the user-visible proof that the engine’s state machines agree.

This also explains why `gSpecialVar_ItemId` is useful but dangerous if misunderstood. It is convenient because scripts and specials can share the currently relevant item ID. But if your architecture starts using one global special variable as long-term state, you have lost the distinction between transient dispatch context and persistent progression state. Persistent state belongs in save-backed structures, inventory quantities, party data, event flags, and variables. Transient dispatch context belongs in callback state, task data, temporary globals, and script special variables.

Let me connect this to last week’s assessment. Homework week 17 asked you to trace gameplay from data records through globals, callbacks, tasks, scripts, structs, and concrete functions. Item use is almost a perfect exam question for that skill. A correct trace cannot stop at “the item table has a function pointer.” It has to continue through selected item state, field versus battle dispatch, target acquisition, validation, state mutation, item consumption, message display, and return callback.

And for week 18’s homework and quiz, I will expect you to be able to classify mistakes. If I show you a design where an NPC script directly subtracts Potion quantity and edits party HP, you should be able to say: that script is crossing into item mechanics and party internals. If I show you a design where the Bag knows whether a cave allows Escape Rope, you should be able to say: that legality belongs to field or map context, not the pocket UI. If I show you a design where a badge unlock is represented only by whether the badge item is in the Bag, you should ask whether the game actually models badges as inventory items or as event flags, and whether scripts need to branch on that state.

Now, one more example before we move deeper. Think about a key item that toggles a mode, like a bicycle. It is field-use, not party-use. The selected item ID points to a field handler. The handler checks whether the current map permits the mode. Indoors? Probably no. Certain maps? Maybe no. If allowed, it changes player movement state and returns to the overworld. Notice what did not happen: no party selection, no HP edit, no battle controller turn. Same dispatch spine, different branches.

That is why the architecture scales. The system does not need a universal item-effect object that can express every possible behavior declaratively. FireRed chooses a more C-native approach: data table to function pointer, then specialized code, then callbacks and tasks for long-lived UI or field effects. In a modern engine, you might implement the same idea with interfaces, command objects, async coroutines, or data-driven effect graphs. But the architectural question is unchanged: who owns selection, who owns legality, who owns mutation, who owns persistence, and who owns returning the player to a coherent screen?

So, keep the board pipeline visible. In the next pass, we are going to zoom into the awkward middle of the path: the moment after a field-use handler decides it cannot finish immediately. That is where the continuation code becomes the real architecture, because it has to preserve intent across a mode change without letting the Bag, the party menu, the script VM, and the overworld all become one tangled subsystem.

Good. So, let’s stand inside that awkward middle for a while.

I’m going to draw this as a little relay race on the board. First runner: the Bag or registered item shortcut. Second runner: the item-use function pointer. Third runner: a continuation callback that can survive a fade or mode change. Fourth runner: the overworld, party menu, battle menu, or field effect that actually finishes the behavior. The mistake, when you first read this code, is to think the item-use handler itself “does the item.” Sometimes it does. But often it only decides who should do the item later.

That is why `pokefirered/src/item_use.c`, especially the excerpts we are using as `chunk_7e88bbaddbab5bb9`, `chunk_8f5c0eba4013eb8a`, and `chunk_ce2671932ba5ff71`, is such a useful file for this week. It is not just a collection of item behaviors. It is a boundary-management file. It knows about the Bag, the Berry Pouch, the party menu, the overworld field callback, field effects, battle-use returns, and event flags and variables. That sounds messy, and some of it is messy, but there is an architecture underneath it. The code is repeatedly asking, “Am I still in the Bag? Am I already on the field? Do I need a party selection? Do I need to fade out first? Do I need to lock controls? Do I need to remove the item now or after the visible effect starts?”

Now look at the continuation variable. The file declares a static EWRAM function pointer, `sItemUseOnFieldCB`, with the shape `void (*)(u8 taskId)`. That one line is very high signal. It means FireRed is not trying to keep a whole object graph alive across the transition. It stores the smallest possible intent: “after we are back on the field, call this function for this task.” So if we use the bicycle, the pending continuation becomes `ItemUseOnFieldCB_Bicycle`. If we use a rod, the pending continuation becomes `ItemUseOnFieldCB_Rod`. If we use Escape Rope, it becomes `ItemUseOnFieldCB_EscapeRope`. The item-use function pointer from the item data brought us into the generic handler; the static continuation pointer carries us from menu world back into field world.

Pause there, because that is a pattern you can reuse in your own engine. You do not always need a giant “item use transaction” object. Sometimes you need one stable callback slot, one task id, and a small amount of task-local data. The advanced judgment is knowing when that is enough. FireRed can get away with it because the GBA game is mostly single-threaded, callback-driven, and modal. There is one active front-end context at a time. The player cannot open three item menus and race their callbacks against each other. In a modern asynchronous UI, this exact global pointer would be dangerous unless wrapped in ownership rules. But in FireRed’s runtime shell, it is a compact continuation mechanism.

Now, follow the bicycle path as a concrete example. `FieldUseFunc_Bike` first checks legality. It reads the player’s destination coordinates, gets the metatile behavior under the player, and checks conditions like Cycling Road and rail metatiles. If dismounting is illegal, it displays the “can’t dismount” message in the current context. If biking is allowed by the overworld and not disallowed by the player state, it assigns `sItemUseOnFieldCB = ItemUseOnFieldCB_Bicycle` and calls `SetUpItemUseOnFieldCallback`. That support path is in `pokefirered/src/item_use.c chunk_8f5c0eba4013eb8a`. Notice the separation: the legality check is immediate, but the actual avatar mutation, `GetOnOffBike`, is deferred until the field context is ready.

I’m writing two phrases on the board: “legal now” and “mutate later.” That is the point. `FieldUseFunc_Bike` can answer “may the player use the bike?” while still refusing to perform the bike transition inside the Bag screen. Once the field is back, `ItemUseOnFieldCB_Bicycle` plays the bell if needed, toggles the player avatar bike flags, clears held movement, unfreezes object events, unlocks field controls, and destroys the task. The item did not simply mutate inventory. It coordinated avatar state, audio feedback, object-event locking, and task cleanup.

Now let’s look at the function that makes that handoff possible, `SetUpItemUseOnFieldCallback`. It checks `gTasks[taskId].data[3]`. In this file, that task data slot is being used as a context marker: are we using the item from the Bag, or are we already on the field? If `data[3]` is not one, FireRed sets `gFieldCallback = FieldCB_FadeInFromBlack` and then calls `SetUpItemUseCallback`, which routes the current menu out through the appropriate exit callback. If `data[3]` is one, it calls `sItemUseOnFieldCB` immediately. That little branch is the difference between “close the Bag, return to overworld, then continue” and “we are already on the overworld, continue now.”

Check yourself here. If the bicycle handler simply called `GetOnOffBike` while the Bag was still drawing, what systems would be out of sync? You should be thinking: the avatar flags might change before field controls are restored, the Bag’s window animation may not have completed, object events may still be locked for menu interaction, and the player could be returned to a screen whose visual state does not match the newly mutated overworld state. That is why the continuation matters. It lets the visible mode transition and the state mutation happen in a stable order.

There is a second callback slot in the same area, `gFieldCallback2`, set by `SetFieldCallback2ForItemUse` to `FieldCB2_UseItemFromField`. This shows up for field-launched submenus such as the TM Case, Berry Pouch, Teachy TV, Town Map, and Fame Checker. These are not quite the same as the bicycle. The bicycle returns to the field and toggles movement state. The Town Map returns to the field, fades out, cleans up overworld windows and tilemaps, launches the region map UI, and then needs a way to restore the field after the region map closes. That is why you see `Task_UseTownMapFromField` wait until the palette fade is inactive, call `CleanupOverworldWindowsAndTilemaps`, set `gFieldCallback2`, call `InitRegionMapWithExitCB(REGIONMAP_TYPE_NORMAL, CB2_ReturnToField)`, and destroy the task. That flow is also in `pokefirered/src/item_use.c chunk_8f5c0eba4013eb8a`.

So we have two continuation shapes. One shape says, “When the field resumes, execute this specific item action.” That is `sItemUseOnFieldCB`. Another says, “When this launched field-adjacent UI returns, restore the field in a controlled way.” That is `gFieldCallback2` pointing at `FieldCB2_UseItemFromField`. In both cases, the item system is not owning the entire world. It is placing hooks at the boundary between worlds.

Now, let’s use Escape Rope because it forces us to connect item legality, map data, inventory mutation, and field effects. `CanUseEscapeRopeOnCurrMap` checks `gMapHeader.allowEscaping`. That is beautiful in its simplicity. The item-use code does not hard-code every cave. It asks the current map header whether escape is allowed. Then `ItemUseOutOfBattle_EscapeRope` either prints Oak’s “not the time” message or records the quest-log event, stores `ItemUseOnFieldCB_EscapeRope` as the continuation, and enters the same field callback setup path. In the continuation, `ItemUseOnFieldCB_EscapeRope` calls `Overworld_ResetStateAfterDigEscRope`, removes the used item through `RemoveUsedItem`, prepares the task data, and displays the “player used item” message on the field. The message callback is `Task_UseDigEscapeRopeOnField`, which resets the initial player avatar state and starts the Escape Rope field effect with `StartEscapeRopeFieldEffect`.

Again, notice the sequencing. The legality check happens before consuming the item. The item is removed only once the use is committed. The overworld state is reset before the visible field effect begins. The task is destroyed after the field effect has been launched. If you consume the item too early, failed use loses inventory. If you start the field effect before resetting avatar state, you risk animation or movement leftovers. If you destroy the task before assigning the message callback, the UI has nowhere to resume. Each line is small; the architecture is in the order.

Now I want to connect this to the script and progression layer, because this week is not only “how items do effects.” It is also “how items become unlock inputs.” The event variable and flag support in `pokefirered/src/event_data.c chunk_bff5bbc2efc3008f` gives us `VarGet`, `VarSet`, `FlagSet`, `FlagClear`, and `FlagGet`. These functions ultimately address persistent storage in `gSaveBlock1Ptr->vars` and `gSaveBlock1Ptr->flags`, except when the id refers to a special variable or special flag. That means progression state is not scattered randomly across NPC scripts. The scripts speak through a small event-data API.

Then `pokefirered/src/scrcmd.c chunk_7609d397203c8536` gives the script VM commands that use that API. `ScrCmd_additem` reads an item id and quantity through `VarGet`, calls `AddBagItem`, and writes the success boolean to `gSpecialVar_Result`. `ScrCmd_removeitem` does the same with `RemoveBagItem`. `ScrCmd_checkitemspace` and `ScrCmd_checkitem` ask whether the inventory can hold or contains some quantity, again writing to `gSpecialVar_Result`. `ScrCmd_setflag`, `ScrCmd_clearflag`, and `ScrCmd_checkflag` bridge script text to persistent boolean progression. So a key item gate, an NPC gift, a blocked doorway, or a badge-dependent unlock can be built from these script commands without every one of those scripts manually knowing the Bag’s internal pocket layout.

Here is the design connection. Item use is C-native dispatch. Script progression is VM command dispatch. Both are tables or command streams that eventually call C functions. The previous battle AI work gave us script pointer control and predicate-style branching inside battle. We are not reteaching that today, but the mental model carries forward: a tiny interpreter or dispatch layer moves through commands, and certain commands cross into native code to read or mutate real game state. In item use, the command is effectively “call this item’s field or battle use function.” In scripts, the command is “set a flag,” “check an item,” or “start a field effect.” Different surfaces, same architecture: data or bytecode selects native behavior, native behavior updates shared state, and the player sees a coherent result after callbacks settle.

Let me give a concrete progression example. Suppose an NPC blocks a cave until the player has a certain key item. The item itself might never be “used” from the Bag. Instead, the NPC script uses `ScrCmd_checkitem` to ask, “Does the Bag contain this item?” The result lands in `gSpecialVar_Result`. A following conditional command branches on that comparison result. If false, the NPC displays a blocker message. If true, the script may set a story flag with `ScrCmd_setflag`, remove the item with `ScrCmd_removeitem` if it is consumable, apply movement, open a door, or start a field effect. That is item-as-input rather than item-as-action. The same inventory state that powers the Bag UI becomes a progression fact in the event VM.

Now contrast that with a Potion. A Potion’s ordinary field use goes to the party menu because `struct Item` in `pokefirered/include/item.h` includes `type`, `fieldUseFunc`, `battleUsage`, and `battleUseFunc`, and medicine uses a party-selection callback such as `gItemUseCB = ItemUseCB_Medicine` before moving to `CB2_ShowPartyMenuForItemUse`. We covered item records and Bag pockets in the previous week, so I am not going to reopen that whole data layout. What matters now is ownership. The Bag owns selection of the item. The item-use handler owns choosing the next mode. The party menu owns selecting the target creature. The item-effect execution owns mutation of HP, status, PP, or level. Then the UI callback owns returning the player to the correct screen.

That ownership split is why battle-use medicine is not identical to field-use medicine. In battle, `BattleUseFunc_Medicine` sets `gItemUseCB = ItemUseCB_MedicineStep` and switches to the party menu through a battle return path. Stat boosters in battle are even more direct: `BattleUseFunc_StatBooster` calls `ExecuteTableBasedItemEffect` on the active battler’s party member, delays for a few frames, removes the item, prints the stat booster message, and returns to battle after input. That code is in `pokefirered/src/item_use.c chunk_ce2671932ba5ff71`. The same item-effect table can be involved, but the surrounding screen and turn context are different, so the continuation and return callback are different.

Quick check for understanding. Why is `gItemUseCB` not enough for Escape Rope? Think it through. `gItemUseCB` is appropriate when the next step is party-menu selection and then a per-creature item effect callback. Escape Rope does not target a party member. It targets the overworld state and map transition rules. So it uses `sItemUseOnFieldCB` and a field effect path instead. Why is `sItemUseOnFieldCB` not enough for a Potion? Because a Potion needs the party menu to ask which creature receives the effect. If you answer those two questions correctly, you understand the core dispatch split.

The support function `DisplayItemMessageInCurrentContext` is another small but important boundary device. It expands placeholders into `gStringVar4`, then chooses either `DisplayItemMessageInBag` with `Task_ReturnToBagFromContextMenu`, or `DisplayItemMessageOnField` with `Task_ItemUse_CloseMessageBoxAndReturnToField`. Same message, different return behavior. That is a recurring FireRed pattern: common semantic content, context-specific callback. The “Oak forbids use” message is not just text. It is a modal response that must return to the right owner.

Now, let’s pull the source packet together for a moment. `pokefirered/include/item.h` is the cross-module contract for item records and function pointers. `pokefirered/src/item_use.c chunk_7e88bbaddbab5bb9` gives us the setup table and dispatch support, including `sExitCallbackByItemType`, `SetUpItemUseCallback`, and the field continuation path. `pokefirered/src/item_use.c chunk_8f5c0eba4013eb8a` shows field-use continuation examples such as Bike, Rod, TM Case, Berry Pouch, Repel, Escape Rope, Town Map, and Fame Checker. `pokefirered/src/item_use.c chunk_ce2671932ba5ff71` shows battle-use and special cases like stat boosters, medicine, Enigma Berry routing, and the shared quest-log helper. `pokefirered/src/event_data.c chunk_bff5bbc2efc3008f` gives the persistent flag and variable access layer. And `pokefirered/src/scrcmd.c chunk_7609d397203c8536` gives the script command surface for checking, adding, and removing items, setting flags, comparing vars, and starting or waiting for field effects.

The sophistication here is that item behavior is not one system. It is a negotiation among systems. Some items are UI launchers. Some items are party-targeted effects. Some items are battle commands. Some items are overworld transitions. Some items are merely facts that scripts check. Some items, like flutes and repels, mutate flags or variables that other systems later consult. `FieldUseFunc_Repel`, for instance, checks `VAR_REPEL_STEP_COUNT`; if no repel is active, it plays the repel sound, then `Task_UseRepel` sets `VAR_REPEL_STEP_COUNT` to `ItemId_GetHoldEffectParam(gSpecialVar_ItemId)`, removes the item, and prints the use message. That variable is not the item itself. It is the ongoing world condition produced by the item. This is how a one-time menu action becomes a multi-step overworld rule.

So, if you are designing the lab version this week, do not start by writing “usePotion” and “useEscapeRope” as isolated functions. Start by naming the owners. The inventory owns item count. The item table owns which handler to call. The field handler owns legality checks that depend on map state. The party menu owns target selection. The script VM owns story gating. The flags and vars layer owns persistent progression memory. The task system owns waiting across frames. The callback system owns mode transitions. Once you name those owners, the implementation gets much less mysterious.

And that leads us into the next part of the lecture. We have now seen how FireRed preserves intent across a mode change. Next, we need to look more carefully at blockers: not only “can this item be used here?” but “which piece of persistent state makes the world agree that the player has earned this unlock?” That is where badges, HMs, map permissions, party moves, flags, variables, and inventory checks all start to overlap, and our job is to keep those overlaps explicit instead of letting them collapse into one vague word, “progression.”

Good. So now, when we say blocker, I want you to stop thinking only in terms of the message box. The message box is the symptom. The blocker is the state predicate that fails. That distinction matters because FireRed has several different kinds of predicates living in different places.

Let me put a small chain on the board. Item selected, current item id, use-function pointer, context check, state mutation or refusal. In FireRed, the selected item flows through gSpecialVar_ItemId, and the item’s data record exposes use functions through the item accessors. The source packet’s item accessor chunk, pokefirered/src/item.c chunk_96832b5354d66a3a, is the clean data-to-function bridge: ItemId_GetType, ItemId_GetFieldFunc, ItemId_GetBattleUsage, and ItemId_GetBattleFunc read fields out of gItems. That is the architectural hinge. The item is not a giant switch statement in the bag menu. The item record carries enough information for the menu to dispatch to the right behavior.

Now, we already covered bag pockets and quantities last week, so I am not going to reopen that machinery. What I want you to notice today is what happens after the bag has done its job. The bag’s job is selection and presentation. After that, use behavior moves into item_use.c, party_menu.c, field effects, script commands, and event data. That is why week 18 sits exactly where it does in the course plan. Week 17 gave us the Bag as a UI facade. Week 18 asks, “When the UI says use, who decides whether the world accepts that use?” And by week 19, this has to connect back to persistence, because flags, vars, and save-block state are what make the unlock survive a reboot.

Let’s take Escape Rope as the first concrete blocker. You select Escape Rope. The item data points to an out-of-battle use handler, and the handler in pokefirered/src/item_use.c chunk_8f5c0eba4013eb8a is a very small but very revealing implementation. CanUseEscapeRopeOnCurrMap does not ask, “Does the player own Escape Rope?” That question was already answered by inventory. It asks whether gMapHeader.allowEscaping is true. If it is true, ItemUseOutOfBattle_EscapeRope records a quest log event, sets sItemUseOnFieldCB to ItemUseOnFieldCB_EscapeRope, and sends control through SetUpItemUseOnFieldCallback. If it is false, it routes to the familiar Oak-style refusal message through PrintNotTheTimeToUseThat.

So, check for understanding: where is the Escape Rope unlock stored? Not in the Escape Rope item. Not in the party. Not in a badge flag. For this case, the permission is in the current map header, specifically allowEscaping. The item is merely the input. The map supplies the spatial permission. The callback and task system supply the timing. The bag supplies the selection. If those ownership lines blur in your design, you will end up with an item system that somehow knows every cave, every dungeon, and every special exception. FireRed avoids that by letting the map header answer the map question.

Now compare that to Repel. Repel is a field-use item too, but its blocker is not a map permission. In pokefirered/src/item_use.c chunk_ce2671932ba5ff71, FieldUseFunc_Repel checks VarGet(VAR_REPEL_STEP_COUNT). If the current repel step count is zero, the handler schedules Task_UseRepel; that task sets VAR_REPEL_STEP_COUNT to ItemId_GetHoldEffectParam(gSpecialVar_ItemId), removes the item, and prints the used-item message. If the variable is already nonzero, the handler prints the “effects lingered” message. So what is the blocker? It is not “this route does not allow Repel.” It is not “the player lacks a badge.” It is a temporary progression-like variable saying, “A repel effect is already active.”

That is a different category of state. On the board, I am going to write three columns: inventory state, world permission, and persistent or semi-persistent progression state. Escape Rope consumes inventory and asks world permission. Repel consumes inventory and writes a variable. A badge-gated field move asks party state and flag state. A key item may not be consumed at all, but it can still route through the same dispatch shell. Different cases, same architecture: item use is a dispatch point, not a monolithic effect engine.

Now let’s connect this to event_data.c, because otherwise “flag” and “var” become magic words. In pokefirered/src/event_data.c chunk_bff5bbc2efc3008f, VarGet and VarSet go through GetVarPointer. That means a script variable is not just a loose global; it is resolved through a layer that decides whether the variable lives in save block storage or in the special variable table. In the neighboring event-data support, pokefirered/src/event_data.c chunk_b8160166cd1a306b, FlagSet, FlagClear, and FlagGet operate through GetFlagAddr and bit operations over flag storage. This is the memory substrate for progression. When a script checks a badge, checks a story event, or remembers that a system effect is active, it is usually talking through this layer.

And that layer also explains why gSpecialVar_Result is so common. Script commands need a standard return slot. If a script says checkitem or checkpartymove, the C function needs somewhere to leave the answer for the script VM. In pokefirered/src/scrcmd.c chunk_4abaefc1371646f8, the item script commands use VarGet to resolve the item id and quantity, then write gSpecialVar_Result with results from CheckBagHasItem, CheckBagHasSpace, or GetPocketByItemId. In pokefirered/src/scrcmd.c chunk_2800162c34bde901, ScrCmd_checkpartymove scans the player party for a move, ignores eggs, writes the party slot to gSpecialVar_Result when it succeeds, and also writes species into gSpecialVar_0x8004. That is not just convenience. That is the contract between script bytecode and C helpers.

Let’s use Cut as the example, because it forces all the layers to show up. A Cut tree script is not satisfied by owning HM01. Ownership of the HM is only the teaching input. A monster must know MOVE_CUT. The player must have the appropriate badge flag. The current tile or object must be something cuttable. The field effect must then run the animation and alter the object or metatile. In data scripts, field move scripts use commands like goto_if_unset on a badge flag, checkpartymove MOVE_CUT, setfieldeffectargument, and dofieldeffect. The C side that supports checkpartymove is in pokefirered/src/scrcmd.c chunk_2800162c34bde901, and the general field-effect argument command family appears in pokefirered/src/scrcmd.c chunk_7609d397203c8536 as part of the wider script-to-world control surface. The important design point is that “can use Cut” is not one boolean in one place. It is an intersection of story flags, party moves, local world geometry, and field-effect execution.

Now pause and ask yourself: why not simply put “requires badge 2” in the HM item data? That would feel tidy for about ten minutes. Then Surf from the overworld shoreline, Surf from the party menu, Cut from a tree event, Strength on a boulder, and special map exceptions would all start pulling that rule in different directions. FireRed instead lets the entry point own the check appropriate to that entry point. The script checks the story gate when the world object is asking. The party menu checks field-move eligibility when the party menu is asking. The item-use handler checks item-specific context when the bag is asking. The shared flag and var layer keeps those checks consistent because everyone calls the same FlagGet, VarGet, and related helpers.

This is the same architectural discipline you saw in the Battle AI scripts, just aimed at player progression instead of opponent decision-making. In the AI lectures, script pointer control let a data-like command stream query battle state and branch. Here, script commands query inventory, party moves, flags, and variables, then branch world progression. Do not overextend the analogy, but keep the pattern: small commands, shared state accessors, and explicit result slots. FireRed likes state machines, but it also likes narrow bridges between state machines.

Now let’s bring in healing items, because they look simple but they demonstrate another kind of dispatch. In pokefirered/src/item_use.c chunk_7e88bbaddbab5bb9, FieldUseFunc_Medicine does not heal immediately. It sets gItemUseCB to ItemUseCB_Medicine and then calls the item-use setup callback. Ether, PP Up, Rare Candy, evolution stones, and Sacred Ash follow the same pattern with different gItemUseCB values: ItemUseCB_TryRestorePP, ItemUseCB_PPUp, ItemUseCB_RareCandy, ItemUseCB_EvolutionStone, ItemUseCB_SacredAsh. In other words, the field item-use layer says, “This item requires a party target, and once the party menu gives me that target, call this effect callback.” The effect itself belongs with party-menu and Pokémon data handling, not with the bag list.

Concrete example. Suppose the player uses a Potion from the bag outside battle. The item dispatch does not immediately choose a monster. It sets the item-use callback for medicine and exits toward the party menu. The party menu owns target selection. After the player chooses a party slot, the callback can apply the table-based item effect to that monster, update HP, remove the item if it worked, and print the correct message. If you built this in a clone, you should not write “Potion opens a special Potion screen.” You should write “Potion is an item record whose field-use handler sets a party-target callback.” That is the reusable architecture.

Now contrast that with a key item like the Bicycle. In pokefirered/src/item_use.c chunk_7e88bbaddbab5bb9 and the surrounding item-use source, FieldUseFunc_Bike checks environmental conditions: Cycling Road, rail metatile behavior, whether biking is allowed, whether player state disallows it. If allowed, it sets sItemUseOnFieldCB to ItemUseOnFieldCB_Bicycle and routes through SetUpItemUseOnFieldCallback. The Bicycle is not consumed. It does not need a party target. It toggles avatar movement state. So this handler is field-context behavior, not party-context behavior. Same dispatch shell, different owner.

Registered key items are a nice edge case because they bypass the visible bag list while still using the same item-use handlers. In pokefirered/src/item_menu.c chunk_8563374a46f05c26 and the raw source around UseRegisteredKeyItemOnField, the game checks gSaveBlock1Ptr->registeredItem, verifies the item is still in the bag, locks player controls, freezes object events, stores the registered item in gSpecialVar_ItemId, creates a task from ItemId_GetFieldFunc, and marks task data so the handler knows it was invoked from the field. That is an elegant reuse. Select-button Bicycle and bag-menu Bicycle do not need two Bicycle implementations. They need two entry paths into the same handler.

Let me ask a check question here. If a student says, “Registered items are separate from bag items,” what is wrong with that? The visible input path is separate, yes. But the item identity, inventory validation, and field-use function pointer are shared. The registered item is an alternate invocation path, not a second item system. That distinction will save you from duplicating state in your lab this week.

Now, let’s tie this to blockers more formally. A blocker is not always a denial. Sometimes it is a deferral. SetUpItemUseCallback is a deferral mechanism. It decides which callback should receive control after the bag fades out. In pokefirered/src/item_use.c chunk_7e88bbaddbab5bb9, the exit callback table maps item types toward party menu or field return behavior. SetUpItemUseOnFieldCallback adds another layer: if the item was not already invoked directly from the field, it stores FieldCB_FadeInFromBlack into gFieldCallback, exits the menu, waits for the fade/weather condition, and only then calls sItemUseOnFieldCB. That means “use item” can span several frames and several modes without losing intent. The intended operation is held in function pointers and task state.

That is why the callback and task material from week 1 is not background trivia. SetMainCallback2 and RunTasks were not isolated engine facts. They are why a bag action can close a menu, fade the screen, re-enter the overworld, wait for weather fade-in, and then execute a field effect without blocking the CPU or stacking synchronous calls. Advanced architecture work is often about seeing these old mechanisms come back in new clothing.

Let’s synthesize this portion before we push further. Item use in FireRed is a dispatch problem over multiple state owners. The item table identifies possible handlers. The bag menu selects an item and launches the handler. item_use.c performs item-specific context checks and chooses whether to route to field behavior, party targeting, battle behavior, or refusal text. party_menu.c owns party-target selection and field-move menu checks. scrcmd.c gives scripts commands like checkitem, checkflag, checkpartymove, and field-effect invocation. event_data.c owns the durable flag and variable access layer. And map headers, metatile behavior, avatar state, and party move data each answer the questions that belong to them.

So when you build the lab version, I do not want a giant UseItem function with Potion, Escape Rope, Key Item, and HM cases all mutating every subsystem directly. I want a dispatch surface. Potion should dispatch to a party-target effect. Escape Rope should check a map-level escape permission and then schedule a field effect. A key item should validate field context and run without consumption. A badge-gated field move should combine flag state, party move state, and world interaction state, probably through script-like predicates rather than through item ownership alone. That is the week 18 standard.

And now, with that model in place, we are ready to look at the next overlap: items that are not “used” in the ordinary menu sense at all, but still act as scripted unlock inputs. That is where Tea, key story items, badge checks, route guards, and inventory queries start to look less like inventory features and more like script-language predicates over save data.

So let’s step across that boundary carefully. Up to now, the item has been the thing the player selected. The player opens the Bag, chooses an item, and the item-use code decides what happens next. But in a creature RPG, many important items are not primarily “used” by the player at all. They are carried. They are detected. They are treated as evidence that the world should now respond differently.

And that distinction matters architecturally. A Potion is active behavior. The player says, “Use this now.” Tea, a key, a badge, a ticket, or a Silph Scope-like story object is often passive permission. The player may never press “Use” on it in the relevant scene. Instead, a script asks, “Does the player have the required thing?” or “Has the required flag been set?” or “Is the required variable in the required range?” Then the world branches.

Put that on the board. Left side: selected item. Right side: queried item. The selected item enters through item-use dispatch. The queried item enters through script or event logic. Both refer to inventory state, but they are not the same control flow.

This is one of the biggest mistakes I see in student clone projects after week 17. You build an inventory system, you build a use function, and then you try to make every story gate into a special item-use handler. So the guard who wants Tea becomes, somehow, an effect of selecting Tea in the Bag. The locked door becomes an effect of using a key from the inventory menu. The field move becomes an item because the menu is convenient. That can work for one prototype. It does not scale into a coherent RPG architecture.

FireRed’s approach is more layered. The Bag and item-use code handle the selected-item pathway. The script system and event data handle the world-query pathway. The two pathways meet at shared state: item quantities, party data, flags, variables, current map context, and sometimes special-purpose globals. The source focus for this week makes that split very visible. The item-use flow in pokefirered/src/item_use.c, especially chunk_7e88bbaddbab5bb9, is about dispatching behavior after a player chooses an item. The continuation chunks, chunk_8f5c0eba4013eb8a and chunk_ce2671932ba5ff71, are still in that family: field continuation, support code, and the extra steps needed after a use decision. But pokefirered/src/event_data.c chunk_bff5bbc2efc3008f is about event flags and variables as save-backed progression state, and pokefirered/src/scrcmd.c chunk_7609d397203c8536 is where script commands give map scripts a language for checking and changing that state.

Notice the design pressure. Items are data. We covered that last time. Pockets and quantities are data. The Bag UI is a facade over that state. But progression is not just item data. Progression is world logic. It asks whether the presence of an item, or the use of an item, or the completion of a scene, should alter what scripts do next.

Let me give you a concrete example. Imagine a guard blocking a city gate. In a poor architecture, the guard object might directly inspect the Bag data structure, remove Tea, set the door open, change its dialogue, and maybe teleport the player. That is a lot of responsibility for a guard interaction. It also means every guard becomes a little custom program with private rules.

In a better FireRed-style architecture, the object event launches a script. The script asks a progression question. Maybe it checks inventory. Maybe it checks a flag representing that Tea has already been delivered. Maybe it checks a variable representing story stage. If the condition fails, the script displays blocking dialogue. If it succeeds, the script can set a flag, update a variable, remove an item if the design calls for consumption, and release the player. The inventory is an input to the script, but the script owns the story branch.

Let’s pause for a check. If I ask, “Where should the rule live that says this guard stops blocking the road after Tea is delivered?” the answer is not “inside Tea’s use handler.” The answer is: in the event scripting and progression state layer. Tea may be part of the predicate, but the world script owns the consequence.

Now, this is where the earlier AI-script lecture is useful, but only as a memory hook. We are not reteaching AI pointer control. Just recall the pattern: a small command language advances through predicates and branches. Battle AI used that idea for choosing behavior under combat constraints. Map scripts use the same general architectural idea for progression constraints. A script command checks state, branches, sets state, and resumes. The domain is different, but the shape is familiar.

Same with party-aware predicates from the battle AI week. When a field move is gated by badge and party move state, you should hear that as a predicate over multiple systems. Does the player have the badge flag? Does some party member know the move? Is the player facing the correct terrain or object? Is the current map allowing this action? That is not merely “does the player own an HM item?” In fact, treating HM ownership as sufficient is one of those simplifications that breaks the game’s design language. The item may introduce the move, but the unlock depends on save flags, party records, and field context.

On the board, I’ll write this as a predicate stack: inventory state, flag state, variable state, party state, map state, interaction state. Then under it I’ll write: script branch or item-use continuation. That is the central model for today’s overlap.

Let’s connect this to files. event_data.c, in the packet as pokefirered/src/event_data.c chunk_bff5bbc2efc3008f, is the support layer for flags and variables. Those are not glamorous systems, but they are the backbone of progression. A flag is a small persistent boolean: defeated this trainer, received this item, opened this shortcut, acquired this badge. A variable is a small persistent scalar: current story stage, selected choice, temporary script result, count, or other script-visible value. scrcmd.c, specifically pokefirered/src/scrcmd.c chunk_7609d397203c8536 in our packet, is the bridge that exposes those operations to the script language.

That separation is not accidental. You do not want every map script to know where save memory stores bitfields. You want script commands like check flag, set flag, clear flag, compare variable, set variable, and then branch. The script command layer is a controlled interface. The event data layer is the storage and helper layer. Together, they make progression scriptable without letting every feature poke arbitrary memory.

Now compare that to item_use.c. Item-use dispatch is more like a user command router. Player selected item ID. We look up what category of item this is, or what function pointer is associated with it, or what special case applies. Then we start an effect: party selection, message box, field transition, key item behavior, escape behavior, registered item behavior, and so on. The important thing is that the action begins with a menu choice.

The script-query path begins differently. The player talks to an NPC, steps on a tile, presses A on an object, enters a map, crosses a trigger, or completes some other world interaction. The script then queries item and progression state. That is why “items as unlock inputs” belongs beside item-use dispatch but not inside it.

Let’s make this concrete with Escape Rope versus a story key. Escape Rope is a selected item. The player chooses it, and the system has to ask, “Can this be used here?” If yes, it consumes or schedules the effect and transitions the player out. The use handler is a reasonable owner of that check, because the player requested the effect from the Bag. A key to a locked building is different. If the player presses A on the door, the door script asks whether the key condition is satisfied. The key is not necessarily “used” from the Bag. The door interaction is the active event.

And if you are building the lab this week, that difference should show up in your code. Potion should be a menu-selected item that routes into party targeting and healing. Escape Rope should be a menu-selected item that checks a field permission and then schedules a transition. A key item can be menu-selected but non-consumable, often producing text or context behavior. A locked door, however, should not require the key item to know every door in the game. The door script should ask for the key, flag, or variable it needs.

Let’s do a small board trace. Player talks to guard. Object event dispatches script. Script command checks flag: has the guard already accepted Tea? If yes, show open dialogue or allow passage. If no, script checks inventory for Tea. If false, show blocking dialogue. If true, remove Tea or set delivered flag, depending on design, then change dialogue and allow passage. The item itself has not dispatched an effect. The script has consumed inventory state as a predicate.

Now, you may ask, why not just check inventory every time and skip the flag? Good question. In some designs, that is fine. But a flag gives the world memory independent of the item. Suppose the item is consumed. If you only check inventory, the player no longer has Tea, so the guard would block again. Suppose the item is not consumed. If several guards can respond to the same item, you may need flags for which guard has already run which scene. Suppose a later event should know that the guard scene happened, not merely that the player owns Tea. Inventory state answers ownership. Flags answer history.

That is a key phrase: inventory state is not the same as story history.

Variables extend this idea when boolean history is not enough. A flag can say “badge obtained.” A variable can say “story chapter equals 4,” or “fossil choice equals Dome,” or “quest progress equals delivered package but not received reward.” FireRed’s event data support, again represented in pokefirered/src/event_data.c chunk_bff5bbc2efc3008f, gives this save-backed machinery to many systems. Script commands in pokefirered/src/scrcmd.c chunk_7609d397203c8536 let event scripts operate on it without hard-coding C branches for every route gate.

Let me check understanding here. If you are looking at a blocked path and trying to locate the implementation, what is your first question? It should not be, “Which item uses this?” It should be, “What event triggers this decision?” Is it an object script, a map script, a tile trigger, a field move interaction, or a Bag item-use action? Once you know the entry point, then you follow the state query.

And this gives us a practical debugging strategy. When a field item does not work, trace from the Bag into item_use.c. When a story gate does not open even though the player has the item, trace from the map event script into scrcmd.c and event_data.c, and then into the inventory query or flag query being used. If a badge-gated move is denied, do not stop at the HM item. Check badge flag, party move, map behavior, and field context.

This is also how we connect week 18 to the overall course plan. In the first part of the course, we built the runtime shell: callbacks, tasks, and per-frame dispatch. In the map weeks, we saw object events and scripts as world behavior. In the battle weeks, we saw battle command flow and predicate-driven decisions. In week 17, we studied inventory as data plus UI facade. Now week 18 is the crossing point. Items are no longer just records in a Bag. They become inputs into callback flow, task flow, party selection, field effects, and script progression.

So the sophistication level rises. I am no longer satisfied if you can say, “This item heals 20 HP.” At the advanced level, you need to say, “The item record identifies the item; the Bag UI selects it; item-use dispatch chooses a party-targeting path; party menu state chooses a mon; the effect mutates the party data; the UI prints the result; quantity may be decremented; control returns through the appropriate callback or task continuation.” That is the complete architecture sentence.

For a progression item, the sentence changes: “The item record and inventory quantity exist, but the player-visible unlock is entered through an event script; the script command checks inventory, flags, variables, or party state; event_data stores persistent booleans and variables; scrcmd exposes those checks and mutations; the script branches to blocking or unlocking behavior.” Different sentence, different ownership.

Let’s bring in one of the support examples from the broader packet. pokefirered/src/battle_setup.c chunk_494d132a59422c85 includes event_data.h, script.h, event scripts, field effects, overworld, item, and battle-related headers all in one source neighborhood. I am not citing that to claim it implements today’s exact item-use dispatch. I am citing it because it shows how FireRed’s systems are cross-wired at boundaries: battle setup is not isolated from script state and event state. The game frequently has to ask progression questions before entering another major mode. That is the same architectural theme we are studying with item unlocks.

Similarly, pokefirered/src/daycare.c chunk_119931105f546346 includes event_data.h, script.h, item constants, menu helpers, party and storage-related systems. Daycare is not an item-use feature, but it is another example of a feature that sits at the intersection of party data, UI, script-facing state, and persistent progression. These source neighborhoods remind us that FireRed is not a set of pure isolated modules. It is a set of disciplined interfaces around shared save and runtime state.

Now, let’s test the model with a deliberately tricky case: a badge-gated field move. Is that item-use dispatch or scripted unlock? The honest answer is: it can involve both, depending on entry point. If the player uses an HM-related item or selects a party move from a menu, there may be a use-style dispatch or party-menu pathway. If the player presses A facing water, or an overworld interaction offers Surf, the field system and script-like checks may initiate the action. But the unlock predicate is not item ownership alone. It asks whether the badge flag is set, whether an eligible party member exists, whether the terrain supports the move, and whether the current context permits it.

So, in your lab, if you implement badge-gated Cut or Surf as “if player owns HM, allow,” that is below the week 18 bar. If you implement it as “if badge flag and party move and field target are all valid, allow,” then you are closer. If you route the player-visible entry through the correct surface, item menu versus world interaction, then you are at the architecture level we want.

Let’s slow down and make sure the terms are clean. A dispatcher chooses behavior based on an ID, context, or state. An item-use dispatcher starts with an item ID chosen by the player. A script command dispatcher starts with a script opcode. A task dispatcher starts with a task callback. A callback dispatcher starts with the main loop calling the current callback. We have seen all of these. FireRed’s architecture reuses this idea constantly, but the dispatch surfaces are not interchangeable. The question is always: who owns the next decision?

For a Potion, item_use.c owns the first decision after the Bag. For a guard, scrcmd and the event script own the branch. For an Escape Rope, item_use.c asks the field context whether it is allowed and then hands off to field transition behavior. For story flags, event_data is the persistent truth source. For party move checks, party data and move slots are part of the predicate. For battle-only items, the battle context may own legality and effect application.

That is why we keep talking about “surface area.” It is not just an API phrase. It is how you avoid turning the inventory system into a pile of special cases. The item system should expose enough information and hooks for other systems to ask questions. It should not become the universal owner of world progression.

Here is a small design exercise. Suppose you are adding a “Museum Pass.” The player receives it from an NPC. It allows entry into one building. It is not consumed. What state do you need? You need an item record for the pass, and it probably lives in a key-item pocket. You need a receive-item script that gives it to the player and maybe sets a flag saying the gift event has happened. You need a door or guard script that checks whether the pass is present, or checks a derived flag if the pass is meant to be permanent story state. You need dialogue branches for blocked and allowed cases. You do not need a complex “Use Museum Pass” handler unless the design says selecting it should do something.

Now change the example. “One-use Ferry Ticket.” The player gives it to an attendant, it is consumed, and the ferry scene plays. Same architecture, but different consequences. The attendant script checks inventory, removes one ticket, sets a travel-related flag or variable, and triggers the transition. The ticket’s Bag use handler can simply say something like “This cannot be used here,” or show description text, because the attendant interaction is the true use context.

That is a subtle but powerful design rule: some items are used by selecting them, and some items are used by presenting them to the world.

Let’s take another check for understanding. If the item is consumed only when an NPC accepts it, where should the removal happen? In the NPC or event script path, not in the generic Bag selection path. Otherwise, the player could consume the item in the wrong place, or the item would need global knowledge of all valid recipients.

Now, I want to tie this back to the course’s assessment trajectory. Homework week 17 asked you to trace gameplay from data records through globals, callbacks, tasks, scripts, structs, and concrete source functions. Week 18 is testing whether you can do that across boundaries. A weak answer names one file. A strong answer names the entry point, the state queried, the state mutated, and the continuation path. For today’s topic, that often means item_use.c for selected items, event_data.c for flags and variables, scrcmd.c for script-visible progression, and whatever party or field modules participate in the predicate.

The research packet’s source focus gives us exactly those anchors: pokefirered/src/item_use.c chunk_7e88bbaddbab5bb9 for the core item-use flow; pokefirered/src/item_use.c chunk_8f5c0eba4013eb8a for field item-use continuation; pokefirered/src/item_use.c chunk_ce2671932ba5ff71 for item-use support continuation; pokefirered/src/event_data.c chunk_bff5bbc2efc3008f for event flags and variables; and pokefirered/src/scrcmd.c chunk_7609d397203c8536 for script commands that drive progression flow. Those are the files you should have open during the lab. Not just one of them. All of them, because the behavior crosses them.

Let me do a local recap before we move onward. Item-use dispatch is the selected-item pathway. Scripted unlocks are the world-query pathway. Both can reference item state. Only one begins with the Bag. Flags record persistent history. Variables record compact progression values. Script commands give map logic a controlled way to test and mutate that state. Field moves and key items become interesting because they combine inventory, party, map, and script conditions. The architectural goal is not to make every item powerful. The goal is to put each decision at the surface that naturally owns it.

And that prepares us for the next part of the lecture. We are going to look more closely at how a script-level blocker differs from an item-level failure message. Both may show the player a sentence like “You can’t use that here,” but inside the engine they come from different call paths, different state assumptions, and different recovery behavior. That distinction is what lets FireRed keep the Bag, the overworld, party data, and progression scripts cooperating without collapsing them into one giant conditional.

So, if I draw this as two lanes on the board, the upper lane is “player explicitly uses an item,” and the lower lane is “world script asks whether progress is allowed.” The mistake I want you to avoid is treating those as two ways to write the same if statement. They are not. They have different callers, different ownership, and different promises about what has already happened.

In the upper lane, the Bag or field menu has already decided that the player is trying to use a particular item. That item id is now the center of the call path. In FireRed, you see that very directly in pokefirered/src/item_use.c, especially the item-use flow in chunk_7e88bbaddbab5bb9 and the continuation chunks chunk_8f5c0eba4013eb8a and chunk_ce2671932ba5ff71. The code is organized around globals and callbacks such as gSpecialVar_ItemId, gItemUseCB, sItemUseOnFieldCB, ItemMenu_SetExitCallback, BerryPouch_SetExitCallback, and the task id that represents the live menu interaction. The item is the subject of the sentence. “Can this item do its thing right now?” That is the question.

In the lower lane, the map or script is the subject. The player may not have opened the Bag at all. They may have pressed A on a door, stepped on a trigger, talked to an NPC, or approached an obstacle. The script says, “Given the current story state, inventory state, party state, and map state, what branch should this scene take?” That is where pokefirered/src/scrcmd.c, chunk_7609d397203c8536, becomes important. The script command layer gives you ScrCmd_checkitem, ScrCmd_checkflag, ScrCmd_setflag, ScrCmd_setvar, ScrCmd_compare_var_to_value, ScrCmd_goto_if, ScrCmd_checkpartymove, and the field-effect commands. The object being dispatched is not the item. The object being dispatched is the script program counter.

Let’s use a concrete example. Suppose we are implementing a locked laboratory door that requires a keycard. If the player stands in front of the door and presses A, I would not design that as “force the player to use the keycard from the Bag.” I would put that check in the door script. The script runs something equivalent to checkitem keycard, 1; stores the result in gSpecialVar_Result; compares or branches; and either opens the door or prints the locked-door message. In FireRed’s command layer, that pattern is supported by ScrCmd_checkitem, which reads an item id and quantity through VarGet and writes the boolean answer to gSpecialVar_Result. That is in pokefirered/src/scrcmd.c, chunk_7609d397203c8536. Notice the ownership. The door owns the door rule. The keycard item does not need to know every door in the game.

Now contrast that with Escape Rope. Escape Rope is not primarily a door unlock. The player selects Escape Rope from the Bag and expects the item to act. So the item-use handler owns the check. In pokefirered/src/item_use.c, chunk_8f5c0eba4013eb8a, ItemUseOutOfBattle_EscapeRope calls CanUseEscapeRopeOnCurrMap, and that function asks whether gMapHeader.allowEscaping is true. If yes, it records the quest log event, assigns sItemUseOnFieldCB to ItemUseOnFieldCB_EscapeRope, and routes back through SetUpItemUseOnFieldCallback. If no, it calls PrintNotTheTimeToUseThat. That is an item-level failure message. The map contributes a property, yes, but the item handler owns the decision because the player is using the item.

Pause there and check your understanding. If a cave says “you cannot escape from this map,” where should that condition live? It should live as a map property, gMapHeader.allowEscaping, because that property is about the space. But who asks that property during Escape Rope use? The Escape Rope item handler asks it. If a door says “you need the Secret Key,” who asks that? The door script asks it. Same inventory system, different architectural owner.

This distinction matters for recovery behavior. When a script blocks progress, the script usually remains in control of the dialogue, camera, object lock, and any following branches. The Bag might never open. No item menu callback has to be restored. No pocket cursor needs recalculation. The script can simply show text, set a flag, play a sound, wait for input, and end. But when an item-level failure happens, FireRed must return to the right UI context. Was the item used from the Bag? Was it used while already standing in the field? Was it in the Berry Pouch? Is the right exit callback CB2_BagMenuFromStartMenu, CB2_ReturnToField, CB2_BagMenuFromBattle, or a party-menu transition? That is why item_use.c keeps passing taskId around and checking gTasks[taskId].data[3]. That little task data slot tells the handler which context it is recovering into. It is not glamorous code, but it is exactly the kind of glue that makes a GBA RPG feel coherent.

Let me put a small call trace on the board. Player selects Repel from the Bag. The item id is stored in gSpecialVar_ItemId. The item’s field-use function runs, FieldUseFunc_Repel. That function checks VarGet(VAR_REPEL_STEP_COUNT). If the repel counter is zero, it plays the sound effect, switches the current task to Task_UseRepel, then, after the sound finishes, sets VAR_REPEL_STEP_COUNT using VarSet, consumes one bag item through RemoveUsedItem, and displays the message. If the counter is not zero, it prints the lingering-effect message and returns to the Bag context. That is item-level gating based on a script variable. The variable itself belongs to the event-data layer, but the rule “do not stack Repel while Repel is active” belongs to the Repel item behavior.

That tells us something subtle. Script variables are not only for scripts. Event variables are the compact shared state substrate for the overworld. pokefirered/src/event_data.c, chunk_bff5bbc2efc3008f, shows the storage model: gSaveBlock1Ptr->vars for normal vars, gSaveBlock1Ptr->flags for persistent flags, sSpecialFlags for special runtime flags, and special variables such as gSpecialVar_Result and gSpecialVar_ItemId. VarGet resolves either an actual variable pointer or, if the index is not a variable, treats the value as a literal. FlagSet, FlagClear, and FlagGet operate through bit storage. So when item_use.c reads VAR_REPEL_STEP_COUNT, and when scrcmd.c reads a script operand through VarGet, they are cooperating through the same event-data service.

This is why we spent so much time in earlier weeks tracing data table to callback to visible behavior. We are doing the same thing again, but now the visible behavior is not a battle turn or a menu list. It is a progression affordance. The player sees “Repel’s effect lingered,” or “Oak forbids use of that item here,” or a door opening, or a field move animation. Underneath, one path is a task-driven item handler, another path is a script VM branch, and both are reading the same save-backed state model.

Now, for badge-gated field moves, the ownership gets even more interesting. A field move like Cut or Surf is not just “has HM item.” It typically involves at least four questions. Does the party contain a Pokémon that knows the move? Has the player earned the badge or flag that authorizes overworld use? Is the map tile or object in front of the player compatible with that field move? And once approved, which animation or field effect should run?

FireRed’s script command layer has a direct party query for this: ScrCmd_checkpartymove in pokefirered/src/scrcmd.c, chunk_7609d397203c8536. It loops through the player party, skips empty slots and eggs, calls MonKnowsMove, and then writes either the matching party index to gSpecialVar_Result or PARTY_SIZE if nobody qualifies. It also stores the species in gSpecialVar_0x8004 when it finds a match. That is very different from the item-use dispatch for medicine. A Potion asks the party menu to choose a target and then applies a table-based item effect to that target. A field obstacle script asks, “Is there a party member who can participate in this scripted scene?” Same party data, different caller.

Once the script has decided to proceed, the field effect system can take over. In scrcmd.c, the relevant commands include ScrCmd_dofieldeffect, ScrCmd_setfieldeffectargument, and ScrCmd_waitfieldeffect. The command sets arguments in gFieldEffectArguments, starts a field effect through FieldEffectStart, and can wait until FieldEffectActiveListContains no longer reports the effect as active. The data side is visible in context/pokefirered/data/field_effect_scripts.s, where entries like gFldEffScript_UseCutOnTree, gFldEffScript_UseSurf, gFldEffScript_UseRockSmash, and gFldEffScript_UseStrength connect field effect ids to native calls. I am citing that file here because it helps you see the bridge: script-level progression logic does not need to manually animate every leaf, splash, or boulder. It delegates to field effects.

So, if you are implementing this week’s workshop task, do not make a single function called UseBadgeGatedThing that checks everything. Split the authority. Inventory owns possession and consumption. Party owns creature eligibility. Event flags own progression authorization. The map owns whether the local tile or object is the right kind of target. Field effects own the visible animation. Script commands own the branching sequence that ties those checks into a scene.

Let me test that with a design question. Imagine the player has HM01, has a Pokémon with Cut, but lacks the Cascade Badge, and presses A on a cuttable tree. Should the tree script say “you need a new badge,” or should the HM item say that? In the normal obstacle interaction, the tree script should own that failure because the player interacted with the tree, not the HM item. The script can check the party move and badge flag, branch to the right explanatory text, and never enter the Bag dispatch path. If the player opens the Bag and tries to use the HM item as an item, then the item’s own field-use or TM/HM case path owns that separate behavior. Those are two different verbs from the player’s point of view.

Now compare that to healing. A Potion does not care where you are standing on the map, except for broad context like battle versus field. The item dispatch hands control to the party menu by setting gItemUseCB to ItemUseCB_Medicine and calling the callback setup. That is in pokefirered/src/item_use.c, chunk_7e88bbaddbab5bb9. Then the party menu can choose a monster, and the item effect code can determine whether the target can actually be healed. If it cannot, the failure message is “it won’t have any effect,” because the attempted item-target pair failed. That would be a strange thing for a map script to own. The map does not know or care which party slot the Potion targets.

The Poke Flute gives us a nice hybrid example. FieldUseFunc_PokeFlute loops over the party and applies an Awakening-like table effect to each member. If anybody wakes up, it records the item-use event, plays the fanfare through a task sequence, and displays the “awakened” follow-up message. If nobody wakes up, it prints the catchy tune message. Again, this is item-owned because the player used the Poke Flute. But it reaches into party state because the item’s effect is party-wide. That is the point: ownership is not the same as data locality. An item handler may read party data. A script may read inventory data. What matters is which user-facing action is currently being resolved.

Now I want to connect this back to prior work without re-teaching it. In the battle AI weeks, we looked at script pointer control and party-aware predicates. There, the AI script could ask questions about party slots, statuses, and move consequences, then move its instruction pointer. Here, the overworld script does a comparable thing with progression state. It checks flags, variables, inventory, party moves, and then branches. The mechanisms are not identical, and we should not flatten them into one abstraction, but the architectural pattern should feel familiar: compact state, small query commands, explicit branch control.

And from last week’s Bag lectures, remember that the Bag is a facade over item storage and UI. Today we are looking at what happens after that facade selects an item. The Bag does not contain all item behavior. It sets the stage, stores the selected item id, and invokes the appropriate field or battle use function from the item data record. Then item_use.c and its collaborators decide whether to transition to party UI, return to the field, launch a subtool like the Town Map or TM Case, apply a table-based effect, or print a failure. That is why FireRed can have so many item categories without making the Bag itself an enormous progression engine.

Let’s recap this slice before we move on. Item-level failure means the item-use path is already active. You should expect gSpecialVar_ItemId, task recovery, menu callbacks, and context-sensitive message display. Script-level blocking means the script VM is active. You should expect flags, vars, gSpecialVar_Result, comparison results, goto_if branches, field-effect commands, and scene-local dialogue. Both may consult inventory. Both may consult party state. Both may show similar text. But they are not interchangeable, because each one must return control to a different runtime surface.

For the next part, we will use that distinction to trace a full unlock-style interaction from inventory possession through script branching into field effect execution. We are going to keep the same two-lane picture on the board, but now we will let the lanes cross deliberately: first with a key item that acts as a scripted unlock input, and then with a badge-gated field move where inventory, party, flags, and map metatile checks all have to agree before the player sees the world change.

So, let us deliberately cross the two lanes now. On the board, I am going to draw the item-use lane on the left and the script-progress lane on the right. The left lane begins with the player selecting an item from a menu. The right lane begins with the player interacting with the world: talking to an NPC, pressing A on an object, stepping onto a coordinate, or triggering a map script. The mistake I want you to avoid, especially in your week 18 lab, is treating these as just two skins over the same function call. They both may ask, “Does the player have this thing?” They both may start a field animation. But architecturally, they are different owners of control.

In the item-use lane, the selected item is already the subject. The engine has a concrete item id in `gSpecialVar_ItemId`, and the question is, “What behavior should this item dispatch?” That is why, in `pokefirered/src/item_use.c`, especially the source focus around `chunk_7e88bbaddbab5bb9`, you see the dispatch code lean on item metadata and callback setup: `ItemId_GetType`, `GetPocketByItemId`, `ItemId_GetFieldFunc`, `SetUpItemUseCallback`, and the callback table that maps item type to an exit surface. If the item is a party-targeting item, the exit callback is `CB2_ShowPartyMenuForItemUse`. If the item is a field item, the exit callback is `CB2_ReturnToField`. That is not just a UI convenience. That is the architecture preserving the correct caller. A potion does not directly rewrite the overworld. It needs a party target. A bicycle does not need a party target. It needs the overworld to regain control after a short transition.

Now compare that with the script-progress lane. In the script lane, the selected subject is not an item. The selected subject is the event. The player is standing in front of a door, a tree, a sleeping creature, a guard, a boulder, a badge gate, a machine, whatever the scene has authored. The script may consult inventory, but the inventory is evidence, not the dispatch root. That is why `pokefirered/src/scrcmd.c`, in the week source focus `chunk_7609d397203c8536`, gives us commands like `ScrCmd_checkitem`, `ScrCmd_removeitem`, `ScrCmd_additem`, `ScrCmd_checkflag`, `ScrCmd_setflag`, `ScrCmd_compare_var_to_value`, `ScrCmd_goto_if`, `ScrCmd_checkpartymove`, and `ScrCmd_dofieldeffect`. The script VM is asking questions, storing answers, and choosing branches. It is not saying, “Run the item’s use handler.” It is saying, “Given the world state, which script path should we execute?”

Let us make that concrete. Suppose we implement a locked research door for the lab exercise. The door requires a key item. The wrong mental model is, “The key item opens the door.” That sounds natural in player language, but it is not the best engine sentence. The better engine sentence is, “The door script checks whether the bag contains the key item; if yes, the script opens the door, records progression, and returns control to the overworld.” That wording matters because it tells you where the code belongs. The key item can still exist in the bag. It can still have a description. It may even have a field-use handler that says, “There is no use for that here,” if the player tries to use it from the bag. But the unlocking behavior belongs to the door script, because the door has the coordinates, the scene context, the one-time flag, the metatile or object event to update, and the dialogue branches.

So on the board, I would write a simplified trace like this. Player presses A on the door. The map script runs. The script issues something equivalent to `checkitem ITEM_SECRET_KEY, 1`. In FireRed’s command layer, `ScrCmd_checkitem` reads the item id and quantity through `VarGet`, calls `CheckBagHasItem`, and writes the boolean result into `gSpecialVar_Result`, as shown in `pokefirered/src/scrcmd.c` `chunk_7609d397203c8536`. Then the script compares that result, usually through a compare command or an immediate branch pattern, and `ScrCmd_goto_if` uses the script context’s comparison result to jump or continue. If the item is absent, the script displays locked-door text and releases control. If the item is present, the script might play a sound, call `ScrCmd_removeitem` if the design consumes the key, call `ScrCmd_setflag` to mark the door opened, perhaps call `ScrCmd_setmetatile` or hide an object event, and then release the player.

Notice what carried the answer across the boundary. It was not a C return value travelling all the way back to the bag. It was script state: `gSpecialVar_Result`, `ctx->comparisonResult`, flags, vars, and possibly a permanent map-side consequence. The supporting storage layer is in `pokefirered/src/event_data.c` `chunk_bff5bbc2efc3008f`, where the course packet points us to `gSpecialVar_Result`, the `gSpecialVar_0x8000` family, `VarGet`, `VarSet`, `FlagGet`, `FlagSet`, and `FlagClear`. And that file is worth treating as more than a helper library. It is one of the continuity organs of the whole RPG. When a script says, “This door has been opened,” or “this badge has been earned,” or “this temporary field state is active,” those tiny bit and halfword operations become the player’s remembered world.

Let me pause for a check. If the player selects the key item from the bag while standing nowhere near the door, should the key item scan the map for doors and open one? No. And why not? Because the key item handler does not own the scene. It does not know which door is being addressed, which dialogue should play, which flag represents that particular obstacle, whether this is the first time or a repeat visit, or which map object should disappear. The script owns those facts. The item’s possession is an input to the script, not necessarily the item’s own use effect.

This distinction also explains the feel of items like Escape Rope. Escape Rope is closer to a genuine item-use effect, because when you choose it from the bag, the item itself is the player’s command: “escape this place.” In `pokefirered/src/item_use.c` `chunk_8f5c0eba4013eb8a`, `ItemUseOutOfBattle_EscapeRope` checks `CanUseEscapeRopeOnCurrMap`, and that check reads `gMapHeader.allowEscaping`. If the map allows it, the item-use path records the quest log event, assigns `sItemUseOnFieldCB` to `ItemUseOnFieldCB_EscapeRope`, and goes through `SetUpItemUseOnFieldCallback`. Then the continuation removes the used item, displays the “player used item” message, and ultimately calls `StartEscapeRopeFieldEffect` from `Task_UseDigEscapeRopeOnField`. This is a clean item-use case because the map contributes a permission bit, but the player’s selected item contributes the action.

Now contrast that with a badge-gated field move. This is the second crossing of our lanes. A move like Cut, in the overworld design sense, is not simply “an item effect,” even though HMs live in inventory and moves live on party members. It is a coordination problem. The world object says, “I am a cuttable tree.” The party says, “A non-egg party member knows the required move.” The progression layer says, “The relevant badge or story flag permits overworld use.” The field-effect layer says, “I know how to animate and resolve this environmental change.” And the script or field-special layer has to bring those facts into agreement.

The source focus we have today gives us the script-side pieces very clearly. In `pokefirered/src/scrcmd.c` `chunk_7609d397203c8536`, `ScrCmd_checkpartymove` initializes `gSpecialVar_Result` to `PARTY_SIZE`, then scans `gPlayerParty`. For each real party member, it rejects eggs and calls `MonKnowsMove`. On success, it writes the party index to `gSpecialVar_Result` and also writes the species to `gSpecialVar_0x8004`. That failure sentinel is important. It means the script does not need a complicated data structure to ask, “Who can do this?” It gets either a valid party index or the sentinel value `PARTY_SIZE`, and then it can branch. That is very similar in spirit to the battle AI predicate material from earlier weeks: a command inspects structured runtime state, writes a compact result, and the small VM advances or redirects its instruction pointer. We are not re-teaching AI pointer control today, but I want you to recognize the recurring architectural shape.

Now add the badge. The badge is usually represented as a flag, not as an item. So, in our lab version of a Cut-style obstacle, the script might first check the party move, then check the badge flag, and then check the local obstacle state. `FlagGet` and `FlagSet` in `pokefirered/src/event_data.c` `chunk_bff5bbc2efc3008f` operate over packed flag storage, with ordinary saved flags living in `gSaveBlock1Ptr->flags` and special flags living in a separate special area. That detail tells us something deeper: progression permissions are cheap, global, and persistent. The system wants scripts to ask them constantly. A badge gate is therefore not implemented as “look through the bag for badge item number three.” It is implemented as “does this progression flag say the player has earned the permission?”

Then, when all checks pass, the script can launch visible field behavior. `ScrCmd_dofieldeffect` in `pokefirered/src/scrcmd.c` `chunk_7609d397203c8536` reads an effect id through `VarGet`, stores it in `sFieldEffectScriptId`, and calls `FieldEffectStart`. `ScrCmd_setfieldeffectargument` writes into `gFieldEffectArguments`, and `ScrCmd_waitfieldeffect` sets up a native wait until the active field-effect list no longer contains the effect. That gives us the runtime pattern: script remains the author of sequence, field effect owns animation and low-level presentation, and event data records the durable consequence. If the tree should stay gone, set a flag or update the map’s object state appropriately. If the tree only disappears for this map load, use temporary state. Those choices are design choices, but the architecture gives you separate places to put them.

Here is the concrete example I want you to carry into workshop. Imagine the player faces a cuttable vine. The interaction script starts. First, it checks whether the vine has already been cut by reading a local flag; if already cut, maybe the object is hidden and the script never runs, but let us keep it explicit. Second, it runs `checkpartymove MOVE_CUT`. If `gSpecialVar_Result` equals `PARTY_SIZE`, no eligible party member knows Cut, so the script prints a refusal message. Third, it checks the badge flag. If the move exists but the badge is missing, the script prints a progression message, not a party message. Fourth, if both checks pass, it may buffer the species or nickname of the party member, ask for confirmation, set field-effect arguments for the vine’s position, call `dofieldeffect`, wait for that field effect, set the obstacle-cleared flag, update the metatile or object visibility, and release the player.

Now, why separate the “no move” message from the “no badge” message? Because the architecture makes different blockers legible. If you collapse all failure into “can’t use that now,” you may still have a functional game, but you lose design precision and debugging precision. In a field move gate, the party state and the progression state are independently meaningful. This is exactly the level of sophistication I expect now because your recent homework already asked you to trace gameplay from data records through globals, callbacks, tasks, scripts, structs, and concrete source functions. At this point in the course, a vague answer like “the item checks if it can be used” is not enough. You should be able to say which variable receives the result, which command branches on it, which callback returns to which surface, and which persistent flag makes the change survive.

Let us bring the item-use lane back in for a moment. Medicine items are another useful contrast. In `pokefirered/src/item_use.c` `chunk_ce2671932ba5ff71`, the field-use medicine handlers do not directly heal a hard-coded slot. `FieldUseFunc_Medicine` assigns `gItemUseCB = ItemUseCB_Medicine` and then sets up the item-use callback so the party menu can ask for a target. Ether, PP Up, Rare Candy, evolution stones, and Sacred Ash follow the same broad pattern with different `gItemUseCB` functions. In battle, `BattleUseFunc_Medicine` assigns `gItemUseCB = ItemUseCB_MedicineStep` and enters the party menu from the battle item context. That little difference, `ItemUseCB_Medicine` versus `ItemUseCB_MedicineStep`, carries the difference between field and battle resolution. The same data-driven item effect can be consulted, but the surrounding runtime is different.

This is where the previous two lectures on item data records and the bag facade plug in. The bag gives the player a pocketed list and a selected item. The item data gives type, pocket, hold effect, field function, and battle function. But dispatch is not complete until the engine knows the current surface. Are we in the bag from the start menu? Are we using an item from the field? Are we in battle? Did the item need a party target? Are we closing to `CB2_ReturnToField`, to `CB2_BagMenuFromStartMenu`, to `CB2_BagMenuFromBattle`, or into a field callback that must fade the overworld back in? That is why `SetUpItemUseOnFieldCallback` looks at `gTasks[taskId].data[3]`, why `sItemUseOnFieldCB` exists as a deferred field continuation, and why `FieldCB2_UseItemFromField` freezes object events, locks field controls, fades in, and creates a wait task before unlocking again. Those details in `pokefirered/src/item_use.c` `chunk_8f5c0eba4013eb8a` are small, but they are exactly what prevents the menu, overworld, and script systems from stepping on each other.

Let me ask another check for understanding. If Repel is active and the player tries to use another Repel, is that a script blocker or an item-use blocker? It is an item-use blocker. The player selected Repel from the bag, and the item handler checks the relevant state. In `FieldUseFunc_Repel`, the code reads `VAR_REPEL_STEP_COUNT` with `VarGet`; if it is zero, it plays the sound, later writes the new step count with `VarSet`, removes the item, and displays the used-item text. If the variable is nonzero, it displays the lingering-effect message. That variable lives in the same event-data system scripts use, but the owner of the interaction is still the item handler. Shared state does not imply shared control flow.

And that sentence is probably the most important sentence of today’s lecture: shared state does not imply shared control flow. Inventory, flags, vars, party data, map headers, metatile behavior, object events, field effects, and quest log calls can all appear in the same feature. But you still have to identify who owns the current interaction. The bag owns a selected-item use. The script VM owns an authored map interaction. The battle controller owns an in-battle item use. The party menu owns target selection. The field effect system owns presentation and animation of environmental effects. Save-backed event data owns durable progression memory.

So, to connect this to the larger course plan, week 18 is where our systems stop looking like separate chapters. In week 1, we talked about the runtime shell and main callbacks. In the task lectures, we treated `RunTasks` and task ids as per-frame dispatch. In the map and script weeks, we looked at map headers, object events, flags, vars, and script commands. In battle AI, we studied compact predicate commands that steer a VM-like control flow. In week 17, we put item records, bag pockets, quantities, and bag UI on the table. Today we connected those pieces into a real gameplay path: player input selects or triggers something; data identifies possible behavior; globals and task data hold the current context; callbacks hand control to the next surface; scripts branch on flags, vars, inventory, and party state; field effects produce world-visible change; and event data remembers what changed.

For your lab, I want your potion, Escape Rope, key item, and badge-gated field move to show four distinct ownership patterns. The potion should prove you understand item-to-party targeting. Escape Rope should prove you understand item-to-field continuation and map permission. The key item should prove you understand inventory as a script unlock input, not merely a bag-use command. The badge-gated field move should prove you can combine inventory history, party move state, badge flags, map or metatile context, and field-effect execution without pretending they are all the same subsystem.

We will stop there for today. The synthesis is this: FireRed’s item effects are not implemented by one giant “use item” idea. They are implemented by dispatch across cooperating state machines. The elegance is in the handoff. Item data chooses a handler. The bag or berry pouch exits through the right callback. Party-targeted effects install `gItemUseCB`. Field items defer through `sItemUseOnFieldCB`, `gFieldCallback`, and sometimes `gFieldCallback2`. Scripts use `gSpecialVar_Result`, flags, vars, comparisons, and branches to turn inventory and party state into authored progression. Once you can trace those handoffs precisely, you are no longer just reading decompiled C. You are reading the architecture of a creature RPG as a set of contracts between systems, and that is the level we need for the rest of week 18 and for the final systems work in week 19.

## Source References
- pokefirered/src/battle_util.c
- pokefirered/src/daycare.c
- pokefirered/src/battle_setup.c
- pokefirered/src/pokemon_summary_screen.c
- pokefirered/src/learn_move.c
- pokemon-showdown/data/mods/gen9ssb/moves.ts
