# Creature Records in FireRed

Lecture ID: lecture_w09_d01
Week 9, Day 1

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

## Transcript
All right, let’s pick up exactly where last week left us. We have spent a lot of time looking at the overworld as a data-backed machine: map headers point to layouts, object events become actors, local IDs connect visible NPCs to script labels, and the script interpreter advances by reading commands, checking flags and variables, branching, blocking, and eventually giving control back to the overworld loop. I am not going to re-teach that whole path today. I want you to carry it forward as a foundation. The key idea was that FireRed does not treat the game world as one giant hand-authored procedure. It treats the world as records plus interpreters plus runtime state.

Today we move that same idea into the creature model. And this is a major shift in the course. Week 9 begins the creature and party data model block, and for the next few weeks we are going to look at what a Pokemon actually is from the engine’s point of view. Not as a character. Not as a sprite. Not as a name in the UI. But as a persistent record that can be stored in the party, stored in a PC box, passed into battle, modified by items, summarized on a screen, serialized into save memory, and protected from casual layout coupling.

So, if I write on the board, “What is a Pokemon?”, the answer for our purposes is not “a species plus level.” That is the beginner’s answer. The advanced answer is: a Pokemon is a layered runtime record with stable identity fields, packed mutable subrecords, derived battle-facing stats, and accessor functions that control the boundary between raw storage and game logic. That sentence is dense, so we are going to unpack it carefully.

Let me put three boxes on the board. The first box says species data. The second says individual creature record. The third says runtime use. Species data is the shared table: Bulbasaur has certain base stats, types, growth rate, learnset relationships, and so on. Individual creature record is your particular Bulbasaur: personality, original trainer, nickname, experience, current moves, PP, EVs, IVs, status, current HP, level. Runtime use is what the game is doing right now: showing the summary screen, calculating damage, healing with a Potion, awarding experience, writing to save, or entering battle.

The architecture mistake many clone projects make is to collapse those three boxes into one object too early. They create a Creature class with base attack, current attack, species name, move list, sprite path, map position, battle flags, evolution data, save methods, UI display strings, and maybe even script callbacks all crammed into it. It feels productive for a few days. Then the engine grows, and every system reaches into every field directly. At that point, the record is no longer an architecture; it is a shared pile of assumptions.

FireRed is more disciplined than that. The source focus for today is centered on pokemon.h and pokemon.c. The Pokemon data declarations in pokefirered/include/pokemon.h, chunk_55fc8220f5b93cdc, give us the public vocabulary around creature data. The struct contract in pokefirered/include/pokemon.h, chunk_8e98575ccadc6d51, is especially important because it separates the stored BoxPokemon portion from the party-facing Pokemon portion. And the mon data constants and access patterns in pokefirered/include/pokemon.h, chunk_2cc1cd9d6bfc7136, show the API surface that other systems are expected to use instead of freely poking through the raw layout. The implementation side lives in pokefirered/src/pokemon.c, chunk_af8613c6e25be253. Then the species data table, the shared table that feeds individual creatures, is in pokefirered/src/data/pokemon/species_info.h, chunk_99a58307a160a13c.

Now pause there. Notice the split. Headers define the contract. The implementation enforces the mechanics. Data tables provide species facts. That division should sound familiar from weeks 1 through 8. We saw it with callbacks and tasks. We saw it with map headers and object events. We saw it with scripts. FireRed keeps repeating this pattern: data table, runtime structure, interpreter or accessor layer, visible behavior.

Let’s make this concrete. Suppose the player opens the Pokemon summary screen. The summary screen is not supposed to know how the encrypted or packed data inside a boxed creature is arranged. It wants to ask questions. What species is this? What level? What moves? What is the current HP? What is the attack stat? The include list in pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, shows that summary logic pulls in pokemon.h along with menu, battle, item, move, and party menu dependencies. That is exactly the kind of consumer we care about. The summary screen is a runtime feature that needs creature facts, but it should not become the owner of creature storage rules.

So FireRed-style architecture gives it accessors. In our clone vocabulary, that means functions like GetCreatureData and SetCreatureData, modeled after the GetMonData-style pattern from pokefirered/include/pokemon.h, chunk_2cc1cd9d6bfc7136. Instead of writing summaryScreen.currentMon.box.secure.moves[0], the UI asks for MON_DATA_MOVE1 or whatever equivalent key the engine defines. That may seem bureaucratic. It is not. It is a protection boundary.

Here is the check for understanding. If I change the internal storage layout of moves from four separate fields to an array, should the summary screen change? No. If I change the way boxed creatures are packed or encrypted, should the item system change? No. If I add a fifth move slot for a custom fangame, should every menu and battle function immediately know the raw memory layout? Still no. The accessor boundary is what lets storage evolve while the rest of the engine continues to ask stable questions.

Let’s look more closely at the two-record idea: BoxPokemon and Pokemon. A BoxPokemon is the persistent core. It is the part that can live in storage. It has identity and long-term creature state. A Pokemon, in the party sense, wraps that boxed core with additional runtime fields that matter when the creature is immediately usable: current HP, calculated stats, level, status, and similar party-facing state. That relationship is the architectural claim supported by pokefirered/include/pokemon.h, chunk_8e98575ccadc6d51. The exact field names matter less than the separation itself. Box storage should not need every transient field required by active party participation.

Now, you might ask, “But current HP is persistent too, right? If I save with an injured Pokemon, it stays injured.” Yes, good. Persistent does not mean boxed. The distinction is not simply saved versus unsaved. The distinction is compact creature identity and stored substructure versus the expanded party record used by active game systems. In a minimal clone, you may decide to serialize the whole party record, including current HP and status. That is fine. But you still want to separate the idea of species facts, individual identity, and derived battle stats.

Let me draw an example on the board. We create a level 5 Charmander. What do we need at minimum? Species ID: Charmander. Personality: some random 32-bit value, or in a simpler clone, a stable random seed. Level: 5. Experience: the amount appropriate for level 5 under that species growth curve. Moves: maybe Scratch and Growl. PP for each move. IVs or simplified stat variation, if we are including them. EVs, probably zero at creation. Current HP and calculated stats. Original trainer identity if trading or ownership matters. Nickname if the UI supports it. Maybe met location later.

Now, which of these are species data? Charmander’s base stats, type, growth curve, possible abilities, and learnable moves come from species tables. The packet points us directly to pokefirered/src/data/pokemon/species_info.h, chunk_99a58307a160a13c, for the species info table. Which of these are individual stored data? Personality, experience, moves, PP, EVs, IVs, nickname, ownership. Which are derived? Attack, defense, speed, special attack, special defense, max HP. Those are computed from species base stats plus level plus individual modifiers.

This is the moment where advanced learners should resist the temptation to store everything as authorial truth. If you store both base stats and calculated stats inside every creature, you now have consistency problems. What happens when the creature levels up? What happens when an EV changes? What happens if a balancing patch changes species base stats? FireRed’s structure makes a distinction between values that define the creature and values that can be recalculated from the creature plus species table. In a clone, that distinction is one of the most important design choices you can make.

Let’s connect this back to the broader objective for the week: designing minimal clone versions of map loading, script execution, party data, battle turns, item use, and save persistence. By week 9, you should no longer think of those as independent assignments. Map loading gives you a location and object-event context. Script execution gives you controlled changes to world state. Party data gives scripts and battles something persistent to operate on. Battle turns read creature data, mutate HP and status, and eventually award experience. Item use reads bag data, checks party data, applies a rules function, and writes back to the creature record. Save persistence snapshots the world and party records into durable storage.

So when I say “creature records,” I do not mean an isolated struct. I mean the record that sits at the crossroads of nearly every major system.

Let’s walk one path. The player talks to a scripted NPC who gives them a starter. We already understand the object-event and script-entry side from the previous lectures, so we will treat that as prior foundation. The script command eventually calls into a special or utility function that creates a Pokemon and places it in the player’s party. At that moment, the script system should not manually fill out every field. It should request creation: species, level, maybe fixed personality or default moves. The Pokemon module should produce a valid creature record. That means the record has a species, experience consistent with level, valid moves and PP, calculated stats, and current HP initialized sensibly.

Then the player opens the party menu. The party menu reads the party slots. The summary screen reads accessor values. Later, battle setup begins. The source packet points to pokefirered/src/battle_setup.c, chunk_494d132a59422c85, which includes pokemon.h, load_save.h, script.h, event_data.h, battle.h, and battle transition code. That include mix tells a story: battle entry is a bridge from overworld and event state into battle state, and party creatures are part of that bridge. The battle engine does not invent the player’s Pokemon. It consumes the party records produced and maintained elsewhere.

Now suppose Charmander takes damage. During battle, HP changes. After battle, that modified HP must be reflected in the party. If the creature levels up, experience changes, level may change, stats are recalculated, and move-learning may trigger. The packet gives us pokefirered/src/learn_move.c, chunk_af3598df6f092723, as a related example of a move relearner state machine, with menu and task machinery around move selection. Again, the important point is not to re-teach that state machine. The point is that move changes are mediated by systems that ask and set creature data. A menu state machine may guide the player’s choice, but the creature record remains the durable target of the change.

Here is another check for understanding. Imagine a Potion. What information does it need? It needs to know whether the target is a valid party creature, whether current HP is below max HP, how much HP to restore, and how to write the new HP back. What should it not need? It should not need to know the byte offset where HP lives in the party struct. It should not need to know how the boxed substructure is encrypted. It should not need to know how species base HP is stored. The item effect is a rules operation over a public creature-data interface.

This is why the GetMonData-style API is not just C-era inconvenience. In a modern engine, you might implement this as methods, properties, typed accessors, ECS components, or serialization schemas. The form can change. The architectural purpose stays the same: most systems should not own raw creature layout.

Now let’s talk about the packed or encrypted boundary, because this is where FireRed becomes especially instructive. The stored creature data is not just a plain friendly object meant for every module to wander through. FireRed uses secure substructures and checksum-oriented protection in the Pokemon storage design. We are not going to spend today doing bit-by-bit reverse engineering of every field, but you should understand the design pressure. A handheld RPG has limited memory, a need for stable save layout, a need to store many creatures, and a desire to make corruption or casual tampering detectable. The source focus in pokefirered/src/pokemon.c, chunk_af8613c6e25be253, belongs here because implementation functions are where encryption, decryption, checksum, data retrieval, and mutation behavior are centralized.

In a clone, you probably do not need to encrypt your creature records. But you absolutely do need to decide where the storage boundary is. If you use JSON, do not let the entire codebase depend on the JSON shape. If you use a database row, do not let battle code depend on column names. If you use a binary save file, do not let UI code parse bytes. The FireRed lesson generalizes: raw persistence format is not the same thing as runtime access contract.

Let me give you a minimal design that I would accept for the lab this week. We define a CreatureRecord with speciesId, personality, level, experience, moves, pp, evs, ivs, currentHp, status, and maybe nickname. We define a SpeciesInfo table keyed by speciesId, containing base stats, types, growth rate, and default learnable move data. We define getCreatureData(record, field) and setCreatureData(record, field, value), or in a typed language, narrow methods like getSpecies, getLevel, getMove(slot), setCurrentHp, addExperience, recalculateStats. We define a Party as a fixed-size array or list of creature slots, probably six active slots if we are following Pokemon conventions. And we define a creation function that is the only normal way to construct a valid new creature from species and level.

