# Input to Avatar Movement

Lecture ID: lecture_w06_d01
Week 6, Day 1

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

## Transcript
All right, let’s pick up from where we left the overworld last week. We are not going to reload Pallet Town from scratch today. We are not going to walk again through the entire warp-state-to-map-load path. You already did that work in the last module: warp destination state, map headers, layouts, metatile blocks, collision lookup, object events, and the role of CB2_Overworld as the map runtime callback. Today we use that as the floor under our feet. The map exists. The player avatar exists. The engine is in the overworld callback. The question now is much more immediate: the player presses a button, and the avatar either moves, fails to move, turns, talks, triggers a script, bumps into something, steps onto a warp, or does nothing because the field is not ready to accept control.

That sounds simple when described from the player’s side. “I pressed right, so my character walked right.” But architecturally, that sentence hides almost the whole discipline of field control. Input is not movement. Input is a request. Movement is one possible accepted consequence of that request, after the overworld runtime checks state, permissions, direction, tile behavior, object occupancy, scripts, and sometimes special modes like surfing, biking, ledges, forced movement, or scripted lockout.

So, if I write on the board, “button press equals movement,” I am going to cross that out immediately. The better version is: “button press becomes an avatar control decision.” And then under that, we need several branches: movement attempt, interaction attempt, field menu attempt, script dispatch, or ignored input because the avatar is gated. That is the center of today’s lecture.

Now, remember the course-level architecture. We have been decomposing FireRed as a creature-collector RPG into cooperating runtime systems: the runtime shell, overworld maps, event scripting, creature data, battle, inventory, UI, save, and link systems. In weeks one and two, the important idea was that the Game Boy Advance program is not organized around one giant “game loop” function where everything is obvious. Instead, behavior is distributed across callbacks, tasks, global state, data tables, and scripts. We saw that with AgbMain and main callback slots, including SetMainCallback2 in pokefirered/src/main.c, chunk_6cfd90f6d0136799, and with RunTasks in pokefirered/src/task.c, chunk_3ffebc0341225936. I am mentioning those only as a reminder of the runtime shell. Today, the interesting question is what this shell dispatches during normal map play.

When the overworld is active, player control is not the same thing as direct sprite manipulation. The avatar sprite is a visible artifact of a richer field-control system. The source focus for today is pokefirered/src/field_control_avatar.c, especially chunk_636f753078bf545a for avatar field control, chunk_79332c416dfb6ac9 for player interaction handling, and chunk_4488cb84aee4d6dd for field-control branching. We will also lean on pokefirered/src/fieldmap.c, chunk_eeb0180842f7ece9, because even though we covered tile behavior last week, the field-control code cannot decide movement without asking map questions. The point is not that field_control_avatar.c owns the whole world. The point is that it coordinates a decision across systems.

Let’s make this concrete. Suppose the player is standing in front of a sign and presses A. From the player’s point of view, a text box appears. From the engine’s point of view, that is not “the A button prints text.” The A button causes an interaction check. The interaction check asks, “What tile or object is in the facing direction? Is there an event object there? Is there a background event there? Is this a sign tile? Is the player currently allowed to interact? Is another script already running? Is movement locked?” If those checks produce a script pointer or an event, control shifts toward the script system and UI system. The visible result is text, but the architectural result is a branch from field input into event scripting and message UI.

Now suppose the player presses right while facing an open tile. That has a different shape. The input is interpreted as directional intent. The avatar controller may first turn the avatar if needed, may then evaluate whether the desired step is legal, may test collision, elevation, object occupancy, tile behavior, and special movement cases. Only after that does it start a movement action. So the move does not happen when the button is pressed. The move happens when the controller accepts the request and enters a movement state. This distinction matters for your lab this week, because your reducer should not return “new position” just because a direction exists. It should return a decision: accepted movement, rejected movement, interaction dispatch, warp trigger, object interaction, script dispatch, or no-op under gating.

Let me pause and check the room here. If I ask, “What is the difference between polling input and controlling the avatar?” the answer I want is not “one reads buttons and one moves the sprite.” That is too shallow. The stronger answer is: polling input gathers raw player intent, while avatar field control interprets that intent against runtime state and map/event rules. The controller is a reducer over input plus field state. It may cause movement, but it may also cause a turn, collision rejection, script lookup, menu opening, or nothing.

This is also why advanced architecture work requires us to be careful with ownership. The input subsystem can tell you that A was newly pressed or that a directional button is held. It should not know what a sign is. The map subsystem can tell you tile behavior and collision properties. It should not know whether the player has just tapped A. The script system can execute an event. It should not poll the D-pad every frame to decide walking. The avatar field-control layer is the mediator that composes these facts.

This is one of those places where FireRed looks simple because the end-user interaction is simple. But the internal architecture is doing exactly what large game systems do: it protects each subsystem from becoming everyone else’s dumping ground. If you violate that in your clone, you will feel it by week eight. If movement code directly opens bag menus, starts battles, changes map layouts, writes save fields, and mutates party data, you might get a prototype working, but you will lose the ability to reason about the runtime.

So let’s connect this to the full RPG stack. The runtime shell asks, “What callback is active this frame?” The overworld map runtime says, “We are currently in field play.” The field controller says, “Is player control available, and what did the input mean?” The map layer says, “Here is the tile and collision information.” The object-event system says, “Here are NPCs or objects occupying positions and here are their scripts.” The event scripting system says, “If an interaction resolves to a script, I can run it.” The UI system says, “If that script opens text, I can draw the message box and manage input while text is active.” The save system eventually records persistent results, such as flags or position. The battle system may be entered if a script or encounter calls for it. The inventory system may be entered if the player opens a menu or uses an item. The link system may constrain or redirect behavior in multiplayer contexts. One button press can be the first domino, but the domino path is not hardcoded as one line.

You saw a hint of this cross-system nature in the research packet’s high-value source chunk from pokefirered/src/battle_setup.c, chunk_494d132a59422c85. That file includes headers such as overworld.h, script.h, event_object_movement.h, fieldmap.h, field_control_avatar.h, field_player_avatar.h, battle.h, and battle_transition.h. We are not studying battle setup today, but that include cluster is evidence of the architectural crossing: battle entry is not isolated from field state. The field can lead to battle, and battle setup needs to speak to the overworld and script layers. That is the sort of coupling we want to identify and then discipline.

Now, let’s put a frame-by-frame example on the board. The player is on Route 1. The overworld callback is running. The player holds up. On frame N, input polling records that the up direction is held. The field controller sees that the avatar is idle and field control is not locked. It computes the intended facing direction. If the avatar is not already facing up, there may be a turn behavior first, depending on the exact control state and movement mode. If a step is attempted, the controller asks whether the tile one step ahead is passable. This is where last week’s tile behavior work becomes a dependency, not the lecture topic itself. The field map support in pokefirered/src/fieldmap.c, chunk_eeb0180842f7ece9, is part of the larger mechanism that lets game code query map blocks and tile behavior instead of embedding map facts inside input code.

Then the controller checks whether an event object blocks the tile. A standing NPC is not just a sprite; it is an object event with position, movement state, facing, local id, and possibly a script. If the target tile is blocked, the player may simply stop or turn. If the target tile is free, the avatar enters a movement action. That action takes multiple frames. During those frames, the player is not free to start a second independent step by magic. The avatar is in a movement state. The input may still be polled, but movement acceptance is gated.

That phrase, “movement state gating,” is one of today’s key terms. Gating means the engine refuses to interpret certain inputs while a higher-priority state is active. If the avatar is mid-step, if a script is running, if a message box owns input, if a transition is happening, if a forced movement is active, then normal field control cannot simply accept fresh movement commands. This prevents contradictory behavior. Imagine if you could open a sign text box while your avatar was halfway through a ledge jump, or trigger a warp while a script had locked the player in place for an NPC approach. The game would not merely look strange; its state machines would conflict.

Here is another check for understanding. Why do we need state gating even though the GBA reads buttons every frame? Because polling is not permission. Polling tells us what the player is doing physically. Permission tells us whether the current game mode is allowed to consume that input as field control. Good. That distinction will come back again when we talk about menus, battle command selection, naming screens, and link rooms, because each mode consumes input differently.

Now, let’s talk specifically about A-button interaction. In many student clones, A-button logic is implemented as, “If button A and facing NPC, talk; else if facing sign, read; else if facing item, pick up.” That is not a bad first sketch, but it tends to become brittle. FireRed’s field interaction handling, represented in our focus by pokefirered/src/field_control_avatar.c, chunk_79332c416dfb6ac9, is better understood as an ordered lookup problem. The engine must ask what kind of interactable is in the player’s facing position, and different categories have different priority and dispatch paths. An event object directly in front of you is not the same as a background event on a tile. A hidden item is not the same as a sign. A door warp is not the same as an A-button script. Some interactions are based on the coordinate in front of the avatar; others are based on the tile the avatar is standing on; others are automatic and do not require A at all.

So, in your mental model, do not make “A button” the owner of all event logic. Think of it as one trigger source into an event lookup system. Movement onto a tile is another trigger source. A map load can trigger scripts. A trainer seeing the player can trigger a script. A special field move can trigger scripts. The field-control layer is one entry point among several.

Let me give you a concrete example with two adjacent cases. Case one: you press A while facing an NPC. The controller checks that interaction is permitted. It looks in the facing direction, resolves an object event, turns the NPC or player as needed, and dispatches the NPC’s script. That script may open dialogue, give an item, start a battle, set a flag, or branch based on game state. Case two: you press A while facing a wall sign. There may be no object event at all. The controller instead resolves a background event or tile-based script and dispatches that. The visible UI may be identical, a text box at the bottom of the screen, but the lookup path differs. If your architecture collapses both into “thing in front has text,” you erase a distinction the engine needs for maps, flags, hidden items, and special cases.

This is where the course’s earlier “data table to callback to visible behavior” tracing remains useful. A map’s object events and background events are data. The runtime loads them into active map state. The field controller queries them. The script system executes the selected script. The UI renders the result. The player sees dialogue. That trace crosses data, globals, callbacks, tasks, scripts, structs, and source functions, which is exactly the skill the week two homework and quiz were checking. At week six, I expect you to make that trace without treating any one layer as magical.

Now, one subtlety: field control is not only about successful actions. Rejection is behavior. If the player presses right into a rock, the controller still did work. It interpreted input, checked facing, checked collision, possibly turned the avatar, possibly played a bump response or simply withheld movement. A collision rejection is a first-class result of the reducer. That is why the lab says your controller-to-avatar reducer should decide whether input causes movement, collision rejection, warp trigger, object interaction, or script dispatch. Rejection is not absence of architecture. It is a branch in the architecture.

