# Legality Is a Filter Over Data

Lecture ID: lecture_w22_d02
Week 22, Day 2

## Objectives
- Identify the FireRed files, structs, functions, constants, data tables, and state variables that implement each major game system.
- Connect week 22 material to the overall course plan.

## Transcript
All right, let’s pick up from yesterday’s comparison between the Showdown Dex and FireRed’s static tables. Yesterday I kept pushing one sentence: the Dex is not just a pile of JSON-like data, it is a facade over battle-relevant data. Today I want to sharpen that into a second sentence, and I want you to keep this one in your notes because it becomes very useful when you design your own creature RPG: legality is a filter over data.

Not legality as in “is this record present.” Not legality as in “can my lookup function find it.” Legality means: given a rule environment, a generation, a mod, a format, and sometimes an acquisition path, should this thing be allowed to participate? That is a different question from whether the data exists.

Let me say that again more concretely. If I can ask a data system for a move called Hidden Power, and it returns a move record, that tells me Hidden Power is known to the data layer. It does not, by itself, tell me that Hidden Power is legal in the current format, available to the current species, learnable by this particular individual, or representable in a FireRed-style runtime. That distinction is the center of today’s lecture.

Now, to connect this to the course architecture: in FireRed, we have spent many weeks tracing data table to runtime global to callback, task, script, or battle behavior. That’s still the model. FireRed’s core question is usually, “What table does this index address, and which subsystem consumes it?” We saw that in the runtime shell with `AgbMain`, in `pokefirered/src/main.c` `chunk_b35676322b169f85`, and we saw how control is handed off with `SetMainCallback2` in `pokefirered/src/main.c` `chunk_6cfd90f6d0136799`. We saw tasks created and dispatched through `CreateTask` and `RunTasks`, in `pokefirered/src/task.c` `chunk_cb0bb91a147bfb59` and `chunk_3ffebc0341225936`. I am not going to re-teach that shell today. I’m using it as a frame.

The new thing in week 22 is that Showdown asks us to separate lookup from admissibility. FireRed certainly has constraints, but many of those constraints are compiled into tables, constants, scripts, party structures, and menu flows. Showdown, because it has to represent many generations and many rule environments, makes the boundary more visible.

So, board cue here: I’m writing three words in a row. “Exists.” “Resolved.” “Legal.” These are not synonyms.

“Exists” means there is a data record somewhere. “Resolved” means the lookup layer can normalize a user-facing identifier into the canonical record. “Legal” means the current rule context permits it.

Showdown’s Dex documentation is useful because it makes the lookup layer explicit. The source packet points us to `pokemon-showdown/sim/DEX.md` `chunk_922688d7428150d1` for the Dex purpose and move lookup. That is our starting comparison point. When the Dex returns move data, it is acting as a facade: client code does not need to know every raw table location or every alias resolution detail. It asks the Dex. FireRed, by contrast, tends to expose the tables more directly through C constants and arrays. A move ID indexes into move data. A species constant indexes into species data. The architecture is lean, fast, and ROM-oriented.

But, and this is the important bit, FireRed’s direct table access should not trick you into thinking there is no filtering. There is filtering. It is just distributed differently.

Let’s use moves first. In FireRed, battle move behavior is not simply “read a row from the move table and do exactly that.” Battle code includes many constants and subsystems that interpret move effects, abilities, items, weather, statuses, scripts, and battler state. The packet’s excerpt from `pokefirered/src/battle_util.c` `chunk_9335e5727aa0657d` is a good evidence point here because the include list alone tells the story: `constants/moves.h`, `constants/items.h`, `constants/abilities.h`, `constants/battle_move_effects.h`, weather constants, battle scripts, battle AI commands, and party or Pokémon utility headers all converge in battle utility code. That means a move’s meaning is not isolated inside one table row. The row is data. The battle engine supplies interpretation.

In Showdown, the same architectural fact appears in a more dynamic shape. `pokemon-showdown/data/moves.ts` `chunk_012eada95ff7aa5f` is identified in the packet as containing secondary move data. Showdown move records include battle-relevant fields, but those fields exist inside a Dex and simulator environment that can be modified by generation-specific data. So the record you get is already shaped by the mod you loaded. That’s why `pokemon-showdown/sim/DEX.md` `chunk_5fbe60392b5eedf9`, the generation mod chunk, matters so much. A Gen 9 Dex and a Gen 3 Dex are not just two filters over one flat dictionary. They are different rule-aware views over data.

Now, pause there. Check for understanding. If I ask, “Does this move exist?” and you answer by saying, “It is legal in Gen 3 OU,” you have skipped two levels. If I ask, “Is this move legal?” and you answer, “The Dex can retrieve it,” you have also skipped two levels. Those are different claims. Advanced architecture work requires you to keep them separate, especially when writing test tools.

Let’s walk a concrete example. Suppose we write the workshop script for this week. The script loads a Showdown generation mod, prints selected move and species records, filters nonstandard data, and documents how that differs from FireRed static tables. We might load a mod through the Dex API, then ask for a move, a species, an ability, and an item. The packet specifically points to `pokemon-showdown/sim/DEX.md` `chunk_74ee605430e5596f` for the moves, species, abilities, and items APIs. That API surface is very revealing. Showdown gives you category-specific lookup namespaces: moves, species, abilities, items. That means the code speaks in domain concepts, not raw array offsets.

In FireRed, if we are tracing the equivalent, we would start with constants. A move is a `MOVE_` constant. An item is an `ITEM_` constant. A species is a `SPECIES_` constant. Then we would ask: which table consumes the constant? Which function reads it? Which global state stores it during battle, party inspection, menu display, or script execution? This is the method you used in homework and quiz work: identify files, structs, functions, constants, data tables, and state variables that implement a major system. Week 22 raises the bar by asking you to compare that with a system where the lookup layer itself is a first-class abstraction.

Let me give you a FireRed-side trace, but briefly, because you already know the tracing method. Battle entry is not just “the player touched grass and now a battle exists.” `pokefirered/src/battle_setup.c` `chunk_494d132a59422c85` shows the battle setup module pulling in overworld, task, script, event data, Pokémon utilities, battle transition, battle tower, wild encounter, and other dependencies. That is the architectural boundary between field state and battle state. If a wild encounter is possible, or a trainer battle is configured, battle setup coordinates the transition. Legality in FireRed is often enforced before or during these transitions by scripts, flags, encounter tables, party state, and battle setup conditions. The game does not need a universal “legal format validator” because it is one fixed commercial ruleset with a tightly controlled acquisition pipeline.

Showdown does need something closer to universal validation, or at least reusable validation concepts, because it supports multiple generations, formats, custom mods, historical content, and data that may exist but not be allowed. That is exactly where `pokemon-showdown/sim/NONSTANDARD.md` `chunk_800f1eafbea0ed7c` becomes central. The packet summarizes that chunk with the phrase “all data requires filtering.” That phrase is not just a Showdown implementation detail. It is the conceptual heart of the lecture. A database can contain future, past, event-only, unreleased, custom, or obsolete records. A simulator can know about them. A format may still reject them.

Board cue: I’m drawing a box labeled “Data Universe.” Inside that, a smaller box labeled “Resolved Dex View.” Inside that, a smaller box labeled “Format-Legal Set.” Then, inside that, an even smaller box labeled “Individual Set.” The individual set is what a particular creature may actually have: species, level, ability, item, moves, form, origin constraints, and so on.

FireRed collapses some of these boxes because the official game is not trying to host every competitive format from every generation. But the boxes still exist conceptually. The ROM contains data. The current map or script selects a subset. The party structure stores individual Pokémon. Menus and battle code interpret what is currently possible.

Now let’s talk learnsets, because this is where many students overfit. A learnset is not the same thing as move data. Move data says what the move is. Learnset data says how a species may acquire that move, usually within some version or generation context. Showdown’s modern learnset files, including `pokemon-showdown/data/mods/gen9dlc1/learnsets.ts`, are named in the packet as high-signal modern modeling references. But the packet also warns us: this is not FireRed behavior. Use it as a secondary source-use note, not as authority for how FireRed does learning.

In FireRed, the move relearner is a runtime menu and state machine, not just a static legality query. The packet gives us `pokefirered/src/learn_move.c` `chunk_af3598df6f092723`, whose excerpt explicitly describes the “Move relearner state machine,” including `CB2_MoveRelearner_Init`, list menu scroll state, and `MoveRelearnerStateMachine`. This is a perfect example of our course thesis. A player-visible system comes from data plus state plus callbacks and tasks plus UI code. The move may be in a learnable set, but the experience of relearning it is mediated by a menu state machine, input handling, list scrolling, script return paths, and party mutation.

So if you build a clone and ask, “Where should legality live?” the answer is: not in only one place. You want a clean legality service or validator if you support many rule contexts, but you also need runtime subsystems that enforce local constraints at the point of interaction. For example, a move relearner screen should not show moves the creature cannot relearn. A trade screen should not allow a forbidden transfer if the rule context forbids it. A battle engine should not assume the team builder was honest if your game supports imported teams or network play. This is why Showdown’s separation is so valuable pedagogically. It shows us the difference between data lookup and rule filtering.

Let’s make that concrete with a small imaginary comparison. In a FireRed-like C architecture, you might have `gBattleMoves[MOVE_THUNDERBOLT]`. That record gives you power, type, accuracy, PP, effect, and maybe other fields depending on your codebase. If a Pikachu uses Thunderbolt, the battle engine does not ask, at that moment, “Could this Pikachu have legally learned Thunderbolt from every possible origin path?” It assumes the party data is already valid because the game’s own acquisition systems created it. The legality boundary is distributed across learn-up moves, TMs, tutors, scripts, party creation, gift Pokémon, and save persistence. Remember, we already studied save block ownership and load-save initialization. I am not going back through sector validation today. The only point we need is that FireRed’s save system preserves state produced by controlled in-game systems.

In Showdown, a user can type or import a team. That changes the threat model. The simulator cannot assume the party came from an official acquisition pipeline. So legality has to be reconstructed as a filter over data. Is the species available in this generation? Is the ability available? Is the move compatible with the species? Is the item standard? Is the thing marked nonstandard? Is the format allowing it anyway? That last question matters because nonstandard does not always mean unusable everywhere. It means the data has a status that must be interpreted by a format or validator.

Check for understanding again. If I hand you a Showdown move object and it has a property indicating some nonstandard status, should your lookup script delete it from memory? No. The data layer may still need to know it. Your script should filter it for the current output or legality report. That is the difference between destructive data pruning and contextual filtering. In architecture terms, destructive pruning loses information. Contextual filtering preserves information and makes admissibility explicit.

Now, let’s connect this to generation mods. Yesterday we said a Showdown mod is not just a cosmetic namespace. The generation mod changes what data means in that generation. `pokemon-showdown/sim/DEX.md` `chunk_5fbe60392b5eedf9` supports that point directly because it is the generation-specific Dex.mod focus in the packet. If you call into a Gen 3 mod, the records you retrieve should reflect Gen 3 assumptions. If you call into a Gen 9 DLC mod, you are in a different data environment. For advanced students, the key design lesson is this: the mod is part of the lookup context, not an afterthought applied after lookup.

FireRed’s equivalent is less flexible but easier to reason about. It is essentially one generation-specific ruleset compiled into the program and data. Yes, there are runtime modes, link states, battle types, maps, scripts, and flags. We have covered RFU mode constants, link manager callback messages, and VBlank timers already, so I will only gesture at them here. The important contrast is that FireRed’s “mod” is the cartridge build. Showdown’s mod is a runtime or library-level selection.

