# Items as Scripted Unlock Inputs

Lecture ID: lecture_w18_d02
Week 18, Day 2

## Objectives
- Design minimal clone versions of map loading, script execution, party data, battle turns, item use, and save persistence.
- Connect week 18 material to the overall course plan.

## Transcript
All right, let’s pick up exactly where yesterday’s lecture left us. We are no longer asking, “What is an item?” We already handled that. We are also not going to re-open the bag UI as though the bag itself were the architecture. The bag is the interface facade. The item record is the data. The item-use dispatch path is the bridge from data to behavior. Today we care about the next step: when an item becomes an input into the world’s progression logic.

Put that sentence in your head very precisely. An item is not only something the player consumes. It can be a key that changes which script branch is legal. It can be a proof that a previous condition was satisfied. It can be a portable permission token. And in a creature RPG, that permission token often does not act alone. It combines with party state, map state, event flags, event variables, badges, and current runtime context.

So if I use a Potion, the result is mostly local. We inspect the party, choose a target, change hit points, maybe play a fanfare, then return to the previous menu or field state. If I use an Escape Rope, the item is still in the bag, yes, but the actual effect is a map and overworld transition. If I use a key item near a locked door, the item may not “do” anything by itself. The nearby script asks, “Does the player have this thing?” and then the script decides whether to unlock the door, show refusal text, set a flag, move an object, warp the player, or leave everything unchanged.

That distinction is the spine of today’s lecture. Items can execute behavior directly, and items can also become scripted unlock inputs. FireRed uses both patterns, and the interesting architecture lives in the boundary between them.

Let me point to the source packet so we have a concrete anchor. The source focus for this week puts item-use flow in pokefirered/src/item_use.c, especially chunk_7e88bbaddbab5bb9, then the field item-use continuation in chunk_8f5c0eba4013eb8a, and the support continuation in chunk_ce2671932ba5ff71. Those chunks are where we should mentally place the item-use side of the interaction. Then, for the progression side, the packet identifies pokefirered/src/event_data.c chunk_bff5bbc2efc3008f for event flags and variables support, and pokefirered/src/scrcmd.c chunk_7609d397203c8536 for script commands that implement progression flow. So the architecture is not “item code does everything.” It is “item code, event data, and script commands cooperate.”

Now, board cue here: I’m drawing three boxes. The first box says inventory state. The second says runtime use handler. The third says event script state. Under inventory state, I’m writing item id and quantity. Under runtime use handler, I’m writing context: field, battle, party menu, registered key item. Under event script state, I’m writing flags, vars, map objects, warps, and message branches.

The mistake many clone implementations make is to collapse those three boxes into one giant if statement. You’ll see beginner code like, “if item equals CardKey, open door.” That works for one door in one room. It does not scale to a game. It also destroys the reason the original architecture separates inventory, item-use behavior, and script progression. The card key is inventory state. The door opening is map script behavior. The fact that a specific door has already opened is event state. Those are different lifetimes and different owners.

Let’s make this advanced, because by week 18 you have already been assessed on decomposing the full RPG into map loading, script execution, party data, battle turns, item use, and save persistence. The question is not whether you can name those systems. The question is whether your minimal clone can keep the ownership boundaries clean while still feeling like one coherent game.

Suppose we are building a small FireRed-style clone. We want four use cases for this week’s lab: Potion, Escape Rope, a key item, and a badge-gated field move. Let’s reason through each one in terms of ownership.

Potion is item-use plus party data. It begins from the bag or battle item menu, dispatches to a healing handler, asks the party system for a valid target, mutates a creature’s HP, consumes quantity if appropriate, and reports a result. It may be legal in the field and in battle, but the presentation and turn consequences differ. In battle, using an item usually consumes the trainer’s turn. In the field, it resumes overworld control or menu control. So the clone needs to distinguish effect semantics from context semantics.

Escape Rope is item-use plus map loading. The item handler does not merely decrement a quantity and print text. It needs to ask whether the current map permits escape behavior. If permitted, it requests a warp destination, transitions through field effects, and loads a new map. FireRed’s broader source packet reminds us that battle and overworld transitions often include event and map dependencies; for example, pokefirered/src/battle_setup.c chunk_494d132a59422c85 includes dependencies like overworld, item, load_save, script, event_data, field effects, and battle transition headers. That kind of include cluster is not random. It reflects a real architectural fact: player-visible actions frequently cross module boundaries, but they should cross them through controlled interfaces.

A key item is item-use plus script state, but sometimes indirectly. Some key items can be used from the bag, like a bicycle or rod. Others are not “used” from the bag at all in the ordinary sense; they are checked by map scripts. The player talks to an NPC, examines a door, steps on a tile, or triggers an object event. The script runs. The script checks flags, variables, inventory, and maybe party state. Then the script decides what happens. So, in the clone, the key item should not need to know every door it unlocks. The door script should know what condition it requires.

Badge-gated field move is the most interesting because it combines party data, item-like unlocks, and event flags. In classic terms, the move exists on a party member, but the permission to use it in the field may depend on a badge flag or story variable. That means the field action checks the party for capability, checks event state for authorization, checks the current tile or map for applicability, then invokes a field effect or script. So this is not “the move object does everything.” It is a coordinated unlock check.

Check for understanding before we go deeper. If I say, “The player has the key, therefore the door should be open,” what have I skipped? I’ve skipped event state. The player having the key is a condition. The door being open is persistent world state. Those may be related, but they are not identical. A locked door can remain closed until the player interacts with it. Once opened, it might set a flag so it remains open even if the key is later removed. Or the game might keep checking the item every time. Those are design choices, but your architecture should make the distinction available.

Now let’s connect this to FireRed’s script system. We have already seen, in earlier weeks, that the overworld is not simply hard-coded C movement. Maps load headers, layouts, object events, and scripts. Event scripts then act as a small progression language. Today, the important source anchor is pokefirered/src/scrcmd.c chunk_7609d397203c8536. The exact commands in that region are less important for us right now than the architectural role: script commands are the sanctioned way for map and story logic to inspect and mutate progression state. They sit between raw engine systems and authored content.

Event flags and variables, meanwhile, live behind event data support, identified in pokefirered/src/event_data.c chunk_bff5bbc2efc3008f. That matters because flags and variables are not just ordinary temporary locals. They are part of the game’s progression memory. Some of them persist into the save file. Some drive object visibility. Some gate dialogue. Some represent story milestones. The item system should not casually duplicate that state.

Let’s use a concrete example. Imagine we have a “Research Pass” key item that allows entry into a restricted lab. In a naive implementation, the item use handler says, “If current map is LabDoorMap and player faces lab door, open it.” That couples item code to map geometry, object behavior, text, and door state. It will work for one demo and then become a maintenance problem.

A cleaner minimal clone design says: inventory stores Research Pass. The door object has an interaction script. The script calls something like checkitem Research Pass. If false, it displays “Authorized staff only.” If true, it checks flag LabDoorUnlocked. If the flag is already set, it opens or allows passage immediately. If the flag is not set, it plays an unlock message, sets LabDoorUnlocked, changes the door metatile or object state, and then continues. The key item is not the door. The key item is a scripted unlock input.

Notice what this gives us. First, the same item can unlock multiple scripts without expanding the item handler. Second, the same script can combine item checks with badges, variables, party checks, or quest state. Third, save persistence becomes straightforward: the inventory persists that the player owns the pass, and event flags persist that specific world transitions have happened. Those are separate save concerns.

Now, on the board, I’m adding a fourth box below the first three. This one says save persistence. I’m drawing arrows from inventory state to save, and from event flags and variables to save. I am not drawing an arrow from “current use handler stack” to save. That is deliberate. The handler is runtime control flow. It should finish and leave durable facts behind in durable state. If the player saves after unlocking the lab door, we need to save the flag or the map object state derived from it. We do not save “currently inside item use callback number four.” That callback is transient.

There are exceptions in real engines where you save mid-script or preserve special task state, but for our minimal clone, avoid that complexity. Persist stable game facts, not temporary control flow.

This is also where the callback and task material from early in the course comes back, but only briefly. We do not need to re-teach SetMainCallback2 or RunTasks. You already know the runtime shell. Today, remember that item use often moves through callbacks and tasks because it involves menus, fades, party selection, text boxes, and field transitions. In FireRed, this is why item_use.c is not merely a table of pure functions. The chunks identified for this week, pokefirered/src/item_use.c chunk_7e88bbaddbab5bb9, chunk_8f5c0eba4013eb8a, and chunk_ce2671932ba5ff71, belong to an engine where item effects may need staged continuation. A use handler may begin an operation now and finish it after the player chooses a party member, after a message closes, or after the overworld resumes.

For your clone, the equivalent might be a small state machine. You do not need to recreate every FireRed callback exactly. But you do need to represent the same truth: item use is not always instantaneous. Potion use may require target selection. Escape Rope may require fade out, map load, and fade in. A registered key item may hand control to field logic. A badge-gated field move may open the party menu, validate the selected creature, run a confirmation prompt, then start a field effect.

Let’s pause for a check. If your item use API is “useItem(itemId) returns boolean,” what problem are you going to hit? You are going to hit asynchronous or multi-step behavior. A boolean is too small to describe “opened party selection,” “waiting for text,” “started warp,” “failed because map forbids it,” “failed because no valid target,” or “succeeded and consumed a battle turn.” For a trivial toy, boolean is fine. For the architecture we are studying, you want a richer result or a staged state machine.

In a minimal advanced clone, I would accept an API where the item handler returns a result object. Not a bloated one. Something like: outcome type, consumed item or not, consumed battle turn or not, next UI state, optional script to run, optional field transition request. The important point is that item use should declare what kind of continuation it needs rather than directly owning all possible systems.

Let me make that less abstract. Potion in field returns “open party target selection,” then after target selection returns “heal creature and consume item,” then returns “show message and resume bag.” Potion in battle returns “open party target selection,” then “heal creature, consume item, mark trainer action used, return to battle turn executor.” Escape Rope returns “request field escape transition,” and the field system handles map load. Research Pass, if used from the bag, might return “no direct use here,” because its main behavior is script-checked. The lab door script, however, calls inventory checks and event flag commands.

Now we need to connect this to script variables as blockers. A flag is usually binary: defeated boss, received badge, door opened, event completed. A variable is useful when progression has more than two states: quest stage, puzzle counter, chosen fossil, current gym puzzle status, number of switches pressed, active rival encounter stage. In FireRed’s architecture, event_data.c is the home for this kind of event state support, and the source packet specifically calls out pokefirered/src/event_data.c chunk_bff5bbc2efc3008f. When script commands in scrcmd.c operate on that state, they allow authored content to block or branch without rewriting core engine code.

Here is a board example. I’m writing:

