# Species Tables Feeding Runtime Pokemon

Lecture ID: lecture_w09_d02
Week 9, Day 2

## Objectives
- Use Pokemon Showdown as a secondary comparison for battle data hooks, Dex/mods, simulator turns, and regression testing without replacing FireRed as the main architecture source.
- Connect week 9 material to the overall course plan.

## Transcript
Good afternoon. Let’s pick up exactly where yesterday’s lecture left us. Yesterday we treated a Pokemon, in FireRed’s architecture, not as “a monster object” in the modern object-oriented sense, but as a record with a public contract around it. That distinction matters. The record is allowed to be compact, packed, partially encrypted, and inconvenient internally, because the rest of the engine is not supposed to poke at that raw layout directly. The rest of the engine is supposed to ask questions through an access boundary. In the FireRed source focus for this week, that boundary is visible in `pokefirered/include/pokemon.h`, especially the Pokemon struct contract in `chunk_8e98575ccadc6d51`, the mon data constants and access pattern declarations in `chunk_2cc1cd9d6bfc7136`, and then the implementation side in `pokefirered/src/pokemon.c`, `chunk_af8613c6e25be253`.

So today’s question is not simply, “What fields are in a Pokemon?” That was the beginning. Today’s question is, “How does a species table feed a runtime Pokemon without making every Charmander identical?” That is the architectural problem. Species data is the template. Runtime Pokemon data is the individual. The engine needs both. If it only had the species table, every member of the same species would have the same level, HP, moves, status, friendship, ownership, personality, and growth history. If it only had runtime records with no species table, it would duplicate base stats, types, growth rates, learnsets, egg groups, abilities, and other shared facts across every individual creature. FireRed avoids both extremes by separating durable individual state from shared species metadata.

Let me put that on the board. On the left, I’ll write “species facts.” Base HP. Base Attack. Types. Catch rate. Growth rate. Gender ratio. Egg cycles. Learnable moves, depending on which table we’re discussing. On the right, I’ll write “individual facts.” Species ID, yes, because the individual needs to point back to the table. But then also personality, original trainer identity, experience, level-derived stats, current HP, moves known right now, PP right now, status, held item, friendship, ribbons, and so on. The architecture lives in the arrow between these two columns. FireRed’s runtime code repeatedly asks, “Given this individual’s species ID and current stored state, what should the game now display, compute, or mutate?”

That arrow is the topic of the lecture.

Now, before we dive into the table mechanics, I want to connect this to the overall course plan. In weeks 1 through 3, we treated FireRed as a layered runtime: startup code, main callbacks, tasks, and data tables. We traced how `AgbMain` gets the machine into a known state, how `SetMainCallback2` changes the current high-level mode, and how `RunTasks` acts as per-frame dispatch. Then in weeks 4 through 8, we moved outward into maps, object events, scripts, flags, variables, and UI flows. You learned that an NPC is not just a sprite, and a script is not just dialogue. A map object record points to runtime object state; script labels point into bytecode-like command streams; flags and variables become world memory. I am not going to re-teach that today. Instead, I want you to notice the rhyme. A map object record becomes runtime object behavior through callbacks and script execution. A species record becomes runtime creature behavior through Pokemon records, accessors, stat calculation, move logic, battle setup, summary screens, and storage boundaries.

That is the broader pattern of this course: data table, runtime state, access boundary, visible behavior.

Species tables are one of the cleanest examples because the player constantly experiences the result. When you catch a Pidgey, the player sees a creature with a nickname slot, an original trainer, a level, current HP, four move slots, experience progress, nature-like personality effects in later engines, and a summary screen. But underneath that experience, the engine is mixing table data and individual data over and over. The species table tells the engine what Pidgey is. The Pokemon record tells the engine which Pidgey this is.

Look at the source focus for today. The declarations and contract live in `pokefirered/include/pokemon.h`, with the broader Pokemon data declarations in `chunk_55fc8220f5b93cdc`, the struct contract in `chunk_8e98575ccadc6d51`, and the mon data constants in `chunk_2cc1cd9d6bfc7136`. The actual species information table is in `pokefirered/src/data/pokemon/species_info.h`, `chunk_99a58307a160a13c`. The runtime implementation that makes these records usable is in `pokefirered/src/pokemon.c`, `chunk_af8613c6e25be253`. Those are the core FireRed sources for today. Keep those four locations mentally grouped: header contract, species table, accessor constants, implementation.

Now, let’s slow down over the word “feeds.” I am using it deliberately. The species table does not become the Pokemon. It feeds calculations, initialization, validation, display, and battle setup. A species record might provide base stats. But the Pokemon record stores the actual current stats after level, IVs, EVs, nature rules where applicable, and other transformations have been applied. A species record might provide typing. But the individual may temporarily behave differently in battle because of move effects, abilities, volatile statuses, or battle scripts. A species record might define a growth rate. But the individual stores experience. The level can be derived or synchronized from experience, depending on the operation being performed.

Here is a concrete example. Suppose we create a level 5 Bulbasaur as a starter. The engine needs a species ID for Bulbasaur. That species ID is the bridge into `gSpeciesInfo` or the equivalent species info table in `pokefirered/src/data/pokemon/species_info.h`, `chunk_99a58307a160a13c`. From the table, the engine can learn Bulbasaur’s base stats, types, growth behavior, and other shared facts. But the actual starter in your party also needs a personality value, original trainer data, current experience, current HP, move slots, PP, friendship, and calculated stats. Those do not belong in the species table. They belong in the individual Pokemon or BoxPokemon representation described by the Pokemon contract in `pokefirered/include/pokemon.h`, `chunk_8e98575ccadc6d51`.

Now pause there. If I ask, “Where should Bulbasaur’s base Special Attack live?” the answer is species data. If I ask, “Where should this Bulbasaur’s current HP live after a battle?” the answer is individual runtime or stored Pokemon data. If I ask, “Where should the fact that this individual currently knows Tackle in move slot 0 live?” that is individual data. If I ask, “Where should the fact that Bulbasaur as a species can have certain starting or learnable moves live?” that is shared species or move-learning data, depending on the table being consulted. Check your understanding: the same visible summary screen is the result of both sides. It is not “all table” and it is not “all object.”

This is exactly why `GetMonData`-style accessors are not just convenience wrappers. They are architectural pressure valves. The header constants in `pokefirered/include/pokemon.h`, `chunk_2cc1cd9d6bfc7136`, define the vocabulary that other systems can use to ask for data: species, HP, status, moves, PP, experience, and so forth. The implementation in `pokefirered/src/pokemon.c`, `chunk_af8613c6e25be253`, then decides how to retrieve or set that data from the underlying representation. The battle AI, the summary screen, daycare, party menu, trade, storage system, and script specials do not all need to know the raw storage layout. They need a stable question-and-answer interface.

You have already seen this pattern with scripts. A script command handler hides the exact mechanics of a flag write or a message box transition from the map event that invoked it. Here, the accessor hides the exact mechanics of reading a possibly packed creature record from the system asking about it. Different subsystem, same design instinct.

Let me give you a subsystem example from the packet. In `pokefirered/src/battle_ai_script_commands.c`, `chunk_34a415cc38858fdc`, the AI command code iterates over party slots and asks for values like species, HP, and status using `GetMonData`. That is a very high-signal architectural clue. Battle AI cares about battle decisions. It should not decode Pokemon storage. It should not care whether a value is directly stored, packed, derived, or protected by a checksum boundary. It asks for `MON_DATA_SPECIES`, `MON_DATA_HP`, and `MON_DATA_STATUS`, and the Pokemon module answers. That is the access boundary doing real work.

Notice also the party dimension in that example. The party is not a list of species. It is a list of individual Pokemon records. If the AI scans the enemy party and sees a species, that species is only one field among many. The same party slot also has HP, status, level, moves, and other individual facts. That is why the lab this week asks you to implement a minimal creature record with species ID, personality, level, experience, moves, PP, stats, and accessor functions that hide the raw storage layout. The lab is not asking you to clone the entire FireRed structure. It is asking you to practice the boundary. Can your battle code, summary code, and storage code ask stable questions without knowing how the bytes are arranged?

Now, let’s compare briefly with Pokemon Showdown, but carefully. Showdown is not our primary architecture source. FireRed is. FireRed is a GBA game built around C structs, static tables, memory-constrained storage, callbacks, tasks, and platform-specific constraints. Pokemon Showdown is a server-side simulator with TypeScript data modules, Dex abstractions, mods, battle objects, and a test harness. We use Showdown as a secondary comparison because it makes some battle-data ideas extremely explicit. It should sharpen our understanding of FireRed, not replace it.

In Showdown, the Dex and mods architecture lets the simulator ask, “Which generation or ruleset’s data am I using?” That is a different solution to a different problem. FireRed mostly has one compiled ruleset and one main species table for its target game. Showdown has to support many generations, formats, modded data layers, and regression tests across them. So when you look at Showdown’s data modules, such as the research packet’s recurring references to `pokemon-showdown/data`, and especially modded data like `pokemon-showdown/data/mods/gen9dlc1/learnsets.ts`, `pokemon-showdown/data/mods/gen9predlc/learnsets.ts`, and `pokemon-showdown/data/mods/gen8dlc1/learnsets.ts`, you are seeing a modern simulator’s answer to “how do we swap or layer data rules?” FireRed’s answer is much more static: compile the table, index by species, use C accessors and engine functions.

But the common idea is still valuable. Both engines need a disciplined route from species identity to battle behavior. Showdown’s route often goes through Dex lookups, modded data tables, and event-like hooks. FireRed’s route goes through constants, structs, tables, and functions compiled into the ROM. If we pretend these are the same architecture, we learn the wrong lesson. If we compare them as two answers to related pressure, we learn a lot.

For example, the packet gives us `pokemon-showdown/data/mods/gen2stadium2/scripts.ts`, `chunk_3480e574205d5d0f`, where damage calculation logic checks things like move identity, immunity, OHKO behavior, damage callbacks, fixed damage, and level-based damage. That chunk is useful today not because FireRed implements damage in TypeScript, obviously it does not, but because it shows how a simulator exposes battle data hooks as first-class control points. The move can carry behavior. The battle object can call into that behavior. A rules mod can alter the script. In FireRed, comparable behavior is distributed through C battle code, move effect tables, constants, battle scripts, and runtime battler state. Different mechanics, same architectural concern: how do declarative-ish battle facts and procedural battle rules meet during a turn?

Let’s make that distinction sharper. In FireRed, a species table entry is not a battle turn. It is not enough to say, “Charizard has these base stats and types.” During battle, the engine also needs the individual Charizard’s level, current HP, stat stages, status, selected move, PP, held item, ability-related behavior where the generation supports it, side conditions, weather, and the opponent’s state. Some of that begins with species data. Much of it is individual or battle-context state. So when we say “species tables feed runtime Pokemon,” we are describing the first part of a pipeline, not the whole pipeline.

On the board, I’ll draw the pipeline as four boxes. First box: species table. Second box: individual Pokemon record. Third box: party or battle participant projection. Fourth box: battle turn state. The arrow from species table to individual record is used during creation and stat calculation. The arrow from individual record to party or battle participant is used when entering battle, opening menus, healing, trading, storing, or summarizing. The arrow from battle participant to battle turn state is used when the engine resolves actions frame by frame or command by command. Showdown’s simulator turn model is very explicit about this later part. FireRed’s battle system is more tightly coupled to its C runtime and state arrays, but conceptually the same distinction applies: a species is not a turn participant until individual and battle context are layered on top.

Let’s do a quick check for understanding. Imagine you are implementing a move relearner. Which data do you need? You need the individual Pokemon, because you need to know which party slot the player selected and which moves it currently knows. You need species-related move history or learnset data, because you need to know what moves are eligible. You need UI state, because the player navigates a list. You need script or callback transitions, because the move relearner is entered from the overworld and menu flow. In the packet, `pokefirered/src/learn_move.c`, `chunk_af3598df6f092723`, is described as a move relearner state machine with menu states and task/callback-like flow. That is a perfect example of this course’s recurring shape. The feature is player-facing, but its architecture crosses creature records, species or learnset knowledge, menus, scripts, and task-driven state.