Let’s make a small board model. I am drawing a box labeled “raw input.” An arrow goes to “field control gate.” From there, if closed, the result is “ignored by field movement.” If open, the next box is “classify input.” Directional input goes to “movement attempt.” A press goes to “interaction attempt.” Start might go to a menu branch, depending on context. The movement attempt box asks map and object questions. The interaction attempt box asks facing-position and current-position event questions. Both can lead to scripts. Movement can also lead to warp triggers or tile effects. And scripts can then lock field control, open UI, start battle, or modify state.

Notice the feedback loop. A script that starts from interaction may set a flag. That flag may later change what another interaction does. A movement step may trigger a warp, which changes the map state and avatar position. A battle may return to the overworld and restore field control. So “input to avatar movement” is the entry point into a much larger set of runtime state transitions.

The fact that FireRed’s source separates many of these responsibilities is also visible in other chunks from the research packet. For example, pokefirered/src/learn_move.c, chunk_af3598df6f092723, explicitly documents a move relearner state machine, with callback and menu states. That is not overworld movement, but it reinforces the same architectural pattern: player-visible behavior is often a state machine layered on callbacks and tasks. The pokemon summary screen include-heavy source in pokefirered/src/pokemon_summary_screen.c, chunk_e8e17a42bbf17d46, similarly shows how UI, party data, link considerations, menu helpers, and battle-related constants can meet in one feature. The lesson is not that every feature should include everything. The lesson is that complex RPG features are crossings between subsystems, and good architecture names the crossing points.

For field movement, the crossing point is especially delicate because it happens constantly. Every frame in normal play, the engine must decide whether the player controls the avatar, whether the avatar is already busy, whether an input edge matters, whether held input continues movement, and whether tile or object state blocks the request. Small mistakes here are felt immediately as sluggish controls, accidental double steps, missed interactions, or scripts firing at the wrong time.

Let me ask another check question. Suppose the player is holding up, and on the next frame presses A while the avatar is still walking between tiles. Should the sign one tile ahead activate immediately? In a well-gated field-control system, generally no. The avatar’s movement state owns the moment. The A press may be ignored for field interaction, or handled only after movement completes depending on buffering rules, but it should not freely dispatch an interaction against an unstable position. Why? Because the facing coordinate, current coordinate, and movement completion state must agree. If you dispatch while those are inconsistent, you can talk through objects, read the wrong sign, or trigger scripts from positions the map designer never intended.

This is why we talk about “attempt flow” instead of “movement function.” A function that moves the player one tile is too low-level to explain the user experience. The attempt flow begins earlier, at input classification and gating, and ends later, after either movement state starts, rejection happens, or another system takes control. In pokefirered/src/field_control_avatar.c, chunk_4488cb84aee4d6dd, our focus is exactly this kind of field-control branching. The important architectural claim is that the branch point is not an implementation detail. It is the policy layer for field play.

Now, as advanced learners, you should also notice the difference between deterministic state updates and presentation. The avatar sprite moving across pixels is presentation over time. The logical map position changes at a controlled point in the movement action. The camera may scroll. Object event coordinates and sprite coordinates must remain coherent. But the reducer we are designing for lab should first decide the semantic result. “Accepted move north” is the semantic result. The animation system can then realize that over frames. If you mix semantic movement and pixel interpolation too early, testing becomes harder, because your movement rules are hidden inside animation timing.

A clean lab design might take an input snapshot, an avatar control state, a map query interface, and an object query interface. It returns a decision object. I am not asking you to reproduce FireRed exactly. I am asking you to preserve the architectural separation FireRed teaches. The reducer can say, “blocked by collision,” “blocked by object,” “start movement,” “dispatch object script,” “dispatch background script,” “trigger warp,” or “no control because locked.” Then a separate runtime layer applies that decision. That separation lets you unit test movement policy without drawing sprites.

And that is the bridge from this lecture to the rest of week six. Today we are concentrating on the path from input to avatar movement. Next time, we will stay in the same source neighborhood but lean harder into interaction checks and field control: how the engine distinguishes object interactions, background events, tile-triggered effects, and script ownership of input. We will not suddenly leave the overworld. We are narrowing the lens from map loading to moment-by-moment control.

So, before we go deeper into the actual branch categories, hold this synthesis in your head: the overworld is not a passive map with a sprite on top. It is an active runtime mode. Field input is admitted only when the mode allows it. Avatar movement is an attempted state transition, not a direct consequence of the D-pad. Interactions are lookups against event data and map behavior, not hardcoded text boxes. And FireRed’s architecture gives us a practical example of how a creature-collector RPG keeps runtime shell, map data, event scripts, UI, battle entry, inventory access, save implications, and link constraints from collapsing into one untestable loop.

Now let’s continue from that model and start separating the two most common player intents: directional intent and action intent. Directional intent asks, “Can I move or turn?” Action intent asks, “Can I interact with what the avatar is facing or standing on?” Those sound like siblings, but they do not ask the same questions, and the engine cannot answer them with the same lookup.

So, if I press right on the D-pad, the directional intent is not “move one tile right.” It is more carefully, “the player is expressing a desire toward east.” That desire may become a turn-in-place, a step, a bump animation, a ledge hop, a forced movement, or nothing at all. And if I press A, action intent is not “talk.” It is more carefully, “query the interaction surface around the avatar, using the avatar’s facing direction and sometimes the tile underfoot, then dispatch whichever behavior owns that surface.”

Let me put that distinction on the board, because it is the hinge for the lab this week. Directional intent enters the avatar movement attempt pipeline. Action intent enters the interaction lookup pipeline. Both pipelines begin in field control, and both are gated by the current field state, but they diverge almost immediately.

In FireRed, our main source anchor here is pokefirered/src/field_control_avatar.c, especially chunk_636f753078bf545a for avatar field control, chunk_79332c416dfb6ac9 for player interaction handling, and chunk_4488cb84aee4d6dd for the field-control branching. The important architectural claim is not just that this file reads buttons. The claim is that this file mediates between low-level input and high-level game meaning. It is a reducer-like layer, although in C it is not packaged with that modern vocabulary. It takes a bundle of current facts, such as held keys, new keys, avatar facing, movement lock state, map tile behavior, event object state, script availability, and special map modes, and reduces them into one of a small number of consequences.

Now, let’s be precise about why that matters. Suppose we wrote the naive version. Every frame, if right is held, increase x by one pixel. If A is pressed, call TalkToNpc. That seems harmless when your world is a rectangle with one character. But in a creature-collector RPG, that is already wrong in maybe ten different ways. The right button might be ignored because a text box is open. It might rotate the avatar because the player just changed direction while standing. It might request movement, but movement is rejected because the tile ahead is blocked. It might request movement, be accepted, and then after the step completes trigger a warp tile. It might be overridden by a script that is pushing the avatar along a path. It might be disallowed during link activity. It might need to preserve a pending step animation rather than start a second one. So field control is not a convenience layer. It is where raw input is converted into legal field commands.

Here is the concrete example I want you to keep in your head. The avatar is standing in front of an NPC. There is also a sign one tile to the avatar’s left. The player is facing north and presses A. What should happen? We do not scan all interactable things nearby. We do not say, “nearest thing wins.” We ask what the avatar is facing, because A-button interaction is directional. The object event in front of the player has priority over the sign to the side because the interaction query is not a radius query; it is a facing query. If the player instead turns left and presses A, the sign becomes eligible. That one example is enough to show why movement intent and action intent need different coordinates. Movement asks, “what is ahead if I try to enter it?” Action asks, “what semantic target is in the facing interaction position, or underfoot in special cases?”

Check for understanding here. If I press A while facing a blocked tile, does the engine necessarily care that the tile is blocked? Not necessarily. For movement, blocked means “you may not enter.” For interaction, blocked may be irrelevant or even expected. A counter, a sign, a door, an NPC, a PC terminal, a bookshelf, all of those may be things you cannot walk into but can interact with. So collision is not the same as interaction. That is the point I want you to say out loud to yourself before you start the reducer lab.

Now, if we connect this back to the map and tile work from last week, we can do it without re-teaching the whole map system. You already know that tile behavior is queried from map block data rather than invented in the input loop. The current lecture depends on that. In pokefirered/src/fieldmap.c, chunk_eeb0180842f7ece9 is part of the tile behavior support we are using as a foundation. Field control should not know, in a hardcoded way, that a particular numeric tile means grass or water or a warp. It should ask the field map and metatile behavior layers what kind of surface is present. That gives us a clean separation: input code decides that a query is needed; map code answers questions about the world; behavior code interprets the answer; script code or movement code performs the consequence.

Let’s draw the flow as a spoken board diagram. Raw keys enter the field-control branch. The branch first asks, “is the avatar controllable right now?” If no, the input is either ignored or routed to another active mode. If yes, the branch separates newly pressed action buttons from held directional buttons. For directional input, it computes desired direction and asks whether the avatar should turn, step, collide, or trigger a special movement rule. For action input, it computes the facing target and asks whether an object event, background event, tile behavior, or script should respond.

Notice the order of those questions. We are not starting with pixels. We are starting with authority. Who is allowed to interpret this input right now? That is a recurring course theme. In week 1, when we talked about AgbMain and callback slots, the point was that runtime ownership is explicit. In week 2 and week 3, when we talked about generated data and headers as contracts, the point was that systems communicate through stable shapes. In week 4 and week 5, when we traced maps, object events, and collision, the point was that visible behavior emerges from data tables plus runtime state. Week 6 is where those ideas become tactile. You press a button, and all of those architecture decisions are suddenly in the path.

Let’s take movement gating in more detail. Movement state gating means the avatar cannot accept a new movement command just because the player is holding a direction. There is an avatar state. There are object event states. There may be a script context. There may be a field effect. There may be a menu or message box. There may be a task that owns a transition. So the movement attempt is conditional on the field being in a state where player control is admitted. This is why, in a reducer you write for the lab, I do not want to see a function named applyInput that simply mutates x and y. I want to see a function that returns a decision, something like no action, turn, attempt step, reject with collision, interact with object, dispatch script, trigger warp, open menu. You can name the variants differently, but the shape should express the architecture.

Here is a useful test. If your reducer cannot represent “the player pressed right but the avatar only turned to face right,” your model is too primitive. If it cannot represent “the player pressed right, a blocked tile produced a bump but no coordinate change,” it is too primitive. If it cannot represent “the player pressed A and a script begins without movement,” it is too primitive. If it cannot represent “the step succeeded and only after step completion a tile trigger fires,” it is too eager. That last one is subtle. Many field consequences are not instantaneous at button-down time. They are staged across frames, because movement animation and map transitions are temporal.

This is where the task and callback shell from earlier weeks becomes practical again. The overworld callback keeps the field runtime active; tasks and state machines advance small pieces over frames. We do not need to re-open CB2_Overworld today, but remember the design role: it gives the overworld a per-frame home. Field control lives within that running map context. Input is sampled each frame, but consequences may span many frames. A step begins in one frame, advances over several frames, and only later resolves into final position and follow-up triggers. Advanced engine design is full of this pattern: input is instantaneous, intent is discrete, animation is temporal, and gameplay consequences are staged.