Now, why fixed-size party slots? Because party position is gameplay state. Slot one matters for battle lead. Slot order matters for menus. Empty slots matter for whether a gift Pokemon can be received. The party is not just “all creatures owned by the player.” It is an ordered active subset. That distinction becomes important when we later compare party data to PC storage. FireRed’s Pokemon and BoxPokemon split is a strong clue here: active party creatures and stored box creatures share a core, but active participation adds more.

Let’s tie this back to the course plan. Weeks 1 and 2 gave us the runtime shell and the source organization. Weeks 3 through 8 took us through maps, object events, scripts, flags, variables, and world memory. We learned to trace visible gameplay from data records through globals, callbacks, tasks, scripts, structs, and concrete functions. The recent homework and quizzes already checked that you can identify the files, structs, functions, constants, data tables, and state variables for major systems. So the bar now goes up. I am no longer asking only, “Can you find the struct?” I am asking, “Can you explain why this struct boundary exists, which systems should be allowed to touch it, and what a minimal clone version should preserve?”

That is the advanced move. You do not copy FireRed field-for-field unless you are building a decomp modification. For a clone architecture, you copy the pressure-tested boundaries. Species table separate from individual record. Stored core separate from active party wrapper. Accessor API separate from raw layout. Derived stats recalculated from stable inputs. Scripts and items request mutations through controlled functions. Save persistence writes records without teaching every system the save format.

Before we continue into the exact accessor pattern, I want to make sure this is landing. If I ask you, “Where does Bulbasaur’s base attack live?”, the answer is species info, supported by pokefirered/src/data/pokemon/species_info.h, chunk_99a58307a160a13c. If I ask, “Where does this particular Bulbasaur’s current experience live?”, the answer is the individual Pokemon record, through the contract described in pokefirered/include/pokemon.h, chunk_8e98575ccadc6d51. If I ask, “How should the summary screen obtain that value?”, the answer is through Pokemon accessors or equivalent data APIs, supported by the mon data constants and access patterns in pokefirered/include/pokemon.h, chunk_2cc1cd9d6bfc7136. If I ask, “Where does the engine implement the details of reading and writing those fields?”, we look to pokefirered/src/pokemon.c, chunk_af8613c6e25be253.

Good. That gives us our footing.

Now I am going to shift from “what is stored” to “how systems talk to the stored thing.” Keep the three boxes on the board: species data, individual record, runtime use. In the next part, we are going to walk through accessor design as an API boundary, and then we will use that boundary to connect party slots, battle turns, item effects, and save persistence into one minimal creature RPG design.

So, accessor design. This is one of those topics that sounds small until you try to build the rest of the game without it. If every system directly reaches into the creature record and says, “I know where the species field is, I know how moves are packed, I know how PP is stored, I know how the stats are cached,” then the creature record stops being a record and becomes a public dumping ground. At that point, changing storage is nearly impossible. FireRed avoids that problem by making the Pokemon record a contract, not just a C struct sitting in memory.

Let me put this on the board. On the left, I am writing “raw storage.” In the middle, I am writing “GetMonData / SetMonData-style API.” On the right, I am writing “callers: summary, party menu, battle, scripts, items, save.” The rule is simple: most systems should not care how the record is internally arranged. They should ask for data by meaning. Give me species. Give me level. Give me current HP. Give me move one. Give me PP for move two. Give me held item. That is the mental model behind the mon data constants and access patterns in pokefirered/include/pokemon.h, chunk_2cc1cd9d6bfc7136, and the implementation details in pokefirered/src/pokemon.c, chunk_af8613c6e25be253.

Now, advanced point here: an accessor is not just a convenience function. It is an architecture boundary. It says, “This is the vocabulary by which the rest of the engine is allowed to talk about a creature.” If that vocabulary is sloppy, the rest of the engine becomes sloppy. If that vocabulary is precise, you can build map loading, script effects, party management, battle turns, item use, and save persistence around the same stable object.

Think about the summary screen. The source packet points us to pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, and even from the includes you can see the pattern: it pulls in pokemon.h, data.h, item constants, move constants, party menu support, and battle-related constants. That is not a random collection. The summary screen is a consumer of creature state. It needs to display what the Pokemon is, what it knows, what it holds, where it came from, and how battle-relevant numbers look. But it should not become the owner of Pokemon storage policy. It should be a reader and presenter.

Let’s make that concrete. Suppose our minimal clone has a creature record like this: species ID, personality, level, experience, four moves, four PP values, current HP, max HP, attack, defense, speed, special attack, special defense. Now the novice version of this engine says, “Fine, every caller can do creature.moves[0] or creature.stats.attack.” That will work for maybe two labs. Then you add save persistence, or boxed storage, or recalculated stats after Rare Candy, or personality-derived nature, or a compressed PC format, and suddenly every direct field access becomes a liability.

The stronger design says, “The record may have fields, but callers ask through accessors.” So the battle system asks GetCreatureData(mon, MON_DATA_SPEED), or the equivalent in our clone. The item system asks GetCreatureData(mon, MON_DATA_LEVEL), decides whether the item can apply, then calls SetCreatureData or a higher-level ApplyExperienceCandy function. The save system serializes the record, but it does so at the storage boundary, not by teaching every gameplay system about file layout.

Check for understanding here. If I ask you, “Why not just make all fields public if C lets us do it?” the answer is not “because public fields are always bad.” The answer is that this specific record is shared by too many systems with different needs. Battle wants fast runtime stats. Save wants stable persistence. Summary wants display values. Scripts want high-level checks. Items want controlled mutation. So if they all directly manipulate the same raw representation, they start breaking each other’s assumptions.

Now, connect that to species tables. The individual record does not contain everything. It should not contain everything. A Charmander individual does not need to store the entire Charmander species definition. It stores “I am species Charmander,” and the species table supplies base stats, type, growth rate, learnset-related data, ability possibilities, and similar defaults. In our packet, the species data table focus is pokefirered/src/data/pokemon/species_info.h, chunk_99a58307a160a13c. That table feeds runtime Pokemon, but it is not itself the individual Pokemon. This distinction matters deeply. Species data answers, “What is this kind of creature?” Individual data answers, “What is this particular instance?”

Let me draw a little arrow now. Species ID in the Pokemon record points to species info. The accessor for attack, for example, may return a cached individual stat. But the calculation that produced that stat probably used species base attack, level, IV-like values, EV-like values, nature-like modifiers if present in your design, and maybe badge or battle modifiers elsewhere. The key idea is that species tables are read-mostly design data, while Pokemon records are mutable player state.

Here is a concrete example from a minimal clone. A player receives a level 5 seed creature. The constructor does not copy the entire species row into the creature. It sets species ID to 1, level to 5, experience to the level 5 threshold, personality to a random 32-bit value, move slots to the starter moves, PP to the max PP for those moves, and stats to calculated values. If later we rebalance species 1’s base defense in the table, newly calculated stats will reflect that design data. But if that creature has gained experience, used PP, taken damage, learned a move, or received a nickname in a fuller design, those are individual facts and belong to the creature record.

This is also where we need to be precise about party slots. A party is not just six species IDs. A party is a small array of full individual records, usually with some count or validity rule. In FireRed terms, the Pokemon and BoxPokemon distinction in pokefirered/include/pokemon.h, chunk_8e98575ccadc6d51, gives us a strong architectural hint: the engine distinguishes the party-facing runtime Pokemon contract from a more storage-oriented boxed representation. For the lab, you do not need to implement all of FireRed’s packing or encryption boundaries, but you do need to preserve the idea that “party creature” is not the same thing as “species row.”

Let’s pause on that because it is a common design bug in student projects. Someone makes party equal to an array of species IDs: [1, 4, 7]. That is enough to display icons, but it cannot represent the game. Which one has low HP? Which one used Tackle three times and has reduced PP? Which one leveled up? Which one has a different personality? Which one was modified by an item? So a minimal party slot needs to hold the individual record, not just a pointer to a species. The species table is shared design data. The party slot is owned player state.

Now I want to connect this to the earlier weeks without re-teaching the event system. We already spent time on object-event records, NPC local IDs, script labels, trigger variables, and script pointer execution. Keep those as prior foundation. When an NPC gives the player a Pokemon, the script should not construct raw memory by hand. It should call a high-level function: give creature species X at level Y, maybe with default moves. Under the hood, that function creates a valid Pokemon record using the same constructor and accessors as everything else. That is how the script VM remains a coordinator, not the owner of Pokemon layout.

This is visible in the way FireRed modules cluster. The battle setup area, pokefirered/src/battle_setup.c, chunk_494d132a59422c85, includes pokemon.h, load_save.h, script.h, script_pokemon_util.h, event data, battle headers, transition headers, and overworld headers. That is an integration point. It is where world state, script state, and creature state start crossing into battle. But the presence of all those headers does not mean battle setup should violate the Pokemon record boundary. It means battle setup is a bridge. Bridges are allowed to connect systems; they should not erase the borders between them.

Let’s now walk through a minimal battle turn using the three-box model. On the board, I am writing: party slot to battler state to move execution to writeback. The party slot contains persistent creature data. The battler state is temporary battle runtime data. The move execution logic reads the selected move, current PP, stats, species-derived types, and battle modifiers. After the move is used, the engine decrements PP, applies damage to the opponent’s current HP, maybe awards experience, and then writes persistent consequences back to the party record.

The important phrase is “persistent consequences.” Not every battle value belongs in the Pokemon record. Accuracy stages, confusion counters, volatile locks, selected action for this turn, target selection, temporary stat stage changes, and turn order calculations are battle runtime state. Current HP and PP generally persist after the battle, so they belong in the individual record or are written back to it. Experience gain persists. Level changes persist. Learned moves persist. A temporary defense boost does not persist unless your game explicitly designs it that way.

This separation gives you a clean clone design. Your party array holds CreatureRecord objects. When battle starts, you create BattleCreature views or battler structs from the party records. Each battler view has a reference or index back to the party slot plus temporary battle fields. During turn execution, you read through accessors and write persistent changes through controlled functions. At the end of battle, you reconcile the persistent fields. In a very small clone, the party record and battler may be the same object for simplicity, but I want you to understand what coupling you are accepting when you do that.

Quick check. If a move lowers the opponent’s defense for the rest of battle, should SetCreatureData write a lower defense stat into the party record? No. That is a battle-stage modifier. If a Potion heals 20 HP outside battle, should SetCreatureData or an ApplyHealingItem function change current HP in the party record? Yes, because current HP persists as part of party state. If a Rare Candy increases level, should it only change the level field? No. It must also update experience rules as needed, recalculate stats, possibly adjust current HP according to the game’s policy, and maybe trigger move learning. That is why higher-level mutation functions often beat raw SetData calls for complex actions.

Now, item use. This is where accessors prove their value again. The item system should not know how a Pokemon stores current HP. It should know the item effect: heal current HP up to max HP, restore PP for one move, increase level, teach a move, hold an item, cure status in a fuller version. For each of those, it calls the creature API. Get current HP. Get max HP. Set current HP. Get move in slot N. Get PP in slot N. Set PP in slot N. Maybe validate against species compatibility for a TM-style item. The actual fields remain behind the boundary.