If you answered, “The move relearner only needs the species table,” that is incomplete. If you answered, “The move relearner only needs the Pokemon’s current moves,” also incomplete. The interesting feature is in the join.

Now, let’s connect this to stored state and packed boundaries. Yesterday we introduced the idea that a Pokemon record can have an internal representation that the rest of the engine should treat as private. Today, we need to emphasize why that privacy becomes more important as the project grows. In a small toy RPG, you might store a creature as a plain struct and let any system read `creature.hp` or `creature.moves[2]` directly. That can work for a prototype. But the moment you add storage boxes, trading, checksums, save serialization, encryption or obfuscation, derived stats, migration, and UI screens, direct field access becomes a liability. Every caller becomes coupled to your storage layout.

FireRed’s `GetMonData` pattern is a disciplined answer. In `pokefirered/include/pokemon.h`, `chunk_2cc1cd9d6bfc7136`, the mon data constants form a shared vocabulary. In `pokefirered/src/pokemon.c`, `chunk_af8613c6e25be253`, the implementation can centralize the details. This lets other modules remain relatively ignorant. For instance, the summary screen source, `pokefirered/src/pokemon_summary_screen.c`, `chunk_e8e17a42bbf17d46`, includes `pokemon.h`, battle constants, move constants, party menu, trade, and other UI-related headers. That tells us the summary screen is a consumer of Pokemon data, not the owner of the Pokemon storage design. It needs to display the creature. It should not define what a creature is.

That distinction is subtle but important at an advanced level. We are no longer just identifying files. That was an earlier assessment skill. You have already been checked on mapping major systems to files, structs, functions, constants, tables, and state variables. Now I expect you to explain coupling direction. Which module owns the representation? Which module consumes it? Which constants are part of the public contract? Which fields should not leak? Which calculations should be centralized because they must remain consistent across battle, summary, party menu, daycare, storage, and save?

Let’s use daycare as another example, but again we will not fully open that system today. The packet points to `pokefirered/src/daycare.c`, `chunk_119931105f546346`, with includes across battle, data, mail, Pokemon storage, event data, random, moves, menu, script, party menu, overworld, Pokedex, trade, and more. That include list alone tells you daycare is a crossing point. It touches stored Pokemon, species-related compatibility and offspring logic, UI, events, and world progression. If daycare code had to understand every byte of Pokemon storage directly, it would be fragile. Accessors let it ask stable questions and perform controlled mutations.

Now, I want to make one careful correction to a common mental model. Students often say, “The species table is like a class, and each Pokemon is like an instance.” That analogy is partly useful, but it can mislead you. In an object-oriented language, a class usually carries behavior and instances carry fields, with dispatch rules managed by the runtime. FireRed’s species table is not a class in that sense. It is a static data table. It does not own methods. Behavior lives in engine functions that interpret species IDs, move IDs, item IDs, battle states, and script commands. So a better analogy is: the species table is a database table of shared facts, and the Pokemon record is a save-backed individual row that points into that table. The engine functions are the query and simulation logic.

Let me say that another way. Species ID is a foreign key. Not literally SQL, of course, but architecturally it behaves like one. A Pokemon record stores a species ID. Many systems use that ID to look up shared facts. The table does not reach into the Pokemon. The Pokemon does not copy the whole table. The engine joins them when needed.

This also explains why accessors often take a pointer to a Pokemon and a data ID. The caller is saying, “For this individual, give me this fact.” Some facts come from stored individual data. Some facts may be derived. Some facts may require special handling. A clean accessor boundary allows the implementation to evolve. In your lab, when you implement `GetCreatureData` or whatever you name it, I want you to preserve that design idea. Do not expose the whole storage struct to battle and UI code just because it is easier. Make the easy thing look slightly more formal now so that later features do not tear through it.

Let’s return to Showdown for a moment, specifically regression testing. One of the reasons Showdown is valuable as a comparison is that its simulator has to be tested against many edge cases. The research packet identifies `pokemon-showdown/test` as a recurring module around assertions, Pokemon, moves, battle, species, and Showdown. FireRed’s original codebase is not organized around modern unit tests in the same way. So when we use Showdown in this course, one of its best contributions is not “copy its architecture.” It is “notice what a battle simulator makes testable.” A Showdown-style regression test can assert that a particular interaction resolves a particular way under a particular ruleset. In a FireRed-inspired engine project, you can borrow that testing instinct even if your runtime model is closer to FireRed.

For example, suppose your minimal creature record lab includes stat calculation. A FireRed-inspired test might create a species table entry with known base stats, create an individual creature at level 10 with known personality or IV-like values, call the accessor for calculated Attack, and assert the result. A battle-oriented test might create two creatures, feed them into a simplified damage function, and assert that changing species base Defense changes the result while changing current HP does not change the calculated incoming damage except through fainting checks. That is the level of precision I expect now. You are not just building structs. You are building trustable seams between table data, individual state, and simulation logic.

And again, Showdown gives us a language for this. In `pokemon-showdown/data/mods/gen2stadium2/scripts.ts`, `chunk_3480e574205d5d0f`, the simulator’s damage path explicitly considers move callbacks, fixed damage, level damage, immunities, and other hooks. In your FireRed architecture reading, ask the parallel question: where does FireRed encode equivalent hooks? Is it in a move effect constant? A battle script? A C function? A table field? A status flag? That question will carry us into the battle module in later weeks.

For today, though, stay anchored on the species-to-runtime boundary. If you lose that anchor, the rest of battle architecture becomes mushy. You will start attributing everything to species data or everything to battle state. Neither is correct.

Let’s walk through a creature’s life cycle at a high level, using the systems we have already covered as stepping stones. A script gives the player a starter. We are not re-teaching script command handlers, but remember: the script system can trigger engine functions that mutate world and party state. That starter creation function needs a species ID and a level. It initializes an individual record. During initialization, it consults species data for base facts. It assigns or receives a personality value. It chooses moves. It calculates stats. It places the record into a party slot. Later, the summary screen reads the party slot through Pokemon accessors. Later still, the battle engine projects that party member into battler state. After battle, changes such as HP, experience, level-up moves, PP, or status are written back to the individual record. If stored in a PC box, the representation may shift toward a BoxPokemon boundary. If traded, ownership and personality-related display behavior matter. If saved, the data must serialize correctly.

That is a lot of systems. But the course plan is designed so that none of those words are new anymore. Runtime shell, callbacks, tasks, scripts, flags, variables, data tables, UI, party, save. Week 9 is where the creature itself becomes the center of gravity.

Now, before we move to the next layer, I want to leave you with a diagnostic question. When you inspect any creature-related function in FireRed, ask: is this function reading shared species facts, reading individual stored facts, deriving a value from both, or mutating the individual? Those four categories will keep you sane. Reading shared species facts points you toward `species_info.h`, `chunk_99a58307a160a13c`, and related data. Reading individual facts points you toward the Pokemon and BoxPokemon contract in `pokemon.h`, especially `chunk_8e98575ccadc6d51`. Deriving values from both points you toward implementation code in `pokemon.c`, `chunk_af8613c6e25be253`. Mutating individual facts should make you look for accessor discipline and storage safety, again grounded in the mon data constants from `pokemon.h`, `chunk_2cc1cd9d6bfc7136`.

Let’s check understanding one more time before we continue. If a summary screen displays “Level 16,” is level necessarily stored as a raw independent field? Not necessarily. Depending on the representation and operation, level may be stored, derived from experience, cached, or synchronized. What matters architecturally is that the summary screen should not need to know the entire policy. It asks through the Pokemon data API. If battle AI wants to know whether a party member is fainted, should it inspect the raw struct layout? No. The packet’s battle AI example in `pokefirered/src/battle_ai_script_commands.c`, `chunk_34a415cc38858fdc`, shows the healthier pattern: ask for species, HP, and status through `GetMonData`.

All right, with that foundation set, we can now get more precise. Next I want to separate creation-time use of species tables from read-time use of species tables, because those are often confused. Creation-time use means the table helps initialize an individual. Read-time use means the table remains a reference for interpreting that individual later. The same species entry can participate in both, but the data flow is not identical. So keep the board diagram visible: species facts on the left, individual facts on the right, accessors in the middle, and battle or UI consumers downstream. We are going to use that diagram for the next pass.

Creation-time species use is like consulting a blueprint before construction. Read-time species use is like consulting a standard after construction. When FireRed creates or regenerates a Pokemon, it needs the species record for base stats, types, growth rate, gender ratio, egg data, and initial move possibilities. That is species table as input. But once the individual exists, the runtime Pokemon owns its personal facts: personality, experience, current HP, PP, IV-like hidden values, EV-like accumulated values, moves, condition, held item, and so on. Those are not simply copied species facts. They are the creature’s history.

Now, look back at the board. I am circling the arrow from species facts to individual facts and writing “initialization.” Then I am circling the arrow from individual facts back through accessor code to UI and battle, and writing “interpretation.” The same table sits on the left, but it is not doing the same job both times.

A concrete example. Suppose we create a Bulbasaur at level five. The species table gives us Bulbasaur’s base stats and growth behavior. The creation code can combine species, level, experience rules, personality, and stored substructure fields to compute the starting stats. But later, when the summary screen displays the Pokemon, it should not say, “Bulbasaur’s HP is whatever the base HP says.” It has to read this individual’s level, HP, max HP, experience, moves, PP, and status. That is why the accessor layer matters. The Pokemon summary module, supported by pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, includes pokemon.h, data.h, constants for moves, party menu pieces, battle-facing headers, and other UI dependencies. That include pattern is not accidental. The summary screen is a consumer of creature data, not the owner of the storage format.

Check yourself here: if I change a species table entry, which existing Pokemon facts should change immediately, and which should not? Base-stat interpretation may affect recalculated derived stats when recalculation occurs. A species type lookup may affect battle behavior. But the individual’s nickname, personality, current PP, status condition, and experience do not magically become new values just because the species table was edited. That distinction is one of the core week 9 skills.

Now let’s add Pokemon Showdown as a comparison, carefully. Showdown is useful because it makes many battle data hooks explicit. Its data layer and simulator layer are built for a different environment: server-side JavaScript or TypeScript, text-driven battle simulation, many generations and mods, strong testability, and fast iteration. FireRed is a Game Boy Advance program with compiled C data, fixed memory assumptions, callbacks, tasks, save constraints, and direct UI integration. So we do not replace FireRed with Showdown. We use Showdown to name patterns we can then recognize in FireRed.

In Showdown, a move, ability, or generation mod can attach behavior through hooks. The research packet points us toward pokemon-showdown/data as a recurring module and specifically notes data, learnsets, mods, and moves as high-signal areas. It also points to pokemon-showdown/sim as the simulator-side module around Battle, Dex, Pokemon, and Move concepts. The architectural lesson is this: Showdown separates data lookup, mod selection, and turn simulation in a way that makes regression testing very natural. FireRed does not present the same abstraction boundaries, but FireRed still has boundaries. They are just expressed through headers, constants, globals, C structs, tables, and functions like GetMonData.

Let me put that comparison on the board as two columns. On the FireRed side I am writing: species_info.h table, Pokemon and BoxPokemon structs in pokemon.h, accessor constants, pokemon.c implementation, battle consumers, summary consumers, save consumers. On the Showdown side I am writing: Dex, data files, mods, simulator Battle object, event hooks, tests. The important move is not to say one is better. The important move is to ask what pressure each architecture was responding to.

FireRed’s pressure is cartridge-era runtime stability. It wants compact stored data and predictable access. That is why the contract in pokefirered/include/pokemon.h, chunk_8e98575ccadc6d51, is so central for us this week. The struct contract tells other modules what a Pokemon is allowed to be at the boundary. The mon data constants and access patterns in pokefirered/include/pokemon.h, chunk_2cc1cd9d6bfc7136, then give the rest of the game a vocabulary for asking questions without manually decoding raw storage. The implementation in pokefirered/src/pokemon.c, chunk_af8613c6e25be253, is where those questions become actual reads, writes, recalculations, and storage decisions.

