# Items as Data and State

Lecture ID: lecture_w17_d01
Week 17, Day 1

## Objectives
- Trace FireRed gameplay from data records through globals, callbacks, tasks, scripts, structs, and concrete source functions.
- Connect week 17 material to the overall course plan.

## Transcript
All right, today we move into the inventory system, and I want you to notice the timing of this week in the course. We are not studying items because items are a cute side feature. We are studying items because they are one of the cleanest places in FireRed where data, persistent state, menu state, script-facing behavior, and battle-facing behavior all touch the same concept from different angles.

Last week, when we looked at battle AI and outcome routing, the center of gravity was decision flow. A trainer table or encounter table fed setup, battle state advanced under callback and task control, and then result values carried us back to the overworld. This week, the center of gravity shifts. We are still tracing the same architectural path, data table to globals to callback or task or script to visible behavior, but the object we trace is not a trainer, not an encounter, not a move decision. It is an item. And an item is deceptively simple. A Potion looks like a row in a table. Then it becomes a stack in the Bag. Then it becomes a row in a menu. Then it becomes a script condition, or a battle action, or a held-object effect, or a sellable commodity, or a key item with no quantity semantics in the ordinary sense.

So, let me put the first sentence of the day on the board: an item is not the same thing as an inventory entry. I’ll say that again, because if you blur these two ideas, the code will look messier than it is. An item is a record of static meaning. An inventory entry is a piece of mutable save-backed state that refers to that item. FireRed’s architecture depends on keeping that distinction mostly intact, even though the player experiences both as one thing called “the Bag.”

Now, if you look at the source focus for today, the important files are pokefirered/src/item.c, especially chunk_1b104a09a7f41ad7 for the broad item system, chunk_296b886a4f0b7cc8 for lookup and mutation flow, and chunk_352eff45b08b4413 for continuation of item support. On the UI side, pokefirered/include/bag.h, chunk_8f2c0bdfc3224a33, gives us the cross-module contract for Bag text, windows, yes-no prompts, money display, and helper functions. Those are not random support files. They show the central pattern for this week: item.c owns much of the semantic and mutation logic, while bag-facing APIs let the menu layer display and ask about that state without becoming the owner of the inventory rules.

Let’s start with the static side. In a creature RPG, item data records usually answer questions like: What is the item’s name? What is its price? What pocket does it belong to? Can it be used in the field? Can it be used in battle? What function handles the use behavior? What description should appear in the UI? What hold effect, if any, does the item imply? FireRed’s item system follows this old handheld-engine pattern very directly. Instead of loading flexible runtime JSON, it compiles item records and constants into the ROM. That fits what we discussed earlier in the course about generated data versus runtime-loaded data. FireRed’s runtime is not discovering a schema at startup. It is compiled against a set of item constants and data structures, and the game logic uses those constants as stable identifiers.

Here is the architectural consequence. When the player selects a Potion, the menu does not need to know the Potion’s healing value by reading the text “Potion” and interpreting it. It has an item ID. That item ID indexes static item data. Then the selected action routes through functions that know whether this item can be used now, whether it needs a party target, whether using it should decrement quantity, and whether control should return to the field, the party menu, the bag, or battle. The display text is one face of the item, not the item itself.

Let me connect that to earlier weeks without redoing them. In the battle weeks, we repeatedly traced stable IDs through different layers: move IDs, species IDs, trainer IDs, and status constants. Same story here. An item ID is a compact bridge between compiled data and runtime state. You should be hearing an echo of the trainer table work, the wild encounter input work, and the battle result storage work. The exact systems differ, but FireRed’s design habit is consistent: stable data identifiers, small global state records, and a set of callbacks, tasks, or scripts that interpret those records under the current mode.

Now, let’s move from item records to Bag state. This is the second key distinction. The Bag does not contain full item records. The Bag contains entries, usually item ID plus quantity, arranged by pocket. The item record says, “This ID is a Potion; it belongs in this pocket; here is its price and behavior.” The Bag entry says, “The player currently has 7 of that item in this pocket.” That separation matters because the same static item record can be referenced from many places: shops, field scripts, battle use logic, pickup systems, held item slots, and bag UI.

Imagine a concrete example. The player receives an Antidote from an NPC script. The script layer should not manually scan a UI list, insert a row, draw a window, and decide the stack limit. Instead, it should ask inventory logic to add item ID Antidote with quantity 1. The inventory logic determines the correct pocket from static item data, searches that pocket for an existing stack, checks quantity limits, and either increments the stack or creates a new entry if there is space. Then, later, the Bag menu can render the result. That is a healthy separation. Script says “award item.” Inventory says “can this be represented in save state?” UI says “how does the player inspect or select it?”

This is where pokefirered/src/item.c, chunk_296b886a4f0b7cc8, becomes important for today’s lecture. That chunk is part of the item lookup and mutation flow. The important claim is not merely that FireRed has add and remove functions. The deeper claim is that item mutation is centralized enough that different callers can rely on shared rules. A shop purchase, a field pickup, a script reward, and a use-from-Bag operation all need to agree on stack limits, pocket routing, and failure behavior. If they do not agree, you get the classic RPG bug where the UI says there is room, the script thinks there is room, but the actual save structure cannot hold the item.

Let me pause and check understanding. If I ask you, “Where is the quantity stored, in the item record or in the Bag entry?” the answer should be Bag entry. If I ask, “Where is the pocket classification stored?” the answer should be item data, or at least derived from item data. If I ask, “Why not let the menu directly mutate quantities?” the answer is because menus are temporary presentation state, while inventory mutation must obey save-backed rules that scripts, shops, battles, and field events all share. Good. That distinction is going to carry a lot of weight.

Now, I want to talk about globals, because this is an advanced class and we should not pretend FireRed is a pure domain model with dependency injection and neatly separated services. It is a Game Boy Advance C codebase. State is often global, or reachable through global pointers, or stored in task data arrays, or passed through script variables. We have already seen this with main callbacks in pokefirered/src/main.c, chunk_6cfd90f6d0136799, and task dispatch in pokefirered/src/task.c, chunk_3ffebc0341225936. The Bag and item systems participate in that same runtime shell. Menu interaction is not a blocking function call that returns a result in the style of a desktop app. It is spread across frames, callbacks, tasks, input handlers, and transient menu state.

So, the Bag UI is a facade in a very literal sense. It lets the player believe they are interacting with one object, “my Bag,” but under the hood the code is coordinating persistent inventory arrays, temporary cursor positions, text windows, yes-no prompts, money display, item descriptions, pocket tabs, and selected-item behavior. pokefirered/include/bag.h, chunk_8f2c0bdfc3224a33, is useful because headers show contracts. A header tells you what other modules are allowed to ask for. In this case, the Bag-facing interface includes text and window helpers, yes-no behavior, and money/menu helpers. That tells us that the Bag is not just a data structure. It is a mode of interaction.

Let me draw a simple flow on the board. Static item data points to item ID, pocket, price, use behavior, description. Save-backed Bag state stores item ID and quantity inside pocket arrays. Bag menu state stores selected pocket, scroll position, cursor row, and window IDs. Script or battle code calls item functions to add, remove, check, or use. Rendering code calls Bag window helpers to show names, quantities, descriptions, money, and prompts. Now, the important thing is that these boxes overlap in the player’s experience but should not be collapsed in your mental model.

Think about the difference between “Can I use this item?” and “Can I display this item?” Displaying an item is mostly a UI problem. You need a name, maybe a quantity, maybe a description. Using an item is a gameplay problem. You need context. Are we in battle? Are we in the field? Does it require a Pokémon target? Is the target fainted? Is the stat already maxed? Is this a key item that triggers a script rather than being consumed? Is this an item whose use is blocked in the current map or mode? Those checks do not all belong in the list renderer.

This point also links us to the party menu and summary screen. The packet notes pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, includes item-related headers such as item.h and constants/items.h along with party menu and battle-related headers. That is evidence of item behavior crossing into Pokémon inspection and party workflows. You do not need the summary screen to own the item database, but it must understand enough of the item interface to show or manipulate held item state. Likewise, pokefirered/src/battle_util.c, chunk_9335e5727aa0657d, includes item.h and constants/items.h alongside battle headers, move constants, abilities, hold effects, and battle move effects. That tells us items are not trapped inside the Bag screen. They are part of the battle semantics.

Now, I want to slow down on that word “semantics.” A quantity entry in the Bag is not semantic by itself. If I say item ID 13 quantity 3, the number 13 only becomes meaningful when interpreted against item data and constants. Then it becomes, for example, a healing item, or a Poké Ball, or a key item, depending on the table. And once that item enters battle, the meaning may be further interpreted by battle utility code. A held item with a hold effect is not merely an inventory object sitting in a list. It becomes part of the creature’s effective state during battle. That is why the battle utility chunk is a fair supporting citation here: pokefirered/src/battle_util.c, chunk_9335e5727aa0657d, shows item-related includes in the same compilation unit that handles battle utilities and battle constants. At architecture level, items are shared vocabulary across systems.

Let’s use a concrete example, and I’ll deliberately choose one that crosses layers. Suppose the player has a Potion in the Items pocket and opens the Bag from the overworld. The item record supplies the display name, description, pocket, and use function. The Bag state supplies that the player owns, say, three Potions. The Bag UI supplies the pocket list, cursor, windows, description panel, and input handling. When the player presses A and chooses Use, the UI does not heal blindly. It routes to item-use logic. That logic determines that a party target is needed. The game transitions into a party selection interface, and now item state meets party state. When the target is selected, the item effect function checks whether healing is legal and meaningful. If the target is already at full HP, the use should fail or produce an explanatory message without consuming the item. If the target is damaged and eligible, HP changes, then inventory decrements by one. Finally, the UI must update or close according to the current mode.

Notice the order there. You do not want to decrement first and validate later. That is one of the inventory mutation rules we care about this week. In game systems programming, especially in C with persistent save-backed arrays, mutation order is design. The correct rule is usually: identify item and context, validate capacity or eligibility, apply gameplay effect, then mutate inventory if the effect actually consumed the item. Some items are consumed on use. Some are not. Some actions select an item but hand off to a script. Some are blocked. So “remove one item” cannot just be tied to “the player pressed A.” It must be tied to successful use under the item’s rules.

Here is a check for understanding. Let’s say an Escape Rope is selected in a location where it cannot be used. Should the Bag UI remove it because the player chose Use? No. The player initiated an attempted use, but the semantic use failed. The mutation rule depends on successful, context-valid effect. Now ask the same for a Potion used on a fainted Pokémon, depending on the game’s rule set. Again, selection is not consumption. Consumption is part of effect resolution.

