# Party Data Across Gameplay Screens

Lecture ID: lecture_w11_d01
Week 11, Day 1

## Objectives
- Decompose a complete creature-collector RPG into runtime shell, overworld maps, event scripting, creature data, battle, inventory, UI, save, and link systems.
- Connect week 11 material to the overall course plan.

## Transcript
All right, let’s pick up from where week 10 left us. By now, I am going to assume you are comfortable with the idea that a party member is not just a sprite, not just a species identifier, and not just a battle participant. We have already spent enough time on Pokemon and BoxPokemon representation, species tables, GetMonData-style access, stat calculation inputs, move slots, PP, and learnset tables that I do not want to re-teach those foundations today. Today we are going to use them.

The question for today is narrower and, architecturally, more interesting: what does it mean for the same party data to be seen, displayed, passed through menus, used in battle-adjacent flows, and eventually mutated by UI? That sounds simple until you trace it through a real GBA-era codebase. A player opens the party menu. They select a Pokemon. They view summary pages. They inspect moves. They back out. Maybe they enter a move relearner flow. Maybe they replace a move. Maybe they cancel. At every step, the game must know whether it is merely reading the party slot or actually changing it.

So the core distinction I want on the board first is this: observing party data is not the same as owning permission to mutate party data. Let me write that down. Board cue: “read view versus mutation authority.” Under that, I’ll write “summary screen” on the read side, and “move replacement confirmation” on the mutation side. That is the mental model for the first half of today’s lecture.

Now, this week sits at the end of our creature and party data model module. Weeks 9 through 11 have been moving from static records into runtime behavior. Week 9 gave us the creature record shape. Week 10 asked how battle stats and move eligibility are derived from that shape. Week 11 asks what happens when the rest of the game touches those records. This is also where the full course architecture becomes visible again. The party is not isolated. It crosses the runtime shell, the overworld, event scripts, creature data helpers, battle setup, inventory items, UI screens, save persistence, and link constraints. If your clone architecture treats the party as a small array and nothing else, you will get something working for a toy battle. But you will not get a game that can survive menus, scripts, fainting checks, item usage, move learning, daycare, trade, and save/load without accidental corruption.

Let’s use FireRed as our anchor. In the source focus for today, the summary screen appears in pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46. That chunk is useful before we even inspect individual functions because the include list tells us what this screen touches. It includes pokemon.h, pokemon_summary_screen.h, task.h, menu_helpers.h, link.h, overworld.h, item.h, party_menu.h, trade.h, battle_main.h, region_map.h, field_specials.h, and constants for moves, items, party menu, battle, and songs. That is not a random pile of dependencies. It is a map of the screen’s architectural position. The summary UI reads creature data, participates in the task system, respects link and battle contexts, draws menu text and graphics, and can be reached from multiple gameplay situations.

Pause there. If I ask, “Is the summary screen part of the creature data model or part of the UI system?” the correct advanced answer is: it is a UI system component that depends on the creature data model through a controlled interface. It should not be understood as the owner of creature storage. It is a reader, a presenter, and sometimes a dispatcher into other flows.

That distinction matters because screens in this architecture are state machines. We covered callback slots and tasks earlier in the course: AgbMain starts the runtime shell, SetMainCallback2 redirects the active top-level behavior, and RunTasks dispatches task logic per frame. I am not going to re-teach that, but I want you to bring it forward. A summary screen is not a blocking function call that prints a struct and returns. It enters a visual mode, schedules or runs tasks, responds to input over frames, and eventually yields control back to whatever invoked it. During that time, the party data has to remain coherent.

Here is a concrete example. Imagine the player opens the party menu from the overworld and chooses their Ivysaur in slot zero. The party menu knows the slot index. The summary screen needs to show species, nickname, level, current HP, stats, moves, PP, held item, origin data, maybe ribbon or region-related details depending on generation and screen page. The summary screen should not copy the Pokemon into a separate permanent creature record and then operate on that copy as if it were authoritative. If it did, any later mutation would raise a hard question: which record is real? The party array? The summary copy? A local work buffer? Instead, well-behaved UI reads from the party slot when constructing its display state, and only specific flows commit writes to the real party data.

Now, we need to be careful. “Read-only” does not mean “no state.” The summary screen absolutely has state. It has cursor state, page state, scroll state, window state, sprite state, background state, help context, and probably temporary buffers for text formatting. But those are UI state, not creature ownership state. Let’s make that distinction precise. Board cue: I’m drawing a vertical line. On the left: “Pokemon data: species, moves, PP, experience, stats, personality, ownership fields.” On the right: “Summary UI state: selected slot, active page, text buffers, windows, sprites, input mode.” The left side is game state. The right side is presentation and interaction state. Some functions bridge the two, but they should not casually merge.

You saw something related in earlier labs when you designed minimal clone versions of map loading, script execution, party data, battle turns, item use, and save persistence. Several of you implemented party inspection by handing UI code a direct mutable object. That is fine for a small assignment if nothing else can happen during the screen. But today we are raising the bar because the midterm is close, and because week 11 homework is going to expect a cleaner separation. The lab this week asks you to implement a party summary screen model that reads creature data without mutating it, then add a move-learning flow that mutates move slots only after confirmation. That is exactly the split we are analyzing in FireRed.

Let’s now connect summary viewing to gameplay screens more broadly. The same party slot might be referenced from the overworld party menu, from an item-use flow, from battle transition logic, from trade, from link contexts, or from script-driven NPC services. The screen has to answer: who invoked me, what may the player do here, and what should happen when they exit? This is why source files like pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, include not only pokemon.h but also link.h, overworld.h, party_menu.h, trade.h, and battle_main.h. The summary screen is a view over party data, but it is also a crossroads between systems.

Let me say that in architecture language. A party slot is a stable address within a gameplay-owned collection. A screen receives a reference to that address, usually as an index plus context, and builds transient interaction state around it. The context determines allowed transitions. For example, from ordinary party inspection you may be able to page left and right across party members. From a move selection flow, you may be constrained to inspecting moves. From a link or trade context, certain actions are disabled or redirected. So the slot identity is stable, but the affordances around that slot are context-sensitive.

Check for understanding. Suppose a summary screen shows the current move list for slot two. The player presses B and exits. What should have changed in the Pokemon record? Nothing. Maybe the active callback changed, maybe the task list changed, maybe VRAM and windows were cleared, but the creature’s moves, PP, stats, and held item should be identical. Now suppose the player enters a confirmed move replacement flow and chooses to replace move index one. What should change? The move slot and the corresponding PP-related data, and only after the confirmation path commits. That is the boundary.

This is where the move relearner becomes our second major case study. In pokefirered/src/learn_move.c, chunk_af3598df6f092723, the research packet identifies the start of the Move Relearner state machine. The excerpt explicitly frames it as “Move relearner state machine,” beginning with CB2_MoveRelearner_Init, list menu scroll positions, and a sequence of menu states. The important point is not just that there is a menu. The important point is that FireRed does not treat move relearning as “call TeachMove immediately when the player enters the screen.” It structures the flow as a state machine that gathers player intent, displays prompts, waits for input, checks conditions, and only then moves toward mutation.

That pattern is central to all serious creature RPG UI. Any gameplay screen that can mutate party data should be suspicious of premature writes. You do not decrement an item before the target is confirmed unless you have a rollback plan. You do not replace a move before the player confirms which move to forget. You do not alter a Pokemon’s state just because a menu cursor hovered over an option. Cursor movement is not commitment. Text display is not commitment. Eligibility checking is not commitment. Confirmation is commitment.

Let’s walk the move relearner conceptually, without getting buried in every state name yet. The relearner begins by entering a special callback-driven UI mode. It sets up list menu state so the player can browse candidate moves. It uses prior data, especially species and level-up move information, to decide what can be relearned. We covered level-up move data last time, so I am not going to rebuild that table logic here. Today, the point is that eligible moves become menu entries, menu entries become a player selection, and the player selection becomes a potential mutation. Potential mutation is still not mutation.

Now look at pokefirered/src/learn_move.c, chunk_e820ee15ae8caa6d. The research packet excerpt gives us the later confirmation path. It mentions MENU_STATE_TEACH_MOVE_CONFIRM, then says that if cancelled, the flow goes to setup battle mode, while if confirmed and the Pokemon has an empty move slot, VAR_0x8004 is set to TRUE and the flow goes to printing text then fanfare. If confirmed and the Pokemon does not have an empty move slot, it proceeds to the prompt about trying to learn the move, then confirmation about deleting an old move, then choosing which move to forget. That is a lot of ceremony around a single mutation, and the ceremony is the architecture.

Why does this matter? Because the UI is protecting the party record from ambiguous intent. If there is an empty move slot, the mutation is simple: add the selected move into that empty slot and update the related PP data. If all slots are full, the game must ask whether to forget an old move. If the player says no, the selected relearn move should not be written. If the player says yes, the UI must ask which old move to delete. If the player backs out there, again, the party data should remain unchanged. Only when the player selects the old move and confirms does the mutation become legitimate.

Let’s put that on the board as a timeline. “Browse candidate moves.” No mutation. “Select candidate.” No mutation. “Confirm teaching.” Still may be no mutation if full slots require another decision. “Choose old move.” Still potentially reversible depending on the exact prompt path. “Final confirmed replacement.” Mutation. This is what I want you to model in your lab. Not because FireRed’s exact menu state constants are sacred, but because the separation between intent collection and data commit is a durable design principle.

There is a subtle point here that advanced students often appreciate: the party slot is both an object of attention and a target of possible command. In the summary screen, the party member is mostly an object of attention. In move relearning, it becomes a target of command. In battle, it becomes an actor. In save, it becomes serialized state. In trade, it becomes transferable state with ownership implications. In link play, it becomes synchronized or constrained state. Same underlying creature record, different role depending on subsystem. A mature architecture does not need a different data model for each role, but it does need clear boundaries for how each subsystem may interact with that record.

This is why the course objective says we are decomposing a complete creature-collector RPG into runtime shell, overworld maps, event scripting, creature data, battle, inventory, UI, save, and link systems. Today’s topic is one of the best examples of decomposition not meaning isolation. The systems are separate enough to reason about, but they cooperate constantly. The summary screen sits in UI. It reads creature data. It is entered through runtime callbacks. It may be launched from overworld or menu contexts. It must respect link restrictions. It may hand off to move-related flows. It eventually returns to the invoking context. If you can trace that without hand-waving, you are doing architecture, not just code reading.