Now let’s compare two A-button outcomes. First, the avatar faces an NPC. In that case, interaction handling in pokefirered/src/field_control_avatar.c, chunk_79332c416dfb6ac9, is the kind of source region we care about, because it represents the player interaction side rather than the walking side. The engine must determine whether an event object in the facing tile is interactable, whether that object has a script, whether the player should face the object, whether the object should face the player, and whether control should transfer to the script system. Second, the avatar faces a sign tile. There may be no object event at all. The query instead falls through to background event or tile behavior logic. The action button is the same physical button, but the dispatch target is different.

That is the difference between an input binding and a game command. The input binding is A. The game command might be talk, read, use, inspect, surf, cut, open, or do nothing. In a mature RPG engine, the button does not own the command. The world owns the command, and the button requests that the world reveal the eligible command.

Let’s pause for a check. Imagine the player is standing on a warp tile and presses A while facing an NPC. Which intent should win, the underfoot warp or the facing NPC? Be careful. In the usual field flow, a warp tile is generally movement-triggered when the avatar steps onto it or completes movement onto it, not because A was pressed. The A press should normally be evaluated as action intent against the facing interaction target. That means underfoot triggers and facing interactions belong to different moments in the field-control timeline. This is why your lab design should separate “post-movement tile resolution” from “action button interaction lookup.” If those are in the same if statement, you will almost certainly create priority bugs.

Now, I want to connect this to the complete creature-collector decomposition, because one of our course objectives is not merely to understand walking. Walking is the front door into the whole game. From field control, a player can open the inventory UI, talk to a trainer, trigger a battle, activate a warp, inspect an object, execute a script that modifies flags, or enter a link-sensitive feature. The overworld is therefore not isolated. It is the routing layer through which many other subsystems become reachable.

A trainer interaction is a good example. The field interaction detects a trainer or script-bearing event object. The event script may call battle setup. In the research packet, pokefirered/src/battle_setup.c, chunk_494d132a59422c85, is useful evidence for this larger architecture because its include set crosses the same boundary we are describing: task, overworld, item, sound, pokemon, script, event data, event object movement, field map, field control avatar, field player avatar, screen effects, message boxes, and battle transition. That is not accidental. Battle entry is not a separate program launched from nowhere. It is reached through field events, and it needs to coordinate avatar control, scripts, transition effects, party data, and battle state. So when we say “A pressed on trainer,” we are compressing a large multi-system handoff into a friendly phrase.

The same is true for inventory, though with a different path. Pressing Start, rather than A or a D-pad direction, may route to a field menu if field state allows it. That menu can lead to the bag. The bag can lead to item use. Item use can affect the field, the party, scripts, flags, or battle eligibility depending on context. The architectural lesson is that field control is not “movement code plus some extras.” It is a permission and dispatch surface for the overworld. It decides whether the player is currently allowed to ask the runtime for one of several high-level actions.

Now let’s return to movement, because the movement attempt flow has its own internal stages. Stage one is input normalization. If multiple directions are held, the engine needs a rule for which one is considered. Stage two is avatar availability. Is the player already moving? Is a script controlling them? Is a forced movement active? Stage three is direction handling. Does the avatar need to turn first, or is the avatar already facing the requested direction? Stage four is movement feasibility. What is the tile ahead? Is there an object there? Is the elevation compatible? Is the tile behavior passable for the current movement mode? Stage five is consequence selection. Start a step, reject with collision, start a special action, or defer to a tile behavior rule. Stage six is post-step resolution, which may include encounters, warps, scripts, or camera adjustment.

Do not memorize that as an official FireRed enum. Treat it as an architectural decomposition. The actual C code in pokefirered/src/field_control_avatar.c, especially chunk_636f753078bf545a and chunk_4488cb84aee4d6dd, is organized around the engine’s concrete functions and branches. But for our purposes as designers, the mental model is the reducer. Given input plus field state, produce a legal field decision.

Let me give you a second concrete example, this time involving a ledge-like movement. The player presses down while facing south at the edge of a ledge tile. A naive collision model might say the tile ahead is blocked or passable. But the game needs a richer behavior: if approached from the correct direction, the avatar may hop; from the wrong direction, the same tile boundary may reject movement. That means passability is not simply a property of the destination tile. It can depend on direction, current tile, destination tile, movement mode, and scripted state. This is why the tile behavior layer matters and why field control queries it rather than embedding all decisions directly in D-pad code.

Another check for understanding. If a tile has a special behavior, should field control immediately run the script as soon as the D-pad is pressed? Usually no. First, the movement has to be accepted. Then the avatar has to complete the movement or enter the special movement state. Then the engine can resolve what standing on or crossing that tile means. You should think in frame phases: intent, admission, animation, settlement, trigger. That phase separation prevents bugs where the player starts a warp while still visually standing on the previous tile, or triggers grass encounters when a blocked movement never actually entered grass.

This also explains why object interactions and object collisions are separate questions. An NPC can block movement because its object event occupies a tile. That same NPC can also be interacted with using A. But those two facts may be checked by different paths. Movement collision asks whether the avatar can enter the occupied tile. A-button interaction asks whether the object in the facing tile has interaction semantics. In many games, those are related but not identical. A decorative object might block movement but have no script. A hidden item might not block movement but can be found through an interaction lookup. A trigger tile might not respond to A but responds to stepping. Separating those categories is what lets content designers combine behaviors without rewriting input code.

If you are building a minimal clone, this is where I would expect your design to become more advanced than the week 4 homework. Back then, a minimal map loader and script executor were enough. For week 6, you need a field-control contract. I would write the core as a pure or mostly pure decision function if your language makes that convenient. Its inputs would include current avatar state, pressed buttons, held buttons, facing direction, map query interface, object query interface, and mode flags. Its output would be a decision object. Then an imperative shell would apply the decision by starting animation, launching script, playing bump feedback, or changing callback state. That split makes testing straightforward. You can create table tests: facing north, A pressed, NPC ahead, expect script dispatch; facing east, right held, empty tile ahead, expect movement; facing east, right held, wall ahead, expect collision rejection; facing south, standing on warp after completed step, expect warp dispatch.

Notice how this lab connects to the course-wide decomposition. Runtime shell owns the frame loop and callback. Overworld maps provide spatial data. Event scripting provides authored consequences. Creature data becomes relevant when scripts or encounters need party and species state. Battle is reached through trainer or wild encounter dispatch. Inventory and UI are reached through menu permissions and item actions. Save is affected because movement and scripts mutate persistent flags, position, party state, and inventory state. Link systems constrain what field actions are legal when communication features are active. A single D-pad press does not touch all of those systems, but the field-control architecture must be compatible with all of them.

That compatibility is the real design target. FireRed can have a town map, an indoor shop, a cutscene, a trainer battle, a sign, tall grass, a warp, a menu, and a link room without replacing the input loop every time. The input layer stays small because it delegates meaning to stateful subsystems. The map says what surfaces exist. Object events say who occupies space and what scripts they own. The script system says what authored story actions should run. Battle setup says how to leave field mode and enter battle mode. UI systems say whether menus can open and what they own while active. Save systems persist the consequences after the fact.

So, as we move into the next segment, keep these two sentences in mind. Directional input is a request to change or test avatar locomotion state. Action input is a request to resolve an interaction target in the avatar’s local field context. Those requests share the same controller, the same frame loop, and some of the same gating checks, but they are not the same operation. In the next part, we will follow that difference into priority rules: what happens when multiple possible interactions exist, how the engine chooses object events versus background events, and how field control prevents one physical button press from dispatching two pieces of game logic at once.

All right, pick up exactly there. Suppose the player presses A while facing north. That sounds trivial at the gameplay level: talk to the person, read the sign, inspect the tile, maybe surf, maybe cut, maybe do nothing. Architecturally, though, that one button press is a controlled arbitration problem. The engine must ask, “Who is allowed to consume this action?” And it must ask that question in a strict enough order that the player experiences the world as stable rather than random.

Let me put that on the board as a queue, not a code listing yet. First, is field control even accepting input right now? Second, is the avatar in a state where interaction is legal? Third, is there an object event directly in front of the avatar? Fourth, if no object event consumes it, is there a background event, such as a sign, hidden item, or scripted tile? Fifth, if neither object nor background event consumes it, is there a special field move or contextual action? And finally, if nothing matches, the A button is ignored for this frame.

That order is not arbitrary. It is what makes the world feel physical. If an NPC is standing in front of a sign, the expected result is usually that you talk to the NPC, not that you read the sign through them. If a cuttable tree occupies the interaction target, the special interaction belongs to that target, not to some unrelated background coordinate behind it. FireRed’s avatar field control code is doing this kind of prioritization in pokefirered/src/field_control_avatar.c, especially in chunk_79332c416dfb6ac9, where the player interaction handling is separated from the ordinary directional movement attempt. That separation is one of the key architectural points for today.

Now, notice the phrasing I just used: “consume this action.” That is a useful mental model, but be careful. We are not necessarily talking about an event system with a heap-allocated event object traveling through listeners like in a modern engine. This is C code on the Game Boy Advance. The consumption is usually represented by branch outcomes, state variables, script launch calls, task transitions, and input gating. But the design question is the same as in a modern engine: once one subsystem has accepted the input, the others must not also run as if the input were still available.

Here is the concrete example I want you to keep in your head. The player is standing one tile south of an NPC. Behind that NPC, one tile further north, there is a sign tile. The player faces north and presses A. At a data level, there are at least two possible things nearby: the object event for the NPC and the background behavior or event associated with the sign. At a user-experience level, there is only one sane result: the NPC talks. So field control cannot merely say, “Look at the coordinate in front of the player and fire whatever is in the map grid.” It must first resolve whether an object event occupies that target space and whether that object is interactable in the current context.

Now let’s connect this back to the source focus. In pokefirered/src/field_control_avatar.c, chunk_636f753078bf545a is the avatar field control material, the place to think about directional input and avatar control flow as one branch of the field controller. Chunk_79332c416dfb6ac9 is the player interaction handling material, the A-button side of the same problem. Chunk_4488cb84aee4d6dd is important because it shows field-control branching, meaning the system is not treating every frame as one flat “poll input and do everything” procedure. It is selecting a kind of field behavior based on current state and current input. Then pokefirered/src/fieldmap.c, chunk_eeb0180842f7ece9, gives us the tile behavior support, which becomes relevant after the avatar-facing coordinate has to be interpreted as terrain, sign, door, ledge, warp, counter, water, or some other map behavior.

So, if I draw this as a little diagram on the board, I want the left side to be button state and the right side to be world query. Button state alone is never enough. If I press A, the system still has to ask, “A in relation to what?” If I press up, it has to ask, “Up into what?” The common error in beginner clone projects is to build an input handler that directly mutates x and y. Press up, y minus one. Press A, call interact. That works for a blank grid demo. It fails immediately for a creature RPG because the input is not the behavior. Input is evidence used by a reducer, and the reducer consults avatar state, map state, object event state, script state, and tile behavior.