This is why I keep using the phrase “inventory mutation rules” rather than just “add and remove.” The hard part is not subtracting one from an integer. The hard part is making all callers agree on when subtracting one is correct. pokefirered/src/item.c, chunk_296b886a4f0b7cc8, is where we focus for lookup and mutation flow because that is where these shared policies become concrete source behavior rather than design slogans.

Now, let’s connect this to money, because money is also inventory-like but not item-like. The week context asks us to include money and menu helpers, and pokefirered/include/bag.h, chunk_8f2c0bdfc3224a33, is relevant here because the Bag interface is not only about item rows. It includes money display and menu support. Architecturally, money is a scalar resource, not a stack in a pocket. It appears in shops and certain menus, and it may be displayed near the Bag or related windows, but it is not a normal item entry. So we should not force it into the item table model. This is another advanced modeling lesson: similar UI does not imply identical domain representation. “The player owns 3 Potions” and “the player has 1200 money” may appear in adjacent menu surfaces, but one is a pocketed item stack and the other is a numeric save variable with its own formatting, caps, and transaction rules.

That distinction will matter in the lab. When you create an inventory model with pockets, stack limits, add and remove operations, and a Bag UI facade, I do not want your UI facade to become a god object. It should expose display and selection commands. It can ask for item names, quantities, descriptions, and whether to show money. But the rules for whether an item can be inserted, stacked, consumed, or rejected should remain in the inventory model or item service layer. If your list widget is the only place that knows the max stack size, you have already lost the architecture.

Now, let’s bring scripts into the picture. In FireRed, scripts are not just dialogue. They are how many world interactions express conditional progression and rewards. We saw script-facing behavior in earlier weeks with maps and event objects, and more recently with battle setup and result routing. The battle setup file, pokefirered/src/battle_setup.c, chunk_494d132a59422c85, includes item.h along with task, overworld, script, event data, and battle transition headers. That kind of include pattern is not proof of one single function by itself, but it is strong architectural evidence that item logic participates in world-to-battle orchestration. Items can affect field progression, battle entry, or special modes. Again, the item is not merely a row in the Bag screen.

Let me give you the mental trace I expect you to be able to perform by the end of today. Start with an item constant. Find its static data record. Determine its pocket and basic behavior. Then trace where the player’s current ownership is stored in the Bag state. Then trace how a script, pickup, shop, or use action calls into item mutation. Then trace how the menu reflects the new state through Bag windows and list rendering. Finally, if the item has battle or party relevance, trace how item.h and constants/items.h bridge into party screens, summary screens, or battle utilities. This is the same tracing muscle you used in week 16 for the complete RPG decomposition, just applied more narrowly and with higher precision.

I want to make one subtle point before we move on. The Bag UI is allowed to know about pockets. It has to. Pocket tabs, pocket names, scrolling lists, quantities, and descriptions are presentation features. But knowing that the current visible pocket is the Items pocket is different from owning the rule that Antidote belongs in the Items pocket. The first is UI state. The second is item classification. If you are building a clone, the test is simple: can a non-UI caller add an Antidote correctly without constructing a Bag screen? If yes, your separation is probably healthy. If no, your Bag UI is doing domain work.

That exact discipline also helps with save/load. We are not fully in the save module today, but remember the course arc. Runtime shell, maps, scripts, party, battle, inventory, UI, save, and link systems are not independent chapters. They are layers that repeatedly hand state to each other. A Bag entry must be saveable. A temporary cursor position usually does not need to be saved in the same way. A selected item ID might live briefly in a global or task data slot while a callback transition happens. Persistent ownership must survive power-off. Temporary menu selection must survive only long enough to complete the interaction. If you mix those lifetimes, bugs follow.

So, pause and answer this one mentally. The player opens the Bag, highlights the third item in the current pocket, then closes the Bag without using anything. What persistent gameplay state changed? Ideally, none. Maybe the engine remembers a pocket position for convenience, depending on implementation, but no item quantity should change, no party state should change, no script flag should change. Now the player uses a Potion successfully. What state changes? Party HP changes, Bag quantity changes, and the menu display must refresh. Those are different layers responding to one resolved action.

That is the level of precision we need this week. Not “the Bag stores items,” but “static item records define item meaning; Bag entries store ownership and quantity; menu state tracks temporary interaction; item functions enforce lookup and mutation; scripts and battle code call those functions rather than duplicating inventory policy.” Keep that sentence in your notes, because it is basically the spine of today’s lecture.

We will next move deeper into how pocket organization and stack limits shape the add-item and remove-item paths, and we will use the item.c chunks as our concrete anchor rather than treating inventory as an abstract array problem.

So let’s put pocket organization on the board as a separation of responsibilities. The item record says, “I belong to this pocket.” The save data says, “The player owns this many of this item.” The Bag UI says, “I am currently showing this pocket, this scroll position, this cursor position, and this selected item.” Those are three different claims. They may refer to the same item ID, but they are not the same state.

Now, why does FireRed bother with pockets at all? At the player level, the answer is obvious: usability. Potions, Poké Balls, key items, TMs, Berries, and held items would be painful to browse as one flat list. But architecturally, pockets are not only a visual grouping. They constrain storage behavior. They affect stack limits. They affect sorting expectations. They affect which commands are legal. They affect which UI affordances appear. A Key Item does not behave like a Potion. A TM does not behave like a Nugget. A Bike is not “used up.” A Potion is.

If I write on the board, item ID arrow item record arrow pocket, that is the static side. Then underneath it I write, bag pocket array arrow item slot arrow item ID plus quantity, that is ownership. And then underneath that I write, bag menu state arrow selected pocket plus cursor plus callback, that is interaction. The mistake many clone projects make, especially in first inventory implementations, is that they collapse all three lines into one object. They create a class called Item and put name, description, count, selected, usable, pocket, price, and UI color in the same place. That seems productive for the first afternoon. It becomes a structural problem the moment you need one Potion record but many save files, or one item definition but different quantities, or one menu view that can temporarily select an item without changing the item itself.

FireRed’s architecture is older C, so it does not express this separation through classes, but the separation is still very clear. The source focus for today gives us the trail. The item data and lookup behavior live in pokefirered/src/item.c, especially chunk_1b104a09a7f41ad7 for the item system, chunk_296b886a4f0b7cc8 for lookup and mutation flow, and chunk_352eff45b08b4413 for the continuation of item support. The public-facing Bag UI contract is exposed separately in pokefirered/include/bag.h, chunk_8f2c0bdfc3224a33, where the menu, text, windows, yes-no prompts, and money helpers are not pretending to be the item database. That split matters.

Let’s use a concrete example. Suppose the player receives five Poké Balls from a shop purchase. The shop does not need to know how the Bag draws its pocket list. The shop does not need to know whether the Ball pocket is currently open. It needs to ask inventory policy a question: can this item and quantity be added? If yes, mutate the Bag state. Then it needs to charge money and show text. The item system provides the item’s meaning, the Bag state stores ownership, and the menu helpers render the result. If the player is not in the Bag UI at all, the mutation still needs to be correct.

Now compare that to using a Potion from inside the Bag. The item ID is selected through UI state. The item’s record determines whether it is usable and what kind of use function or behavior it has. The party system receives the actual gameplay effect, because HP belongs to a creature, not to the item table. Then the item quantity is decremented only if the use succeeds. Finally, the display refreshes, because the same list row may now show a lower quantity or disappear if the quantity reaches zero. That is not one operation in one layer. It is a chain of responsibilities.

Check yourself here: if a Potion fails because the selected Pokémon is already at full HP, should the Bag quantity change? No. And notice how much architecture is hidden in that “no.” It means selection is not the same as commitment. It means previewing or targeting an item is not the same as consuming it. It means the mutation rule sits after successful resolution, not at the moment the cursor lands on the item. That is exactly the kind of rule your week 17 lab is trying to make you model: pockets, stack limits, add and remove operations, and a Bag UI facade that exposes display and selection commands without owning the core inventory policy.

Let me slow that phrase down: “Bag UI facade.” A facade is not fake. It is not unimportant. It is the front surface through which the player interacts with a deeper model. But it should not become the authority for everything. In FireRed terms, the Bag window API in pokefirered/include/bag.h, chunk_8f2c0bdfc3224a33, is a contract for drawing text, presenting windows, yes-no choices, and money-related menu helpers. That contract is related to inventory, but it is not identical to item truth. It is a user-interface boundary.

This is the same architectural pattern we have been tracing all semester. Earlier, when we talked about AgbMain and SetMainCallback2, we did not say “the game loop is the game.” We said the runtime shell dispatches the active mode. When we discussed tasks and RunTasks, we did not say a task is the feature. We said tasks are per-frame units of behavior that let a feature advance over time. When we examined encounter data and battle setup, we did not say the wild encounter table is the battle. We said data flows into runtime globals and then into a battle mode. Inventory follows the same course thesis: data table, runtime state, callback or task or script, visible behavior.

On the board, I’m going to draw the item path as five boxes. Static item record. Bag pocket entry. Operation function. Calling context. Visible result. Under calling context I’ll write three examples: field script, Bag menu, battle. Now, I want you to notice something subtle. The same item ID can travel through different contexts. A Potion in the Bag menu and a Potion selected in battle are not different item records. But their legal use context differs. The item record can contain fields that help classify usage, but the active mode still matters. In battle, timing, targeting, and turn rules matter. In the field, party selection and menu flow matter. In a shop, price and quantity capacity matter.

This is where the advanced learner has to resist overgeneralizing. You might be tempted to say, “I will make a universal UseItem function that handles everything.” That might sound elegant, but it often becomes a giant conditional tower. FireRed’s C code uses concrete functions and tables to route item meaning while still letting different systems own their own flow. The item.c chunks are our anchor precisely because they show that item lookup, price, effects, pocket classification, and mutation rules are centralized enough to be consistent, but not so centralized that the Bag UI becomes the whole game.

Let’s bring money into the picture, because money is a good stress test. Money is not an item quantity. You do not store “money” as a normal Bag item with an item ID and stack count. Yet the Bag and shop interfaces need money display helpers. That is why the bag interface chunk, pokefirered/include/bag.h chunk_8f2c0bdfc3224a33, is important. It tells us that inventory-adjacent UI has to coordinate with money display and menu prompts. But architecturally, money should not become “just another pocket” unless the game’s design really says it is. FireRed’s design treats it as a player resource, shown near inventory workflows, but not identical to item ownership.

A concrete shop example: the player buys one Escape Rope. The shop flow checks price. It checks whether the player has enough money. It checks whether the item can fit into the appropriate pocket. If those checks pass, it subtracts money and adds the item. If capacity fails, the player should not lose money. Again, the ordering matters. You can hear the rule even without reading a single line of assembly or C: never charge for an item that cannot be stored. The code must respect that gameplay invariant.