Let me give another concrete example, this time from the clone perspective. Suppose you are implementing a PartySummaryScreen class or module. You might be tempted to pass in a Creature object and then store it as this.creature. That is acceptable only if you are disciplined about what operations the screen exposes. Better is to pass in something like partyId and slotIndex, or a read facade over the party member, and have explicit commands for mutations. For example, SummaryScreenModel can compute display rows from getCreatureData(slotIndex), but it does not expose setMove. Then MoveLearningFlow receives the same slot index, gathers selectedMoveId and replacementMoveIndex, and calls a party service method like teachMove(slotIndex, selectedMoveId, replacementMoveIndex) only at the commit point. The exact names do not matter. The boundary matters.

Now, because you are advanced students, let’s complicate that model. What if the summary screen displays derived stats? Those stats may be stored or recalculated depending on the engine. What if a Pokemon levels up just before entering the screen? What if a held item changes from an item-use menu and then the summary screen is resumed? What if the party order changes? What if a link operation restricts modification? These are not edge cases in the abstract. These are the reasons FireRed’s screens include context and state, and why source files at these boundaries include many neighboring modules.

A useful rule is this: if a UI screen can outlive one frame, it should not assume that its initial formatted text is the authoritative state. It may cache display artifacts, yes, but the authoritative party record remains elsewhere. On hardware like the GBA, you do cache aggressively for practical reasons, because drawing text, decompression, VRAM operations, and tilemap updates have costs. But caching for display is not the same as ownership. When leaving a screen, you should be able to discard almost all UI state and still have the game state intact.

Let’s check understanding again. I’ll pose this as a small debugging scenario. A student clone has a bug: opening the summary screen and viewing the moves page restores a fainted Pokemon to full HP. Where would you look? You would not start in battle damage calculation. You would look for display code that accidentally calls a stat recalculation or initialization routine with write-back semantics. You would inspect whether the summary model is rebuilding the creature from species defaults instead of reading the existing party record. You would ask whether a helper that was meant for creation or healing is being reused for display. The bug is a violation of read-view discipline.

Another bug: the player enters move relearning, chooses Flamethrower, reaches the “Which move should be forgotten?” prompt, presses B, and Flamethrower still appears in the move list afterward. Where do you look? You look at the state machine commit point. You ask whether the selected candidate move was written too early. You ask whether the replacement flow mutates before the delete-old-move confirmation. The FireRed source focus in pokefirered/src/learn_move.c, especially chunks chunk_af3598df6f092723 and chunk_e820ee15ae8caa6d, gives us the correct architectural shape: a sequence of menu states that delays commitment until the player has passed the necessary confirmations.

Now, let’s bring in event scripting. The move relearner is often encountered as an NPC service, not as a free-floating menu. The overworld script talks to the player, checks conditions, maybe asks for a cost, then launches a special screen or callback. When the screen completes, it returns information to script variables or a follow-up state. The excerpt from chunk_e820ee15ae8caa6d mentions VAR_0x8004 being set to TRUE in one path. We do not need to overinterpret that one variable, but we should notice the pattern: UI flows often communicate results back to scripts through small pieces of global or event data. That is how a multi-frame UI can fit into a script-driven overworld interaction.

This is one of the places where the runtime shell, task system, and event scripting meet. The script cannot simply call a blocking C function and wait in the ordinary desktop sense. The game transitions into a callback or task-driven menu mode, runs across frames, and then returns with result flags that the script or calling context can interpret. Earlier in the course, when we traced data table to callback to visible behavior, this was the pattern. Here the visible behavior is not a trainer battle or map transition; it is a party mutation UI.

Inventory also fits into this story. Think about TMs, HMs, evolution stones, healing items, held items, and rare candies. Each item flow starts from an inventory selection, often asks for a party target, may display summary-like data or compatibility information, and may mutate the target Pokemon. The same discipline applies. Moving the cursor over a party slot does not consume the item. Displaying “able” or “not able” does not consume the item. Pressing A on a valid target may still lead to a confirmation. Only after the correct confirmation path should the item count and party data be changed. If your architecture puts item decrement inside the display eligibility function, you have a design problem.

Battle is related but not identical. Battle systems often operate on battler structures or battle-specific copies derived from party data. At battle start and end, data crosses the boundary. The research packet flags pokefirered/src/battle_setup.c, chunk_494d132a59422c85, as a source that includes task.h, overworld.h, item.h, pokemon.h, load_save.h, script.h, strings, event data, battle transition, and battle-related modules. Again, the include list shows the boundary. Battle setup is not just “start battle.” It pulls from overworld context, party data, scripts, save-relevant state, and transition UI. The party member’s role shifts from menu subject to battle participant, but the central concern remains: know when you are reading, when you are staging, and when you are committing changes back.

Let me pause and recap the first major idea before we go further. Party data is stable gameplay state. Gameplay screens are temporary state machines that read it, display it, and sometimes request controlled mutations. The summary screen is our clean read-heavy example, supported by pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46. The move relearner is our mutation-after-confirmation example, supported by pokefirered/src/learn_move.c, chunks chunk_af3598df6f092723 and chunk_e820ee15ae8caa6d. The broader architecture matters because these screens sit between runtime callbacks, tasks, scripts, UI, inventory, battle, save, and link rules.

Now, I want to sharpen the phrase “party slot ownership.” In ordinary programming language, ownership might mean memory ownership. That is part of it, but here I mean gameplay ownership. Who is allowed to decide that slot three now has a different move list? Who is allowed to reorder party members? Who is allowed to remove a Pokemon from the party? Who is allowed to serialize it? Who is allowed to send it across a link trade boundary? In a well-structured engine, those decisions are not scattered through every drawing function.

A party slot can be identified by an index, but the index alone is not enough information for safe behavior. Slot index plus mode tells you what operations are legal. Slot index plus caller tells you where to return. Slot index plus selected action tells you which command may eventually be committed. In FireRed-style architecture, this often appears as globals, task data, menu state variables, and callback transitions. In a modern clone, you may represent it with explicit state objects or reducers. The representation changes; the control problem does not.

Here is a board-work cue. I’m going to sketch a simplified dataflow. On the left, “Party array.” From it, an arrow goes to “Summary screen display model.” That arrow is labeled “read.” From “Summary screen display model,” arrows go to “pages,” “windows,” “sprites,” and “input.” None of those arrows go back to Party array. Now below that, “Move learning flow.” It also reads from Party array, because it needs current moves and open slots. It reads learnset data, because it needs candidate moves. It writes to temporary selection state: candidate move, confirmation response, replacement index. Only at the far right is an arrow back to Party array, labeled “commit teach move.” That one arrow is the dangerous arrow. That is the arrow you test.

When you write tests for this week’s lab, I expect you to test absence of mutation, not only successful mutation. That is a more mature testing habit. Test that opening the summary screen does not change the creature. Test that moving between summary pages does not change the creature. Test that entering move learning and cancelling at the first prompt does not change the moves. Test that cancelling after selecting a move but before selecting an old move does not change the moves. Then test that confirming an empty slot teach changes exactly one slot. Then test that confirming replacement changes exactly the selected slot and updates PP consistently. The negative tests are what defend your architecture.

One more check for understanding before we continue into the detailed screen lifecycle. Why is it not enough to say, “The UI should not mutate data except when it should”? Because that sentence does not identify the commit point. Advanced engineering requires naming the commit point in the state machine. In FireRed’s move relearner, the state sequence gives us named places where the player is browsing, confirming, declining, choosing, and completing. In your own implementation, you need the same clarity even if your state names are different. A vague boolean like isLearningMove is not enough. You want states that distinguish browsing candidates from confirming teaching from choosing replacement from committing the change.

As we move into the next segment, keep this frame in mind: every gameplay screen that touches the party has a contract. The summary screen contract is mostly “display the selected party member accurately and return control without mutation.” The move learning contract is “collect intent through a menu state machine and mutate move slots only after confirmation.” The item-use contract is “validate target and consume resources only on successful application.” The battle setup contract is “derive battle participants from party state and later reconcile appropriate outcomes.” The save contract is “persist the authoritative party state, not temporary UI decorations.” The link contract is “restrict or synchronize operations so remote and local state do not diverge.” Same party data, different contracts.

Now let’s start walking the summary screen lifecycle itself. Not line by line yet, but phase by phase, because phase structure is what lets you read a large source file without getting lost. First, entry: some caller chooses a party slot and a mode. Second, initialization: the screen prepares backgrounds, windows, sprites, text buffers, and task or callback state. Third, data extraction: it reads the selected Pokemon’s fields through the Pokemon interface, which we have already studied in prior lectures. Fourth, rendering: it formats the read data into visible pages. Fifth, input handling: it responds to page changes, party member changes, move selection if available, and exit commands. Sixth, return: it cleans up the UI state and resumes the appropriate caller. Of those six phases, only certain specialized subflows should write to the party record.

That is where we will pick up next: how to read a source file like pokemon_summary_screen.c as a screen lifecycle rather than as a pile of functions, and how to decide which state belongs to the UI, which state belongs to the party, and which transitions are allowed to cross that boundary.

So, let’s do exactly that. Imagine I have pokemon_summary_screen.c open on the projector, and I am not asking, “Where is the one function that displays HP?” That is too small a question. I am asking, “What is the lifetime of this screen, and what authority does it have over the Pokemon it is showing?” That framing is the difference between reading the file as UI code and reading it as architecture.

The summary screen source, in pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, immediately tells us something important just from the include surface. It includes pokemon.h, task.h, menu helpers, link, overworld, party menu constants, battle constants, trade, region map, item data, move constants, and text utilities. Now, an inexperienced reading of that include list might say, “Wow, this screen does everything.” But an architectural reading says, “No, this screen sits at a junction.” It needs to be callable from several contexts, and it needs to render a coherent view of a party member without pretending that it owns all the systems it touches.

Let me put that on the board. I’m drawing three boxes. On the left, caller context. In the middle, summary screen local state. On the right, party Pokemon record. The left box might be the party menu, the battle-adjacent party menu, a trade flow, or a field script-driven interaction. The right box is the actual Pokemon data, the thing we studied in weeks nine and ten. The middle box is everything the summary screen knows temporarily: which Pokemon is selected, which page is currently visible, which windows and sprites are active, whether the player is sliding between pages, which help text applies, maybe which move row is highlighted.