Showdown’s pressure is maintainable competitive simulation across generations. It needs a Dex that can answer, “What does this species or move mean in this generation or this mod?” It needs simulator turns that are deterministic enough to test. It needs modded learnsets and data overrides, as suggested by the packet’s references to pokemon-showdown/data/learnsets.ts and pokemon-showdown/data/mods/gen9dlc1/learnsets.ts, pokemon-showdown/data/mods/gen9predlc/learnsets.ts, and pokemon-showdown/data/mods/gen8dlc1/learnsets.ts. That tells us Showdown treats “which data universe am I in?” as a first-class question. FireRed, by contrast, is mostly one compiled data universe, unless we as hackers or engine maintainers create variants.

Now, bring that back to species tables feeding runtime Pokemon. In FireRed, the species table in pokefirered/src/data/pokemon/species_info.h, chunk_99a58307a160a13c, is part of the compiled world. A runtime Pokemon stores a species ID, not a full copy of every species fact. This means the individual record is compact, but also that consumers must know when to dereference the species table. If the battle system needs type information, it can derive it from species. If it needs current HP, it must read the individual. If it needs whether the Pokemon is alive, again, individual HP. If it needs base catch rate for capture logic, species table. If it needs friendship, individual. If it needs growth rate, species. If it needs experience points, individual.

That list sounds simple, but advanced bugs happen exactly where developers blur it. Imagine you are implementing our lab’s minimal creature record. You include species ID, personality, level, experience, moves, PP, and stats. Now you add a function called GetCreatureAttack. Should that function return the species base attack? No, not if it is modeling runtime battle stats. It should return the individual’s computed attack after level, species base stat, individual modifiers, training modifiers, nature-like personality interpretation if present in your design, and any battle-stage modifiers if battle state is included. But should the record store base attack directly? Probably not, unless you have a cache invalidation reason. The species table already owns the base attack fact.

Here is the board cue: I am writing three questions under every field. “Who owns it?” “When is it computed?” “Who is allowed to read it?” For species base stats, species table owns it, creation and recalculation consult it, consumers should read through species-aware functions. For current HP, the individual owns it, battle and item usage mutate it, consumers read through mon accessors. For displayed max HP, it may be stored or computed depending on the exact representation, but it must remain consistent with the individual and species. That is the engineering habit I want from you now.

Let’s use the battle AI example one more time, not to re-teach script commands, but to sharpen the data boundary. In pokefirered/src/battle_ai_script_commands.c, chunk_34a415cc38858fdc, the AI code shown in the packet walks party slots and asks for species, HP, and status through GetMonData. Architecturally, that is a battle subsystem inspecting party state through a creature API. It is not a battle subsystem knowing the raw encrypted or packed layout. This matters because the party is stored as Pokemon records, the PC may store BoxPokemon-like records, and internal substructures may have constraints that should not leak everywhere.

Now compare Showdown. In Showdown, a simulated Pokemon object is already a battle-facing object in a simulator. The packet’s Showdown comparison around pokemon-showdown/data/mods/gen2stadium2/scripts.ts, chunk_3480e574205d5d0f, shows damage logic calling into move data and callbacks: damageCallback, fixed damage, level-based damage, immunity checks, and so on. In other words, Showdown’s battle turn can ask an active move object what special behavior it has. FireRed also has battle data and battle code, but much of the specialization is expressed through C functions, constants, tables, and battle script machinery rather than TypeScript object hooks. The comparison helps us see a design axis: do you attach behavior to data objects, or do you drive behavior through central engine code that interprets IDs and flags?

Neither answer is universally correct. For FireRed’s original target, compact data and centralized engine interpretation are natural. For Showdown’s target, extensible hooks and testable simulation objects are natural. But when you build your own creature RPG, you must choose deliberately. If your species table includes an ability ID, where does the ability behavior live? Is it a switch in the battle engine? A function pointer table? A script? A data-defined hook? A rules object loaded by a Dex? Your answer determines how easy it is to add content, how easy it is to test, and how much runtime memory you spend.

Quick check for understanding. I will give you four facts, and you tell yourself whether they belong in the species table, the individual Pokemon record, battle temporary state, or UI-only state. “Charmander’s base speed.” Species table. “This Charmander has 17 current HP.” Individual record, or battle copy synchronized from it depending on moment. “This Charmander is at minus one attack stage during this battle.” Battle temporary state. “The cursor is currently highlighting this Charmander in the summary screen.” UI-only state. Good. If that classification feels automatic, you are ready for the more subtle part.

The more subtle part is that FireRed often has layered versions of truth. A party Pokemon is persistent enough to be saved. A battle battler may carry derived or temporary battle values. A menu may cache strings or sprites. A script may hold a selected party index in a variable. The fact that several layers refer to “the same Pokemon” does not mean they have the same ownership. This is why earlier course work on callbacks, tasks, and scripts still matters. We are now threading creature records through the runtime shell we studied in week 1 and the event system we studied later. A script can choose a party slot. A callback can open a party menu. A task can animate a selection. A battle system can copy or derive battle-facing state. But the underlying Pokemon record remains a controlled storage object with access rules.

This is also why week 9 sits at the start of the Creature and Party Data Model module, leading into weeks 10 and 11. We are not just memorizing struct fields. We are preparing to understand battle entry, party management, storage, healing, leveling, evolution, move learning, and save persistence. The move relearner file in pokefirered/src/learn_move.c, chunk_af3598df6f092723, is useful as a preview because it includes script, task, data, menu, summary screen, graphics, strings, and move constants, and the packet notes its state machine comments. That is exactly the kind of cross-system feature that becomes manageable only when creature records have stable boundaries. The move relearner is not merely a menu. It is a script-entered, task-driven UI that consults Pokemon data and move data, then mutates an individual’s move slots according to engine rules.

Let’s walk a concrete scenario. The player talks to a move relearner. We do not need to re-teach NPC local IDs or script command handlers; those are prior foundations. The script gets us into a special flow. The menu needs to know which Pokemon is selected. The move list needs to know what species and level history imply about available moves. The UI needs to display move names and maybe PP or type. When the player chooses a move, the individual Pokemon’s move set and PP must change. The species table does not get edited. The learnset data does not get edited. The selected Pokemon record changes. If the engine later saves the game, that changed move slot persists.

Now, if you were building the lab version, this is where accessor design pays off. You might create GetCreatureData(creature, CREATURE_DATA_SPECIES), GetCreatureData(creature, CREATURE_DATA_MOVE1), SetCreatureData(creature, CREATURE_DATA_MOVE1, value), and RecalculateCreatureStats(creature). The point is not to imitate names mechanically. The point is to prevent the move relearner, battle AI, summary screen, daycare, and storage code from each learning the raw byte layout. The daycare source excerpt, pokefirered/src/daycare.c, chunk_119931105f546346, demonstrates how a feature can sit at a busy intersection of systems: battle, items, mail, Pokemon storage, event data, random, move constants, menu, scripts, overworld, Pokedex, naming, help, and trade. A module like that should not also be responsible for knowing packed creature internals.

Pause there. Notice how our course pattern is repeating: data table to runtime object to callback, task, or script to visible behavior. In week 2, we saw generated data and headers as contracts. In the overworld weeks, we saw map records, object events, and scripts. In week 8, you were assessed on identifying files, structs, functions, constants, data tables, and state variables that implement major systems. Week 9 is now forcing you to use that skill at a smaller granularity. Not “where is the Pokemon system?” but “which exact layer owns this exact fact?”

Let me make the Showdown testing comparison concrete. In Showdown, because battles are simulator objects and the data universe can be selected through Dex and mods, you can write regression tests that say, in effect, set up a battle, pick two Pokemon, execute a move, assert the result. The research packet points us to pokemon-showdown/test as a module around assert, Pokemon, moves, battle, species, and Showdown, including pokemon-showdown/test/TESTS.md, pokemon-showdown/test/assert.js, and pokemon-showdown/test/common.js. FireRed does not naturally give us that same high-level test harness. If we want regression confidence in FireRed-like code, we usually need to isolate pure-ish functions, build harnesses around data tables, or test behavior through emulator-oriented integration. That is not a reason to abandon FireRed’s architecture. It is a reason to understand what testing support the architecture gives us and what we may need to add.

For your project work, this matters. If your species data is plain C tables and your runtime records are packed structs, test your accessor functions directly. Test that setting a move does not overwrite PP. Test that changing species ID triggers whatever recalculation policy you intend. Test that a fainted creature is detected by current HP, not by species. Test that serialization preserves individual fields. Then, if you borrow from Showdown conceptually, borrow the discipline of deterministic setup and assertions. Do not borrow the whole data model blindly.

I want to close this segment with a synthesis, but not the lecture, because we still need to go further into how species-derived stats are recalculated and where packed storage boundaries become dangerous. The synthesis for this pass is: species tables feed runtime Pokemon in two different ways, initialization and interpretation. Accessors protect the individual record from casual structural dependency. Battle, UI, daycare, move learning, and scripts should consume creature facts through that boundary. Pokemon Showdown gives us a secondary vocabulary for Dexes, mods, battle hooks, simulator turns, and regression tests, but FireRed remains our architectural source because its constraints are the constraints we are studying.

So keep the diagram up. Species facts on the left. Individual facts on the right. Accessors in the middle. Consumers downstream. Now we are going to zoom into the accessor side and ask what happens when a getter is not just a field read, but a policy decision.

When I say policy decision, I mean the getter is deciding what the rest of the program is allowed to know, and in what form. A field read says, “Here is the byte at this offset.” An accessor says, “Here is the meaning of this creature fact, after storage format, validity, encryption or packing, and runtime rules have been accounted for.”

So, board cue here, I am going to write three phrases under the word accessor: raw location, semantic name, permitted interpretation. Raw location is where the data physically lives. Semantic name is something like species, level, current HP, move one, friendship, or held item. Permitted interpretation is the rule that says, “When some other system asks for this fact, this is the version of the fact it receives.”

That distinction is why the constants in pokefirered/include/pokemon.h, chunk_2cc1cd9d6bfc7136, matter so much. A constant such as a MON_DATA-style identifier is not merely a nicer spelling for an offset. It is a public vocabulary. The battle system, party menu, summary screen, daycare, scripts, and move learning code can ask for a creature fact without taking a dependency on the precise shape of BoxPokemon or Pokemon. That is the architectural point. The codebase is not saying, “Everyone may rummage through this struct.” It is saying, “Here is the authorized vocabulary for creature facts.”

Now, advanced students, this is where I want you to slow down, because the naive version of this idea is too simple. The naive version is, “Accessors are good because they hide fields.” True, but insufficient. In this engine, accessors are also the place where a stored creature becomes safe enough to use. If an individual Pokemon has packed substructures, if some parts are encrypted or checksummed, if box storage excludes runtime-only battle values, if party storage includes current HP and calculated stats, then a getter may have to cross a representation boundary.

And when a getter crosses a representation boundary, it becomes policy.

Let’s use a concrete example. Suppose a menu wants to display a Pokemon’s species name and current stats. The species name comes from the creature’s individual species ID, but the meaning of that species ID points back into the species table. The stats, however, are not simply “in the species table.” They are calculated from several sources: species base stats, the individual’s level, individual variance, training values, possibly nature in later-facing design discussions, and current runtime state such as HP. In FireRed’s layout, the contract for Pokemon and BoxPokemon is declared in pokefirered/include/pokemon.h, chunk_8e98575ccadc6d51, and the species facts are centralized in pokefirered/src/data/pokemon/species_info.h, chunk_99a58307a160a13c. So if the summary screen asks for attack, it should not be manually reconstructing the storage path from those pieces. It should ask through the Pokemon data API and then present the result.

That is exactly why pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, is useful as a consumer-side reference. Notice the includes in that file: pokemon.h, data.h, constants for moves and items, battle-facing headers, party menu headers. The summary screen sits at the junction of several systems. It needs creature facts, move facts, item facts, and UI behavior. But architecturally, we do not want summary UI code to become the owner of creature representation. It should consume the public creature contract.

Check for understanding. If I ask you, “Why should the summary screen not directly decode packed Pokemon data?” the answer is not just “because that would be messy.” The stronger answer is: because direct decoding would duplicate storage policy in a UI module, and then every future change to storage, validation, encryption, checksum handling, or stat recalculation would have to be audited across UI code. That is the real failure mode.