The source packet’s daycare module, pokefirered/src/daycare.c, chunk_119931105f546346, is useful evidence for how creature data becomes shared across systems. The excerpt shows it pulling in pokemon storage, event data, random, move constants, party menu, overworld, Pokedex, naming screen, trade, and more. Daycare is not battle, not summary, not ordinary item use, but it still depends on Pokemon records and species or move facts. That is exactly why the record boundary matters. The more systems can touch a creature, the more expensive raw storage leakage becomes.

Let’s take the move relearner as another example. The packet gives us pokefirered/src/learn_move.c, chunk_af3598df6f092723, with an explicit comment describing a move relearner state machine and includes for script, task, data, overworld, summary screen, constants for moves, and UI helpers. We are not going to re-teach tasks today, but remember the earlier RunTasks model. A menu state machine can span frames and still be editing one party creature. The move relearner needs to inspect possible moves, display them, let the player select one, and then mutate the selected Pokemon’s move slots. That mutation should go through the same creature API boundary. Otherwise your UI state machine becomes a secret second implementation of Pokemon editing.

Now let’s tie save persistence into this, because save is where architecture debt becomes visible. Saving the game is not just dumping whatever objects happen to exist in RAM. At minimum, you need a stable saved schema: map position and map ID, event flags and variables, party count and party records, bag contents, maybe PC storage, trainer identity, play time, and other progression state. We have already discussed flags and variables as world memory, so today we focus on party records. A save file should preserve individual creature state, not recompute it entirely from species. Species table data can be part of the ROM or game data package. The individual record is player-owned state.

But there is a subtle issue. Should cached stats be saved? FireRed’s actual representation has its own contract and storage details, and the packet points us to pokefirered/include/pokemon.h, chunk_55fc8220f5b93cdc, for Pokemon data declarations and to pokefirered/src/pokemon.c, chunk_af8613c6e25be253, for implementation. In a minimal clone, you have a choice. You can save derived stats for fast loading, or you can save only the canonical inputs and recalculate derived stats on load. Advanced answer: define which fields are canonical. If level, experience, species, personality, and growth inputs are canonical, then max HP and attack can be derived. But current HP is not purely derived, because damage persists. PP is not purely derived, because move use persists. So do not casually throw everything into “recalculate on load.”

Let me give you a concrete save/load scenario. The player has a level 12 creature with max HP 35 and current HP 9. It knows four moves, with PP values 20, 0, 15, and 5. The player saves in a cave. When loading, the game must not regenerate it as a fresh level 12 creature with full PP and full HP. The species table can recover base stats. The record must recover current HP and current PP. If your minimal clone rebuilds the party from species and level alone, it has lost player state.

Here is the design I would accept in the lab. Define CreatureRecord with canonical persisted fields: speciesId, personality, level or experience, moves array, pp array, currentHp, maybe stat experience or IVs if you include them. Then define derived runtime fields: maxHp, attack, defense, speed, specialAttack, specialDefense. You may persist derived stats if you want, but your load function should either validate or recalculate them consistently. The cleanest student implementation is usually to persist canonical fields, then call RecalculateStats after load. If current HP was 9 before recalculation and max HP changes because of a data patch, clamp current HP to the new max. That gives you a deterministic, understandable policy.

Now, bring map loading back in. The week 9 objective asks you to design minimal clone versions of map loading, script execution, party data, battle turns, item use, and save persistence. These are not six unrelated features. Map loading creates the world context. Script execution reacts to player contact with events in that context. Scripts may give items, start battles, check flags, or modify the party. Battle reads party data and writes persistent consequences. Item use reads and writes party data. Save persistence stores the map, script-relevant world memory, inventory, and party records. The Pokemon accessor API is the creature-state spine running through those systems.

Notice how much prior course material becomes useful now. From week 1 and week 2, we had the runtime shell: callbacks, tasks, and the idea of data table to callback to visible behavior. From the overworld weeks, we had map headers, layout registry references, and object events. From the scripting weeks, we had script pointer execution, command handlers, flags, and variables. Now in week 9, we are saying: when those scripts and callbacks need to touch creatures, they do so through a stable record contract. The architecture is becoming cumulative.

Let me ask a check-for-understanding question, and I want you to answer it silently first. An NPC script gives the player a level 5 creature. Which systems are involved? You should have at least four. The map system got you into the map with that NPC. The object-event and script system started the script. The party system found an empty slot. The Pokemon constructor created an individual record using species data. The save system later persists that new party state. If the NPC gift triggers a nickname screen or summary screen, UI systems become consumers too. The species table alone did not give the player a creature. The script alone did not either. The behavior emerges from systems crossing at narrow APIs.

Now, one more layer of sophistication: packed or encrypted boundaries. FireRed has reasons to separate visible logical fields from raw stored layout, and the week context explicitly includes encrypted or packed creature data boundaries. You do not need to reproduce FireRed’s exact mechanisms in the workshop. But you should reproduce the architectural lesson. Raw storage may be optimized, packed, encrypted, checksummed, or split into substructures. Public gameplay logic should still ask meaningful questions. If later you change moves from four fixed fields to a small array, or you compress PP into bytes, or you move boxed creatures into a different representation, callers should mostly survive.

This is why “GetMonData-style APIs” are not an old C inconvenience. They are a way to stabilize meaning when representation is unstable. In modern languages, you might express the same idea with methods, properties, domain services, immutable value objects, serializers, or ECS components with query APIs. The point is not the exact C style. The point is that systems talk in domain terms rather than storage offsets.

Before we pause, let me recap the chain. Species info, supported by pokefirered/src/data/pokemon/species_info.h, chunk_99a58307a160a13c, defines kind-level facts. The Pokemon struct contract in pokefirered/include/pokemon.h, chunk_8e98575ccadc6d51, defines the individual record boundary. The mon data constants and access patterns in pokefirered/include/pokemon.h, chunk_2cc1cd9d6bfc7136, define a vocabulary for reading and writing that record. The implementation in pokefirered/src/pokemon.c, chunk_af8613c6e25be253, owns the storage details. Consumers like the summary screen in pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, the move relearner in pokefirered/src/learn_move.c, chunk_af3598df6f092723, daycare in pokefirered/src/daycare.c, chunk_119931105f546346, and battle setup in pokefirered/src/battle_setup.c, chunk_494d132a59422c85, demonstrate the broader pattern: many systems need Pokemon data, so Pokemon data needs a disciplined API.

For the next segment, keep your eyes on one question: when a system changes a creature, is it changing canonical creature state, derived creature state, or temporary runtime state? If you can answer that, your minimal clone will avoid most of the architectural mistakes that make creature RPGs hard to extend. We will use that question next to design the actual lab interface: the constructor, the accessor constants, the party slot operations, and the small set of mutation functions that are allowed to recalculate or validate the record.

So let’s do that. Imagine I am drawing a boundary line on the board. On the left side I am writing “raw creature record.” On the right side I am writing “game systems.” Between them I am drawing one narrow doorway, and over that doorway I am writing “accessors and sanctioned mutations.” That is the architectural move FireRed is pushing us toward. Not because every call site is abstract in the modern object-oriented sense, but because the record is important enough, compact enough, and weird enough that the rest of the game should not casually poke at every byte.

Now, in your minimal clone, do not begin by asking, “What fields do I need in my class?” That question sounds reasonable, but it tends to produce an anemic bag of public fields. Begin instead by asking, “What promises does a creature record make to the rest of the engine?” A party menu wants to know a name, species, level, HP, status, held item, and move list. Battle wants stats, ability-like behavior if your clone has it, move PP, current HP, volatile battle-only modifiers, and fainted state. Item use wants to ask whether a potion may heal this creature, whether a revive may target it, whether a TM-like item can teach a move, and then it wants mutation functions that enforce the rules. Save persistence wants a stable representation that can be serialized and loaded without accidentally storing temporary battle modifiers. The map and script layers want to refer to a party slot or a species reward without knowing the storage shape. Those are all different clients. If they all directly own the record layout, the creature model stops being a model and becomes shared global mush.

And that is why the FireRed source focus for today matters. In pokefirered/include/pokemon.h, especially the chunks we are focusing on this week, the declarations and constants act like a public contract. The implementation side in pokefirered/src/pokemon.c, chunk_af8613c6e25be253, is where the details live. Then consumers such as pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, and pokefirered/src/battle_setup.c, chunk_494d132a59422c85, are allowed to be complicated in their own ways without becoming owners of the creature storage format. That separation is not decorative. It is what lets the same Pokemon record be shown in a menu, brought into battle, healed by an item, deposited in storage, and serialized into save data.

Let me put a small clone interface on the board verbally. I would have a constructor, maybe “CreateCreature,” that takes species ID, level, personality or seed, and maybe an origin marker if your clone tracks where the creature came from. It fills canonical fields: species, personality, experience, level if you store level directly, moves, PP, IV-like values if present, EV-like values if present, nature-like derived behavior if present, current HP, and status. Then I would have accessor constants, not stringly typed keys if I can avoid it. Something like data ID species, data ID level, data ID experience, data ID move one, data ID PP one, data ID current HP, data ID max HP, data ID attack, and so on. The point is not to copy FireRed’s exact enum names in your clone. The point is to copy the dependency direction: external systems ask for data through a narrow vocabulary.

Now here is the first subtlety. A getter is not always just a field read. If I ask for current HP, that probably is a stored field. If I ask for max HP, that may be derived from species base stats, level, and individual values. If I ask for display name, that may fall back to species name if no nickname exists. If I ask for whether the creature is fainted, that may be derived from current HP equals zero. So in your design, GetCreatureData is allowed to compute. That is not a violation. It is the whole reason you have the accessor. The caller should not need to know whether max HP is stored, cached, recalculated, packed, encrypted, or computed from a species table.

This is where the species table comes in. FireRed’s species information is a separate source of truth. The source packet names pokefirered/src/data/pokemon/species_info.h, chunk_99a58307a160a13c, as the species data table focus for this week. That table feeds runtime Pokemon, but it is not itself an individual Pokemon. Think carefully about that difference. “Bulbasaur has base stats and growth information” is species data. “This particular Bulbasaur has 17 current HP, this personality, these moves, and this much experience” is creature instance data. If a student stores base attack separately inside every creature record in the save file, I immediately ask: is that canonical instance state or a cached derivation? If it is just copied from the species table, you have created duplication that can drift. If it is a calculated final stat that depends on level and individual values, you may cache it, but then you need invalidation rules.

Let’s check that distinction with a concrete example. Suppose a script gives the player a level 5 Charmander. We are not going to re-teach script pointer execution today; you already handled script command handlers and flag variables in the recent script lectures. Use that as prior foundation. The script command says, effectively, “add this species at this level to the party.” The script layer should not fill every move slot, calculate stats, set PP, and patch current HP manually. It should call an operation near the creature model, something like GiveCreatureToParty or CreateCreature followed by AddToParty. That operation consults the species table, picks the starting moves, computes experience for level 5 if experience is canonical, initializes PP from the move definitions, calculates stats, and sets current HP to max HP. The script is an event policy layer. The Pokemon module is the creature construction layer.