Now here is the critical rule. Most state in the middle box must be disposable. If I press left or right and move from the skills page to the moves page, I have not changed the Pokemon. If I scroll from Bulbasaur to Pidgey, I have not changed either Pokemon. If the UI redraws the OT name or met location or ability label, I have not changed the party. Those are reads. They may be expensive reads in a GBA sense, because they involve formatting strings, copying tiles, loading palettes, and scheduling sprites, but they are still reads.

This matters because many bugs in menu-heavy RPGs come from failing to separate “selection” from “mutation.” Selection is a pointer-like idea. It says, “The user is currently looking at slot two.” Mutation says, “The contents of slot two have changed.” Those must not be blurred. If your summary screen changes party data merely because a row becomes highlighted, then backing out of a menu becomes dangerous. If your move replacement UI writes the new move before the final confirmation, then cancellation becomes a recovery problem rather than a no-op.

You can see why this is week eleven material. Earlier in the course, when we decomposed the whole RPG into runtime shell, overworld maps, event scripting, creature data, battle, inventory, UI, save, and link systems, we were mostly building the map. Now we are studying the joints. Party data is not interesting only because of its struct layout. You already know the difference between the party-facing Pokemon object and the storage-oriented representation, and we are not going to re-teach that. Party data is interesting because so many screens borrow it. Battle borrows it. The party menu borrows it. The summary screen borrows it. Item use borrows it. Day care, trade, link, save, all of them have opinions about this same small set of records. So the architecture question becomes: how does each screen borrow the party without accidentally becoming the party’s owner?

Let’s make that concrete. Suppose the player opens the party menu and selects a Charmeleon in slot one. From there, the player chooses Summary. The summary screen receives enough information to know the party location and the selected index. It does not need to copy the entire Pokemon into private ownership for normal display. It needs to read fields through the Pokemon interface. That interface boundary is important because, as we discussed before, FireRed’s data model is not just a plain public bag of fields that every UI module pokes directly. The summary screen asks for data: species, nickname, level, current HP, stats, moves, PP, ribbons or markings depending on page, origin data, and so on. But for ordinary page rendering, it should not be rewriting those fields.

Now, check yourself here. If the player changes from the info page to the moves page, what changed? Not the Pokemon. The page index changed. If the player moves from slot one to slot two while staying in the summary screen, what changed? The selected party index changed, and the formatted display changed. The party array did not reorder itself. If the player exits the summary screen, what should happen? The caller regains control, usually with enough context to restore the previous menu flow. The caller context continues. That is the screen lifecycle reading.

This is also why the include list in pokemon_summary_screen.c is not just noise. The file’s connections to task, menu helpers, party menu, trade, battle, and overworld imply that the summary screen is a reusable presentation surface. The evidence is in pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, where the module is visibly positioned among Pokemon data access, UI helpers, link-related context, and caller systems. We are not claiming from memory that it is reusable; we are reading that from the source surface and then verifying it against the behavior we know from the game.

Let me pause on that phrase, “source surface,” because it is a useful technique for your projects. Before you dive into the functions, ask what kinds of modules the file imports. A file that includes only graphics and text helpers is probably a pure presentation file. A file that includes event data, script, party menu, battle, trade, and Pokemon interfaces is probably a boundary file. It receives control from several places and has to return to several places. Boundary files deserve extra suspicion. Not negative suspicion, but architectural suspicion. You ask, “What is local? What is global? What survives exit? What is just a temporary view?”

Now let’s follow a typical display pass. The screen has a selected party slot. It reads from that slot. It formats the nickname. It reads the species-dependent display information, which rests on the species records we covered earlier. It reads current stats, which rest on the stat calculation pipeline we covered last week. It reads move slots and PP, which rest on the move data model we already covered. But notice the direction of dependency. The summary screen is a consumer of those systems. It should not reimplement stat calculation. It should not re-decide move eligibility. It should not inspect packed fields by hand when an interface function already exists. At this point in the course, that should feel almost obvious, but I want you to notice how often real codebases violate it under schedule pressure.

Here is a small example. Say we want to add a custom “training score” line to a fan-made summary screen. There are two possible designs. In the first design, the summary screen directly computes the score by reading every relevant internal field it can find and combining them. In the second design, the creature module exposes a query function, or the summary screen calls existing getters and a small shared helper, and then only formats the result. The second design is usually healthier, because it preserves the summary screen’s role as a reader and renderer. If later battle rewards, vitamins, or save migration change how the score is represented, the summary screen remains a consumer. It doesn’t become a second implementation of the data model.

Now, that does not mean UI never mutates party data. That would be false. Week eleven is not “UI is read-only.” Week eleven is “UI mutation must be explicit, staged, and confirmed at the correct boundary.” The cleanest bridge to that idea is the move learning flow, which we will examine more deeply in the next lecture. But we should preview it now because it sharpens our reading of the summary screen.

In pokefirered/src/learn_move.c, chunk_af3598df6f092723, the source itself labels the move relearner as a state machine. That is unusually friendly evidence. We do not have to infer only from scattered functions; the source comments describe a MoveRelearnerStateMachine and its menu states. Later, in pokefirered/src/learn_move.c, chunk_e820ee15ae8caa6d, the flow distinguishes confirmation, empty move slot handling, the “trying to learn” prompt, deletion confirmation, and the selection of an old move. That is exactly the architecture pattern we want: the UI can explore choices before writing the creature data.

So, if I draw the move relearner next to the summary screen, the contrast is useful. The summary screen mostly says, “Read and display.” The move relearner says, “Read, propose, ask, maybe mutate.” The important word is maybe. Before confirmation, the selected new move is UI state. The currently highlighted old move is UI state. The scroll position in the list menu is UI state. The prompt text is UI state. Only after the player confirms replacement should the Pokemon’s move slots and PP be changed. And if the Pokemon has an empty move slot, then the flow can mutate without selecting an old move, but still only after the teach confirmation. That behavior is reflected in the state description in learn_move.c chunk_e820ee15ae8caa6d, where confirmation branches differently depending on whether an empty move slot exists.

Let’s run a concrete scenario. The player talks to the Move Relearner and chooses a Wartortle. The menu displays several eligible moves. The player highlights Bite. At that instant, has Wartortle learned Bite? No. The highlighted row is local menu state. The player presses A. The game asks for confirmation. Has Wartortle learned Bite now? Still no, unless the state has crossed the confirmation boundary and found an empty slot or proceeded into replacement. The player confirms, and suppose Wartortle already has four moves. The game now enters the replacement prompt. Has Wartortle learned Bite yet? Still not as a final mutation, because the old move has not been chosen. The player highlights Tackle. Has anything mutated? No. Highlighting Tackle is still selection. The player confirms forgetting Tackle. Now the move slot changes. That is mutation.

That chain is not mere UX trivia. It is data integrity. It lets B cancel work. It lets text prompts be interrupted safely. It lets the same party data be viewed by other systems without half-written moves. It lets save persistence remain simple because save should serialize actual game state, not speculative UI state. If your clone project writes the new move immediately and stores the old move somewhere as an undo buffer, you can make it work, but you have made the architecture harder. You have converted a simple commit boundary into a compensation system. Compensation systems are not always wrong, but in a menu state machine like this, they are usually a smell.

Now, check for understanding. I’m going to say three variables, and I want you to mentally place each in one of our boxes: caller context, UI state, or party data. First, selected party slot. That is usually UI state or caller-passed context, depending on who currently owns navigation. It is not the Pokemon itself. Second, current HP. That is party data, read through the Pokemon interface. The rendered digits are UI output, but the value belongs to the Pokemon. Third, scroll position in the move relearner list. That is UI state. It may survive while the menu is open, but it should not be saved as part of the Pokemon. If those placements feel clear, you are tracking the core boundary.

Let’s connect this back to the runtime shell. In earlier weeks, we spent a lot of time on callbacks and tasks: AgbMain setting the runtime in motion, SetMainCallback2 changing the primary mode of control, RunTasks dispatching per-frame tasks. I am not going to re-teach those mechanisms, but I want you to carry them forward. A screen like the summary screen is not just “called” in the desktop application sense where a function runs and returns immediately. It installs a mode of execution. It allocates or initializes state. It uses tasks or callbacks to process frames. It eventually returns control to another mode. So when we say “summary screen reads party data,” we mean that across many frames, through its lifecycle, it repeatedly treats party data as a source for display, while its own task-local fields track interaction.

This is one reason the lab this week asks you to implement a party summary screen model that reads creature data without mutating it, and only then add a move-learning flow that mutates move slots after confirmation. The sequencing is deliberate. If you cannot first build a read-only projection of a creature, you will not build a safe mutation flow. You need to be able to say, “This object is my model of what the screen is showing,” without confusing it with the stored creature record. Then, later, when you commit a move replacement, you should be able to point to the exact line where the stored creature changes. In code review, that line should be boring and obvious. “Here is the commit.” Everything before it should be navigation, rendering, validation, and confirmation.

Let me say that again in a slightly different way, because it is one of the main professional lessons of this week. Good UI architecture makes the write path narrow. The read path can be wide. Many pages may read species, stats, moves, held item, nature, ability, origin, and markings. But the write path should be narrow, named, and guarded by state. This applies not only to FireRed. It applies to inventory systems, save editors, party management screens, skill trees, character sheets, and online account settings. Read broadly, write deliberately.

Now, in a creature RPG specifically, party slot ownership adds another wrinkle. A party slot is not just an index into an array. It is also a gameplay identity at a moment in time. Slot zero may be the lead Pokemon in overworld encounters. Slot zero may be the default participant in some battle setup logic. Other screens may remember the slot they came from. The party menu may allow switching order, using an item, giving a held item, viewing summary, or canceling. So if a summary screen receives “slot zero,” it must be careful about whether it is allowed to change party order. For a normal summary screen, no. It can move the viewing cursor to another party member, but that is not necessarily the same as reordering the party. Again, selection versus mutation.

