# Tiles as Runtime Queries

Lecture ID: lecture_w05_d01
Week 5, Day 1

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

## Transcript
All right, let’s pick up from where we left the overworld last time. We are not restarting the map system today. We already did the map header. We already did the layout registry reference. We already traced how a warp destination becomes a loaded map under the overworld callback. Today I want you to mentally step one layer downward. Not “what map am I in?” and not “which object events are defined for this town?” but “when the player tries to step one tile north, what question does the runtime ask of the map?”

That is the key phrase for today: tiles as runtime queries.

Notice I did not say “tiles as art.” In a creature RPG, especially one in the FireRed family, a tile is certainly drawn. It has pixels. It belongs to a tileset. It contributes to the visual scene. But for gameplay architecture, the more important fact is that a tile answers questions. Can the player stand here? Is this water? Is this tall grass? Is this a ledge? Is this a door-like metatile? Is this something that should trigger surf logic, bike logic, encounter logic, or object movement rejection? So the tile is not just a static square in a map editor. At runtime it becomes a query target.

Let me put that on the board. Imagine I draw a small grid, five by five. In the center I put the player. North of the player I draw a dark block, east I draw tall grass, south I draw a normal path, west I draw water. If we were only building a renderer, each of those cells might just say, “draw image index 37,” “draw image index 82,” and so on. But in FireRed architecture, the movement system does not only need a picture index. It needs a semantic answer. The north cell says, “blocked.” The east cell says, “walkable, but grass behavior.” The south cell says, “walkable floor.” The west cell says, “water; maybe blocked unless the avatar is surfing or can initiate surf.” That is the difference between a tile image and a tile behavior query.

In the source focus for this week, that is why we care about pokefirered/src/fieldmap.c, especially the runtime support chunk, pokefirered/src/fieldmap.c chunk_642df7a31e75f54c, the map block and tile behavior flow in pokefirered/src/fieldmap.c chunk_eeb0180842f7ece9, and the helper flow in pokefirered/src/fieldmap.c chunk_77ef7f3f8bff9777. Those chunks sit underneath the more narrative systems we discussed last week. The map header says what map we are on. The layout reference says where the map’s block data comes from. The overworld callback keeps the map runtime alive. But these fieldmap routines are where the map becomes searchable by coordinate.

So, first conceptual point: the overworld engine does not want to pass around “the whole map” every time something moves. It wants narrow functions that answer narrow questions. Given x and y, what block is here? Given x and y, what metatile behavior is here? Given x and y and elevation, is movement allowed? Given a camera origin, which visible region should be drawn? This is a very old console architecture lesson, but it is also a clean software architecture lesson. You make large authored data available through small runtime accessors.

Let’s slow that down. The map as authored data is large and mixed-purpose. It includes visual composition, collision meaning, encounter zones, event references, object placements, and layout dimensions. If every subsystem rummaged directly through that data in its own way, you would get inconsistent behavior immediately. The renderer might interpret a coordinate one way, the collision system another way, and the object movement system a third way. FireRed avoids that by using fieldmap helper flow as a central layer. Again, our source focus names that helper flow directly in pokefirered/src/fieldmap.c chunk_77ef7f3f8bff9777. The exact functions are less important at this moment than the architectural contract: coordinates go in, map facts come out.

Now, a check for understanding. Suppose I ask: why not just store a Boolean collision grid, one true or false value per tile? Take ten seconds and think about that. Why would a Boolean grid be too weak for a FireRed-style creature RPG?

The answer is that “blocked” is not one universal property. A tile may be blocked for the walking player but valid for water movement. A ledge may be passable from one direction but not the other. Tall grass is walkable, but it is not semantically the same as a road, because it may participate in wild encounter checks. A counter tile may block movement but still allow interaction across it. A warp tile may be standable and also cause a transition. So if all you have is true or false, you flatten out the information the rest of the engine needs. FireRed’s style is not “tile equals obstacle or not.” It is “tile has behavior, and different systems query that behavior for their own decisions.”

This is where the phrase “metatile behavior” matters. A metatile is not only a chunk of rendered tile graphics. It is the unit that can carry gameplay semantics. The battle setup code gives us a useful cross-reference here, even though today is not a battle lecture. In pokefirered/src/battle_setup.c chunk_494d132a59422c85, the include list pulls in both metatile_behavior.h and fieldmap.h alongside overworld, event object movement, field control, and battle transition headers. That does not prove every detail of field movement by itself, but it is evidence of a broader architectural fact: battle entry, especially wild battle entry, is not isolated from the map. It depends on field state and tile semantics. The battle engine may feel like a separate world once you are in the fight, but the decision to enter that world can start with a tile query.

Now let’s make the concrete example more precise. Imagine the player is standing at coordinate x equals 10, y equals 15 on a route. The player presses right. The avatar system computes a destination coordinate, x equals 11, y equals 15. Before moving the sprite, the runtime has to ask several questions. First, what is at that coordinate in the map block data? Second, what metatile behavior is associated with that block? Third, is there an object event currently occupying that coordinate? Fourth, are movement rules modified by the player state, such as surfing, biking, scripted movement, or forced movement? Fifth, if the movement succeeds, does the resulting tile have a behavior that should trigger follow-up logic?

That sequence is why I want you to stop thinking of collision as a single function called “can move.” In a polished RPG, movement is a pipeline of queries. Some queries are geometric: is the coordinate inside the valid map region? Some are tile-based: what behavior does the metatile expose? Some are entity-based: is an object event there? Some are state-based: what kind of avatar movement mode is active? Some are event-based: after entering the tile, should something happen?

And yes, this is exactly what you need for the week five lab. Your grid map implementation should not just have a two-dimensional array of art IDs. It should support metatile lookup, collision checks, camera offset, and object-event occupancy. If your sample movement attempt says, “move north rejected because tile behavior is wall,” that is useful. If it says, “move east accepted, destination behavior is tall grass, encounter hook would be eligible,” that is more FireRed-like. If it says, “move south rejected because object occupancy blocks the destination even though the floor tile itself is walkable,” now you are modeling the right separation.

Let me connect that back to our course arc. In week one, we decomposed the game into runtime shell, overworld maps, event scripting, creature data, battle, inventory, UI, save, and link systems. In week two, we emphasized data flowing through generated sources, headers, and runtime callbacks. In weeks three and four, we moved into map records, layout references, object events, warps, and the overworld load path. Week five is where the map stops being a record and becomes an active surface. It is queried every frame, or nearly every frame, by systems that need local answers.

So if the earlier mental model was “data table to callback to visible behavior,” today’s version is “map block to metatile behavior to movement decision to visible behavior.” Same course thesis, one layer more concrete.

Now, I want to bring in Pokemon Showdown carefully, because it is useful here, but only as a comparison. FireRed is our main architecture source. Showdown is not an overworld engine. It does not solve camera-relative map drawing. It does not have GBA metatile memory constraints. But Showdown is excellent for seeing the same architectural pattern in a different domain: data is not merely read; data provides hooks that the runtime queries at decision points.

For example, in pokemon-showdown/data/mods/gen2stadium2/scripts.ts chunk_3480e574205d5d0f, the excerpted logic discusses damage calculation cases such as immunity checks, OHKO moves, fixed damage, level-based damage, and a move damage callback. That is a battle version of today’s map idea. A move is not just “base power 80.” A move can expose behavior that the simulator calls during a turn. Likewise, in pokemon-showdown/data/abilities.ts chunk_da22cf969179258c, abilities are organized as data with ratings and battle relevance, and in the broader Showdown architecture those ability records can carry effects that the simulator consults. The comparison is not “Showdown tiles are like FireRed tiles,” because Showdown does not have tiles in this sense. The comparison is “both systems use data records as runtime query surfaces.”

Let me say that again because it is subtle. FireRed asks, “what does this metatile mean for movement or field behavior?” Showdown asks, “what does this move, ability, item, species, or modded rule mean for this battle event?” In both cases, the runtime is organized around hook points. A movement attempt is a hook point. A damage calculation is a hook point. A turn transition is a hook point. A terrain or field effect update is a hook point. Advanced architecture is often about choosing those hook points well.

But there is a difference in shape. FireRed is a C codebase for fixed hardware and authored maps. Its hooks are often represented through constants, tables, helper functions, globals, and explicit control flow. Showdown, being a modern TypeScript simulator, can express many battle hooks closer to the data definition itself, especially through scripts and mod directories. That Dex/mods architecture is useful to compare later in the course when we talk about battle data and regression testing. For today, just keep the analogy in your pocket: a tile behavior query in the field is like a battle data hook in the simulator. It is a controlled question asked by the runtime at the moment a decision must be made.

Now, back to the board grid. I am going to draw the player at 10,15 again. Let’s say the destination 11,15 contains tall grass. The fieldmap layer can provide the block or behavior at that coordinate. The movement system determines the tile is not physically blocking. So the player can step into it. But after the movement completes, another system can observe the tile behavior and decide whether to run an encounter check. Notice the timing. If you run encounter logic before movement resolution, you risk triggering encounters on failed movement attempts. If you run it without asking tile behavior, you risk encounters on roads. If you bake encounter chance directly into the renderer, the design has collapsed. The clean design is: movement resolves position; tile behavior describes the ground; encounter code asks whether this behavior is eligible.

That is the principle I want you to apply in your own clone architectures. Do not make your map renderer decide collision. Do not make your collision grid decide encounter categories. Do not make your object list secretly override tile meanings without a clear query. Build a small field query interface. Then let movement, camera, encounters, and scripts use that interface.

Now let’s talk about camera-relative drawing, because this is where people often mix concerns. A camera is not the same thing as the player position. Usually the camera follows the player, yes, but the renderer needs to know which map cells correspond to the visible screen. That means it needs a camera origin or offset. If the camera’s top-left map coordinate is x equals 6, y equals 11, then the screen cell at local position 4,4 corresponds to map coordinate 10,15. So rendering is also a query problem: for each visible screen position, translate from screen-relative coordinate to map coordinate, then ask the map for the block or metatile to draw.

In FireRed’s fieldmap focus, that camera-relative map support belongs with the same family of runtime helpers. The source focus packet points us to pokefirered/src/fieldmap.c chunk_642df7a31e75f54c for fieldmap runtime support and chunk_eeb0180842f7ece9 for map block and tile behavior flow. Again, we are not treating those as decorative utilities. They are the bridge between large map data and per-frame work. The camera asks for draw data. The movement code asks for behavior data. The collision code asks for passability-related data. Different questions, same underlying coordinate system.

Here is another check. If the camera is offset, should collision checks use screen coordinates or map coordinates? Think it through.

They should use map coordinates. Screen coordinates are a presentation detail. If the player appears near the center of the screen and the camera scrolls, the player’s screen position may remain nearly fixed while the player’s map coordinate changes. Collision must care about the actual destination in the map. Rendering needs the camera transform. Movement needs world or map coordinates. Mixing those is a classic bug. You press right, the sprite moves correctly for a few steps, then collision seems to happen against the wrong tile because the code accidentally queried the visible grid instead of the underlying map coordinate. That is the kind of bug your lab should be designed to reveal.