Now I’m going to ask a check-for-understanding question, and I want you to answer it in terms of state ownership. The Bag menu cursor is on an Escape Rope. The player presses A. A yes-no prompt appears: “Use this item?” Where is the selected item stored during that prompt? Is it in the item table? No. Is it in the Bag ownership slot? The item ID and quantity are there, but the temporary decision state is not. The temporary selection belongs to menu state, task data, or a callback-specific struct, depending on the exact screen flow. That is why we distinguish durable ownership from temporary interaction.

This distinction will become even more important tomorrow when we treat the Bag as a UI facade. Today, we are still grounding the item as data and state. Tomorrow we will focus more heavily on windows, cursor movement, and display commands. But you cannot understand the facade unless you already understand what it is shielding. It shields the rest of the program from the details of text windows and input flow, and it shields the inventory model from being polluted by transient cursor state.

Let’s connect to another source packet example briefly. The Pokémon summary screen includes item-related headers and constants, as shown in pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46. That does not mean the summary screen owns item definitions. It means the summary screen participates in item-related presentation and held-item behavior. The include list itself is evidence of cross-module contact: summary screen, item, constants, party menu, battle-related constants, and data. Advanced reading of source code is not only reading function bodies. Sometimes it is reading include boundaries and asking, “Why does this module need that contract?” In this case, a Pokémon summary screen must show or interact with held items, but the item record still belongs to the item system.

The same point appears from the battle side. pokefirered/src/battle_util.c, chunk_9335e5727aa0657d, includes item.h and constants for items and hold effects alongside battle, moves, abilities, weather, and Pokémon constants. That tells us held items are part of battle resolution, but they are not implemented as arbitrary Bag menu behavior. A held item in battle is a runtime modifier attached to a battler or Pokémon, with effects interpreted by battle utilities. The item’s static data helps define the effect, but the battle engine decides when that effect matters. We covered battle AI script pointer control and party-aware predicates recently, so I am not going to re-teach that machinery. I only want you to carry forward the same habit: identify the data source, identify the runtime owner, and identify the dispatcher that turns it into behavior.

Now let’s talk stack limits. Stack limits are one of those low-glamour rules that reveal whether your inventory model is real. If a pocket slot can hold ninety-nine of an ordinary item, then adding one Potion to ninety-eight Potions is simple. Adding five Potions to ninety-eight Potions is not simple if the design allows multiple stacks, because you might fill one stack to ninety-nine and then create another. But in many Pokémon-style inventories, ordinary items are represented uniquely within a pocket, with a bounded quantity, rather than allowing arbitrary duplicate stacks. The add-item operation therefore has to ask: does this item already exist in this pocket? If yes, can its quantity increase without exceeding the maximum? If no, is there an empty slot? That is mutation policy, not rendering policy.

Write this as pseudo-board logic, not code yet: first, resolve item ID to pocket. Second, find existing slot. Third, test quantity capacity. Fourth, if no existing slot, find empty slot. Fifth, commit mutation. Sixth, report success or failure. What you must not do is draw the item in the list and then infer the model from the drawn list. Rendering is downstream. The source focus in pokefirered/src/item.c chunk_296b886a4f0b7cc8 is useful for this part of the lecture because it is specifically about item lookup and mutation flow. That phrase “lookup and mutation” is exactly the pair we care about. Lookup answers what the item is and where it belongs. Mutation changes what the player owns.

Let’s use Rare Candy as a more interesting example. The item record tells the system this is a usable item with a particular field behavior. The Bag tells us whether the player owns any. The party menu or target-selection flow tells us which Pokémon is selected. The Pokémon system applies the level-up effect if legal. If it succeeds, inventory removes one Rare Candy. If it fails, perhaps because of a level cap or another rule in a modified game, inventory should not remove it. If you are building your lab model, you do not need all of Rare Candy’s creature logic, but you do need the shape of the transaction. A use operation may depend on another system, and inventory consumption should be tied to the resolved result.

That word “transaction” is useful, but we have to be careful. FireRed is not using database transactions. It is using ordered procedural logic. But conceptually, the player experiences the action as atomic: either the item use happened and the count changed, or it did not happen and the count stayed. A half-success is usually a bug. Imagine if a Potion disappeared but HP did not increase. Or HP increased but the Potion stayed. Both are state consistency failures. The first feels unfair to the player. The second creates duplication. Both come from placing mutation at the wrong layer or wrong time.

Let me give you a practical design rule for your own creature RPG architecture: inventory operations should return information, not just mutate silently. An AddItem-style operation should be able to report success or failure. A RemoveItem-style operation should fail if the quantity is unavailable. A CanAddItem query is sometimes useful before a purchase, but you must still handle failure at the actual add step, because state may have changed between query and commit. In a single-player GBA game, that race is less dramatic than in a server game, but the structure is still healthy. FireRed’s architecture is full of these small policy functions that allow scripts, menus, and battle code to call into shared behavior instead of copying rules.

Now, somebody might ask, “Where do scripts enter this?” Good. Scripts are the world-facing authoring layer. A map script or NPC script can give the player an item, take an item, check for an item, or branch based on inventory state. But the script should not manually scan pockets in script bytecode. It should call native commands or special functions that know the inventory model. This is the same pattern as trainer battles. We already studied trainer table structure and battle result storage, so we will not re-open those details. The important carry-forward is this: scripts express game progression, while engine functions enforce system policy. If an NPC says, “Here, take this HM,” the script owns the story moment. The item system owns whether the Bag can store it, how it is classified, and how the quantity is represented.

On the board, I’ll write: script intent is not storage implementation. That sentence is worth keeping. It protects you from putting too much procedural detail in content scripts. In a data-driven RPG, scripts should be powerful enough to express events, but not so responsible that every content author can accidentally implement a different inventory system.

Now let’s look at key items, because key items are where naive stack logic breaks. A Potion quantity is meaningful: five Potions means five uses. A Bicycle quantity is not meaningful in the same way. You own it or you do not. There may still be a quantity field in the slot structure, because the Bag slot representation is generic, but the gameplay interpretation is not identical. That means the item’s pocket or importance classification shapes how add and remove should behave. You usually should not have five Bicycles. You usually should not consume the Bicycle on use. You usually should not sell it. So the item record carries facts that downstream menus and systems interpret.

This is one of the deepest reasons item data records exist. They are not just labels for UI text. They are compact declarations of policy. Price, pocket, hold effect, field use function, battle use classification, importance, and related attributes let many systems ask the same item what it means. The specific FireRed item system in pokefirered/src/item.c chunk_1b104a09a7f41ad7 gives us that concrete anchor: items are not loose strings floating around the codebase. They are records that source functions can query.

Let’s do another check. If you add a new item called “Silver Charm” to a clone project, what systems should you expect to touch? You need a static item record with name, description, price or sell behavior, pocket, and use classification. You need constants or IDs so scripts and systems can refer to it. You need inventory add and remove behavior to work automatically if the item fits an existing category. You may need a field-use function if it does something in the overworld. You may need battle utility handling if it has a held effect. You may need UI text to display properly. But you should not need to hand-edit every Bag menu row. If your design requires custom UI code for every ordinary item, the data model is not carrying enough meaning.

Now notice how this connects to the larger course plan. Weeks 17 through 19 are our Items, Menus, and Party UI module. We are deliberately moving from battle-heavy architecture into player-facing management systems. That is not a downgrade in sophistication. Menu systems in RPGs are where data correctness, player feedback, and state transitions meet under very tight constraints. A battle bug is often obvious because something explodes visibly. An inventory bug can sit quietly until a save reload, a shop transaction, or a script reward exposes it. So we are increasing, not decreasing, our precision.

The recent week 16 homework and quiz asked you to decompose a complete creature-collector RPG into runtime shell, overworld maps, event scripting, creature data, battle, inventory, UI, save, and link systems. This week assumes you can already name those pieces. I am no longer satisfied with “inventory is a system.” I want you to say which functions own item lookup, which structs own quantities, which callbacks own menu flow, which scripts request item changes, and which UI helpers present money, messages, and yes-no choices. The assessment bar moves from decomposition to traceability.

Let’s return to pockets and quantities. A pocket is often implemented as an array with a fixed capacity. That fixed capacity is not only a memory decision; it is a design decision made visible through messages like “There is no room.” On the Game Boy Advance, fixed-size arrays are natural because memory is constrained and save serialization is simpler. You know how much space the Bag takes. You know how to write it into save data. You know how to scan it. In a modern engine, you might be tempted to use a dynamically growing list, and that is fine if your design supports it, but then you must decide whether the player can truly hold unlimited distinct item types. If not, you still have a capacity rule; you have only hidden it somewhere else.

A fixed pocket also gives us simple mutation invariants. Empty slots can be represented by item ID zero or a defined none value. Non-empty slots should have a valid item ID and a positive quantity. Quantities should not exceed the pocket’s stack limit. Items should be in the pocket their item record says they belong to. If your clone project permits an item to sit in the wrong pocket, the UI may still draw something, but your model is corrupted. The item record is the authority for classification; the Bag slot is the authority for ownership.

Now, I want you to imagine debugging a report from a player: “After using my last Antidote, the Bag cursor moved weirdly and selected the wrong item.” Where do you look? Not just at RemoveItem. You look at the mutation path and then at the UI refresh path. Removing the last item may compact the pocket list, clear a slot, or leave an empty slot to be skipped. The cursor state must respond. If the list shrinks from five visible entries to four, and the cursor was on the fifth, you need to clamp it. That is not an item data problem. That is UI state responding to model mutation. Tomorrow’s Bag facade lecture will spend more time here, but I want you to see the dependency now.

This is also why source boundaries matter. The bag header, pokefirered/include/bag.h chunk_8f2c0bdfc3224a33, represents functions other modules are allowed to call for Bag-related UI behavior. The item implementation chunks represent item policy and support. Other modules such as pokefirered/src/pokemon_summary_screen.c chunk_e8e17a42bbf17d46 and pokefirered/src/battle_util.c chunk_9335e5727aa0657d include item-related contracts because they need item facts in their own domains. That is healthy coupling: not no coupling, but directed coupling through headers and shared constants.

Let’s pause for a recap before we go deeper. Item records define meaning. Bag entries define possession. Pocket arrays define organization and capacity. Mutation functions enforce add, remove, and query rules. Calling contexts such as scripts, shops, battle, party screens, and Bag menus request operations. UI helpers display, confirm, and refresh. If you can keep those layers separate in your head, FireRed’s item architecture becomes much less mysterious.

Now, for the next step, we are going to trace a reward item from an NPC script into the Bag, because that path will let us connect scripts, item records, and mutation rules without drifting back into battle material. Keep your notes open to the five-box diagram: static item record, Bag pocket entry, operation function, calling context, visible result. We are going to walk that diagram in order, and I want you to listen for exactly where the state changes and exactly where it does not.