Slide cue: imagine the left side says FireRed, and beneath it: compile-time constants, ROM tables, controlled acquisition, direct IDs. The right side says Showdown, and beneath it: Dex facade, generation mods, normalized lookup, nonstandard filtering, validator context. Neither side is “better” in the abstract. They optimize for different products.

FireRed is a constrained handheld game. It wants deterministic, memory-conscious behavior on a fixed platform. Showdown is a simulator and battle platform. It wants to represent many rule environments and accept external team descriptions. So FireRed favors table indexing and distributed enforcement. Showdown favors facade lookup and explicit filtering.

Let’s bring abilities and items into the same frame. The packet includes `pokemon-showdown/data/abilities.ts` `chunk_da22cf969179258c`, whose excerpt describes ability ratings. Those ratings are not FireRed-style cartridge mechanics. They are simulator-side metadata useful for evaluation, search, or competitive interpretation. An ability can have a rating field in Showdown because the data model serves more than just executing cartridge behavior. It supports tooling, display, analysis, and metagame reasoning. In FireRed, ability constants and battle effects are more tightly coupled to the battle engine’s needs. Again, same domain object, different architectural pressure.

This is why I am careful with the word “secondary” when we use Showdown in this course. Showdown is an excellent comparison source. It can clarify boundaries that FireRed hides through fixed-platform assumptions. But when we ask, “How does FireRed implement this?” Showdown is not the authority. FireRed source is the authority. If we are discussing battle utility dependencies, we cite `pokefirered/src/battle_util.c` `chunk_9335e5727aa0657d`. If we are discussing battle setup crossing from overworld to battle, we cite `pokefirered/src/battle_setup.c` `chunk_494d132a59422c85`. If we are discussing the move relearner menu state machine, we cite `pokefirered/src/learn_move.c` `chunk_af3598df6f092723`. If we are discussing Dex lookup or modded data facade behavior, then Showdown’s `pokemon-showdown/sim/DEX.md` chunks are the right evidence.

Now I want to set up the lab mental model. When your script loads a generation mod and prints selected records, I do not want a dump. A dump proves almost nothing. I want a small report that distinguishes record existence, resolved lookup, and legality-related filtering. For example, print the raw requested ID, the normalized ID, whether the record exists, whether it carries a nonstandard marker, and whether your script includes or excludes it under your chosen rule. Then, for FireRed comparison, write a note saying, “In FireRed, this would more likely be represented by a move constant and static table access, while legality would be enforced by acquisition tables, scripts, menu flows, and battle assumptions.”

That sentence is worth more than fifty lines of undifferentiated JSON. It shows that you understand architecture.

Let me pause and ask a diagnostic question. Suppose your Showdown script asks for a species and gets a valid species record. Then it asks for a move and gets a valid move record. Can you conclude that the species can learn the move? No. You need learnset data or validator logic. The species record and the move record are primary objects, but compatibility is a relation. Relations are where legality becomes interesting.

FireRed has the same concept, but with a different shape. A species can have base stats, types, abilities, growth rate, egg groups, and so on. A move can have battle properties. The relation between species and moves appears in level-up learnsets, TM/HM compatibility, tutors, special scripts, and event distributions. The move relearner then creates a player-facing path through part of that relation. That is why `learn_move.c` matters. It is not merely UI. It is a legality-shaped interface into party mutation.

We are going to continue from here by classifying the major legality boundaries in FireRed first, and then mapping each one to the closest Showdown concept without pretending they are identical. Keep the three words visible in your mind: exists, resolved, legal. The rest of today is basically us refusing to collapse those three words into one.

So, let us put the first boundary on the board. I am writing, “existence boundary.” This is the lowest bar. It asks only, does this identifier point to a record in the data universe I am currently using?

In Showdown, that is the reason the Dex facade is such a useful comparison point. The documented Dex purpose in `pokemon-showdown/sim/DEX.md`, chunk `chunk_922688d7428150d1`, is not merely convenience lookup. It gives code a consistent way to ask for a move record, species record, ability record, or item record without every caller manually knowing where that data lives. And then `pokemon-showdown/sim/DEX.md`, chunk `chunk_74ee605430e5596f`, makes that more explicit through the moves, species, abilities, and items APIs. So if I say, “Dex moves get Flamethrower,” Showdown’s architecture is saying, “Resolve this human-ish or ID-ish request into a structured move object from the currently selected data layer.”

Now compare FireRed. FireRed does not have one runtime Dex object sitting there as a facade over all battle data. It has C constants, arrays, headers, structs, and include relationships. So the existence boundary is distributed. `MOVE_FLAMETHROWER` exists because the move constant exists, because the move data table has an entry at the corresponding index, because battle code includes the constants and data headers that allow that index to mean something. We have seen this pattern since week 2, when headers became cross-module contracts. Today, we are just applying that old idea with a sharper word: existence.

And notice the trap. Existence is not legality. A move can exist in the move table without being learnable by a particular species. A species can exist in the species table without being obtainable in ordinary play. An item can exist without being valid in a given battle context. If you collapse existence into legality, your clone architecture will become brittle, because every data lookup will accidentally become a rules decision.

Let me give a concrete example. Suppose we are asking whether a Charizard may know Surf. At the existence layer, the question is laughably easy. Does the species Charizard exist? Yes, as a species constant and species data record. Does Surf exist? Yes, as a move constant and move data record. But the interesting question is not whether both records exist. The interesting question is whether the relation between that species and that move is admitted by the game’s acquisition rules. That relation may be represented in several places: level-up learnsets, TM or HM compatibility, tutor eligibility, special scripts, or external event distributions. In FireRed, those are not all one beautiful object. They are scattered across data tables and gameplay systems. That is the architecture lesson.

Pause there. Check yourself. If your code says, “the move exists, therefore the party Pokémon may have it,” what layer did you skip? You skipped the legality filter. You treated lookup as permission.

Now I am writing the second boundary: “resolution boundary.” Resolution asks, after I name something, what exact record do I get back, and under which ruleset?

This is where Showdown’s mod system matters. `pokemon-showdown/sim/DEX.md`, chunk `chunk_5fbe60392b5eedf9`, describes `Dex.mod` as a generation-specific data mechanism. That means the same identifier can be resolved through a particular generational lens. A move might have different properties in different generations. A species might have a different ability set, learnset availability, or battle-relevant interpretation depending on the mod. So Showdown’s resolution boundary explicitly includes the chosen mod.

FireRed’s version is simpler and stricter because the ROM is one concrete game. There is no runtime “Gen 3 FireRed mod” chosen by the battle engine in the same way. FireRed is compiled around a fixed set of constants and tables. But do not confuse “fixed” with “not layered.” The resolution still depends on which subsystem is asking. Battle code resolves a move through battle move data and battle scripts. UI code resolves it through strings and menu presentation. Learn-move code resolves it through party data and learnable move lists. The identifier is shared, but the meaning emerges from the caller’s path through the system.

That is why the includes in `pokefirered/src/battle_util.c`, chunk `chunk_9335e5727aa0657d`, are such a useful architectural clue. That file pulls in `constants/moves.h`, `constants/items.h`, `constants/abilities.h`, `constants/pokemon.h`, `constants/hold_effects.h`, and `constants/battle_move_effects.h`, along with battle scripts, battle message, controllers, random, event data, weather, and more. This is not trivia. It shows you that battle legality and battle behavior are not computed from one isolated record. Battle utility code sits at the intersection of identifiers, state variables, scripts, effects, items, abilities, weather, and controller flow.

So if we map this back to our three words, `battle_util.c` is often working after existence and resolution. By the time a battle effect is being evaluated, the species, move, ability, and item identifiers have already become indices into the battle state. But that does not mean everything is legal. Battle still filters by context. Can this move be selected? Is the battler asleep? Is the item usable? Does the ability suppress an effect? Is the target semi-invulnerable? Those are contextual legality filters over already-resolved data.

Let me put that in a sentence worth copying into your notes: legality is not one gate at the front of the program. It is a series of filters at different distances from the data.

Now let us classify the major FireRed legality boundaries. First, construction legality: can this record be produced by normal game systems? That includes wild encounters, starters, gifts, trades, fossils, eggs, and scripted distributions. Second, mutation legality: once the creature exists, can its fields be changed in this way? Leveling, evolution, move learning, item use, healing, status changes, EV changes, and nickname changes all live here. Third, participation legality: can this creature, item, or move be used in the current mode? Battle, overworld, link trade, link battle, Safari Zone, field moves, menus, and scripts all impose different filters. Fourth, persistence legality: can this state be saved and later trusted enough to restore? We will not re-teach the save block material from the earlier lecture, but remember that save ownership and validation are part of this larger story. Persisted state is not automatically meaningful; it is meaningful because load-save initialization and validation decide which bytes become world state again.

Now, let us focus on mutation legality, because the last passage pointed us to `learn_move.c`. The research packet excerpt from `pokefirered/src/learn_move.c`, chunk `chunk_af3598df6f092723`, begins with a dense include set: `script.h`, `task.h`, `event_data.h`, menu helpers, list menu, text windows, summary screen, graphics, strings, and `constants/moves.h`. Then the comment describes the move relearner state machine, beginning with `CB2_MoveRelearner_Init` and moving through `MoveRelearnerStateMachine`. That tells us something extremely specific. The move relearner is not a passive list of moves. It is a callback-driven and task-driven interface that mediates a party mutation.

Say that out loud in your head: mediates a party mutation.

The player sees a menu. Architecturally, the system is walking through a legality-shaped UI. The interface must know which party member is being edited, which moves are eligible to relearn, which current move might be replaced, which menu state is active, which script should resume afterward, and how to update the party data if the player confirms. The visible behavior is simple: “Teach this move?” The underlying boundary is sharper: “This move may be introduced into this Pokémon’s four-move set through this specific relearner path, under these script and menu states.”

Here is the concrete example I want you to keep. Imagine a Pokémon that once could have learned Ember by level-up but no longer has it. The move relearner may expose Ember. But suppose FireRed has a move that exists in `constants/moves.h` and appears in battle move data but is not part of that species’ eligible relearner set. The move relearner UI should not show it merely because the move exists. Nor should it show every move the battle engine can animate. Its filter is narrower. It is based on a species-to-move relation and a gameplay service.

In Showdown terms, learnsets act as a secondary modeling reference. The packet names `pokemon-showdown/data/mods/gen9dlc1/learnsets.ts` as a high-signal modern learnset file, with the warning that it is not FireRed behavior. That warning is pedagogically important. A modern Showdown learnset file is excellent for understanding the shape of species-to-move relations, but it is not evidence that FireRed permits the same relation. If you use modern learnsets to validate a FireRed clone, you have smuggled in the wrong generation’s legality. That is exactly why `Dex.mod` matters on the Showdown side and fixed compiled tables matter on the FireRed side.

Let me ask a check-for-understanding question. If your lab script this week loads the latest Showdown mod, asks for a species, prints its learnset, and then declares that result to be “FireRed legal,” what is wrong? The lookup may be correct for the selected Showdown mod, but the conclusion crosses a boundary. You resolved data in one ruleset and asserted legality in another. The correct lab note would say, “This demonstrates how a modern simulator models the relation; FireRed must be checked against its own compiled data and gameplay paths.”