Now add object events. We covered object events as data last week, so I am not going to reteach their map-record structure. Today we only care about what happens after the map is loaded and object events are active runtime occupants. An object event has a position, movement rules, and some notion of whether it blocks or interacts. So when the player attempts to move into x equals 11, y equals 15, the tile might be walkable but the destination might still be unavailable because an NPC is standing there. That is not tile collision. That is occupancy collision. The research packet notes pokefirered/src/event_object_movement.c as the high-signal object-event movement source for runtime movement claims, and we should treat it as paired with fieldmap.c after chunk review. Architecturally, this is a second query layer over the first: map says what the ground is; object movement says what entities occupy or intend to occupy.

In a robust implementation, those two layers should stay separable. If you edit the tile under an NPC to become a wall just because the NPC is there, you have destroyed information. When the NPC moves away, what was the tile? If the player interacts across a counter, is the counter blocked because of tile behavior or because of an object? If two NPCs attempt movement on the same frame, are they colliding with the map or with each other? These questions require the engine to keep ground semantics and entity occupancy distinct.

Let’s use a miniature lab-style example. Suppose our grid stores metatile IDs, and a table maps metatile ID to behavior. Tile 1 is floor. Tile 2 is wall. Tile 3 is tall grass. Tile 4 is water. Tile 5 is ledge facing south. Separately, we have an occupancy map for object events: an NPC at 4,2 and a moving object reserving 5,2. The player at 3,2 presses right. The destination is 4,2. Tile lookup returns floor, so tile collision says yes, floor is passable. Occupancy lookup returns NPC, so movement is rejected. The player at 3,3 presses right into tall grass at 4,3. Tile lookup returns tall grass, passable. Occupancy lookup returns empty. Movement succeeds. After movement, the encounter system sees tall grass behavior and may roll. The player at 3,4 presses right into water at 4,4. Tile lookup returns water. If walking, rejected or surf prompt candidate, depending on game state and interaction direction. If already surfing, accepted. Same coordinate, same tile behavior, different answer because player state participates in the query.

That last sentence is important. A tile behavior is not always the final decision. It is evidence used by a decision. So when we say “tiles as runtime queries,” we do not mean the tile magically knows the whole game rule. We mean the tile exposes semantic facts, and movement code combines those facts with avatar state, object occupancy, scripts, and sometimes map-specific conditions.

This is also why regression testing matters once systems get complex. FireRed itself is not organized around the kind of test harness Pokemon Showdown has, but Showdown gives us a useful comparison for deterministic rule validation. In a battle simulator, if a move damage callback or modded rule changes, you want regression tests to catch behavior drift. The research packet points us toward pokemon-showdown/test as a recurring module for that testing culture, while pokemon-showdown/data and pokemon-showdown/data/mods show how rule variants can be organized. For our FireRed-inspired lab, you can borrow the testing mindset without replacing the architecture. You can write sample movement attempts as regression cases. “Wall rejects walking.” “Grass accepts walking and marks encounter eligibility.” “NPC occupancy rejects movement on floor.” “Camera offset does not affect collision coordinate.” Those are overworld equivalents of simulator turn tests.

Let me pause and check the room. If I say, “a metatile behavior is a hook,” what do I mean? I do not mean it is a function pointer in every case. I mean it is a named semantic value that runtime systems are designed to ask about. The hook point is the query: movement attempt, post-step handling, interaction, encounter check, camera draw. The behavior value is the answer or part of the answer.

And this should also clarify why we spent so much time in earlier weeks on callbacks and tasks. The fieldmap does not run in a vacuum. The main loop calls the active callback. The overworld callback owns the per-frame map experience. Tasks and scripts layer behavior on top of that. We already covered SetMainCallback2 and RunTasks earlier, so I am not going to reopen that machinery. But now you can see why it mattered. A per-frame shell is only useful if the systems underneath it can answer small questions quickly and consistently. Fieldmap queries are exactly that kind of small, repeated work.

As we continue this lecture, we will move from this general model into the specific flow: block access first, then behavior extraction, then collision interpretation, then camera-relative drawing, then object-event boundaries. Keep the pipeline in your head. Authored map data becomes block data. Block data gives metatile identity. Metatile identity gives behavior. Behavior feeds movement and field logic. Camera transforms map coordinates into visible draw requests. Object events add dynamic occupancy over static ground. That is the spine of week five, and it is the piece that turns last week’s loaded map into something the player can actually walk around in.

So let’s put the first function-shaped idea on the board. I’m going to write: “given x and y, return block.” Not “draw the map.” Not “move the player.” Just “return block.” That narrowing is the architectural move.

In FireRed, the fieldmap layer gives the overworld runtime a way to treat the loaded map as a queryable surface. The source focus for today, especially pokefirered/src/fieldmap.c chunk_642df7a31e75f54c and pokefirered/src/fieldmap.c chunk_eeb0180842f7ece9, is useful because it keeps separating the question from the consequence. One part of the code knows how to obtain the map block at a coordinate. Another part knows how to interpret that block as a metatile. Another asks what behavior that metatile has. Later systems decide whether that behavior means “solid,” “water,” “ledge,” “encounter terrain,” “door-like transition,” or something else.

That separation matters because the player’s movement is not the only client. The camera needs map blocks. Field effects need tile behaviors. Object movement needs boundaries. Script-facing field logic needs to know what kind of tile the player is standing on or facing. Battle setup also becomes relevant here, and I want you to notice the cross-module pressure. In pokefirered/src/battle_setup.c chunk_494d132a59422c85, the include list pulls in metatile_behavior.h, fieldmap.h, event_object_movement.h, field_player_avatar.h, and battle-related headers in the same compilation neighborhood. That does not mean fieldmap “is battle,” of course. It means the path from walking on terrain to initiating a wild battle is not a philosophical abstraction. It is represented as source-level dependencies between overworld movement, tile behavior, encounter setup, and battle transition machinery.

Now, pause there, because that is easy to say too quickly. The architectural claim is not “tiles cause battles.” The better claim is: tiles are queried by overworld systems, and some of those systems use the answer to decide whether a higher-level gameplay process should begin. The tile does not know about the player’s party. The tile does not know the battle UI. The tile behavior is a compact runtime fact. Other systems consume that fact.

Let me give you a concrete example. Imagine the player attempts to step north from coordinate 10, 14 to coordinate 10, 13. A naive clone might represent the whole map as a two-dimensional array of strings: “grass,” “wall,” “path,” “water.” Then movement code might say, “if grid[y][x] equals wall, reject; if grass, allow and maybe roll encounter.” That is fine for a weekend prototype, but it collapses too many layers. In the FireRed architecture we are studying, the authored map gives block data. The block yields a metatile identity and associated attributes. The behavior query gives a behavior value. Then collision and field logic interpret that behavior. So the movement attempt becomes a chain of small questions: is the coordinate inside the loaded map area? What block is there? What metatile behavior is associated with that block? Is that behavior passable from this direction? Is there an object event occupying that destination? Does the player’s current movement mode change the answer? Only after those questions are answered do we update position or reject the movement.

On the board, I’ll draw that as a vertical stack. Coordinate at the top. Then block lookup. Then metatile id. Then behavior. Then policy. Then result. The important word is policy. The lower layers retrieve facts. The higher layers decide what those facts mean for a gameplay action.

Check for understanding here: if I ask you, “Where should the rule live that says a player without Surf cannot enter water?” the answer should not be “inside the raw map block array.” The raw block array should not know the party, badges, field moves, or menu state. It can expose that the tile behaves like water. The decision about whether the avatar may enter it belongs in the movement and field-control layer that has access to avatar state and progression state. That distinction is one of the reasons this codebase is a better architecture study than a toy grid example.

Now let’s connect that to camera-relative drawing. We are not yet doing the whole rendering pipeline; do not jump back to startup, callbacks, or the map load sequence. We have already done that. What matters today is that drawing also begins as a query. The visible screen is a moving window over the larger map. The renderer does not need to reinterpret the whole world every frame. It needs to know which map blocks correspond to visible background positions, given the camera offset. So camera-relative drawing is another client of block access. It asks, in effect, “For this screen-space tile position, which map-space block should I display?”

This is why week five sits exactly where it does in the course plan. In weeks three and four, we were making sure you could trace data records into loaded runtime state. You saw map headers, layout references, object events, warp state, and the callback that owns overworld execution. The week four homework and quiz asked you to design minimal clone versions of map loading, script execution, party data, battle turns, item use, and save persistence, so I am going to raise the bar now. It is no longer enough to say, “the map is loaded.” Loaded into what usable shape? Queried by whom? At what granularity? With which dynamic overlays? This is the difference between a data-driven architecture as a slogan and a data-driven architecture as an executable design.

Let’s compare, carefully, with Pokemon Showdown, because it gives us a useful secondary lens. Showdown is not our main architecture source for the overworld. It does not replace FireRed for fieldmap design. But Showdown is very good at making battle data hooks explicit. In pokemon-showdown/data/abilities.ts chunk_da22cf969179258c, the data itself carries competitive ratings and descriptive ability information, and elsewhere in the simulator, battle behavior is routed through hooks and callbacks. In pokemon-showdown/data/mods/gen2stadium2/scripts.ts chunk_3480e574205d5d0f, the damage flow checks immunities, OHKO logic, damage callbacks, fixed damage, and other move-specific branches through structured simulator logic. That gives us a comparison point: Showdown’s battle simulator repeatedly asks data-informed questions during a turn, just as FireRed’s fieldmap repeatedly asks tile-informed questions during overworld movement.

But be precise. Showdown’s “Dex and mods” model is designed for multiple rule sets, generations, and competitive formats. The research packet flags pokemon-showdown/sim and pokemon-showdown/data/mods as recurring modules for Dex, mods, simulator turns, and regression testing. That is a battle architecture lesson. FireRed’s fieldmap is a handheld RPG overworld lesson. The common pattern is not the domain. The common pattern is query-driven runtime behavior. Showdown asks, “what does this move, ability, item, or generation override do at this turn hook?” FireRed asks, “what does this block or metatile behavior imply for this coordinate, movement attempt, or draw request?” The analogy is useful only if we keep the boundary intact.

A good advanced design instinct is to notice when two systems rhyme without forcing them to be the same system. If you were building your own creature RPG today, you might use a FireRed-like map query layer for overworld traversal and a Showdown-like hook layer for battle resolution. You would not necessarily store grass tiles as Showdown-style effects. You would not necessarily store battle abilities as map metatiles. But you might test both with the same discipline: deterministic inputs, small query functions, regression cases for edge conditions.

Let’s make that concrete for the lab. Your workshop grid map this week is not just “draw a grid and walk around.” It needs metatile lookup, collision checks, camera offset, and object-event occupancy. So suppose your map has a 20 by 15 block layout. Your visible viewport is 10 by 8. The camera origin is at map coordinate 6, 4. When drawing screen tile 0, 0, you should query map coordinate 6, 4. When drawing screen tile 3, 2, you query map coordinate 9, 6. That is camera-relative drawing in miniature. You are transforming screen-space requests into map-space block queries.