QuestVar_LabAccess = 0 means not started.
QuestVar_LabAccess = 1 means talked to scientist.
QuestVar_LabAccess = 2 means received Research Pass.
Flag_LabDoorUnlocked means the lab door has been opened.

Now, inventory may also contain Item_ResearchPass. So why have both QuestVar_LabAccess and the item? Because they answer different questions. The item answers, “Does the player currently possess the credential?” The variable answers, “Where is the player in the authored quest?” The flag answers, “Has this world object changed state?” You could compress them, but compression creates ambiguity. Advanced architecture is often about refusing false simplicity.

Suppose the player gets the Research Pass, unlocks the lab door, and then an NPC takes the pass away later. Should the lab door relock? Maybe yes, maybe no. If the door script only checks inventory every time, it relocks automatically. If the script sets Flag_LabDoorUnlocked, then the door remains unlocked. That is not an implementation detail. That is game design expressed through state ownership. Your engine should make both designs possible.

Now, let’s include battle turns because the objective for this course segment asks us to design minimal clone versions of battle turns as well. Field unlock items and battle-use items share the item record and inventory store, but they differ in turn economy. In a battle, using a Potion is not just healing. It is an action selected by a battler controller that participates in turn resolution. We are not re-teaching the battle AI script pointer control from the prior comparison lectures, but remember the principle: battle systems often run through controlled command flow rather than arbitrary direct calls. In FireRed, battle-related modules include item and event dependencies in several places. The research packet’s pokefirered/src/battle_util.c chunk_9335e5727aa0657d shows battle utility code including item.h, event_data.h, battle scripts, battle controllers, constants for items, moves, abilities, and hold effects. That include neighborhood supports a claim we have made repeatedly: battle behavior is a coordinated engine domain, not a single isolated function.

So for a clone, do not let field item logic accidentally consume a battle turn, and do not let battle item logic accidentally run overworld scripts. You can share effect primitives. Heal creature by amount is shared. Remove status is shared. Check item quantity is shared. But “how do we return control?” and “what economy did this action consume?” are context-specific.

Let’s do a quick verbal trace of a badge-gated field move, because this is the example where students usually blur the boundaries. The player is standing near water and presses A, or chooses Surf from a party member. The field system identifies an applicable tile or interaction. The party system answers whether any creature knows the required move. The event state answers whether the required badge or authorization flag is set. The script or field effect system displays the appropriate message. If approved, the movement mode changes, the player avatar enters surfing state, and the map continues running.

Where is the item? In FireRed-style design, the HM itself can be an item that teaches the move, while the field use of the move is gated by badge/event state and party knowledge. So the item participates earlier as acquisition and learning input. The unlock later is not “the HM item did Surf.” The party member’s move plus badge flag plus map tile did Surf. This is exactly why week 18 sits after our party, battle, and inventory modules. The item system alone cannot explain the behavior.

Now I want to zoom out to the course plan. Weeks 17 through 19 are about Items, Menus, and Party UI, but that label is almost misleadingly modest. These systems are where the player’s choices touch the rest of the engine. A bag menu is not just a list. It is a launch surface for party mutation, battle turn actions, field transitions, script unlocks, and persistent progression. So week 18 is a hinge week. We are connecting the data-driven item records and bag quantities from earlier lectures to the overworld scripting and save-state architecture from earlier modules.

By the time we finish this week, your minimal clone should not merely have an inventory array. It should have item-use dispatch that can route by context, party data that can be inspected and mutated safely, a script system that can check flags, variables, and inventory, a map loader that can respond to field transition requests, a battle turn executor that can incorporate item actions, and save persistence that stores durable consequences. That sounds like a lot, but the key is that each part can be minimal. Minimal does not mean tangled. Minimal means the smallest version that preserves the correct boundaries.

Let me give you a deliberately small architecture. Inventory is a map from item id to quantity, plus maybe key item possession for non-consumables. Party is an array of creatures with HP, status, moves, and species. Event state is two stores: flags and variables. Map state has current map id, player position, object states derived from flags, and available scripts. Battle state has battlers, turn queue, selected actions, and a result processor. Item definitions include use categories and handler references. Scripts can call engine commands like check item, set flag, compare variable, give item, take item, warp, message, and start battle.

That is enough. You do not need the full GBA engine. But you do need the direction of dependency to be sane. Scripts may ask inventory questions. Item handlers may request scripts or field transitions. Save code serializes inventory, party, event state, current map, and major battle state only if your design permits saving in battle. Map loading reads map definitions and applies event state. Battle turns read item actions and party state. Those are the connections.

Another check for understanding: in this clone, where should the code live for “Oak’s Parcel lets the Viridian Mart script advance after delivery”? It should not live in the generic item handler for Oak’s Parcel. The item can be defined as a key item or regular item. But the Mart clerk or Professor Oak script should check possession or quest variables and then set progression flags, remove the item if needed, and give the next reward. That is scripted progression. The item is an input.

If you’re wondering, “But doesn’t that make scripts too powerful?” yes, scripts are powerful by design. The safeguard is not to make scripts weak. The safeguard is to make script commands narrow and explicit. A script should not poke arbitrary memory. It should call commands exposed by the engine: check item, give item, set flag, compare variable, warp, lock player, release player, apply movement, start battle. FireRed’s script command source, pokefirered/src/scrcmd.c chunk_7609d397203c8536, is important in exactly this sense. Script command implementations are the controlled bridge from authored event flow into engine state.

So, as we continue, keep this mental model: item-use code answers, “What happens when the player actively uses this item in this context?” Script progression answers, “What world behavior is unlocked when state conditions are satisfied?” Inventory state can feed both, but it should not swallow both. That is the difference between a prototype that works for one demo and an architecture that can carry a whole creature RPG.

In the next portion, we will walk through a full trace from pressing A on a locked door, through script command evaluation, through inventory and flag checks, into map object mutation and save persistence. Then we’ll mirror that with a battle item trace so you can see exactly where the two flows share primitives and where they must diverge.

So let’s run that door trace carefully, because it is where a lot of otherwise clean student clone designs start to blur boundaries.

The player presses A facing a locked door. In a minimal creature RPG, you might be tempted to say, “The door checks whether the player has the key item.” That sentence is fine as a user-facing description, but architecturally it is too compressed. The door does not need to become an inventory system. The inventory does not need to become a map system. The clean version is: the field input system detects interaction, the map object or tile provides a script pointer, the script interpreter evaluates conditions, and one of those conditions may query inventory state or event flags.

I’m going to put that on the board as a trace, not as code yet. Player input, facing tile, script lookup, condition checks, side effects, persistence. Now, beside condition checks, write three possible sources: variable, flag, inventory. Those are not interchangeable, but they are often combined. A variable can say, “Which phase of this dungeon are we in?” A flag can say, “Has this door already been unlocked?” Inventory can say, “Does the player currently possess the Secret Key?” The unlock behavior is usually not just inventory. If it were only inventory, then every time the player approached the door, the engine would repeat the same unlock ceremony. The stronger pattern is: inventory authorizes the transition, and a flag records that the transition has occurred.

This is exactly why the week 18 source focus includes event_data and scrcmd, not only item_use. In pokefirered/src/event_data.c, chunk_bff5bbc2efc3008f, the important architectural idea is that flags and variables are central world-state primitives. They are not incidental script helpers. Then in pokefirered/src/scrcmd.c, chunk_7609d397203c8536, the script command layer gives authored event flow a controlled way to read and mutate that state. So when we say items are scripted unlock inputs, we are not saying every unlock lives in item code. We are saying inventory can participate in script command decisions, alongside flags, variables, party checks, and map state.

Let’s make the concrete example a little richer. Suppose we have a locked power plant gate. The player needs an item called ITEM_PLANT_PASS. Before the player obtains the pass, pressing A on the gate displays, “The security gate is sealed.” After the player obtains the pass, pressing A displays, “The Plant Pass activated the gate,” plays a sound, changes the gate metatile or object state, sets FLAG_POWER_PLANT_GATE_OPEN, and then allows passage permanently. Notice the permanent part. If the player later deposits or loses the pass, depending on your game design, the gate may still remain open because the flag is the canonical record of the world transition. The item was the unlock input; the flag is the world result.

Now, check your understanding here. If the item is consumed, where should that consumption happen? Not inside the map renderer. Not inside the save serializer. It should happen as a deliberate script or item-use side effect at the moment the unlock is accepted. If the item is not consumed, then the inventory query is read-only, and the flag still records the unlock. Either way, the map loading code should later ask, “What version of this map should I instantiate given saved flags and variables?” It should not re-run the full dramatic unlocking script just because the map loads.

That separation also helps us design the minimal clone you are building for this week. Your clone does not need FireRed’s full scripting language. It does need the same shape of responsibility. A map loader can read a map definition with objects and scripts. A script executor can run a small instruction set: message, check flag, set flag, check item, remove item, set tile, warp, maybe start battle. Party data can answer questions about current monsters, HP, status, and known field moves. Battle turns can run their own command loop. Item use can dispatch to handlers. Save persistence can serialize the durable state: inventory, party, map position, flags, variables, and any persistent object mutations that are not derived from flags.

Let’s compare two designs. Design A says: the door object has a Python or C function called onInteract, and inside that function it directly loops over the bag, edits the map tile array, writes to the save file, and maybe starts a fade transition. That can be made to work. But it is a tangled design, because testing the door now requires the bag implementation, the map renderer, the save writer, and the transition system all at once. Design B says: the door points to a script. The script command executor knows how to ask inventory, set flags, queue map mutations, and return control to the overworld loop. The save system later persists the flags. In a clone, Design B is more code at first, but it is less code once you have ten doors, three badges, two key items, and a field move.

And this is where yesterday’s item-use dispatch lecture plugs in. In pokefirered/src/item_use.c, chunk_7e88bbaddbab5bb9, the source focus is the item-use flow: item selection is routed into behavior through structured dispatch rather than every item being a one-off menu branch. The continuation chunks, pokefirered/src/item_use.c chunk_8f5c0eba4013eb8a and chunk_ce2671932ba5ff71, matter because field usage needs continuation state. You do not always press Use and immediately finish. You may open the party menu, select a creature, validate a move, run a field effect, return to overworld, or display a failure message. So even on the item side, the engine is not a flat “call function and done” structure. It is a controlled interaction between UI, task/callback flow, field state, and scripts.

Now let’s mirror that against the locked door. In the locked door case, the player’s primary action is not “use item from bag.” It is “interact with world.” The item is consulted by the script. In the bag case, the player’s primary action is “use item.” The world, battle, or party state may be consulted by the item handler. Same primitives, inverted ownership.