Now let’s connect this to stat recalculation, because this is where many creature RPG implementations quietly become inconsistent. There are two broad categories of data on the board. On the left, stable species facts: base HP, base attack, typing, growth rate, learnability, ability slots, body metadata, and so on. On the right, individual facts: personality, experience, level, moves, PP, current HP, status, friendship, held item, and the rest. Calculated stats live between those two categories. They are not purely species facts, and they are not purely arbitrary individual facts. They are derived runtime facts.

So when does the game calculate them? At creation? On level-up? After vitamins? After evolution? When entering battle? When healing? When loading from save? The answer in a production engine is usually not “one magical time.” Instead, there are several events that can invalidate calculated stats, and the code needs a known path for rebuilding them. FireRed’s pokemon.c implementation, identified in the packet as pokefirered/src/pokemon.c, chunk_af8613c6e25be253, is the implementation side of that contract. That is where the accessor vocabulary becomes actual behavior.

Let me give you a design smell. If five different systems each know the formula for max HP, you do not have a creature model; you have five approximations of one. One approximation will eventually forget a level boundary. Another will handle eggs differently. Another will mishandle an invalid species. Another will display a value before recalculation. That is how data-driven games produce bugs that look supernatural from the player’s perspective but are completely ordinary from the source perspective.

Now, a quick FireRed-specific framing. BoxPokemon is the stored creature shape. Pokemon is the party/runtime creature shape. The exact structure contract is not something we are inventing in lecture; it is anchored in pokefirered/include/pokemon.h, chunk_8e98575ccadc6d51. The reason this split matters is that a boxed creature does not need every volatile runtime value in the same form as a party creature. Party members participate in battles, menus, healing, item use, and overworld-triggered checks. Boxed creatures must be compact, persistent, and safe to store. So if you are implementing the week 9 lab creature record, and you put every possible derived value into the saved record with no accessor boundary, you have missed the lesson. The lab asks you to implement species ID, personality, level, experience, moves, PP, stats, and accessor functions that hide raw storage layout because the architecture is about controlling which facts are persisted and which facts are derived.

Let’s put a small example on the board. Imagine a stored record:

species equals Bulbasaur, level equals 12, experience equals some number, move slots contain Tackle and Vine Whip, PP values are stored beside those moves, and calculated attack is currently 18.

Now the creature levels to 13. What changes? Experience changes. Level may change. Max HP, attack, defense, speed, special attack, and special defense may change. Current HP may need a policy decision: does it increase by the delta in max HP? Is it preserved as an absolute number? Is it clamped? Moves may change if the level triggers a learn move opportunity. Evolution may become available depending on rules outside just the stat formula. The species table did not mutate. The individual did. But the individual’s derived stats are valid only after recalculation.

So if another system reads attack immediately after the level changes but before recalculation, you have a stale read. If another system writes attack directly, you have an authority problem. If another system reads species and level and recomputes attack itself, you have duplicated policy. The accessor layer and the related mutation functions are how you prevent those three bugs.

Now let’s bring in Pokemon Showdown, carefully, because it gives us useful comparison language but it is not replacing FireRed here. Showdown’s architecture is battle-simulator-first. Its data folders, such as pokemon-showdown/data and pokemon-showdown/data/mods, organize species, learnsets, formats, and generation-specific modifications in a way that is extremely useful for deterministic battle testing and variant rules. The packet specifically calls out pokemon-showdown/data/learnsets.ts and several modded learnset files like pokemon-showdown/data/mods/gen9dlc1/learnsets.ts, pokemon-showdown/data/mods/gen9predlc/learnsets.ts, and pokemon-showdown/data/mods/gen8dlc1/learnsets.ts as high-signal sources. That tells us something important: Showdown treats “which moves can this species learn under this ruleset?” as a data problem with mod overlays.

FireRed also has species and learn data, but its architecture is bound to GBA-era memory, C structs, generated data, save representation, and callback-driven runtime behavior. So the comparison is this: FireRed teaches us how a shipped handheld RPG organizes persistent creature state and runtime consumers under strict constraints. Showdown teaches us how a battle simulator can expose battle data through Dex-style lookup, mods, hooks, and tests. Both care about data-driven species facts. They just optimize for different runtime worlds.

A useful Showdown example from the packet is pokemon-showdown/data/mods/gen2stadium2/scripts.ts, chunk_3480e574205d5d0f. The excerpt shows damage logic routing through move interpretation: resolving a move, checking immunity, handling OHKO moves, handling damage callbacks, level-based damage, fixed damage, and then continuing through damage calculation. That is a battle hook model. A move is not just a number. A move may carry callbacks and special-case behavior. In FireRed, we are not converting the engine to TypeScript hooks. But the comparison helps you name the idea: battle data often has points where plain table values are not enough, and the runtime needs controlled behavior hooks.

The FireRed equivalent, conceptually, is not “copy Showdown’s Dex.” The FireRed equivalent is: identify where tables feed battle behavior, where battle code asks for creature facts, and where constants and accessors define the contract. That is why a battle AI file such as pokefirered/src/battle_ai_script_commands.c, chunk_34a415cc38858fdc, is worth noticing. The excerpt shows AI command code looking through a party, selecting either enemy party or player party, and retrieving species, HP, and status through GetMonData-style calls. That is a beautiful architectural clue. Even battle AI script commands, which are low-level and performance-sensitive, are not simply poking random offsets for species and HP. They are consuming party creature facts through the data API.

Let me say that again in plainer terms: the AI is downstream of the creature model. It should not own the creature model.

That also connects back to our previous weeks. In week 7 and week 8, we practiced tracing visible behavior from data records through globals, callbacks, tasks, scripts, structs, and concrete source functions. We looked at script pointer execution, command handlers, flags, variables, object events, and local IDs. We are not re-teaching that today, but we are using the same method. Instead of tracing an NPC’s script entry, we trace a creature fact. A species table entry becomes a base stat, typing, or growth rule. A party slot holds an individual record. An accessor exposes a fact. A consumer such as battle AI, summary UI, daycare, move learning, or script logic asks for that fact. Visible behavior follows.

This is the overall course pattern. Every major system is some version of data table, runtime state, dispatch mechanism, and visible behavior. In week 1, we named the whole RPG stack. In the runtime shell lectures, AgbMain, SetMainCallback2, CreateTask, and RunTasks gave us the frame loop and callback/task architecture. In overworld and script weeks, map headers, object events, triggers, flags, variables, and script command handlers gave us world behavior. Now in week 9, Pokemon and BoxPokemon, species info records, accessors, party slots, and packed storage boundaries give us creature identity and progression. Weeks 10 and 11 will lean on this. Battle cannot be understood cleanly unless creature facts have a clear source. Save persistence cannot be understood cleanly unless we know which creature fields are stored and which are derived. Link behavior cannot be understood cleanly unless the serialized creature contract is stable.

Now, one more concrete case: daycare. The packet includes pokefirered/src/daycare.c, chunk_119931105f546346, and even from the include list you can see the daycare system touches pokemon storage, event data, random, moves, party menu, overworld, Pokedex, naming, trade, and more. That should immediately raise your architectural caution. Daycare is not “just one feature.” It is a feature sitting across creature storage, progression, move inheritance or move handling, script interaction, UI, and world state. Therefore daycare code must be especially disciplined about how it reads and writes Pokemon facts. If daycare logic needs a species, compatibility value, move, or stored creature field, it should use the established data contract rather than assuming a private layout.

This is the advanced lesson: the more cross-system a feature is, the less freedom it should have to bypass boundaries.

Now pause and check yourself. If I say, “The daycare module includes pokemon_storage_system.h and pokemon.h, so it is allowed to know everything about storage,” is that correct? No. Including a header gives the module access to the public contract. It does not mean the module should duplicate every internal assumption. In C, the language will often let you do more than the architecture wants you to do. Good engine code depends on social and structural discipline, not just compiler enforcement.

The move relearner gives us another useful consumer example. pokefirered/src/learn_move.c, chunk_af3598df6f092723, is identified in the packet with a comment describing a move relearner state machine: initialization, list menu scroll positions, menu states, and UI transitions. Again, we are not re-teaching task and menu state machines, but notice the junction. The move relearner must ask, “What species is this? What moves are available? What moves does this individual already know? What slot can be overwritten? What does the player choose?” Species-level learnability and individual move slots meet inside a UI-driven state machine. If you muddle species data and individual move storage, move relearner behavior becomes hard to reason about.

Showdown’s learnsets give a useful contrast here. In Showdown, learnsets are prominent data modules because the simulator must answer legality and ruleset questions across formats and generations. In FireRed, learnability is part of the handheld RPG’s progression, UI, and save-bound creature model. Again, same domain, different architectural center of gravity.

Let’s use a small mental exercise. Suppose you add a new species to your lab engine. You add the species table entry but forget to update the accessor that validates species IDs. What happens? Maybe creation works, but summary display fails. Maybe battle stat calculation reads past the table. Maybe move learning sees the species as invalid. Maybe save/load preserves the species ID but runtime code treats it as an egg or empty slot. The exact failure depends on the engine, but the pattern is universal: species table expansion must be coordinated with the public creature-data vocabulary and the validation policy.

That is why I keep drawing the line between initialization and interpretation. During initialization, the species table seeds the individual. It may determine starting stats, growth rate, typing, base friendship, ability possibilities, or legal starting moves. During interpretation, the individual’s species ID points back into the species table whenever a system needs species facts. A Pokemon does not carry a full private copy of all species data. It carries identity and individual state. The species table remains the shared source for species-level facts.

So let’s be precise. If a Charmander evolves into Charmeleon, what changes? The individual remains the individual. Personality, original trainer data, experience, move PP, friendship, and other individual facts may persist according to game rules. Species changes. Since species changes, derived stats must be recalculated using the new base stats. Typing changes if the species table says it changes. Ability interpretation may need a rule. Learnsets available from that point forward may differ. The individual record is continuous, but species interpretation is redirected.

That is the elegance of the model. Identity is not equivalent to species. Species is one field in the individual record, but many systems treat it as a key into a larger table.

Now, because you are advanced students, I want to name a risk that appears when people overlearn the accessor lesson. They sometimes make every getter recompute everything every time. That sounds clean, but it can be expensive and can produce inconsistent side effects if getters are no longer pure. The better distinction is: accessors should expose valid facts; mutation paths should maintain derived facts; recalculation should occur at known invalidation points; expensive derivations should be cached only when there is a clear owner and refresh policy.

In FireRed terms, a getter for current HP should not secretly level up the Pokemon. A getter for attack should not decide to process evolution. A function that handles level gain may recalculate stats, update HP policy, and trigger move learning. A getter should not become an unbounded gameplay event. So when I say “getter as policy,” I do not mean “getter as hidden game loop.” I mean the getter protects representation and returns the semantically correct view of the requested data.

Let me write that on the board: accessors are boundaries, not garbage cans. If the rest of the engine is confused about ownership, dumping all logic into GetMonData-style functions does not fix the architecture. It just hides the confusion. The data API should centralize representation knowledge. It should not absorb unrelated feature flow.

Now, we should connect this to regression testing, because the homework already asked you to consider Pokemon Showdown as a secondary comparison for battle data hooks, Dex/mods, simulator turns, and regression testing. Showdown’s test area, especially pokemon-showdown/test as identified in the packet, matters because a simulator can run deterministic battle scenarios quickly. It can assert that a rules interaction still produces the expected result after data or hook changes. FireRed’s decompilation context is different, but we can borrow the testing mindset. If you change species data, stat formulas, move learning data, or accessor policy, you should have small tests or lab harnesses that prove the visible facts did not drift.

For your lab, a regression test might create a creature from species ID and level, read its stats through accessors, level it up, recalculate, and confirm that raw storage was not directly accessed by the test except through a controlled fixture. Another test might put a creature into a boxed form and then restore it to party form, verifying that species, personality, moves, PP, and experience persist, while runtime stats are reconstructed. That test is FireRed-inspired, even if your implementation is smaller.

A Showdown-inspired test would be more turn-oriented: create a battle state, choose moves, advance a simulator turn, and assert outcomes. We are not there yet as the main project layer. But when we reach battle architecture, you will see why Showdown’s model is attractive for regression testing. It isolates battle rules from rendering and overworld state. FireRed’s battle system lives inside a full handheld engine with callbacks, tasks, graphics, audio, save, party, and item integration. So tests require more careful slicing.