Now suppose the player is at 9, 6 and presses right. The destination is 10, 6. Your movement code should not ask, “what sprite is drawn at screen position 4, 2?” That would be mixing presentation with gameplay state. It should ask the map model for the destination block, ask the tile-behavior layer for behavior, ask the collision layer whether that behavior blocks the avatar, and ask the object occupancy layer whether a dynamic object already occupies 10, 6. If all checks pass, then the player’s map coordinate changes. The camera may subsequently move, and drawing will follow.

I want to say that again in a slightly different way because it is one of the core week five misunderstandings. The camera does not define where the player is. The camera defines what part of the map is visible. The player has a map coordinate. Objects have map coordinates. Collision checks are in map coordinates. Drawing converts map coordinates into screen positions. If you invert that relationship, your clone will work for about thirty minutes and then break the first time the camera scrolls, the player approaches an edge, or an NPC moves while partially offscreen.

The helper flow in pokefirered/src/fieldmap.c chunk_77ef7f3f8bff9777 is part of why I keep using the phrase “small questions.” Helper functions are not incidental decoration in this part of the architecture. They preserve the boundary between representation and use. A block access helper can hide border handling. A metatile behavior helper can hide how attributes are packed or extracted. A collision helper can hide directional interpretation. This is old C code with hardware constraints, but the architectural lesson is modern: if many systems need the same fact, centralize the query, not every consequence of the query.

Now, let’s add object events to the board, but only as a dynamic overlay. We covered object event records earlier, so I am not going to re-teach the map JSON idea or the event list idea. Today’s point is runtime occupancy. A static tile might be passable. A person object standing on it might make it temporarily impassable. Or an object might be moving from one tile to another, which creates an even more subtle boundary question: is the destination free, reserved, entering, leaving, or blocked? The week context names pokefirered/src/event_object_movement.c as the high-signal source for movement-boundary claims, so when you reason about object-event movement, do not invent a second collision world. Treat objects as dynamic participants layered over the static fieldmap query.

In your lab implementation, this means an attempted move should fail if a blocking object occupies the destination, even if the underlying tile says “floor.” It also means your test cases should include both static collision and dynamic occupancy. Test one: wall tile, no object, movement rejected. Test two: floor tile, no object, movement accepted. Test three: floor tile, object present, movement rejected. Test four: grass tile, no object, movement accepted and terrain behavior returned for possible encounter logic. That fourth case is important because passability and behavior are not synonyms. Grass is passable, but it still matters.

This is also where battle comparisons can sharpen your testing mindset. In Showdown, regression tests are valuable because simulator turns combine many small hooks: immunity checks, damage callbacks, generation-specific scripts, and so on. The packet points us to pokemon-showdown/data/mods/gen2stadium2/scripts.ts chunk_3480e574205d5d0f for a damage path with several conditional hooks. If you change one condition, you can break an old format. In our FireRed-inspired overworld layer, a small change to block lookup or behavior extraction can break ledges, grass, water, doors, NPC blocking, or camera edges. Different domain, same lesson: regression tests protect query semantics.

Let me ask a check question. If your grid lab has a function called canMoveTo(x, y), and inside it you directly index the render buffer, inspect the visible tile image, check NPC sprites by screen pixel, and decide whether to roll a wild encounter, what architectural smell should you identify? Yes: the function is asking presentation objects for gameplay truth, and it is collapsing multiple policies into one place. A stronger design would have getBlockAt, getBehaviorAt, isBehaviorPassableForAvatar, isOccupiedByObject, and perhaps getTerrainEffectForStep. The names do not have to be exactly those, but the responsibilities should be separated.

Now, I want to bring us back to the course-level spine. In week one, we decomposed the creature-collector RPG into runtime shell, overworld maps, scripting, creature data, battle, inventory, UI, save, and link systems. In week two, we traced source files, structs, functions, constants, data tables, and state variables. In weeks three and four, we moved into map records, layout references, object events, warp state, and loaded-map runtime. Week five is where the loaded overworld becomes interactive space. That is why tile behavior queries matter. They are not a minor utility. They are one of the places where data becomes moment-to-moment play.

And because you are advanced learners, I want you to resist the temptation to over-object-orient this too early. A modern clone can absolutely wrap this in classes or ECS components or immutable data structures. Fine. But the FireRed lesson is lower-level than that. The question is: what is the minimal fact needed by the caller, and where is the most stable place to answer it? If the caller needs to know what block exists at coordinate x, y, answer that. If the caller needs to know what behavior that block implies, answer that. If the caller needs to know whether the avatar may step there, answer that at the layer that understands avatar state, object occupancy, and tile behavior together.

Think about how this will pay off when we reach later systems again. Battle setup can be triggered by overworld conditions, but battle turns will have their own data hooks. Inventory can affect traversal, but item data should not be embedded into map blocks. Save persistence records positions and flags, but it should not serialize an entire freshly derivable collision interpretation for every tile. Link systems may synchronize player state, but they still need deterministic interpretations of position and movement. The tile query layer is small, but it becomes a contract that many other systems lean on.

Let’s do one more board example before we move into the specific block-flow details. I’ll write three rows.

First row: authored value. Maybe the map layout says block 312 at coordinate 10, 13.

Second row: runtime interpretation. Block 312 corresponds to a metatile whose behavior is tall grass.

Third row: consumers. Movement says passable. Encounter logic says eligible terrain. Rendering says draw the visual tiles associated with block 312. Audio or field effects might say use grass-step feedback. Object movement says an NPC may or may not be allowed depending on movement permissions.

The same authored value supports multiple runtime consumers. That is the power of the design. But it only works if those consumers do not corrupt the common query layer with their own private assumptions.

Now, as we go next into block access, keep listening for three things. First, how the code protects coordinate lookup from becoming scattered arithmetic. Second, how metatile behavior is extracted as a reusable answer. Third, how collision and camera drawing consume the same map reality for different purposes. That is the bridge from the general model into the actual FireRed flow, and it is also the bridge from week five’s lecture into the lab you are going to implement.

So, let’s now turn that bridge into source-shaped thinking. I’m going to write one phrase on the board: “movement does not read the map; movement asks the map.” That is the key distinction. If your movement code is crawling through layout arrays, masking bits in three different places, and deciding for itself what an out-of-bounds coordinate means, then you have already lost the architecture. You may still get a playable prototype, but you do not have the FireRed-style separation we are studying this week.

In FireRed, the field map layer gives the rest of the overworld a small vocabulary of runtime questions. What is the elevation here? What is the collision value here? What metatile id is here? What behavior attribute belongs to that metatile? These are not philosophical questions. They correspond directly to the flow in pokefirered/src/fieldmap.c, especially the map block and tile behavior path called out in chunk_eeb0180842f7ece9. The important thing is not merely that these functions exist. The important thing is that they narrow the contract. Callers do not need to know the complete representation of the virtual map. They need an answer.

Now, look at the board. I’m drawing a little pipeline. Coordinate, then block lookup, then masked field, then semantic answer. For collision, the answer is basically, “Can ordinary movement enter this block?” For metatile id, the answer is, “Which authored block is visually and semantically present?” For behavior, the answer is, “What gameplay category does this metatile advertise?” That last word, advertise, is deliberate. A tile does not execute all of the behaviors itself. It advertises a behavior value, and other systems decide what to do with that value.

Here is the concrete example. Imagine the player presses up while standing at map coordinate 10, 6. We are not going to re-teach the main callback or overworld callback today; we already built that foundation in the previous weeks. Assume the per-frame overworld loop has reached the point where the input has become a movement attempt. The movement attempt proposes target coordinate 10, 5. At that point, good architecture says, “Ask the field map.” It does not say, “The player movement code should remember how wide the map buffer is, where the border padding begins, what mask extracts collision, and how connected maps are represented.” That information belongs behind the fieldmap query layer.

This is why the undefined-coordinate behavior matters so much. In pokefirered/src/fieldmap.c, chunk_eeb0180842f7ece9, the query functions treat undefined map grid blocks differently depending on the question. Collision returns an impassable answer for undefined blocks. Metatile id falls back to a border block answer masked as a metatile id. Elevation has its own fallback. That is a very dense design lesson. The default answer is not universal. It is tailored to the consumer’s need. For movement, undefined should be conservative, so it blocks. For drawing, the edge still needs something visible, so border tiles are useful. For behavior, the metatile id can lead to an attribute lookup through the layout. Same coordinate, different question, different safe answer.

Pause there and check your understanding. If the target coordinate is outside the real authored map, should the collision query and the rendering query necessarily return the same kind of failure? No. Exactly. Collision wants safety. Rendering wants continuity. If both systems shared one crude “lookup failed” path, either the player could walk into garbage, or the screen edge would become visually broken. FireRed avoids that by giving callers question-specific APIs.

Now, connect that to the phrase from the last passage: one authored value supports multiple runtime consumers. A block entry is not just a picture. It can carry a metatile id, collision information, elevation information, and then, indirectly through metatile attributes, behavior. The fieldmap code is acting like a translation layer between compact authored data and runtime gameplay questions. In pokefirered/src/fieldmap.c, chunk_642df7a31e75f54c and chunk_eeb0180842f7ece9 are the relevant evidence for this runtime support and block-to-behavior flow. The player avatar, camera, field effects, encounters, and object movement should not each invent their own translation.

Let me give you a deliberately bad version, because advanced students often recognize the smell immediately. Suppose in your lab you store tiles in a two-dimensional array, and then your player movement function says, “If tile id equals 5, block movement; if tile id equals 6, play grass sound; if tile id equals 7, treat as ledge.” That may pass the first demo. But what happens when you swap art? What happens when two different tiles are both grass? What happens when a tile is visually a flower patch but semantically tall grass? What happens when a region-specific tileset uses different metatile ids for the same behavior? You have coupled gameplay to art identity. FireRed’s behavior query layer is the escape hatch from that coupling.

Instead, your lab should make the movement code say something more like, “Give me the collision value at the target coordinate,” and separately, after movement succeeds, “Give me the behavior at the coordinate I now occupy.” The first question gates entry. The second question triggers consequences. That distinction is small but architectural. Collision is precondition logic. Behavior is post-entry or context logic. Sometimes behavior is also precondition logic, as with surf-like or ledge-like cases, but even then it should be queried as behavior, not guessed from art.

Now I want to bring in Pokémon Showdown, but carefully. Showdown is not replacing FireRed here. It is not our map runtime source. It does, however, give us a useful secondary comparison for query and hook design in battle systems. In Showdown, the Dex layer is the battle-data lookup layer. The research packet points us to pokemon-showdown/sim/DEX.md, chunk_922688d7428150d1, for Dex as a lookup library for moves, species, items, abilities, natures, stats, and related battle data. It also points to pokemon-showdown/sim/DEX.md, chunk_5fbe60392b5eedf9, for Dex.mod as the way to ask for generation-specific data. That is the battle-side version of the same architectural instinct: do not scatter raw data interpretation everywhere. Ask the appropriate runtime layer.

For example, if Showdown wants Tackle in a modern format versus Tackle in a Gen 1 format, the caller should not be full of little historical exceptions. It should go through the format-aware Dex. In FireRed overworld terms, if the map wants a grass behavior on one tileset and a visually different grass behavior on another tileset, the movement or encounter code should not be full of metatile-id exceptions. It should go through the map and metatile behavior query path. Different domain, same architecture pattern.