Let me pause and make this a check for understanding. If the player presses A while the avatar is still in the middle of a step animation, should the game start the interaction immediately, queue it, or ignore it? There is not one universal answer for every game, but for this architecture, the important answer is that the field controller has to make that decision explicitly. You do not want script dispatch to race with locomotion state. If the avatar’s logical position and drawn position disagree for several frames during a step, which coordinate should A use? The tile the player came from? The tile they are moving into? The tile they are visually closest to? FireRed’s style of field control avoids that ambiguity by gating interactions through movement state and field-control state. That is why movement state gating is not just polish. It is correctness.

And this is also where last week’s tile discussions become useful without reopening them. We already studied metatile data, block access, tile behavior queries, and collision checks. Today, those are services used by field control. We do not need to re-teach how a metatile behavior is stored. What matters now is the direction of dependency. The input layer does not know that a tile is a counter, water, a warp, or a sign by itself. It asks the map and tile behavior layer. Field control is the client; fieldmap and metatile behavior support are the source of environmental answers. That division is what lets the overworld feel data-driven without putting all the logic into the map data.

Now, I want to sharpen the distinction between movement attempt and interaction lookup. Directional input asks, “Can the avatar occupy or attempt to enter the adjacent tile?” Action input asks, “What is the semantic target in front of the avatar?” Those sound close because both involve the facing direction and the adjacent coordinate, but the meaning differs. For movement, collision rejection is a valid complete answer. You tried to move into a wall; the avatar bumps or remains in place. For interaction, collision may actually be evidence that there is something meaningful to inspect. A wall tile might be nothing. A sign-like tile might be a script. A counter might allow talking to a shopkeeper across the counter. An NPC blocks movement, but that same blocked target can become a successful A-button interaction.

That is an important design pattern. The same spatial relationship can mean “reject movement” in one branch and “dispatch script” in another. So if you are designing the lab reducer this week, do not write a function named something like resolveAdjacentTile and make it return one universal answer. You probably need a movement-oriented resolution and an interaction-oriented resolution, or at least a result type rich enough to preserve the distinction. Otherwise you will create bugs where every collision is dead space, or every interactable tile becomes walkable, or pressing A accidentally uses the same path as stepping forward.

Let me give another example. Imagine the player is facing a counter with an NPC on the other side. The avatar cannot move through the counter. Directional input toward the counter should fail as locomotion. But A input toward the counter may have to project one tile further or use special counter behavior to find the NPC beyond it. That kind of rule is exactly why interaction logic belongs in field control and supporting tile behavior queries, rather than in a naive movement function. In the source packet, the tile behavior support in pokefirered/src/fieldmap.c chunk_eeb0180842f7ece9 is relevant here because terrain and metatile behaviors are not passive art labels; they are queried by runtime code to decide what kind of field action is possible.

Now, let’s talk about priority more rigorously. A priority rule is a promise to designers. It says, “If you build a map with these overlapping possibilities, the engine will resolve them this way every time.” That promise matters because the maps and scripts are data authored under assumptions. If object events sometimes lose to background events depending on frame timing, map authors cannot reason about their own work. If pressing A in front of an NPC sometimes starts a hidden item script instead, the game feels broken and the authoring model becomes untrustworthy.

So the field-control branch is not just low-level code. It is part of the content contract. Headers are contracts across C modules, as we said earlier in the course, but runtime priority rules are contracts with the data. The data says, “Here is an object event at this coordinate.” The field controller says, “Given the player’s facing and state, I will ask whether that object should receive the interaction before I fall through to other possibilities.” This is why our course keeps returning to the chain from data record to runtime global to callback or task to visible behavior. The interaction result is visible behavior, but its reliability comes from that entire chain.

You can also see the broader architecture boundary if you compare this with battle setup. In pokefirered/src/battle_setup.c, chunk_494d132a59422c85, the include list itself shows how many systems can be pulled together when a field event crosses into battle: overworld, item, sound, pokemon, script, event data, metatile behavior, fieldmap, field_control_avatar, field_player_avatar, battle, battle transition, and more. I am not citing that chunk to teach battle setup today. I am citing it to remind you that field control sits upstream of major mode transitions. A trainer sight event, wild encounter, scripted battle, or special tile can start from overworld field logic and then hand control to the battle architecture. That is why clean input gating matters. A stray duplicate dispatch is not just a double text box. It can become a double transition, a corrupted script state, or an impossible player state.

Let’s do a small board trace. I will write “frame N” at the top. On frame N, the hardware buttons have a current state. The main callback for the overworld is already active from our previous weeks; we are not re-teaching CB2_Overworld today, but we are using it as the runtime foundation. The per-frame work eventually reaches tasks and field-control logic. The avatar has a facing direction, a movement status, and a current map coordinate. The field controller checks whether input is allowed. If a directional button is newly pressed or held in the accepted way, it moves into a movement attempt path. If A is newly pressed, it moves into an interaction attempt path. Those branches may both read nearby coordinates, but they should not both claim the same frame in contradictory ways.

Now, what happens if the player holds up and presses A at the same time? This is where advanced learners should stop thinking in terms of “the input” as a single scalar. The button register can contain multiple bits. The field controller imposes a policy. It may prioritize one class of input over another depending on state. It may ignore A while movement begins. It may allow A only when there is no movement command being resolved. The important thing is that the policy exists in code, not in our hopes. In pokefirered/src/field_control_avatar.c chunk_4488cb84aee4d6dd, the field-control branching is the kind of place where you look for that policy, because branching logic is where multiple possible requests become one chosen behavior.

Here is a useful way to phrase it for your lab: the controller-to-avatar reducer should produce one dominant field outcome per frame. That outcome might be no-op, start step, reject movement, trigger warp, interact with object, dispatch background script, open menu, or defer because field control is locked. If you let it produce a loose list of actions, you then need a second arbitration layer anyway. FireRed’s architecture tends to make these decisions through C control flow, script starts, flags, task state, and avatar movement status. Your clone can represent it as a tagged result type, but the conceptual obligation is the same.

Let me test that with a scenario. The player is facing a door tile and presses up. Is that movement or interaction? Good. It is directional movement, but the result may be warp trigger rather than ordinary occupancy. The player did not press A. The semantic action is still caused by a movement attempt. Now the player is facing a sign and presses A. That is interaction lookup, not locomotion. Now the player is facing an NPC and presses up. That is a movement attempt that likely collides or is rejected, not a conversation, unless the game has a special bump-to-talk rule, which FireRed generally does not use as the normal NPC interaction model. You see the pattern: the same neighbor coordinate participates in different questions.

This distinction will matter when we get to story progression in weeks 7 and 8. Event scripts are not merely text boxes. They are the story VM’s way of changing flags, giving items, starting battles, moving objects, and altering future map behavior. If A-button lookup dispatches the wrong script, progression can break. If movement gating allows the player to trigger a warp while a script owns control, progression can break. If an object event receives interaction while it is in the middle of a scripted movement, progression can break. So, again, field control is not just “feel.” It is a guardrail around narrative state.

Now, check your understanding again. Why should the avatar’s facing direction be stored as state instead of inferred only from the last pressed button? The answer is that interaction can happen after movement has stopped. If I walk north, release the D-pad, and then press A, the engine needs to know I am still facing north. Also, scripts can turn the player. Forced movement can change facing. Warps and map loads can establish facing. So facing is part of avatar state, not just input history. That is an architectural point you will see repeatedly in creature RPGs: the player’s visible pose often encodes future interaction behavior.

Let me also point out a subtle timing issue. A button interaction should typically use an edge, a newly pressed button, rather than continuously firing every frame while held. Movement often has repeat behavior: hold a direction, keep walking subject to step timing and collisions. Interaction usually should not repeat every frame because script dispatch is not idempotent. If you hold A in front of an NPC, you expect one conversation start, not sixty script starts per second. Field control prevents that both by checking the appropriate button transition and by handing control to script or message states that lock ordinary input. This is what I mean by one physical press not dispatching two pieces of game logic.

In a modern architecture, you might call this debouncing or command latching. In this codebase, it is embedded in the field-control and script/task state. The naming may differ, but the problem is universal. Inputs are noisy over time because a human button press lasts many frames. Game logic wants discrete commitments. The field controller is the translator from duration-based physical input to stateful gameplay commands.

Now, a brief recap before we go one level deeper. Directional input and A input share the frame loop, avatar position, facing direction, and map queries. They differ in the question they ask. Movement asks whether to step, fail, or trigger movement-adjacent behavior like a warp. Interaction asks what target should receive an action request. Object events generally need priority over background events because the player perceives objects as occupying the immediate world. Tile behavior support, like the material in pokefirered/src/fieldmap.c chunk_eeb0180842f7ece9, gives field control semantic facts about terrain. And the branching in pokefirered/src/field_control_avatar.c chunks_636f753078bf545a, _79332c416dfb6ac9, and _4488cb84aee4d6dd is where those facts are turned into player-visible outcomes.

For the next few minutes, I want to connect this to the rest of the complete RPG decomposition. Runtime shell gives us the per-frame place where input can be interpreted. Overworld maps give us coordinates, events, and tile behaviors. Event scripting gives us the executable consequence of many interactions. Creature data is usually not touched by ordinary walking, but it becomes relevant when a field event starts a battle, gives a creature, checks party state, or gates an HM-like action. Battle takes over when a field interaction or encounter changes mode. Inventory participates when A finds an item, a script gives or removes an item, or the player opens a menu. UI owns text boxes, choice menus, party screens, bag screens, and message flow. Save persists the effects after scripts change flags, position, party, inventory, or progression. Link systems are mostly outside today’s single-player field control, but they remind us that input and avatar state become much stricter when remote synchronization is involved.

That is the course-level reason week 6 starts here. We are now at the hinge between maps as loaded data and story as executed behavior. Weeks 1 through 5 gave us the shell, data paths, map loading, tiles, collision, and battle comparison foundations. Week 6 asks, “How does the player actually touch that world?” Not abstractly. Not through a UI mockup. Through per-frame field control, movement attempts, A-button lookup, and state gates.

So when you write this week’s lab reducer, make it boring in exactly the right way. Give it an input snapshot. Give it avatar state. Give it a map query interface. Give it an object-event query interface. Give it a script-dispatch result. Then force it to choose one outcome. If the avatar is locked, no-op. If a script owns control, no-op or script-controlled behavior. If a step is active, continue or ignore new interaction depending on your model. If a directional request is accepted, resolve movement, collision, or warp. If A is accepted, resolve object interaction first, then background interaction, then contextual tile action, then no-op.

And as we move into the next part, keep your eye on ownership. The hard part is not detecting that A was pressed. The hard part is proving that exactly one subsystem owns the consequence of that press, and that every other subsystem sees a consistent world afterward.