So imagine the script says, in ordinary design language, “give the player a Potion.” We are not going to re-teach the whole script VM today, because we have already spent weeks on maps and script dispatch, but we do need to remember one thing from that unit: the script is a calling context. It is not the owner of item truth. The script requests a mutation. The item system decides whether that mutation is valid.

Let me put that sentence on the board: the script asks; the inventory system enforces.

That distinction is small, but it is the kind of small distinction that keeps a large RPG from becoming impossible to reason about. If every NPC script manually knew where the Items pocket began, how many slots it had, how to stack quantities, how to reject overflow, and how to refresh the Bag display, then the game would not have an item architecture. It would have dozens or hundreds of little item implementations scattered through event content. FireRed avoids that. The event content can express intent, while the item module performs the actual inventory operation.

Now, in the five-box diagram, the first box is the static item record. For our Potion example, the static record says what a Potion is. The record gives the item its name, price, hold effect or field-use behavior where applicable, pocket assignment, description, and use-related function pointers or identifiers, depending on the specific item. The important point is that the record describes item identity and capabilities. It does not say, “the player currently owns three Potions.” That current ownership belongs somewhere else.

This is exactly the distinction we keep coming back to across the course: data records define possible world facts, while runtime state records define current world facts. Trainer tables defined possible trainer encounters, but the overworld and battle setup decided whether this trainer fight was happening now. Wild encounter tables defined possible species and probabilities, but the encounter runtime selected one concrete encounter. Battle result storage recorded what actually happened after battle. Here, item records define possible objects in the design space; Bag state records what the player actually has.

The source packet points us to `pokefirered/src/item.c`, especially `chunk_1b104a09a7f41ad7` for the item system and `chunk_296b886a4f0b7cc8` for item lookup and mutation flow. Those chunks matter because they place item identity and inventory mutation in one source module instead of making every caller reinvent the rules. That is the evidence for the architectural claim I am making here: FireRed treats item operations as shared system behavior, not merely as UI behavior and not merely as script behavior.

Now move to the second box: the Bag pocket entry. If the item record answers “what is a Potion,” the Bag entry answers “how many Potions are in this slot.” A typical Bag slot is not a full copy of the item record. It does not need to store the name, the description, or every use rule. It stores an item id and a quantity. That is enough, because the id can be used to look up the static record when the game needs display text or behavior.

Let’s do a quick board example. Suppose the player owns five Potions and one Escape Rope. In a naive system, you might imagine five separate Potion objects sitting in a list. FireRed’s Bag model is more compact than that. The pocket has an entry that is effectively “Potion, quantity five,” and another entry that is “Escape Rope, quantity one.” When the UI draws the Bag, it uses the item id to find the name “Potion,” and it uses the quantity to draw the count. When the player uses one Potion outside battle, the mutation logic reduces the quantity. If the count becomes zero, the slot can be compacted away, or treated as empty according to the pocket’s maintenance rules.

Check your understanding for a moment. If I change the Potion’s display name in the static item table, how many Bag entries need to be rewritten in the save file? None. Exactly. The Bag entry only points to the item id. The name comes from the item record at lookup time. But if I give the player one more Potion, does the static item record change? Also no. The player’s Bag state changes. That is the separation.

Now, third box: operation function. This is where the real rules live. A reward script should not simply append an item to an array. It should call a function that knows whether the item can stack, whether the relevant pocket has space, whether the quantity exceeds a limit, and whether special pocket sorting or compaction is required. The context research identifies `pokefirered/src/item.c chunk_296b886a4f0b7cc8` as the item lookup and mutation flow, and that is the chunk I would keep next to your notes for this part of the week. This is where we care about operations like “do we have this item,” “can we add this item,” “remove this item,” and “how many do we have,” not as abstract API slogans, but as concrete runtime gates.

In lecture language, an add operation usually has three conceptual phases. First, resolve the item id to its pocket. Second, search existing entries for a matching id that can accept more quantity. Third, if stacking cannot complete the operation, search for an empty slot in the same pocket. If neither path works, the operation fails and the caller must handle that failure.

That failure path is part of the architecture, not an annoyance. Think about an NPC trying to give the player an item when the Bag is full. The correct user-visible result is not silent deletion. It is also not corrupting the pocket by writing past capacity. The script needs a clean yes-or-no answer from the inventory layer. If the add succeeds, the script can display the received-item message and maybe play a fanfare. If the add fails, the script can tell the player there is no room. The operation function is the hinge between clean content logic and protected state.

Let’s make that concrete. Suppose an NPC reward script requests “add one Potion.” The function consults the Potion item id, determines that Potion belongs in the ordinary items pocket, then scans that pocket. If there is already a Potion stack with room, it increments that quantity. The visible result later is that the Bag shows one more Potion. If there is no Potion stack but an empty slot exists, it writes a new entry with the Potion id and quantity one. If there is neither stack room nor empty slot, it returns failure. Notice what did not happen. The script did not draw Bag windows. The script did not know the pocket capacity. The script did not copy the Potion description. The script did not decide how item quantities are stored. It only asked for a mutation.

Now, fourth box: calling context. In our example, the context is an NPC script. But the same item module has to serve many callers. Shops add items after purchase and remove money. Field item pickups add items and then set event flags. Party screens may consume evolution stones or healing items. Battle may consume held items or use items from a restricted battle menu path. The Bag UI itself may remove an item when the player tosses it or use it when the player selects a command.

This is why the module boundary matters so much. If each caller had its own add or remove rules, then the player could end up with different behavior depending on whether they obtained a Potion from a shop, an NPC, a pickup ball, or a debug script. FireRed’s structure pushes those contexts toward shared item operations. Again, the packet’s focus on `pokefirered/src/item.c chunk_1b104a09a7f41ad7`, `chunk_296b886a4f0b7cc8`, and `chunk_352eff45b08b4413` supports this: the item support code continues beyond mere table lookup into the functions that other systems rely on.

Let’s pause and connect this to last week’s assessment level. By week 16, you were already asked to decompose a complete creature-collector RPG into runtime shell, overworld maps, event scripting, creature data, battle, inventory, UI, save, and link systems. So I am not asking today, “what is a system?” You have already been assessed on that. I am asking a more advanced question: when two systems touch, which one owns the invariant? In this case, event scripting owns story intent. Inventory owns Bag correctness. UI owns presentation. Save owns persistence. That is the level of separation I expect in week 17.

Now let’s bring in the fifth box: visible result. The player sees text and menus. The player does not see an array scan. The player does not see a struct field assignment. The player sees “Received Potion,” or sees the Potion count in the Bag increase, or sees a failure message. That visible result is downstream of the mutation, not a substitute for it.

This is where `pokefirered/include/bag.h chunk_8f2c0bdfc3224a33` becomes important. The research packet identifies it as the Bag text, windows, yes-no, and money interface. A header like that is a cross-module contract. We talked in week 2 about headers as contracts, and this is a clean example: the Bag interface exposes operations other code can call without forcing those callers to know the private details of how the Bag screen draws windows or formats its money display. The Bag UI facade is a separate topic tomorrow, but we need the preview now. The inventory model can say “the player has this item.” The Bag facade can say “draw this item, ask for confirmation, show money, respond to selection.” Those are related, but they are not the same responsibility.

Let me ask you a check question. If the player opens the Bag and scrolls to Potion, has the player’s inventory state necessarily changed? No. Scrolling is UI state. Selection position is UI state. Window contents are UI output. The Bag pocket entries are inventory state. If the player chooses “Use” and the use operation succeeds, then inventory may change. That separation is why UI can be canceled without affecting the model.

And this is a place where advanced students sometimes overcorrect. You hear “UI facade” and assume the UI is shallow or unimportant. It is not shallow. On the GBA, the Bag screen has real responsibilities: window allocation, text printing, list movement, command menus, yes-no prompts, money display, palette and tile management, callbacks and tasks. But those responsibilities are presentation and interaction responsibilities. They should not become the authoritative definition of whether the player owns an item. That authority belongs to Bag state and item mutation functions.

Now, let’s trace our reward item end to end, slowly, as if we were debugging it.

The NPC script runs because the overworld script engine has reached that command sequence. The player presses A, the event object interaction begins, and the script says, in effect, “try to give item X quantity Y.” That command enters a C-side helper or special that eventually calls into item logic. The item logic receives the item id and quantity. It resolves the item’s pocket through the static item data. It checks current Bag state in the appropriate pocket. It finds either a compatible stack or an empty slot. It writes the new quantity or new slot. It returns success. The script then continues down the success branch, displaying the received-item message and possibly setting a flag so the reward cannot be claimed again.

Now, identify the exact state changes. First state change: Bag pocket entry quantity or slot contents. Second possible state change: script flag or event variable marking the reward as collected. The text window is not the same kind of state; it is transient UI state. The item record is not changed. The callback shell is not fundamentally changed, except insofar as text display may use callbacks or tasks to manage frame-by-frame interaction. The source-level path crosses systems, but ownership remains localized.

Let me say that another way, because it is a useful exam answer. A reward item is not “stored in the NPC.” It is also not “stored in the message.” The NPC script contains an instruction to request an inventory mutation. The durable result is stored in the player’s Bag data, and the one-time nature of the reward is stored in event state. The message is evidence to the player that the operation happened, not the operation itself.

Now, if we connect this to save persistence, the Bag state eventually has to be saved because it is part of player progress. The static item table does not need to be saved, because it ships in the ROM. This is the same ROM-versus-RAM distinction we have used repeatedly. The record for Potion is stable program data. The fact that Anthony’s save file has five Potions is save data. If you are designing your lab inventory model this week, this is exactly the split you should reproduce. Your item catalog can be loaded from fixed data. Your player inventory should be mutable state. Do not put ownership counts into the item definition file. That design seems convenient for the first five minutes and becomes painful as soon as you have shops, rewards, pickups, and saves.

Let’s also talk about quantities, because quantities are where item systems become less trivial. A stack limit is not only a UI display choice. It affects mutation logic. If the maximum stack is 99, and the player has 98 Potions, and an NPC gives five more, the add operation must decide whether partial addition is allowed. FireRed-style inventory operations typically want clean success or failure for a requested quantity, because callers need reliable branching. If the request is “give five,” success should mean five were added. Failure should mean the caller can show “no room” or avoid taking money. Partial mutation is dangerous unless the API explicitly promises it and all callers understand it.