Showdown’s battle hooks make the comparison even sharper. The packet identifies pokemon-showdown/data/mods/gen2stadium2/scripts.ts, chunk_3480e574205d5d0f, as a high-signal example where damage calculation checks move form, immunity, one-hit KO behavior, damage callbacks, fixed damage, category, and typing. That is a battle runtime asking a series of structured questions and allowing data-backed hooks to modify the answer. FireRed’s tile behavior system is simpler, but conceptually it is doing the same kind of separation. The tile says, “I am this kind of thing.” The runtime asks, “Given that kind of thing, what rule applies right now?”

Be careful, though. The analogy has limits. Showdown is a battle simulator. Its hooks can be rich functions because battle effects are deeply compositional. Abilities, items, statuses, weather, move effects, and format rules all stack. A FireRed map tile behavior is not usually a free-running callback. It is more like a compact semantic label consumed by C functions. So if you copy Showdown’s hook system directly into your overworld lab, you will probably over-engineer it. The correct lesson is not “turn every tile into a JavaScript-style event handler.” The correct lesson is “centralize lookup, preserve semantic labels, and make consumers ask narrow questions.”

Let’s do a check for understanding with a contradiction. Suppose I create a metatile that visually looks like tall grass. Its behavior attribute says tall grass. But its collision bit says impassable. What happens architecturally? Do not answer with one final gameplay outcome too quickly. The better answer is: the query layer can report both facts. Collision can say, “No, ordinary movement cannot enter.” Behavior can still say, “This metatile’s behavior is tall grass.” Whether the player ever experiences the grass-step effect depends on the movement flow, because if movement never succeeds, post-step consumers may never run. The architecture permits contradictory authored data; it does not magically make contradictory content meaningful. That is a content validation issue, not a query-layer issue.

That point will matter in the lab. Your grid map should not hide contradictions by collapsing everything into one enum like WALL, GRASS, WATER, FLOOR. That is too simple for the architecture we are learning. Use at least separate concepts for metatile id, collision, behavior, and occupancy. If you combine them too early, you cannot model FireRed’s runtime questions. And after week four’s homework and quiz, I am going to hold you to that higher bar. You have already designed minimal versions of map loading, scripting, party data, battle turns, item use, and save persistence. Week five is where we stop treating the overworld map as a static array and start treating it as a runtime service.

Now, camera movement adds another layer. The camera is not asking exactly the same question as avatar movement. The avatar asks, “Can the actor enter target coordinate?” The camera asks, “Can the visible window shift in this direction without leaving the valid map or connection area?” In pokefirered/src/fieldmap.c, chunk_77ef7f3f8bff9777, the helper flow around map border checks supports this distinction. The code checks border identity and connection validity. It uses player position, map offset, and direction vectors to decide whether camera movement is permitted. Again, notice the pattern. The camera does not need to become an expert in map storage. It asks a border or camera movement helper.

On the board, I’m adding a second pipeline below the movement one. Player movement: proposed coordinate, collision, object occupancy, behavior after success. Camera movement: proposed screen shift, border check, connection validity, redraw source. Those pipelines overlap because they share map reality. They differ because they are different consumers. This is one of the most important architectural ideas in week five. Shared data does not mean identical interpretation. Shared query layer does not mean every caller asks the same question.

Now let’s briefly connect object-event movement, without re-teaching object events from last week. You already know that maps can define object events, and we are not going back through the object record format today. The new point is that object movement introduces occupancy as a runtime fact that is not identical to tile collision. A tile may be passable in the map data but blocked because an NPC is standing there. Conversely, an object may have movement permissions or scripts that make it behave differently from the player. The research packet names pokefirered/src/event_object_movement.c as the high-signal object-event movement source to use after chunk review, and that is exactly how we will use it in the next lecture: not as a replacement for fieldmap collision, but as the runtime layer that adds actor occupancy and movement boundaries on top of tile queries.

That layering is what your workshop implementation should mirror. Do not put NPCs directly into the terrain grid as permanent wall tiles. Use a terrain query first, then an occupancy query. If your NPC walks away, the tile beneath it did not become a different metatile. The occupancy changed. That sounds obvious, but many first prototypes accidentally encode temporary objects as terrain. Then door scripts, NPC movement, camera redraw, and collision all become tangled.

Now, why are we talking about Showdown regression tests in a tile lecture? Because the test habit transfers. Showdown’s test module is useful as a secondary comparison for deterministic battle-mechanics testing. The packet specifically identifies pokemon-showdown/test/TESTS.md, chunk_134ac9f75b9d6477 and chunk_e8da8b9a442469fd, along with pokemon-showdown/test/common.js, chunk_979fde4c3177ea4f, for reproducible battle scenarios using small teams, explicit choices, fixed seeds, and controls around random chance. We are not testing battles this week, but the discipline is the same: create a small world, issue a small input, assert the runtime state.

For the lab, your equivalent of a Showdown battle regression is a movement regression. Place the player at 2, 2. Place a wall at 2, 1. Press up. Assert that the player remains at 2, 2 and that no step behavior fires. Then change the wall to passable grass. Press up. Assert that the player moves to 2, 1 and that the grass behavior is reported. Then place an object event at 2, 1 on an otherwise passable tile. Press up. Assert that terrain allows entry but occupancy denies it. That last test is the important one. It proves you did not collapse terrain collision and object occupancy into the same crude condition.

Let’s pause for another check. If a movement attempt fails because an NPC occupies the destination, should the map grid collision value at that coordinate change? No. It should not. The tile remains passable or impassable according to terrain. The movement attempt fails because another runtime layer adds a temporary blocker. Good. And if the camera needs to draw the tile under that NPC, should it ask the object system for the terrain? No. It should ask the field map for the metatile and then render the object separately. Excellent. That separation is the course thesis showing up in miniature.

Tie this back to the overall course plan. In week one, we decomposed the RPG into cooperating systems. In week two, we looked at source organization, generated data, headers, and runtime contracts. In weeks three and four, we built up map records, layout references, object events, and the transition from warp state into a loaded map runtime. Now, week five is the payoff for that foundation. We are inside the loaded map, asking how the game turns authored space into per-frame decisions. Tiles as runtime queries is the hinge between static data and living overworld behavior.

And that hinge repeats later. In battle, moves and abilities become runtime questions through battle data and hooks. That is where Showdown helps us compare Dex lookup, mods, simulator turns, and regression tests without becoming our primary source. In inventory, item ids become runtime effects through item-use dispatch. In save systems, compact persisted values become restored runtime state through load paths. In UI, structured state becomes drawn windows and menus through callback-driven screens. The pattern is not “everything is a table.” The pattern is “data becomes behavior only when the right runtime system asks the right question.”

So, before we move into the next part, here is the local synthesis. FireRed’s map grid should be read as a service boundary. The fieldmap code in pokefirered/src/fieldmap.c, especially chunk_642df7a31e75f54c, chunk_eeb0180842f7ece9, and chunk_77ef7f3f8bff9777, gives us the source-grounded shape of that boundary: block access, metatile id extraction, behavior attribute lookup, collision defaults, and border or camera helpers. The callers remain focused. Movement asks whether entry is legal. Camera asks whether view motion is legal and what to draw. Field effects ask what kind of tile has been stepped on. Object movement adds occupancy and actor rules. Same map reality, different runtime questions.

Keep that model in your head as we go forward, because the next step is where mistakes become visible. Once collision, camera, and object events all consume the same grid, ordering starts to matter. If you query behavior before movement succeeds, you can trigger effects from a tile you never entered. If you move the camera before validating border conditions, you can reveal invalid map space. If you treat object occupancy as tile collision, NPC movement will corrupt terrain. Those are not abstract design sins. They are exactly the kinds of bugs your week five lab is designed to expose.

So let’s make this ordering concrete. Imagine the player presses right while standing at coordinate ten, twelve. The input system does not get to say, “Well, the animation should move to eleven, twelve because the button was right.” That is too early. The input system proposes intent. The movement layer turns that intent into a candidate coordinate. Then the map runtime is asked a set of questions about that candidate coordinate. What block is there? What metatile does that block resolve to? What behavior is attached to that metatile? Is there an object occupying the destination? Is the player’s elevation compatible with the tile and with any object there? Only after those questions are answered can the runtime commit to movement, animation, camera scroll, and later step effects.

Let me put that on the board as a little pipeline, but remember, this is a conceptual pipeline, not a claim that every function is neatly named this way. First, input becomes intended direction. Second, intended direction becomes candidate position. Third, candidate position becomes map block lookup. Fourth, map block lookup becomes tile behavior. Fifth, tile behavior plus object occupancy becomes movement permission. Sixth, committed movement becomes animation, camera adjustment, and post-step effects. The point is not the exact naming. The point is that a tile is not mainly a graphic at this moment. It is a query target.

This is why I want you to be careful when you implement the week five lab. If your grid cell stores only “walkable true” or “walkable false,” you can get through the first ten minutes of testing and still have the wrong architecture. A FireRed-like map runtime does not want one Boolean. It wants a set of interpretable facts. Water is not merely blocked. Water might be blocked for walking, enterable while surfing, connected to encounter rules, visible to camera drawing, relevant to reflection effects, and relevant to field moves. Tall grass is not merely walkable. It is walkable, but it may initiate wild encounters, play a rustling animation, hide part of the avatar sprite, and interact with bike or running rules. A ledge is not merely walkable or blocked. It is direction-sensitive. You can often move off it in one direction and not climb back from the opposite direction.

That is the first sophistication jump for today. Earlier in the course, especially in weeks one and two, it was acceptable to say, “Data table feeds runtime behavior.” That was the right level then. Now, because your recent homework and quiz work already asked you to design minimal clone versions of map loading, script execution, party data, battle turns, item use, and save persistence, I expect a sharper answer. You should now be able to say, “The runtime asks different questions of the same data depending on which subsystem is currently making the decision.” That is a much more architectural sentence.

In FireRed, this is exactly why fieldmap support matters. The week five source focus points us at pokefirered/src/fieldmap.c, especially chunk_642df7a31e75f54c for runtime support, chunk_eeb0180842f7ece9 for map block and tile behavior flow, and chunk_77ef7f3f8bff9777 for helper flow. We are not treating those as decorative helper files. We are treating them as the layer that lets higher-level movement and field systems ask, “What is at this coordinate?” without each subsystem separately decoding layout memory. That separation is one of the things that makes the overworld tractable.

Now, a check for understanding. Suppose you have a bridge tile drawn over water. The player is standing on the bridge. The water graphic is visible. A naive renderer-oriented model might say, “This tile is water, so maybe the player needs Surf.” But the runtime behavior may need to say, “For movement, this behaves like bridge floor at this elevation.” So if I ask, “What is the tile?” the right counterquestion is, “For which purpose?” For drawing, it may include water imagery. For movement, it may behave like passable bridge. For encounter logic, maybe no water encounter should occur because the player is not in the water layer. That is the sort of distinction you need to preserve.