Now I want you to notice a connection to map loading. Earlier in the course, we treated map headers, layouts, object events, and scripts as data feeding runtime behavior. A map load creates an overworld context. Object events and trigger variables select script entry points. But when that script gives or changes a creature, it crosses into a different subsystem. The map does not own Pokemon state. The script does not own Pokemon state. They request a mutation. In your minimal clone, the clean design is not “the map JSON contains the whole party.” The clean design is “map loading restores the map state; save loading restores party state; scripts coordinate between them through commands.” That is the same architecture shape we have been tracing all term: data table, runtime state, callback or task or script, visible behavior.

Let’s draw the minimal clone flow. The player steps on a trigger tile. The overworld dispatches a script, based on the trigger variable and map event data. The script command says, “give creature species 4 at level 5.” The script executor calls the party API. The party API asks CreateCreature to initialize the record. CreateCreature asks species info for base data and learnset policy. The party API finds an empty slot and writes the creature into that slot. The script sets a flag so the gift is not repeated. Save persistence later serializes flags, variables, party slots, bag, map position, and other durable state. Notice how each subsystem touches only its own durable state plus the public API of the neighboring subsystem.

Here is a check for understanding. If the move relearner changes a Pokemon’s moves, is that canonical creature state, derived creature state, or temporary runtime state? Take a moment. It is canonical creature state, because after the menu closes, after battle, after save and reload, the creature should still know that move. And because it is canonical, the mutation must also update related canonical fields, especially PP for that move slot. That is why a consumer like the move relearner, represented in the packet by pokefirered/src/learn_move.c, chunk_af3598df6f092723, is architecturally interesting. It is a UI and state machine client, but it must route durable move changes through disciplined Pokemon operations. It should not leave a move slot and PP slot inconsistent.

Now contrast that with a battle attack stage boost. If Growl lowers Attack during battle, is that canonical creature state? No. The creature’s saved Attack stat is not permanently reduced by Growl. That belongs to battle runtime state. It may refer to the Pokemon’s calculated stat, but it is not the same as rewriting the Pokemon record. This is exactly the trap that catches many clone projects. They represent a battler as the same object as the saved creature and then start storing battle-only fields directly on it. At first that works. Then a battle ends and some modifiers remain. Then switching creatures creates strange leaks. Then saving during a battle or after a scripted battle gets ambiguous. So for your lab, I want a separate battler view or battle participant record. It can hold a reference or index to the party slot, plus copied or computed battle fields: temporary stat stages, selected move, volatile status, turn order information, protect-like flags if your clone has them, and AI decisions. Persistent current HP and persistent major status may be written back. Temporary modifiers are discarded.

FireRed’s battle setup source helps justify this boundary. The packet points to pokefirered/src/battle_setup.c, chunk_494d132a59422c85, as a transition and setup module that includes pokemon, save loading, scripts, event data, battle constants, and battle transition concerns. That is a convergence point. Battle setup is not merely “call battle.” It is where overworld circumstances, scripts, trainer data, party data, and battle runtime preparation meet. In your clone, that means StartBattle should not be a random method on the map object that directly edits every Pokemon. It should collect battle inputs, create battle runtime state, and then let the battle loop operate on battlers.

Let’s make this concrete. Suppose your party slot zero contains a level 12 Squirtle with Tackle, Tail Whip, Water Gun, and one empty move slot. It has 31 current HP out of 34. The player enters a wild battle. The battle system builds player battler zero from party slot zero. It reads species, level, stats, moves, PP, current HP, and status through accessors. During turn one, the enemy uses a move that deals 8 damage. Is the damage temporary or persistent? Current HP damage is persistent across battle in Pokemon’s model, so at some sanctioned point the party record’s current HP must become 23. But if Tail Whip lowered the enemy Defense stage, that does not go back into the wild creature’s long-term record unless you capture it after the battle, and even then battle stages do not become saved stats. The capture result creates or adopts a creature record with canonical fields, not a record polluted by turn-local stage changes.

Let me pause here, because this is a place where advanced students sometimes overcorrect. You might say, “Fine, I will make everything immutable and return a new creature after every operation.” That can be excellent in a simulator or server design. Pokemon Showdown often gives us useful comparison points for deterministic battle modeling, and the packet includes pokemon-showdown/test and pokemon-showdown/data as recurring secondary modules. But FireRed is not primarily a server simulator. It is a GBA game with memory pressure, packed records, global arrays, callback state, and save constraints. So the architectural lesson is not “copy every C detail.” The lesson is “control mutation.” In C, that often means functions that mutate structs behind a known contract. In a modern clone, it might mean immutable records or controlled reducers. Either is fine if the boundary is explicit.

Now, item use. This is the simplest place to test whether your design is honest. A potion needs to ask, “Can I apply this item to this party slot?” If current HP is zero, some games allow healing items, some require revive first; your design policy decides. If current HP equals max HP, potion fails. If it succeeds, current HP increases up to max HP. The item module should not calculate max HP by duplicating the stat formula. It should call GetCreatureData for max HP or a CanUseItemOnCreature helper. Then it should call HealCreature or ApplyItemToCreature. Why? Because the item system’s expertise is item rules and inventory consumption. The creature system’s expertise is valid creature mutation. In pokefirered/src/daycare.c, chunk_119931105f546346, and pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, you can see the broader pattern of many non-battle systems including Pokemon interfaces because they need creature data in different user-facing contexts. That is the pressure that makes access discipline valuable.

Here is another check for understanding. If a Rare Candy raises level by one, what must be updated? Do not answer “level” and stop. In a robust creature RPG, the operation may update experience, level, calculated stats, current HP delta, move learning opportunities, evolution checks if your clone includes them, and display refresh. Some of those are canonical changes. Some are derived recalculations. Some are follow-up workflows. The item-use command should not scatter those across five systems. It should call a level-up operation that owns the sequence or returns a result object saying, “level changed, stats changed, new move available.” That result can then drive UI.

This is why I want your lab interface to include a small set of mutation functions, not only SetCreatureData. SetCreatureData is tempting because it seems general. FireRed has GetMonData-style access patterns, and the week’s focus includes mon data constants and access patterns from pokefirered/include/pokemon.h, chunk_2cc1cd9d6bfc7136. But the presence of a general accessor pattern does not mean every subsystem should blindly set arbitrary fields without invariants. For a clone, I would allow low-level setters only inside construction, loading, or tightly controlled internal routines. For gameplay, use verbs: HealCreature, DamageCreature, SetStatus, ClearStatus, TeachMove, RestorePP, GainExperience, RecalculateStats, ValidateCreatureRecord. Verbs carry invariants better than raw field writes.

Let’s connect this to save persistence, because persistence is where vague architecture gets punished. Your save file should contain durable world memory: player position, map identity, flags, variables, party records, PC storage if present, inventory, money, maybe quest log state. We already spent time on flags and variables as world memory, so carry that forward. The party is also world memory, but with a different internal contract. When saving, you should serialize the canonical creature record, not the summary screen’s current display strings, not the battle menu selection, not the animation state, and not temporary stat stages. When loading, you should be able to validate or recalculate derived values. If your save contains both level and experience, you need a policy for mismatch. If your save contains stats, you need a policy for recalculation. If your save contains moves and PP, you need a policy for illegal PP greater than max PP. FireRed’s packed and protected storage details are more specialized than our lab, but the architectural point is directly portable: define the boundary of durable creature data.

On the board, I would now write three labels: canonical, derived, temporary. Under canonical, I would put species ID, personality or seed, experience, moves, PP, current HP, status, held item, friendship if present, nickname if present. Under derived, I would put level if derived from experience, final stats, display name fallback, type if read from species, learnable moves if read from tables. Under temporary, I would put battle stat stages, selected command, flinch this turn, disabled move counter, escape attempt count, and UI cursor position. Your exact clone may move one or two items between canonical and derived depending on design. FireRed stores some things for practical reasons that a clean-room teaching clone may compute. But you must be able to justify every choice.

Let’s run one full scenario. The player loads a save. Save persistence restores map ID, coordinates, flags, variables, inventory, and a party array. Party slot zero is occupied. Slot one is empty. The map loader reads the map header and object events, which we are not re-teaching, and places the player in the overworld. The player talks to an NPC. The object event local ID and script pointer foundation from last week gets us to a script. The script checks a flag, sees that the reward has not been claimed, and calls a command to give a creature. The command asks the party module whether there is space. The party module constructs a creature from species table data and puts it into slot one. The script sets the flag. The player opens the summary screen. The summary screen asks for species, level, moves, stats, and current HP. It does not care whether stats are packed or computed. Then the player enters battle. Battle setup reads the party, creates battlers, runs turns, writes persistent HP and status back, discards temporary modifiers, and returns to the overworld callback. Then the player uses a potion. The item module asks the creature API whether healing is allowed, applies healing, consumes the item, and refreshes UI. Finally, save persistence writes the new flag, the new party slot, the changed HP, and the changed inventory count. That is a minimal creature RPG architecture.

Notice how many prior course systems are present in that paragraph. Map loading, script execution, party data, battle turns, item use, and save persistence all appear, but the Pokemon record is the hinge. In weeks one through eight, we built the mental model for callbacks, tasks, data tables, maps, events, scripts, flags, and variables. Week nine now gives us the thing those systems act upon most often: a durable creature whose identity survives across scenes. Weeks ten and eleven will become easier if you keep this boundary clean, because battle and inventory stop being mysterious piles of special cases and become clients of a stable record.

Before we move on, quick diagnostic question. A summary screen displays Attack as 22. Should the summary screen store 22 in its own model? No, not as authoritative state. It may cache the number for display during a frame or menu page, but the source should be the creature accessor, which may calculate from the record and species info. If the creature levels up while the menu is open, either the menu refreshes from the accessor or responds to a change event. It does not become a second creature database.

A second diagnostic question. A script wants to check whether the player has a particular species in the party. Should the script loop over raw party memory and inspect struct fields? In a minimal clone, please do not. Give it a party query: PartyContainsSpecies, FindPartySlotBySpecies, or CountPartySpecies. The script layer can branch on the result. That preserves the same discipline we used with flags and variables: scripts express progression logic; subsystem APIs answer domain questions.

Now, there is one more advanced point I want to add before we shift into implementation detail. Accessors are not just encapsulation for its own sake. They are also a compatibility layer between storage and meaning. FireRed’s Pokemon and BoxPokemon representation includes boundaries where data may be packed, encrypted, or organized for save and storage constraints. Our packet explicitly frames this week around Pokemon and BoxPokemon representation, party slots and stored state, and encrypted or packed creature data boundaries. Even if your clone uses plain objects, pretend that one day you will need to change the layout. Maybe you add abilities. Maybe you add forms. Maybe you add a second move resource besides PP. Maybe you add storage boxes. If your battle system, item system, summary screen, and scripts all know the raw layout, every change becomes a migration across the whole engine. If they speak through GetCreatureData-style constants and mutation verbs, the change is localized.