Let me say that again because it is a clean exam answer. For a scripted unlock, script owns the interaction and inventory is a predicate. For direct item use, item dispatch owns the interaction and script or field state may be a continuation target. If you mix those up, you get strange designs where every key item needs hard-coded knowledge of every door, or every door needs hard-coded knowledge of the entire bag menu.

Now, let’s put a tiny pseudo-script on the board, in speech rather than syntax. First command: if FLAG_POWER_PLANT_GATE_OPEN, jump to already-open behavior. Second command: if player lacks ITEM_PLANT_PASS, show locked message and end. Third command: show activation message. Fourth: set FLAG_POWER_PLANT_GATE_OPEN. Fifth: set gate tile to open, or hide gate object. Sixth: maybe play sound. Seventh: end. That is the whole unlock. Notice the order. We check the permanent flag first because once the gate is open, we do not care whether the item is still present. We check inventory only before the state transition. Then we record the transition before or at the same time as visual mutation.

A subtle point: should the script set the tile directly, or should it only set the flag and let a map refresh routine derive the tile from the flag? In a full engine, you often do both in different contexts. During the live interaction, the player needs immediate feedback, so the script may directly mutate the current map representation. On future map loads, the map loader or object event initialization applies the saved flag so the map appears open from the start. That is not duplication if one path is the live transition and the other path is reconstruction from persistent state.

This connects back to map loading from earlier in the course. We studied map headers, layout registry references, and object events because the map is not just a picture. It is a data-driven staging area for scripts, collision, warps, objects, and conditional behavior. In your minimal clone, do not make the map loader merely parse tiles. Have it instantiate interactables with script IDs and have it apply saved flags before control returns to the player. That one design choice makes item-gated progression feel like part of the world instead of a menu trick.

Let’s do a quick comprehension check. Imagine the player uses a key item from the bag while standing anywhere in the world. The item handler says, “This item does nothing here.” Is that a failure of the item system or the script system? It depends on the design. If the key item is meant to be used directly, like a detector or flute, then the item handler must evaluate context. If the key item is meant to open a door only when interacting with that door, then using it from the bag may correctly do nothing, because the door script is the owner of that unlock. The advanced move is not to force all key items into one use model. The advanced move is to classify the ownership of the interaction.

Now let’s bring battle into the comparison, because the divergence matters. A Potion in battle is also an item, and it also consults party state. But it is not a map unlock. The battle engine has its own turn state, battler controllers, command buffers, and message flow. When you choose Potion, the item-use path must validate that the item is battle-legal, choose a target, modify HP, consume the item, and then return control to battle turn progression. The durable persistence is delayed or indirect: after battle, the party HP and inventory quantities remain changed, but the battle scene itself is transient.

The research packet points us toward pokefirered/src/battle_util.c, chunk_9335e5727aa0657d, as an example of battle code depending on item, event data, move constants, abilities, and battle scripts in one ecosystem. That does not mean battle items should be implemented by overworld scripts. It means the battle engine has its own script-like and state-machine-like mechanisms. Similarly, pokefirered/src/battle_setup.c, chunk_494d132a59422c85, is useful because it sits near the boundary between overworld event conditions and entering battle. It includes references around overworld, item, script, event_data, field effects, and battle transition concerns. That is the architectural neighborhood where world state and battle state meet, but they do not collapse into one giant mode.

For your clone, model that as two dispatch surfaces. Field item use and battle item use may share item data records and inventory quantities, but they should not share the entire execution path. A Potion’s data record may say it restores 20 HP. The field handler may open the party menu and apply it outside battle. The battle handler may spend the player’s action and apply it inside the turn system. Same item, same healing primitive, different control context.

Let’s return to the gate and add a badge-gated field move, because that is the lab case where inventory, party, and flags intersect. Suppose the player faces a cracked boulder. The boulder script checks whether the player has the Smash Badge flag, and whether some party creature knows Rock Smash, and perhaps whether the map allows that field move. The item equivalent might be a key item hammer, but the Pokémon-like version uses party state as an unlock input. The same architectural pattern applies. The boulder script should not become a complete party menu. It should ask a party predicate: “Does any eligible party member know the required move?” It should ask an event predicate: “Has the badge flag been set?” Then it triggers a field effect and removes or hides the boulder.

This is why earlier course material on party-aware predicates and status checks was not just battle AI trivia. We are reusing the idea, not re-teaching it. A party is not only battle roster data. It is also progression capability data. In your clone, party data should expose narrow queries: hasMove, hasUsableFieldMove, firstEligibleCreature, canReceiveHealing, hasConsciousMember. Do not let scripts inspect raw party arrays unless your script VM is explicitly designed for that. A small predicate API gives designers expressive unlocks without coupling scripts to storage layout.

Now I want to pause on save persistence, because this is the part students underbuild. A save file should not just preserve the player’s bag. If the Plant Pass opened the gate, saving and loading should preserve the opened gate. The strongest way is to persist the flag, not the current tile mutation. On load, the map applies flag-conditioned object visibility or metatile changes. This gives you a recoverable model. If a future patch changes the map layout, the saved flag still means “gate open,” and the loader can apply the new representation. If instead you serialize arbitrary tile edits, you have made saves fragile against map revisions.

There are exceptions. Some games persist dynamic tile edits, temporary puzzle state, or object positions. But for progression unlocks, flags and variables are usually the right durable abstraction. Variables are useful when the state has multiple phases. A gate is closed or open, so a flag works. A machine might be off, missing fuse, powered, overloaded, and repaired; that wants a variable or enum-like progression value. In FireRed terms, event flags and vars form that backbone, which is why pokefirered/src/event_data.c chunk_bff5bbc2efc3008f is part of today’s source focus rather than a side reference.

Let’s do another check for understanding. If the player uses Escape Rope in a cave, what must be persisted immediately? The item quantity changes, the player’s new map position eventually changes, and maybe some script variable related to the escape sequence does not need to persist at all. The animation task, fade state, and temporary warp command should not be treated as permanent save data. You persist durable facts, not every transient control step. That distinction separates save architecture from “dump all globals to disk,” which is tempting in a clone but painful once you add versioning.

Now, for the minimal implementation, I would sketch the data structures like this in your mind. MapDefinition has tiles, objects, warps, and script references. RuntimeMap is the loaded, mutable current map. ScriptState has instruction pointer, temporary result registers, and maybe a wait mode. GameState has flags, variables, inventory, party, and location. ItemRegistry maps item IDs to data and handler IDs. ItemUseContext says whether we are in field, battle, party menu, or script. BattleState has battlers, turn queue, pending action, and its own messages. SaveData is a serializable subset of GameState, not the whole engine.

Do you see how the week 18 material plugs into the overall course plan? In weeks 1 and 2, we cared about runtime shell, callbacks, generated data, headers, and data-to-behavior tracing. In the map weeks, we cared about authored world data and object events. In the scripting weeks, we cared about variables, flags, and command execution. In the party and battle weeks, we cared about party data as both combat state and queryable capability. Now, with items, we are tying those strands together. An item is not just a row in a table. It is a possible input into field scripts, battle turns, party mutation, menu continuation, and save-visible progression.

And to be clear, this is why a technically serious FireRed-inspired architecture is more than “make a bag and make items do things.” The bag is a UI facade over inventory state. We covered that. Item data records describe properties. We covered that. Dispatching item effects connects records to handlers. We covered that yesterday. Today’s increment is the world-state integration: how inventory and item use participate in authored progression without stealing responsibility from scripts, maps, party predicates, battle state, or persistence.

Let me give you a failure case because these are memorable. Suppose a student implements Cut as an item handler attached to HM01. When used from the bag, it searches adjacent map tiles for cuttable trees and removes one if present. That seems okay for one tree. But now suppose an NPC script says, “You may pass only if you can cut this tree,” and a badge flag is required, and the tree should stay gone after save/load. If the HM item handler owns all of that, then interacting with the tree, using the move from the party menu, and loading the map after the tree is gone all need to call into item code. The better model is that the tree’s script owns the tree interaction, party data proves a creature can use Cut, badge flags authorize it, a field effect animates it, and a flag records that this specific tree or blockage is removed if it is meant to be permanent. The HM item data may still exist, but it is not the universal owner of every cuttable tree.

Now, if you are thinking, “But FireRed often has special cases,” yes, absolutely. Production game code has special cases because games are made under constraints, and because the GBA engine has particular callback and task machinery. We are not pretending every behavior is pristine. But the source organization still shows the recurring boundaries. Item use flow in pokefirered/src/item_use.c, chunks chunk_7e88bbaddbab5bb9, chunk_8f5c0eba4013eb8a, and chunk_ce2671932ba5ff71, belongs near item dispatch and continuation. Event flags and variables in pokefirered/src/event_data.c chunk_bff5bbc2efc3008f belong near durable progression state. Script commands in pokefirered/src/scrcmd.c chunk_7609d397203c8536 belong near authored control flow. Those are the boundaries to imitate in a clone even if your code is much smaller.

Let’s close this segment with a small synthesis, not the end of the lecture, just the checkpoint before we go deeper. There are three questions you should ask for every item-related unlock. First, who owns the player action: the item menu, the world script, the party menu, or the battle turn? Second, what state authorizes the behavior: inventory, flag, variable, party predicate, battle condition, or some combination? Third, what state persists afterward: item quantity, flag, variable, party mutation, location, or nothing durable? If you can answer those three, your implementation will usually land in the right module.

After the break in the trace, we are going to turn this into a minimal clone control flow. We will write it as if we were designing the engine interfaces: a map interaction calls a script executor, the script executor calls inventory and event-state predicates, a successful unlock queues a field mutation, and the save system reconstructs that result later from flags. Then we will put the battle item trace beside it and look at exactly where the shared item registry stops being enough.

All right, let’s make that trace concrete. Imagine I am drawing four boxes across the board from left to right. The first box says player action. The second says script or item dispatcher. The third says domain state. The fourth says persisted consequence. That is the shape I want you to keep in mind, because it prevents a very common advanced-student mistake: treating the item as the owner of the entire interaction.

The item is not always the owner. Sometimes the item is merely evidence. Sometimes it is a trigger. Sometimes it is a consumable resource. Sometimes it is a menu command that opens a different state machine. Sometimes it is a battle input that must wait for the battle controller to accept it. And sometimes, especially with progression unlocks, the item is almost passive. The world script asks, “Does the player possess this thing?” and then the world script decides what changes.

So, if we were designing the minimal clone now, I would not begin with a giant “use item” function. I would begin with contexts. Field context, battle context, party-menu context, and script-check context. Then I would ask which context has authority to mutate what. In FireRed, the separation is visible if you look at the item-use flow in pokefirered/src/item_use.c, especially the source-focus chunk chunk_7e88bbaddbab5bb9. That area is useful because it shows item use as flow control, not just as data lookup. Then the continuation in pokefirered/src/item_use.c chunk_8f5c0eba4013eb8a helps us see that field item use often continues through callbacks and stateful UI transitions. And chunk_ce2671932ba5ff71, also in pokefirered/src/item_use.c, is one of the places to keep in mind when you are tracing support logic around those effects.