Here is the concrete edge case. A shop purchase says, “buy ten Poké Balls.” If the Bag has room for only three, should the game take full money and add three? Obviously not. Should it take money for three without asking? Also no, unless the shop UI is designed around that. So the inventory add check must support the caller’s transaction semantics. The shop wants to know whether the full purchase can fit before committing money changes. That is why inventory functions often appear in pairs conceptually: check capacity, then perform mutation, or perform a mutation that atomically returns failure without changing state. The architecture has to protect the transaction.

The same idea appears in reverse for removal. If a script or menu says “remove one Escape Rope,” the item logic should verify that the player has one. If the quantity is greater than one, decrement. If the quantity becomes zero, clear or compact the slot. If the player does not have the item, return failure. Again, the caller should not manually scan the pocket unless it is inside the inventory module. Callers can ask questions. They should not own the structure.

Now let me point to a supporting contrast. In `pokefirered/src/pokemon_summary_screen.c chunk_e8e17a42bbf17d46`, the packet shows includes for `constants/items.h`, `item.h`, and party menu-related headers. That summary screen is not the item system itself, but it needs item knowledge because held items and item names appear in creature UI. This is a good reminder that item identity flows into many screens. The summary screen can display or interact with item-related information, but the existence of those includes does not mean the summary screen should become the owner of Bag mutation rules. It is a consumer of item services.

Similarly, `pokefirered/src/battle_util.c chunk_9335e5727aa0657d` includes `item.h` and item constants alongside battle headers, abilities, weather, and move effects. We are not going to reopen battle AI today, because that was last week’s topic, but we should notice the pattern: battle needs item information, especially for held items and battle effects, yet the item definitions remain shared. Battle is another calling context and consumer. It is not a separate universe with unrelated item ids.

Now I want you to sketch a call path in your notes. Start with “NPC reward script.” Draw an arrow to “inventory add operation.” Draw an arrow from there to “item record lookup for pocket and rules.” Draw another arrow to “Bag pocket array mutation.” Then draw an arrow back to “script success branch.” Then draw one more arrow to “message and event flag.” That loop is the architecture. Data lookup happens before state mutation. State mutation happens before success presentation. Success presentation happens before the player regains control.

Check for understanding: where would you put the fanfare sound in that path? After the successful add, in the presentation branch. Good. You do not play the fanfare before knowing the item was actually added. Where would you put the “this reward was already collected” flag? Usually after success, or in a success-controlled script branch, because setting it before the add would risk losing the item if the add fails. This is not just cleanliness; it is player-progress correctness.

That last point is especially important in creature RPGs because many rewards are unique or progression-relevant. A common item like Potion is forgiving. A key item, HM, fossil, or story item is not. If a script marks the reward collected but the Bag mutation failed, the player may be locked out of progress. So the item architecture is not merely about quantities. It is about making state transitions reliable at the boundary between content and engine.

Now, how does this connect to the week’s lab? You are building an inventory model with pockets, stack limits, add and remove operations, and a Bag UI facade that only exposes display and selection commands. I want your lab implementation to preserve the same discipline we are tracing here. Your item catalog should be static data. Your Bag should contain item ids and quantities. Your add function should return a meaningful success or failure. Your remove function should not allow negative quantities. Your UI should call model operations instead of editing arrays directly. If your UI button handler reaches into a pocket list and mutates quantities by hand, you have collapsed the model and facade layers.

Let me give you a design smell. If your code says something like, “when the player clicks the Potion row, directly subtract one from the row’s displayed quantity,” that is wrong at this level of the course. The row is a view of the state. The model owns the quantity. The UI should request “use item,” and then redraw from the updated model. That is how you avoid the classic bug where the screen says two Potions but the saved inventory says three, or the player cancels a prompt and the display has already changed.

The Bag header, again `pokefirered/include/bag.h chunk_8f2c0bdfc3224a33`, is useful because it reminds us that the Bag interface contains display and prompt machinery: text, windows, yes-no, money helpers. The fact that money appears near Bag UI helpers is not accidental. Shops are a place where inventory and currency form a transaction. You need the UI to display the player’s money and confirm a choice, but the state mutation still needs to be coherent: remove money, add item, or do neither if the transaction cannot complete. Tomorrow, when we talk about the Bag as a UI facade, we will lean into that. Today, keep it as an example of why item state cannot be reduced to a list menu.

Let’s make one more advanced connection. In a data-driven RPG, item ids are stable identifiers across systems. Scripts refer to them. Shops refer to them. Battle code refers to them. Party UI refers to them. Save data stores them. That means item constants are part of a cross-module language. The packet repeatedly shows `constants/items.h` included in modules such as daycare, summary screen, battle setup, and battle utility, including `pokefirered/src/daycare.c chunk_119931105f546346`, `pokefirered/src/pokemon_summary_screen.c chunk_e8e17a42bbf17d46`, `pokefirered/src/battle_setup.c chunk_494d132a59422c85`, and `pokefirered/src/battle_util.c chunk_9335e5727aa0657d`. Those includes are not the whole architecture, but they are evidence that item identity is shared language across gameplay modules.

That shared language is powerful and risky. It is powerful because one item id can connect data, scripts, UI, battle effects, and save state. It is risky because changing an item id casually can break every reference. This is why generated constants and fixed tables matter so much in older C game architectures. You are not passing around rich self-describing objects with runtime reflection. You are often passing small numeric ids with agreed meanings. The agreement is enforced by headers, tables, and disciplined lookup functions.

So, when you design your own inventory model, do not treat ids as throwaway array positions unless you also control migration and persistence. If the save file says item id 13, and tomorrow you reorder your item table so id 13 means something else, the saved inventory changes meaning. FireRed’s architecture assumes stable constants. That is part of the technical cost of a data-driven table architecture.

Let’s return to the reward path one last time and name the layers in order. Static item record: what the item is. Bag pocket entry: what the player owns. Operation function: how ownership changes legally. Calling context: why the operation is requested. Visible result: what the player sees after the operation. If you can trace those five without blending them, you can read almost every item-related flow in this week’s source focus.

And now, to transition us into the next part of today’s lecture, we are going to complicate the example. A Potion is easy because it is stackable, ordinary, and has a simple field use. Key items, TMs, berries, and money-adjacent shop operations expose more of the architecture. They force us to ask how pockets differ, how sorting is maintained, how use commands are chosen, and how the UI learns which commands are legal for the selected item. Keep the same five-box diagram visible, because we are not replacing it. We are going to stress-test it.

All right, so let’s stress-test it. Leave those five boxes on the board. I’m going to add a second row underneath them, and the second row is going to say: pocket policy, stack policy, command policy, mutation policy, and return policy. Those are not separate systems. Those are the ways the item system becomes interesting.

A Potion does not make us confront much of that. Its data record says, in effect, here is the item’s name, description, pocket, price, use behavior, and related metadata. The bag state says, here is how many Potions the player owns. The menu lets the player choose Use, Toss, Give, or whatever is legal in that context. The operation reduces quantity if the item is consumed. Then the visible result is HP restored, a message printed, and control returned to the right callback or script path.

But now imagine the cursor is on the Bicycle. Same five boxes. Data record, bag state, operation, calling context, visible result. However, the legal behavior changes. The Bicycle is not just “an item with quantity one.” It is a key item. That means the pocket policy changes, the command policy changes, and the removal policy usually changes. You may be able to register it, you may be able to use it in the field, but you should not be able to consume it like a Potion or sell it like a commodity. So if your clone inventory model simply stores item id and count, and then says, “well, all items have the same actions,” it is already below the sophistication of the FireRed architecture.

In the source focus for today, the important thing is that this distinction is not hard-coded only in the UI. The UI participates, but it is not the sole authority. In pokefirered/src/item.c, especially the item system material identified in chunk_1b104a09a7f41ad7 and the item lookup and mutation flow in chunk_296b886a4f0b7cc8, item identity is interpreted through accessor-style functions and mutation helpers. The record tells other systems what the item is, and then the bag and menu layers ask questions of that record. Is this item in the key item pocket? Is this item important? Is there a field use function? What is its pocket? What is its price? What does it do in battle? Those questions are what turn a flat item id into behavior.

Now, pause on that phrase: “turn a flat item id into behavior.” That is one of the major course themes, going all the way back to our first pass over the engine shell. FireRed often stores compact ids, flags, indexes, and pointers, and then uses tables plus state machines to give those compact values meaning. We saw that with maps, where a map header is not the map by itself, but a compact gateway into layout, scripts, object events, music, and transitions. We saw that with encounters, where a wild encounter table does not fight the battle by itself; it feeds battle setup. We saw that with battle AI, where script pointer control and predicates create behavior from small command streams. Today, the same architectural pattern appears in inventory. Item id is the seed. The tables and stateful callers make it live.

Let me give you a concrete example, and I’ll talk through it slowly because this is exactly the kind of flow you should be able to reproduce in the week 17 lab. Suppose the player receives HM01 from an NPC. We are not going to re-teach the whole script engine here, but recall the shape: an event script runs because the player interacted with an object event or crossed some scripted condition. That script requests an inventory mutation. The item system then has to answer, can the bag accept this item? Which pocket does it belong to? If the player already owns it, does the quantity increase, or is this effectively a unique possession? If the add succeeds, what message should the player see? If it fails, what message path should run?

That is data records through scripts through globals through visible output. The source packet’s battle_setup.c excerpt, pokefirered/src/battle_setup.c chunk_494d132a59422c85, is useful as a comparison point because it shows item.h, script.h, event_data.h, overworld.h, and battle-related modules living together in a transition-heavy file. We are not studying battle setup today, but that include pattern reminds us that these systems are not isolated silos. Scripts, overworld state, item ownership, and specialized transitions all need shared contracts. Inventory is one of the bridges.

Now watch the bag side. When HM01 is added, the bag mutation code cannot just append blindly. It has to locate the correct pocket. It has to respect capacity. It has to respect quantity rules. It has to maintain the pocket in a form the UI can later display. This is why our lab asks for pockets, stack limits, add and remove operations, and then a UI facade. If you build the display first and store everything as an array of strings, you will have painted yourself into a corner. The architecture wants mutation correctness beneath display convenience.

I’ll put a small pseudo-structure on the board. Not source code, just a model. ItemRecord: id, name, pocket, price, importance, fieldUse, battleUse, description. BagPocket: item slots, capacity, maybe max quantity rules. ItemSlot: item id and quantity. BagUI: display pocket, display description, ask yes or no, show money, return selection. Now, notice the dependency direction. The UI may read item records. The UI may request an operation. But the UI should not become the only place that knows whether an item stacks or where it belongs.

That dependency direction is reinforced by the bag interface called out in pokefirered/include/bag.h chunk_8f2c0bdfc3224a33. The research packet describes that header as the bag text, windows, yes-no, and money interface. That is a cross-module contract. And remember our week 2 language: headers in this codebase are not decoration. They are promises between modules. A bag header that exposes text windows, yes-no prompts, and money helpers is telling you that the bag is not just a data container. It is also a controlled facade for player-facing inventory interaction. But because it is a facade, not the root truth, it should ask the item and save-state layers for facts rather than inventing them.