Let’s connect that to object events without re-opening the entire object event lecture from last week. We already know object events come from map data and become runtime actors. Today’s point is narrower. Object events are not part of the terrain, but they participate in movement legality. If an NPC is standing on a road tile, the road did not become a wall. The destination is blocked because there is an actor occupying it. That sounds obvious, but implementation mistakes often collapse these two things. Students write a grid where each cell has one “blocked” flag, and when an NPC stands somewhere, they set that cell to blocked. Then the NPC moves away, and now they have to remember what the old tile used to be. That is a red flag. Terrain and occupancy should be separate queries layered together at the decision point.

This is also why the research packet’s note about pokefirered/src/event_object_movement.c matters for our week. We are using it carefully, after the fieldmap chunk review, as high-signal evidence for runtime movement claims. The movement actor layer should ask map questions; it should not become the owner of map truth. If the movement code starts rewriting terrain semantics as actors move, you have made the world harder to reason about.

Now, let’s briefly compare this to Pokémon Showdown, but keep the comparison in its proper place. Showdown is not our overworld architecture source. It is not trying to draw a Game Boy Advance field map, and it is not trying to scroll camera-relative metatile layers. But it is a very useful secondary comparison for a pattern we keep seeing: runtime hooks over structured data. In FireRed’s overworld, a metatile behavior lets movement, camera, effects, and scripts interpret map data. In Showdown’s battle simulator, moves, abilities, formats, and generation mods expose hooks that the simulator calls during turn resolution.

For example, the research packet points us to pokemon-showdown/data/abilities.ts chunk_da22cf969179258c, where abilities are not only static labels. The excerpt even includes rating commentary, but architecturally the important part is that ability records are structured data used by the battle system. Elsewhere in Showdown, such data can define hooks that affect events in battle. Likewise, pokemon-showdown/data/mods/gen2stadium2/scripts.ts chunk_3480e574205d5d0f shows simulator logic dealing with move damage behavior, including checks such as immunity, OHKO handling, damage callbacks, level-based damage, and fixed damage. That is battle-domain logic, not map-domain logic, but the architectural rhyme is strong. The simulator is not asking, “What graphic is this move?” It is asking, “When this move is resolved in this context, what behavior should occur?”

Pause there. Does everyone see the analogy and the limit of the analogy? The analogy is data plus hooks plus runtime context. The limit is domain. FireRed’s fieldmap is about coordinates, metatiles, camera drawing, collision, and actors. Showdown’s simulator is about battle state, turns, moves, abilities, and generation-specific rule modifications. If you import Showdown’s architecture back into FireRed wholesale, you will make nonsense. But if you use Showdown to sharpen your sense of runtime queries, it is very valuable.

Let me make that more concrete. In a Showdown battle turn, the simulator must answer questions like, “Can this move hit?”, “What is its effective base power?”, “Does the target have immunity?”, “Does an ability alter the result?”, “Which generation’s rules apply?” The source packet’s Showdown module notes point us toward pokemon-showdown/sim, including DEX.md, NONSTANDARD.md, and README.md, as the place where the Dex and simulator structure are explained. The packet also emphasizes data mods, including paths like pokemon-showdown/data/mods/gen9dlc1/learnsets.ts and pokemon-showdown/data/mods/gen8dlc1/learnsets.ts. A modded Dex lets the simulator answer a rules question under a specific rule set.

In FireRed’s overworld, the equivalent question is not “Which generation’s learnset applies?” It is “Which map layout, blockset, metatile behavior, and coordinate context applies?” Same architectural family, different vocabulary. In both cases, the runtime should not scatter special cases everywhere. It should centralize the question enough that the rest of the engine can ask it consistently.

Now, back to our map lab. I want you to implement a small grid map that supports metatile lookup, collision checks, camera offset, and object-event occupancy. If you implement it as a single two-dimensional array of characters, you will probably feel productive at first. Dot means floor, hash means wall, W means water, N means NPC. But then you will immediately hit trouble. Is N the terrain or the object? If the NPC walks off the tile, what appears underneath? If W is water, is it blocked, surfable, drawable, encounter-capable, or all of those? If the camera scrolls, are you indexing world coordinates or screen coordinates?

Instead, I want you to split the model. The map has blocks or cells that resolve to metatile IDs. Metatile IDs resolve to behaviors. Objects have world coordinates. The camera has an offset into world coordinates. Movement proposes a world coordinate. Collision asks terrain behavior and occupancy separately. Drawing takes the camera offset and samples world coordinates into screen positions. That architecture is small enough for a lab, but it resembles the real pressure in FireRed.

Let’s do a board example. I’ll draw a five-by-five world grid. The player is at world coordinate two, two. The camera’s top-left world coordinate is one, one. That means the player appears at screen coordinate one, one, because screen coordinate equals world coordinate minus camera offset. Now the player presses right. The candidate world coordinate is three, two. Before drawing anything, we query the map at three, two. Suppose the metatile ID is 27. We look up metatile 27’s behavior and get “ledge east.” If movement direction is right, maybe that is legal and triggers a hop. If movement direction were left, maybe it is not legal. Then we query object occupancy at three, two. If an NPC is already there, movement is blocked, even though the ledge behavior by itself might have allowed motion. Only after that do we update player position, potentially update camera offset, and draw the next frame.

Here is the check for understanding. If the player attempts to move into an occupied grass tile, should the grass encounter check run? No, because the player did not enter the tile. The behavior exists, but the movement was not committed. If your lab prints “wild encounter check” merely because the candidate tile was grass, you have found an ordering bug. Candidate queries can inspect behavior, but committed movement triggers step consequences. That distinction will come back when we discuss scripts and field effects in later weeks.

Now I want to connect this to the larger course plan, because week five is not an isolated fieldmap week. Weeks three through five are our overworld map runtime module. Earlier, we built from map records, layout references, object events, warp destination state, and the CB2_Overworld runtime callback. I am mentioning those as foundation, not re-teaching them. The new layer is that a loaded map is still not behavior. It is potential behavior. The runtime has to query it every frame and every movement attempt. After this week, when we move into the next module, you should carry that pattern forward. Battles will also be runtime interpretation of structured data. Inventory will also be runtime interpretation of item records and menu state. Save systems will serialize selected runtime state, not every possible derived fact. Link systems will constrain which state transitions can be synchronized. The course is a sequence of increasingly specific answers to one question: how does a data-driven creature RPG convert static records into player-visible behavior?

FireRed gives us the primary historical architecture for that question. Showdown gives us a modern, test-heavy comparison for battle rules, especially when we later discuss deterministic simulator turns and regression testing. The research packet explicitly tells us not to replace FireRed with Showdown, and that is the right warning. Showdown is excellent when we ask how battle data hooks, Dex mods, and simulator tests can organize complex rule variation. FireRed remains our authority for GBA-era runtime structure, callbacks, tasks, field maps, object movement, and hardware-conscious drawing.

Regression testing is worth previewing here. In the overworld lab, you can create a tiny test table of movement attempts. Start at coordinate one, one. Try to move north into wall, expect blocked. Try to move east into floor, expect position changes. Put an object at two, one, try to move east, expect blocked by occupancy. Move camera offset after a successful step, expect screen coordinate to update but world coordinate to remain authoritative. That is the overworld equivalent of what Showdown does at a larger scale for battle rules: construct states, run turns or decisions, and assert outcomes. When we later look more closely at pokemon-showdown/test, that test culture will be one of the useful comparisons. The domain differs, but the discipline of “given this state, after this runtime query and transition, expect this result” transfers beautifully.

And notice how this raises the bar on your lab submissions. I do not only want a demo where a square moves around. A moving square is a rendering accomplishment, not yet an architecture accomplishment. I want to see that the square is moving because the runtime made the right queries in the right order. Your code should make it possible to inspect why movement failed. Was it terrain? Was it an object? Was it a map boundary? Was it an elevation mismatch, if you choose to implement elevation? That diagnostic quality matters. Real engines are debugged through reasons, not vibes.

Let’s return for a moment to FireRed’s source boundaries. pokefirered/src/battle_setup.c chunk_494d132a59422c85 is interesting here even though it is not the center of today’s lecture, because its include list crosses overworld, event object movement, metatile behavior, fieldmap, avatar control, battle transition, and battle headers. That tells us something architectural: battle entry is not floating in a separate universe. The game has to bridge from field state into battle state. A wild encounter is not just “battle starts.” It is the result of overworld position, tile behavior, player movement, encounter logic, transition setup, and then battle initialization. So when I say tile behavior is a runtime query, do not hear that as a small local trick. It is one of the ways the overworld hands meaningful context to other systems.

The same is visible in a different way in pokefirered/src/pokemon_summary_screen.c chunk_e8e17a42bbf17d46. Its include list spans Pokémon data, tasks, menus, link, overworld, items, moves, party menu, region map, and battle constants. Again, the point is not that include lists are architecture by themselves. The point is that a creature RPG is a network of systems that must expose stable contracts. Headers, data records, callbacks, tasks, and helper functions are the surfaces where those contracts show up. We talked about headers as cross-module contracts in week two. Week five gives you a physical example: fieldmap helpers let movement and rendering code avoid owning raw map representation.

Now, I want to test a subtle idea. Imagine two students implement the same visible behavior. In both demos, the player cannot walk through a wall, cannot walk through an NPC, and the camera follows the player. Student A has one function called movePlayer that checks the grid, mutates the grid, moves the NPC markers, scrolls the camera, and triggers grass effects. Student B has separate map lookup, behavior lookup, occupancy lookup, movement commit, camera projection, and step effect phases. Which implementation is more FireRed-like architecturally? Student B. Not because more functions are automatically better, but because the system has separated questions that change for different reasons. If tile behavior rules change, that should not require rewriting camera projection. If camera dimensions change, that should not change collision. If NPC occupancy changes, that should not rewrite terrain.

That separation also protects you from asset changes. Suppose an artist changes the visual appearance of a path tile. If the metatile behavior remains “normal ground,” movement should not change. Suppose a designer changes a tile from normal ground to slippery ice while keeping a similar palette. Movement should change even if the art looks familiar. That is data-driven architecture in practice: art, map placement, behavior labels, and runtime systems are related but not identical.

A quick comprehension check before we move on. When the player is halfway through a walking animation between two tiles, what coordinate should collision use for the next attempted movement? In a tile-based engine, usually you do not accept a new tile movement as fully independent until the current movement state reaches a boundary or a controlled transition point. The committed logical coordinate and the animated pixel position are related, but they are not the same thing. This matters for camera-relative drawing too. The avatar may be visually between tiles while the map coordinate state still follows a discrete movement model. If you merge pixel position and tile position too casually, you will create edge bugs at boundaries, ledges, doors, and NPC interactions.

Now, I am going to leave the board example up, because it will help us in the next section. What I want you to carry forward is the phrase “runtime query.” A tile is not passive. A tile answers questions. But it answers only through the systems that interpret it. The raw grid does not know whether the player is walking, surfing, biking, being forced by a script, sliding on ice, or following an NPC route. The runtime context supplies the question. The metatile behavior supplies part of the answer. Object occupancy supplies another part. Camera state supplies another. That is the architecture we are studying today, and it is the architecture your lab should make visible.