So the lab version I want is deliberately small but architecturally serious. You will implement a creature record with species ID, personality, level or experience, moves, PP, stats, and accessor functions that hide raw storage. You will create a species info table small enough to understand, maybe three species. You will create a party array with fixed slots. You will implement construction, getters, a few setters or mutation verbs, stat recalculation, move teaching, healing, damage, and serialization. Then you will connect it to a tiny script command or scripted event so that a map interaction can give a creature. Then you will connect a toy battle turn so that damage changes current HP. Then an item use path so a potion heals. Then save and load so the result persists.

And if that sounds like a lot, it is only because the creature record is central. The individual pieces are small. The challenge is keeping them in the right place. That is the advanced bar for week nine. Not “can you make a struct with fields?” You can all do that. The bar is “can you make a record that remains stable while six systems depend on it?” FireRed’s own organization, especially the divide between the pokemon header contract in pokefirered/include/pokemon.h, the implementation in pokefirered/src/pokemon.c, chunk_af8613c6e25be253, and the many consumers like summary, learn move, daycare, and battle setup, gives us the evidence for that design pressure.

So, as we go into the next part, keep that three-way classification active: canonical, derived, temporary. Every time we name a field or write an operation, I am going to ask which bucket it belongs to. And when we write the minimal clone interface, we will not judge it by whether it resembles FireRed cosmetically. We will judge it by whether map loading, script execution, party management, battle turns, item use, and save persistence can all use it without learning private storage details. That is the real test of the creature record.

So let’s make the interface concrete now. I’m going to put a small record on the board, but I want you to hear the design principle before you look at the fields. The creature record is not just a bag of values. It is a boundary. The rest of the game is allowed to ask questions of it and request changes to it, but the rest of the game should not be allowed to depend on how the record is packed, encrypted, cached, recalculated, or arranged in memory.

In FireRed, that boundary is visible in the pokemon header declarations and constants in pokefirered/include/pokemon.h, especially the struct contract in chunk_8e98575ccadc6d51 and the mon data constants and access patterns in chunk_2cc1cd9d6bfc7136. The implementation then lives behind that contract in pokefirered/src/pokemon.c, chunk_af8613c6e25be253. That separation is the architectural lesson. The lesson is not, “copy FireRed’s exact memory layout.” The lesson is, “make the storage layout boring to everyone except the creature module.”

Now, on the board, I’ll write a minimal clone creature record. Not C syntax yet, just the shape. Species ID. Personality. Level. Experience. Four move IDs. Four PP values. Current HP. Calculated max HP, attack, defense, special attack, special defense, speed. Status condition, held item, nickname if your clone needs one, and maybe original trainer data if trading or ownership matters in your scope. If we were building a two-hour lab implementation, I would start even smaller: species ID, personality, level, experience, moves, PP, current HP, and a stats block. That is enough to feed the systems we care about today.

But immediately, we need to classify. Species ID: canonical. Personality: canonical. Level: maybe derived from experience in a stricter implementation, but many minimal clones may store it canonically for simplicity. Experience: canonical. Moves: canonical. PP: canonical. Current HP: canonical runtime state that must persist. Max HP and battle stats: derived from species base stats, level, IV-like inputs if you implement them, EV-like inputs if you implement them, nature-like modifiers if you implement them, and temporary battle effects if you are in battle. So if you store max HP, you are storing a cache. That cache must have a recalculation rule.

Pause there. Check your understanding. If a Rare Candy increases a creature from level 15 to level 16, which fields are allowed to change directly, and which fields must be recalculated? You should be saying: experience or level changes directly depending on clone policy; max HP and other stats must be recalculated; current HP may receive a deliberate adjustment, commonly increasing by the same amount max HP increased, but that is a game rule, not a raw storage consequence. Moves may change only if the level-up move learning flow says so. PP usually does not magically refill unless the specific design says it does.

That distinction is what keeps item use from corrupting battle data. It also keeps the summary screen honest. Look at the consumer pressure in FireRed. The summary screen includes pokemon.h, item headers, move constants, party menu, battle constants, and many UI helpers in pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46. That file should be able to ask, “what is this creature’s species, level, moves, item, stats?” It should not be the place where the packed substructure of a Pokémon is decoded. Similarly, the move relearner state machine in pokefirered/src/learn_move.c, chunk_af3598df6f092723, is concerned with menus, selected moves, and state transitions. It can call into Pokémon data APIs, but it should not become an alternate Pokémon serializer. And daycare, in pokefirered/src/daycare.c, chunk_119931105f546346, pulls in pokemon storage, event data, battle, strings, menus, overworld, and trade-related headers because daycare sits at the crossing of many systems. That crossing is exactly where accessors matter most.

Now let’s connect that to our minimal clone. Suppose we write GetCreatureData and SetCreatureData, modeled conceptually after a GetMonData-style API. I am not saying every modern codebase should use integer field constants forever. In a typed language, you may use methods or properties. In a C-style FireRed-inspired clone, a field selector can be very practical. The important idea is that map scripts, party menus, battle code, item effects, and save loading all use the same sanctioned access path.

So, board cue: I’m drawing six boxes around the creature record. Map loading. Script execution. Party data. Battle turns. Item use. Save persistence. The creature record sits in the center.

Map loading first. In the weeks on object events and triggers, we learned that maps are not just pictures; they are data-backed runtime spaces. I am not going to re-teach object-event records or script labels here. Use those as prior foundation. For this week, the map loader’s job is to restore the world enough that a player can walk around and encounter things. It needs access to the party, because the party determines whether field effects are available, whether repel-like effects are active, maybe whether a following creature appears, and certainly whether wild battles can start with a valid lead creature. But map loading should not inspect raw creature bytes. It asks the party module, “do we have usable creatures?” The party module asks the creature accessors, “current HP greater than zero? species not empty? egg state if implemented?” That is a layered design.

Script execution second. We already studied script pointer execution, command handlers, flags, and variables. Today, scripts become clients of creature data. A script command might give the player a starter. Another might check whether a creature knows a move. Another might heal the party. Another might remove a creature or set a flag after a trade. In a minimal clone, script commands should call functions like AddCreatureToParty, HealParty, CreatureKnowsMove, or SetCreatureData. They should not allocate a creature record and fill the storage fields by hand in ten different script handlers. If they do, your clone will work for one week and then become fragile.

Here is a concrete example. Imagine a starter choice script. The player picks Bulbasaur. The script command should not say, “write species equals 1 at byte offset zero, write level equals 5 at byte offset two, write move one here, write PP there.” It should say, CreateCreatureFromSpecies(speciesBulbasaur, levelFive, generatedPersonality), then AddCreatureToParty. Inside CreateCreatureFromSpecies, the creature module consults the species table, assigns level, initializes experience, initializes legal starting moves, assigns PP based on moves, recalculates stats, sets current HP to max HP, and returns a valid record.

This is where species tables enter the story. The species info table in pokefirered/src/data/pokemon/species_info.h, chunk_99a58307a160a13c, represents data that feeds runtime Pokémon. Your minimal clone needs the same category of table, even if it has only three species. Base HP, base attack, typing if battle needs it, growth rate if experience needs it, learnset if move learning needs it. The creature record stores the individual. The species table stores what is common to every member of that species. Confusing those two is one of the fastest ways to create an unmaintainable creature RPG.

Now party data. The party is not the creature. The party is a container with rules. In FireRed terms, party slots and stored state are part of the week’s source focus, and the difference between Pokémon in active party form and boxed storage form is part of the broader contract described in pokefirered/include/pokemon.h, chunk_8e98575ccadc6d51. In a minimal clone, the party can be an array of six creature records plus a count. But even there, do not underestimate the container. The party decides which slots are occupied. The creature record decides what an occupied slot means. The party module should offer operations like GetLeadCreature, SwapPartySlots, AddCreatureToParty, RemoveCreatureFromParty, CountUsableCreatures. The battle system should not scan six raw slots and improvise its own definition of “usable” unless that definition is specifically battle-local.

Check for understanding again. If a fainted creature remains in slot one, is slot one empty? No. Empty means no creature. Fainted means a real creature whose current HP is zero or whose status says unable to battle, depending on your design. That distinction affects party display, script checks, save data, and battle transitions. So in your clone, do not represent fainted by deleting the creature. That is a category error.

Battle turns fourth. Battle is where temporary data becomes seductive. A combatant has stat stages, volatile status, selected move, turn order, pending damage, protection state, maybe substitute HP, maybe confusion count, maybe binding counters. Almost none of that belongs in the canonical creature record. The battle system can create a BattleMon or BattleParticipant structure from the party creature. At battle start, it reads species, level, stats, moves, PP, current HP, status, item, and maybe ability if implemented. During battle, it manipulates battle-local state. At the end, it writes back only the canonical changes: current HP, permanent status, PP spent if your design spends PP immediately from the party record or writes it back after battle, experience gained, level changes, learned moves, consumed held items.

FireRed’s broader source organization supports this separation. Battle setup sits near overworld, item, Pokémon, save loading, scripts, event data, and battle transition headers in pokefirered/src/battle_setup.c, chunk_494d132a59422c85. That is a transition zone. It prepares a battle from overworld conditions and party state. It should not mean the overworld and battle share every private detail. It means the transition code knows how to hand off stable state to the battle engine.

For comparison, and only as comparison, Pokémon Showdown’s battle scripts emphasize deterministic move resolution through active battle objects, such as the damage and move handling visible in pokemon-showdown/data/mods/gen2stadium2/scripts.ts, chunk_3480e574205d5d0f. Showdown is not our FireRed architecture authority, but it is useful to remind us that battle engines often prefer rich runtime objects rather than direct save records. That difference is healthy. Persistent creature records and battle participants have different jobs.

Item use fifth. Items are a stress test for accessors. A potion modifies current HP but should obey max HP. A revive modifies fainted state and HP. A vitamin might modify effort-like data and force stat recalculation. A Rare Candy modifies level and may trigger learn moves. A PP Up modifies a move’s PP capacity if you support that. A TM or HM modifies moves, but only after legality, compatibility, and replacement rules. If item code directly changes raw fields, each item becomes a tiny unauthorized creature editor.

So in the clone, I would write item effects against operations. HealCreature(creature, amount). ReviveCreature(creature, fractionOfMaxHp). TryTeachMove(creature, moveId). AddExperienceOrLevel(creature, amount). RecalculateCreatureStats(creature). Use accessors under those operations, and keep policy in one place. That is why the learn move code in pokefirered/src/learn_move.c, chunk_af3598df6f092723, is so instructive as a consumer. It is not merely changing a number. It is running a state machine around a player decision: choose move, maybe replace old move, update the record, return to a previous flow. The creature record boundary lets that UI state machine focus on the decision rather than the storage.

Save persistence sixth. Save is the place where your category choices become permanent. If you save derived stats, you must know when to trust them. If you save temporary battle state accidentally, you may resume into nonsense. If you save only species and level but forget current HP, then healing, fainting, and damage have no persistence. If you save moves but not PP, every reload becomes a free restore. So a minimal save format should write the canonical creature fields and enough cached fields only if you can validate or rebuild them.

Let me phrase that as an engineering rule: save canonical state, rebuild derived state, discard temporary state unless the game explicitly supports saving inside that temporary mode. For our clone, that means save species ID, personality, experience or level, moves, PP, current HP, status, held item if present, party order, and boxed storage if implemented. On load, run NormalizeCreatureRecord. That function checks species validity, clamps level, validates moves, clamps PP to legal maximums, recalculates stats from the species table, clamps current HP to max HP, and returns a safe creature. This is the same spirit as hiding encrypted or packed Pokémon data boundaries. The rest of the game gets a valid creature, not an invitation to reason about broken storage.