Now, notice the phrase I just used: “flow control.” Not “item effect.” If I say “item effect,” you may imagine one nice pure function: item in, state out. That is attractive. It is also too small for this engine style. A potion needs party targeting, HP validation, animation or messaging, quantity consumption, and a return path to the bag or party menu. An Escape Rope needs map eligibility, warp destination logic, maybe a fade transition, and then durable location state once the save file is written. A key item may need no consumption at all. A badge-gated field move may not even be an item in the bag; it may combine badge flags, party move predicates, map behavior, and script variables.

Let’s take the lab version, because this is exactly what your week 18 work is preparing you to implement. Suppose our clone has a locked cave door. The door opens only if the player has the “Ancient Gear” key item. The obvious beginner implementation is: when the player selects Ancient Gear from the bag, check whether the player is near the door, and if yes, open it. That works for a toy, but it gives the wrong architecture for a FireRed-style game. The better implementation is: the map object, when interacted with, starts a script. The script says, “Check inventory for Ancient Gear.” If present, set a flag, play the door animation, change the blocked metatile or object visibility, and continue. If absent, show text and return. In this model, the item unlocks the script branch, but the map script owns the world mutation.

Why is that distinction important? Because persistence becomes simple. The save file does not need to remember that the player once used Ancient Gear at coordinate 12, 8 on map 37. It needs to remember that event flag CAVE_DOOR_OPEN is true. Then, when map loading reconstructs objects and metatiles, that flag can suppress the closed door or choose the open layout. This is exactly the kind of design you should associate with FireRed’s event flag and variable support in pokefirered/src/event_data.c chunk_bff5bbc2efc3008f. The flags and variables are not decoration around the script system. They are the compact durable memory of world progression.

Let me pause there and check understanding. If the player has the Ancient Gear, opens the door, saves, powers off, and reloads, what state should be trusted to restore the door? Not the item-use animation. Not the previous script call stack. Not the bag cursor. The event flag. The flag is the durable result. The item was the input evidence.

Now compare that with a potion. If a potion heals a party member and then the player saves, what durable state matters? The party member’s HP and the item quantity. We do not set “used potion on slot two” as a progression flag. That would be noise. The world does not care about the historical fact of potion use unless some script explicitly asks for it, which ordinary healing does not. This is where advanced design becomes less about adding systems and more about refusing to persist irrelevant history.

On the board, I would write three small clone interfaces. First, Inventory has hasItem, addItem, removeItem, and maybe countItem. Second, EventState has getFlag, setFlag, getVar, setVar. Third, ScriptExecutor has commands that compose those primitives. The key point is that the ScriptExecutor should not reach into bag internals. It should ask inventory questions through a narrow interface. Likewise, the item-use dispatcher should not know every map’s progression rules. If it does, your clone will become a pile of special cases.

FireRed’s source organization nudges us in this direction. The script command progression flow is represented in pokefirered/src/scrcmd.c chunk_7609d397203c8536, while flag and variable storage support lives in pokefirered/src/event_data.c chunk_bff5bbc2efc3008f. Item-use flow is elsewhere, in pokefirered/src/item_use.c. That separation is not perfect in the abstract academic sense, but it is very practical. Items, scripts, and event state cooperate without collapsing into a single universal “game logic” file.

Now let’s complicate the door example. Suppose the Ancient Gear is consumed when the door opens. Who consumes it? The script should. The script checked the condition; the script owns the successful branch; the script can remove the item before setting the flag or after setting the flag, depending on how you define failure recovery. In a small clone, you might say the script command sequence is: check item, show confirmation text, remove item, set flag, animate door. But that order has consequences. If animation can fail, or if the player can be interrupted, you need to decide whether the item is consumed before or after the world mutation. FireRed’s engine style often avoids this exact transactional language, but as clone designers we should be explicit.

For our minimal architecture, I would make the script command atomic at the gameplay level: once the player confirms, remove the item and set the flag in the same script step, then queue the visual work. That way the durable state does not depend on whether a fade or animation callback completes before a save. If your engine allows saving mid-animation, then you must be even stricter. Either block saving during transient visual states, or persist enough state to reconstruct them. FireRed generally keeps the player inside controlled callbacks and tasks during these transitions, and we have already studied that runtime shell. Remember SetMainCallback2 and RunTasks from earlier weeks; we are not re-teaching them now, but they explain how the engine can temporarily own input and sequencing while an effect completes.

Now, field-use versus battle-use becomes clearer. In battle, the “world script owns the branch” model usually does not apply. The battle controller or battle turn system owns the branch. If the player uses a potion in battle, the item-use decision becomes a battle action. It must respect turn order, battler targeting, action restrictions, and battle messages. The shared item registry can tell us that the item is a potion-like healing item, but the battle system decides when the healing takes effect. That is why shared item data is necessary but insufficient.

This is a good place to connect back to our prior AI work without reopening it. When we studied AI script pointer control and party-aware predicates, we saw that a battle decision often depends on compact state queries: HP thresholds, status, party availability, move effects. Item use in battle follows the same discipline. You ask predicates against battle and party state, but you do not let a bag menu directly mutate the battle in a way that bypasses the turn engine. If you do, your AI and player actions will stop being comparable. Worse, your tests will become misleading, because “using a potion” from the menu and “using a potion” as a battle turn action will not be the same behavior.

For the clone, I would model battle item use like this. The bag UI produces an intent: use item X on battler or party slot Y. The battle system validates the intent in the current battle context. If valid, it schedules a battle action. During turn resolution, the battle action calls the item effect helper, mutates HP or status, consumes quantity, and emits messages. That is different from the cave door, where the map script checks inventory and sets an event flag. Same item inventory, different owning state machine.

Check yourself on this distinction. If a key item opens a door, who owns the success branch? The script. If a potion heals during a battle turn, who owns the success branch? The battle turn resolver. If a potion heals from the field party menu, who owns the success branch? The item-use and party-menu flow together, with party data as the durable mutation. There is no single answer called “the item system.” There are item-indexed behaviors in several contexts.

Let’s do another concrete example: badge-gated field moves. In a simplified creature RPG, you might have a move called Cut that removes a small tree on the map. The player must have the right badge and a party member that knows Cut. Is this an item? Not exactly. But architecturally it behaves like an unlock input because a script or field interaction asks for proof. The proof is distributed: event flag for badge ownership, party predicate for known move, map predicate for facing a cuttable object, and maybe script variable for temporary result. The field move is not just “use move.” It is a script-mediated unlock where party state substitutes for inventory state.

This is why your week 18 lab includes potion, Escape Rope, key item, and badge-gated field move together. They look like different gameplay features, but architecturally they test whether you can route authority correctly. Potion tests party mutation and item quantity. Escape Rope tests field context and map transition. Key item tests inventory as script evidence. Badge-gated field move tests flags plus party predicates plus map interaction. If you implement all four with one giant switch that mutates everything directly, it may pass a tiny demo, but it will not scale to the course architecture.

Now, I want to bring in map loading and save persistence, because those objectives are not separate from item use. Consider again the cave door. On first visit, the map loader reads the map header and object definitions, constructs the scene, and consults event flags for object visibility or script conditions. We covered map headers and object events earlier, so I will only invoke that foundation here. When the script sets CAVE_DOOR_OPEN, the visible world changes. When the player reloads, map loading must consult that same durable flag and build the opened state. That gives us a complete loop: map interaction, script execution, inventory predicate, event flag mutation, save persistence, map reconstruction.

Say that loop back to yourself mentally. Map interaction starts it. Script execution coordinates it. Inventory provides the unlock predicate. Event state records the result. Save persistence stores event state. Map loading reads event state later. That is a FireRed-like way to think. Not because every detail is identical, but because the responsibility boundaries resemble what the source is showing us across item_use.c, event_data.c, and scrcmd.c.

Now I’ll put a small verbal diagram on the board. Player presses A at door. Overworld finds the facing object or metatile script. ScriptExecutor begins DoorScript. DoorScript calls inventory.hasItem(ANCIENT_GEAR). If false, message says, “The mechanism is missing a gear.” If true, script calls inventory.removeItem(ANCIENT_GEAR, one), eventState.setFlag(CAVE_DOOR_OPEN), map.queueMetatileChange, and message says, “The door unlocks.” Save writes inventory and eventState. Reload reads eventState before finalizing map collision. That is the whole clone path.

Notice what I did not include. I did not include the bag UI. The player never selected the item. That is legitimate. An item can matter without being actively used from the bag. This is a subtle but important point for progression design. Sometimes “use item” means the player chooses it. Sometimes “has item” means a script gate chooses to inspect it. FireRed uses both patterns throughout the broader architecture, and our source focus this week is precisely about not confusing them.

Now let’s contrast Escape Rope, because it is field-use but not script-gated in the same way. The player selects Escape Rope from the bag. The item dispatcher checks whether the current map permits escape behavior. If not, show a failure message and do not consume the item. If yes, consume or schedule consumption, begin a field transition, and update location. In the FireRed source focus, the item-use flow and field continuation in pokefirered/src/item_use.c chunk_7e88bbaddbab5bb9 and chunk_8f5c0eba4013eb8a are the evidence to keep beside you here. Field item use is callback-shaped because the visible result is not instantaneous. You may have fades, sounds, map changes, and return callbacks.

For a clone, I would represent Escape Rope as a field item handler that returns one of a few structured results: cannotUse with message, consumedAndContinue, openPartyMenu, startFieldEffect, or enqueueBattleAction if you are sharing a high-level interface. But I would be careful with that last one. A result enum is useful; a universal effect object that pretends field and battle are the same can become vague very quickly. Advanced engine design often means allowing two systems to share data while preserving different control flow.

Let me ask a check question. If Escape Rope fails because the player is outdoors, should item quantity decrease? No. What state persists? Usually nothing, except perhaps the current message is transient and not saved. If Escape Rope succeeds, what persists? The reduced item quantity and the new location, plus any normal save state associated with being there. Do we need an event flag that says “used Escape Rope”? Usually no. Again, persist the consequence, not the anecdote.

Now, how do script variables fit into this? Flags are excellent for yes-or-no progression. Variables handle small numeric or enumerated state: which phase of a quest, how many items have been delivered, which fossil was chosen, which puzzle state is active. In pokefirered/src/event_data.c chunk_bff5bbc2efc3008f, the important architectural idea is that event data gives scripts a shared memory substrate. And in pokefirered/src/scrcmd.c chunk_7609d397203c8536, script commands are the language that reads and writes that substrate for progression flow. In the clone, do not overbuild this. You do not need a full bytecode VM on day one. But you do need a script execution layer that can read and write flags and vars through a stable API.