So, let us now widen the lens without leaving the map. That sounds contradictory, but it is exactly the discipline I want you to build. We are still in FireRed’s field runtime. We are still talking about metatile lookup, tile behavior queries, collision, camera-relative drawing, and object-event occupancy. But I want to compare this style of architecture to another creature battle codebase, Pokemon Showdown, not because Showdown should replace FireRed as our architectural source, but because Showdown makes a different set of runtime-query ideas very explicit.

In FireRed, today’s question is, “What does this tile mean right now?” In Showdown, a common question is, “What does this move, ability, species, item, or rule mean right now?” That word “right now” is doing a lot of work. A tile is not just a number in FireRed. A move is not just a base power in Showdown. Runtime context determines which query is being asked, which data is consulted, and which hook is allowed to affect the answer.

Let me put that on the board. On the left side, I am writing FireRed overworld: coordinate, map layout block, metatile behavior, object occupancy, movement mode, camera. On the right side, I am writing Showdown battle: Pokemon, move, ability, item, weather, terrain, rule set, generation mod. Now, under both columns, I am writing the same phrase: data interpreted by a runtime.

That is the comparison. Not “FireRed is old C and Showdown is TypeScript.” That is surface-level. The deeper comparison is that both systems avoid hard-coding every visible outcome into one giant decision table. They store data, then route runtime questions through specialized helpers and hooks.

For FireRed, our source focus this week is specifically pokefirered/src/fieldmap.c, including chunk_642df7a31e75f54c for fieldmap runtime support, chunk_eeb0180842f7ece9 for map block and tile behavior flow, and chunk_77ef7f3f8bff9777 for helper flow. When I say “tile behavior query,” I mean that as a real architectural movement in this codebase: the runtime gets from coordinate-like information to block information, and from block information to behavior information, and from behavior information to movement or interaction decisions. That is why I have been careful not to say “the map blocks the player.” The map does not block anything by itself. Code asks a question about a coordinate, and the answer participates in blocking, drawing, triggering, or interaction.

Now, compare that with the Showdown example in pokemon-showdown/data/mods/gen2stadium2/scripts.ts, chunk_3480e574205d5d0f. That excerpt shows damage logic using runtime checks such as immunity, OHKO handling, damage callbacks, level-based damage, and fixed damage before continuing through ordinary damage calculation. Again, the move’s data is not merely read and displayed. It is queried in a context. The source, target, active move, generation behavior, and callback path all matter.

That should feel familiar now. A ledge tile in FireRed is not just “ledge.” It is “ledge, queried from a direction, under a movement state, by an actor at a particular coordinate.” A damage callback in Showdown is not just “special damage.” It is “special damage, queried during the damage calculation phase, for a source and target, inside a battle context, under a generation or mod rule set.”

Check your understanding here. If I ask you, “Where is the behavior?” and you answer, “In the data,” you are only half right. If you answer, “In the function,” you are also only half right. The behavior is in the contract between the data and the runtime query. That is the advanced answer. The same raw tile can participate in different decisions depending on what the engine is asking. The same raw move record can participate in different outcomes depending on what phase of the battle engine is asking.

Let us make this concrete with the lab model you are going to build. Suppose your grid has a metatile at coordinate 10, 7, and that metatile has a behavior tag we will call water. You also have a player at 10, 6 attempting to move down. A beginner implementation says, “If target tile equals water, block movement.” That works until you add Surf. Then you change it to, “If target tile equals water and player is not surfing, block movement.” That works until you add a script that forces the player onto a dock animation, or a fishing interaction, or an NPC that can move over terrain the player cannot. The better design is to phrase it as a query: “Can this actor enter this coordinate under this movement mode and interaction context?” The tile behavior is one input. The actor type is another input. The occupancy grid is another input. The script state may be another input.

So, on the board, I am drawing a function-shaped box. It takes actor, from coordinate, direction, movement mode, and map state. Inside the box, it performs a block lookup, extracts behavior, checks object occupancy, checks boundary conditions, and returns a structured answer. Not just true or false if you can avoid it. For the lab, I want at least enough structure that you can distinguish “blocked by wall,” “blocked by object,” “blocked by map boundary,” and “allowed.” Why? Because debugging field movement is painful when every failure collapses into false.

This is also where camera-relative drawing enters as a runtime query. The camera is not changing the map. The camera changes which rectangle of the map is being asked for display. If the player moves one tile east, the map data does not slide around in memory as a conceptual requirement. The viewport’s relationship to the world shifts. So when you draw, you are asking, “Which world tile appears at this screen tile?” That is another query: screen coordinate plus camera offset gives map coordinate, then map coordinate gives block, then block gives graphics and behavior metadata. Drawing mainly cares about visual metatile composition. Movement mainly cares about behavior and occupancy. Both begin with coordinate translation and block access.

This is why week 5 belongs exactly where it does in the course plan. In weeks 1 and 2, we decomposed the creature RPG into cooperating runtime systems and learned to trace from data tables through globals, callbacks, tasks, scripts, structs, and concrete functions. In weeks 3 and 4, we grounded that in the map record, layout registry, object events, and the overworld load path. We already covered map headers and layout references, so I am not going to reopen that box today. Today we are past “how does a map get selected?” and into “once the map is live, how does the engine interrogate it every frame?” This is the transition from loading architecture to runtime architecture.

And that distinction matters for your later battle work. FireRed’s overworld tile query and Showdown’s battle hook query are cousins. Not twins, but cousins. Pokemon Showdown’s data model makes the hook pattern very visible. In pokemon-showdown/data/abilities.ts, chunk_da22cf969179258c, abilities are not described only as inert labels; the excerpt even includes ability rating commentary, which is metadata for human and tooling use, while the broader Showdown architecture supports abilities as data entries with effects that the simulator can call at relevant moments. Meanwhile, Showdown’s Dex and mods system lets different generations or formats reinterpret data. The research packet points us to pokemon-showdown/sim and files such as pokemon-showdown/sim/DEX.md as high-signal sources for that Dex and mod architecture. The lesson for us is not to copy that into FireRed’s overworld. The lesson is to recognize the architectural idea: stable data access plus contextual interpretation plus testable runtime hooks.

Now let us apply that idea backward into FireRed. FireRed does not have a TypeScript Dex object mediating tile queries in the same way Showdown mediates battle data. FireRed is organized around C source modules, globals, arrays, structs, and helper functions. But the shape is still there. In pokefirered/src/fieldmap.c chunk_eeb0180842f7ece9, the map block and tile behavior flow is the source-backed place to study how block access becomes behavior access. In chunk_77ef7f3f8bff9777, the helper flow matters because helper boundaries tell us what the original engine authors considered reusable questions. And in event-object movement, which our packet identifies through pokefirered/src/event_object_movement.c as the high-signal source for runtime movement claims after chunk review, object movement boundaries become part of the same runtime question. A tile may permit movement, but an object may occupy the destination. Or an object’s movement range may prohibit the step even when the tile itself is walkable.

Let me pause there. If you are designing the lab, do not make collision a property of the tile only. That is the most common architecture error in this assignment. Collision is a decision made from multiple layers. The tile behavior layer answers, “What kind of surface or map feature is here?” The map boundary layer answers, “Is this coordinate inside the loaded layout?” The object layer answers, “Is another actor occupying or reserving this coordinate?” The movement-rule layer answers, “Is this actor allowed to traverse this behavior from this direction in this state?” The final movement result is composed from those answers.

A good test case is a bridge or overpass. Even if your lab does not implement elevation, think about the design pressure. Two things may visually overlap but not collide because they are on different movement layers. The previous map lectures gave us the foundation for elevation and layout data, so you should already be suspicious of any collision system that takes only x and y and returns one universal answer. FireRed’s actual field systems have to handle richer cases than a toy grid. We are simplifying in lab, but we are simplifying in the direction of the real architecture, not away from it.

Here is a concrete movement attempt. The player is at world coordinate 5, 5. The camera origin is 2, 3, meaning the player is currently drawn at screen tile 3, 2. The player presses right. Your runtime computes the target coordinate as 6, 5. It asks the map block layer for the metatile at 6, 5. That metatile behavior says tall grass. Then it asks the object occupancy layer whether an NPC occupies 6, 5. No. Then it asks the movement rule layer whether the player walking mode can enter tall grass from the left. Yes. The move is accepted. Separately, the camera system asks whether the viewport should scroll, and the drawing system later asks which map coordinates correspond to each screen tile. Notice that the movement query did not draw anything. The drawing query did not decide whether movement was legal. They share map access, but they are not the same responsibility.

Now change one thing. Put an NPC at 6, 5. The tile behavior answer is still tall grass. The movement mode answer is still “walkable.” But the composed movement result is blocked by object occupancy. If your debug output says only “cannot move,” you have thrown away the most useful information. If your debug output says “blocked: object occupancy at 6, 5,” you can immediately distinguish a bad object table from a bad metatile behavior. That is the kind of diagnostic clarity I expect from advanced students.

This is also how you should read includes and module boundaries. In pokefirered/src/battle_setup.c, chunk_494d132a59422c85, the excerpt includes both field-facing headers such as overworld.h, fieldmap.h, event_object_movement.h, metatile_behavior.h, and battle-facing headers such as battle.h and battle_transition.h. I am not using that chunk to claim battle setup performs all tile queries; I am using it to point out a real architectural boundary crossing. Battle setup sits at a place where field state can lead into battle state. That is an example of the course-wide pattern: subsystems remain distinct, but gameplay crosses them. The player steps in grass; field movement and tile behavior participate; encounter logic may trigger; transition code moves the game into battle. You cannot understand the visible behavior by studying only one table or only one callback.

Pokemon Showdown gives us a different testing lesson here. Because Showdown’s simulator is built around deterministic battle turns and data hooks, regression testing can assert that a move, ability, or modded rule produces a specific result under a controlled battle state. The research packet points us to pokemon-showdown/test as a recurring module for regression testing, and to pokemon-showdown/sim for simulator turn architecture. For our FireRed-inspired lab, we can borrow the testing attitude without borrowing the domain. You should create sample movement attempts as regression cases. Given this grid, this camera, this actor table, and this movement mode, an attempted move should return this result and produce this updated state. That is the overworld equivalent of a simulator turn test.

Let us check understanding with a small oral quiz. I will describe three failures, and I want you to name which layer you would inspect first. The player cannot walk onto a normal-looking floor tile. First guess: metatile behavior or movement-rule interpretation. An NPC refuses to move inside its expected patrol area even though the tiles are walkable. First guess: object-event movement boundaries, not the visual tile. The map draws the wrong tile at the edge of the screen after the player moves. First guess: camera-relative coordinate translation or block lookup for drawing, not collision. Good. That separation is the point.

Now, one subtlety: do not overcorrect into a giant abstract query engine. FireRed is not architected as a modern entity-component system with a general query planner, and your lab should not become one either. The right abstraction is modest. Make the common questions explicit. “Get metatile at world coordinate.” “Get behavior at world coordinate.” “Can actor enter coordinate?” “Is coordinate occupied?” “Convert screen tile to world tile using camera origin.” These are enough. If you create a huge generic rule engine, you will spend your time debugging your framework instead of learning the map runtime.