Check for understanding here. If the cursor is on a Potion and then on a Bicycle, what should change first in your mental model? Not the sprite. Not the text window. The item record interpretation changes. The item id maps to a different pocket, different command set, and different use semantics. The UI is responding to item metadata and bag state. If you said “the menu changes,” that is visible and true, but it is one layer too late for an architectural answer.

Now let’s add TMs and HMs, because these are excellent stress tests. A TM-like item has identity as an item, but it also points into another domain: moves. That means the item is not only inventory data. It is inventory data with a bridge to the creature and move systems. This is where the earlier weeks start paying rent. We do not need to re-teach learnsets today, but we do need to remember that a creature can or cannot learn a move based on structured creature data and rules. So a TM use flow has to answer at least three questions. Does the bag contain the item? What move does the item represent? Which party members are eligible targets?

You can see the broader source pattern in the packet’s pokemon_summary_screen.c excerpt, pokefirered/src/pokemon_summary_screen.c chunk_e8e17a42bbf17d46. That file includes constants/items.h and item.h alongside pokemon.h, party_menu.h, constants/moves.h, and summary screen modules. Again, don’t memorize the include list as trivia. Read it as architecture evidence. Items, moves, party data, and UI screens touch because the player experience touches all of them. A held item, a TM, or a party selection screen does not respect our neat lecture boundaries.

So when a TM is selected, the UI cannot simply say, “Use item, decrement quantity.” It may need to open a party menu or another selection interface. It may need to show compatibility. It may need to call into move-learning logic. It may need to return to the bag if canceled. And if the move is learned, the item mutation may happen only after the learning operation completes successfully. That is return policy. Very important. You do not consume the TM merely because the player opened the menu. You consume it, if the generation’s rule says it is consumable, after the irreversible operation succeeds.

Let’s connect that to tasks and callbacks, without reopening week 1 from scratch. The runtime shell gives you per-frame dispatch through callbacks and tasks. Menus and transitions often become small state machines. We saw this explicitly in the learn_move.c research excerpt, pokefirered/src/learn_move.c chunk_af3598df6f092723, where the comments describe a move relearner state machine and list menu tasks listening to button input. That excerpt is not the bag source, but it supports the same point: FireRed frequently handles complex UI flows by breaking them into callback and task-driven stages. Inventory use is not an exception. When an item opens a party menu, a yes-no prompt, a money display, or a move-learning screen, it is entering the same family of staged UI control.

Here is the concrete trace. Player opens the bag. Main callback and tasks are now in a menu-oriented mode rather than normal overworld walking. The bag display reads a pocket from save-backed bag state. The cursor selects a TM. The item record says this belongs to the relevant pocket and has a use behavior. The bag facade prints the item description and exposes commands. The player chooses Use. The use function or use flow transitions to a party selection screen. The party screen checks creatures against the move rule. A selected compatible creature enters the learn move flow. That flow may itself show move replacement if the moveset is full. Only after the result is accepted should bag mutation occur, and only according to the item’s rules. Then control returns to the correct UI or overworld script continuation.

Notice how many modules we just crossed without hand-waving. Item table. Save-backed bag state. Bag UI facade. Party menu. Creature data. Move learning. Task and callback state. This is why week 17 belongs after battle and party architecture, not before it. Inventory looks simple when you call it “a list of items.” It becomes a serious engine subsystem when the items are allowed to call into the rest of the game.

Now, berries. Berries teach a slightly different lesson. A berry is more ordinary than a key item in one sense, because it can have quantities. But berries also often have specialized pockets, sorting expectations, planting or field interactions in related games, and battle or held-item effects. In FireRed’s architecture, even when a berry is just displayed and counted in the bag-like interface, it still participates in the item record model. If a berry can be held, used, sold, or checked in some special UI, then the item table and pocket state need to carry enough information for those operations.

The packet’s battle_util.c excerpt, pokefirered/src/battle_util.c chunk_9335e5727aa0657d, is helpful here because it includes item.h and constants/items.h together with hold effects, battle constants, abilities, moves, and battle scripting modules. That is a source-backed reminder that items are not confined to the overworld bag. Held items and battle item effects must be interpretable by battle utilities. The bag is where the player views and changes ownership; battle is another caller that reads item meaning. Same item id, different caller, different visible behavior.

Let me ask a sharper check. If a held berry activates during battle, is the bag UI involved? No. The item system is involved, item constants are involved, battle utilities are involved, creature state is involved, but the bag window facade is not the actor. This distinction matters because students often over-attach item behavior to the inventory screen. The inventory screen is only one consumer of item data. The battle engine, party menu, shops, scripts, daycare, summary screen, and field use code can all become consumers.

We even see this breadth in pokefirered/src/daycare.c chunk_119931105f546346, where the excerpt includes constants/items.h, party and storage-related headers, menu helpers, scripts, event data, and Pokémon data. Daycare is not today’s item focus, but it demonstrates the general FireRed style: gameplay subsystems include the contracts they need and cooperate through shared data structures and helper APIs. Items can appear as fees, held objects, mail-adjacent behavior, party interactions, or menu prompts depending on the feature.

Now let’s talk about money-adjacent shop operations, because they expose a different kind of state boundary. Money is not an item, but the bag UI often needs to display it or reason near it. Buying and selling use item records, bag capacity, quantities, and prices, but the player’s money is a separate resource. That separation is healthy architecture. If you treat money as “just item zero with a giant count,” then shop code becomes awkward, display becomes awkward, and save semantics become awkward. FireRed’s bag.h chunk_8f2c0bdfc3224a33 being identified as covering money and menu helpers is exactly the clue we need: the bag-facing UI can expose money display helpers without collapsing money into the bag pocket model.

So, for a shop purchase, trace the five boxes with the second row added. Item record: the shop entry points to an item id, and the item record provides price and pocket. Bag state: does the player have room for the purchase, and if the item stacks, can the existing slot absorb the quantity? Operation function: add item, subtract money, or reject safely. Calling context: shop script or shop menu, not ordinary field use. Visible result: money display updates, quantity appears in bag, shop text confirms purchase, or failure text explains the constraint.

Here is the subtle part. The order of validation matters. In a robust design, you do not subtract money and then discover that the bag is full. You check affordability and bag capacity before committing. Or, if the code structure stages the operation, it needs a rollback-safe order. This is not just a FireRed trivia point. This is the same transactional thinking you use in server code, database writes, and simulation engines. Inventory mutation is a transaction over small embedded-state structures.

Let’s do a board cue here. I’ll write “validate, then commit, then report.” Under validate: item exists, pocket exists, capacity, quantity bounds, money if relevant, context legal. Under commit: modify bag slots, modify money, maybe set event flag, maybe update party item, maybe consume quantity. Under report: update windows, play sound, print message, return to callback or script. That three-step pattern is not a literal single function in every case, but it is the mental model that keeps you from writing fragile inventory code.

Now, where do globals enter? FireRed’s bag state is save-backed, so the player’s inventory is not an ephemeral local variable owned by the menu. The menu has cursor state, scroll state, window ids, selected item ids, and task data. The bag ownership lives in persistent game state. That is why mutation helpers matter. They prevent every caller from inventing its own way to poke at the save structure. In a C codebase with global pointers and module-level state, helper functions are a discipline mechanism. They do not make the architecture purely object-oriented, but they create boundaries: get item metadata here, check bag capacity there, add through this helper, remove through that helper, display through the bag facade.

This connects directly to your week 17 homework. At this point in the course, a minimal clone inventory cannot be a loose list with a print function. Earlier labs and quizzes already checked whether you can decompose the RPG into runtime shell, overworld, event scripting, party data, battle, inventory, UI, save, and link systems. So now the bar rises. I expect your inventory model to encode pockets as real policy boundaries. I expect stack limits. I expect add and remove operations to fail without partial corruption. I expect the UI facade to expose display and selection commands, not unrestricted mutation of the underlying array. And I expect you to be able to trace one example from data record to visible behavior.

Let me phrase that as a design test. If I ask, “What happens when the player tries to receive a second copy of a key item?” your architecture should have an answer. Maybe the game never does that through content, but the operation should still behave coherently. If I ask, “What happens when the player buys ninety-nine Potions while already holding fifty?” your stack and capacity rules should answer. If I ask, “What happens when the selected item opens a party menu and then the player cancels?” your return policy should answer. The UI text is the least interesting part unless the state is correct.

Now we should distinguish two forms of legality: static legality and contextual legality. Static legality comes from the item record. A key item is important. A TM points to a move. A Potion is consumable. A battle-only item may have battle use metadata. Contextual legality comes from where the request is made. An Escape Rope might be a field-use item, but it is not legal in every map context. A battle item might be legal during battle but not from the field bag. A held item can be given from a party-related menu but may have link or battle restrictions. The record says what the item is capable of; the caller says whether that capability is currently allowed.

That distinction is visible across the research packet. The pokemon_summary_screen.c chunk_e8e17a42bbf17d46 brings item.h into a creature summary context. The battle_util.c chunk_9335e5727aa0657d brings item.h into battle interpretation. The learn_move.c chunk_af3598df6f092723 brings menu state machines into move selection. The item.c chunks for this week, chunk_1b104a09a7f41ad7, chunk_296b886a4f0b7cc8, and chunk_352eff45b08b4413, are where item records and mutation support live. Same item domain, multiple callers.

Check yourself on this: if two modules ask about the same item id and get different allowed actions, does that mean the item table is inconsistent? Not necessarily. It may mean the context differs. The field menu, battle engine, party menu, shop, and script system are allowed to have different command policies. What would be bad is if they each duplicated item identity rules in incompatible ways. That is what lookup helpers and shared constants are meant to prevent.

Let’s return to the five-box diagram and update it one more time. Item data record is not only descriptive; it is a dispatch hint. Bag state is not only storage; it is persistent ownership with pocket constraints. Operation functions are not only add and remove; they are validation and transaction boundaries. Calling context is not incidental; it selects the legal command set and return path. Visible result is not only text; it is the player-facing evidence that all the hidden state transitions happened correctly.

That is the architectural lesson of items as data and state. The item table gives the game vocabulary. The bag gives the player possession. The UI gives the player controlled access. Scripts, battles, shops, and party screens give reasons to touch that possession. And the helper functions keep those touches from becoming random writes into global save memory.

For the next part, keep your eye on the facade idea. We have been talking about the bag as though it were half state container and half screen, but FireRed is more disciplined than that phrase suggests. The bag interface gives us windows, descriptions, prompts, money display, cursor behavior, and selection flow, while the item and save helpers remain responsible for the facts of ownership. So next we will narrow from “items as data and state” into “the bag as a UI facade,” and we will ask exactly what the screen is allowed to know, what it is allowed to change, and what it must delegate.