Suppose a museum guard asks for three shards before opening a stairway. Inventory alone is not enough if the hand-in can happen one shard at a time. You might use a variable SHARDS_DELIVERED. Each time the player talks to the guard, the script checks inventory count, removes one if present, increments the variable, and if the variable reaches three, sets MUSEUM_STAIRS_OPEN. On reload, the variable preserves partial progress, and the flag preserves completion. That is a more sophisticated version of the Ancient Gear example, and it shows why variables are not just “flags with numbers.” They represent progression states where partial order matters.

Could you represent that by leaving the shards in the inventory until all three are present? Yes. That is a design choice. But the moment you allow partial delivery, you need durable quest state outside the inventory. This is the kind of modeling decision I expect you to make explicitly in homework_w18. Do not just ask, “Can I code it?” Ask, “What state is the source of truth after reload?”

Let’s tie this to party data briefly. A badge-gated move has a similar source-of-truth question. If the tree is cut and disappears permanently, the event flag for that tree or route section is the durable world result. The party member knowing the move is just authorization at the moment of use. If the player later deletes the move, the already-cut tree should not reappear unless your design says it should. Conversely, if the field move only clears a temporary obstacle that resets when the map reloads, then you may not set a permanent flag. You might mutate the current map session only. FireRed-style games use both durable and temporary changes, and your clone should make that difference intentional.

Here is the advanced test: identify the minimum durable state. For a healed creature, durable state is HP and status. For an opened story door, durable state is a flag. For a multi-step delivery, durable state is a variable and maybe inventory counts. For a battle item, durable state after battle may include party HP, consumed quantity, and battle outcome, but the turn-selection cursor is not durable. For an Escape Rope, durable state is location and quantity. Minimal persistence is not a storage optimization only; it is a correctness tool. The less irrelevant history you store, the fewer contradictions you can load.

Now, one more source connection before we move forward. The broader packet points out pokefirered/src/battle_setup.c chunk_494d132a59422c85 as a useful source for battle transition and event integration, with includes that cross overworld, item, load_save, script, event_data, field effects, and battle modules. I am not citing that to make you memorize include lists. I am citing it because it shows the architectural neighborhood. Battle entry and field progression are not isolated islands. The engine has to move between overworld scripts, event data, field effects, and battle setup. Item unlocks live in that same neighborhood. A key item may be checked by a script before a battle. A battle result may set a flag. A field item may initiate a transition. The architecture is a network of controlled handoffs.

So, if I were grading your clone design, I would look for those handoffs. I would want to see that the map loader does not hard-code every quest. I would want to see scripts using event-state APIs. I would want to see inventory item counts separated from item metadata. I would want to see party predicates as queries, not as duplicated loops scattered through door scripts. I would want to see battle item use enter the battle turn system rather than secretly patching battler HP from the bag UI. And I would want save persistence to store stable facts, not transient menu states.

Let’s do a final check for this segment. I’ll give you a scenario, and you classify it. The player talks to a guard. The guard says, “Only trainers with the Thunder Badge may pass.” The player has the badge. The guard steps aside forever. What authorized the behavior? A flag, the badge flag. Who owns the interaction? The script attached to the guard. What persists afterward? A separate flag or variable representing that the guard moved, unless the badge flag alone is intended to imply it. Next scenario: player uses a potion from the bag outside battle. What authorized it? Inventory count plus party target validity. Who owns it? Item-use and party-menu flow. What persists? Quantity and party HP. Third scenario: player uses a potion during battle. What authorized it? Inventory count, battle rules, and target validity. Who owns it? Battle action resolution. What persists? Quantity and party state after the battle-relevant mutation, not the menu path used to choose it.

That is the level of precision I want. Not because the words are fancy, but because the engine will force the distinction on you as soon as features interact. In the next stretch, we will keep the same four boxes on the board, but we will zoom in on the script executor itself. We will ask how small it can be while still supporting item-gated doors, variable-based quests, party-aware field moves, and battle handoffs without turning into a general-purpose scripting language too early.

Now, keep those four boxes visible, because they are about to become our design test for the script executor. If your script system cannot answer those four questions cleanly, it is already too vague. And if it answers them by saying, “Well, the script just does everything,” then you have made the script engine too powerful too early.

Let me say that more precisely. In a minimal FireRed-like clone, the script executor should not be the inventory system, should not be the party system, should not be the battle system, and should not be the save system. It should be a coordinator over small, explicit state operations. It can ask, “Does the player have the Card Key?” It can ask, “Is flag 27 set?” It can set a variable. It can start a message. It can request a warp. It can request a battle. But the minute it owns all item mutation, all party mutation, all map mutation, and all battle turn logic, you no longer have architecture. You have a god interpreter with a game attached to it.

So, board cue here: I am writing “script command equals permissioned verb.” Not “script command equals arbitrary code.” A script command is a permissioned verb. Check flag. Set flag. Compare variable. Give item. Remove item. Start battle. Warp player. Open message. Wait for input. Resume. Those are verbs, but each verb is narrow. The narrowness is what lets item-gated progression remain debuggable.

This is exactly why the source focus for today includes both event data and script commands. The event flag and variable support in pokefirered/src/event_data.c, chunk_bff5bbc2efc3008f, is not decorative bookkeeping. It is the storage substrate for world memory. Then pokefirered/src/scrcmd.c, chunk_7609d397203c8536, gives us the script-side verbs that read and mutate that memory as part of progression flow. And then item use comes in from the other side, through pokefirered/src/item_use.c, especially chunk_7e88bbaddbab5bb9 for the item-use flow, chunk_8f5c0eba4013eb8a for field item-use continuation, and chunk_ce2671932ba5ff71 for support behavior around item use. Those chunks are important together because they show the pattern we care about: inventory actions and script progression are connected, but they are not the same subsystem.

Now let’s make this concrete. Suppose we are building a minimal clone version of a locked generator room. The player can walk up to the generator room door. The door script says, “If the player has the Basement Key, unlock the door; otherwise display ‘It is locked.’” There are two tempting bad designs here. First bad design: the door directly scans the bag and mutates bag contents and warps the map and sets quest variables all in one object-specific function. That works once. Then you add five more locked doors, two keycards, a badge gate, a required party move, and a story variable, and now your map object scripts are full of duplicate special cases. Second bad design: the key item itself knows every door it can open. That also works once, until you realize that key items can be inspected from the bag, used on the field, checked by NPC scripts, and validated by map triggers. The key item should not know the whole world.

The cleaner design is this. Inventory owns whether the key exists. Event flags own whether the door has already been unlocked. The script executor owns the conditional progression flow. The map loader owns which script is attached to that door tile or object. The save system owns persistence of inventory quantities and event flags. So when the player presses A on the door, the map interaction system starts the door script. The script checks flag DOOR_GENERATOR_OPEN. If it is already set, it opens or warps. If not, it asks inventory, “Do we have ITEM_BASEMENT_KEY?” If yes, it plays the unlock message, sets the flag, and then opens. If no, it displays the locked message. Notice what did not happen. The door script did not become a bag UI. The key item did not become a map router. The save system did not know the meaning of a generator door. Each system kept a small contract.

Quick check for understanding. If the player uses the Basement Key manually from the bag while standing nowhere near the generator door, should that always unlock the generator door? No, not unless your design explicitly defines the key’s field-use handler that way. In many creature RPG cases, the door script checks the key as an unlock input, while the bag use action may simply say, “This cannot be used here.” That distinction is the whole lecture today. An item can be an unlock input without being actively “used” from the bag at the moment of unlocking.

Now let’s connect this to the field-use versus battle-use distinction we already established without re-teaching it. When a Potion is used from the bag on the field, the item-use dispatch gets you into a target-selection and healing flow. When a Potion is used during battle, battle action resolution has additional authority because the item use consumes a turn-like decision, respects battle constraints, and mutates battle-relevant state. But a key item used as a script unlock input may not go through either of those exact paths. It may be queried by a script command or by a script helper. So we now have three item relationships: item as directly used effect, item as battle action input, and item as script condition. Same inventory database, different authority path.

For the minimal clone, I would implement this in a deliberately boring way. And I mean boring as praise here. Your item table has an item id, name, pocket, fieldUseHandler, battleUseHandler maybe, and key item classification. Your inventory has add, remove, count, and has. Your script VM has opcodes like message, checkItem, compare, jumpIfFalse, setFlag, clearFlag, checkFlag, setVar, warp, startBattle, and end. Your map object can reference a script id. Your save file stores inventory, party, flags, variables, current map id, player position, and maybe a small amount of pending script state if you support mid-script saving. At this stage of the clone, you do not need a rich embedded language. You need enough command structure to prove that progression can cross system boundaries without becoming spaghetti.

Let me put a little pseudo-board example into speech. Imagine script GeneratorDoor. Command one: check flag generatorDoorOpen. Command two: if true, jump to OpenDoor. Command three: check item BasementKey. Command four: if false, jump to LockedText. Command five: message “The Basement Key turned in the lock.” Command six: set flag generatorDoorOpen. Command seven: OpenDoor. Command eight: play door animation, warp or change collision. LockedText just displays “It is locked.” Then end.

What matters is not the syntax. What matters is that each command is small enough to test. You can unit test checkItem without loading a map. You can unit test setFlag without inventory. You can integration test the door script with a tiny fake inventory and fake flag table. Then, when a player reports, “I had the key but the door stayed locked,” you know exactly where to inspect: inventory count, script branch, flag write, map state update, or save persistence. That is the professional value of these separations.

Now, advanced point. Script variables and flags are not the same, even if both are just numbers under the hood. A flag is best for a boolean world fact: door opened, NPC defeated, item picked up, badge obtained. A variable is best for a small state machine: quest phase equals 0, 1, 2, or 3; current elevator floor; chosen fossil; rival starter species; temporary script result. In a minimal clone, yes, you can store both as integers. But your API should keep their meanings distinct. When pokefirered/src/event_data.c, chunk_bff5bbc2efc3008f, appears in today’s packet, the architectural point is that event memory is a first-class service. It is not a random global bag of booleans. It is a shared progression layer.

And that shared layer is how items become unlock inputs. The item does not necessarily persist the unlock itself. The item may remain in the bag forever, like a key item. The persistent unlock is often a flag. That is why the save system must store both the inventory and the event flags. If you save after opening the generator door and reload, the engine should not need to replay the key-use moment. It loads the map, loads the event flag table, and the door is already open or the object is gone or the collision is changed. The item was evidence used to authorize the transition; the flag is the durable world fact after the transition.