So let’s make that ownership idea operational. Imagine I pause the emulator on one frame, and I hand you six facts: the newly pressed buttons, the held buttons, the avatar’s facing direction, the avatar’s movement state, the map tile in front of the avatar, and the object event, if any, occupying that target position. That is enough to describe most ordinary field-control frames. Not every frame in the engine is ordinary, of course. Some are script-owned, some are menu-owned, some are transition-owned. But when we are in normal overworld control, that little bundle is the heart of the reducer you are going to write in lab.

Now, watch the ordering. I’m going to write this on the board as a priority chain, not as implementation syntax. First, “is field control allowed?” Second, “is the avatar already committed to motion?” Third, “is there a newly pressed interaction button?” Fourth, “is there directional intent?” Fifth, “what does the map or object system say about the attempted target?” That order is not decorative. If you flip it, the player-visible behavior changes.

For example, suppose the player is walking north and presses A during the middle of the step animation. In a naive input system, you might immediately query the tile in front of the current facing direction and dispatch an interaction. That will feel wrong, because the avatar’s visual position, logical position, and facing state are mid-update. FireRed’s field control code is careful about this class of problem. The source focus in pokefirered/src/field_control_avatar.c, chunk_636f753078bf545a, is valuable here because it sits at the point where avatar field control is not just “read buttons,” but “read buttons under movement-state constraints.” The code’s job is to keep input from leaking into subsystems that cannot yet accept it.

Let’s take a concrete scene. The player is standing in front of an NPC. The avatar faces up. The player presses A. What should happen? At the reducer level, the outcome is not “A was pressed.” The outcome is “dispatch an object interaction script for the object in the facing tile.” So we query the object-event layer before we query background events. Why? Because if an NPC is standing on a tile that also has some background behavior, the visible, player-facing affordance is the NPC. The player is saying, in effect, “talk to what I am facing.” That is an object-event question first. The player is not saying, “please inspect the raw metatile behind the NPC.”

That priority is one of those details that separates a real RPG field controller from a toy movement demo. A toy demo can say, “if A, inspect tile.” A creature-collector RPG has overlapping meanings on the same coordinate: an object event may occupy a map square, a background event may exist on or behind that square, a tile behavior may imply surf or door or ledge or counter behavior, and a script may have temporarily disabled normal control. The interaction code has to collapse all of that into one answer. The player should never experience the system as ambiguity. The player presses A, and the game confidently does one thing.

In the source packet, pokefirered/src/field_control_avatar.c, chunk_79332c416dfb6ac9, is the key anchor for this part of the story because it focuses on player interaction handling. Pair that with pokefirered/src/field_control_avatar.c, chunk_4488cb84aee4d6dd, which supports the branching logic around field control, and you can see the architectural pattern we have been tracing since week one: a tiny input event does not directly mutate the world. It enters a gatekeeper function, the gatekeeper checks state, and then it delegates to the one subsystem that owns the consequence.

Quick check for understanding. If the player presses A while facing an NPC, and the tile under the NPC also has a hidden-item background event, which interaction should win? Yes, the NPC interaction should win under the normal priority model. The hidden item should not be collected through the NPC’s body. That sounds obvious, but “obvious” behavior in a game is usually the product of very deliberate ordering in code.

Now let’s compare that with directional movement. Suppose the player holds right. Directional input is not a script dispatch by default. It is a movement attempt. And a movement attempt has a different decision tree. First, if the avatar is not facing right, the input may update facing without taking a step, depending on state and timing. Then, once the avatar is facing right and movement is allowed, the controller asks whether the destination can be entered. That question touches the map, object events, elevation rules, collision flags, and sometimes special tile behavior. We already spent the previous lectures on tiles as runtime queries and collision checks, so I am not going to re-teach metatile access here. Just carry that forward: the field controller does not need to know how every tile behavior is encoded. It needs a query interface that can answer, “what happens if the avatar attempts to enter this coordinate?”

And that is why pokefirered/src/fieldmap.c, chunk_eeb0180842f7ece9, matters in today’s lecture even though the psychological topic is input. The input layer depends on tile behavior support, but it should not become the tile database. If your controller-to-avatar reducer in lab has a giant hard-coded table of every tile kind, you have already blurred the boundary. The reducer can ask questions like “is this blocked,” “is this a warp,” “is this a ledge,” “is this a water tile,” but it should not become the canonical owner of map semantics.

Let me put another board note beside the priority chain: “input chooses intent; map and event queries classify consequence.” That sentence is a compact design rule. Input tells us what the player is trying to do. It does not, by itself, tell us whether the result is a step, bump, warp, script, or no-op. The world model decides that.

Here is a slightly richer example. The avatar is facing a counter. An NPC is on the other side of the counter. The player presses A. If we only query the adjacent tile, we might miss the NPC, because physically the NPC is not on the immediately adjacent square that blocks movement. But the game convention says that counters extend interaction reach. So the interaction system needs contextual geometry. It is not merely “look at coordinate plus direction.” It is “look at coordinate plus direction plus tile behavior plus special interaction rules.” That is exactly why interaction checks deserve their own lecture day this week. Movement and interaction share facing direction and map coordinates, but their spatial rules are not identical.

And notice the architecture lesson hiding there. Movement uses collision geometry. Interaction uses affordance geometry. They often overlap, but they are not the same abstraction. A wall blocks movement. A sign may block movement or may be background-only, but it is interactable from a neighboring tile. A counter blocks movement but permits talking over it. A warp may accept movement but not A-button interaction. A hidden item may accept A-button interaction while being invisible to movement. Advanced learners should be very suspicious of any implementation that tries to reduce all of these to a single “tile type” field with one meaning.

Let’s pause for a check. If I ask you, “what is the input meaning of pressing up?” the answer is not “move the player north.” The better answer is “request north-facing or northward movement, subject to avatar state and world queries.” If I ask you, “what is the input meaning of pressing A?” the answer is not “start a script.” It is “request interaction in the avatar’s current context, subject to field-control gating and priority rules.” That distinction will save your lab design.

Now, let’s connect this to the larger course architecture. We are in week six, the beginning of the module on input, events, and story progression. Weeks one and two gave us the runtime shell: startup, callbacks, task scheduling, and the idea that visible behavior is spread across callbacks, tasks, globals, data tables, and scripts. Weeks three and four moved through map headers, layouts, object events, and the map loading path. Week five compared battle data and simulator-style testability, with Pokemon Showdown only as a secondary comparison. Today, we are at the bridge between “the map exists” and “the player can make the map do something.” That bridge is not glamorous, but it is structurally central.

In FireRed terms, this is why field-control code imports and cooperates with so many other modules over the full project. We saw in the research packet that pokefirered/src/battle_setup.c, chunk_494d132a59422c85, includes field_control_avatar.h and fieldmap.h alongside battle, script, overworld, event object movement, and transition headers. That does not mean field control owns battle. It means field actions can route toward battle setup through controlled interfaces. A trainer’s line-of-sight event, a wild encounter after a step, or a scripted battle after talking to an NPC all begin as field-world events but eventually hand ownership to battle setup. The correct mental model is a relay of ownership, not one enormous god system.

Let’s make that relay concrete. A directional press may become a successful step. A successful step may trigger a tile callback, a warp, a wild encounter check, a trainer sight check, or nothing. If it becomes a wild encounter, field control should not execute the battle turn loop. It should arrange the transition and hand off to battle setup. If it becomes a warp, it should not manually rebuild every map subsystem from scratch. It should feed the existing warp and map-loading path we already studied. If it becomes a script, it should not interpret all script commands inline. It should dispatch to the script system and release normal avatar control until the script gives it back.

That handoff discipline is what lets the whole creature RPG remain understandable. Runtime shell owns frame progression. Overworld callback owns the map runtime frame. Field control owns normal player intent interpretation. Map and object systems answer spatial questions. Script system owns story-command execution. Battle owns turn resolution. Inventory and UI own menu interaction. Save owns persistence. Link systems own synchronized multiplayer behavior. The lecture objective asks you to decompose the full RPG into those systems, and today’s contribution is showing where input enters that decomposition.

Let me give you a failure mode I have seen in student engines. The student writes an update function called updatePlayer, and inside it there is input polling, walking animation, collision, NPC dialogue, item pickup, door warps, random encounters, cutscene flags, music changes, and sometimes even battle initialization. At first, that feels productive. One file, one player, one update loop. But the moment you add a second control mode, such as a menu, a scripted cutscene, a bike, surf movement, strength pushing, ledges, or multiplayer constraints, that function becomes a knot. You cannot prove ownership because everything is allowed to do everything.

The FireRed-style lesson is not that every project must copy its exact C layout. The lesson is that the field controller should be a disciplined dispatcher. It can be stateful. It can be complicated. But its complexity should be about priority, gating, and delegation, not about privately reimplementing every subsystem.

Now, if you are thinking ahead to the workshop, here is how I want your reducer to behave. I am not asking you to reproduce every FireRed edge case. I am asking you to model the architectural shape. Your reducer gets an input snapshot. It gets an avatar state. It gets a map-query service. It gets an object-query service. It returns one outcome. The outcome might be “continue movement,” “turn in place,” “attempt step,” “blocked bump,” “warp,” “object interaction,” “background interaction,” “script dispatch,” or “no-op.” The important constraint is that it returns one dominant result, not five half-results.

And I want you to include state gating explicitly. Do not bury it in convenience helpers. Have a visible early question: who currently owns field control? Normal player input? Script? Movement animation? Menu? Transition? Once you ask that first, many confusing edge cases become simple. If a script owns control, A-button presses do not talk to nearby NPCs. If a movement animation owns control, directional input may be buffered or ignored depending on your design, but it should not create a second overlapping step. If a menu owns control, the D-pad navigates menu options, not the avatar. Same physical buttons, different owner, different meaning.

That sentence is worth repeating slowly: same physical buttons, different owner, different meaning. This is why input polling is not the same thing as input semantics. Polling tells us which buttons changed. Semantics come from the active state machine.

Let’s do one more concrete trace. The player stands one tile below a sign. They press A. Frame begins. Runtime callback runs the overworld frame; we are using CB2_Overworld as prior foundation here, not re-opening that lecture. Field control is allowed because no menu, transition, or script has control. The avatar is not mid-step. The A button is newly pressed. The interaction code looks in the facing direction. It does not find an object event. Then it checks background interaction or tile-based interaction. It identifies the sign event or background script. It dispatches the script. After that dispatch, normal field control is no longer free to interpret the same A press as movement, item use, or anything else. The script now owns the next sequence of player-visible behavior.

Now change one fact. Same avatar, same sign, but the player is holding up instead of pressing A. This is no longer an interaction trace. It is a movement trace. The controller may attempt to step north. The map query rejects entry because the sign blocks movement or because the tile is not enterable. The result is a blocked movement response, maybe a bump-facing state, maybe a sound or animation depending on details. It should not read the sign text. Why? Because movement intent and interaction intent are different even when they aim at the same coordinate.