Now, a board-work moment. I’m drawing a line down the middle. Left side: raw storage. Right side: game behavior. Under raw storage, I write species, personality, exp, moves, PP, HP, status. Under game behavior, I write starter selection, party menu, battle damage, potion, save/load, summary screen. The accessors are the bridge. GetCreatureData is not glamorous, but it is what prevents behavior code from becoming storage code.

Let’s walk a single creature through the six systems. The player enters a map. Map loading restores the party and sees Charmander in slot one. It does not compute Charmander’s base attack. It just makes the world active. The player talks to an NPC. The script checks whether the lead creature exists and maybe gives a held item. The party module returns slot one. The creature accessor sets held item. The player opens the summary screen. The summary UI asks for species, level, HP, moves, and stats. It displays them. It does not know if stats were cached or recalculated ten frames ago. The player enters battle. Battle setup reads the party creature and creates a battle participant. During a turn, Ember spends PP and damage is calculated from battle-local structures plus stable creature stats. The enemy hits back, and current HP changes. After battle, experience is awarded, level may increase, stats are recalculated, and the party creature is updated. The player uses a potion afterward. The item effect asks max HP, asks current HP, applies a bounded heal, and writes current HP. Then the game saves. Save persistence writes the canonical fields and ignores battle-only turn order, last selected command, and animation state.

That story is simple, but the architecture is not trivial. Each system touches the creature, but each system touches it differently. That is why a shared raw struct is not enough as a design. A shared raw struct says, “everyone can see everything.” A proper creature module says, “everyone can ask the questions they are entitled to ask.”

Let me add one advanced wrinkle, because this is week 9 and your recent homework and quizzes have already checked your ability to identify source files, structs, functions, constants, data tables, and state variables. At this point, I expect you to think in dependencies. The creature module depends on species data. Species data should not depend on party UI. Party UI depends on creature accessors. Battle setup depends on party state and creature accessors. Item effects depend on creature operations. Save depends on creature serialization. If you reverse those dependencies casually, your clone becomes hard to test. For example, if RecalculateStats calls the summary screen to learn what species is selected, the architecture is backwards. If CreateCreatureFromSpecies asks the map script engine how to assign moves, the architecture is backwards. The lower-level data model should be usable without booting the entire overworld.

This also connects to the course arc from the first weeks. We started with AgbMain, callbacks, tasks, and the runtime shell. Then we moved through maps, object events, scripts, flags, and variables. Those systems were all ways of answering, “how does the game decide what runs next?” Creature records answer a different question: “what persistent individual state is being carried through those runtime flows?” The two questions meet constantly. A script command runs because the script interpreter advances. That command may give a creature. A battle starts because overworld and battle setup transfer control. That battle consumes creature state. A menu appears because callback and task systems draw and process input. That menu reads creature state. The course is deliberately building from execution flow toward persistent domain data.

So, before we move into the exact lab design, I want you to test your own clone design with three questions. First, can I change the creature’s internal layout without editing map scripts, item effects, battle turn code, and save UI? Second, can I recalculate derived stats from canonical data and species info after loading a save? Third, can I explain which system owns each temporary value during battle or menus? If the answer to any of those is no, the problem is not just a missing field. The problem is a boundary that has not been drawn clearly enough.

And now we are ready to turn this into implementation shape. In the next portion, I’m going to write the minimal clone API as if we were preparing the week 9 workshop: a species table, a Creature struct, a Party struct, accessor constants or typed accessors, creation routines, stat recalculation, item operations, battle write-back, and save normalization. Keep FireRed’s source organization in mind as evidence: pokemon.h as the public contract, pokemon.c as the implementation center, species_info.h as the data table, and consumers like summary, learn move, daycare, and battle setup as proof that many systems need creature data without owning its representation.

So, let’s put the implementation shape on the board. I’m going to write this as a minimal clone architecture, not as a literal FireRed replacement. That distinction matters. We are not trying to reproduce every byte of the Game Boy Advance storage layout. We are trying to preserve the architectural pressure that FireRed’s design responds to.

On the board, first box: SpeciesInfo table. Second box: Creature record. Third box: Party container. Fourth box: accessor layer. Fifth box: consumers. And under consumers I’m writing summary screen, battle setup, learn-move UI, daycare, item use, save system.

That picture is the whole week, really. FireRed’s `pokefirered/include/pokemon.h` contract, especially the Pokemon struct and data-access chunks `chunk_8e98575ccadc6d51` and `chunk_2cc1cd9d6bfc7136`, is not just saying, “Here are some fields.” It is saying, “Other systems may ask creature questions, but they should not casually become owners of creature layout.” Then `pokefirered/src/pokemon.c` in `chunk_af8613c6e25be253` is the implementation center that makes that boundary real. And the species table in `pokefirered/src/data/pokemon/species_info.h`, `chunk_99a58307a160a13c`, is the other side of the boundary: stable species facts that runtime Pokemon records refer to rather than duplicate.

For our clone, I would begin with a species record that contains the immutable biological design data. Species ID, name, base stats, growth rate, type information, base experience yield, learnable moves if we want to include that, and perhaps catch rate or item compatibility later. Notice I said immutable. Not because no game patch could ever change it, but because one individual creature does not own those facts. A level 12 Bulbasaur does not carry its species’ entire base-stat table inside itself. It carries a species ID, and that ID points into species data.

Now, right next to that, I’d define Creature as runtime individual state. Species ID, personality, level, experience, move IDs, PP, IV-like or simplified individual values if we include them, current HP, status, held item if our clone supports it, and calculated stats. If we are being disciplined, the calculated stats are either cached with a dirty flag or recalculated at controlled moments. What we should not do is allow every menu, every item, and every battle operation to improvise its own stat formula.

Let me give a concrete example. Suppose our clone has a creature with species ID 1, level 5, experience 135, moves Tackle and Growl, PP 35 and 40, and current HP 19. The summary screen wants to display Attack. The battle engine wants to use Attack in damage calculation. A healing item wants to restore HP but not exceed max HP. The save system wants to persist the creature and reload it tomorrow. These are four different consumers. If all four read raw fields directly, the moment we change stat storage, we break four systems. If all four go through something like `GetCreatureData(creature, CREATURE_DATA_ATTACK)`, or a typed function like `Creature_GetStat(creature, STAT_ATTACK)`, then the representation has room to evolve.

That is the reason FireRed’s GetMonData-style API is worth studying at an advanced level. It is not merely an old C trick. The constants and access patterns called out in `pokefirered/include/pokemon.h`, `chunk_2cc1cd9d6bfc7136`, turn creature data into a controlled query interface. The consumer asks for data by semantic meaning. The implementation decides whether that meaning lives in a packed substructure, a calculated field, a decrypted block, or a public member.

Check your understanding here. If the party menu asks, “What is this Pokemon’s current HP?”, should it know where current HP lives in the struct? No. It should know the query it is allowed to make. If the battle engine lowers HP after damage, should it write through a controlled operation? Yes. Because HP is not just a number on the screen. It affects fainting, switching, item eligibility, experience outcomes, and later save persistence.

Now let’s add the Party container. In the minimal clone, Party is not complicated. It is an array of six Creature records and a count. But conceptually it is doing something important: it gives the rest of the game a stable way to refer to player-owned active creatures. Party slot zero is not “the first Creature variable we happened to allocate.” It is a stored gameplay position. That position feeds menus, battle lead selection, healing center logic, scripts that check whether the player has a usable Pokemon, and save serialization.

This is where I want you to connect back to earlier weeks without re-opening those lectures. We already studied object-event records, NPC local IDs, script labels, trigger variables, and script pointer execution. Those systems are world interaction systems. They decide that an event happens. But when the event says, “Give the player a starter,” or “Check whether the party is full,” or “Heal the party,” the creature model takes over. The script VM should not invent party semantics. It should call into a party or Pokemon utility layer. FireRed’s wider source organization reinforces this division. For example, `pokefirered/src/battle_setup.c`, `chunk_494d132a59422c85`, includes and coordinates battle, Pokemon, save loading, overworld, scripts, and event data. That file is interesting because it sits at a border. It does not mean battle setup owns all of those systems. It means battle setup orchestrates them.

So for our clone, I would sketch these functions. `CreateCreature(speciesId, level, personality)` initializes individual state. `Creature_GetData` and `Creature_SetData` provide general access if we are following the FireRed style closely. Or, in a modern typed implementation, `getCreatureLevel`, `setCreatureExperience`, `getCreatureMove`, `setCreaturePP`, and so on. `RecalculateCreatureStats` reads the species table and the creature’s individual state. `Party_AddCreature` inserts into a slot. `Party_GetCreature` returns a reference only through a controlled interface, or at least makes clear who may mutate it.

And now the advanced point: accessors are not automatically good design. A trivial accessor that merely exposes every raw field with extra syntax gives you bureaucracy, not architecture. The accessor is valuable when it protects an invariant. For example, setting experience may require recalculating level. Setting level may require recalculating stats. Changing max HP may require preserving current HP ratio or clamping current HP. Setting a move may require resetting PP, unless it is a move replacement flow that preserves some separate rule. These are invariants. They are the reason the boundary exists.

Let’s do a little board-work example. I’ll write:

Creature has speciesId 4, level 16, exp 5600, currentHp 8, maxHp 39, moves Ember and Scratch.

Now the player uses a Rare Candy-like item. What changes? Level increases from 16 to 17. Experience may be adjusted to the level floor, depending on the game’s rule. Stats are recalculated from species base stats and individual data. Max HP might go from 39 to 41. Current HP should usually increase by the difference, so it becomes 10, not stay at 8 and not jump to full unless the item says so. Moves may need to be checked for level-up learning. Evolution may need to be queued or checked. The bag item count must decrease only if the operation succeeds.

That one item use touches inventory, creature data, learnset logic, UI messages, and maybe evolution. If you let the item system manually poke raw creature fields, you have guaranteed future inconsistencies. Instead, item use calls a creature operation: apply level increase, recalculate stats, return a result object or status code saying what happened. The item system owns item count and user messaging. The creature system owns creature invariants. The learn-move system owns move-choice flow. In FireRed, the presence of consumers such as `pokefirered/src/learn_move.c`, `chunk_af3598df6f092723`, and `pokefirered/src/pokemon_summary_screen.c`, `chunk_e8e17a42bbf17d46`, is evidence of that pressure. These modules need Pokemon data constantly, but they should not become the canonical definition of what Pokemon data means.

Let me pause and ask a check-for-understanding question. If the summary screen shows the wrong Attack after a level-up item, where do you first look? You do not begin by blaming the summary screen. You ask whether the level-up operation recalculated stats, whether the stat cache was updated, and whether the summary screen is querying the canonical accessor. The UI may reveal the bug, but the creature boundary is where the invariant belongs.