Consider an edge case. The player opens the party menu, chooses Summary on slot three, then presses up or down inside the summary screen to inspect adjacent party members. When the player exits, where should the caller cursor be? There are a few plausible answers, and the correct one depends on the game’s UX contract. It might return to the originally selected slot, or it might return to the last viewed slot. But either way, that is caller or UI navigation state. It is not the same as changing which Pokemon lives in slot three. The architecture must distinguish “cursor now points at slot four” from “slot three and slot four have been swapped.” If your code represents both with casual integer changes near the party array, you have made a bug easy.

This is where I want you to start reading menus as transactions. Not database transactions with all the formal machinery, but transaction-shaped flows. The move relearner begins with a candidate Pokemon and a candidate move. It collects user intent. It checks whether direct insertion is possible. If not, it asks which existing move should be forgotten. It confirms or cancels. Finally, it commits. The summary screen is mostly a non-transactional read view, but it lives next to transactional flows. It may call into them, return from them, or share state conventions with them. In FireRed, the source focus for this week deliberately pairs pokemon_summary_screen.c chunk_e8e17a42bbf17d46 with learn_move.c chunks_af3598df6f092723 and e820ee15ae8caa6d because the pair shows both sides: presentation reads and menu-mediated mutation.

Let’s put a small pseudo-trace on the board, verbally. Player selects party slot two. Caller records slot two and opens summary. Summary initializes page state to info page. Summary reads slot two nickname, level, species, stats. Summary renders. Player presses right. Summary changes page state to moves page. Summary reads move slots and PP. Summary renders. Player presses B. Summary cleans up and returns to caller. No party mutation occurred. Now a second trace. Player selects Move Relearner. Relearner opens eligible move list. Player highlights move. Relearner stores candidate move in UI state. Player confirms. Relearner checks empty slot. If empty, commit new move to Pokemon. If full, prompt for old move. Player selects old move. Player confirms. Commit replacement. Return. In the second trace, there is exactly one conceptual commit moment.

You should be able to annotate your own lab code the same way. If I ask, “Where is the party write?” you should not say, “Well, the screen kind of updates as the user moves around.” No. The answer should be precise. “The party write happens after the confirm state, in the function that applies the selected new move to the selected move slot.” Or, “There is no party write in this screen; it only creates a view model from the creature record.” That precision is what we are training.

Let me also point out a subtle source-reading trap. Sometimes rendering code writes to buffers, windows, sprite attributes, or global UI memory. Those are writes, but they are not writes to the party record. Do not let the word “write” become too broad. We care about which domain is being mutated. Writing text into a window tilemap is a UI mutation. Updating a cursor position is a UI mutation. Changing a task data field is a task mutation. Setting a script variable may be event-system mutation. Replacing Tackle with Bite in the Pokemon’s move slot is party data mutation. Advanced architecture work is partly about naming the domain of each write.

That domain naming helps with save behavior too. The save system should persist the durable game state: party, bag, flags, variables, player position, boxes, and so forth. It should not persist the transient fact that the summary screen was halfway through drawing a stat page, unless the game has some explicit suspend-state design, which FireRed’s normal menu flow does not require. So when you draw the boxes on your own paper, add a fourth box underneath: save persistence. Draw arrows from durable data to save. Do not draw arrows from every temporary menu highlight to save. This is the larger course decomposition coming back into focus. Runtime shell drives screens. Screens read and sometimes mutate party. Save persists durable state. Event scripts may initiate flows. Battle may consume and mutate combat-relevant party data. Inventory may apply items that mutate HP, PP, status, held item, or evolution conditions. The boundaries keep the whole thing understandable.

Now, I’ll ask a slightly harder check. Suppose the summary screen displays a Pokemon’s current attack stat, and the player has just used a stat-changing item in a previous menu. Should the summary screen cache the old attack number and keep showing it until reopened? No, not if the source party data has changed before the summary render. A read-only screen is not the same as a stale screen. It should read or refresh its projection at the right lifecycle points. Read-only means it does not cause the mutation. It does not mean it ignores mutations caused elsewhere. This distinction matters when you have nested screens. If an item-use flow returns to the party menu or summary view, the display must reflect the committed change.

And that brings us to one of the design questions you will face in your lab: do you store a view model, or do you read directly every frame? On the GBA, with its constraints and rendering model, many screens build intermediate display buffers and redraw only what they need. In a modern clone, you might use a view model object that is regenerated when the selected creature changes or when a committed mutation occurs. Either approach can be correct. The architectural requirement is not “never cache.” The requirement is “do not confuse cache with authority.” If the view model says the move is Tackle but the party record says the move is Bite after a confirmed replacement, the party record wins. The view model must be refreshed.

Let’s bring this back to the source again. pokemon_summary_screen.c chunk_e8e17a42bbf17d46 is valuable for us because it sits among the systems we are integrating this week: Pokemon interface, menu helpers, task system, link and trade contexts, battle constants, party menu constants, and rendering utilities. learn_move.c chunk_af3598df6f092723 and chunk_e820ee15ae8caa6d are valuable because they show the state-machine treatment of a UI flow that eventually mutates move data. Together, they give us a pattern: screens are not just visual files, and data modules are not just storage files. The architecture lives in the controlled handoff between them.

Before we move on, take thirty seconds and test the pattern against another familiar flow: using a Potion from the bag on a party member. The bag screen owns item selection. The party menu owns target selection. The Pokemon record owns current HP. The item-use logic validates whether the item can apply, computes the result, and then commits HP mutation if the player has actually chosen the item and target. The summary screen later reads the new HP. See how the same boxes work? Caller context, UI state, durable party data, commit boundary, return path. Once you can see that shape, FireRed becomes much less like a pile of special cases and much more like a set of repeated architectural moves.

All right, now I’m going to transition from the general boundary model into a closer reading strategy for pokemon_summary_screen.c itself. We are going to look at how to cluster functions by lifecycle role: initialization, data extraction, page drawing, input response, and teardown. The important thing is that we will not treat every function as equally architecturally important. Some functions are plumbing. Some are formatting. Some define state transitions. Some cross module boundaries. Our job is to sort them, because sorting them tells us where mutation is allowed and where it would be suspicious.

So, let’s start that sorting exercise. If I put pokemon_summary_screen.c on the board as one giant file, that is not yet architecture. That is just text. Architecture starts when we ask, “Which pieces are responsible for owning time, which pieces are responsible for reading data, which pieces are responsible for rendering, and which pieces are allowed to mutate something that survives after this screen closes?”

I’m going to write five labels across the board: initialization, data extraction, page drawing, input response, teardown. Now, notice I did not say “summary screen functions” as one category. That category is too broad to be useful. The source packet points us specifically to pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, and even the include list is already giving us evidence about the screen’s architectural position. It includes pokemon.h, task.h, menu helpers, link, overworld, party menu constants, battle constants, region map support, move constants, and text utilities. That means this screen is not an isolated widget. It is a screen-sized adapter sitting between party data, visual presentation, player input, and whatever gameplay context launched it.

Now, before we go any further, quick check for understanding. If the summary screen includes pokemon.h, does that automatically mean it should directly rearrange party slots, teach moves, heal HP, and write save data? No. Exactly. Header access does not imply ownership. It means the screen can speak the language of Pokemon records. Ownership still depends on the caller context and on which function path is executing. This distinction matters because in large C game codebases, access is often syntactically cheap. A file can include a header. A function can receive a pointer. A global can be visible. But architectural permission is more constrained than syntactic access.

So, when we classify summary-screen code, initialization is where the screen receives its world. That includes which party or storage source it is viewing, which slot is currently selected, what mode it is in, and where it should return. In a modern object-oriented or ECS system, you might expect that to appear as a constructor argument or a screen descriptor object. In FireRed, you usually see a combination of globals, callback setup, task data, and state variables. That should sound familiar from our earlier weeks on AgbMain, SetMainCallback2, CreateTask, and RunTasks. We are not redoing that material today, but the prior shell model is now paying off. A summary screen is not “called” in the same way a blocking desktop dialog is called. It is entered into the runtime shell, then it owns frames until it hands control back.

Now data extraction is the category I want you to take most seriously today. Data extraction is where the summary screen asks, “What is this creature’s nickname? What is its species? What are its moves? What is its held item? What are its stats? What ribbons or markings or origin fields need to be displayed?” This is where the Pokemon and BoxPokemon material from the last two weeks becomes foundation rather than the topic itself. We already know there is a packed creature record boundary. We already know GetMonData-style APIs exist to keep callers from casually knowing every internal detail. So today’s point is not “how is a Pokemon stored?” Today’s point is “how does a gameplay screen consume that record without becoming the owner of that record?”

Let me give you a concrete example. Suppose the player opens the party menu, chooses the second party member, and selects summary. The summary screen needs to show four move names, four PP values, stats, nature-adjacent information, and origin data. It may need to respond to left and right to move between party members. It may need to respond to up and down to switch pages. But if the player simply looks at the summary and presses B, nothing about the Pokemon should have changed. That sounds obvious, but as an architecture rule it is strong. It means page drawing functions should be suspicious places to find mutation. If you see code that draws the move page and also changes the move list, that is a smell unless you are in a very specific mode with a very explicit commit boundary.

This is where we connect to the week’s lab. In your lab model, I do not want you to implement a “summary screen” by copying creature objects into a mutable view object and then writing them back at the end. That is the wrong default. The default should be read-through: the screen has a selected creature reference, reads fields through the creature interface, formats them into view model fields or tilemap text, and does not commit back. Temporary UI state belongs to the screen. Durable creature state belongs to the party record.

Now, page drawing is different from data extraction, although in older C code the two are often interleaved. Page drawing answers, “Given the data we need, what do we put in backgrounds, windows, sprites, palettes, and text buffers?” The include list in pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, tells us why that gets busy: graphics, strings, dynamic placeholder text utilities, region map, item constants, move constants, and menu support all converge here. The summary screen has to translate internal creature facts into a visual artifact the player recognizes. That translation can be elaborate without being logically authoritative.

Let me slow down on that phrase: visually elaborate does not mean logically authoritative. A screen can have many functions, many assets, many state variables, and many rendering details, and still be mostly a reader. In fact, that is common in Game Boy Advance UI code. The hardware constraints make presentation code dense. Tilemaps, windows, VRAM, palettes, sprites, scanline effects, and text printing all need procedural handling. So a large function count is not evidence of domain ownership. It may just be evidence of hardware-facing presentation.