That is the kind of distinction your tests should capture. Test that A in front of a sign dispatches the sign script. Test that up into a sign does not. Test that A during script ownership does nothing at the field-control level. Test that movement into a warp returns a warp outcome, while A facing the same warp tile does not necessarily warp. Test that an object event wins over a background event when both appear to be reachable. These are not just gameplay tests. They are architecture tests for ownership and priority.

Before we move on, let me ask the room one more thing. Where should hidden-item detection live? Not the item data itself, but the decision that pressing A in this spot should look for a hidden item. Think it through. It should be in the interaction path, using event or background query support, not in raw directional movement. If you put it in movement, then walking over hidden items would become dangerously coupled to finding them. If you put it in inventory, the bag system suddenly needs spatial map knowledge. So the field interaction layer asks the world, “is there an interaction here?” and if the answer is “hidden item script or special,” then script or item systems can take over from there.

Good. That is the level of separation I want.

Now, let’s return briefly to the source anchors. The reason I keep naming pokefirered/src/field_control_avatar.c, chunk_636f753078bf545a, chunk_79332c416dfb6ac9, and chunk_4488cb84aee4d6dd, is that this file is not just a miscellaneous input file. It is the place where field input becomes avatar-world intent. And the reason pokefirered/src/fieldmap.c, chunk_eeb0180842f7ece9, belongs in the same lecture is that avatar-world intent cannot be resolved without map behavior queries. Input and map are decoupled, but they meet every frame under normal control.

So, the recap before we deepen this in the next segment is this. Do not model overworld input as “buttons directly cause actions.” Model it as “buttons propose intent to the active control owner.” Normal field control accepts that intent only when avatar state allows it. Movement intent is resolved through movement gating, collision, tile behavior, object occupancy, and possible transition outcomes. Interaction intent is resolved through a priority lookup: object first, then background or tile context, then specialized field actions, then no-op. Every accepted result hands ownership to exactly one next subsystem.

And that prepares us for the second half of the week. Today, we are building the input-to-avatar chain. Next, we will zoom in on interaction checks and field control as a richer system: not just “can I move,” but “what does this place mean when I face it, press A, step onto it, or trigger it through a script?” Keep the reducer model in your head as we go, because it gives us a clean way to reason about the messy cases without pretending the game world is simpler than it really is.

So let’s keep going from that reducer idea and make it more precise. When I say “reducer,” I do not mean FireRed literally has a modern Redux-style function named reduceInputToAvatarAction. It does not. I mean there is an architectural shape here that is useful for us as advanced readers of the engine. The game takes a compact input state, combines it with overworld state, player-avatar state, map geometry, object events, and script gating, and then produces exactly one field-control outcome for that frame or short sequence of frames. The source we are anchoring this in is pokefirered/src/field_control_avatar.c, especially chunk_636f753078bf545a for avatar field control, chunk_79332c416dfb6ac9 for player interaction handling, and chunk_4488cb84aee4d6dd for the field-control branching logic.

Now, I want you to notice something subtle. Earlier in the course, we treated the runtime shell as the machinery that repeatedly gives the overworld a chance to advance. We are not going to re-teach CB2_Overworld here, but we are absolutely using it as a foundation. The input-to-avatar chain only makes sense because the overworld is already in its per-frame loop. The map is already loaded. The player object already exists. Collision and tile behavior queries already have something concrete to query. That means today’s question is not “how does the game exist?” It is “given that the map runtime exists, how does a human button press become a field decision?”

Let me draw the mental version on the board. On the left, write raw buttons. Not hardware details today, just the semantic buttons: D-pad direction, A, B, Start, Select, maybe registered item inputs. In the middle, write field mode. Is the player free? Is a script running? Is an object movement active? Is a message box up? Is the player avatar already stepping from one tile to the next? On the right, write accepted command. Move north. Turn to face east. Talk to object. Read sign. Trigger surf. Open menu. Do nothing. That “do nothing” is important, by the way. In a tight game loop, no-op is not a failure. It is a valid result. Most frames in a real game are no-ops with respect to starting new field actions.

Here is the first advanced point: input is not authoritative. Input is only a request. This is a distinction that separates a toy prototype from a creature-collector RPG engine. In a prototype, pressing right may immediately set x equals x plus one. In FireRed’s architecture, pressing right proposes an intent. The field-control layer asks whether that intent is legal, whether it conflicts with ongoing motion, whether it maps to movement or facing, whether there is an edge transition, whether a tile behavior interprets it specially, and whether another subsystem should take ownership. That ownership transfer is one of the recurring themes of this course. The runtime shell calls the overworld; the overworld delegates to field control; field control may delegate to avatar movement, event scripting, object interaction, menu handling, battle setup, or map transition.

A concrete example. Imagine the player is standing in front of an NPC in Viridian City, facing north, and presses A. The movement reducer, if we can use that term, should not try to move the avatar. It should inspect interaction context. First, is player control allowed this frame? If yes, then what is the player facing? North. What tile is immediately north? Is there an object event there? If there is an NPC object occupying that facing tile, then object interaction wins. The engine turns or addresses the NPC, selects the script attached to that object event, and field control’s job is essentially complete for that input. Script execution now owns the next piece of visible behavior. That priority structure is why pokefirered/src/field_control_avatar.c chunk_79332c416dfb6ac9 is so important for us: it is not merely “A button code.” It represents the field’s policy for interpreting interaction intent.

Now compare that with standing in front of a sign. Same A button. Same facing direction. But no NPC object occupies the facing tile. The lookup continues. The engine asks whether the tile, background event, or map-defined interaction can answer the request. This is where our previous map-data weeks become useful without being repeated. A sign is not a creature. It is not a battle participant. It is usually map context plus script data. So the accepted command becomes script dispatch from a background or tile interaction rather than object interaction. In both cases, the user pressed A. The visible behavior is text. But architecturally, the source of the behavior is different.

Check your understanding here. If I ask, “Does the A button open text?” the correct advanced answer is no. The A button requests an interaction. The field-control layer resolves that request against object priority, facing direction, tile context, special actions, and gating state. Text is only one possible downstream effect. If you can say that cleanly, you are now reading this part of the engine at the right level.

Let’s add movement now. Suppose the player presses right while standing on a normal walkable tile. The engine first has to decide whether the avatar is allowed to accept a new movement request. If the avatar is already mid-step, no new tile movement begins. That might sound obvious, but it is one of the reasons grid-based movement feels stable. Without that state gating, you get diagonal leaks, skipped collision checks, animation desynchronization, or object events missing their chance to trigger. So the field-control code is not just checking “button pressed?” It is checking “button pressed while the field is in a state that can consume it?”

After that, the direction becomes an attempted movement. Attempted is the key word. The system looks at the destination tile and at occupancy. The tile behavior support in pokefirered/src/fieldmap.c chunk_eeb0180842f7ece9 matters because the field-control decision needs a vocabulary for terrain. The tile is not just an index into graphics. It can be interpreted as ledge, door, water edge, tall grass, warp, impassable surface, counter, or something else depending on behavior metadata and surrounding state. Again, we are not re-teaching metatile storage today, but we are using the fact that tile behavior queries turn raw map blocks into runtime decisions.

Let me phrase this as a design rule you can carry into the lab: never let the controller move the avatar directly. Let the controller produce intent, and let a field reducer consume intent plus world state. If the reducer says movement accepted, then and only then does avatar movement begin. If it says collision rejection, maybe the player turns to face the blocked direction and plays a bump-like response, but does not change tile. If it says warp trigger, movement may be accepted and then hand ownership to map transition. If it says object interaction, no movement happens at all, but script dispatch begins. This is exactly the kind of controller-to-avatar reducer you will write in the workshop.

Now, I want to connect this to the larger architecture objective for the week. We are decomposing a complete creature-collector RPG into runtime shell, overworld maps, event scripting, creature data, battle, inventory, UI, save, and link systems. Field control sits at a crossroads among several of those. It is part of the overworld, but it is also the front door into event scripting. It can lead to inventory, for example if Start opens the menu or a registered item is used. It can lead to battle, for example through trainer interaction or wild encounter logic after movement. It can lead to save or UI indirectly through menu systems. It can lead to link systems in special facilities. The research packet’s broader source map reinforces this: pokefirered/src/battle_setup.c chunk_494d132a59422c85 includes dependencies such as overworld, script, event object movement, metatile behavior, fieldmap, field_control_avatar, and field_player_avatar, which is a nice piece of evidence that battle entry is not isolated from field control. Battle setup is downstream from overworld context.

This is why I keep pushing you away from thinking in terms of “the movement file” or “the battle file” as isolated boxes. The engine is a set of cooperating state machines. Field control is one of the places where the cooperation becomes visible. A player takes a step. That step may simply animate. Or it may trigger a warp. Or it may cause an encounter check. Or it may place the avatar in front of a trainer whose line-of-sight script takes over. Or it may be rejected because an object event occupies the destination. In each case, the same human action, pressing a direction, enters the same general field-control area, but exits into a different subsystem.

Let’s do a more detailed example, because this is where advanced students usually find the hidden complexity. Picture the player standing one tile south of a door tile, facing north. The player presses up. The requested action is movement north. Field gating says the player is free. Collision says the destination is enterable or specially enterable. Tile behavior says this tile is a door or warp-like transition, depending on the map’s configuration. Avatar movement may begin, but the accepted result is not just “new coordinate.” The result includes a transition responsibility. The warp subsystem or script subsystem must be prepared to take over once the movement reaches the correct point. That is a different outcome than stepping north onto ordinary floor.

Now picture the player standing one tile south of a counter with a shopkeeper north of the counter. The player presses A while facing north. The adjacent tile may be a counter tile, and the NPC may be beyond it, not occupying the immediately adjacent tile. Good field-control logic cannot only ask, “Is there an object exactly one tile ahead?” It may need special interaction rules for counters, tile behaviors, or object reachability. This is why interaction checks are richer than movement checks. Movement asks, “Can my body enter this location?” Interaction asks, “What meaningful thing is being addressed by my facing direction and context?” Those are related but not identical questions.

Put another way, collision is about physical permissibility. Interaction is about semantic addressability. A wall blocks movement, but a sign on a wall can be addressable. A counter blocks movement, but a clerk across the counter can be addressable. Water may block ordinary walking, but with the correct field move or state it may become a surf prompt. This is the conceptual center of the second half of the week, and it begins here in the input-to-avatar lecture.

Let’s pause and check for understanding again. I’ll ask it in a way that sounds like an exam question. A player presses A while facing a tile. Name two reasons the engine might not dispatch the script for the tile immediately. One, an object event may have higher priority, so an NPC or interactable object may consume the interaction. Two, global or local gating may prevent player control because a script, movement animation, message, transition, or other field state already owns the frame. You could also say that the tile may not have an associated background event, or that a special field action may intercept the request. The important thing is that interaction dispatch is conditional, not automatic.