Now, I am going to draw a small table on the board verbally. Column one is “system.” Column two is “data.” Column three is “filter.” Column four is “state that makes the filter contextual.”

For battle, the data includes move records, species stats, ability constants, item constants, battle scripts, and effect constants. `pokefirered/src/battle_util.c`, chunk `chunk_9335e5727aa0657d`, supports that claim because its include surface joins exactly those categories. The filters include move usability, targeting, immunity, ability suppression, item conditions, weather effects, status restrictions, and battle mode constraints. The contextual state includes battler structs, side conditions, weather state, turn state, controller state, and script position.

For battle entry, the data includes map and trainer references, encounter definitions, event flags, transition constants, and battle setup parameters. `pokefirered/src/battle_setup.c`, chunk `chunk_494d132a59422c85`, is our evidence here. Its include list pulls in `overworld.h`, `pokemon.h`, `load_save.h`, `safari_zone.h`, `quest_log.h`, `script.h`, `script_pokemon_util.h`, `event_data.h`, field movement, metatile behavior, event scripts, player avatar, field effects, battle transition, and battle controller material. Again, the include graph is showing the boundary. A battle does not begin just because a trainer record exists. The game must pass through overworld state, event state, script state, map behavior, and transition setup.

This is the same pattern you saw in the Cable Club lectures, just applied locally instead of over RFU and link state. In the link manager, we cared about communication mode constants and callback messages. Here, we care about battle setup constants and callback transitions. The general architecture skill is identical: do not identify the system only by the data table. Find the state machine that admits the data into player-visible behavior.

For inventory and item legality, the same distinction holds. An item can exist as a constant. It can have a name. It can have a description. But whether it can be used from the bag, held by a Pokémon, consumed in battle, sold, registered, used on the field, or rejected by the current menu depends on item effect data and caller state. This is where Showdown’s item lookup is useful but incomplete. `pokemon-showdown/sim/DEX.md`, chunk `chunk_74ee605430e5596f`, gives us an API category for items, but FireRed’s item legality is spread across bag UI, field use, battle use, hold effects, scripts, and party mutation routines. In other words, Showdown gives a clean facade. FireRed gives a compiled system of cooperating tables and functions.

For abilities, Showdown’s `pokemon-showdown/data/abilities.ts`, chunk `chunk_da22cf969179258c`, even includes rating metadata, explaining values from detrimental through essential. That is a perfect example of secondary data that FireRed does not carry in the same form. A rating is useful for simulator analysis, teambuilder sorting, AI heuristics, or metagame commentary, but it is not FireRed battle behavior by itself. FireRed’s ability legality starts with whether the species may have that ability, then continues into whether the battle engine checks that ability under the current effect. So, if you are building a FireRed-inspired clone and you import ability ratings, you must mark them as tooling metadata, not core cartridge behavior.

Let us slow down and make this very concrete with one species, one move, one ability, and one item. Suppose our creature is Bulbasaur, our move is SolarBeam, our ability is Overgrow, and our item is a Potion. In FireRed architectural terms, each of those names resolves through a different data family. Bulbasaur resolves through species constants and base species data. SolarBeam resolves through move constants and battle move data. Overgrow resolves through ability constants and species ability slots, then later through battle effect checks. Potion resolves through item data and item-use routines.

Now ask four questions. Does each thing exist? Yes, assuming the relevant constants and records exist. Does each thing resolve? Yes, in the appropriate subsystem. Is the combination legal as a generated or mutated party member? That is now more specific. Bulbasaur may have Overgrow because its species data allows it. Bulbasaur may know SolarBeam if acquired through the appropriate path, such as TM compatibility in the correct game context. Potion is not a held battle power item in the same way a held item with a hold effect is. It is a bag item that may be used under certain party or battle conditions. So the question “Is Bulbasaur with SolarBeam, Overgrow, and Potion legal?” is under-specified. Do you mean legal as a party state? Legal as a battle participant? Legal as a save record? Legal as a player action right now from this menu?

That is the advanced move for today: when someone says “legal,” ask, “Legal at which boundary?”

Showdown’s nonstandard filtering gives us a crisp comparative vocabulary. `pokemon-showdown/sim/NONSTANDARD.md`, chunk `chunk_800f1eafbea0ed7c`, is summarized in the packet as “all data requires filtering.” That is one of the most important sentences in this week. Showdown can contain data for past generations, future formats, unofficial content, event-only things, CAP-style content, and other records that should not all be admitted into every ruleset. Therefore, the simulator must distinguish “present in data” from “allowed in format.” FireRed has the same abstract issue, but its filters are mostly embodied in compiled gameplay routes, not in one universal `isNonstandard`-style check.

So, if we were writing a verifier for a FireRed save file, we would not merely ask whether move IDs are within range. That is necessary, but primitive. We would ask whether the species exists in FireRed, whether its ability slot is valid for that species, whether its moves can be produced by level-up, TM/HM, tutor, breeding, gift, trade, event, or other legitimate route, whether its current level and evolution state are coherent, and whether the location, flags, and progression context matter for the claim we are checking. And then we would label the result carefully. Maybe “structurally valid.” Maybe “plausible in-game.” Maybe “obtainable without events.” Maybe “battle-legal under local rules.” Those labels are not pedantry. They prevent architecture bugs.

Now, quick check. Why is “move ID less than number of moves” not a legality check? Because it only verifies that the identifier is in range. It says nothing about species compatibility, acquisition route, current context, or game mode. It is an existence or structural check, not a full legality check.

Let us connect this back to the course plan. Weeks 1 through 21 gave you the machinery: startup, callbacks, tasks, maps, scripts, party data, battle, inventory, save, and link. Week 22 changes the viewpoint. We are now comparing FireRed to Showdown to learn how a modern battle simulator separates lookup, modded data, and format filtering. But the goal is not to replace FireRed with Showdown. The goal is to become more precise when we trace a game system from table to state to behavior.

That is why your week 22 lab asks for a Showdown-side lookup script. It is not busywork. Loading a generation mod, printing selected move and species records, filtering nonstandard data, and documenting the difference from FireRed static tables forces you to practice the distinction. When the script says a move exists, you should write “exists.” When `Dex.mod` changes the record, you should write “resolved under this mod.” When a format or nonstandard check rejects something, you should write “filtered from this ruleset.” Then, when you return to FireRed, you should look for the equivalent boundary in constants, data tables, scripts, callbacks, tasks, and state variables.

Now I want to make one more mapping before we move on. Showdown’s `pokemon-showdown/data/moves.ts`, chunk `chunk_012eada95ff7aa5f`, is identified in the packet as secondary move data. That phrasing matters. A move data record can tell you properties of the move: power, type, category, flags, secondary effects, and so on, depending on the simulator’s schema. In FireRed, the battle move data and battle scripts together produce behavior. But neither source, by itself, tells you every species that may learn the move. Move behavior and move distribution are different axes.

Students often conflate those axes because they are both “about moves.” Do not. The battle engine asks, “What happens if this move is used?” The learnset system asks, “Which Pokémon may obtain this move, and through what path?” The UI asks, “How do I show and confirm the move?” The save system asks, “How do I persist the current four move IDs and PP values?” The link system asks, “How do I communicate enough battle state to synchronize or conduct multiplayer behavior?” Same move ID, different architectural role.

Let me say it another way. A move is not one thing in the architecture. It is an identifier traveling through several systems. Each system attaches different obligations to it.

Board cue: I am underlining “identifier traveling through systems.” That phrase is how you should think about species too. Species is not only a Pokédex entry. It is base stats, sprite selection, cry, evolution rules, encounter result, party struct field, battle battler attribute, summary screen display, trade payload field, and save data component. A legality filter may touch any one of those surfaces. If your verifier or clone engine checks only one, it is not wrong, but it must be honest about scope.

This is also why advanced architecture work requires naming state variables and functions, not just files. Saying “battle code handles it” is too vague. `battle_setup.c` is about admitting the game into battle through overworld, script, field, transition, and event conditions, as supported by `pokefirered/src/battle_setup.c`, chunk `chunk_494d132a59422c85`. `battle_util.c` is about battle-time helper behavior across moves, items, abilities, weather, scripts, and constants, as supported by `pokefirered/src/battle_util.c`, chunk `chunk_9335e5727aa0657d`. `learn_move.c` is about a menu and callback state machine that permits a controlled mutation of party moves, as supported by `pokefirered/src/learn_move.c`, chunk `chunk_af3598df6f092723`. Those are three different legality regions. Battle entry, battle execution, and party move mutation are not interchangeable.

So, when you work on homework week 22, I expect your answers to be more explicit than they were in week 18. Earlier, it was acceptable to say, “This table feeds this function.” Now I want, “This table establishes existence; this function resolves it for a subsystem; this state machine filters it for a player action; this global or struct field records the result.” That is the level the course is moving toward, because weeks 23 and 24 will ask you to use Showdown-style comparison and tests without losing the FireRed architecture underneath.

Let us stop for a moment and test the whole chain. I will give you a statement: “Because a move appears in Showdown’s data, it should appear in FireRed’s move relearner.” Is that valid? No. First, the Showdown record might be from a different generation mod. Second, a move behavior record is not a species learnset relation. Third, the move relearner is a specific FireRed mutation interface, not a general display of all moves. Fourth, FireRed’s compiled constants and tables are the authority for FireRed behavior. Good.

Second statement: “Because an item exists in FireRed constants, it can be used in battle.” Also no. Existence of an item identifier does not imply battle usability. Battle use depends on item type, effect, menu path, battle state, and sometimes restrictions imposed by mode or script.

Third statement: “Because Showdown has nonstandard filtering, FireRed must have an identical nonstandard field.” No. The concept maps; the implementation does not. Showdown’s explicit filtering language helps us reason. FireRed’s filters are expressed through data omission, constants, scripts, table relations, menu options, and state-machine branches.

That last distinction is the heart of the lecture. A modern simulator often makes legality visible as metadata and format rules. A GBA RPG often makes legality visible as pathways through compiled systems. Same abstract problem, different architectural surface.

Now, to make that distinction useful rather than merely philosophical, let’s turn it into a tracing habit.

When you see a piece of data, do not ask only, “Does this record exist?” Ask, “What route through the program is allowed to observe this record, and under what state?” That is the legality question. In Showdown, the route often begins at the Dex facade. The lecture packet points us to pokemon-showdown/sim/DEX.md chunk_922688d7428150d1 for the Dex purpose and move lookup, chunk_5fbe60392b5eedf9 for generation-specific Dex.mod behavior, and chunk_74ee605430e5596f for the moves, species, abilities, and items APIs. The architectural point is that Showdown concentrates a large amount of “what data means for this battle context” behind an access layer. So a script says, in effect, “Give me Thunderbolt in gen 3,” and the Dex answers with a normalized record from the correct generation view.

FireRed is not shaped that way. FireRed does not generally ask a runtime Dex object, “Please resolve this move in the active generation.” FireRed is already the generation. The generation boundary is compiled into constants, tables, and code paths. So the comparable FireRed question is not “which mod am I in?” but “which compiled table, constant namespace, script path, menu state, or battle routine can reach this identifier?”

Let me put that on the board as a sentence, because it is the shortest version of today’s model: in Showdown, legality is frequently a query-time filter over a broad data universe; in FireRed, legality is frequently a reachability property inside a fixed program.