Now let’s include battle turns, because this is where many clone projects start to blur storage state and temporary state. In a battle, a creature has persistent properties: species, level, moves, PP, experience, current HP, status if your rules persist status after battle. But battle also creates temporary properties: volatile conditions, turn order modifiers, selected action, stat stages, temporary transformations, substitute HP, protection state, and so on. In a minimal clone, you might only implement HP, move choice, damage, PP decrement, fainting, and experience. Still, you should distinguish party storage from battle participant state.

Here is the simplest safe design. When battle begins, create BattleMon or BattlerState records from the party Creature records. Copy the data needed for battle. During each turn, mutate BattlerState for temporary combat flow. When battle ends, write back only the persistent changes: current HP, PP, persistent status, experience, level-ups, newly learned moves if battle can cause them. Do not write back confusion counters or “flinched this turn” flags. Those belong to the battle state machine, not to the creature record.

This is one of those lines that sounds obvious until you implement the system. Then, under deadline pressure, you are tempted to put “temporary attack modifier” into Creature because it is convenient. Resist that. The moment temporary battle state enters the saved creature record, your save file can preserve nonsense. The player reloads and a party member is still in a one-turn condition from a battle that no longer exists.

FireRed’s architecture has more historical and hardware-specific details than our clone needs, including packed and encrypted boundaries in Pokemon storage, but the lesson scales cleanly. The public contract in `pokefirered/include/pokemon.h`, `chunk_8e98575ccadc6d51`, and implementation in `pokefirered/src/pokemon.c`, `chunk_af8613c6e25be253`, tell us to be careful about which systems are allowed to interpret raw Pokemon memory. In a C codebase with packed data, that is a correctness issue. In a modern clone with objects or structs, it is still a correctness issue, just with different syntax.

Now, save persistence. This is where the minimal clone either becomes stable or becomes a pile of accidental snapshots. Saving should not mean “dump whatever happens to be in memory.” It should mean “serialize normalized persistent game state.” Party creatures are persistent. Species tables are not saved; they come from the build or game data. Battle temporary records are not saved unless your game explicitly supports mid-battle saving, and even then that is a separate design. UI cursor positions might be saved only if the game intentionally resumes menus. Script variables and flags are saved because they represent world memory, as we covered in the prior lectures. Map position is saved. Inventory is saved. Party is saved. The currently executing transient callback is usually not saved directly; instead, you resume into a known mode.

So, for our clone, the save file might contain player location, flags, variables, inventory, party count, six serialized Creature records, money, play time, and maybe PC storage later. Each Creature record should be serialized through a save-specific representation. I would not necessarily serialize calculated stats if they can be derived, unless doing so is part of your compatibility contract. If you do serialize them, then load must validate or recalculate them. The word I want you to write down is normalization. Save normalization means that after loading, the game state satisfies the same invariants as if it had been produced through normal gameplay.

Let’s make that concrete. Suppose an older save says a creature has level 17, current HP 42, and species data now says max HP at level 17 should be 41. On load, what do you do? For a class clone, you clamp current HP to max HP and record that the save was migrated. You do not let impossible HP propagate because the battle system will eventually trip over it. Similarly, if the save contains move ID 999 and your current move table has no such move, you need a migration rule, a fallback, or a hard load error. The wrong answer is to let the summary screen, battle engine, and item menu each discover the bad value differently.

Now, I want to tie this back to the overall course plan. Weeks 1 through 8 gave us the runtime shell, callbacks, tasks, maps, object events, scripts, flags, and variables. Those systems answer questions like, “Where is the player?”, “What event did they touch?”, “What script should run?”, and “What world state changed?” Week 9 starts the creature and party data model. Now we answer, “What is the player carrying as living game state?”, “How do species tables feed individual records?”, “How do menus, battles, items, and saves share that state without corrupting it?” Weeks 10 and 11 will raise the pressure because battle and inventory are not polite consumers. They mutate things. They create edge cases. They force us to decide which layer owns each rule.

And that is why the week 9 workshop is not just “make a struct.” If your workshop solution is only:

Creature has fields.
Party has array.
Done.

Then you have missed the architectural lesson. The better solution says:

Species facts live in a table.
Individual creature state lives in Creature.
Party slots organize active ownership.
Accessors protect layout and invariants.
Operations perform meaningful state transitions.
Consumers request data or actions without owning representation.
Save/load normalizes the persistent subset.

I’m saying that in prose, not as a formal checklist, because this is how I want you to reason while reading FireRed. When you see `pokefirered/src/daycare.c`, `chunk_119931105f546346`, including Pokemon-related headers along with menu, event data, strings, and party menu dependencies, treat that as architectural evidence. Daycare is not merely a cute side feature. It is a consumer that needs long-lived creature state, species rules, progression rules, UI, and script-facing world state. If your creature model cannot support daycare without daycare becoming the owner of creature internals, your boundary is too weak.

Same thing with the summary screen. `pokefirered/src/pokemon_summary_screen.c`, `chunk_e8e17a42bbf17d46`, is a dense consumer because it displays identity, moves, stats, items, and context-sensitive actions. It is a stress test for read access. Learn move, in `pokefirered/src/learn_move.c`, `chunk_af3598df6f092723`, is a stress test for controlled mutation. Battle setup, in `pokefirered/src/battle_setup.c`, `chunk_494d132a59422c85`, is a stress test for orchestration across overworld, script, save, item, and battle boundaries.

Let’s run one more concrete flow, end to end. The player talks to an NPC that gives them a creature. We are not re-teaching script execution here; we already did that. The script command fires because the object-event and script-entry machinery did its job. Now the command calls `Party_AddCreature(CreateCreature(speciesId, level, personality))`. Creation reads `SpeciesInfo` to establish legal base values. The party layer checks capacity. If there is room, it inserts into a slot and returns success. The script sets a flag or variable saying the gift was received. The fanfare and text are UI concerns. On the next frame, the party menu can display the new creature through accessors. If the player saves, the save system serializes the party record. If the player enters battle, battle setup builds battler state from the party slot. If the creature gains experience, battle writes back experience, level, HP and PP changes, and any move changes through controlled operations.

That is the full data route. Notice how many prior course systems are present, but none of them swallow the creature model. Runtime shell keeps frames moving. Scripts initiate the event. Flags remember world progression. Party owns active creature membership. Species data supplies immutable facts. Battle owns temporary combat flow. Save owns persistence. That is the course architecture coming together.

I’ll leave us at this midpoint with a local recap, not the final lecture close. The minimal clone is useful only if it preserves the same boundaries that make FireRed legible: table data for species, individual records for Pokemon, accessors for layout control, operation functions for invariants, and carefully chosen write-back points from battle, item, menu, and save systems. In the next stretch, we can make this even more exact by walking through pseudo-code for the accessors and the stat recalculation path, and then we will compare a naive direct-field implementation against a boundary-respecting one to see where the bugs actually enter.

So let’s pick up exactly there. Imagine I draw two little boxes on the board. The first box says “raw creature record.” The second says “creature operations.” The mistake in a beginner clone is to let every system reach into the first box. The boundary-respecting version makes almost every system go through the second box.

In FireRed terms, that is why the contract in pokefirered/include/pokemon.h, especially the struct and data declaration areas in chunk_55fc8220f5b93cdc, chunk_8e98575ccadc6d51, and chunk_2cc1cd9d6bfc7136, matters so much. The header is not just a convenient place to put fields. It tells the rest of the engine, “Here is what a Pokemon record is allowed to mean, and here are the named data slots you may ask for.” Then pokefirered/src/pokemon.c, chunk_af8613c6e25be253, becomes the behavioral side of that contract. It is where the access pattern is implemented, where layout stops being everybody’s business, and where invariants can be centralized.

Now, let’s do the minimal clone pseudo-code verbally. Suppose our classroom clone has a CreatureRecord with speciesId, personality, level, experience, moves, pp, currentHp, maxHp, attack, defense, speed, specialAttack, and specialDefense. A naive implementation would let the potion code say, “party[slot].currentHp += 20.” It would let the battle code say, “party[slot].experience += gainedExp.” It would let the summary screen say, “read party[slot].moves[2].” And that feels productive for about one week.

Then the bugs arrive. A potion heals beyond max HP. A level-up changes max HP but current HP is not adjusted correctly. A move is overwritten but PP is not reset. A fainted creature is given zero HP in one system and a negative HP in another. Save files preserve a half-updated record. And because direct access is scattered, the bug is not “in the potion system.” It is now in the architecture.

So, on the board, I would write this as a rule: systems request creature facts by name, and systems mutate creature facts through operations that know the invariants. That is the GetMonData-style lesson. The constants and access patterns named in pokefirered/include/pokemon.h, chunk_2cc1cd9d6bfc7136, are the important architectural clue here. A caller should not need to know whether experience sits near moves, whether stats are derived, whether some data is packed, or whether personality affects substructure order. The caller asks for “level” or “species” or “current HP,” and the Pokemon module decides how that answer is retrieved.

Check your understanding here. If an item menu wants to know whether a potion can be used, what should it ask? It should not inspect a dozen fields and reconstruct the health model itself. It should ask through an accessor or helper: what is current HP, what is max HP, is the creature fainted, can this item apply? The item system owns item choice and UI flow. The creature system owns creature state interpretation.

Now let’s make the stat recalculation path concrete. In a minimal clone, when experience changes, we need to determine whether the level changes. If the level changes, we recompute derived stats from species base stats, level, and individual modifiers. Species base stats should come from an immutable table, like the species data table represented in pokefirered/src/data/pokemon/species_info.h, chunk_99a58307a160a13c. That table is not the Pokemon. It is the species definition. The individual record says, “this is a level 17 Bulbasaur-like creature with this personality, these moves, this current HP.” The species table says, “the species has this base HP, this base attack, this type pairing, this growth behavior, these general facts.”

That separation is what keeps a party of six meaningful. Six creatures may share one speciesId, but they must not share one mutable record. If they did, gaining experience on one would level them all. Taking damage on one would damage the species. That sounds absurd, but it is exactly the category error that appears in small clone projects when species data and instance data are not separated.

So the recalculation flow is: battle awards experience to the party record through an operation; the operation updates experience; the creature module checks the growth curve and determines the new level; then it reads immutable species facts from the species table; then it recomputes stats; then it applies current HP adjustment carefully. If max HP rises by three during level-up, current HP usually rises by three as well, preserving the amount of damage already taken rather than fully healing or ignoring the max HP increase. That detail is small, but it reveals the larger architecture. Derived fields are not random cached numbers. They are the output of a policy.

Notice how this connects to battle turns. Battle owns temporary combat flow. It may have battler structs, turn order, selected moves, volatile effects, damage calculations, and messages. But after battle, some outcomes have to be written back: current HP, status, experience, PP spent, possibly friendship, learned moves, evolution triggers, and so on. The boundary question is not “can battle touch Pokemon data?” It must. The better question is, “where are the write-back points, and are they named operations?” FireRed’s battle setup code, for example, sits at a boundary between overworld state and battle state; pokefirered/src/battle_setup.c, chunk_494d132a59422c85, is useful evidence because its include list shows how battle setup draws from overworld, item, pokemon, save loading, script, event data, and battle transition modules. That is not accidental coupling. That is a transition hub. The mistake would be spreading transition logic everywhere.