Now input response is the category where mutation becomes possible but still not automatic. If the player presses B, maybe we tear down. If the player presses left or right, maybe we change selected party index. If the player presses A on a move in a special context, maybe we open a move details page or return a selection to another system. The key question is, “Does this input change UI state, or does it change creature state?” Changing the selected page is UI state. Changing the selected party slot, if you are only browsing, is UI state. Replacing Tackle with Flamethrower is creature state. Those belong in different mental boxes.

I’m going to draw a little timeline on the board. Entry, initialize visual resources, load selected Pokemon facts, draw page, wait for input, update screen state, redraw, eventually exit. Now I’m going to add a second line under it: durable mutation. For ordinary summary browsing, that second line is empty. Nothing commits. For move learning, the second line has a single marked point: confirmation and replacement. That is why the second lecture this week, on Move Learning as a Menu State Machine, pairs so tightly with today. The summary screen teaches us how to read party data across gameplay screens; learn_move.c teaches us how to mutate move slots only after a carefully staged UI process.

The packet’s learn_move.c chunks are very helpful evidence here. In pokefirered/src/learn_move.c, chunk_af3598df6f092723, the source is explicitly framed around a Move Relearner state machine. It begins with initialization through CB2_MoveRelearner_Init and then moves into named menu states. That comment block is architecture written in the code: fade to black, set up list menu, handle input, confirm choices. Then chunk_e820ee15ae8caa6d describes later states around teaching confirmation, trying-to-learn prompts, confirming deletion of an old move, choosing which move to forget, and final teaching. The important contrast is this: the move relearner screen may display move data for a long time before it mutates anything. Display is not commit.

Let’s make that concrete with a Charmander example. Imagine the player brings a Charmander to a move relearner and selects a move that Charmander can relearn. The UI first needs to list candidates. That list is data derived from species, level history rules, current moves, and game constraints. Listing Ember or Metal Claw or whatever the valid candidate is in a given ruleset is not mutation. The player moves the cursor. Still not mutation. The player presses A. Still maybe not mutation, because the game may ask for confirmation. The player confirms. If there is an empty move slot, now the commit can be direct: write the move into the empty slot and initialize PP. If there is no empty slot, the game enters the replacement flow. The old move is not deleted merely because the player expressed interest. It is deleted only after the player chooses which old move to replace and confirms that flow. That is exactly the architectural discipline described in learn_move.c, chunk_e820ee15ae8caa6d.

Check for understanding here: why is “cursor moved to Scratch” not enough to delete Scratch? Right, because cursor position is exploratory UI state. It represents attention, not intent. And even intent is often staged. Pressing A can mean “inspect,” “select for confirmation,” or “advance the prompt,” depending on the state. The state machine gives those inputs meaning.

This is the reason I keep pushing you to name the owner of each state variable. If a variable stores the current summary page, the summary screen owns it. If a variable stores which row in a list menu is highlighted, the menu task owns it or the screen owns it as UI state. If a variable stores the Pokemon’s actual first move, the party Pokemon record owns it. If a variable stores “which move are we considering teaching,” that is transitional menu state. If a variable stores “this Pokemon now knows the move,” that is durable creature state. Those are not philosophical differences. They determine where bugs appear.

A common bug in student clones is premature mutation. You open a move learning menu, immediately place the candidate move into a temporary creature object, then try to undo if the player cancels. That seems convenient until the flow branches. What if the player cancels from the “which move should be forgotten” prompt? What if the player backs out from the confirmation prompt? What if the screen returns to the field script and sets an event variable saying success or failure? What if you display the summary during the process? Suddenly your temporary mutation leaks into screens that should only display committed state. FireRed’s architecture avoids that by keeping the candidate move and menu progress separate from the durable party mutation until the state machine reaches the teaching point.

Now let’s return to pokemon_summary_screen.c. When you read this file for the lab, I want you to resist the urge to start at line one and produce a mechanical paraphrase. Instead, skim for lifecycle boundaries. Ask: where is the main callback? Where are tasks created? Where are windows and backgrounds initialized? Where are Pokemon fields read? Where are pages selected? Where is input interpreted? Where is control returned? When a function calls into pokemon.h, ask whether it is getting display data or causing mutation. The packet also names pokefirered/include/pokemon.h, chunk_9b5ff7d0_cd9f4c67 in the source focus, and pokefirered/src/pokemon.c, chunk_9c96aedd5b8237e6, as the helper flow foundation. The header and helper implementation are the contract zone. The summary screen should use that contract to ask questions about a Pokemon. It should not need to unpack the creature representation by hand.

And this is where advanced reading differs from beginner reading. A beginner says, “This function prints the stat number.” An advanced reader says, “This function is part of a read-only projection from party data into screen state; it depends on the Pokemon accessor contract; it should not be responsible for recalculating ownership or committing mutation.” That second sentence is architecture. It tells us what changes are safe.

Let me give you another example that sounds small but matters. Suppose you want to add a new summary page showing contest-style traits or a custom training score in your clone. Where should that data come from? If the score is derived from species and level and held item, the page can compute or request it at draw time. If the score is persistent, it must live in the creature record or in some associated durable data structure. The summary page can display it, but the page itself should not become the storage location. If you store the score only in summary-screen state, it disappears when the screen closes. If you store it in summary-screen state and write it back opportunistically, you have created an unclear commit boundary. That is where save bugs and cross-screen inconsistencies come from.

Now, let’s connect this to the larger course architecture. By week 11, you should be able to place this screen in the whole RPG decomposition. The runtime shell gives us callbacks and tasks. The overworld map gives us the context that may launch a party menu or NPC script. Event scripting can initiate a move relearner or force a party selection. Creature data provides the Pokemon record and accessors. Battle may read the same moves and stats, but under battle-specific state. Inventory may launch item-use flows that target a party member. UI provides the rendering and input systems. Save determines what durable changes survive power-off. Link systems constrain what screens can do during communication-sensitive modes. Party data is not one subsystem off to the side; it is a shared domain object touched by many screens, each under different rules.

This is also why the source include list in pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, is not just noise. link.h appearing near a summary screen is a reminder that not every summary visit occurs in the same global mode. battle_main.h and constants/battle.h remind us that battle-adjacent contexts can care about party data differently from field contexts. party_menu.h and constants/party_menu.h remind us that the summary screen is often reached through a party menu workflow rather than directly from the overworld. region_map.h reminds us that origin display can pull from map-section data. Each include hints at a dependency edge. Our job is to decide whether the edge is read-only presentation, UI control, or domain mutation.

Let me pause and ask a diagnostic question. If you are implementing your lab and your SummaryScreenModel has a method called replaceMove, what should you think? You should be uneasy. Not necessarily wrong in every possible design, but uneasy. A summary model that reads data should not normally perform move replacement. Move replacement belongs to a move-learning flow or a party-management command with an explicit confirmation state. If, however, you have a summary screen mode specifically launched as “choose a move to forget,” then the summary UI may participate in selection. But even then, the mutation should happen at the boundary where the move-learning state machine receives the selected move slot and confirms the replacement. The screen can return a slot index. It does not have to own the write.

This is a very useful design pattern for your own engines: screens return decisions; domain services commit decisions. I’ll write that on the board. Screens return decisions; domain services commit decisions. In FireRed-style C, the “domain service” may not be a neat class. It may be a function in pokemon.c, a script variable result, or a state-machine branch. But the idea still holds. Separate “the player highlighted slot two” from “slot two has now been overwritten.”

Now, I want to bring in teardown, because students often ignore it. Teardown is not just freeing memory. On the GBA, teardown can mean restoring callbacks, clearing windows, resetting palettes, destroying tasks, and returning to overworld or another menu. In a party data screen, teardown also marks the end of the screen’s authority. Once it exits, its UI state should no longer be the source of truth. If you need something after teardown, it must be returned through an explicit result path or committed to durable state before exit. This is especially important when a field script launched the UI. The script may be waiting on a variable, like success or cancel, not on some hidden screen object that no longer exists.

So the architecture we are building today is not merely about Pokemon. It is about controlled data flow across gameplay screens. FireRed’s creature data is central because it is valuable, persistent, and shared. The summary screen reads it. The party menu selects it. The battle engine consumes a battle-shaped projection of it. The item system may mutate HP, status, PP, or held item through explicit item-use flows. The move relearner mutates move slots only after confirmation. The save system preserves the result. Once you see these roles, you can predict where code should live.

Let’s do one more check for understanding before we move into the next part. I’ll describe three actions, and you decide whether each is UI state, derived display data, or durable party mutation. First, the player presses R to switch summary pages. UI state, yes. Second, the summary page displays Attack as a number computed from the Pokemon’s current stored attributes and stat rules. Derived display data, or at least a read of derived creature data through the helper flow. Third, the move relearner replaces Growl with a selected relearned move after the player confirms. Durable party mutation. Good. The reason this classification matters is that each category has a different test strategy. UI state tests check navigation. Display tests check that reads and formatting are correct. Mutation tests check before-and-after party records and cancellation paths.

And now, a short recap before we push deeper. We started with the boundary model: caller context, UI state, durable party data, commit boundary, return path. We then classified pokemon_summary_screen.c by lifecycle role rather than treating every function as equally important. We used the evidence in pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, to see the summary screen as a connector between party data and multiple gameplay contexts. We contrasted that mostly read-only screen with pokefirered/src/learn_move.c, chunk_af3598df6f092723 and chunk_e820ee15ae8caa6d, where the move relearner state machine stages player intent before committing a move-slot mutation. That contrast is the heart of today’s lecture.

All right, next I want to take that classification method and turn it into a practical reading procedure you can use in the lab. We are going to pretend you are staring at a 3,000-line UI file and you have ninety minutes to understand it well enough to modify it safely. The first pass is not to understand every line. The first pass is to mark the entry points and exits. What callback enters this screen? What task runs each frame? What condition returns control? The second pass is to mark data reads. Search mentally, or with tooling, for Pokemon accessor calls and move or item constants. The third pass is to mark writes. Any function that changes Pokemon data, party order, item ownership, script variables, or global mode deserves extra attention. The fourth pass is to connect writes to user confirmations. If a write is not downstream of an explicit state transition or caller contract, you investigate it.

That procedure is how you keep your clone architecture from becoming accidental. And in the next segment, we will apply it to the move replacement flow more directly: not just “a move changes,” but exactly how the UI walks from candidate move, to confirmation, to full-move-set conflict, to old move selection, to final write, and then back out to the caller with a result.