Let’s do one final check for understanding before we move forward. I am going to ask three questions, and I want you to answer them mentally.

First, when a consumer asks for MON_DATA_SPECIES, what architectural dependency should it take? It should depend on the public Pokemon data API and constants, not on a private offset inside packed storage.

Second, when a system needs base attack or growth rate, where is the authority? Species-level authority belongs in the species info table, anchored today by pokefirered/src/data/pokemon/species_info.h, chunk_99a58307a160a13c, with the individual species ID acting as the key.

Third, when current attack is stale after level-up or evolution, what kind of bug is that? It is an invalidation and recalculation bug. It is not solved by copying base stats into more places. It is solved by defining mutation paths and derived-stat refresh policy.

Good. Now keep that mental model up, because next we are going to look at packed storage boundaries more sharply. In particular, we need to ask what happens when the same conceptual fact, say “move in slot two” or “held item” or “experience,” is represented differently depending on whether the creature is in a boxed record, a party record, a trade buffer, a battle struct, or a UI selection buffer. That is where advanced engine work gets interesting, because the question stops being “Where is the field?” and becomes “Which representation is authoritative at this moment in the game flow?”

So, let us sharpen that authority question, because it is one of the places where students who are otherwise very good C programmers start making architectural mistakes. They look at a creature and say, “Well, the move is stored here.” And my answer is, “At which phase?” Stored for save persistence? Stored for party display? Stored for battle execution? Stored for a menu preview? Stored for a trade? Those are not all the same question.

If I draw this on the board, I am going to put one label in the middle: conceptual Pokemon. That is the thing the player imagines they own. Around it, I am going to draw several boxes: boxed storage record, party record, battle participant state, summary-screen view, move-learning UI, daycare logic, and AI query. Same creature, different operational needs. The player experiences continuity. The engine does not necessarily store continuity in one universal shape.

FireRed’s architecture makes this especially clear because the creature contract is not just “a struct with fields.” The week’s source focus in pokefirered/include/pokemon.h, especially chunk_8e98575ccadc6d51 for the Pokemon struct contract and chunk_2cc1cd9d6bfc7136 for mon data constants and access patterns, tells us that the rest of the program is expected to ask for creature facts through named data channels. In plain language, the header says: here are the legitimate questions you may ask about a Pokemon, and here are the public pathways for asking them. That is an API boundary, even though we are in C and not in a modern object system.

Now, why does that matter? Because once a value can be packed, encrypted, derived, cached, or temporarily copied, direct field access becomes a liability. If you bypass the accessor and read a slot directly, you are betting that the raw representation you see is the current authoritative representation. In FireRed, that is often the wrong bet. The GetMonData-style pattern exists so callers can say, “Give me MON_DATA_SPECIES,” or “Give me MON_DATA_HP,” or “Give me the move in this slot,” without needing to know whether that datum lives in a compact substructure, a party-only extension, or a derived region that requires checksum or encryption handling. The implementation side in pokefirered/src/pokemon.c, chunk_af8613c6e25be253, is where that contract becomes behavior.

Let us take a concrete example. Suppose the player opens the summary screen. The summary screen needs name, species, level, item, moves, PP, stats, experience progress, ribbons or status depending on generation and UI page, and enough presentation data to render a coherent view. But the summary screen should not become the owner of those facts. It is a consumer. The include list in pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, is a useful reminder: that module reaches across pokemon.h, party menu, battle constants, item constants, strings, and region map sections. It is a coordination surface, not the canonical creature store. If the summary screen starts inventing its own interpretation of personality, met data, move legality, or stat calculation, then you have duplicated the creature model inside a UI module. That is how a small game becomes unmaintainable.

Check your understanding here. If the summary screen shows Attack as 72, where did 72 come from? Not from the species table alone. Not from the party struct alone in the abstract. It is the result of base stats from species data, level, individual values, effort values, nature or generation-specific rules where applicable, and current stored or derived stat fields. So the correct mental model is not “the summary screen reads Attack.” It is “the summary screen requests a stat fact that has been produced by the creature data system under the current rules.” That distinction is subtle, and it is the kind of distinction advanced architecture work depends on.

Now let us connect this back to species tables. The species table in pokefirered/src/data/pokemon/species_info.h, chunk_99a58307a160a13c, is not a list of living Pokemon. It is a table of species defaults and species rules. It tells us what a species is like before individuality, before party history, before current HP, before move PP has been spent, before experience has changed, before the player has attached an item. A Bulbasaur’s base stats are species facts. A particular Bulbasaur’s current HP is instance state. A particular Bulbasaur’s current PP for Vine Whip is instance state. Its legal learnset is species and progression data interpreted by systems such as level-up, tutor, machine, breeding, or special event paths. If you collapse those into one layer, you lose the ability to answer simple questions cleanly.

Let me put another board note here: species data feeds creation and recalculation; instance data preserves history and current condition. That sentence is worth keeping. Species data is upstream of many computations, but it is not the runtime creature itself.

Consider move learning. The move relearner module, pokefirered/src/learn_move.c, chunk_af3598df6f092723, even announces itself as a state machine in the excerpt. It has menu states, list scrolling, fade transitions, and selection handling. But from our perspective today, the important point is not the menu polish. The important point is that a move-learning interface has to consult species or learn data, inspect the current Pokemon, produce a candidate list, and then mutate the Pokemon only through a legitimate update path. If it directly scribbles a move ID into raw packed storage without updating PP, display state, or any related invariants, you get mismatched records. The player sees one move. Battle uses another move. Or the move appears with zero PP because you changed the move but not the associated PP slot. That is not a visual bug. That is a broken data boundary.

This is also where our lab for the week is deliberately designed to be small. You are implementing a minimal creature record with species ID, personality, level, experience, moves, PP, stats, and accessor functions that hide the raw storage layout. I do not want you to build all of FireRed. I want you to feel why accessors are not ceremony. In your lab, if you store moves and PP as parallel arrays, the accessor should protect their relationship. If you later change the storage to a packed move block, code outside the creature module should not care. If you compute stats from species and level, the caller should not manually patch Attack after every level-up. The mutation path should make it hard to leave the object in an invalid intermediate state.

Now, let us bring in Pokemon Showdown, carefully, as a secondary comparison. We are not replacing FireRed with Showdown. FireRed remains our main architecture source because our course is about a cartridge-era creature RPG: packed records, save constraints, field scripts, party slots, UI callbacks, and battle integration. Showdown is useful because it makes some battle-data hooks more explicit and more testable in a modern simulator architecture.

In the Showdown excerpt from pokemon-showdown/data/mods/gen2stadium2/scripts.ts, chunk_3480e574205d5d0f, the damage flow checks immunities, handles OHKO moves, calls a move damage callback when present, handles fixed damage, and continues through damage calculation. That is a different environment from FireRed, but architecturally it gives us a clean contrast. Showdown has data and scripts that can attach behavior to move definitions or modded rule sets. FireRed also has move data and battle logic, but the integration style is more static, table-driven C with battle command functions and global battle state. So when you compare them, do not say, “Showdown is better because callbacks.” Say, “Showdown exposes battle hooks in a way that is convenient for a simulator and regression tests; FireRed encodes battle behavior in a form suited to its platform, memory model, and compilation pipeline.”

That comparison is valuable for your final projects. If you are building a modern research engine or a teaching simulator, you may choose Showdown-like hooks for moves, abilities, and formats. If you are building a FireRed-style ROM architecture or a constrained C engine, you may choose table IDs, constants, and switch-like command logic. The deeper lesson is that battle behavior needs a controlled extension surface. Whether that surface is a callback in TypeScript or a battle command table in C, it must preserve determinism and make rules auditable.

Let me ask a quick check-for-understanding question. If a move has special behavior, where should that special behavior live? The beginner answer is, “In the move.” The more precise answer is, “In a battle rule system that can associate that move’s ID or definition with special behavior during the correct battle phase.” That distinction matters because the creature record should not contain the full behavior of Thunderbolt or Protect or an OHKO move. The creature can know that it has a move ID. The battle engine interprets that move ID under the current rules.

This separation shows up in FireRed AI code too. The battle AI excerpt in pokefirered/src/battle_ai_script_commands.c, chunk_34a415cc38858fdc, queries party Pokemon with GetMonData for species, HP, and status. That is exactly the kind of dependency we want to notice. The AI is not presented as the owner of the party record. It asks questions about party members through the Pokemon data interface. Even when the code has a bug or unused path, the pattern is architecturally revealing: AI behavior depends on creature state, but creature state is still behind accessors. So, again, authority is separated from consumption.

Now, there is a subtle consequence here. Once multiple modules consume Pokemon facts, the accessor layer becomes part of the game’s semantic contract. If GetMonData returns species zero for an empty slot, then many systems may build assumptions around that. If HP zero means fainted, then battle, party menu, AI, summary, and script checks may all rely on that convention. If current HP exists only in party records and not boxed records, then moving a Pokemon into or out of the party may require transformation. This is not just “serialization.” It is a domain transition.

Think back to our earlier weeks on scripts, flags, and variables, but do not re-open all of that machinery. We learned that field scripts are not just text; they are runtime control over state. Now, in week 9, the same idea appears inside creature data. A script may award a Pokemon, check the party, start a battle, or give an item. It touches the creature model through controlled functions. The script interpreter does not need to understand packed substructures. It should ask the Pokemon system to create, inspect, or mutate Pokemon. This is the same course thesis again: data table, runtime state, callback or script path, visible behavior.

Daycare is another good example because it crosses so many systems. The FireRed daycare module excerpt, pokefirered/src/daycare.c, chunk_119931105f546346, includes pokemon storage, event data, random, moves, menu, scripts, overworld, Pokedex, naming screen, party menu, and trade-related headers. That import pattern tells a story. Daycare is not merely a box that holds two Pokemon. It is a feature where stored creature records interact with steps, eligibility rules, offspring generation, move inheritance, UI text, map scripts, and player progression flags. If the daycare system modifies creature data, it must do so in a way that preserves the same invariants the rest of the game expects. Otherwise the bug may not appear in daycare. It may appear later in battle, summary, trade, or storage.

Here is a concrete failure mode. Suppose a daycare-like system increments experience or level, but it only changes the visible level field and does not update experience, stats, or moves that should be learned by level. The summary screen may show a higher level. Battle may calculate using stale stats. The move relearner may disagree with the creature’s history. Evolution checks may trigger incorrectly. That is why mutation paths matter. Advanced students should begin thinking in terms of transactions: what facts must change together for the creature to remain valid?

Now, because we are using Pokemon Showdown as a comparison, let us also talk about mods and Dex organization. Showdown’s data model has to support multiple generations and rulesets in one simulator. The research packet points us toward pokemon-showdown/data and pokemon-showdown/sim as recurring modules, especially Dex and mods. Architecturally, a Dex layer answers questions like, “What does this species mean under this ruleset?” or “What does this move do in this generation?” FireRed does not need a general multi-generation mod loader in the same way. It targets one game. But FireRed still has a Dex-like conceptual role: species constants, move constants, data tables, and lookup functions define the ruleset the runtime is using.

So if you are designing your own creature RPG, ask yourself: do I have exactly one ruleset, like a fixed campaign game, or do I need multiple rule contexts, like a simulator, randomizer, competitive sandbox, or mod platform? If you have one ruleset, a FireRed-style compiled data table may be simple and robust. If you need many rulesets, a Showdown-style Dex abstraction becomes more attractive. But do not adopt a mod architecture just because it sounds modern. Every layer you add must earn its complexity.

Regression testing is another place where Showdown is instructive. A simulator can run battle turns deterministically, assert outcomes, and test edge cases for moves, abilities, immunities, and generation-specific mechanics. The research packet points to pokemon-showdown/test as a recurring course module around assert, Pokemon, moves, battle, species, and Showdown. FireRed’s original environment is not arranged around modern unit tests in the same way, but that does not mean FireRed is architecturally unserious. It means verification has a different historical and technical shape. For our course, we borrow the testing lesson: when battle behavior depends on species tables, move data, instance state, and turn order, you need regression cases that pin down the expected outcome.