Let me compare two clone designs. In clone A, the battle function receives a pointer to the actual party record and directly mutates every field during the turn. Damage subtracts from currentHp immediately. PP changes immediately. Experience changes immediately. If the player disconnects from the battle screen or if the battle has a special scripted outcome, you have to audit every intermediate mutation. In clone B, the battle runtime creates battler state from party records, runs the temporary combat sequence, and then commits specific results back to the party through operations. Clone B is not always simpler in raw line count, but it is simpler to reason about. It gives you a transaction boundary.

Now, I am not saying FireRed is a modern database transaction system. We are not projecting enterprise patterns onto a Game Boy Advance game. What I am saying is that the same architectural question exists: when does temporary state become durable state? During map loading, the loaded map header and objects describe the current world view. During script execution, flags and variables become durable progression memory. During party operations, creature records become durable player-owned state. During battle, battler state is temporary until selected outcomes are committed. During save, all of the durable state must be serialized consistently.

That gives us a very compact minimal clone architecture. We need a MapState with current map id, layout reference, object instances, and script entry points. We need a ScriptState with an instruction pointer, wait conditions, and access to flags and variables. We need a PartyState with up to six CreatureRecords. We need a BattleState with active battlers, selected actions, turn order, and temporary effects. We need an ItemState or BagState with item quantities and item effect functions. And we need a SaveState that serializes world flags, variables, party, bag, location, and a little bit of system metadata.

But here is the advanced point: those are not just folders. They are ownership boundaries. If the save system recalculates Pokemon stats while saving, it is doing too much. If the item system knows the raw storage layout of a creature, it knows too much. If the script system manually edits battle internals, it bypasses the battle boundary. And if the map loader creates Pokemon records directly, you probably misplaced encounter or gift logic.

Let’s bring in a concrete example from a familiar player action: using a Rare Candy-like item. The UI asks the player to select an item. The bag system confirms the item exists and decrements it only at the correct point. The party menu asks the player to select a creature. The item effect function checks whether the creature can gain a level. The creature operation adds enough experience or directly applies a level increase, depending on how the clone models that item. Then stat recalculation happens inside the creature module. If a move should be learned, control may pass into a move learning state machine. The research packet points us to pokefirered/src/learn_move.c, chunk_af3598df6f092723, which is a good supporting example because the excerpt explicitly frames the move relearner as a state machine with menu states. That is the same style of thinking: a user-facing feature is not one giant function; it is state transitions coordinated with creature data.

Pause there and test yourself. In that Rare Candy flow, who owns the level number? The creature record owns the stored level, but the creature module owns the right to update it correctly. Who owns the inventory count? The bag or item system. Who owns the menu cursor? The UI task or menu state. Who owns whether a script should resume afterward? The script or field system. When you can answer those questions cleanly, your clone is starting to resemble FireRed architecturally, even if it has one percent of FireRed’s content.

Now let’s compare direct-field implementation against boundary-respecting implementation more sharply. Suppose a student writes a function called usePotion(creature). Inside it, it sets creature.hp equal to min(creature.hp plus 20, creature.maxHp). That sounds fine. Then a second student writes battleDamage(creature, amount), and it sets creature.hp minus equals amount. A third student writes revive(creature), and it sets creature.hp equal to creature.maxHp divided by two. The code works until you add status conditions, faint checks, battle messages, abilities, friendship, held items, or save validation. Then each function becomes its own interpretation of what HP means.

The boundary-respecting version says: applyHealing(creature, amount), applyDamage(creature, amount, source), reviveCreature(creature, fraction), isFainted(creature), getCurrentHp(creature), getMaxHp(creature). These names may look boring, but boring names are doing architectural work. They are collecting policy. If later you decide that healing cannot apply to fainted creatures except through revive, you have a central place to enforce it. If later max HP is recalculated, you do not have every system caching an old value.

This is why accessor design is not just encapsulation theater. In FireRed, the Pokemon structure is not merely a plain object for convenience. The course source focus points us to pokefirered/include/pokemon.h, chunk_8e98575ccadc6d51, for the struct contract, and pokefirered/src/pokemon.c, chunk_af8613c6e25be253, for the implementation side. The advanced lesson is that a struct contract can make a C codebase more modular when the rest of the program respects the access pattern. C does not force you to respect it. Architecture does.

Let me put another board cue here. I draw three horizontal layers. Top layer: gameplay systems, such as maps, scripts, menus, battle, items. Middle layer: operations, such as GetCreatureData, SetCreatureData, RecalculateStats, ApplyExperience, HealCreature, SpendMovePP. Bottom layer: storage, such as party array, boxed record, packed fields, species table references. The rule is that top-layer systems may call middle-layer operations. They should not casually tunnel into bottom-layer storage.

There are exceptions, and advanced engineers should always ask about exceptions. Performance can require direct access in hot loops. Legacy code can expose fields before boundaries are formalized. Some data may be intentionally public because it is not dangerous. But exceptions should remain explainable. If you cannot explain why a system bypasses an accessor, assume it should not.

Now, how does this relate to encrypted or packed creature data boundaries? FireRed’s full Pokemon model is more complex than our classroom clone. It distinguishes stored and active representations, and some creature data is not meant to be treated as a simple flat public object. The exact details are less important today than the boundary lesson. Packed or encrypted storage creates an architectural pressure: if every caller has to decode, shuffle, or validate storage, the whole program becomes brittle. Accessors are the pressure valve. They let storage be compact, protected, or historically weird while giving the rest of the engine stable questions to ask.

And that connects back to species tables. The species table is ordinary-looking data, but it feeds runtime behavior constantly. Summary screens need display facts. Battle needs stats, types, and move behavior connections. Evolution and learning systems need species-dependent rules. The daycare code excerpt in pokefirered/src/daycare.c, chunk_119931105f546346, is useful here not because we are teaching daycare today, but because its includes show that a creature-adjacent feature draws together battle, constants for items and moves, mail data, storage, event data, random, menus, overworld, Pokedex, trade, and more. Creature records sit in the middle of the game’s feature web. That is why this week matters.

Let’s do one more concrete walkthrough, this time from map to script to party. The player talks to an NPC who gives a starter creature. We already know from previous lectures how object events and script labels provide the entry point, so I will not reteach local IDs or script command dispatch. We will just use them as the front door. The script says, in effect, “give the player this species at this level.” That command should not manually allocate a creature by writing every field in the script interpreter. Instead, it should call a creature creation function. That function receives speciesId and level. It chooses or receives a personality value. It initializes experience consistently for the level. It chooses initial moves, initializes PP, computes stats from species info, sets current HP, and returns a valid record. Then the party system adds it to the first open slot. Then the script sets a flag so the gift cannot be repeated.

See the boundaries? Script owns progression logic: has the gift happened, what text displays, what branch follows. Party owns membership: is there room, which slot is used. Creature creation owns record validity. Species data owns immutable base facts. Save later owns persistence. None of those systems has to become the other.

Check for understanding. If there is no room in the party, where should the failure be detected? The party add operation should detect capacity. The script may decide what message to show after failure, but it should not count raw party slots by duplicating party internals. If the species id is invalid, where should that be detected? Ideally in the creature creation path or a validation layer close to it. If the player already received the starter, where is that remembered? In flags or variables, our world memory from last week. These answers are small, but they are the architecture.

Now, as we connect week 9 to the overall course plan, notice the course has changed texture. In weeks 1 through 3, we cared about the runtime shell: startup, callbacks, tasks, and how frames keep moving. We used AgbMain and SetMainCallback2 earlier, and task creation and RunTasks earlier, to understand how the engine gets time on the CPU. In weeks 4 through 8, we moved through maps, object events, scripts, flags, variables, and the data-backed overworld. Now in week 9, the question is not “how does an event begin?” We know that. The question is “what durable player-owned state does that event modify?” Creature records are one of the most important answers.

Weeks 10 and 11 will build on this. Once we understand creature records and species tables, battle stops looking like magic. Battle becomes a temporary interpreter of creature state plus move data plus rules. Inventory stops looking like a bag of arbitrary effects. It becomes a set of item operations that call into party, creature, battle, map, or script boundaries. Save persistence stops looking like “dump memory to disk.” It becomes a deliberate snapshot of durable state, with temporary callbacks, menu cursors, and battle intermediates either excluded or reconstructed.

This is also where our secondary comparison to Pokemon Showdown becomes useful, but only as comparison. The research packet reminds us that Showdown’s data and tests are high-signal for battle data hooks and deterministic regression testing. For example, pokemon-showdown/data/mods/gen2stadium2/scripts.ts, chunk_3480e574205d5d0f, shows damage logic expressed through move objects, callbacks, immunities, fixed damage, and category-like properties. That is a different architecture from FireRed’s C engine, but the comparison is productive: both systems need a disciplined boundary between data definitions, runtime battle state, and durable creature identity. Showdown is more simulator-oriented. FireRed is the primary architecture source for this course because it ties battle back to overworld, party, save, UI, and cartridge-era constraints.

Let’s close this part with the minimal clone checklist, but I’ll say it as a synthesis rather than a handout. A minimal map loader does not need every FireRed feature, but it needs to load a map identity, layout reference, object list, and script entry points. A minimal script executor does not need every command, but it needs an instruction pointer, blocking behavior, flags, variables, and calls into other systems. A minimal party model does not need breeding, ribbons, mail, or boxes on day one, but it needs valid creature records, party capacity, accessors, and stat recalculation. A minimal battle turn system does not need every move effect, but it needs temporary battler state, action selection, turn resolution, PP use, HP changes, and deliberate write-back. A minimal item system does not need every item, but it needs item quantities and effect functions that call proper operations. A minimal save system does not need every checksum detail on day one, but it must know which state is durable and must avoid preserving half-temporary runtime machinery.

The through-line is this: FireRed is legible because many of its systems are data-driven, but data-driven does not mean “everything reads everything.” It means tables, structs, globals, callbacks, tasks, scripts, and accessors cooperate through recognizable boundaries. The Pokemon record is one of the best places to see that discipline because it is touched by almost every major system. Menus display it. Items modify it. Battle consumes and writes back parts of it. Scripts create and award it. Species tables feed it. Save persists it. Storage may pack it. Accessors protect it.

So when you go into the week 9 lab, do not try to impress me with the number of creature features you can squeeze in. I want the smaller, harder thing: a minimal creature record whose layout is hidden well enough that you can change it later. Implement species ID, personality, level, experience, moves, PP, stats, and accessor functions. Then write one or two operations that prove the boundary matters: add experience and recalculate stats; use a healing item without exceeding max HP; spend PP through a function instead of decrementing a field from battle code. If your clone can do that cleanly, then you are no longer just copying Pokemon-like mechanics. You are practicing the architecture that makes a creature RPG maintainable.

And that is the final synthesis for today. Runtime shell gives the engine motion. Map loading gives the player a place. Object events and scripts give that place behavior. Flags and variables give the world memory. Creature records give the player durable companions. Species tables give those companions shared biological facts. Battle gives them temporary conflict. Items and menus give the player controlled ways to inspect and modify them. Save persistence carries the result forward. Week 9 sits right at the hinge between world systems and battle systems, because the party is where overworld progression becomes combat capability. Keep that hinge clean in your clone, and the rest of the course will fit together much more naturally.

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