And when I say reachability, I do not mean only control-flow reachability in the compiler sense. I mean gameplay reachability. Can the player get to this item through a mart, a pickup table, a script giveitem command, or a held item on an encountered Pokemon? Can this move reach a Pokemon through level-up, TM, tutor, egg inheritance, evolution move handling, or the move relearner? Can this battle option reach an effect through the current battle type, controller state, menu selection, item pocket, and item effect table? That is legality as the player experiences it.

Here is a concrete example. Suppose we are thinking about moves. In Showdown, you might write a lookup script for the lab: load a generation mod, call the moves API, print the move record, inspect whether it exists, inspect secondary behavior, and then filter out records marked as nonstandard when your format does not permit them. That is exactly the kind of exercise suggested by pokemon-showdown/sim/NONSTANDARD.md chunk_800f1eafbea0ed7c: all data requires filtering. Not all known data belongs in every playable context.

In FireRed, the analogous investigation is spread out. The move constants are visible through constants like those included in pokefirered/src/battle_util.c chunk_9335e5727aa0657d, where the file pulls in constants/moves.h, constants/items.h, constants/abilities.h, constants/pokemon.h, constants/battle.h, and constants/battle_move_effects.h. That include list is not just bookkeeping. It tells us battle utility code sits at the point where several identifier spaces become meaningful together. A move ID by itself is not enough. The move ID becomes behavior when battle code combines it with effect constants, ability checks, item checks, weather checks, battler state, and battle script execution.

So if I ask, “Is this move legal?” you should immediately ask, “Legal for what?” Legal to exist in the move table? Legal for a species to learn? Legal for a Pokemon currently in the party to know? Legal for the move relearner to offer? Legal to execute this turn under Taunt, Disable, Encore, PP, choice-lock, battle type restrictions, or some other runtime condition? Those are different filters.

Let’s use the move relearner because it is a compact example of FireRed’s style. The packet gives us pokefirered/src/learn_move.c chunk_af3598df6f092723, and the excerpt explicitly frames the “Move relearner state machine.” It mentions CB2_MoveRelearner_Init, list menu scroll position tasks, row handling, and MoveRelearnerStateMachine states such as a fade-to-black state. Notice the shape. This is not merely “look up all moves.” It is a UI-controlled state machine that creates tasks, displays a list, handles directional input, and eventually commits a selected move. Legality here is not one boolean attached to the move record. Legality is the set of moves that can enter that list for the selected Pokemon, then survive UI selection, cost checks, party mutation, and summary refresh.

Check your understanding for a moment. If a move appears in constants/moves.h, does the move relearner automatically offer it? No. The move must be reachable through the relearner’s own data path and state machine. If a move appears in a Showdown moves table, does every format automatically allow it? Also no. The Showdown side needs nonstandard and format filtering. The important difference is where you go hunting for the filter.

Now, let’s bring in secondary move data from Showdown, because it gives us a good comparison vocabulary. The lecture packet names pokemon-showdown/data/moves.ts chunk_012eada95ff7aa5f as a source for secondary move data. In Showdown’s data modeling, a move record can carry rich structured fields: base power, category, type, accuracy, flags, priority, secondary effects, volatile statuses, drain, recoil, and so on. I am not saying every one of those fields appears in the excerpt we have here; I am using the packet’s source focus: this file is where modern Showdown move data lives, and the named chunk is specifically attached to secondary move data. The architectural lesson is that Showdown’s move record is a modeling object. It wants to describe battle semantics in a form the simulator can read, extend, override, and test.

FireRed’s move behavior is more distributed. Some values live in move data tables. Some meanings live in constants. Some behavior lives in battle scripts. Some behavior lives in C utility functions. Some behavior appears as special cases because this is a commercial handheld game engine, not a general-purpose battle simulator framework. That is why pokefirered/src/battle_util.c chunk_9335e5727aa0657d matters to us. Its include surface shows battle utility code joining move constants, item constants, ability constants, weather constants, hold effects, battle animation constants, and battle move effect constants. That is FireRed’s “semantic merge.” It happens through compiled code and table conventions rather than through a single TypeScript object exposed by a Dex API.

And this is where advanced students often make a subtle mistake. They say, “Showdown is cleaner because all the data is in one place.” Sometimes, yes, for inspection. But “cleaner to inspect” is not the same as “the original game must have worked that way.” FireRed’s architecture was shaped by memory layout, ROM tables, GBA constraints, established engine patterns, and the fact that it shipped one target ruleset. Showdown’s architecture is shaped by multi-generation support, mod layering, active competitive formats, testability, and user-created variants. Those are different pressures.

Let’s do a board-work trace. I’ll write four columns: identifier, data record, access path, legality boundary.

In the first row, put “move ID.” The data record in FireRed is whatever move data table and related constants define the move’s basic properties. The access path might be battle execution, party summary display, TM use, tutor use, level-up learning, or move relearner. The legality boundary depends on the path. A move can be battle-executable if already known, but not teachable by TM. A move can be in the engine but not reachable by normal gameplay. A move can be listed in a learnset but blocked because the Pokemon already knows it or has no available move slot without deletion. The same identifier passes through different gates.

In the second row, put “species ID.” In Showdown, species lookup through the Dex returns a species record in a generation context, which is why pokemon-showdown/sim/DEX.md chunk_74ee605430e5596f matters for species APIs. In FireRed, species constants and species tables define base stats, types, abilities, growth data, evolutions, learnsets, sprites, cries, palettes, and so forth through separate table families. The species being defined does not mean it appears in the wild. Wild encounter tables, gift scripts, trainer parties, evolution chains, trades, and event distributions are all separate reachability filters.

In the third row, put “item ID.” Again, existence is not usability. pokefirered/src/battle_setup.c chunk_494d132a59422c85 is useful here because its include surface joins overworld, item, sound, Pokemon, load/save, scripts, event data, battle, battle transition, and battle setup concerns. That file lives near the handoff from field context into battle context. Items cross that boundary only through specific systems. A Potion in the Bag and a held item on a battler are both items, but they are not observed by the same code path at the same time. A Key Item may exist and be script-usable, but that does not make it battle-usable.

Now, think about the phrase “all data requires filtering.” In Showdown’s NONSTANDARD document, cited in the packet as pokemon-showdown/sim/NONSTANDARD.md chunk_800f1eafbea0ed7c, that statement is nearly a governance principle. The simulator knows about many things: past-generation moves, event-only distributions, CAP content, unreleased data, alternate formats, modded content, and so on. The Dex can know more than a format allows. Therefore, filters are not incidental; they are the difference between the data universe and a valid battle.

FireRed also knows more than any one moment allows, but its “more” is not always expressed as metadata. The ROM contains tables for all kinds of things not currently available to the player. The player standing on Route 1 cannot encounter every species merely because species data exists. The player in a trainer battle cannot use every item merely because item constants exist. The selected Pokemon cannot learn every move merely because move constants exist. The game’s state variables, scripts, maps, menus, and battle callbacks form the active legality surface.

Let me pause for a check. If I gave you a debugger and asked, “Why can’t this Pokemon learn this move from this menu?” where would you look first in FireRed? You would not start by globally searching for the move’s animation. You would start at the menu path. If it is the move relearner, inspect pokefirered/src/learn_move.c chunk_af3598df6f092723 and the data it consults. If it is a battle item, inspect the bag and battle item use path. If it is a field script gift, inspect script commands and event flags. The filter is attached to the access path.

Now let’s connect that to week 22’s lab. The lab asks you to write a Showdown-side lookup script that loads a generation mod, prints selected move and species records, filters nonstandard data, and documents how this differs from FireRed static tables. The trick is that the script is not just a convenience exercise. It is a comparison instrument. When your script calls a generation mod, you are making generation context explicit. When FireRed uses compiled constants and tables, generation context is implicit. When your script filters nonstandard records, you are making legality policy explicit. When FireRed routes through a menu, script, map, battle state, or task, legality policy is often embodied as program reachability.

So your write-up should not say, “Showdown has a Dex and FireRed has no Dex, therefore they are unrelated.” That is too shallow. It should say, “Showdown’s Dex is a battle data facade that centralizes lookup across data modules and generation mods. FireRed’s comparable facade is distributed across headers, tables, globals, callbacks, scripts, and battle routines.” That is a stronger architectural statement.

And yes, I want you to use the word “facade” carefully. A facade is not just “a file I import.” It is an interface that gives simpler access to a more complex subsystem. In Showdown, the Dex gives a normalized access surface for moves, species, abilities, and items, as the packet directs us to pokemon-showdown/sim/DEX.md chunk_74ee605430e5596f. In FireRed, there is no identical object, but there are repeated local facades. The battle setup module abstracts the transition into battle. The move relearner module abstracts a menu-driven move selection workflow. The task system abstracts per-frame updates. The script engine abstracts event progression. We studied those earlier, and we are not going to re-teach them now, but they matter because legality often appears at those module boundaries.

Here is another concrete example. Imagine a species that exists in the species constants and has base stats, but is never placed in a wild encounter table, never assigned to a trainer, never given as a gift, and never produced by evolution from any reachable species. From a data-definition perspective, the species exists. From a normal-player legality perspective, it is unreachable. From a save-editing perspective, a Pokemon of that species might still be representable in party data. From a battle-engine perspective, if inserted into the party, it might be able to battle because battle code can read its stats and moves. Those are four different notions of legality.

This is why “legal” is a dangerous word unless you attach a system name to it. Legal in encounter generation. Legal in party storage. Legal in link trade. Legal in battle execution. Legal in competitive format validation. Legal in a move tutor menu. Legal in a save file after checksum validation. Each phrase names a different filter.

We can now tie in learnsets as a secondary modeling reference. The packet names pokemon-showdown/data/mods/gen9dlc1/learnsets.ts as a high-signal modern learnset file, but warns us it is not FireRed behavior. That warning matters. Modern Showdown learnsets are excellent for understanding how a simulator models “which species can learn which moves under which sources.” They are not evidence for what FireRed did in 2004. In this course, Showdown is a comparison lens, not a replacement authority. For FireRed, you trace FireRed’s tables and code. For Showdown, you trace Showdown’s Dex, mods, and learnsets. Then you compare the architectural shape.

Let’s say that out loud because it will prevent errors on homework_w22 and quiz_w22: a modern learnset file can teach you how to think about source categories, but it cannot be cited as proof that FireRed allows a move. If you want to prove FireRed behavior, you need the FireRed source path, the relevant table or function, and the runtime path that consults it.

Now, because you are advanced students, I want to push one level deeper. Legality filters are not always negative filters. We often talk as though filters only remove invalid records. But filters also construct meaning. A generation mod in Showdown does not merely delete later-generation data; it can override records so the same named move has generation-appropriate behavior. The packet’s DEX.md chunk_5fbe60392b5eedf9, on Dex.mod generation-specific data, is the cue there. A mod is not just a blacklist. It is a lens through which lookup returns the version of data appropriate to that generation.

FireRed has an analogous but compiled lens: there is no runtime need to ask whether Thunderbolt is the gen 3 Thunderbolt, because the entire codebase is the gen 3 FireRed lens. Move constants, battle effects, animation behavior, item effects, learnsets, and scripts all agree by construction unless the source has a bug or a special case. That agreement is one reason static tables are powerful. But it also means that if you hack FireRed, you must update every table and path that participates in the concept. Adding a move is not “add one JSON object.” It is constants, names, descriptions, effects, animations, learnsets, compatibility, AI considerations, and UI display constraints. The legality filter becomes your responsibility across the whole engine.