Here is a simple test design you could write for your lab engine. Create a species with base Attack 50 and base Speed 30. Create a level 10 instance. Give it move slot two with move ID 7 and PP 15. Use only accessors to read the move, current PP, level, and derived stats. Then mutate the level to 11 through the official mutation function. Assert that derived stats refresh and move slot two remains move ID 7 with PP 15 unless your rules say otherwise. Then change move slot two through the official move setter. Assert that PP is initialized or clamped according to the move definition. That is a tiny test, but it protects the exact boundary we are studying today.

Notice what that test does not do. It does not assert the internal byte offset of move slot two. It does not know whether the record is encrypted. It does not know whether the moves are stored in an array, packed bit field, or substruct. That is the point. A test that depends on private layout is brittle. A test that depends on public creature semantics is useful.

Let us pause and recap the main argument so far. Species tables are stable rule data. Pokemon and BoxPokemon records are instance state with different storage needs. Accessors are not syntactic decoration; they are the boundary that lets multiple systems consume creature facts without owning the raw layout. UI, AI, daycare, move learning, battle, and scripts all become safer when they ask the creature system for facts instead of decoding storage themselves. Showdown helps us see modern alternatives for battle hooks, Dex layering, mods, simulator turns, and regression tests, but FireRed remains our primary architectural source for this course.

Now I want to connect week 9 to the broader course plan. In weeks 1 and 2, we talked about the runtime shell: startup, callbacks, tasks, and how a frame gets work done. In the map and script weeks, we followed object events, script entry, flags, variables, and command handlers as the overworld changed state. In week 8, you were assessed on identifying files, structs, functions, constants, data tables, and state variables across major systems. That was not trivia. It was preparation for exactly this moment. Creature architecture is where those skills converge. A Pokemon is data, but it is also UI, battle input, save content, script consequence, party menu entry, trade object, and emotional player property.

That emotional part is not a joke, by the way. In a creature collector, the player treats a creature as continuous identity. The engine may transform its representation repeatedly, but the player believes this is the same companion. Your architecture has to preserve that illusion through very concrete invariants: species, nickname, personality, experience, moves, PP, met data, current health, status, and ownership information cannot casually desynchronize. If the player withdraws a Pokemon and it loses PP state, they will not describe that as a failed storage transition. They will say the game corrupted their Pokemon. The architecture is responsible for preventing that.

For the next segment, keep three questions ready. First, when a system reads Pokemon data, is it reading species rule data, instance stored data, or derived data? Second, when a system writes Pokemon data, what other values must be invalidated or recalculated? Third, when representation changes between boxed, party, battle, and UI contexts, which representation is authoritative at that moment? Those questions will guide us into the more detailed packed-boundary examples, where we will trace a value from species table to party record to battle consumption and back out to player-visible display.

All right, so let us take those three questions and put them to work on a real path through the system. Imagine a Bulbasaur in slot zero of the player’s party. I am deliberately choosing a starter-like example because it touches many systems without needing a special case. At the board, I am drawing three boxes. The first box says species rule data. The second says instance stored data. The third says derived runtime data. Those are not three different Pokemon. They are three different kinds of facts about one Pokemon.

The species rule data answers questions like, what are Bulbasaur’s base stats, types, growth behavior, and learnable structure? In FireRed, that lives in the species information table, and our source anchor for that is pokefirered/src/data/pokemon/species_info.h, chunk_99a58307a160a13c. The instance stored data answers questions like, what is this particular Bulbasaur’s personality value, experience, moves, PP, current HP, status, and ownership state? That contract is declared around the Pokemon and BoxPokemon definitions in pokefirered/include/pokemon.h, especially chunk_8e98575ccadc6d51, with data access constants and patterns around chunk_2cc1cd9d6bfc7136. The derived runtime data answers questions like, after applying species base stats, level, IV-like and EV-like stored values, nature-like personality effects where relevant, and current battle modifiers, what number should the battle engine or summary screen display right now?

Now listen carefully to the direction of dependency. The species table does not know your Bulbasaur. Your Bulbasaur knows a species ID, and systems use that species ID to consult species rules. That seems obvious, but it is one of the deepest architectural decisions in a creature RPG. If each stored Pokemon copied every piece of species data into itself, changing or auditing species behavior would become a nightmare. If each UI screen guessed species data independently, you would get subtle mismatches. FireRed’s pattern is to keep canonical species records separate and let runtime code combine species records with individual records through accessor functions and calculation paths.

Let me give a concrete example. Suppose the summary screen wants to display a Pokemon’s type and stats. The type is species rule data. The current HP is instance stored data. The attack stat is derived data stored or refreshed in the party representation, depending on where in the lifecycle we are. The summary screen includes pokemon.h and many related UI and battle-facing headers, and the packet gives us pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, as evidence that this screen is not operating in isolation. It is a consumer of the creature model. It needs Pokemon data, item constants, move constants, battle constants, region data, party menu machinery, and so on. That is a useful clue: a UI screen is not just painting strings; it is asking the model layer for interpreted facts.

Pause there and check yourself. If I ask, “Where does Bulbasaur’s base Speed come from?” the answer is species rule data. If I ask, “How much experience does this Bulbasaur currently have?” the answer is instance stored data. If I ask, “What Speed value should I show at level 16 with this individual’s stored training values?” the answer is derived data. If those three categories blur in your design, your bugs become expensive because every caller starts making private assumptions.

Now let us move one step closer to the packed boundary. FireRed’s Pokemon structure is not merely a friendly classroom struct with visible fields that every system pokes directly. The architecture uses accessors, and the lecture packet points us to pokefirered/src/pokemon.c, chunk_af8613c6e25be253, as the implementation-side anchor, along with pokefirered/include/pokemon.h, chunk_2cc1cd9d6bfc7136, for mon data constants and access patterns. Why is this important? Because the physical layout of stored creature data is a dangerous dependency. Once storage becomes packed, encrypted, checksummed, separated into box and party forms, or version-sensitive, direct field access becomes a liability.

Here is the professor rule I want you to write in the margin: most systems should ask for Pokemon facts, not know Pokemon storage. That is the reason GetMonData-style APIs matter. They create a boundary between “I need the current HP” and “I know which substructure, offset, packed field, and decryption step contains HP.” Advanced learners sometimes underestimate this because direct field access looks simpler on day one. But direct access makes every future representation change contagious.

Let us walk through a specific value: current HP. Current HP is not a species property. It is not “Bulbasaur has 45 HP” as a universal truth. The species has base HP. This individual has a level, experience, personality-related data, training data, and a current damage state. So when a battle starts, the battle engine needs enough information to initialize battler state from party state. During battle, damage changes battler-facing state. At the end of battle, persistent consequences must be written back to the party Pokemon. If that write-back skips current HP or status, the player sees false recovery. If it skips PP consumption, the player sees duplicated resources. If it writes derived temporary stat stages into the persistent Pokemon record, the player sees corruption. That boundary is not cosmetic. It is the difference between a stable RPG model and a pile of coincidental fields.

Now I want to bring in Pokemon Showdown, carefully, as a comparison, not as a replacement authority. FireRed remains our architecture source because we are studying a Game Boy Advance creature RPG with persistent party records, box records, packed storage, callbacks, tasks, UI screens, and save boundaries. Showdown is useful because it makes certain battle-data hooks very explicit. For example, pokemon-showdown/data/mods/gen2stadium2/scripts.ts, chunk_3480e574205d5d0f, shows a damage path that checks immunities, handles OHKO moves, calls a move damage callback, handles level-based damage, fixed damage, and then proceeds into calculation. I am not saying FireRed implements that exact TypeScript hook structure. I am saying Showdown exposes, in a modern simulator architecture, the same conceptual question: when a battle asks for damage, which facts come from the move’s rule data, which facts come from the active Pokemon instance, and which facts are temporary battle-context facts?

That comparison is powerful for regression testing. In Showdown, tests can construct battles, run turns, and assert outcomes against a simulator model. The research packet flags pokemon-showdown/test as a recurring module, especially around assert, Pokemon, moves, battle, species, and Showdown. FireRed’s architecture predates that style of accessible JavaScript testing, but the lesson transfers. We can still design our lab creature record so that accessors and calculations are testable. If your minimal creature record has species ID, personality, level, experience, moves, PP, stats, and accessor functions, you should be able to write tests that say, “Given this species table entry and this stored instance, after recalculation the displayed stat is this value, and after using a move the PP is this value.” That is the Showdown-inspired testing habit applied back to FireRed-inspired data boundaries.

Let me add the Dex and mods piece, because it matters for advanced architecture. Showdown has a Dex concept and modded data directories, including examples in pokemon-showdown/data/mods, and the packet specifically highlights learnsets files such as pokemon-showdown/data/mods/gen9dlc1/learnsets.ts, pokemon-showdown/data/mods/gen9predlc/learnsets.ts, and pokemon-showdown/data/mods/gen8dlc1/learnsets.ts as recurring high-signal sources. What is the architectural idea there? It is that battle and species data can be layered by ruleset or generation. A Gen 8 DLC ruleset may not have the same learnsets as another ruleset. A simulator needs to ask the active Dex, not some timeless global truth.

FireRed, by contrast, is a fixed shipped game. Its species table is compiled into the program. But even there, the conceptual lesson holds: callers should go through the right data authority. In FireRed, that authority is the compiled species and move data plus the runtime Pokemon instance. In Showdown, that authority is often the Dex for the selected format or mod. In your own engine, if you later support balance patches, fangame versions, randomizers, or multiple generations, this distinction becomes central. You do not want the party record to secretly encode assumptions from the wrong ruleset.

Let us do a quick check for understanding. Suppose you implement a move relearner. The UI asks, “Which moves can this Pokemon relearn?” Is that question answered only by the Pokemon instance? No. The instance gives you species, level, and maybe current moves or special ownership facts. The species and learnset data define what is legally available. The UI state machine lets the player choose and confirm. FireRed’s move relearner file, pokefirered/src/learn_move.c, chunk_af3598df6f092723, is useful here because the excerpt explicitly frames a Move Relearner state machine and includes script, task, menu, Pokemon summary, graphics, strings, and move constants. So again, a user-facing feature is a coordinator. It does not own all the facts. It asks the creature model and rule tables questions, then writes a narrow, persistent change: one move slot changes, and PP must be initialized or adjusted consistently.

That “narrow write” phrase is worth lingering on. A common student implementation error is to make SetMonData too casual. If setting species simply changes the species ID and nothing else, what happens to experience group? What happens to legal moves? What happens to current HP and recalculated stats? In production code, some writes are ordinary and local, like changing current HP after damage. Other writes are identity-altering, like changing species or level, and they require recalculation or validation. The accessor boundary does not magically solve that. It gives you a place to enforce it.

On the board now, I am drawing a line between boxed representation and party representation. A boxed Pokemon can store long-term identity and compact state. A party Pokemon needs battle-relevant derived stats readily available. That does not mean the party copy is a different creature in the game-design sense. It means the runtime representation is shaped by use. Storage wants compactness and stability. Battle wants speed and convenient access. UI wants formatted display. Save wants durable serialization. Trading wants compatible transfer. These are different pressures on the same domain object.

The daycare source excerpt in the packet, pokefirered/src/daycare.c, chunk_119931105f546346, is a good reminder of how broadly creature data gets pulled through the game. Daycare touches Pokemon storage, event data, random, Pokedex, party menu, overworld, naming, trade, and more. We do not need to re-teach event variables from last week, but notice the bridge: a script or overworld interaction may initiate the daycare flow, yet the durable result is creature data mutation. That is week 8 feeding week 9. The script system gets you to the operation; the Pokemon data model determines whether the operation is coherent.

Now let me compare battle AI briefly. The packet includes pokefirered/src/battle_ai_script_commands.c, chunk_34a415cc38858fdc, where the excerpt shows AI script command logic iterating through a party and calling GetMonData for species, HP, and status. That is a very clean teaching example. The AI does not need to know the raw memory layout of each Pokemon in party storage. It asks for species, HP, and status. Also notice the specific mixture of facts. Species is identity or rule-linking data. HP and status are current instance state. The AI script command is making a tactical decision from accessed facts. That is exactly how we want cross-module consumers to behave.