So let’s do that now. We are going to slow down on the move replacement flow, because this is where a creature RPG either becomes cleanly architectural or becomes a collection of lucky menu hacks. And I want you to notice something before we look at any one state: the move relearner is not just a menu. It is a transaction interface over party data. It gathers a candidate move, checks whether the current party slot can accept that move directly, asks for permission when destructive replacement is required, possibly delegates to another screen-like selector, and then commits the mutation only after the player has crossed the confirmation boundary.

That language is deliberate. Transaction interface. Confirmation boundary. Commit. Those are not terms FireRed uses in comments, necessarily, but they are the architectural shape we can infer from the state machine described in pokefirered/src/learn_move.c, chunk chunk_af3598df6f092723, and especially the continuation in chunk chunk_e820ee15ae8caa6d. The source comments there are unusually helpful because they lay out the move relearner state machine in human terms: fade in, list selection, move detail display, teach confirmation, empty-slot shortcut, full-move-set prompt, delete confirmation, old move selection, stop teaching, and return behavior. When a codebase gives you that much state naming, take advantage of it. It is telling you where the author thought the user-visible milestones were.

Now, board cue here. I’m drawing a horizontal line. On the far left I’ll write “candidate move.” Then a gate: “teach this?” Then a branch. One branch says “empty move slot.” That goes straight to “write new move.” The other branch says “no empty slot.” That goes to “trying to learn prompt,” then “forget old move?” then “which move?” then finally “replace move.” Under the final two boxes, I’m drawing a heavy underline. Those are the only places where we want mutation. Everything before that can display, compute, scroll, preview, or ask, but it should not change the Pokémon’s move list.

And this is the connection back to the first part of today’s lecture. The summary screen, from the source focus in pokefirered/src/pokemon_summary_screen.c, chunk chunk_e8e17a42bbf17d46, sits in the same broad ecosystem of party data, moves, battle constants, menu helpers, and party menu integration. Its job is largely observational. It reads the selected party member, formats species, moves, stats, held item, nature-like derived properties in the broader sense of calculated display data, and renders pages. It may respond to input and page transitions, but the important discipline for your lab is: a summary model should read creature data without mutating it. The move relearner, by contrast, is a controlled mutator. Both screens touch the same conceptual party slot. They do not have the same authority.

Let me make that concrete. Suppose the player selects a level 35 Charizard-like creature in party slot two. We are not re-teaching representation today; we already did the Pokémon and BoxPokemon boundary, the GetMonData-style accessor pattern, and the move slot plus PP foundation in weeks nine and ten. So just bring that forward. The summary screen opens and says, in effect, “What is in slot two? What species? What level? What four moves? What PP? What stats?” It may cache display strings. It may remember that the cursor is on the moves page. It may page left and right. But if the player exits summary, the move list should be byte-for-byte the same unless some explicitly separate action happened.

Now place the same party slot into the move relearner. The player selects a candidate move, say Flamethrower. The first half of the flow is still non-mutating. The list menu scroll position changes. The details pane changes. The selected move ID changes. The menu may update power, accuracy, type, or contest-like metadata depending on game generation and screen design. None of that means Charizard knows Flamethrower. The selected candidate is not creature state. It is UI state.

That distinction is one of the most common bugs in student projects. You store candidateMoveId inside the creature record because it “belongs to the Pokémon screen.” No. It belongs to the screen session. The Pokémon owns learned moves. The menu owns the candidate. The caller may own the result flag. The script may own the next narrative step. If you blur those ownership lines, you get strange problems: canceling still teaches the move, backing out leaves a phantom selected move, opening a different creature inherits the prior move choice, or a save file accidentally preserves a menu cursor as if it were game state.

Let’s connect that to the FireRed evidence. In pokefirered/src/learn_move.c, chunk chunk_af3598df6f092723, the research packet points us to a source comment naming “Move relearner state machine,” with CB2_MoveRelearner_Init and menu scroll state such as listMenuScrollPos and listMenuScrollRow. The key lesson is not the exact variable names by themselves. The key lesson is that scroll position is part of the relearner session state machine. It is not part of the Pokémon. That is a small but powerful architecture signal. A menu can have rich state without claiming ownership over the domain object.

Pause there and check your understanding. If I ask, “Where should the selected row of the move relearner list live?” the answer is not “in the move slot,” and it is not “in the species learnset.” It lives in the menu state, task data, or equivalent screen model. If I ask, “Where should the final learned move live after confirmation?” then yes, that belongs in the party Pokémon’s move array, with the necessary PP initialization or adjustment performed through the appropriate creature-data interface. Different data, different owner, different lifetime.

Now let’s walk through the replacement branch more carefully. The player has chosen a candidate move and confirmed the first question. If the Pokémon has fewer than four moves, the transaction is simple. There is a vacant move slot, so the system can append or assign into the empty slot after confirmation. The source notes in pokefirered/src/learn_move.c, chunk chunk_e820ee15ae8caa6d, describe this branch: after teach-move confirmation, if the Pokémon had an empty move slot, a script variable is set to true and the state proceeds toward printing text and playing a fanfare. Again, I’m paraphrasing the source structure here rather than quoting it at length. Architecturally, that means the UI confirmation is enough because there is no destructive choice. No old move is being erased.

If all four move slots are occupied, the system needs a second level of consent. This is the classic “trying to learn X, but already knows four moves” flow. From an implementation perspective, it is tempting to treat this as just one more yes-no prompt. But it is more than that. It is a fork into a sub-flow that requires selecting which existing move will be overwritten. The player is no longer answering “teach candidate move?” They are answering “am I willing to destroy one of these four existing moves, and if so, which one?” That means your UI state must now include both candidateMoveId and selectedOldMoveIndex. The candidate remains stable while the old-move selector moves around.

On the board, I’ll write two variables. candidateMoveId equals Flamethrower. selectedOldMoveIndex equals cursor position, maybe 0 through 3. Notice the asymmetry. candidateMoveId is a move identifier. selectedOldMoveIndex is a slot index. You should not confuse them. This confusion causes a very real class of bugs. If you accidentally store the old move ID where you need the old move index, replacement can fail when duplicate moves are impossible in the canonical game but possible in debug states, imported data, or later custom mechanics. Even when duplicate moves are disallowed, using an index is the correct expression of the operation: “replace slot 2,” not merely “remove move Scratch.” The mutation target is a slot.

This is why advanced architecture is partly about preserving the verbs of the domain. Summary reads. Relearner previews. Confirmation authorizes. Replacement writes to a slot. Save persists. Battle may later consume the changed move list. The verbs tell you which module has the right to act.

Now, let’s compare that with the summary screen one more time because it prepares you for the workshop. In a summary model, you might build a function like buildSummaryViewModel(party, slotIndex). It returns species name, level, current HP, max HP, held item label, move names, move PP, and maybe move descriptions for the current page. That function should be boring. Boring is good here. If the user changes pages, rebuild or adjust the view model. If the user exits, discard it. A summary view model is a lens over creature data.

For the move-learning flow, you might build a function or state object like MoveLearningSession. It contains the party slot reference or slot index, candidateMoveId, current state, cursor positions, and result. It may read the Pokémon repeatedly. But it only calls the mutation operation in a state named something like CommitMoveToEmptySlot or CommitMoveReplacement. In FireRed’s actual code, the state names and exact functions are specific to its C architecture, callback shell, and task/menu system. But the state-machine evidence in pokefirered/src/learn_move.c, chunks chunk_af3598df6f092723 and chunk_e820ee15ae8caa6d, supports this higher-level reading: the learning flow is divided into visible states, and the write is downstream of confirmation and conflict resolution.

Let me give you a clone implementation example in plain terms. Imagine your party data is an array of Creature objects. Creature at index 1 has moves Ember, Slash, Wing Attack, and Smokescreen. The relearner opens with candidate Flamethrower. The player scrolls from Dragon Rage to Flamethrower. That changes candidateMoveId. The player presses A. The state becomes ConfirmTeachMove. The player chooses Yes. The system checks for an empty move slot and finds none. The state becomes PrintTryingToLearnPrompt, then ConfirmDeleteOldMove. The player chooses Yes again. The state becomes SelectOldMove. The cursor starts on Ember. The player moves down to Smokescreen and presses A. Only now does the code call replaceMove(creature, slotIndex: 3, newMove: Flamethrower). After that, the system may set a result variable, play a sound, print a success message, and return to the caller.

What happens if the player presses B on the old move selection? Well, that depends on the exact state design, but the key property is that no mutation has happened yet. Canceling at that point should return to a “stop teaching?” or previous prompt state, not require an undo. That is a powerful design rule: prefer delayed commit to speculative mutation plus rollback. On constrained hardware and in small games, rollback may look easy, but as soon as the creature record includes PP, relearn flags, move-source metadata, animations, script variables, and save triggers, rollback becomes a liability. FireRed’s state machine shape, as described in the learn_move.c chunks, is very much a delayed-commit design.

Now I want to bring in the runtime shell, because this is week eleven and we are no longer allowed to pretend screens exist in isolation. Earlier in the course, we traced AgbMain, main callbacks, task allocation, and RunTasks as the frame dispatch loop. You do not need to re-learn that today, but you do need to carry it with you. The move relearner is not a blocking function in the desktop sense. It does not simply call scanf, wait, return a value, and continue. It participates in the game’s callback and task-driven runtime. That is why the source focus calls out CB2_MoveRelearner_Init in pokefirered/src/learn_move.c, chunk chunk_af3598df6f092723. CB2 naming places the screen in the main callback world we studied earlier. The visible menu is a state machine spread across frames.

That has a direct implication for your lab. If you implement this in a modern engine, do not hide the state machine inside a single giant event handler. I know you can. Many of you can write one function with a switch statement, a few nested ifs, and a dozen booleans, and it will pass the happy path. But the architecture we are learning is stronger than that. Your state names should correspond to player-visible phases: choosing candidate move, confirming teach, explaining four-move conflict, confirming deletion, choosing old move, committing replacement, showing result, returning. This makes your test cases obvious. It also lets you inspect whether mutation happens too early.

Here is a simple test thought experiment. Start with a full move set. Enter the relearner. Select Flamethrower. Confirm teaching. Reach the old move selection. Cancel. Assert that the original four moves remain unchanged. Then repeat, but select Smokescreen and confirm. Assert that exactly slot three changes to Flamethrower, and the other slots remain unchanged. If you also model PP, assert that the new move receives its proper PP and that unrelated move PP remains stable. This is not just unit testing. It is architecture testing. You are verifying the ownership and timing rules.