A quick check for understanding. If a ROM hacker adds a new move constant and a name string, but does not add a learnset path, TM path, tutor path, or script path to acquire it, what has been created? Not a normally legal move for player use. They have created a partially defined move identifier. Depending on other tables, it may display somewhere, crash somewhere, or be usable only if injected into a Pokemon’s moves. Legality did not follow automatically from existence.

This is also why test strategy differs between the two architectures. In Showdown, a test can often load a mod, create a battle, request a move, and assert behavior through simulator APIs. The pokemon-showdown/test module is identified in the packet as a recurring course module around assert, battle, species, moves, and common test infrastructure. That testing style matches a simulator with explicit battle construction. In FireRed, verification often requires tracing from data table to callback or script to visible behavior. Earlier in the course, we practiced “data table to callback to visible behavior” tracing. This week, we are applying the same technique to legality boundaries.

So, for your notes, I would phrase the practical method this way. First, identify the identifier space: species, move, item, ability, trainer, map, flag, or script. Second, identify the data tables that define static properties. Third, identify the access path that would expose that data to the player or battle engine. Fourth, identify the state variables and mode flags that can block or alter that path. Fifth, distinguish representability from obtainability and usability.

Representability means the program has a way to store or name the thing. Obtainability means normal game routes can produce it. Usability means a current subsystem can act on it. Competitive legality, when we talk about Showdown, is another layer: the format permits it. These terms are not interchangeable.

Let me give one last example before we move forward. Consider an item during battle. The item ID may be representable in the Bag. It may be obtainable through a script, pickup table, mart, hidden item, or save data. But battle usability depends on the item menu path, the current battle type, the item’s effect, and whether the battle controller accepts that action. The source packet’s pokefirered/src/battle_setup.c chunk_494d132a59422c85 shows how battle setup sits near overworld, item, script, event data, Pokemon, and battle transition includes. It is a crossing point. Once you enter battle, the legal surface changes. The Bag is not just “the Bag” anymore; it is a battle menu filtered by battle context.

And this should remind you of our prior work on save and link systems without requiring us to reopen them. Save data can preserve a party or Bag state, but save validity is not the same thing as battle legality. Link code can synchronize participants, but link state is not the same thing as species legality. Those systems are foundations. Today’s point is how data becomes allowed behavior only when a particular subsystem admits it.

So as we continue, keep this mental model active: Showdown teaches us to make filters explicit. FireRed teaches us to find filters in pathways. When you compare them, do not flatten one into the other. Ask what data exists, what layer reads it, what state controls that reading, and what player-visible behavior results. That is the discipline that will make the week 22 homework much stronger than a simple list of files.

Now, let’s push that model one level further. If I ask, “Where is legality implemented?” the wrong advanced answer is, “In the data.” The better answer is, “Legality is implemented where data is admitted into a runtime pathway.” That distinction matters because a move table, by itself, does not know whether the move can appear on a wild Pokémon, a trainer Pokémon, a level-up learnset, a TM, an egg move chain, a move relearner list, or a battle command menu. The same move identifier can be legal in one pathway and impossible in another.

So, on the board, I’m writing three columns: “data exists,” “data is reachable,” and “data is permitted.” Those are not synonyms. In FireRed, data existence often means a constant exists, a table slot exists, or a struct field can store a value. Reachability means some code path can find that value. Permission means the current game state, species, context, and subsystem allow it to become visible behavior.

Take moves. FireRed has constants for moves, and battle code includes move constants throughout its utility layer. The research packet points us to pokefirered/src/battle_util.c, chunk_9335e5727aa0657d, where the file includes constants/moves.h along with constants for items, abilities, Pokémon, hold effects, and battle move effects. That inclusion pattern is architecturally revealing. Battle utility code is not treating moves as isolated strings or loose names. It is operating against compile-time identifiers that connect move IDs to effects, abilities, items, and battle state. But that still does not answer whether a particular Charizard can know a particular move. It only tells us that the battle subsystem has vocabulary for moves and effects.

Now compare that to Showdown. In pokemon-showdown/sim/DEX.md, chunk_922688d7428150d1, the Dex is described as the battle data facade, and move lookup is one of the central examples. You ask the Dex for a move record; you do not hand-scan a C array. In pokemon-showdown/sim/DEX.md, chunk_74ee605430e5596f, the APIs for moves, species, abilities, and items are treated as lookup surfaces. That is a very different architectural shape from FireRed, but it is trying to solve a related problem: how does a runtime system obtain normalized battle data without every caller knowing the storage layout?

Here is the advanced comparison. Showdown centralizes lookup through a facade. FireRed distributes lookup through C tables, constants, and subsystem-specific code paths. So, when Showdown says, in effect, “use the Dex to get the move,” the next legality question becomes, “Which mod’s Dex, and which filters?” In FireRed, when code reads move-related data, the next legality question becomes, “Which table did this pathway read, and what state allowed that pathway to run?”

Let me make that concrete. Suppose we are considering whether a Pokémon can use Thunderbolt. There are several different questions hiding inside that sentence. Can the battle engine execute Thunderbolt if a battler’s move slot contains that move ID? That is one question. Can a party Pokémon currently have Thunderbolt in its four moves? That is another. Can a species learn Thunderbolt by level-up? Another. By TM? Another. Can the move relearner show it? Another. Can an NPC trainer’s party be authored with it? Another. Can a save file contain it? Another. Those are not interchangeable legality checks.

This is where I want you to slow down during the week 22 homework. If your answer says, “moves are in the move table,” you have not yet answered the architectural question. You have identified existence. You have not identified admission. I want file, struct, function, constant, table, and state variable, but I also want the pathway. What reads it? When? Under what callback or task or script? What is the player-visible result?

Now, look at FireRed’s move relearner as a clean example of legality as a pathway. The packet gives us pokefirered/src/learn_move.c, chunk_af3598df6f092723. The excerpt explicitly identifies a “Move relearner state machine,” with CB2_MoveRelearner_Init and MoveRelearnerStateMachine states, including menu behavior and input handling. That is not just UI. That is a legality surface. The move relearner’s visible list is not “all moves that exist.” It is a list produced by a subsystem with its own state machine, menu state, scroll position, and selected Pokémon context. So the player’s experience of legality is: this menu either offers the move or it does not. The table may exist elsewhere, the constant may exist globally, but the permission is expressed by this particular state machine deciding what list to build and how to respond to input.

Check for understanding here. If I say, “FireRed has a move constant for a move, therefore the move is legal for a species,” what is wrong with that statement? Right, it confuses representability with legality. A value can be representable in memory and still not be admitted by any normal acquisition path. And now the harder follow-up: if I say, “The battle engine can execute a move, therefore the Pokémon can legally learn it,” what is wrong there? Same category error, but across subsystems. Battle execution legality and learnset legality are different filters over overlapping data.

Showdown makes this easier to name because the source materials explicitly warn us that data requires filtering. The source focus includes pokemon-showdown/sim/NONSTANDARD.md, chunk_800f1eafbea0ed7c, whose key lesson for us is that all data requires filtering. That is exactly the phrase I want in your head, but translated carefully into FireRed terms. Showdown may have many records in a data universe: modern moves, past generation moves, unreleased data, event-only data, format-restricted data, and so on. The simulator cannot merely ask, “Does this object exist?” It must ask whether this object belongs in the chosen ruleset or generation mod.

And that brings us to mods. In pokemon-showdown/sim/DEX.md, chunk_5fbe60392b5eedf9, generation-specific data is handled through Dex.mod. Architecturally, that is a very explicit answer to the problem of historical variation. You do not have one timeless move universe. You have a modded view of data. Gen 3, Gen 4, Gen 9, custom mods, DLC-specific data: each can expose a different effective data surface. That means legality is not only a property of the object; it is a property of the object under a selected data view.

FireRed does not have Dex.mod in that sense. It is a fixed Gen 3-era GBA game with compiled data and routines. But do not mistake “fixed” for “no filters.” FireRed’s filters are often embedded in which subsystem is currently active. Battle setup reads one set of inputs. The party menu reads another. The field script engine reads another. The move relearner reads another. The save system preserves state, but as we said, save validity is not battle legality. The link system synchronizes participants, but link state is not species legality. We carry those earlier weeks forward as foundations, not as the answer to today’s question.

Let’s use battle entry as the second example. In pokefirered/src/battle_setup.c, chunk_494d132a59422c85, the includes tell us the battle setup layer sits at a crossroads: task, overworld, item, Pokémon, load_save, safari zone, quest log, script, event data, event object movement, metatile behavior, field control, avatar, field effects, message boxes, Vs. Seeker, battle transition, and battle constants. That is not random header clutter. It tells us battle setup is an admission boundary between the field world and the battle world. A wild encounter, trainer battle, scripted battle, Safari encounter, or special transition is not created merely because species data exists. It is created because the overworld state, event/script state, encounter conditions, and battle setup functions agree to transfer control into battle.

So if we ask, “Is this species legal as a wild encounter here?” we do not answer by opening only the base stats table. We need the map encounter data and the battle setup path that consumes it. If we ask, “Is this trainer’s Pokémon legal?” we need trainer party data and the path that loads trainer parties. If we ask, “Can the battle engine render this species once loaded?” that is again a different question, involving species constants, graphics, palettes, battle assets, and controller flow. The filters are layered.

Now I’m going to write a small sentence on the board: “A legality claim names a context.” Please copy that exactly. A legality claim names a context. Without context, “legal” is an under-specified word. Legal in the save file? Legal in a link battle? Legal in a cartridge-authored trainer party? Legal through level-up? Legal in a modern simulator format? Legal in a Gen 9 DLC learnset file? Each one is a different claim.

This is why the modern learnsets file in the packet is useful but dangerous. The source focus names pokemon-showdown/data/mods/gen9dlc1/learnsets.ts as a high-signal modern learnset file, but it also says it is a secondary source-use note and not FireRed behavior. That caveat is essential. You can use it to study how a mature simulator models learnsets as data, especially under generation-specific mods. You cannot use it to infer FireRed learn legality directly. If you cite it in the homework, I want you to say what it is doing for your argument. Is it a comparison point? A modeling reference? A warning that learnsets are data-rich and generation-specific? Fine. But it is not evidence that FireRed’s move acquisition behaves the same way.

The same caution applies to pokemon-showdown/data/moves.ts, chunk_012eada95ff7aa5f, which the packet identifies as secondary move data. Showdown move records contain rich effect data for the simulator. FireRed move behavior is distributed across constants, battle move data, effect scripts, battle utility functions, animation tables, messages, and controller behavior. So when you compare them, the question is not, “Which one is correct?” They are correct for different runtime architectures. The comparison is useful because Showdown makes the data facade and filters explicit, while FireRed forces you to trace the pathway through compiled tables and state machines.

Let’s pause for a quick oral check. Suppose your lookup script for the lab loads a Showdown generation mod and prints a move, a species, an ability, and an item. Then it filters out nonstandard records. What have you demonstrated? You have demonstrated a facade-based, generation-aware data query with an explicit nonstandard filter. Now, what have you not demonstrated? You have not demonstrated how FireRed’s battle setup, move relearner, trainer parties, wild encounters, or save state admit those records. That distinction should appear in your lab writeup. The script is not a FireRed clone. It is a contrast instrument.