This is where advanced judgment enters. Data-driven architecture does not mean all behavior must live in data. It means data should be structured so runtime systems can ask stable questions and produce consistent behavior. FireRed uses compiled data and C functions. Showdown uses TypeScript data files, Dex access, mods, scripts, and simulator hooks. Both can be data-driven in the architectural sense, but the mechanism differs. So when you write your lab explanation, be precise. Do not say, “FireRed works like Showdown.” Say, “Both codebases separate stored game facts from contextual runtime interpretation, but they implement that separation through different language and engine structures.”

Let me bring this back to the phrase from the end of the previous section: a tile answers questions, but only through the systems that interpret it. That is the conceptual spine of today’s lecture. It connects to the overall course because a creature RPG is full of things that look like static records but behave like runtime participants. A map header becomes a loaded map through the overworld runtime. A layout becomes collision and drawing through fieldmap helpers. An object event becomes a moving, blocking, script-triggering actor through object-event movement code. A move record becomes damage or status through a battle engine. An ability becomes an effect only when the simulator or battle engine reaches the right hook point. A save block becomes continuity only when load and write systems interpret it correctly.

So, for the next portion, we are going to stay with the lab-facing model and talk about how to structure the movement attempt itself: what gets computed before state mutation, what should be reserved before animation begins, and why camera movement should usually follow accepted movement rather than participate in deciding whether the step is legal. Keep the board diagram in mind: world coordinate, block lookup, behavior query, occupancy query, movement rule, result. If you can keep those boxes separate while still making them cooperate, you are no longer just drawing a tile map. You are building the first serious slice of an overworld runtime.

Now, let’s take that board diagram and turn it into a single movement attempt. I want you to imagine the player presses right. Not “the player moves right,” not yet. The input is only a proposal. The runtime receives a proposed direction, and the first mature design decision is that we treat that proposal as a query against the world before we treat it as a mutation of the world.

So, if our avatar is at world coordinate, say, x equals 10, y equals 7, and the player presses right, the candidate destination is x equals 11, y equals 7. That candidate coordinate is the center of the next few queries. We ask, what block is there? What metatile behavior does that block imply? Does the actor’s movement mode allow entry? Is another object already occupying or reserving that coordinate? Is there a special boundary rule, maybe ledge direction, water, doorway, counter edge, or map connection? Only after those questions return a legal result do we update the actor’s intended position and begin animation.

Board cue: I’m writing “input is a proposal” above the movement pipeline. Under it, I’ll write “candidate coordinate,” then “tile behavior,” then “occupancy,” then “commit.” That word commit matters. In a robust overworld runtime, movement has a pre-commit phase and a committed phase. Before commit, we are allowed to say no without changing persistent state. After commit, animation, camera scrolling, encounter stepping, trigger checks, and object-event updates can begin to observe that movement as real.

This is where FireRed is a particularly good architecture source. In the fieldmap material we are using this week, especially pokefirered/src/fieldmap.c chunk_eeb0180842f7ece9, the map block and tile behavior flow makes the map into something queried by coordinates. The runtime is not simply iterating over a picture. It can ask, at this position, what block data applies? And from that block, what behavior category is attached? The companion helper flow in pokefirered/src/fieldmap.c chunk_77ef7f3f8bff9777 reinforces the same theme: fieldmap support functions exist so that higher-level systems do not hand-parse the map every time they need an answer. They ask a helper, and the helper gives back runtime meaning.

Now, pause there, because this is one of those deceptively small ideas that affects the rest of the engine. If tile behavior is a runtime query, then many systems can share the same world vocabulary. Player movement can ask whether a tile blocks walking. Surf logic can ask whether it is water. Encounter logic can ask whether terrain supports an encounter. Field effects can ask whether the tile permits the action. Battle setup can include field-related headers and movement-related support without owning the map representation itself. The research packet points us to pokefirered/src/battle_setup.c chunk_494d132a59422c85, where battle setup includes fieldmap, metatile_behavior, field control, player avatar, event object movement, and battle transition headers together. The important architectural lesson is not “battle setup is map code.” It is the opposite. Battle setup can cooperate with map-derived meaning because the engine has already separated field representation, metatile behavior, avatar control, and battle transition responsibilities into named modules.

Let’s do a concrete step. Suppose our lab grid has a block table where block 3 means grass, block 4 means wall, block 5 means water, and block 6 means ledge facing down. The rendered tile art might make grass look like grass, but movement should not inspect pixels or sprite names. It should call something like getBlockAt(11, 7), then getBehaviorForBlock(block), and receive “tall grass” or “impassable” or “water.” If the player is walking and the destination behavior is water, the movement rule says no. If the player is surfing, the same destination might say yes. Same coordinate, same block, different actor capability. That is why the behavior query should not directly mean “passable true or false” in every case. It should mean “here is what this tile is,” and then movement rules interpret that meaning for the current actor and mode.

Check for understanding: if a tile is water, is the water tile itself passable or impassable? The advanced answer is, neither in isolation. It is water. Passability is a relationship among tile behavior, actor state, direction, and sometimes script state. Walking player, no. Surfing player, yes. Certain object events, maybe no. A cutscene-controlled object, perhaps yes if the script intentionally overrides normal rules. That distinction is how you avoid encoding too much policy into your lowest-level map accessor.

Now let’s bring object-event occupancy into the same movement attempt. We used object events last week as data-bearing map records, so I’m not going to re-teach their map header placement. We need only carry that foundation forward. At runtime, object events become actors with positions, movement states, facing directions, and collision participation. So when the player attempts to step from 10, 7 to 11, 7, the tile might be walkable grass, but an NPC may already be standing at 11, 7. Or more subtly, an NPC may not yet be standing there, but may have already committed to moving into it from 12, 7. If our runtime only checks current positions, two actors can accept movement into the same destination during the same update window.

That is why reservation is not a luxury. It is the difference between a grid runtime and a visual trick. Before animation begins, a committed move should reserve the destination coordinate. The actor’s visible sprite may still interpolate across frames, but the logical destination has been claimed. Other actors now query occupancy against both settled positions and reservations. In a lab implementation, I would represent this with two layers: occupied cells for actors not moving, and reserved destination cells for actors whose movement has been accepted but not visually completed. The exact data structure can vary, but the semantics should be explicit.

Board cue: next to “occupancy,” I’m adding two sublabels: “current” and “reserved.” If you only write “current,” your first demos will look fine, and then your first multi-object movement test will expose the flaw.

Let’s run the example slowly. Player at 10, 7 proposes right into 11, 7. NPC A is at 12, 7 and has just proposed left into 11, 7. If the update order processes player first, player reserves 11, 7, and NPC A is rejected or waits. If NPC A processes first, NPC A reserves it and player is rejected. That may be acceptable if the engine has a deterministic priority rule. What is not acceptable is both actors deciding yes because neither one has mutated its current coordinate yet. That creates a state contradiction masked by animation. Advanced engine bugs often look exactly like that: a contradiction hidden until a later system tries to reconcile it.

This is also why camera movement should normally follow accepted movement rather than decide movement legality. The camera is a view transform. It affects which part of the map is drawn, and it may affect when map connections or draw buffers need updating, but it should not be the first authority on whether the player may step. The player’s candidate world coordinate is world-space. The camera’s offset is screen-space. If you confuse those, you get bugs where the player cannot move near the screen edge because the camera math says something awkward, or where collision checks break when the camera scrolls between tiles.

In FireRed terms, the fieldmap source focus for this week, including pokefirered/src/fieldmap.c chunk_642df7a31e75f54c, is runtime support. That support is precisely what lets drawing, block lookup, and coordinate helpers cooperate without collapsing into one giant “screen tile” routine. Camera-relative map drawing is real and important, but it is downstream of world interpretation. The map exists as world data. The camera chooses a window over that world. The movement system should ask about world coordinates, not “whatever tile is currently under this screen pixel.”

Let me phrase that as a rule you can use in the workshop: collision uses world coordinates; rendering uses camera-relative coordinates. When an actor moves, the movement rule checks the destination in the world. After the move is accepted, the camera may scroll to keep the player framed. Then rendering draws the appropriate world blocks relative to the camera. If you make rendering coordinates the source of truth, every camera transition becomes a collision risk.

Now, there are exceptions, and you should be alert to them. Some old console engines use scrolling buffers, border padding, and partially loaded map strips, so the runtime support has to keep the camera and map buffer synchronized. But even there, conceptually, you want to preserve the distinction. The player did not become legal because the screen scrolled. The screen scrolled because the player’s accepted movement changed what should be visible.

Let’s compare this, briefly, to Pokemon Showdown, because it gives us a useful secondary mirror. Showdown is not our main architecture source for the overworld. It does not replace FireRed for fieldmap behavior, camera drawing, or object events. But Showdown is excellent for thinking about hooks and deterministic state transitions. In pokemon-showdown/data/mods/gen2stadium2/scripts.ts chunk_3480e574205d5d0f, the damage flow shown in the research packet checks immunity, then OHKO behavior, then damage callbacks, then level-based or fixed damage, and then continues through the calculation. That is battle code, not map code, but architecturally it is doing something familiar: it turns an attempted action into a sequence of runtime queries and hook points before final damage is applied.

The analogy is useful if we keep it disciplined. A FireRed movement attempt asks tile behavior, occupancy, and movement permissions before committing position. A Showdown move resolution asks Dex data, modded scripts, immunities, callbacks, and battle state before committing damage or effects. In both cases, the engine is not just reading data. It is staging a decision through a controlled pipeline. The data does not act by itself. The engine reaches the hook point, passes the relevant state, and only then does the behavior matter.

That helps us understand why Pokemon Showdown’s Dex and mods are such a strong comparison later in the course. A modded learnset or ability table is not inherently a battle. It becomes battle behavior when the simulator turn reaches the appropriate lookup or event hook. The research packet points to pokemon-showdown/data/abilities.ts chunk_da22cf969179258c as an example of data carrying ratings and ability meaning, and to the pokemon-showdown sim materials as a recurring module around Dex, move, battle, and simulator state. Again, not our overworld authority. But it reinforces the same architecture pattern we’ve been tracing since week 1: data table, runtime state, dispatch point, visible behavior.

And now connect that back to FireRed. The field tile does not “make” the player stop in the abstract. The movement attempt reaches a collision or behavior query. The result is interpreted by avatar movement code and object movement code. The source-use note in our packet flags pokefirered/src/event_object_movement.c as high-signal for object-event movement claims, and we use it after the fieldmap chunks because object movement depends on the lower-level map queries being meaningful. That ordering is important pedagogically and architecturally. First understand how the map can answer coordinate questions. Then understand how actors use those answers to decide motion.

Now, for the lab, I want you to build your movement attempt in a way that can be tested without graphics. This is where advanced students sometimes over-invest in rendering too early. You can test the serious architecture with printed movement attempts. Put the player at 2, 2. Put a wall at 3, 2. Put grass at 2, 3. Put water at 1, 2. Put an NPC at 2, 1. Then run four proposed moves: right, down, left, up. The correct results might be blocked by wall, accepted into grass, blocked by water while walking, blocked by occupancy. No sprite art needed. No camera needed. Just runtime queries and movement rules.

Then add camera after that. Let the camera have an origin, say cameraX equals 0 and cameraY equals 0. If the player’s accepted world position moves beyond some screen threshold, adjust the camera origin. Rendering asks, for each screen cell, what world cell is camera origin plus screen offset? That is the camera-relative map drawing part. But if the camera changes and your collision results change for the same world coordinates, you have coupled the wrong systems.