Now, the useful question is not, “Is the bag state or is the bag UI?” The useful question is, “At each boundary, which module is allowed to know which fact?” That is the advanced architectural question. If we answer it carefully, the whole inventory system becomes much less mysterious.

Look at the board for a moment. I am going to draw three boxes, left to right. The left box is item definition data. That is the record for Potion, Escape Rope, Poke Ball, Town Map, TM case entries, berries, and so on. The middle box is possession state. That is what the player actually owns: item id, quantity, pocket, slot. The right box is interaction state. That is what the player is currently looking at: which pocket is open, which row is highlighted, whether a yes-or-no prompt is visible, whether the money window is being drawn, whether we are choosing a party member for a medicine item.

The mistake beginners make is to collapse those boxes. They say, “The bag contains items.” That is true in ordinary speech, but it is not precise enough for architecture. The item table contains item meanings. The save block contains ownership. The bag screen contains a temporary view of ownership and a set of commands. FireRed keeps those mostly separated.

We can see the separation in the source focus for today. In pokefirered/src/item.c, chunk_1b104a09a7f41ad7, the item system defines the global pocket layer through gBagPockets and initializes pocket pointers into save memory with SetBagPocketsPointers. That is important. gBagPockets is not a fresh independent inventory database. It is a runtime view over the save-block arrays: items, key items, Poke Balls, TM/HM, and berries. So when the code says “bag pocket,” you should hear, “a small runtime descriptor pointing at a region of persistent player ownership state.”

Now contrast that with pokefirered/include/bag.h, chunk_8f2c0bdfc3224a33. That header exposes InitBagWindows, BagPrintTextOnWindow, ShowBagWindow, HideBagWindow, OpenBagWindow, CloseBagWindow, GetBagWindow, BagCreateYesNoMenuBottomRight, BagCreateYesNoMenuTopRight, BagPrintMoneyAmount, and BagDrawTextBoxOnWindow. Notice what is absent from that interface. It does not say AddBagItem. It does not say RemoveBagItem. It does not say SetPotionQuantity. It does not expose raw save slots. The bag facade is about presentation and menu conversation. Windows, text, prompts, money rendering. That is a different surface from possession mutation.

So if I ask you, “Where should the code enforce the 999 item stack cap?” the answer should not be “wherever the bag list happens to draw quantity.” Drawing is too late and too local. The cap belongs in the mutation layer. And that is what we see in pokefirered/src/item.c, chunk_296b886a4f0b7cc8, where CheckBagHasSpace and AddBagItem inspect the pocket, find an existing slot for the item, read the stored quantity, and accept the addition only if the resulting count is within the allowed stack limit. RemoveBagItem does the symmetric job: locate the slot, verify enough quantity, subtract, and clear the item id when quantity reaches zero. The screen can ask for a quantity to toss. The mutation function decides whether the state change is legal.

Let’s make that concrete. Suppose the player finds five Antidotes in a field item event. The script layer does not need to know the Antidote’s display description. It does not need to know where the bag draws the quantity text. It only needs an item id and a count. The mutation path asks, “What pocket does this item belong to?” That goes through ItemId_GetPocket, which reads the item record. Then the bag state layer looks at the corresponding BagPocket, which points into save memory. If an Antidote slot exists, it reads the quantity through GetBagItemQuantity. If the quantity plus five fits, it writes the new quantity through SetBagItemQuantity. If no slot exists, it asks BagPocketGetFirstEmptySlot. If there is no empty slot, the transaction fails.

Pause there. That word “transaction” is not in the C code as a fancy database abstraction, but conceptually that is what we want you to see. AddBagItem should either leave the player with a valid new inventory state or report failure. It should not half-add a quantity, forget the pocket constraint, and then ask the UI to clean things up. That is why your week 17 lab asks you to build add and remove operations in the model, not in the rendered list component.

Now, check your understanding. If the player opens the bag and tosses three Antidotes, which part should actually subtract three from the save-backed quantity? Not the text box. Not the yes-or-no menu. Not the cursor. The UI can collect the player’s choice. The state helper should perform the subtraction. In FireRed terms, the bag UI can use prompt helpers like BagCreateYesNoMenuBottomRight from pokefirered/include/bag.h, chunk_8f2c0bdfc3224a33, but the ownership change belongs to RemoveBagItem in pokefirered/src/item.c, chunk_296b886a4f0b7cc8.

There is a subtle detail here that is worth calling out because you are advanced enough now to appreciate why it matters. Quantities in the bag are not just plain exposed numbers. In pokefirered/src/item.c, chunk_1b104a09a7f41ad7, GetBagItemQuantity and SetBagItemQuantity apply the save encryption key when reading and writing bag item quantities. This means a direct write to the quantity field is not just poor style. It can be wrong. It can corrupt the logical meaning of the value. So the helper function is not merely an aesthetic abstraction. It preserves a storage invariant.

That pattern should remind you of earlier systems in the course. When we studied party data, we did not treat every field as a free public variable. Some values were packed, derived, validated, or recalculated. When we studied battle outcome routing, we did not say, “Just set some random global and hope the overworld knows what happened.” We traced the result through specific state variables and callbacks. Same idea here. Inventory state is simple compared to battle, but it still has invariants: valid item ids, valid pockets, valid stack sizes, encrypted quantities, special key item unlocks, and empty-slot compaction.

Let me underline “special key item unlocks,” because this is one of those places where a data-driven system still needs game-specific rules. In AddBagItem, FireRed has special handling for TM Case and Berry Pouch behavior. In pokefirered/src/item.c, chunk_296b886a4f0b7cc8, when adding a TM/HM pocket item, the code can ensure the TM Case exists in the key item pocket; when adding berries, it can ensure the Berry Pouch exists and set the related flag. That is not window code. That is not list rendering code. It is a possession rule with progression consequences. A player-visible UI effect follows from it, but the invariant itself belongs in the item system.

Now, I want to connect this to the item records themselves. The item record does not say, “The player owns three of me.” It says what an item is. In the item lookup continuation in pokefirered/src/item.c, chunk_352eff45b08b4413, the accessors read gItems through SanitizeItemId and expose fields such as name, price, hold effect, description, importance, pocket, type, field use function, battle usage, battle use function, and secondary id. That is a very compact architecture. The item id is the join key. The same item id can be used to retrieve display text, shop price, pocket assignment, field behavior, battle behavior, and held-item effects.

So let’s trace a Potion, conceptually. The player owns some number of Potions because an item slot in the items pocket stores ITEM_POTION and an encrypted quantity. The bag screen displays “Potion” because it asks for the item name through the item lookup layer. It displays the description because it asks ItemId_GetDescription. It decides which pocket list includes that item because the item record says which pocket it belongs to. If the player chooses Use from the field bag, the item’s type and field use function determine whether the flow goes to a party selection screen and then to a use callback. If the player is in battle, the battle use function and battle usage fields matter instead. One id, multiple projections.

That projection idea is powerful. It is also how you should design your lab model. Do not duplicate the name, description, pocket, stack limit, and callback label into every owned item slot. An owned slot should be small. It should usually say, “item id, quantity.” Then the UI resolves the id against item definition data. The state model resolves the id against pocket and stacking rules. The behavior layer resolves the id against field or battle use hooks. Duplication feels convenient early and becomes a consistency problem later.

Here is a quick board check. I am writing three statements. First, “A bag slot knows the item’s description.” Second, “An item record knows the item’s description.” Third, “The bag UI can display the item’s description by asking through the item lookup API.” Which one matches FireRed’s shape? The second and third. Not the first. A bag slot should not become a bloated copy of the item database.

This is where the facade language becomes precise. A facade is not a fake module that does everything. It is a controlled surface that makes a subsystem usable without exposing all of its internals. The bag facade in include/bag.h gives other bag-menu code a way to work with windows and prompts without asking every caller to know window ids, tilemap behavior, text colors, and money rendering details. But the item module gives the legal state operations. So the bag facade is a UI facade, not an ownership facade.

Let’s compare that to the party and battle material, briefly, without reteaching it. In the battle AI lectures, we cared about script pointer control and party-aware predicates. The AI code asked questions about party state, status, and battle context through structured helpers rather than manually recomputing the whole battle model each time. Here, the bag menu asks questions about item state and item definitions through helpers. The domain is less dramatic, but the architecture rhymes: data table, runtime state, controlled query and mutation functions, then callbacks or tasks that turn it into player-visible behavior.

And we can see cross-module pressure in the source packet. The pokemon summary screen includes item-related headers and constants in pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, because held items and item descriptions intersect with party-facing UI. Battle utility code includes item and hold-effect headers in pokefirered/src/battle_util.c, chunk_9335e5727aa0657d, because battles need item effects and held-item logic. Those modules should not import the bag window API just to reason about items. That would be the wrong dependency. They need item meaning, not bag presentation.

Now consider money. Money is inventory-adjacent, but it is not just another item stack. The bag header includes BagPrintMoneyAmount in pokefirered/include/bag.h, chunk_8f2c0bdfc3224a33. That tells us the bag UI has a responsibility to display money in the correct window style. It does not imply money is stored as a normal bag slot. This distinction matters when you design your own systems. A shop screen may show money next to item choices, but that does not mean money should be an item in the items pocket. UI proximity is not data ownership.

Let’s do another concrete flow, this time from the bag outward. The player opens the bag, moves the cursor to an item, and presses A. The visible system needs the selected pocket and selected row. From that, it can get the item id using a position helper such as BagGetItemIdByPocketPosition, which appears in pokefirered/src/item.c, chunk_352eff45b08b4413. It can get the quantity through BagGetQuantityByPocketPosition. Then it can build a context menu appropriate to that item: Use, Give, Toss, Register, Cancel, depending on item type, importance, location, and context. If Use is chosen, the behavior should not be hard-coded as “Potion means heal” in the bag list renderer. The selected item id leads to ItemId_GetFieldFunc or ItemId_GetBattleFunc, again in the item lookup layer in pokefirered/src/item.c, chunk_352eff45b08b4413. The item record points to behavior.

That design gives the item system room to grow. Adding a new field-use item should primarily mean adding a new record and a use function, not rewriting the generic bag window machinery. Adding a new pocket changes capacity and routing, but it should not require the yes-or-no menu helper to know what a pocket is. Adding a new prompt layout changes the facade, not the ownership model.