Let’s pause there. What persists: the key still in inventory, maybe, and the door-open flag. What does not persist: the temporary branch result that said “player has key” during script execution. That temporary result is computation, not game state. In your clone, do not accidentally save every scratch variable just because it exists in the interpreter. Save durable variables. Clear or recompute temporary ones.

This also explains badge-gated field moves, which you will implement in the lab. A badge-gated field move is not just “party has move Cut.” It is usually a compound authorization check. Does any party member know the move? Does the player have the required badge or flag? Is the current tile or object a valid target? Is the player in a state where field effects can run? Maybe the map allows it, maybe the script target is correct. Earlier in the course we studied party-aware predicates and status checks across party slots in battle and AI contexts. We are not going to re-teach that today, but we can reuse the mental model: scan party state through a narrow query function, produce a yes or no, and let the caller decide the next branch. Here the caller may be a field effect setup or a script command, rather than AI script pointer control.

So the badge-gated bush example goes like this. Player presses A on a cuttable bush. The map object or metatile behavior routes to a script or field interaction. The script checks whether the player has the required badge flag. Then it checks whether the party has a compatible move. Then it asks for confirmation or directly starts the field effect, depending on the game’s UX. If successful, it sets or changes local map state, maybe removes the bush object until the map reloads or until the area resets. If failed, it displays the right text: “A Pokemon may be able to cut this,” or “You need the correct badge,” depending on how much information the design reveals.

Here is the important refinement. Do not encode that as “ITEM_BADGE_2 allows Cut” unless badges are literally inventory items in your clone. In FireRed-style architecture, badges are better treated as flags or trainer-card state, not bag items. This is exactly why today’s lecture is “Items as Scripted Unlock Inputs,” not “Every Unlock Is an Item.” Inventory state is one possible input. Party state is another. Event flags are another. Variables are another. Map position and target validity are another. The script layer composes those inputs.

Now I want to tie this back to map loading, because progression bugs often look like script bugs when they are actually map-state bugs. When the map loads, it must instantiate objects and collision according to base map data plus event memory. If a one-time item ball was already picked up, the object should not appear. If a door was unlocked, the door may use a different script or may be passable. If a story NPC moved away, the object event may be hidden. That means the map loader is not just reading static layout. It is applying event flags as filters over the map’s object layer. We have seen the course-wide pattern repeatedly: data records become runtime globals, then callbacks, tasks, scripts, and structs produce visible behavior. This week is another example. Static map data says there is a door. Event memory says whether that door is locked. Inventory says whether the player can change that fact. Script commands coordinate the transition.

The packet’s broader source synthesis frames FireRed as cooperating state machines and data tables: callback shell, overworld and map runtime, script VM, creature and party model, battle engine, inventory UI, and save persistence. That is not just course branding. It is the engineering solution to this exact class of feature. You cannot implement item-gated progression cleanly unless you know which state machine is currently in charge.

Let’s make a second concrete example with a battle handoff. An NPC blocks a bridge and says, “Show me the Secret Ticket, then battle me.” The script checks inventory for the Secret Ticket. If absent, message and end. If present, message and start battle. Battle setup, as represented by pokefirered/src/battle_setup.c, chunk_494d132a59422c85, sits at the boundary with includes and dependencies across overworld, item, load_save, script, event_data, event object movement, field effects, and battle transition. That chunk is useful evidence because the boundary is real in the source shape: battle is not isolated from progression, but progression does not become battle turn logic. The script may request battle setup; the battle engine owns the battle.

Then after the battle, what happens? Maybe the NPC sets a defeated flag. Maybe the bridge blocker disappears. Maybe the ticket is consumed, maybe not. Those are script decisions after battle returns. In your clone, the battle result should be placed somewhere narrow: a battle outcome variable or callback result. The script resumes and branches: if player won, set flag bridgeGuardDefeated; if player lost, maybe warp to center or leave the flag unset. Again, script as coordinator. Battle as owner of turns, damage, fainting, item-in-battle constraints, and result.

Check for understanding: should the inventory system know that the Secret Ticket causes a bridge battle? No. It should know count and item metadata. The bridge script knows that this ticket is required at this bridge. Should the battle system know that the Secret Ticket authorized the battle? Also no. It receives configured battle parameters. The authorization path is outside battle. That is how you avoid turning every system into a historian of every prior decision.

Let’s also talk about save persistence in that example. The save file should persist that the player still has or no longer has the ticket, the bridgeGuardDefeated flag, party state after the battle if saved later, current map position, and durable variables. It should not persist “currently checking Secret Ticket” unless you support saving mid-command, which I would avoid in a minimal clone. For our lab clone, treat scripts as short atomic interactions from the perspective of saving. You can save before the interaction or after the interaction, not halfway through a branch. That keeps the persistence problem tractable.

Now, someone usually asks at this point, “Could we represent item-gated doors as data instead of scripts?” Yes. And that is a good design question. For a minimal clone, you might create a declarative lock component: requiredItem, successFlag, lockedText, unlockedText, targetMap. That is absolutely valid for common doors. But the moment the unlock condition becomes “has key, has talked to NPC, party has a living creature with Surf, rival battle completed, and variable questPhase at least 3,” you either need a small condition language or you route to scripts. FireRed’s script-command model gives you a general progression mechanism without making every map object a custom C function. The architectural judgment is to use data declarations for common uniform cases and scripts for authored sequences.

This is where the advanced learner bar rises. In week 14 and week 16 assessments, you were asked to decompose the RPG into map loading, script execution, party data, battle turns, item use, and save persistence. By week 18, I am no longer satisfied with “there is a script system.” I want to hear exact ownership. If your homework says, “The item opens the door,” I am going to ask, “Through which subsystem?” If your answer says, “The script checks the item, sets a flag, and the map loader uses that flag to change the door state,” that is architecture. That is testable. That survives new features.

Let’s do a short recap of this stretch before we go into the implementation sketch. Item-use dispatch gives items active behavior when the player selects them. Field-use continuation keeps overworld item effects from collapsing into bag UI. Event flags and variables provide durable and semi-durable progression memory. Script commands compose checks and mutations into authored sequences. Party state contributes to unlocks like field moves. Battle setup receives handoffs without making scripts own battle turns. Save persistence records the facts that must survive reload, not every transient step that produced them.

One more board cue: I am drawing a line between “authorization” and “effect.” Authorization asks, “May this happen?” Effect asks, “What mutation happens now?” A locked door script uses inventory for authorization. The effect is setting a flag and changing map traversal. A Potion uses inventory and target validity for authorization. The effect is HP mutation and quantity decrement. A battle item uses battle rules for authorization. The effect is owned inside battle resolution. A badge-gated move uses badge flag, party move state, and target tile for authorization. The effect is a field effect plus map mutation. This vocabulary will keep you out of trouble.

Now, as we move into the next part, we are going to sketch a small script VM that is intentionally less powerful than a general programming language, but still powerful enough for these cases. I want you listening for three design constraints as we do it: first, every command has one owner subsystem behind it; second, every durable mutation has an obvious save destination; third, every temporary branch result can be thrown away and recomputed. If your implementation meets those three constraints, then item-gated progression stops being a pile of special cases and starts becoming a reusable architecture.

So, let us put that miniature VM on the board. I am going to write it in words first, not code, because the code is less important than the ownership boundaries.

On the left side of the board, I want a script pointer. In the middle, I want a command decoder. On the right, I want a small set of services: flags and variables, inventory, party, map, message box, and field effects. That is the whole machine for today. Notice what I did not put there. I did not put a general object model. I did not put arbitrary closures. I did not put direct save-file writes scattered through item handlers. The script VM can ask subsystems questions and can request subsystem actions, but it should not secretly become every subsystem.

Now, if you compare that to the source focus for today, this is exactly why we paired the item-use files with the event-data and script-command files. The item-use flow in pokefirered/src/item_use.c, especially chunk_7e88bbaddbab5bb9, gives us the dispatch side: an item is chosen, the context matters, and a use handler decides how to continue. The continuation chunks, pokefirered/src/item_use.c chunk_8f5c0eba4013eb8a and chunk_ce2671932ba5ff71, matter because item use is rarely a single instantaneous function call. Field item use often needs UI cleanup, a message, a return to overworld control, or a field effect. Then pokefirered/src/event_data.c chunk_bff5bbc2efc3008f is the durable event-state side, flags and variables, and pokefirered/src/scrcmd.c chunk_7609d397203c8536 is the progression-flow side, the script commands that make those flags and variables useful. That pairing is not accidental. It is the architectural point of the day.

Let me say that again in a slightly different way. The bag tells you what input the player selected. The item-use layer interprets that input in a context. The script layer converts world rules into small commands. The event-data layer remembers durable consequences. If you merge all four of those into one giant “use item” function, your first demo may work, but your second town, your third badge, your first escape rope, and your first NPC blocker will all start fighting each other.

All right. Suppose we are building the minimal clone. We need map loading, script execution, party data, battle turns, item use, and save persistence. We are not building full FireRed. We are building the smallest architecture that can survive FireRed-shaped pressure.

So, for map loading, the clone needs a current map id, a layout reference, a list of object events, a list of trigger scripts, and a tile behavior grid. That is enough to ask, “What did the player touch?” and “What script should run?” We have already spent weeks on map headers and object events, so I am not going to re-teach that. Just carry forward the idea that the map is not only graphics. The map is a runtime contract: collision, warps, triggers, NPCs, and scripts all hang off it.

For script execution, we need a script pointer and a small command set. I would start with message, check flag, set flag, clear flag, check variable, set variable, compare variable, check item, remove item, check party move, start field effect, warp, give item, and end. You might add wait message and close message if your UI is asynchronous. You might add call and return if your scripts need reuse. But the important part is that every command delegates to one owner subsystem. Check item delegates to inventory. Check party move delegates to party data. Start field effect delegates to the field-effect system. Set flag delegates to event data.

Here is the key design rule. The VM command is glue, not ownership.

If the script says check item, the script VM should not know where the bag pockets are packed in memory. We already covered bag pockets and quantities, and we already covered the bag window as a UI facade. The VM just asks, “Inventory service, does the player have item X?” If the script says check party move, the script VM should not parse creature growth data or held items or battle stats. The party module owns party slots and move data. The VM asks a question and receives a yes or no. If the script says set flag, the VM should not know the whole save layout. It should call the event-data layer.

Pause there. Check for understanding. If I ask you where the knowledge “this tree can be cut” belongs, is that inventory, party, or map? It is map or tile behavior. If I ask where the knowledge “the player owns the required key item” belongs, that is inventory. If I ask where the knowledge “this badge has been earned” belongs, that is event flags. If I ask where the knowledge “a party member knows the required move” belongs, that is party data. The script command may combine those checks, but it does not own their internal representation.