Let me check the room on that. If the player is at world coordinate 10, 7, and the camera is at 8, 5, what screen coordinate is the player drawn at? Yes, 2, 2, assuming direct subtraction and no pixel interpolation. If the camera moves to 9, 5 while the player remains at 10, 7, what is the player’s screen coordinate? 1, 2. Did the player’s world collision state change? No. Only the view changed. That is the mental model I want you to keep.

Now, one layer deeper: what gets computed before mutation? I would compute the actor’s current coordinate, proposed direction, candidate coordinate, destination block, destination behavior, actor movement capability, occupancy or reservation status, and any direction-sensitive rule. Ledges are the easy example. A ledge tile may allow movement only from one side to another. So if you store ledge behavior as merely “passable,” you lose the critical part. Direction matters. Similarly, a counter tile might block movement but allow interaction across it. That means “can move into” and “can interact with across” are different queries. Good tile behavior systems support multiple questions.

This is one of the reasons metatile behavior functions are more flexible than a single collision bit. The behavior category can feed different systems differently. Movement asks one kind of question. Interaction asks another. Encounter logic asks another. Field move logic asks another. Audio or footstep effects might ask yet another. If your lab starts with booleans, that is acceptable for a first pass, but by the end of the exercise, I want you to feel the pressure toward named behaviors and query functions.

Here is a small design smell to watch for: if your player movement code says, “if block id equals 4, reject; if block id equals 5, reject; if block id equals 6, do ledge,” you have tied movement policy to raw block identities. Better is: block id maps to behavior; behavior helpers answer semantic questions. That allows two different wall-looking blocks to share behavior, or two visually different tiles to both count as water, or a special story tile to reuse the same movement rule while changing art. FireRed’s architecture keeps pushing us in that direction: data tables and generated assets are real, but runtime helpers interpret them through stable contracts.

This also sets up week 6 and beyond. When we move from overworld maps into battle, inventory, UI, and save persistence, the same question returns: what is data, what is runtime state, and where is the hook that turns one into behavior? In battle, a move table entry becomes damage or status only when the battle turn reaches its resolution logic. In inventory, an item id becomes an effect only when item-use code dispatches it in the current context. In save, bytes become continuity only when loaded through the correct structures and version assumptions. In overworld, a metatile becomes collision, encounter terrain, or interaction affordance only when queried by the relevant runtime system.

So week 5 is not an isolated “maps week.” It is the bridge between the map records we studied in weeks 3 and 4 and the more general engine architecture we will keep using. You already know that a map header points to layout and events; we are not reopening that. Today’s contribution is that loaded map data must become queryable at frame time. The callback shell from week 1 gives us a place for per-frame updates. The task system gives us a dispatch structure. The map load sequence gives us the current world. Now fieldmap helpers, metatile behaviors, collision checks, camera transforms, and object reservations let that world answer immediate gameplay questions.

And that brings us back to regression testing, where Pokemon Showdown is again a useful comparison. Showdown’s simulator culture benefits from being able to run deterministic battle scenarios: choose teams, choose moves, advance turns, assert outcomes. We can imitate that mindset in our overworld lab. We do not need Showdown’s battle engine for map movement, but we can borrow the testing discipline. Given this grid, this actor state, and this proposed input, assert this accepted or rejected result. Given simultaneous movement reservations, assert the priority rule. Given camera origin and player position, assert the screen coordinate. Given a walking mode versus surfing mode, assert different outcomes for the same water tile.

That is the point where architecture becomes teachable and maintainable. If the only way to know whether movement works is to press buttons in a running game and watch sprites, you have a demo, but not yet a robust system. If you can run movement attempts as data, your map runtime has become inspectable. And when you later add animation, sound, camera smoothing, encounter rolls, and scripts, you can keep the core legality tests stable.

So, to close this portion without closing the whole lecture, keep the pipeline crisp. Input proposes. World coordinates define the candidate. Fieldmap lookup finds block data. Metatile behavior gives semantic meaning. Movement rules interpret that meaning in actor context. Occupancy and reservations protect shared space. Commit changes logical state. Animation and camera follow. Rendering draws the world through the camera. That sequence is not just a clean-room design. It is the shape FireRed keeps suggesting through the fieldmap chunks we are studying, and it is the same broader data-to-runtime pattern we will keep seeing when we compare FireRed’s battle and content systems with Pokemon Showdown’s Dex, mods, simulator hooks, and regression tests.

Now, let me draw one final comparison before we wrap the day, because this is where advanced architecture thinking starts to pay off. FireRed is our primary source for the overworld, and the fieldmap flow is the authority today. But Pokemon Showdown gives us a useful secondary contrast: not for map tiles, but for how a mature simulator turns data into runtime questions. In Showdown, battle effects are not just raw records. They are data records with hooks, callbacks, generation-specific overrides, and regression tests around turn behavior. That is why the research packet points us toward pokemon-showdown/sim and toward data mods like pokemon-showdown/data/mods/gen2stadium2/scripts.ts, chunk_3480e574205d5d0f, where damage calculation is shaped by checks like immunity, OHKO handling, fixed damage, and damage callbacks. Do you see the analogy? FireRed asks, “what does this tile mean for this actor right now?” Showdown asks, “what does this move or ability mean for this battle state right now?”

Those are not the same domain, but they are the same architectural question.

So, board cue here: I am writing “record, query, interpretation, commit.” That is our reusable pattern. In FireRed’s overworld, the record is the map block and metatile data. The query is the block lookup through fieldmap support, especially the flow we are grounding in pokefirered/src/fieldmap.c, chunk_642df7a31e75f54c, chunk_eeb0180842f7ece9, and chunk_77ef7f3f8bff9777. The interpretation is collision, encounter surface, ledge behavior, surfability, door behavior, or whatever tile behavior answers. The commit is movement state, camera state, object-event state, or script activation. In Showdown, the record is a Dex entry, move entry, ability entry, or mod override. The query is a simulator turn asking whether a hook exists and what it returns. The interpretation is battle legality, damage, immunity, priority, or secondary effect. The commit is the changed battle state after the turn.

And I want you to notice what this prevents. It prevents the beginner mistake of treating content data as if it were inert. Data in these games is not inert. It is dormant behavior. It becomes behavior when the runtime asks the right question at the right time.

Concrete example. Suppose our lab grid contains a tile with behavior “water,” another tile with behavior “wall,” and another tile with behavior “tall grass.” The player presses right. The input layer should not say, “move right.” It should say, “propose movement to x plus one.” The fieldmap layer resolves that candidate coordinate to a block. The behavior query returns a semantic category. Then the movement layer asks, “given this actor, current flags, and possible occupancy, is the step legal?” A player without surf cannot enter water. A player with surf may be able to enter water, but only if the transition rules allow it. Tall grass is passable, but it may attach an encounter query after the movement commit. Wall is not passable. Same coordinate proposal, different answers because the tile is a runtime query.

Now compare that to a Showdown move. A move is not just “base power 80.” In pokemon-showdown/data/mods/gen2stadium2/scripts.ts, chunk_3480e574205d5d0f, the excerpted flow shows damage logic checking immunity, OHKO handling, damage callbacks, level-based damage, and fixed damage before ordinary computation proceeds. That is battle data being interrogated by context. The move does not fully mean anything until there is a source, a target, a battle generation, and a turn state. Again: dormant behavior becoming live behavior through runtime query.

Check for understanding here. If I ask you, “where should the tall grass encounter roll live?” the answer is not “inside the input handler,” and it is not “inside the renderer.” It belongs after a successful movement commit, when the system knows the actor actually entered the tile. If I ask you, “where should the grass graphic be drawn?” that belongs in camera-relative rendering. If I ask you, “where should passability be decided?” that belongs in the collision and movement interpretation layer, using fieldmap lookup and tile behavior. Those three answers may all involve the same map coordinate, but they are not the same responsibility.

This is why our week 5 lab matters more than it may look at first glance. A grid map with metatile lookup, collision checks, camera offset, and object-event occupancy is not a toy if you build it with the right seams of responsibility. It is a compressed version of the overworld architecture. When your test says, “player at 5,5 attempts to move to 6,5; tile is wall; movement rejected; camera unchanged; occupancy unchanged,” you are practicing the same discipline we will later use for more complicated systems. And when your test says, “player enters grass; movement succeeds; encounter query becomes eligible,” you are separating movement legality from consequences of arrival.

Let me fold in one more prior course thread, but briefly, because we have already done the map-header and load-sequence work. Earlier, we treated map headers, layout references, object events, warp state, and CB2_Overworld as the foundation that gets the player into a live map. Today we moved one layer deeper. Once the map is live, every frame is not reloading the map. It is querying the map. That is the shift. Week 4 asked whether you could design minimal clone versions of map loading, script execution, party data, battle turns, item use, and save persistence. Week 5 raises the bar: can you make those clone systems stable under repeated runtime queries? Can your data survive being asked questions every frame without turning into scattered special cases?

And this is where regression testing enters the course plan. Showdown is valuable here because its architecture is built around repeatable battle simulation. Its Dex and mods structure, discussed in pokemon-showdown/sim and supported by the research packet’s emphasis on pokemon-showdown/data and pokemon-showdown/test, gives us a model of how content variants can be tested without rewriting the whole engine each time. FireRed does not hand us that same testing harness in the modern sense, but we can learn from Showdown without replacing FireRed as the source of truth. For our project, we can write small regression cases: “ledge blocks movement from one side but permits jump from the other,” “NPC reservation blocks simultaneous entry,” “camera offset changes draw coordinates but not world coordinates,” “grass effect only triggers after successful entry.” These are overworld equivalents of simulator turn tests.

Let me put the closing synthesis plainly. A creature RPG is not one engine; it is several cooperating query engines. The overworld queries maps. The movement system queries tile behavior and occupancy. The camera queries player position. Scripts query flags and variables. Battles query moves, abilities, species data, and turn state. Inventory queries item effects and permissions. Save code queries what state is durable. FireRed teaches this through C modules, globals, callbacks, tasks, map data, and fieldmap helpers. Pokemon Showdown reinforces the same idea through Dex records, mods, simulator hooks, and regression-oriented battle behavior. Different codebases, same architectural lesson.

So as you leave this lecture and move into the workshop, do not build “a grid that moves a square.” Build a miniature runtime. World coordinates are authoritative. Camera coordinates are presentation. Tile behavior is semantic data. Collision is an interpretation step. Occupancy is shared-state protection. Movement commit is the boundary between proposal and consequence. If you keep those boundaries clean in a small lab, then when we add camera scrolling, object-event movement, scripts, encounters, and later battle transitions, you will not be trying to rescue a tangled program. You will be extending a runtime that already knows how to ask the world precise questions.

## Source References
- pokefirered/src/battle_setup.c
- pokefirered/src/daycare.c
- pokemon-showdown/data/mods/gen2stadium2/scripts.ts
- pokefirered/src/pokemon_summary_screen.c
- pokemon-showdown/data/abilities.ts
- pokemon-showdown/data/mods/gen1/README.md