Check for understanding again. Why do we assert the other move slots remain stable? Not because we distrust arrays in general. We assert it because replacement is a slot-specific mutation. A function that rewrites the entire move list from a temporary menu buffer might accidentally reorder moves, reset PP, or erase a move that was not selected. Advanced programmers do not only test that the desired thing happened. They test that adjacent state was not disturbed.

Now, notice the connection to save. The move relearner itself does not need to save the game immediately in the ordinary flow. But after the mutation, the party record is different, and any later save persistence should capture that new state. So the ownership chain is: menu session owns candidate and cursor; party Pokémon owns final move slots; save owns persistence of the mutated party data. Battle later reads that party data and uses the learned move in battle. Summary later reads it and displays it. Inventory might be involved in a TM-like flow, where item consumption is another mutation; that would require its own confirmation and commit boundary. Link systems may constrain whether certain screens can be opened, or may display party data in trade contexts. You can now see the whole course map through one little move replacement operation.

This is why I keep asking you to decompose the complete creature-collector RPG into runtime shell, overworld maps, event scripting, creature data, battle, inventory, UI, save, and link systems. Not because decomposition looks tidy on a slide, but because every real feature crosses those boundaries. The move relearner can be reached from an NPC script in the overworld. That script hands control to a UI state machine. The UI reads creature data and level-up move data. It may set event variables or result flags. It mutates party data only after confirmation. Then control returns through the runtime shell to the script or overworld. Later, battle, summary, and save all observe the effect. One feature, many systems.

Let’s also be precise about source authority. For FireRed, our primary evidence today is not an abstract design pattern book. It is the actual source organization. pokefirered/src/pokemon_summary_screen.c, chunk chunk_e8e17a42bbf17d46, shows the summary screen living at the intersection of Pokémon interfaces, menu helpers, party menu constants, battle constants, moves, strings, region map support, and other UI systems. That tells us summary is a broad reader and presenter of party-adjacent data. pokefirered/src/learn_move.c, chunk chunk_af3598df6f092723, gives us the move relearner state machine setup and list menu behavior. pokefirered/src/learn_move.c, chunk chunk_e820ee15ae8caa6d, gives us the later teaching and replacement phases, including the branch between empty move slots and full move sets. Those chunks are enough to support the architectural claim that FireRed separates screen-session state from creature-record mutation and routes mutation through explicit menu states.

Now, someone may ask: is this separation always perfectly pure in a production GBA codebase? No. Real codebases use globals, script variables, compact task data, and sometimes surprising helper functions. FireRed is not a textbook written in C. But that is exactly why our method matters. We are not saying, “Find the pure object-oriented model.” We are saying, “Trace ownership and mutation through the actual runtime style of the game.” In this codebase, the style is callback-driven, task-driven, table-driven, and state-machine-heavy. So we adapt our architecture vocabulary to that reality.

Let me add one more concrete edge case, because it will matter for the lab. What if the selected candidate move is already known by the Pokémon? A robust move-learning UI should detect that and avoid a meaningless replacement flow. Depending on the exact feature and source path, that may be handled before the list is built, during selection, or during confirmation. The architecture point is the same: eligibility checks are reads and validations. They are not mutations. You can read the current move slots, compare against candidateMoveId, display “already knows this move,” and return to the list without touching the creature record. That is a clean validation failure.

Another edge case: what if the party slot changes while the screen is open? In FireRed’s controlled flow, the UI is usually entered with a selected party member and the broader game does not let arbitrary party reordering happen underneath it. In a modern clone with asynchronous UI or networked state, you would need to guard against stale slot references. You might store a creature ID plus slot index, or lock the party screen while the session is active. The principle from FireRed still helps: party slot ownership is a contract. If your menu points at slot two, then either slot two must remain stable for the session, or your architecture must explicitly handle invalidation.

And now we can tie this to the homework standard for week eleven. Since recent homework and quizzes have already checked your ability to identify files, structs, functions, constants, data tables, and state variables, I am going to expect more than “the summary screen shows Pokémon data” or “the move relearner changes a move.” That answer is now too coarse. I want you to be able to say: the summary screen is a read-oriented UI over the selected party slot; its screen state can change without mutating the party record. The move relearner is a multi-state UI transaction; it reads eligibility and move data, holds candidate and cursor state in the session, branches on empty versus full move slots, and commits a party-data mutation only after the relevant confirmation and old-slot selection. That is the level of precision expected.

Take a breath and look back at the board. We have three vertical layers now. At the top: visible player flow. Choose move, confirm, maybe forget old move, see result. In the middle: screen state. Candidate move, list cursor, prompt state, old move cursor, result flag. At the bottom: domain data. Party slot, move slots, PP, script variables, later save state. The whole trick is to keep arrows between layers honest. Reads can go upward freely. Writes must go downward only at commit points. Return values or script flags can go sideways back to the caller after the transaction resolves.

That mental model is what you should bring into the workshop. First, implement a party summary screen model that reads creature data without mutating it. I recommend you make the read-only nature visible in your API. If your language supports const references, immutable views, selectors, or copy-based view models, use them. If it does not, name things carefully and test no mutation across page changes. Then add the move-learning flow. Do not begin by writing the replacement function. Begin by naming the states. Once the states are named, the replacement function becomes small, almost boring: given a creature, a slot index, and a move ID, update that slot at the authorized time.

And one final note before we move on: this is also where FireRed and Pokémon Showdown can be compared without confusing their roles. Showdown’s data and tests are useful later when we talk about deterministic battle simulation and learnset validation, as the research packet reminds us with pokemon-showdown/data learnset modules and pokemon-showdown/test materials. But for today’s architecture, FireRed remains the primary source because we care about party data moving through gameplay screens on the GBA: callbacks, menus, script returns, and party mutation. Showdown can help you think about battle data hooks and regression tests; it should not replace the FireRed screen architecture we are studying.

So, the transition into the next part is this: we have treated the move relearner as a transaction over one party member. Now we are going to widen the lens slightly and ask how a party menu, summary screen, and move-learning screen pass control among each other without losing track of who owns the selected slot, who owns temporary UI state, and who is allowed to mutate creature data. That handoff is where many clone projects become fragile, and it is also where FireRed’s callback-and-task architecture gives us a very concrete model to study.

So let’s draw that handoff on the board as three boxes, left to right. First box: party menu. Second box: summary screen. Third box: move-learning flow. Now above the boxes I am writing “stable identity,” and below the boxes I am writing “temporary presentation.” Those two phrases are the whole issue. The stable identity is which party slot, which Pokemon record, which actual stored creature we are talking about. Temporary presentation is cursor position, page number, selected move row, scroll offset, whether a prompt is open, whether the palette fade has finished, and so on.

Now, if you blur those two categories, your clone becomes brittle very quickly. You get bugs like, “I opened the summary for slot three, backed out, taught a move, and now slot two changed,” or, “the UI says I replaced Tackle, but the save data replaced Growl.” Those bugs are rarely battle formula bugs. They are ownership bugs. They happen because a screen kept an index after the source list changed, or because a menu state mutated data before confirmation, or because a screen cached a copy of data and then wrote the copy back too broadly.

FireRed is valuable here because it does not treat these screens as isolated app pages. It treats them as gameplay states inside the same runtime shell we studied in the first weeks. The party menu does not live in a web-router style universe. The summary screen does not own the whole game. The move relearner is not a separate modal in a garbage-collected object hierarchy. They are callback and task-driven routines that borrow control, manage local screen state, and then return control to another system. That is why the source relationships matter. In pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, the include list itself is already evidence of the screen’s role: it pulls in pokemon.h, pokemon_summary_screen.h, task.h, menu helpers, link, overworld, strings, item constants, party menu constants, trade, battle_main, move constants, region map support, field specials, and party_menu. That is not random noise. That is a summary screen positioned at the intersection of creature data, menu rendering, party workflows, link restrictions, item display, battle context, and field return behavior.

Pause on that for a second. A summary screen is not “just a UI.” It is a read-heavy gameplay screen that needs to know enough about many systems to present truthful information, but it should not therefore become the owner of all those systems. That distinction is architectural maturity. A naive implementation sees many includes and says, “Oh, this screen controls everything.” A better reading says, “No, this screen depends on many contracts, and its job is to coordinate reads and transitions while keeping mutation narrow.”

Here is the concrete example. Suppose the player opens the party menu, selects the second Pokemon, chooses summary, flips to the moves page, inspects move one, then backs out. What should have changed in the party data? Nothing. Maybe the screen’s internal page index changed. Maybe the cursor row changed. Maybe background tilemaps, sprites, windows, and palettes changed. But the Pokemon’s species, level, moves, PP, held item, experience, condition, and other stored attributes should be exactly as they were. In our lab this week, that is why I asked you to implement a party summary screen model that reads creature data without mutating it. I did not make that a warm-up by accident. At this level, you should be able to separate “I displayed the selected creature” from “I modified the selected creature.” Those are different permissions.

Now I am going to add a small mark between the first and second box on the board. That mark is the selected party slot. In many game engines, you might pass a pointer, an entity ID, an array index, or a handle. In a FireRed-like architecture, the important thing is not which exact representation you choose in your clone. The important thing is that you can answer, at every boundary, “Does this screen own the creature, or does it merely refer to it?” For party Pokemon, the party array is the owner. A summary screen can be given a slot and can read through the Pokemon interface that we discussed in prior lectures. We are not going to re-teach GetMonData-style APIs today; you already had that in the creature records and species table lectures. But we are going to use that foundation. The screen asks the Pokemon model, “What is this creature’s nickname? What is its current HP? What are its moves?” It should not reach through every abstraction and casually rewrite the stored record just because the player moved a cursor.

Check your understanding here: if the summary screen displays a move’s base power and accuracy, where should that information come from? Not from a copied string baked into the summary page. It should be read by following the move ID from the Pokemon’s move slot into the move data table. And if the player simply views the move page, do we write anything back to the Pokemon? No. We have performed a read across two data domains: party creature data and move data. That is enough.