Now let’s talk about movement state gating in more precise terms. In grid movement, the avatar’s logical position and visual position are not always identical during a step. At the beginning of a step, the logical system may know the destination, while the sprite is still animating between cells. During that interval, accepting another movement input as if the avatar were stationary is dangerous. If you allow the player to queue or interrupt carelessly, you can desynchronize object collision, camera motion, encounter checks, and script triggers. FireRed’s field-control architecture treats movement as a stateful action, not just a coordinate assignment. The relevant field-control branching in pokefirered/src/field_control_avatar.c chunk_4488cb84aee4d6dd is useful evidence for this larger claim: the control path is explicitly branching based on what kind of field action is currently permissible and what kind of input has arrived.

In your reducer for lab, I want you to model this with boring clarity. Your reducer should accept an input like direction or A button and a state like “idle,” “moving,” “script locked,” or “menu open.” If the state is moving, a new direction should probably return no new command, or perhaps update facing intent only if your simplified design supports buffering. If the state is idle and a direction exists, it checks destination. If blocked by collision, return collision rejection. If walkable, return movement accepted. If the accepted destination contains a warp trigger, return movement accepted with pending warp, or return warp trigger after movement completion, depending on how you structure the reducer. The exact implementation is less important than the ownership boundary.

And yes, I am deliberately using the word ownership. In a codebase like this, bugs often happen when two systems believe they both own the next visible behavior. The field thinks the player can move while a script thinks it owns the avatar. The menu thinks it can open while a transition is fading. A warp begins while an object movement task is still active. Mature architecture does not merely have many features; it has rules for who is allowed to act at a given time. FireRed’s callback, task, script, and field-control layers are all different answers to the ownership problem.

Let’s connect this back to creature data and battle for a moment, because otherwise movement can feel too local. When movement through grass eventually leads to a wild battle, the player did not directly press a “battle” button. The player pressed a direction. The field accepted movement. The destination and map context permitted or requested an encounter check. Battle setup then prepared a transition into the battle engine. The inclusion relationships in pokefirered/src/battle_setup.c chunk_494d132a59422c85 make that architectural path visible: battle setup depends on overworld, script, fieldmap, metatile behavior, and avatar field-control-related headers. That does not mean all battle logic lives in field control. It means battle entry is a negotiated handoff from field context into battle context.

Same with inventory and UI. Pressing Start is not “draw menu now” in a vacuum. The field must be in a state where the menu is allowed. The player cannot open the menu during a forced movement, a cutscene, or a transition. Once allowed, field control hands off to UI or menu systems. The UI becomes the owner of input for a while. This is a pattern you saw back in the move relearner material, where pokefirered/src/learn_move.c chunk_af3598df6f092723 describes a menu-oriented state machine with callbacks and menu states. The details differ, but the architectural lesson is the same: input interpretation belongs to the active mode. Field input belongs to field control. Menu input belongs to menu control. Battle input belongs to battle control.

Let me say that one more time because it is a useful diagnostic sentence: buttons do not have universal meanings; active modes give buttons meanings. A means “talk” in the field, “confirm” in a menu, “advance text” in a message box, “choose command” in battle, and maybe nothing during a fade. A button’s physical identity is stable. Its semantic meaning is mode-dependent.

Now, if you are designing a clone engine, this is where you should resist the temptation to create one giant input handler. It feels efficient at first. You write handleInput, and inside it you check field, battle, menu, save, link, and everything else. That approach collapses ownership. It also makes it harder to test, because every test must construct too much world state. A better architecture is layered. The runtime shell polls or receives input. The current high-level mode receives the input. The mode-specific controller reduces it into a domain command. That command either mutates local state or hands control to another subsystem through an explicit transition.

For FireRed, the field-control material gives us the domain command layer for the overworld. The map and fieldmap code supply terrain meaning. Object-event code supplies dynamic occupants and scripts. Script code supplies story progression. Battle setup supplies battle transition. UI modules supply menu and message ownership. Save and link systems sit farther away, but they still depend on these transitions being disciplined.

I’ll put one final board example up before we move on. Imagine a table with three columns: input, context, result. First row: D-pad east, avatar idle, destination walkable. Result: start movement east. Second row: D-pad east, avatar idle, destination blocked by wall. Result: face east or reject movement, no coordinate change. Third row: D-pad east, avatar mid-step. Result: no new movement command. Fourth row: A button, facing NPC. Result: object script dispatch. Fifth row: A button, facing sign, no object. Result: background or tile script dispatch. Sixth row: A button, facing water with appropriate capability. Result: specialized field action prompt or dispatch. Seventh row: Start, script running. Result: no menu open. Eighth row: Start, field idle. Result: handoff to menu UI.

That table is not just a teaching aid. It is very close to how I want you to think when you write your reducer. Every row is a test case. Every row protects one architectural rule. If your reducer cannot express those rows cleanly, it is probably mixing responsibilities or hiding important state.

So the recap for this segment is: field control interprets input as intent, not as direct mutation. Movement intent flows through state gating, collision, tile behavior, object occupancy, and transition checks. Interaction intent flows through priority lookup, starting with object context and then moving into background, tile, or specialized field actions. Accepted outcomes hand ownership to exactly one subsystem: movement, script, warp, menu, battle setup, or no-op. The source focus for this is pokefirered/src/field_control_avatar.c chunk_636f753078bf545a, chunk_79332c416dfb6ac9, and chunk_4488cb84aee4d6dd, with tile behavior support from pokefirered/src/fieldmap.c chunk_eeb0180842f7ece9.

In the next stretch, we are going to take that table and make it more operational. We will ask what data the reducer actually needs, what state must be read but not owned, and how a clean lab implementation can preserve the same architectural boundaries without copying FireRed line for line. Keep the two questions in front of you: who owns input right now, and what subsystem owns the next visible behavior? Those two questions will get us through most of the apparent messiness in field control.

So, let’s turn the reducer from a slogan into a design object. If I were writing this on the board, I would draw a rectangle labeled “field-control reducer,” and I would put three arrows coming in. First arrow: current input. Second arrow: avatar and map state. Third arrow: interaction context, meaning the tile and object information near the avatar. Then I would draw one arrow coming out, and I would label that arrow “accepted owner.” Not “movement result,” not “script result,” not “button result.” Accepted owner. That phrase matters because the reducer is not supposed to perform every subsystem’s work. It decides which subsystem gets control next.

Now pause on that for a second. This is where advanced architecture work differs from just reading a function top to bottom. A beginner sees a lot of branches and says, “This function handles walking, talking, tile checks, warps, scripts, and menu behavior.” That is partly true, but it is not the best design description. A better description is: the field-control layer arbitrates among mutually exclusive claims on the next frame of player agency. That is the job. It reads enough state to know whether the A button should talk to an object, whether directional input should become a movement attempt, whether movement should be rejected by collision, whether a special tile should seize control, or whether nothing should happen. But it should not become the battle engine, the bag UI, the save engine, or the map loader.

And this is exactly why the source focus for today sits where it sits. In pokefirered/src/field_control_avatar.c chunk_636f753078bf545a, chunk_79332c416dfb6ac9, and chunk_4488cb84aee4d6dd, we are looking at avatar field control as a decision layer. Then, when that decision needs tile facts, it leans on the tile behavior support that the packet points us to in pokefirered/src/fieldmap.c chunk_eeb0180842f7ece9. The interesting thing is not just that FireRed has collision or that FireRed has scripts. We already built the map and tile foundation last week. The interesting thing today is that field control uses those prior systems as query surfaces. It asks questions of them. It does not dissolve into them.

Let me give you a concrete example. Imagine the player is standing one tile south of an NPC, facing north, and presses A. The reducer needs the input edge, meaning it needs to know that A was pressed in this control moment. It needs the avatar’s facing direction. It needs the avatar’s current map coordinates. It needs the object-event collection for the current map, because there may or may not be an interactable object at the faced tile. It probably needs movement lock state, because if the avatar is mid-step, in a forced movement, or inside a script-controlled pause, then this A press might not be eligible. What it does not need is the full text-box rendering pipeline. It does not need to know how glyphs get drawn. It does not need the detailed trainer-party structure. It does not need to know how battle animations work. It needs to know whether object interaction wins ownership. If yes, it dispatches or initiates the appropriate script path, and then the script and message systems take over.

Now, same physical position, different input. The player presses up instead of A. The reducer reads direction, facing, movement permissions, the target tile, object occupancy, and tile behavior. If the tile is blocked, the accepted outcome is not “move.” It may be a collision-facing update, a bump response, or simply no movement depending on the exact state. If the tile is passable and has no object blocking it, movement owns the next visible behavior. If the tile is a warp tile and the movement step completes onto it, then eventually warp ownership becomes relevant. Notice the timing distinction. Directional input does not mean “warp now.” It means “attempt field movement.” The warp is a consequence of accepted movement and tile semantics after the avatar reaches the tile. That separation is one of the reasons the system can feel consistent. The player is not teleported because the up button was pressed. The player is teleported because a successful field movement placed the avatar onto a tile whose behavior claims control.

Check your understanding here. If I ask, “What data does A-button interaction need that movement does not necessarily need?” a good answer is: it needs the faced interaction target and event lookup priority. It cares about what is in front of the avatar, not just the tile being stepped into. If I ask, “What data does movement need that A-button interaction may not?” a good answer is: it needs movement eligibility, target passability, collision, and step-state transition. There is overlap, yes, but the question being asked is different.

Let’s move the board diagram one level deeper. Under “read state,” I would write “input, avatar, object events, map tile behavior, script lock, menu lock, field effect lock.” I am saying “lock” informally here. The point is that the reducer must respect ownership already held by another subsystem. If a script is running, normal movement should not simply continue because the D-pad is down. If a message box owns the screen, pressing A may advance text, but that is not the same A-button lookup as talking to an NPC on the map. If a field effect is moving the avatar or playing a transition, field input may be ignored or interpreted by that effect. This is movement state gating.

This is also where I want you to connect week 6 back to week 1. In week 1, we described the runtime shell: AgbMain, callback slots, SetMainCallback2, and the per-frame task dispatch with RunTasks. We are not re-teaching that now, but we need to remember its consequence. Input is not processed in a magical continuous stream. It is sampled and interpreted during a frame-driven control loop. Field control is one participant in that loop. Earlier, we used pokefirered/src/main.c chunk_b35676322b169f85 for startup responsibility, chunk_6cfd90f6d0136799 for SetMainCallback2, and pokefirered/src/task.c chunk_3ffebc0341225936 for RunTasks. Today’s material plugs into that model. The avatar reducer is not the whole game loop. It is a piece of per-frame field behavior running under the overworld callback and task architecture that you already studied.