Let us walk a concrete example, because this is where many clone implementations become too clever. Imagine a badge-gated field move. The player is facing a small tree. They press A, or they choose a field move from the party menu, depending on the interface you implement. The intended rule is: the target tile must be a cuttable tree, the player must have the badge flag, the party must contain a creature with the move, and the map should replace the tree with passable ground or mark a temporary object as removed.

What should happen first? We identify context. Are we in the field? Yes. Are we in battle? No. That matters because last time, in Dispatching Item Effects, we separated field-use and battle-use behavior. This is not just a UI distinction. It prevents us from asking battle-only questions in the overworld and overworld-only questions in battle. That same separation appears in the source focus around pokefirered/src/item_use.c chunk_7e88bbaddbab5bb9 for item-use flow and the continuation chunks chunk_8f5c0eba4013eb8a and chunk_ce2671932ba5ff71 for field continuation behavior.

Then the map service checks the tile in front of the player. If the tile is not cuttable, the action fails with a message. The party service checks whether any eligible party member knows the move. If not, the action fails with a different message. The event-data service checks whether the badge flag is set. If not, it fails with the badge-gate message. Only after those authorization checks pass do we run the effect. The field-effect system plays the animation or state transition, the map system mutates the tile or object state, and the script system sets any durable flag if this particular obstacle is permanently removed.

Now, notice the subtle distinction between two kinds of map mutation. If this is an ordinary small tree that should reappear when the map reloads, maybe there is no durable flag. The tile is changed temporarily in the current map session, and after leaving and returning, the tree is back. If this is a story boulder or a one-time barrier, the script sets a flag, and the map load process consults that flag to decide whether to spawn the obstacle. That is the sentence I want you to underline in your notes: durable world change is usually applied at load time from saved event state, not remembered as an arbitrary live-map hack.

This is why pokefirered/src/event_data.c chunk_bff5bbc2efc3008f belongs in today’s lecture. Event flags and variables are not decorative. They are the bridge between one moment of player action and future map construction. And pokefirered/src/scrcmd.c chunk_7609d397203c8536 matters because script commands are the controlled vocabulary by which designers, maps, and events manipulate that bridge.

Let me put a small board trace up.

Player uses key item at locked door. Item-use dispatch sees a field-use key item. It launches or resumes a script. The script checks whether the selected item matches the door requirement, or it checks inventory directly. The script displays the unlock text. It sets a door-open flag. It tells the map system to change the door state or starts an opening animation. Then it ends. On save, the flag persists. On reload, map loading sees the flag and loads the door as open.

That is a clean version. Now let me show the messy version, because this is what you should avoid in your lab. Player uses key item. The item handler directly changes the tile, directly removes the item, directly writes some save struct field, directly starts a text box, directly changes player control, and directly calls a warp function. It will work once. But when an NPC also needs to open the door, you duplicate the logic. When the door should open from a script trigger, you duplicate it again. When saving and reloading puts the door back because you forgot the map loader, you patch the item handler. Then when another map uses the same key item, the patch breaks that map. That is not architecture; that is a list of apologies.

The minimal clone avoids this by making item use an input into scripts when the effect is progression-oriented. That phrase is important: “when the effect is progression-oriented.” Not every item needs a script. A potion in the field can be a direct item handler that opens party selection and calls healing logic. A potion in battle belongs to battle item resolution, because turn order, action consumption, targeting, and battle messages are battle-owned. An escape rope is closer to a field item that asks the map or overworld service for an escape destination and then initiates a warp. A key item that opens a gate should usually route into script progression, because the important consequence is not the inventory operation; it is the world-state transition.

Let us connect that to battle turns, because your homework asks for a minimal clone that includes battle turns as well. In battle, an item is not merely “used.” It is selected as an action in a turn structure. It may consume the battler’s turn. It may have priority implications. It may fail due to battle rules. It may target a party member or active battler. The source packet’s battle_util.c excerpt, pokefirered/src/battle_util.c chunk_9335e5727aa0657d, shows the breadth of battle dependencies through its includes: item, event_data, battle scripts, controllers, abilities, hold effects, move effects, and other constants. We do not need to re-teach battle today, but that chunk is a useful reminder that battle item behavior sits inside a dense battle-owned ecosystem. So, in your clone, resist routing battle potion use through the overworld script VM. That is the wrong owner. Let battle own battle consequences.

At the same time, field progression should not be owned by battle. This sounds obvious, but it is the same mistake in the opposite direction. An unlock input should be interpreted by the world and script systems, not by a combat turn engine. If the player uses a key item on a shrine, and that shrine sets a story variable, you are not in battle resolution. You are in event flow.

Let us do a more advanced example. Suppose a guard blocks a tunnel. The guard should move only if the player has a parcel key item and has spoken to the mayor. That is two conditions: inventory state and a story variable. The player can talk to the guard, or perhaps use the parcel from the bag while facing the guard. You want both paths to converge.

The script should look conceptually like this: check variable mayorConversationStage against the required value; if not enough, show “The guard is waiting for orders.” Then check item parcel; if missing, show “You need the sealed parcel.” If present, show “The guard checks the seal.” Remove item if appropriate. Set flag tunnelGuardMoved. Apply object movement or hide the guard. End.

Where does the item-use handler fit? If the player selects the parcel from the bag in the field, the handler should not reproduce the whole guard script. It should identify that this key item can be used in the field, maybe check the facing object, and then request the relevant script. In a stricter design, the object interaction owns the script, and the key item only provides an input token. In a more convenient clone design, the item handler can dispatch to a script table keyed by item id and map context. Both can work. But do not bury story progression in item code if object interaction also needs it.

Here is a good test question for your design. Can the same locked door be opened by talking to it and by using the key item from the bag? If yes, and both paths call the same script or same progression service, your design is probably healthy. If you have two different implementations, one in door interaction and one in item use, expect bugs.

Another test question. Can the map reload from a save and display the correct door state without replaying the item-use function? If yes, your event flags and map loading are properly connected. If not, you treated a durable state as temporary behavior.

Now, let us talk about variables versus flags, because this is where advanced students often overuse flags. A flag is good for a boolean fact: badge earned, door opened, boss defeated, item collected, guard moved. A variable is good for a multi-stage progression state: quest phase, puzzle count, current elevator floor, rival encounter stage, selected fossil, or number of switches pressed. In pokefirered terms, the source focus points us to event_data.c chunk_bff5bbc2efc3008f for flags and variables as support, and scrcmd.c chunk_7609d397203c8536 for script commands that operate progression flow. In your clone, the distinction matters because it affects script readability and save migration.

Let me give you a bad version. You create flags mayorTalkedOnce, mayorGaveParcel, guardSawParcel, guardMoved, tunnelUnlocked, tunnelEntered, tunnelQuestDone. Some of those might be legitimate, but if they encode one linear quest stage, a single variable called tunnelQuestStage may be clearer. Stage zero: not started. Stage one: mayor spoken to. Stage two: parcel obtained. Stage three: guard moved. Stage four: tunnel entered. Use flags for facts that can coexist independently. Use variables for ordered state.

But be careful. Variables are not a license to make opaque magic numbers everywhere. A minimal clone should name the stages. Even if your underlying save stores integers, your script-facing definitions should be readable. The advanced architectural point is not “flags good” or “vars good.” The point is that durable progression state needs a stable vocabulary.

Now I want to bring save persistence into the picture. We have talked about it indirectly, but let us make it explicit. Your save file should persist inventory quantities, party state, event flags, event variables, current map position, and enough player state to resume. It should not persist every temporary branch result. If a script checks whether the player has the parcel, that result does not need to be saved. Recompute it from inventory. If a script checks whether the party has a move, do not save “canUseCutToday” as a durable flag unless the game design truly means to freeze that fact. Recompute it from party and badge state.

This connects directly to the three constraints I gave you at the end of the previous part. Every command has one owner subsystem behind it. Every durable mutation has an obvious save destination. Every temporary branch result can be thrown away and recomputed. Let us apply them to the guard example.

Check item: owner is inventory; no mutation; result temporary. Check variable: owner is event data; no mutation; result temporary. Remove item: owner is inventory; durable mutation saved in inventory. Set guard moved flag: owner is event data; durable mutation saved in flags. Hide guard object: owner is map/object system; if temporary, it applies live; if durable, map load also consults the flag. Show message: owner is UI/message system; not durable. End script: owner is script VM; not durable.

That breakdown is a design review tool. Use it on your own lab code. If you cannot point to the owner, you probably have leakage. If you cannot point to the save destination, you probably have a reload bug. If you saved a temporary result, you probably created stale state.

Let us pause for a check. Imagine a badge-gated surfing action. The player has the badge, has a party member with the move, and is facing water. Which facts are durable, and which are temporary? The badge flag is durable. The party member’s move is durable as part of party data, but the yes-or-no answer “can surf right now” is temporary. The facing-water check is temporary, derived from current map position and tile behavior. The fact that the player is now surfing may be runtime player movement state, and depending on your save design, you may or may not persist that exact mode. But you should not set a permanent “surf unlocked here” flag just because the player pressed A at water. The authorization is recomputed.

Good. Now, since this is week 18 and not week 5, I want to raise the sophistication one level. Script commands should be small, but scripts should still be debuggable. In a clone project, add tracing early. When a script runs, log the script id, command name, arguments, branch result, and any durable mutation. Not forever in release form, but during development. If a door fails to open, you want to see: check item keycard true, check flag bossDefeated false, branch to locked message. That tells you the rule failed, not the item. This is the same mental discipline we used in earlier weeks when tracing data tables through globals, callbacks, tasks, scripts, structs, and source functions. The path is the architecture.

The FireRed source organization encourages that tracing because behavior is not hidden in one magic place. Item use is in item_use.c chunks for dispatch and continuation. Event flags and variables are in event_data.c chunk_bff5bbc2efc3008f. Progression commands are in scrcmd.c chunk_7609d397203c8536. Battle setup, in pokefirered/src/battle_setup.c chunk_494d132a59422c85, also shows how battle entry depends on overworld, script, event data, field effects, and related systems through its source-level dependencies. The point is not that includes prove behavior by themselves. The point is that the architecture repeatedly crosses subsystem boundaries through named contracts, not through one universal gameplay function.

Let me make the minimal script VM concrete enough that you can implement it after class. The VM has a program counter pointing into a script array. Each command has an opcode and operands. The VM runs until it hits a blocking command or end. A blocking command is something like show message, wait movement, fade screen, choose yes/no, or start field effect. When blocked, the VM stores its continuation state and returns control to the main loop. On a later frame, a task or callback resumes it.