Now, when we move from summary into move learning, the permission model changes. The move-learning flow is allowed to mutate, but only after it has earned that right through the state machine. This is where pokefirered/src/learn_move.c matters. In chunk_af3598df6f092723, the comment explicitly frames the move relearner as a state machine, beginning with CB2_MoveRelearner_Init and then moving through states like fade to black, initialization, menu setup, list input, and so on. Notice the supporting modules: script.h, task.h, field_fadetransition.h, overworld.h, menu helpers, list_menu.h, event_data.h, text_window.h, pokemon_summary_screen.h, constants for songs and moves. Again, those dependencies tell us the workflow’s position in the larger architecture. The move relearner is a menu state machine entered from event scripting in the overworld, using task-like frame progression and menu input, eventually returning a result to the script layer.

That last phrase matters: returning a result to the script layer. The relearner is not just a function that edits a move array. It is a gameplay transaction connected to an NPC, a cost or condition, a selected Pokemon, a selected move, confirmation prompts, possible cancellation, fanfare, and script continuation. So if you are building a clone, the correct abstraction is not “teachMove(pokemon, move)” as the whole feature. That function may exist inside the implementation, but the feature is a stateful transaction around that mutation.

Let’s walk it slowly. The NPC script says, in effect, “We are entering a special menu.” The runtime fades or transitions into that menu. The menu builds a list of eligible moves. The player chooses one. The system asks for confirmation. If the Pokemon has an empty move slot, the mutation can be simple: place the move into the empty slot and initialize its PP. If all move slots are full, the system must branch into a replacement flow. In pokefirered/src/learn_move.c, chunk_e820ee15ae8caa6d, the documented states make that shape visible. The excerpt describes a teach move confirmation state, then says that if the player confirms and the Pokemon had an empty move slot, VAR_0x8004 is set to TRUE and the flow proceeds toward text and fanfare. If the Pokemon does not have an empty slot, the state machine prints the trying-to-learn prompt, waits, asks whether to delete an old move, and only then proceeds toward choosing which move to forget.

So look at the board now. I am drawing a vertical line inside the move-learning box labeled “commit point.” Everything before that line is selection, preview, and intention. Everything after that line is mutation and result reporting. In a robust architecture, you should be able to cancel before the commit point and leave the Pokemon unchanged. You should be able to back out of the move choice, decline to forget an old move, or stop teaching, and the stored move slots should remain exactly as they were. Once the player confirms the replacement, then and only then do we mutate the move slot.

This commit point is one of the most important ideas in week 11. It applies beyond move learning. Item use has commit points. Trading has commit points. Evolution has commit points. Saving has an especially serious commit point. Link battles and trades have distributed commit points, which is one reason the link system appears late in the course rather than early. But the move relearner gives us a clean local example because one party member is selected, one move is selected, and one set of prompts controls whether mutation occurs.

Now, I want to connect this back to the whole course architecture, because by week 11 you should be seeing the stack rather than isolated files. At the bottom, we have creature data and species or move tables. Above that, we have systems that interpret those records: party management, battle, inventory, summary UI. Around that, we have runtime shell mechanics: callbacks, tasks, fades, and frame dispatch. Beside that, we have event scripting, which initiates features like an NPC offering move relearning. And outside or across those layers, we have save and link systems, which constrain when data can be persisted or exchanged. Today’s topic sits right in the center of that stack. Party data is a shared gameplay asset. The summary screen reads it. The move relearner conditionally mutates it. The script layer reacts to the result. The UI has to stay synchronized without becoming the owner of the data.

If you compare that with battle setup, you can see the same architectural pattern at a larger scale. In pokefirered/src/battle_setup.c, chunk_494d132a59422c85, the include list ties battle setup to task, overworld, item, sound, pokemon, load_save, scripts, event data, field movement, battle transition, and related systems. That is another handoff-heavy boundary. The overworld has to initiate battle, the party data has to feed battle participants, battle has to run in its own engine context, and then the game has to return to the field with consequences applied. We are not studying battle setup in detail today, but I want you to see the family resemblance. FireRed often solves gameplay transitions by putting a state machine at the boundary between systems.

Let’s do a quick check for understanding. Imagine you are writing tests for your week 11 lab. You open the summary screen for party slot one. You navigate through all pages. You press B to return. What assertion should you make about the underlying party member? You should assert that the serialized Pokemon record, or at least the relevant fields you expose in your clone, are unchanged. Now you enter the move relearner. You select a move. You cancel at the confirmation prompt. What should your assertion be? Still unchanged. Now you select the move again, choose to replace the second existing move, and confirm. What should change? Exactly the selected move slot, and the PP value associated with that new move if your model tracks PP. What should not change? Species, level, personality, experience, other move slots, held item, friendship, and so on unless your implementation has a very explicit reason. That is how you test mutation boundaries.

And I want to be a little strict here because the recent homework and quiz work has already checked your ability to trace systems through files, structs, globals, callbacks, tasks, scripts, and concrete source functions. At this point in the course, “the menu changes the Pokemon” is not a sufficient explanation. Which menu state? After which confirmation? Through which selected slot? Does it write directly, or does it call a Pokemon helper? Does it report success back to event script? Does cancellation unwind cleanly? These are the questions you should ask automatically now.

Let’s talk about menu state as temporary state. In the move relearner excerpt, chunk_af3598df6f092723 refers to listMenuScrollPos listening to right and left buttons, and listMenuScrollRow listening to up and down buttons. That detail is small but revealing. Scroll position is not party data. The highlighted row is not party data. A list of eligible moves may be derived from party data and learnset data, but the player’s current scroll offset is a screen concern. If the selected Pokemon knows four moves, that is stored creature state. If the move list is currently scrolled to row five, that is UI state. If the player presses down, you update UI state. If the player confirms a move and passes the relevant checks, then you may update creature state.

This is the exact separation that modern UI architectures also try to achieve, although with different vocabulary. You might call it model versus view state, domain state versus component state, persistent state versus ephemeral state. FireRed does not use React or Redux or a modern scene graph, obviously, but the architectural problem is the same. The source makes the old-school version concrete. List menus, tasks, callbacks, text windows, and event variables coordinate the flow; the party array remains the stable domain object being referred to.

Now I’ll give you a failure case, because failure cases make the architecture easier to remember. Suppose you build the move relearner by copying the selected Pokemon into a temporary Pokemon object when entering the menu. The player selects a new move. You update the temporary object as soon as they highlight the move so the preview can show it. Then, when they cancel, you forget to discard the temporary object cleanly, or you write it back during screen exit because your screen always “saves its state.” That is a classic accidental mutation. The player did not confirm, but the Pokemon changed. Another version: you store only a pointer to “current selected Pokemon,” but then the party menu allows switching or sorting while the move relearner still assumes the pointer is valid. Now you have identity drift. FireRed’s constrained screen transitions reduce that kind of risk because each gameplay screen has a narrow mode of operation, but the design principle still matters in your clone.

Let’s bring the summary screen back in. Why does the summary screen need to be involved in a discussion of move learning? Because move learning often asks the player to reason about current moves. Even if the move relearner is not literally the same as the general summary screen, both features consume the same data: move IDs, PP, names, descriptions, and the selected party member. The summary screen is the read-only reference model. It proves that a complex screen can pull from many systems without mutating party data. The move relearner is the controlled mutation model. It proves that UI can mutate party data, but only under a staged confirmation flow. Together, they define the principle for the week: gameplay screens must be explicit about whether they are observers or transaction managers.

Now, say that phrase back to yourself: observers or transaction managers. A summary screen is primarily an observer. A party menu might be a dispatcher, because it sends you to item use, summary, switch, give item, or move selection depending on context. A move relearner is a transaction manager. It starts with a selected creature and a menu of legal operations, then either commits one operation or exits without changing the creature. That language will help you design your own architecture.

We should also notice the script variable in the move relearner flow. The excerpt in chunk_e820ee15ae8caa6d mentions VAR_0x8004 being set to TRUE when the confirmed teaching succeeds into an empty slot path. In FireRed-style scripting, event variables are a bridge between screen-level routines and script logic. The NPC script does not need to know every cursor movement inside the menu. It needs to know the outcome. Did the player teach the move? Did they cancel? Should the script print a follow-up line? Should it consume an item or payment? The menu state machine owns the interaction. The script layer owns the surrounding event logic. That is another ownership boundary.

Here is a concrete design rule for your lab implementation. Your summary screen model should accept a party reference and a selected slot, then produce display data from the current Pokemon without writing to it. Your move-learning flow should accept a party reference, a selected slot, and a candidate move list or a way to compute that list. It can maintain local state such as selected candidate move, selected replacement slot, prompt state, and scroll state. It should expose a commit action that applies the move replacement exactly once after final confirmation. If you implement that as a reducer, a state machine, or callback functions, I do not care as much as I care about the boundary: reads are cheap and frequent; writes are narrow and confirmed.

Now, one more check for understanding. If the player is in the replacement prompt, looking at four existing moves, and moves the cursor from move one to move two, has any party data changed? No. If the UI preview shows “forget Ember,” has any party data changed? No. If the player presses A on Ember but the game asks “Stop learning the new move?” and the player says no or backs out, has any party data changed? Still no, depending on the exact branch. The mutation occurs when the state machine reaches the confirmed teach or replace operation. That is why the state list in learn_move.c is not incidental documentation. It is the behavioral contract.

This is also why we keep FireRed as the primary source for this course. Pokemon Showdown is excellent for thinking about battle data hooks, deterministic test cases, and data-driven learnsets in a simulator setting, and we used it that way in week 10. But Showdown’s architecture is not trying to solve GBA menu callbacks, palette fades, event script returns, party menu dispatch, and summary screen tile rendering. For this lecture, the primary evidence must stay in pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, and pokefirered/src/learn_move.c, chunks_af3598df6f092723 and_e820ee15ae8caa6d, because those are the files showing how party data crosses gameplay screens in the FireRed engine style.

So, as we move into the next section, keep the board diagram in mind. Party menu selects identity. Summary screen reads identity. Move relearner stages a transaction against identity. Event script receives outcome. The runtime shell supplies callbacks, tasks, fades, and frame-by-frame control so those transitions can happen without losing the selected slot. That is the architecture we are extracting, and it is more useful than memorizing any single function name. Next, we are going to look more closely at the shape of the party slot handoff itself: what must be stored, what can be recomputed, and what should never be trusted after the player has moved from one gameplay screen into another.

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