If you are designing the lab version, your AI does not need to exist yet. But your accessor design should make that future AI easy. A future AI should be able to ask getCreatureData(creature, SPECIES), getCreatureData(creature, CURRENT_HP), getCreatureData(creature, STATUS), and not care whether those live in a packed substructure, a flat struct, a saved blob, or a generated test fixture. Advanced architecture is not about making the first version complicated. It is about putting the complication behind the one boundary that is likely to survive.

Let us revisit Pokemon Showdown once more, this time around simulator turns. Showdown’s simulator architecture makes turn execution a first-class testable process. A battle has active Pokemon, selected moves, event hooks, rule data, and a deterministic sequence of updates. The source packet directs us to pokemon-showdown/sim as a recurring module around Battle, Dex, move, and simulator concepts. When Showdown data contains a move callback, as in the gen2 stadium script excerpt from chunk_3480e574205d5d0f, battle behavior is attached to rule data and invoked by the simulator at the correct moment. In FireRed, battle logic is implemented in C across battle engine systems, with data tables and command-like flows suited to the original game. Different implementation style, same architectural tension: persistent Pokemon records should not be casually mutated by every temporary battle event.

Here is a concrete bad design. During battle, you store stat stage changes directly in the Pokemon’s permanent attack and defense fields. Growl lowers Attack, and you write the lowered Attack into the party record. The battle ends, and now the Pokemon is permanently weakened. That is obviously wrong as game behavior, but the architecture error is more general: you confused battle-context derived state with persistent creature state. Correct design keeps temporary modifiers in battle state and writes back only durable outcomes, such as current HP, status, experience, level-up changes, learned moves, PP changes, friendship adjustments, or held item changes when the rules say they persist.

Now, check for understanding again. I will say a fact, and you classify it. “This species is Grass and Poison type.” Species rule data. “This particular Pokemon has 7 PP left on Vine Whip.” Instance stored data. “During this turn, its Speed is effectively doubled because of a battle effect.” Battle-context derived data. “The summary screen displays 31 Attack.” Displayed derived data, probably sourced from recalculated party stats. “The AI sees that an enemy party slot has zero HP.” Instance stored data accessed through a model boundary. If those classifications feel quick now, good. That is the mental muscle this week is building.

Let us connect this to the course plan. In week 1, we decomposed the creature RPG into runtime shell, overworld maps, event scripting, creature data, battle, inventory, UI, save, and link systems. That decomposition was useful, but it was still a map from high altitude. In weeks 2 through 8, we kept tracing table to global state to callback, task, or script to visible behavior. We saw that object events and scripts are not “the game” by themselves; they are entry mechanisms into systems. Now in week 9, Pokemon records are becoming one of the central durable models those systems orbit. Weeks 10 and 11 will build on this. Battle and save behavior become much easier to reason about when we can say exactly what a creature record owns, what species data owns, and what battle state owns.

That is also why homework this week should be stricter than earlier homework. By now, you have already been assessed on decomposing the RPG and tracing source functions. So I am not looking for “I made a Creature class with fields.” I am looking for evidence that your fields have ownership semantics. If your lab has a species table, the creature record should store a species ID, not duplicate the whole species table. If your lab has a getter, it should distinguish raw stored data from computed data. If your lab has a setter, it should not silently violate invariants. If your lab has a party slot, it should be clear whether removing the creature from the slot changes the creature or only changes party membership.

One more FireRed source connection before we transition. The summary screen source, pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, and the AI script command source, pokefirered/src/battle_ai_script_commands.c, chunk_34a415cc38858fdc, are two very different consumers. One is player-facing UI. The other is battle decision logic. Both need Pokemon facts. That is the point. Accessors are not just an encapsulation lecture from a software engineering textbook. They are what let unrelated systems share a durable creature model without agreeing on raw storage details. When you see many modules include pokemon.h, you should not think, “Everyone owns Pokemon internals.” You should think, “pokemon.h is the public contract.”

And because this is an advanced course, let me state the tradeoff honestly. Accessor-heavy designs can become opaque if every getter hides expensive computation, side effects, or inconsistent naming. So the solution is not merely “use getters.” The solution is to design a small, explicit data vocabulary. FireRed’s MON_DATA constants in pokefirered/include/pokemon.h, chunk_2cc1cd9d6bfc7136, are part of that vocabulary. In your lab, do the same. Do not create fifteen slightly different ways to ask for HP. Have one current HP concept, one max HP concept, one species ID concept, and one recalculation path. Then the battle engine, summary screen, storage system, and tests all speak the same language.

Let us close this segment by returning to the three questions from the previous passage. When a system reads Pokemon data, first identify whether it wants species rule data, instance stored data, or derived data. When a system writes Pokemon data, identify what must be recalculated, invalidated, clamped, or synchronized. When representation changes between boxed, party, battle, and UI contexts, identify which representation is authoritative at that moment. These questions will carry us into the next packed-boundary example, where we will follow moves and PP through party storage, battle consumption, and display, and we will be especially careful about what gets written back after the battle turn completes.

Now, let us take the next step carefully, because moves and PP are a perfect stress test for whether you actually understand this architecture or whether you are just naming structs. A species can tell us what a creature is allowed to learn. A party Pokemon tells us what this individual currently knows. A battle Pokemon tells us what this combat participant can do right now, after temporary effects, disabling, choice locking, PP consumption, and all the other battle-time complications have been layered on top. Those are not the same question.

So, if I ask, “Can this Charmeleon learn Flamethrower?” that is a species-and-rules question. If I ask, “Does this Charmeleon currently have Flamethrower in move slot two?” that is an instance storage question. If I ask, “Can this Charmeleon choose Flamethrower this turn?” that is a battle-runtime question. And if I ask, “What should the summary screen display after battle ends?” that is a synchronization question. Same creature, same move name, four different architectural layers.

On the board, I am going to write four columns. First column: species learn rules. Second: stored moves. Third: battle move state. Fourth: UI display. Under species learn rules, put species info and learnset tables. Under stored moves, put the Pokemon or BoxPokemon data accessed through the GetMonData-style boundary. Under battle move state, put battler-side structures, turn state, and battle scripts. Under UI display, put summary screen and party menu consumers. Now look at those columns and notice something: the data does not become more “real” as we move to the right. It becomes more contextual.

This is why FireRed’s access pattern matters so much. In the week 9 source focus, pokefirered/include/pokemon.h chunk_2cc1cd9d6bfc7136 gives us the mon data constants and access pattern vocabulary. That is the contract that lets a consumer ask for MON_DATA_SPECIES, MON_DATA_HP, move fields, PP fields, status, experience, or stats without taking ownership of the raw creature layout. And pokefirered/src/pokemon.c chunk_af8613c6e25be253 is where that contract becomes behavior. The important architectural claim is not simply “there are getters and setters.” The claim is that the getter and setter layer becomes the negotiated border between packed persistent data and ordinary gameplay code.

Now, let’s make that concrete. Suppose a Pokemon has four move slots: Scratch, Growl, Ember, and Leer. In storage, those are not an abstract list object with dynamic entries and metadata attached. They are fixed fields in a compact creature record. The instance has move IDs and PP values associated with those move slots. The species table may say what moves the species learns by level. The move data table may say Ember’s base PP. But the instance stores the current fact that this individual has Ember and currently has, say, 17 PP remaining. The current PP is not rediscovered from the species every time. It is stored creature state.

Pause there and check your understanding. If the species data says Charmander can learn Ember, does that mean a specific Charmander in the player’s party currently has Ember? No. It means the rule set permits or grants that move under some acquisition path. The individual creature record must still store whether Ember is actually in one of its slots. If the move table says Ember has a base PP value, does that mean the current party Pokemon has full PP for Ember? No. Current PP is instance state. It can be depleted, restored, increased by PP Up-style effects, or altered through game logic. That difference is the whole reason this week exists.

Now, watch the packed-boundary issue. A boxed Pokemon is optimized around long-term storage. A party Pokemon extends or materializes additional runtime fields, especially battle-relevant and display-relevant values like current stats. So when you move a Pokemon from the PC into the party, or when you prepare a party Pokemon for battle, you must be aware of which fields are stored directly, which are unpacked or decrypted through an accessor, and which are derived. Moves and PP sit in an interesting middle position. They are stored state, but they are also interpreted through move metadata. The move ID by itself does not tell you the move’s category, power, type, flags, effect, or battle behavior. It tells you which rule record to consult.

This is a recurring pattern in the whole course. Back in the map and script weeks, an object event gave you an object-local identity and a script pointer, but that did not itself execute the scene. The runtime had to interpret it through the overworld, task, and script machinery. We are not reteaching object events now, but we are reusing the same mental model. A stored ID is a compact handle into a larger runtime interpretation system. Species IDs, move IDs, item IDs, map IDs, script pointers, and flag IDs all work this way. The stored thing is small. The meaning comes from the table and the interpreter that consume it.

Now bring in pokefirered/src/pokemon_summary_screen.c chunk_e8e17a42bbf17d46. The excerpt shows the summary screen pulling in pokemon.h, data.h, constants for moves and items, battle-related headers, party menu headers, and UI helpers. That include pattern is not random clutter. It tells you the summary screen is a consumer at the edge of several systems. It needs the creature record contract, the move constants, item data, party context, and UI machinery. But conceptually, it should not decide the raw memory layout of Pokemon. It should ask for the data it needs and render it.

Let’s say the summary screen displays move names and PP. It should not decide, “I know byte offset 23 is move slot one and byte offset 31 is PP slot one.” That would be a brittle cross-module dependency. Instead, it should use the Pokemon access layer and move data tables. The summary screen’s job is presentation. The creature module’s job is representation and access. The move data’s job is static rule metadata. The battle engine’s job is temporary combat interpretation and mutation. If those jobs bleed together, your game becomes very hard to debug.

Now, I want to compare this with Pokemon Showdown, but carefully. Showdown is not our main architecture source for this course. FireRed is. FireRed is a GBA game with packed C structs, global arrays, callbacks, task dispatch, script interpretation, and memory constraints. Showdown is a modern simulator, written around a very different runtime environment. But Showdown is extremely useful as a secondary comparison when we ask, “How does battle data hook into turn simulation, modded rule sets, and regression testing?”

In the research packet, pokemon-showdown/data and pokemon-showdown/sim are called out as recurring modules around Dex, moves, species, battle, and mods. That is exactly the comparison point. Showdown’s Dex layer is a rule lookup system. Its data and mods directories let the simulator ask, “Under this generation or mod, what is this species, move, ability, or learnset?” That is analogous in spirit, though not implementation, to FireRed’s species and move tables. FireRed’s table is compiled into the ROM-oriented C data model. Showdown’s Dex and mods are designed for flexible simulator rule selection.

So if I draw a second board line under the FireRed columns, I can write Showdown underneath like this: Dex data under species and move rules; Pokemon object state under stored or active instance state; Battle object and turn actions under battle runtime; tests under regression validation. Again, do not collapse these into one thing. The Showdown comparison helps because it makes explicit something FireRed often hides through C constants and compiled tables: rule data can be selected, overridden, and tested as a coherent rule environment.

The packet gives us pokemon-showdown/data/mods/gen2stadium2/scripts.ts chunk_3480e574205d5d0f as a concrete battle-data hook example. The excerpt describes damage calculation paths checking immunities, OHKO moves, damage callbacks, fixed damage, level-based damage, and base power behavior. That is a simulator-side example of a move record not merely being a label. A move can carry hooks that affect battle resolution. In FireRed, the implementation style differs, but the architectural lesson transfers: move identity points battle logic toward effect handling. A move slot in a Pokemon record is not “the move” in full. It is a reference to a battle rule.

Here is the check for understanding. If a battle engine sees move ID EMBER in slot three, does it have enough information to resolve the turn? No. It has enough to begin lookup. It still needs move metadata, the attacker state, the defender state, type effectiveness, accuracy, status, battle flags, possible abilities depending on the generation and engine, and turn-order context. The stored move ID is one input into a turn simulation, not the turn simulation itself.

Now, what gets written back? This is the question that separates careful engine design from a pile of working code. During a battle, the player chooses Ember. The battle runtime decrements PP. Maybe the move fails. Maybe the target is immune. Maybe an effect prevents execution. Maybe a move consumes PP even though it misses. The exact rule is battle-engine territory. But once the battle has advanced and committed the action, the party Pokemon’s stored PP must reflect the consumed PP. If the Pokemon is a temporary enemy generated for this battle, maybe it does not persist after battle. If it is the player’s party Pokemon, it usually must persist. If it is a link battle or special facility battle, there may be additional rules about what is restored or not written back. The architecture question is always: where is the authoritative state, and when does a temporary battle copy synchronize with it?