Now, there is a small but revealing FireRed-specific constraint in the item code. The source comments in the mutation flow note that FireRed and LeafGreen assume a single stack of an item in the bag, while other games may check across stacks. We see that behavior around CheckBagHasItem, CheckBagHasSpace, and AddBagItem in pokefirered/src/item.c, chunk_296b886a4f0b7cc8. That is not just trivia. It defines the inventory model’s semantics. If your clone allows multiple stacks of the same item, then CheckHasItem cannot stop at the first matching slot unless your invariant says duplicates never occur. Either you enforce uniqueness on add, or you aggregate across stacks on check. Do not leave that ambiguous.

This is the level of rigor I expect in the week 17 homework. If you say, “My inventory has pockets,” I will ask, “Are duplicate item ids allowed within a pocket?” If you say, “Items stack to 999,” I will ask, “Where is that enforced?” If you say, “The UI removes the item,” I will ask, “Does the UI mutate the model directly, or does it call a model operation?” These are not pedantic questions. These are the questions that determine whether your inventory survives shops, field pickups, battle item use, held items, save/load, and menu redraws.

Let’s recap the chain in one pass. The item table defines what an item is. The item id is sanitized and used to retrieve name, description, pocket, price, type, and use callbacks. The save block stores what the player owns. gBagPockets gives runtime pocket descriptors pointing into that save-backed storage. Quantity helpers protect the encoded representation. Check, add, remove, sort, compact, and lookup functions maintain ownership invariants. The bag header exposes window, text, yes-or-no, and money helpers for presentation. Tasks and callbacks then stitch together player input, selected item ids, menu prompts, and item behavior functions.

If that chain is clear, you are ready for the next narrowing move. We are going to stop talking about the bag as if it were a container with some UI attached, and we are going to treat it as a screen facade sitting on top of the item model. That means we will ask, for every command on the bag screen, what data it reads, what state it may change, what it must delegate, and what it should never know.

So, let’s make that facade idea precise. When I say the bag screen is a facade, I do not mean “fake.” I mean it is a deliberately narrow surface. It allows the player to see, select, confirm, cancel, and route commands, but it should not become the authoritative owner of item truth. The truth lives in the item records and the save-backed bag state. The screen coordinates that truth.

If I were drawing this on the board, I would put three boxes from left to right. First box: item data. That is the static definition of what an item is. Second box: bag state. That is what the player owns right now, including pockets, item ids, and quantities. Third box: bag facade. That is windows, cursor position, text, prompts, money display, yes-or-no questions, and command routing. Now, under the third box I would write: reads model, mutates only through model functions, delegates behavior.

That last line is the important one. The UI does not get to say, “I know how many Potions fit in the medicine pocket, and I will rewrite the array myself.” It asks the item layer. That separation is visible in the source focus for today: pokefirered/src/item.c, chunk_1b104a09a7f41ad7, establishes the item system as a source-level center of gravity; pokefirered/src/item.c, chunk_296b886a4f0b7cc8, is where item lookup and mutation flow belong; and pokefirered/include/bag.h, chunk_8f2c0bdfc3224a33, exposes the bag-facing text, window, yes-or-no, and money interface. Notice the asymmetry. The bag header exposes presentation helpers. The item implementation owns item mechanics.

Let’s use a concrete example. Suppose the player opens the bag, moves to the medicine pocket, highlights a Potion, chooses Use, selects a party member, and the Potion is consumed. At the screen level, that looks like one action. Architecturally it is a chain. The pocket list displays an entry. The cursor selection resolves to an item id. The item id is looked up in the item data table, which tells the program what the item is and what behavior category it belongs to. The UI asks the player for confirmation or target selection. Then the actual use path checks whether the item can be used in this context. Only after the use succeeds should the quantity be decremented through the inventory mutation functions.

Now, pause there and check your intuition. If the player tries to use a Potion on a healthy party member, should the bag UI remove one Potion first and then let the party menu reject the action? No. That would violate the ownership invariant. The item is only consumed when the item behavior succeeds according to the rule path that owns that behavior. The facade can ask, “Which item? Which command? Which target?” It should not decide the semantic success of healing.

This is the same architectural pattern we have been tracing since the first week, just at a smaller scale. In battle setup, as seen in pokefirered/src/battle_setup.c, chunk_494d132a59422c85, the world does not become the battle engine. It gathers enough context to transition into battle and later receives the result. In the battle utility layer, pokefirered/src/battle_util.c, chunk_9335e5727aa0657d, item constants and battle state meet inside battle-aware logic. That is different from the bag screen merely painting a list. Same item id, different owner of the rule.

Let me say that again because it is one of the major design lessons of week 17. Item ids travel widely. Item authority does not. An item id can appear in the bag, in party summaries, in battle utilities, in daycare-adjacent code, in scripts, in marts, in held item fields, and in menu prompts. But the right to interpret that id depends on context. A Rare Candy in the bag screen is a selectable row. In a party-targeting flow, it is a possible command. In the creature model, it becomes an experience or level mutation. In save state, it is a quantity entry. In text, it is a name. In money helpers, it may be a sell price. These are not all the same operation.

You can see how broad the item id’s reach is from the include patterns in the research packet. The summary screen includes item support in pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, because held items and item names matter when inspecting a creature. Daycare code includes constants/items.h in pokefirered/src/daycare.c, chunk_119931105f546346, because item constants become part of larger gameplay systems. Learn-move code, in pokefirered/src/learn_move.c, chunk_af3598df6f092723, shows another menu-driven state machine that is not the bag but still uses the same callback, task, text-window style of architecture. That is the recurring course pattern: specialized systems, shared shell.

Now, for the lab this week, this matters because many of you will be tempted to build the inventory UI by directly storing item stacks inside widget state. That will work for maybe twenty minutes. It will fail as soon as you add sorting, selling, item use, registered key items, or save/load. The lab asks you to create an inventory model with pockets, stack limits, add and remove operations, and a bag UI facade that only exposes display and selection commands. That wording is not accidental. The facade should be able to say, “Render this pocket,” “move cursor,” “open command menu,” “show money,” “ask yes or no,” and “return the selected item id.” It should not be the place where stack compaction rules are invented.

Let’s put a small board example here. Imagine the player has three entries in the medicine pocket: Potion quantity 2, Antidote quantity 1, and an empty slot. The player buys one Potion. The model-level add operation should search for an existing Potion stack, verify the stack limit, increase the quantity, and preserve the compact representation. The mart UI should not scan the medicine pocket itself and increment a struct field. Why? Because the same add rule is needed for field pickups, NPC gifts, battle rewards, and scripted events. If every caller does its own version, your inventory becomes inconsistent in exactly the places players notice: item duplication, disappearing quantities, unsellable entries, and weird empty rows in the middle of a pocket.

Here is the check for understanding. If a script gives the player five Poké Balls, a shop purchase gives the player five Poké Balls, and a debug menu gives the player five Poké Balls, how many add-item implementations should exist? One. You may have three callers and three presentations, but they should converge on the same mutation rule. That is what we mean by inventory mutation rules being part of the model, not part of the facade.

Now connect this to callbacks and tasks. The bag screen still needs active state. It needs to know which pocket is open, where the cursor is, which window is visible, whether a message is printing, and which callback should run when the player exits. FireRed’s broader runtime pattern already prepared us for that. Earlier in the course, we traced SetMainCallback2 in pokefirered/src/main.c, chunk_6cfd90f6d0136799, and RunTasks in pokefirered/src/task.c, chunk_3ffebc0341225936. Today’s bag logic sits inside that same machine. The screen is not a blocking function that freezes the whole game until the player chooses something. It is a per-frame interactive state machine made of callbacks, tasks, windows, and small state transitions.

So when you read bag.h, chunk_8f2c0bdfc3224a33, treat it as a contract boundary. Window routines belong to presentation. Text routines belong to presentation. Yes-or-no prompts belong to presentation. Money display helpers belong to presentation. But when a command means “add this item,” “remove this item,” “does the player have this item,” or “which pocket does this item belong to,” you should expect to cross into item.c, especially the lookup and mutation flow represented by chunk_296b886a4f0b7cc8 and the continuation in chunk_352eff45b08b4413.

The advanced move is to notice that this is not merely clean code. It is how a cartridge-scale game survives complexity. FireRed has many surfaces that can touch items. The player can buy, sell, find, receive, use, hold, toss, register, and inspect items. Scripts need item predicates. Battle needs item effects. Party menus need item targeting. The save system needs persistence. The UI needs display names and quantities. If item behavior were scattered evenly across all those surfaces, the architecture would collapse under feature pressure. Instead, FireRed leans on tables, globals, structs, callbacks, tasks, and module contracts.

Let’s do one final trace, slowly. Static item record: what is this item? Save-backed bag state: does the player own it, and how many? Runtime pocket descriptor: where is the current list for this pocket? Bag facade: how do we display it and collect a command? Item lookup: what behavior should this item have? Context rule: can it be used here? Mutation helper: if the action succeeds, how does the stored quantity change? Callback return: where does control go after the action? That is the whole chain from data record to visible behavior.

And now we can place week 17 in the course map. Weeks 1 through 4 gave us the runtime shell, data generation, maps, scripts, and headers as contracts. The middle of the course gave us creature data, party state, encounter flow, and battle resolution. Weeks 15 and 16 sharpened the idea that a creature RPG is not one giant loop, but a collection of cooperating state machines. Week 17 moves into inventory, menus, and party UI. This is where the architecture becomes especially visible because items sit at the intersection of static data, persistent state, scripted rewards, shop economics, battle rules, and player-facing windows.

That is why I do not want you to think of the bag as “just a menu.” It is a UI facade over a durable model. The bag screen is allowed to be temporary. The bag state is not. The selected row is temporary. The player’s Potion count is not. A prompt window is temporary. The item definition table is not. A task id is temporary. The save-backed pocket contents persist. Good architecture keeps those lifetimes separate.

So, closing synthesis for today: FireRed’s item system is a compact example of the entire course thesis. Data records describe possibilities. Save-backed globals record ownership. Runtime descriptors make those records usable by the current screen. Helper functions preserve invariants. Headers define cross-module promises. Callbacks and tasks convert input into stepwise behavior. Scripts, marts, battles, and party menus all touch item ids, but they do not all own item truth. If you can trace a Potion, a Poké Ball, or a Rare Candy through that chain without losing track of who owns which decision, then you are doing architecture, not just code reading.

Next time, we narrow further into the bag as a UI facade. We will look less at what an item is and more at how the screen behaves: which windows exist, how commands are staged, how money and prompts are displayed, how selection state is carried, and how the facade hands control back to the rest of the game. For now, keep the central rule in your head: the bag presents inventory, but the item model protects inventory.

## Source References
- pokefirered/src/daycare.c
- pokefirered/src/pokemon_summary_screen.c
- pokefirered/src/learn_move.c
- pokefirered/src/battle_util.c
- pokefirered/src/battle_setup.c