And now let me connect forward. Weeks 6 through 8 are our input, events, and story progression module. That means today is not only about walking. It is about the boundary between physical navigation and authored progression. The same A press might open dialogue, inspect a sign, start a trainer encounter, activate a hidden item, trigger a special field script, or do nothing. Those are progression behaviors, but they begin as field-control arbitration. If the arbitration is messy, story progression becomes messy. If the arbitration is disciplined, scripts can stay declarative enough to be authored and reasoned about.

Here is a lab-shaped version of the same idea. Suppose you are building the workshop reducer. I would expect a function that receives a compact input snapshot, an avatar state, and query interfaces for the world. I am deliberately saying query interfaces, not giant mutable global structs, even though the original C code often works through global state. Your clone can be cleaner while preserving the architecture. So you might have something like, “reduceFieldInput(input, avatar, worldQueries, locks),” and it returns a tagged result: no action, face direction, attempt move, reject move, dispatch script, inspect tile, start warp, open menu, maybe initiate battle. I do not care about those exact names. I care that exactly one owner is chosen.

Now, if your reducer both chooses “dispatch script” and immediately mutates inventory, adds a creature, opens text, starts a battle, and saves the game, then you have missed the architectural boundary. That might seem faster for a toy implementation, but it erases the lesson. A reducer should produce a decision or handoff. The target subsystem performs the domain work. When FireRed moves from field contact into battle setup, the battle-facing code is not hidden inside the input polling function. The research packet’s battle setup example, pokefirered/src/battle_setup.c chunk_494d132a59422c85, is valuable because its include surface shows battle transition, overworld, script, event object movement, metatile behavior, fieldmap, and field_control_avatar all meeting at the boundary between field and battle. That is a cross-system handoff, not a single mega-system.

Let’s make this less abstract. Say the player tries to step into tall grass. The reducer’s first responsibility is ordinary movement eligibility. Is the avatar allowed to move? Is the player already moving? Is the tile passable? Does an object block the destination? If movement is rejected, there is no wild encounter roll for that step, because no step into grass occurred. If movement succeeds, the movement subsystem animates the step. After the step completes, the field logic can consider tile behavior and encounter logic. That ordering prevents a category error. Wild encounter is not a response to the D-pad. It is a response to a completed movement into an eligible field condition.

Now compare that with pressing A toward a sign. The player does not move onto the sign. The input does not create a step. Instead, the avatar’s facing vector becomes the query. We ask, “What is in front of the player?” The object or tile behavior there may identify a sign script. The accepted owner becomes script dispatch. The script system then owns the message that appears. Again, the same physical map region can produce different ownership depending on input type and avatar orientation.

Let’s do a quick check. I will phrase this as a debugging question. A student says, “My clone sometimes walks onto a warp tile and also opens the NPC dialogue from the tile beyond it.” What is the likely architectural bug? The likely bug is that their reducer is allowing multiple accepted owners from one input frame or one movement resolution. They may be checking A-button interaction and movement consequence in the same unguarded pass, or they may be failing to separate faced-tile lookup from destination-tile lookup. The fix is not merely “add an if statement.” The fix is to restore priority and ownership. One control moment should choose the appropriate path, and subsequent behavior should be driven by the subsystem that owns the state after that handoff.

This is why field-control branching deserves serious attention even though, superficially, it looks like glue code. Glue code is often where architecture actually lives. Data tables are important. We spent weeks on data records, map headers, layouts, object events, generated assets, and tile behaviors. But data tables only become gameplay when some runtime layer asks the right question at the right time. Field control is one of those layers. It asks, “Does this input matter right now?” “What is the avatar allowed to do?” “What is adjacent?” “What is underfoot?” “Which behavior has priority?” “Who owns the next frame?”

If you are taking notes, I would write this sentence down almost verbatim: field input is a request, not a command. The player requests movement. The player requests interaction. The field-control system validates and routes that request. This is true in FireRed, and it is true in most robust RPG engines. The input device is intentionally dumb. It should not know whether a tile is a ledge, whether an NPC is a trainer, whether a cutscene is active, or whether a menu has priority. Those are runtime facts, not controller facts.

Now, one subtlety. In a low-level C game like FireRed, the boundaries are not always expressed the way we might express them in a modern engine. You will see globals. You will see functions that read state from several systems. You will see branch-heavy control. That does not mean there is no architecture. It means the architecture is encoded in ownership conventions, call order, data access patterns, and subsystem handoffs rather than in a neat class hierarchy. Advanced reverse engineering is learning to see that structure without requiring the original code to look like our preferred modern style.

That is also why our course objective says we decompose a complete creature-collector RPG into runtime shell, overworld maps, event scripting, creature data, battle, inventory, UI, save, and link systems. The decomposition is not an academic taxonomy. It helps you decide where responsibility belongs. Runtime shell schedules. Overworld maps provide spatial state. Event scripting owns authored progression. Creature data owns species, party, moves, and identity. Battle owns turn resolution and battle-specific state. Inventory owns item quantities and use rules. UI owns presentation and menu interaction. Save owns persistence. Link owns multiplayer communication and synchronization. Field control sits at a junction among several of these, but it should not absorb them.

For instance, when an NPC interaction leads to a battle, the path goes through field interaction into script or trainer detection and then into battle setup. That does not make the A-button handler the battle system. When pressing Start opens the field menu, field control may route the request, but the menu UI owns the menu state afterward. When stepping onto a warp tile changes maps, field control and tile behavior help identify the condition, but map loading uses the overworld and warp machinery that we already covered. We do not need to re-teach LoadMapFromWarp today. We just need to recognize when control is handed to that previously studied machinery.

Let’s return to the lab reducer. I want you to avoid copying FireRed line for line because the lab is not a transcription exercise. It is an architecture exercise. But I also want you to preserve the design pressures that FireRed is responding to. Your reducer should be deterministic. Given the same input snapshot and state snapshot, it should choose the same outcome. It should be priority ordered. A blocking modal state should win over free movement. Interaction checks should not randomly race movement checks. It should keep reads and writes clear. Reading tile behavior is not the same as mutating map state. Dispatching a script is not the same as executing every command inside that script in the reducer. And it should be testable with small scenarios.

Here is a good test case. Avatar at position ten, ten, facing north. NPC at ten, nine. Input A pressed. Movement not locked, script not locked. Expected result: object interaction or script dispatch for that NPC. Same setup, input up pressed. Expected result: movement rejected or object collision, depending on your result vocabulary, because the NPC occupies the destination. Same setup, no input. Expected result: no action. Same setup, message box active. Input A pressed. Expected result: message advancement belongs to the message subsystem, or field interaction is gated off, depending on how your shell routes modal input. But it should not talk to the NPC again through the normal map interaction path.

Another test. Avatar at five, five, facing east. Sign tile at six, five, no object event. Input A. Expected result: background or tile interaction script. Input right. If sign tile is impassable, movement rejected. If it is passable in your toy map, movement accepted, but that would be a property of the tile behavior. Again, the same coordinate can be queried as “faced tile for interaction” or “destination tile for movement.” Those are not interchangeable.

And one more. Avatar at three, three, standing on a normal tile, facing south. Destination at three, four is a warp tile and passable. Input down. The reducer says movement attempt accepted. After movement completion, the tile behavior says warp trigger. You may model that as a second reducer stage, or as a movement completion event processed by field logic. What I do not want is an input handler that sees “down plus warp ahead” and immediately changes maps before the step. That loses the animation-state truth of the original design.

Now, let’s connect this to the research packet’s broader source map. The packet emphasizes FireRed as a stack of cooperating state machines plus data tables, and that phrase is useful here. Field control is one state machine among others. The move relearner example in pokefirered/src/learn_move.c chunk_af3598df6f092723 even announces itself as a state machine in the excerpt, with menu states and callbacks. That is a different domain, a UI and creature-data workflow, but the architectural rhythm is familiar: state gates input, input advances a controlled transition, and a subsystem owns the next behavior. In pokefirered/src/pokemon_summary_screen.c chunk_e8e17a42bbf17d46, the include surface similarly reminds us that UI, party data, items, moves, battle constants, and link concerns can meet in one screen without becoming one undifferentiated module. That is the course pattern repeating.

So when you look at field_control_avatar.c, do not treat it as an isolated curiosity. Treat it as the overworld version of a recurring FireRed idea: many modules expose just enough surface for a central controller to decide the next state, and then ownership moves. The exact coding style changes from subsystem to subsystem, but the pattern keeps coming back.

Let me ask another check-for-understanding question. Why is “currently moving” a stronger fact than “D-pad is currently pressed”? Because movement is a stateful animation and collision commitment, while D-pad is just sampled intent. Once a step has begun, the avatar cannot necessarily accept a new unrelated field command until the step resolves. If your clone allows a new A-button interaction during the middle of a tile-to-tile movement, you will create impossible states: talking to an NPC from between tiles, triggering a sign from the wrong facing coordinate, or dispatching a script while the avatar’s logical position and visual position disagree. The original engine avoids that by gating input through movement state.

Now, for your homework this week, the bar is higher than it would have been in week 2. Earlier homework asked you to trace from data records through globals, callbacks, tasks, scripts, structs, and visible behavior. Week 4 asked you to design minimal clone versions of map loading, scripts, party data, battle turns, item use, and save persistence. Week 5 let us use Pokemon Showdown only as a secondary comparison for battle data hooks and deterministic tests. So by week 6, I expect you to speak in handoffs. Do not tell me, “The player presses A and dialogue happens.” Tell me, “The sampled input is accepted by field control, the faced coordinate is checked against object and background interaction priority, a script is dispatched, and the message system owns visible text until it releases control.” That is the level of precision we need now.

Let’s close the day by stepping back. The avatar is the player’s body in the overworld, but architecturally it is also a contract boundary. On one side is raw intent: buttons, direction, repeated presses, newly pressed buttons. On the other side are durable game systems: maps, scripts, battles, inventory, UI, saves, links. Field control is the layer that refuses to let raw intent mutate everything directly. It asks whether input is valid, what spatial facts matter, which priority wins, and which subsystem owns the next behavior.

That gives us the bridge into the next lecture. Today we followed input into avatar movement and basic interaction routing. Next time, we will lean harder into interaction checks and field control: object priority, A-button lookup, special cases, and how authored events become discoverable through spatial queries. Keep the two questions from the previous stretch in your head, because they remain the best debugging questions for this entire week: who owns input right now, and what subsystem owns the next visible behavior? If you can answer those cleanly, FireRed’s field-control code stops looking like a tangle of branches and starts looking like a disciplined arbitration layer sitting between the player’s hands and the world’s rules.

## Source References
- pokefirered/src/battle_setup.c
- pokefirered/src/daycare.c
- pokefirered/src/learn_move.c
- pokefirered/src/battle_util.c
- pokefirered/src/pokemon_summary_screen.c