We saw a similar idea last time with current HP. HP exists as persistent party state, but battle logic also needs fast battler-side values. At the end of a turn or battle, you need a deliberate synchronization path. PP behaves similarly, except that each move slot has its own current PP and its own relationship to a move ID. That coupling matters. If move slot two changes from Growl to Metal Claw, the PP for slot two must now be interpreted relative to Metal Claw’s PP rules, not Growl’s. If you forget that moves and PP are parallel arrays or parallel fields, you can create one of the classic creature-RPG bugs: a move ID changes but the PP slot remains semantically stale.

This is why your lab asks you to implement a minimal creature record with species ID, personality, level, experience, moves, PP, stats, and accessor functions that hide the raw storage layout. I do not want you to build a fancy battle engine in that lab. I want you to experience the boundary. If your UI code reaches into raw storage, you have missed the point. If your level-up code writes a new move but forgets to initialize its PP through the move data table, you have found the point the hard way. If your stat recalculation changes max HP but does not preserve or clamp current HP deliberately, you have found the same architectural boundary from another angle.

Now, let’s connect the move relearner. pokefirered/src/learn_move.c chunk_af3598df6f092723 is useful here because the excerpt announces a “Move relearner state machine” and shows the file pulling in script, task, data, event data, Pokemon summary screen, graphics, strings, and move constants. Again, look at the shape. The move relearner is not just a menu. It is a field interaction, a UI flow, a script-connected service, and a creature mutation path. When a player relearns a move, the game must consult what moves are eligible, present choices, accept a UI decision, possibly replace an existing move, and then update the creature’s stored move and PP data coherently.

And now compare that to Showdown’s learnset data. The packet highlights pokemon-showdown/data/learnsets.ts and modded learnset files such as pokemon-showdown/data/mods/gen9dlc1/learnsets.ts, pokemon-showdown/data/mods/gen9predlc/learnsets.ts, and pokemon-showdown/data/mods/gen8dlc1/learnsets.ts as high-signal sources for learnset modeling. Even without making Showdown our primary source, we can use it as a design contrast. Showdown has to answer simulator questions like “Is this set legal under this ruleset?” FireRed has to answer runtime cartridge questions like “What move should this party Pokemon learn now, and how do I store that choice?” Those overlap, but they are not the same product requirement.

So when you design your own creature RPG, decide which problem you are solving. If you are building an adventure game like FireRed, the move system must support persistent creature records, level-up flows, NPC services, battle consumption, summary display, save/load, and maybe trading. If you are building a simulator like Showdown, the move system must support rule validation, battle determinism, modded generations, and high-volume regression tests. If you are building both, you need a clean boundary between adventure persistence and battle simulation, or the two will constantly corrupt each other.

Let me give you a concrete bug scenario. Suppose your game stores moves and PP in a Creature struct. During battle, you copy the whole Creature into an ActiveBattler struct. The ActiveBattler uses its own moves and PP arrays. The player uses move slot one three times. The ActiveBattler PP goes from 20 to 17. The battle ends. You forget to write that PP back to the party creature. What happens? The summary screen shows 20 PP. The save file stores 20 PP. The player has effectively gained free PP. That is not a display bug. That is an authority bug.

Second scenario. You do write the PP back, but you write it back by move ID rather than by slot. During battle, a temporary effect changes or masks the visible move. Or your engine supports transformation, mimic-like behavior, or copied moves. At battle end, you write the temporary move’s PP into the original slot incorrectly. Now the creature’s stored moves are contaminated by battle-only state. That is also an authority bug, but in the opposite direction. You allowed temporary context to overwrite persistent identity.

Third scenario. The move relearner replaces move slot four. You correctly write the new move ID, but you do not reset the PP slot based on the new move’s max PP. The summary screen displays the new move with old PP. Battle selection now sees a move that might have zero PP or too much PP. This is a synchronization bug between static move metadata and instance state.

If you can classify those bugs, you are beginning to think like an engine architect. First bug: battle mutation not persisted. Second bug: temporary battle state persisted too aggressively. Third bug: instance mutation not reconciled with rule metadata. These three categories come up again and again in creature RPGs.

Now, because this is an advanced course, let’s raise the sophistication one more level. The Pokemon record also contains personality and other values that influence derived behavior. In FireRed, the personality is not just decorative. It can feed gender, nature, ability slot, Unown form, Spinda spots, and other derived properties depending on the system. The general rule remains: do not duplicate derived values unless you have a reason, and when you do cache them, know the invalidation path. pokefirered/include/pokemon.h chunk_8e98575ccadc6d51 gives us the Pokemon struct contract, while pokefirered/include/pokemon.h chunk_55fc8220f5b93cdc gives broader Pokemon data declarations. Those headers are cross-module contracts. They tell the rest of the game how to talk about Pokemon without every consumer becoming a storage expert.

This is also where daycare, breeding, and summary features become relevant without becoming today’s topic. pokefirered/src/daycare.c chunk_119931105f546346 includes pokemon storage, event data, party menu, trade, Pokedex, scripts, naming, and other systems. That file sits at a crossroads because daycare logic manipulates creature identity, stored state, progression, and world services. We are not doing daycare architecture today, but it is a preview of what happens when creature records become world objects. The more systems touch Pokemon, the more valuable the accessor boundary becomes.

Let me ask a quick room question. Imagine the daycare wants to inspect a Pokemon’s species and moves. Should it parse raw boxed data directly because daycare is “close” to storage? No. It should use the same public creature data contract unless there is a very specific low-level reason not to. The fact that a system is old, internal, or performance-sensitive does not automatically justify bypassing the contract. In a C codebase, yes, there will be places that know more than idealized architecture would permit. But as designers reading the architecture, we should still recognize the boundary and understand why it exists.

Now, connect this back to the overall course plan. Weeks 1 and 2 gave us the runtime shell: startup, callbacks, tasks, and the idea that visible behavior comes from data being interpreted by state machines. Weeks 3 through 5 pushed that into maps, object events, scripts, flags, and variables. Weeks 6 through 8 made you trace whole systems from data records through globals, callbacks, tasks, scripts, structs, and source functions. Week 9 begins the creature and party data model. That is not a separate island. It is the same architecture pattern with a different kind of state.

The creature record is the player-facing version of world memory. Flags and variables remember story progress. Party Pokemon remember biological, mechanical, and battle progress. Object events describe interactable things in a map. Species tables describe what a creature type means. Script commands mutate world state. Pokemon accessors mutate creature state. Battle turns temporarily reinterpret creature state under combat rules. Save logic eventually persists the important parts. Same course thesis, new layer.

And looking forward, weeks 10 and 11 will lean on this heavily. When we discuss battle architecture, I do not want to spend half the time asking, “Where does a battler’s species come from?” or “Why does current HP differ from max HP?” We are establishing that now. When we discuss inventory and items, healing items will not make sense unless you understand instance HP and PP. Evolution stones will not make sense unless you understand species transitions and recalculation. TMs and HMs will not make sense unless you understand moves as stored instance slots backed by rule data. When we discuss saving, the question will be what portion of creature state is durable, what can be reconstructed, and what must never be trusted after corruption or version mismatch.

Let us also place regression testing into this picture. FireRed itself, as a decompiled GBA codebase, is not organized around the kind of test harness that Showdown has. But Showdown is instructive because simulator correctness depends heavily on reproducible battle turns and regression cases. The research packet points us toward pokemon-showdown/test as a recurring module around assert, Pokemon, moves, battle, species, and Showdown, and toward pokemon-showdown/sim for the battle and Dex layer. That is the right mental comparison: when battle behavior is highly data-driven, tests should lock down interactions between rule data and turn execution.

So, for your own engine, a good regression test is not merely “creature has four moves.” A good regression test says: create a species rule record, create an instance with specific moves and PP, run a battle action that consumes PP, end the turn, synchronize back to the party record, and assert that the displayed and stored PP match. Another good test says: replace a move through a learning flow and assert that the move ID and PP slot are both updated. Another says: load a boxed creature into a party slot and assert derived stats are recalculated while stored identity remains stable. These tests are architecture tests, not just gameplay tests.

Now I want you to notice how this changes the way we read source. If you open a file like pokemon_summary_screen.c and see many includes, you should ask, “Which data does this file own, and which data does it merely consume?” If you open learn_move.c and see a state machine, ask, “Where is the final write to the Pokemon record, and what accompanying fields must change?” If you open battle AI code, such as pokefirered/src/battle_ai_script_commands.c chunk_34a415cc38858fdc, and see it using GetMonData to inspect species, HP, and status in party slots, notice the architecture: AI decision logic is consuming party Pokemon through the access boundary. It is not treating the party array as arbitrary bytes.

That battle AI excerpt is especially useful because it shows the AI looking across a party, reading species, HP, and status through GetMonData-style calls. The AI is not asking a philosophical question about what a Pokemon is. It is asking operational questions: is there a party member, what species is it, does it have HP, what status does it have? That is runtime gameplay logic using the creature record contract. It is exactly the kind of source line you should learn to recognize as architecture evidence.

Let’s do one final board pass for this segment. I will write: stored identity, stored resources, derived stats, battle temporaries, display consumers, rule tables. Species ID belongs to stored identity. Personality belongs to stored identity. Experience and level are progression state, with level often stored but also related to experience rules. Moves and current PP are stored resources. Max PP is derived from move metadata plus PP modifiers. Attack, Defense, Speed, and so on are derived stats, stored in party representation for runtime convenience. Battle modifiers, volatile status, turn locks, and temporary copied moves are battle temporaries. Summary screen, party menu, battle UI, and AI are consumers. Species info, move data, learnsets, and type charts are rule tables.

Now, if you are building the lab creature record, that board list is almost your design checklist. You do not need FireRed’s full encryption or substruct machinery in the lab. But you do need the discipline FireRed teaches: hide raw layout behind accessors, distinguish static species data from instance data, and make recalculation explicit. Your accessor layer should make the easy thing the correct thing. If code wants a species ID, it asks for species ID. If code wants current HP, it asks for current HP. If code changes level, the code path should either recalculate stats or make the caller explicitly invoke recalculation. Silent half-updates are the enemy.

And one more check for understanding before we transition. A Pokemon’s move slot contains Tackle, and Tackle’s base PP is changed in the rule table for a balance mod. What should happen to an already stored Pokemon’s current PP? There is no universal answer. In a FireRed-style fixed game, rule tables are not normally hot-swapped under a save file in the way a modern modded simulator might be. In a Showdown-style mod environment, the active ruleset determines interpretation. In your own engine, you must define the policy. You might clamp current PP to the new max. You might store PP Ups separately and recalculate max PP. You might migrate saves. The wrong answer is to have no policy and let each screen decide differently.

That is one of the best reasons to use Showdown as a comparison without letting it replace FireRed. Showdown makes rule selection and mods explicit. FireRed makes packed persistence and handheld runtime constraints explicit. Together, they reveal the architectural pressure from both sides: rules need to be data-driven enough to be interpretable, and creature instances need to be stable enough to survive gameplay, UI, battle, storage, trade, and save boundaries.

So the synthesis for this part is: moves and PP are not a small detail inside the Pokemon struct. They are a miniature version of the whole course. A move slot is a stored handle into rule data. PP is mutable per-instance resource state. Battle consumes and temporarily transforms that state. UI renders it. Learning flows replace it. Tests should protect it. And accessors are the membrane that keeps all of those systems from depending on the same fragile byte layout. Keep that model in your head as we move next into the more uncomfortable cases: evolution, level changes, and species transitions, where the creature remains “the same individual” for the player, but several of the tables feeding its runtime behavior change underneath it.

## Source References
- pokefirered/src/daycare.c
- pokemon-showdown/data/mods/gen2stadium2/scripts.ts
- pokefirered/src/pokemon_summary_screen.c
- pokefirered/src/learn_move.c
- pokefirered/src/battle_ai_script_commands.c
- pokemon-showdown/data/abilities.ts