That last sentence should sound familiar from the runtime shell material. We covered main callbacks, task allocation, task IDs, and RunTasks earlier in the course. We are not re-teaching those, but we are using them. A script VM in a GBA-style architecture cannot assume it owns the CPU until all effects are done. It often initiates an operation, yields, and resumes. That is why field item-use continuation matters. The item does not just “do thing.” It may enter a multi-frame sequence that crosses menus, messages, animations, map state, and player control.

So when you implement the lab handlers for potion, escape rope, key item, and badge-gated field move, classify them by continuation style. Potion in field: select party member, heal, consume item, message, return. Potion in battle: select target, submit battle action or execute through battle item logic, consume according to battle rules, continue turn. Escape rope: validate map allows escape, consume item, start warp or escape script, return after transition. Key item: identify context, run script or show failure, usually no consumption. Badge-gated field move: validate badge, party move, target tile; start field effect; mutate map; return to overworld.

Do you hear how each one has a different owner? That is the point. The item id is common, but the effect owner changes by context.

Let me also warn you about one more trap: do not make inventory the source of truth for story unlocks just because the lecture title says “items as scripted unlock inputs.” The word “input” is doing work. A key item can authorize a script branch, but the durable story state is usually a flag or variable. Why? Because the player might keep the item after unlocking the door. Or the item might be removed. Or another event might open the same door without the item. Or a later story event might relock the area. If your only question is “does the player have the key,” you have made the inventory carry too much narrative meaning.

In other words, inventory state is excellent evidence for a branch. It is not always the final world state.

For example, suppose the player has the Secret Key. The mansion door can open. After opening, maybe the player still has the Secret Key. If map loading asks only “does the player have Secret Key,” the door remains open, fine. But if a cutscene opens the door for the player before they obtain the key, that model fails. If the key is later removed for story reasons, the door might incorrectly close. A doorOpen flag is clearer. The script can require the key to set the flag, but the map should load from the flag once the world has changed.

This is the distinction between authorization and consequence. Authorization can depend on inventory, party, badges, variables, current map, facing direction, battle state, or NPC state. Consequence should be written to the subsystem that owns the changed fact. Inventory consequence goes to inventory. World consequence goes to event flags or map state. Party consequence goes to party. Battle consequence goes to battle state. Save consequence follows ownership.

Now, as we turn toward the next part, keep a compact mental model. Items are not magic. They are player-selected inputs with data records behind them, bag quantities around them, UI surfaces in front of them, and use handlers below them. Field progression is not magic either. It is map context plus script commands plus event state. When those two meet, the right design is not to let either side swallow the other. The item layer says, “Here is what the player is trying to use.” The script layer says, “Here is what the world allows that input to mean.” The event-data layer says, “Here is what will still be true after the screen fades, after the map reloads, and after the save is loaded tomorrow.”

In the next stretch, we will take this same vocabulary and push it through the workshop cases one at a time. We will start with the potion because it is the cleanest contrast between field and battle. Then we will use escape rope to talk about map permissions and warp destinations. Then we will use the key item to show script-driven progression without consumption. And finally we will use the badge-gated move as the full integration test: item or party input, badge flag, party state, tile behavior, field effect, map mutation, and save-visible event state all cooperating without collapsing into one tangled function.

So, let’s walk those workshop cases in order.

For the potion, the important architectural point is that the item is not “a healing function.” That is too small a description. A potion is an inventory record, plus a use context, plus a target-selection rule, plus a party mutation, plus a UI return path. In the FireRed item-use flow, the dispatch layer in pokefirered/src/item_use.c, chunk_7e88bbaddbab5bb9, is doing the routing work: what kind of item is this, where is the player using it, and what continuation should run after the menu or party screen finishes? That continuation idea matters because the healing effect is not just arithmetic on HP. The system has to say, “open the party UI, let the player select a valid creature, reject invalid targets, apply the item effect, update inventory if consumed, refresh visible state, and return to the right callback.”

Let me put that on the board as a chain: bag input, item handler, party selection, effect application, inventory update, UI continuation. Notice what is not in that chain. The map script does not need to know how many HP a potion heals. The save system does not need a special “potion was used” field. The battle engine does not need to borrow the overworld’s party menu assumptions. The same item concept can participate in field and battle, but the use context decides the route.

Now compare escape rope. Escape rope is still an item-use case, but it is not primarily a party mutation. It is a map permission and warp case. The handler needs to ask whether the current map permits that kind of escape. If the answer is no, the visible result is a message and no consumption. If the answer is yes, then the item bridges inventory into overworld transition logic. This is where the continuation material in pokefirered/src/item_use.c, chunk_8f5c0eba4013eb8a, becomes a good architectural reference: field item use often cannot finish synchronously inside the bag menu. It may need to close UI, fade, set a warp, run a field effect, or re-enter the overworld callback after state has been prepared.

Here is the clone-design version. Do not write an escape rope function that teleports the player from anywhere. Write a function that asks the map runtime for an escape destination. If the map returns none, show failure text. If it returns a destination, consume one rope, write the pending warp, and hand control to the overworld transition state machine. That small interface prevents the item system from becoming a secret map database.

Check your understanding here. If a player uses escape rope in a cave, which subsystem should know the cave’s exit coordinate? Not the item record. Not the bag window. The map or overworld layer should know, or at least expose it through map metadata. The item handler should ask a question and react to the answer.

The key item case is the opposite of the potion in another way. A key item may be used repeatedly, may not be consumed, and may exist mainly to satisfy a progression predicate. So if we are designing, say, a Silph Scope-like clone object, we do not want “use item” to hard-code every obstacle it can unlock. Instead, scripts should test inventory state or event flags and branch. That is why the event-data layer matters so much. The source focus for pokefirered/src/event_data.c, chunk_bff5bbc2efc3008f, is the flag and variable support that lets progression facts live outside any single UI path. And the script command layer, pokefirered/src/scrcmd.c, chunk_7609d397203c8536, is where those facts become control flow: compare a variable, check a flag, branch to one script block or another, set a result, mark progress.

Let me say that in plainer terms. The item is often not the unlock. The item is evidence. The script decides what that evidence means at a location. If I possess the key card, one locked door script opens. Another script might display a different message. A third script might start a cutscene. The same inventory fact is interpreted by local script context.

That design is what keeps progression authored. Designers can build doors, NPC gates, machines, and environmental checks without asking the item subsystem to know every narrative consequence. The item subsystem answers, “Does the player have item X?” or “Can this item be selected here?” The script system answers, “Given that fact, what happens in this scene?”

Now the badge-gated field move is the full integration test, because it touches almost every system we have been building since the beginning of the course. The input might look like a move selected from the party menu, or an item-like command in a field menu, but the actual predicate is composite. Does the party contain a creature with the move? Does the player have the relevant badge flag? Is the player facing a compatible tile behavior? Is there a field effect implementation? Will the map mutation persist, or is it temporary until reload? In FireRed terms, this is exactly where the item-use support layer in pokefirered/src/item_use.c, chunk_ce2671932ba5ff71, should be read alongside event flags and script commands, not in isolation.

And you can hear the echo from earlier weeks. When we studied battle AI, we cared about script pointer control because the AI was not one giant decision function; it was a small interpreter moving through predicates and branches. When we studied party-aware AI predicates and status checks across party slots, we cared about asking structured questions of party state. We are using the same architectural habit here. The badge-gated move asks structured questions of inventory, flags, party data, map tile behavior, and script state, then routes through a controlled continuation.

For your minimal clone, I would implement this as a small set of contracts. The party module can answer, “Do we have a usable move?” The event module can answer, “Is badge flag set?” The map module can answer, “Is the faced tile cuttable, surfable, strength-pushable, or otherwise interactable?” The script module can run the success or failure branch. The field-effect module can animate or mutate the map. The save module persists only the durable facts: flags, variables, inventory quantities, party data, player position, and map object state that must survive reload.

Let’s test that with a concrete example. The player faces a small tree. They select Cut from a party member. The party check passes because a creature knows Cut. The badge flag check passes because the relevant gym flag is set. The tile behavior check passes because the tile in front is marked as cuttable. The field effect runs the animation, replaces or hides the tree, and sets a local or global event flag so that the tree remains gone if that is the intended rule. If any check fails, the system should fail at the right layer with the right message. No badge? That is a progression failure. No move? That is a party failure. Wrong tile? That is a map interaction failure. Same button press, different architectural cause.

Pause there and ask yourself: where would a bug appear if you collapsed all of that into one function? You would probably consume or mutate state too early. You might play the animation before proving the badge requirement. You might make the tree disappear without setting the persistent flag. You might allow the move from the bag but not from the party menu because the two paths duplicated slightly different checks. Those are not cosmetic errors. They are architecture errors, because the same world rule is being represented in multiple inconsistent places.

This also connects directly to the week 18 assessment. At this level, I am not looking for a toy inventory demo that subtracts one from a count and prints “used potion.” You should be able to design minimal clone versions of map loading, script execution, party data, battle turns, item use, and save persistence, and show how they cooperate. For item use specifically, I want to see context-sensitive dispatch, not just a switch statement with effects. The switch may exist, of course, but it should route into modules that own the relevant state.

One last source connection before we close. The broader FireRed codebase reinforces this cross-module pattern. The battle utility area includes event-data dependencies, as visible in pokefirered/src/battle_util.c, chunk_9335e5727aa0657d, because battle-visible behavior can still depend on broader game facts. The battle setup source in pokefirered/src/battle_setup.c, chunk_494d132a59422c85, pulls together overworld, item, script, event data, field effects, and battle transition concerns. That does not mean everything is cleanly separated in a modern architectural sense. It means the shipped game is built out of cooperating state machines, data tables, globals, scripts, callbacks, and continuations. Our job in the clone is to preserve the useful boundaries while simplifying the implementation.

So the synthesis for today is this: an item is a player-held token, but item use is a negotiated event. The bag says what the player selected. The context says what kind of use is legal. The party says whether a creature can participate. The map says what the world geometry permits. The script system says how progression branches. The event-data layer says what remains true after the moment passes. And the save system makes those durable facts survive.

That is the bridge from this week to the larger course. In weeks one through sixteen, we decomposed the RPG into runtime shell, maps, scripts, party data, battle, inventory, UI, persistence, and link systems. In week seventeen, we practiced tracing behavior from records through globals, callbacks, tasks, scripts, structs, and concrete functions. Week eighteen makes that tracing more demanding because item use crosses boundaries on purpose. A potion, an escape rope, a key item, and a badge-gated field move are not four isolated features. They are four tests of whether your architecture can let a simple menu choice become a correct world event without putting the whole game into one function.

For next time, keep that phrase in mind: a correct world event. Not just a correct item effect. Not just a correct UI response. A correct world event means the visible behavior, the authored script, the runtime state, and the saved facts all agree. That is the standard your workshop implementation should meet.

## 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/abilities.ts