And yes, this is why we are doing Showdown in weeks 22 through 24, after the FireRed architecture has already been built up. If we had started here in week 2, you might have learned the simulator interface and then projected it backward onto the GBA game. But now you have enough FireRed structure to resist that. You know callbacks. You know tasks. You know map headers and object events. You know scripts and save blocks and link state. You know battle entry is not just “call battle.” So Showdown becomes useful as a mirror. It helps us name abstractions that FireRed implements in a more distributed way.

Now let’s bring abilities and items into the same pattern. The packet includes pokemon-showdown/data/abilities.ts, chunk_da22cf969179258c. The excerpt describes ratings for abilities, from detrimental to metagame-defining. That rating field is a beautiful reminder that simulator data often contains analysis-support metadata in addition to raw mechanical behavior. A competitive simulator and team builder benefit from knowing that an ability is generally useful, niche, or format-defining. FireRed’s runtime does not need that rating to execute a battle. So if you map Showdown ability records onto FireRed ability constants, be careful. Some fields are mechanical. Some fields are simulator convenience. Some fields are competitive metadata. FireRed’s ability legality asks different questions: can this species have this ability slot, does the battler state contain it, does battle utility code check it, and does the effect apply under current battle conditions?

In pokefirered/src/battle_util.c, chunk_9335e5727aa0657d, the inclusion of constants/abilities.h alongside battle AI, battle scripts, items, weather, and move effects shows that abilities participate in cross-cutting battle logic. But again, battle logic recognizing an ability is not the same as every species being allowed to have it. The species data path and the battle effect path meet at runtime, but they are separate sources of legality.

For items, the story is similar. Showdown exposes items through a Dex API according to pokemon-showdown/sim/DEX.md, chunk_74ee605430e5596f. FireRed has item constants and item behavior pathways, but a held item’s legality is not answered merely by its existence. Can it be in the Bag? Can it be held? Can it be used in the field? Can it be used in battle? Can it be purchased? Can it be found on a map object? Can it be attached to a traded Pokémon? These are pathway-specific filters. The item table gives the vocabulary. The subsystems give permission.

Now, let me give you a concrete example that connects several weeks. Imagine a student modifying FireRed to add a new species and a new move. They add constants. They add a move record. They add some battle behavior. Then they test by forcing the move into a party Pokémon’s move slot in memory, enter battle, and the move executes. They conclude, “The move is implemented and legal.” What should you say in review?

You should say, “You have demonstrated battle executability, not acquisition legality.” Then you would ask: did you add the move to any level-up learnset? Did you add it to TM compatibility if that is intended? Did you update move relearner behavior if the move should be recoverable? Did you update trainer party authoring if NPCs should use it? Did you update text, animation, contest or summary data if relevant? Did you verify the pathway from data table to callback or task to visible behavior? And if the species is involved, did you update base data, graphics, cries, evolution data, wild encounters, Pokédex data, and any constraints around party creation? That is architecture thinking.

Notice the phrasing. We are not saying a forced memory test is useless. It is very useful for isolating battle execution. But it is not a legality test. In the same way, a Showdown Dex lookup is useful for verifying a normalized move record, but it is not by itself a format legality test unless you also apply the selected mod and filters. That symmetry is the point of today’s lecture.

I want to connect this to the phrase “learnsets as secondary modeling reference.” Learnsets are especially tempting because they look like a direct answer to legality. If a species has a learnset entry, then surely that tells us what it can learn. But even there, you must ask, “Under what generation, what method, what event assumptions, what format, and what simulator conventions?” Showdown learnsets are engineered for simulator and validation needs. FireRed’s learn data is engineered for a specific cartridge’s runtime. The move relearner state machine in pokefirered/src/learn_move.c, chunk_af3598df6f092723, gives us a FireRed-side reminder that learning is not just static data; it is also a menu flow, a script entry point, a selected party member, and a state machine.

Let’s do another check. I’ll state three claims, and you decide whether each is an existence claim, a reachability claim, or a permission claim. First: “MOVE_THUNDERBOLT has a constant.” Existence. Second: “The move relearner menu can display Thunderbolt for this selected Pokémon.” That is reachability plus permission in a specific subsystem, and we would need the exact data path to prove it. Third: “A Gen 9 Showdown mod lookup returns a Thunderbolt move object.” That is reachability through a facade under a selected mod; it is not automatically species legality. Good.

Now, why does this matter for the course plan? Because week 22 is not just about Showdown trivia. It is training you to compare architecture without losing system boundaries. Week 23 and week 24 will ask you to use comparison and verification more aggressively. If you cannot distinguish “data exists” from “data is legal in this context,” your tests will be shallow. You will write scripts that print records and call that validation. Or you will patch C tables and call that gameplay. The advanced move is to make each claim precise enough that a test can falsify it.

For FireRed, a falsifiable legality claim might be: “Given this species and level, this level-up move appears when the level-up learn routine is reached.” Another might be: “Given this map encounter slot and player state, battle setup can instantiate this wild species.” Another might be: “Given this party Pokémon and move relearner entry point, the menu includes these moves and no others.” Each claim points to files, tables, functions, state, and player-visible results. For Showdown, a falsifiable claim might be: “Under this Dex.mod generation, this move lookup returns this effective data, and the nonstandard filter excludes these records.” Different architecture, same discipline.

Let me also flag one subtle point about “nonstandard.” In Showdown, nonstandard is an explicit category that must be filtered according to the chosen use case, as emphasized by pokemon-showdown/sim/NONSTANDARD.md, chunk_800f1eafbea0ed7c. In FireRed, there may not be a field literally called nonstandard in the same way. Instead, standardness is usually implied by shipped pathways. If no normal encounter table, trainer party, gift script, item use, or learning pathway produces a thing, then the thing may be representable but not normally obtainable. That is not the same schema, but it is a similar architectural question: which data belongs to the playable surface?

This is also why hacks and mods can become messy quickly. If you add data without adding filters, you may accidentally make something reachable everywhere or nowhere. If you add a move but forget the UI text path, the battle may work but the menu may not communicate properly. If you add a species but forget a table consumed by a particular subsystem, one screen may function and another may break. FireRed’s architecture rewards complete tracing. Showdown’s architecture rewards explicit mod and validation thinking. Our course goal is to make you fluent in both, while keeping FireRed as the primary source.

So, as you prepare the lab script, write it like an architectural comparison, not a demo. Load the generation mod because pokemon-showdown/sim/DEX.md, chunk_5fbe60392b5eedf9, tells us generation-specific data belongs behind Dex.mod. Print selected moves, species, abilities, and items because pokemon-showdown/sim/DEX.md, chunk_74ee605430e5596f, identifies those lookup APIs as central surfaces. Apply nonstandard filtering because pokemon-showdown/sim/NONSTANDARD.md, chunk_800f1eafbea0ed7c, makes filtering part of responsible data use. Then, in your documentation, contrast that with FireRed’s table-and-pathway model, citing FireRed files such as pokefirered/src/battle_setup.c, chunk_494d132a59422c85, for battle admission and pokefirered/src/learn_move.c, chunk_af3598df6f092723, for move relearner state.

And when you cite pokefirered/src/battle_util.c, chunk_9335e5727aa0657d, do not merely say, “battle utilities include move constants.” Say what that proves and what it does not prove. It proves the battle utility layer is wired to the shared constant vocabulary for moves, items, abilities, species, weather, hold effects, and battle move effects. It does not prove acquisition legality. That distinction is exactly the sophistication I expect at this point in the course.

We will continue from here by looking more closely at how a legality boundary can be documented as a trace. The trace is going to start with a record or identifier, then pass through the lookup or table access, then through the state that chooses the subsystem path, and finally into visible behavior. Keep your three columns visible: data exists, data is reachable, data is permitted. Most weak architecture explanations collapse those columns. Your job now is to keep them separate long enough to say something true.

Now, let us make that trace concrete, because otherwise “legality boundary” stays too abstract.

Suppose I write a small Showdown-side script and I ask the Dex for Thunderbolt. In Showdown terms, that request goes through the Dex facade. The point of the Dex facade, as described in pokemon-showdown/sim/DEX.md chunk_922688d7428150d1, is not merely “there is a JavaScript object somewhere.” It is a lookup surface for battle data. So when I call the move lookup API, I am asking a curated interface to normalize my identifier, find the move record, and hand me something battle code can reason about. In pokemon-showdown/sim/DEX.md chunk_74ee605430e5596f, the same idea is extended across moves, species, abilities, and items. One facade, several data domains.

Now compare that to FireRed. FireRed does not have a single generalized Dex facade in the Showdown sense. It has constant vocabularies, tables, and subsystem-specific functions. If I say MOVE_THUNDERBOLT in FireRed, I am in the world of constants/moves.h, battle move data, move names, animation data, TM compatibility, learnsets, script commands, menu code, and battle utility code. The identifier can travel into many places. That does not mean every place answers the same question.

Let me put this on the board. I am drawing one row for the move identifier. First column: “record exists.” Second column: “subsystem can reference it.” Third column: “player can legally obtain it under current rules.” Those are not synonyms. The fact that a move has battle data tells us it can be executed if something in battle chooses it. The fact that a move appears in a relearner menu tells us something about move history or species-level eligibility. The fact that a TM item teaches it tells us something about inventory, party, compatibility, and menu flow. The fact that a move appears in a simulator data file tells us still another thing: that a modern engine has a record for the move in a particular mod context.

This is why I am being strict about the word “filter.” Legality is not usually an extra blob of data floating by itself. Legality is a filtering operation over data that already exists. Sometimes the filter is explicit, as in Showdown’s nonstandard handling. The source packet points us to pokemon-showdown/sim/NONSTANDARD.md chunk_800f1eafbea0ed7c for the principle that all data requires filtering. That is the cleanest formulation for this week: the database can be larger than the current legal format. You do not delete everything outside the current format; you tag, mod, filter, and query appropriately.

FireRed gives us a more distributed version of the same architectural idea. Let’s say a species exists. Let’s say a move exists. Let’s say the battle engine can execute that move. None of those statements alone means that this species can learn that move in this save file at this time. The actual answer might depend on level-up learnsets, TM/HM compatibility, tutor tables, egg moves, special event distribution, party state, item state, badge or progression flags, and the menu or script path being used. Earlier in the course, when we traced flags and save block ownership, we were building the foundation for exactly this kind of reasoning. I am not reteaching save blocks now. I am reminding you that if a condition lives in saved progression state, then legality may be a runtime question, not just a table question.

Check your understanding here. If I show you a FireRed battle utility function that includes constants for moves, abilities, items, species, weather, hold effects, and battle move effects, what can you safely conclude? You can conclude that the battle utility layer speaks the shared vocabulary. The source packet gives us pokefirered/src/battle_util.c chunk_9335e5727aa0657d for exactly that wiring: includes for battle, Pokemon, constants/moves.h, constants/items.h, constants/abilities.h, constants/pokemon.h, constants/hold_effects.h, and constants/battle_move_effects.h. But you cannot conclude that every combination of those identifiers is legal for acquisition. The battle layer must be prepared to evaluate effects once battle state exists. It is not the sole authority for how the party acquired that state.

Let’s make the example sharper. Imagine a player’s Charizard knows Surf. In a hacked save, or a debug setup, or a test harness, that state might be present. The battle engine’s first job is not to ask, “Was this Charizard produced by a legal acquisition path?” Its first job is to run a battle using the party data it has been given. So if the move slot contains a valid move identifier, the battle engine may be able to display the move, check PP, select a target, and execute an effect path. That is “data is reachable.” But if we are writing a legality checker, we need a different trace. We ask: does the species permit this move by level, TM, tutor, egg inheritance, or event under the target ruleset? That trace is not identical to the battle execution trace.

Showdown makes this distinction easier to see because it has a deliberate mod system. pokemon-showdown/sim/DEX.md chunk_5fbe60392b5eedf9 discusses Dex.mod as a way to access generation-specific data. So “Pikachu” is not a free-floating universal object. The record you get depends on the generation mod you ask for. The same named thing can have different availability, mechanics, or surrounding rule interpretation depending on the mod. That is why this week’s lab asks you to load a generation mod and print selected move and species records. You are not doing that just to become familiar with a library call. You are practicing the habit of saying, “Under which data view am I asking this question?”

FireRed’s equivalent is not Dex.mod. FireRed is one compiled game with static tables and runtime state. But architecturally we can still ask the same question: “Under which ruleset or subsystem path is this identifier being interpreted?” The move relearner is a good example. The packet points us to pokefirered/src/learn_move.c chunk_af3598df6f092723, where the file itself documents a move relearner state machine, with CB2_MoveRelearner_Init and MoveRelearnerStateMachine states for menu behavior. That is not a battle execution path. It is a UI and eligibility path. A move appearing there means the relearner flow has decided to present it, based on its own data and state. So if you cite learn_move.c to support a claim about move acquisition, your claim should be about the move relearner interface and state machine, not about damage calculation or battle effect execution.

Notice the precision I am asking for. Do not say, “FireRed stores moves in constants.” That is too vague. Say: “The move identifier is defined in the shared constants vocabulary, battle utility code includes that vocabulary when resolving battle behavior, and separate menu or script subsystems use other data and state to determine whether that move can be acquired or displayed.” That sentence is longer, but it is true.

Now, slide cue, look at the Showdown side again. The packet names pokemon-showdown/data/moves.ts chunk_012eada95ff7aa5f as a source for secondary move data. A move record there can include much more than a name and base power. It can describe secondary effects, flags, targeting, type, category, accuracy, and whatever the simulator needs to model battle behavior. That is high-value modeling data. But it is not automatically a legal learn path. A learnset file is a different kind of evidence. A learnset says, in effect, “here are routes by which this species can receive this move under these data rules.” And even there, because Showdown is cross-generation and format-aware, you still have to filter.

This is the subtle point: learnsets are closer to legality than move data, but they are still not the whole legality story. A learnset can tell you that a move is associated with a species. A format can still ban the species, ban the move, ban a combination, reject nonstandard data, or apply generation-specific constraints. That is why NONSTANDARD.md matters this week. It trains you to avoid treating the raw database as the legal universe.

In FireRed terms, think of battle setup as the bridge between world state and battle state. The packet gives us pokefirered/src/battle_setup.c chunk_494d132a59422c85, whose includes show it sitting at a crowded boundary: task, overworld, item, Pokemon, load_save, safari_zone, quest_log, script, event_data, battle, battle_transition, and trainer-related constants. That file is not merely “battle.” It is the handoff point from overworld conditions and event/script state into the battle system. If you are tracing whether an encounter can happen, battle_setup.c is much more relevant than a pure move-effect function. But if you are tracing whether a move’s secondary effect can apply after it is selected, battle_util.c is more relevant.

So the method is: name the question before naming the file. If the question is “Does the data record exist?” Showdown Dex lookup or FireRed static tables are plausible evidence. If the question is “Does this generation view expose this record with these properties?” Showdown Dex.mod is plausible evidence. If the question is “Can this move be executed in battle?” battle utility and battle script paths matter. If the question is “Can the player acquire this move through a menu?” learn_move.c, item-use flows, tutor scripts, and compatibility tables matter. If the question is “Can this state persist?” then saved party state and load-save foundations matter. You see how the file list changes with the question.

Let me ask a check-for-understanding question. Suppose your homework answer says, “Mew is in the species constants, therefore Mew is legal.” What is wrong with that? Take ten seconds.

The error is that existence has been confused with legality. A species identifier can exist so the engine can display it, battle with it, trade it, store it, or support special cases. But legality asks whether the player can obtain it under the ruleset being evaluated. That may involve event distribution, map scripts, encounter tables, gift scripts, trade scripts, or external distribution mechanisms. In Showdown, it may involve standardness flags and format filters. In FireRed, it may involve what the shipped game exposes through maps, scripts, items, and progression state. Same principle, different implementation shape.

Now let us tie that back to the broader architecture course. In week one, we decomposed the creature RPG into runtime shell, overworld maps, event scripting, creature data, battle, inventory, UI, save, and link systems. At the time, that decomposition probably felt like a map of modules. By week twenty-two, it should feel like a map of evidence types. If I am making a claim about legality, I need to know which system owns the relevant evidence. The runtime shell tells me when callbacks run. The task system tells me how per-frame state machines advance. The map system tells me what object events and scripts are reachable. The creature data system tells me what records exist. The battle system tells me what happens when combat state is formed. The inventory system tells me what item-mediated transformations are possible. The save system tells me what persists. The link system tells me which states can be exchanged or synchronized. Legality is often the intersection of several of those systems, not a single table.

This is also why the lab for this week is intentionally Showdown-side. We are not replacing FireRed with Showdown. We are borrowing a clearer modern vocabulary. When you write a script that loads a generation mod, prints a move, prints a species, checks nonstandard status, and then writes down how this differs from FireRed static tables, you are practicing source separation. Showdown has a facade and mods. FireRed has compiled tables and subsystem-specific access. Showdown can ask, “What does this mod’s Dex say?” FireRed more often asks, “Which table, constant, callback, task, script, or global state is this subsystem using right now?”

Let’s do one more concrete trace verbally. We start with an item, say a TM item. In the “data exists” column, the item identifier exists in the item constants and item data. In the “reachable” column, the bag menu can show it if the save state says the player owns it. The item-use code can route to a party selection interface. The party selection interface can inspect a party Pokemon. A compatibility check can decide whether the chosen Pokemon may learn the move. Then a move-learning flow can decide whether there is an empty slot or whether the player must forget an existing move. Only at the end does the party data actually change. Later, battle code reads that changed party data and treats the new move as part of the combat state. If you collapse all of that into “the move is in the game,” you have lost the architecture.

And the same trace gives you test strategy. A data existence test might assert that a record can be looked up. A legality test might assert that the record is filtered out under a particular ruleset. A UI integration test might assert that the option appears or does not appear in the menu under a given save state. A battle test might assert that once the move is present, its battle effect resolves correctly. These tests are not interchangeable. Passing one does not imply passing the others.

Recap that in your notes as a sentence, not as a diagram only: legality is a question asked by a rule context over a larger data universe. The larger data universe is necessary, because engines need to represent things beyond the currently permitted set. But the larger data universe is dangerous if you mistake it for permission.

We will continue by applying this directly to learnsets, because learnsets tempt people into a second kind of overclaim. They are much better evidence than raw move data, but they are still evidence inside a rule context. So as we go forward, keep the board columns visible: data exists, data is reachable, data is permitted. Then add one more small note underneath them: “permitted by whom, under what generation, through what path?” That little question is what separates an advanced architecture explanation from a list of filenames.

Now, when we turn to learnsets, the first discipline is to stop using the word “can” too loosely. A species “can learn Thunderbolt” is not a single architectural statement. It could mean the move appears in a learnset table. It could mean the move is obtainable in this generation. It could mean the move is obtainable in this cartridge. It could mean the move is legal in a competitive format. It could mean the current runtime menu will offer it to this particular party member right now. Those are different claims, and mature engine reading keeps them separated.

Let me say that again in the form I want you to use in your lab writeup: learnset membership is not legality by itself. Learnset membership is evidence that a later legality filter may use.

So, imagine I draw a species record on the board. I write “species,” then under it I write base stats, types, abilities, forms, evolutions, and learnset reference. In FireRed, that conceptual species record is not necessarily one unified object the way a modern simulator-facing API would present it. The data is distributed across C tables, constants, and helper functions. In Showdown, by contrast, the Dex facade is intentionally built to make this feel unified. That is why the DEX.md material matters this week. The Dex is not just a folder full of JSON-like records. The Dex is a lookup surface. The packet calls out pokemon-showdown/sim/DEX.md chunk_922688d7428150d1 for the Dex purpose and move lookup, chunk_5fbe60392b5eedf9 for Dex.mod generation-specific data, and chunk_74ee605430e5596f for the moves, species, abilities, and items APIs. Those three chunks together are the architecture point: the simulator wants a stable question-asking interface over versioned data.

FireRed’s architecture asks many of the same questions, but it answers them through compile-time tables, constants, state variables, and procedural code paths. So if a student says, “FireRed has no Dex object, therefore it has no Dex abstraction,” that is too shallow. FireRed does not have Showdown’s Dex facade as a single runtime service. But it absolutely has a set of table-and-function boundaries that answer Dex-like questions: what is this species, what moves exist, what item exists, what ability number means what, what battle effect should this move invoke, what string should be shown, what menu options should be reachable, and what state is the player currently in?

Now, look at the board columns again: data exists, data is reachable, data is permitted. I am going to add a fourth column for today’s last stretch: data is usable here. That last phrase is intentionally local. Usable in a battle turn? Usable in a move relearner menu? Usable in a link battle? Usable in a save file imported from another context? Usable in a validator for a modern competitive ruleset? Every one of those asks a different question.

A concrete example. Suppose we are reasoning about a move. In Showdown, the move lookup path is naturally phrased as something like “ask the Dex for the move record.” DEX.md, especially pokemon-showdown/sim/DEX.md chunk_922688d7428150d1 and chunk_74ee605430e5596f, supports that as the surface: moves, species, abilities, and items are accessed through APIs. The returned record may include battle-facing properties, text-facing properties elsewhere, and flags that matter to simulation. But then the NONSTANDARD.md material, pokemon-showdown/sim/NONSTANDARD.md chunk_800f1eafbea0ed7c, gives us the warning we have been building toward: all data requires filtering. If your script prints every move returned by a data table, you have not printed “the legal move list.” You have printed a larger universe, some of which may be nonstandard, past-generation-only, future-only, event-only, CAP, custom mod content, or otherwise outside the rule context you meant.

In FireRed, the analogous mistake looks a little different. A student opens constants/moves.h, sees a move constant, and says, “This move is in FireRed.” That is only partially true. The constant may exist because the engine needs a numeric identity. Then the move may have a record in the move data table. Then battle code may know how to execute its effect. But that still does not mean a wild Pokémon in FireRed can learn it, or that the player can obtain it through leveling, TM, tutor, breeding, event, or relearner. And it certainly does not mean a particular menu will expose it at a particular moment.

That distinction is visible in the FireRed source focus from the packet. pokefirered/src/battle_util.c chunk_9335e5727aa0657d includes battle-facing headers and constants: battle, moves, items, abilities, weather, hold effects, and battle move effects. That is a strong signal about where move identity becomes battle behavior. But pokefirered/src/learn_move.c chunk_af3598df6f092723 is a very different kind of source. The packet excerpt explicitly labels a “Move relearner state machine,” beginning with CB2_MoveRelearner_Init and then a MoveRelearnerStateMachine with menu states. So if we ask “can this Pokémon get this move from the relearner,” battle_util.c is not the right authority by itself. We need the move-relearning path, its state machine, its list construction, and the species or party data it consults.

Check for understanding here. If I hand you a move ID and a species ID, and I ask, “Is this legal?” what is the first answer? The first answer is not yes or no. The first answer is “in what context?” Good. If the context is “can the battle engine execute this move once it appears in a moveslot,” you trace battle data and battle scripts. If the context is “can the player teach it through a menu,” you trace item, TM, tutor, or relearner code. If the context is “can a Showdown team validator accept it in Gen 9 DLC 1,” you load the correct Dex mod and apply the correct legality filter.

This is also why learnsets are a secondary modeling reference, not a replacement for cartridge behavior. The packet names pokemon-showdown/data/mods/gen9dlc1/learnsets.ts as a high-signal modern learnset file, and I want you to use it in the lab. But do not write that file into your notes as if it teaches FireRed behavior. It teaches a modern data modeling pattern. It is useful because it forces us to think about learn methods, generations, and rule context. It is not useful as direct evidence for FireRed’s runtime behavior. FireRed’s move acquisition paths are anchored in its own source and data tables.

Let’s do a board-work pass through the four claims.

First, “data exists.” In Showdown, the data exists if the relevant data module contains the record and the Dex can resolve it. Move data from pokemon-showdown/data/moves.ts chunk_012eada95ff7aa5f gives us secondary move data, and the abilities example in pokemon-showdown/data/abilities.ts chunk_da22cf969179258c shows that Showdown data may include simulator-supporting metadata like ability ratings. Those ratings are not Game Boy Advance cartridge data. They are part of Showdown’s analysis and simulator ecosystem. That is a beautiful example of why existence inside a data file cannot be collapsed into original-game legality.

In FireRed, “data exists” may mean constants exist, table entries exist, text entries exist, graphics exist, or code paths recognize an ID. Remember our earlier course method: table to global state to callback, task, or script to visible behavior. That method still applies. A move constant is not enough. A battle effect constant is not enough. A string is not enough. You need the path.

Second, “data is reachable.” In Showdown, reachability often means “can the Dex lookup API return it from the selected mod?” DEX.md chunk_5fbe60392b5eedf9 matters because Dex.mod changes the generation-specific view. A Gen 9 lookup and a Gen 3 lookup are not morally the same lookup with a different label. The mod changes which inherited data, overrides, aliases, and rules are in view. That is why your lab script must load a generation mod explicitly. If you use the default Dex and forget the mod, your results may be technically valid for the default environment and useless for the question you thought you were asking.

In FireRed, reachability is usually procedural. Can a script reach this path? Can the overworld call into battle setup? Can the item-use callback reach the move-teaching routine? Can the relearner menu be opened by the NPC script? Can the battle setup code initiate this kind of encounter? pokefirered/src/battle_setup.c chunk_494d132a59422c85 is relevant here because the excerpt shows battle setup sitting at a junction of overworld, item, sound, Pokémon, load-save, safari, quest log, script, event data, field movement, field effects, battle transition, and battle code. That file is not “the battle engine” in the narrow damage formula sense. It is part of the reachability boundary between world state and battle state.

Third, “data is permitted.” In Showdown, this is where NONSTANDARD.md chunk_800f1eafbea0ed7c becomes central. You filter. You do not merely enumerate. A move can be in the data universe and still not be standard for the format. A species can exist as a record and still be banned, unobtainable, past-only, or outside the generation. A modern simulator must represent more than one playable context, because its job is not to be a single cartridge. That is why nonstandard flags are not an annoyance. They are part of the model.

FireRed’s permission model is more implicit. It is scattered through acquisition paths, event flags, map scripts, inventory checks, party checks, and battle rules. We have already covered save block ownership, sector validation, and load-save initialization, so I will not reteach those. But I want you to connect them forward. Save data determines what party you have, what flags are set, what items you own, and what world state is restored. Those state variables feed permission. Similarly, we have already covered RFU mode constants, link manager callback messages, VBlank timers, and link state. I am not reopening that whole unit. But link context is another permission boundary. A thing that exists in local data may be disallowed, transformed, synchronized, or interpreted differently when the multiplayer state machine is active.

Fourth, “data is usable here.” This is the most engine-specific column. In FireRed, if a Pokémon has four moves and is trying to learn a fifth, the learn-move flow has UI state. It has choices. It has cancellation. It has party data mutation. The move’s existence in battle data does not operate the menu. The move’s learnset evidence does not press A for the player. The state machine in pokefirered/src/learn_move.c chunk_af3598df6f092723 is our reminder that visible legality is often mediated by UI and callbacks. The menu is not just presentation. In a cartridge engine, menus are frequently where permission becomes action.

Now let’s take a specific teaching example, and I’ll keep it abstract enough that we do not accidentally assert the wrong species-specific fact. Say we have Species A and Move B. In a Showdown-side lookup script, you might load the Gen 9 DLC 1 mod, ask dex.species.get for Species A, ask dex.moves.get for Move B, inspect the move’s existence and nonstandard status, then inspect learnsets. If the move exists but has a nonstandard flag, your script should document that the record is present but filtered out for standard play. If the learnset says Species A has a path to Move B, you still ask what kind of path and which generation it belongs to. Then, if you are validating a format, you ask whether that format permits transfer moves, event moves, past-generation methods, or only current-generation acquisition.

The equivalent FireRed investigation does not begin with “load a mod.” It begins with constants and tables, then runtime entry points. You identify the species constant. You identify the move constant. You identify the move data table and effect constants. You inspect the acquisition path: level-up learnset, TM/HM compatibility, tutor, breeding, event, or relearner. Then you inspect the function that consumes that path. If it is battle use, you go toward battle utility and battle scripts, with pokefirered/src/battle_util.c chunk_9335e5727aa0657d as one supporting source for the density of battle constants and includes. If it is battle entry, you go toward battle setup, with pokefirered/src/battle_setup.c chunk_494d132a59422c85. If it is relearning, you go toward learn_move.c chunk_af3598df6f092723. Same conceptual question, different architecture.

Pause there. Does everybody see why “Showdown is cleaner” is not the right conclusion? Showdown is cleaner for certain classes of query because it is designed as a simulator and data facade. FireRed is not worse architecture because it lacks that facade. It is architecture under different constraints: fixed ROM data, GBA memory limits, C compilation, callbacks, tasks, script systems, and tightly coupled UI flows. The advanced comparison is not “modern TypeScript good, old C bad.” The advanced comparison is “which boundary has been made explicit, and which boundary is encoded in control flow?”

This is where week 22 connects to the whole course plan. In weeks 1 and 2, we emphasized the runtime shell: AgbMain, main callbacks, SetMainCallback2, task creation, and RunTasks. We used those to understand how visible behavior happens frame by frame. Later, with maps and scripts, we treated map headers, layout references, object events, and script commands as data that become behavior only when the engine reaches them. With save and link systems, we studied persistence and communication state machines. Now, in week 22, Showdown gives us a contrast case: a high-level Dex interface over battle data. But the same course habit remains: never stop at the table. Ask who reads it, when, under what state, and with what filter.

Let me give you the sentence I would expect on a strong quiz answer. “In Showdown, legality is modeled as a filter over a broad Dex data universe, with generation mods and nonstandard metadata shaping the view; in FireRed, comparable legality boundaries are distributed across constants, data tables, event flags, item and party state, callback-driven menus, and battle setup or battle execution functions.” That sentence earns credit because it names both sides and refuses to flatten them.

A weaker answer would say, “Showdown has learnsets and FireRed has learnsets.” That is true in the least useful way. A stronger answer says, “A learnset is a modeling reference, but permission is decided by the acquisition and validation context.” Stronger still: “In a cartridge, acquisition context is often a runtime path through scripts, menus, and party mutation; in Showdown, acquisition context is often represented for validation by data plus format rules.” That is the level you are now responsible for.

Let’s also talk about abilities and items for a moment, because they expose the same boundary. Showdown’s DEX.md chunk_74ee605430e5596f explicitly belongs in our discussion because the Dex APIs cover moves, species, abilities, and items. The data/abilities.ts excerpt, pokemon-showdown/data/abilities.ts chunk_da22cf969179258c, includes ratings. Those ratings are not legality. They are simulator metagame metadata. If your program filters by rating, you are not validating legality; you are making a usefulness or AI-style decision. FireRed has ability constants and battle code that interprets abilities, but it does not have Showdown’s ability-rating layer. So when you compare systems, distinguish identity, behavior, availability, and evaluation. A move can have identity and behavior. A species can have identity and base properties. An item can have identity and field or battle effects. An ability can have identity and battle hooks. None of those alone answers “is this legal here?”

Now, for the lab, your script should demonstrate that distinction in miniature. It should load a generation mod, print selected move and species records, filter nonstandard data, and then document how this differs from FireRed static tables. I do not want a giant validator. I want a small, honest instrument. Print enough fields to show that the Dex lookup is a facade. Show at least one case where existence and standardness are different questions. Then write a note that says, in plain language, “FireRed would require tracing constants and acquisition paths through source modules rather than calling one Dex API.” That note is not decorative. That note is the learning objective.

Here is a quick check. If your Showdown script loads a move and sees that it exists, can it immediately conclude that every species with that move in some historical learnset may use it in the selected format? No. Why not? Because the selected generation, format rules, nonstandard flags, transfer policy, and learn method matter. If your FireRed source reading finds a move effect implemented in battle code, can it immediately conclude that the move is obtainable by the player? No. Why not? Because battle execution and player acquisition are separate paths. Good. That is the core.

Let’s recap the major systems in the language of this course. Runtime shell: callbacks and tasks decide when code runs. Overworld and maps: headers, layouts, object events, and scripts decide what world interactions can be reached. Event scripting and flags: progression state decides which branches are open. Creature data: species, moves, abilities, party structures, and constants define identities and properties. Battle: setup moves from world state into battle state, while battle utility and scripts execute effects. Inventory and UI: item possession and menu state decide what actions the player can invoke. Save: persisted state restores the conditions under which those permissions are evaluated. Link: communication state constrains what local assumptions can safely become multiplayer behavior. Showdown comparison: Dex, mods, nonstandard filtering, and learnsets show a modern facade and validation-oriented version of the same architectural problem.

So when I say “legality is a filter over data,” I do not mean legality is simple. I mean the opposite. I mean data is deliberately larger than any one legal context. Engines need names for things that are not currently obtainable. Simulators need records for past generations, alternate formats, custom mods, and nonstandard content. Cartridge code needs constants, tables, and handlers for behavior that may only be reached through narrow paths. The architectural skill is to locate the filter and name the context.

And that gives us our closing synthesis for today. FireRed teaches us how a creature RPG can be built from static tables, global state, callbacks, tasks, scripts, and specialized UI flows. Showdown teaches us how a simulator can wrap a broad data universe in a Dex facade, generation mods, and explicit filtering. Neither model lets us treat “present in data” as “permitted in play.” For an advanced reader, the real question is always more precise: permitted by which rule system, in which generation, through which acquisition path, under which runtime state, and consumed by which function? Carry that question into the lab, because it is the difference between reading files and understanding architecture.

## Source References
- pokefirered/src/battle_util.c
- pokefirered/src/battle_setup.c
- pokemon-showdown/data/abilities.ts
- pokemon-showdown/data/mods/biomechmons/scripts.ts
- pokefirered/src/learn_move.c
- pokemon-showdown/data/text/moves.ts
