jevsnes.git / third-party / c / patches / README.md
1# Chapter 18: patches, every change we made to the bot
2
3These are the only changes to the bot's own code. Each one is a small diff
4of an upstream file, applied at build time (chapter 17), with a comment in
5the patched code that starts `Carried patch (jev):`. Each exists because the
6host (chapter 4) could not fix the problem from outside: the bad decision is
7made and acted on inside one `ap_tick`, or sits in one of upstream's static
8tables, or between two statements of a `static` function.
9
10Read in order, they are a fairly good story of what it takes to get from
11Link's bed to the Pegasus Boots:
12
13```mermaid
14flowchart TD
15  bed["Link's house"] -->|"0001: stop walking back down the stairs"| sword["the sword, from uncle"]
16  sword --> ep["Eastern Palace"]
17  ep -->|"0003: the anti-fairy circle is not an enemy to walk into"| bk["the big key ($B8)"]
18  bk -->|"0013: a big chest needs its big key"| bow["the bow, from the big chest"]
19  bow -->|"0004: let the bow shot through"| armos["the Armos Knights"]
20  armos --> pendant["the Pendant of Courage"]
21  pendant -->|"0005: the green pendant is bit 0x04"| sahas["Sahasrahla"]
22  sahas -->|"0006, 0007, 0008: walk up, talk until he gives, close the text"| boots["the Pegasus Boots"]
23  boots -->|"0009, 0010, 0031: dash"| book["the Book of Mudora (wired, not yet proven to land)"]
24```
25
26> **Aside: two of them undo upstream's own last commit.** `bcb2537` (2020-02-06)
27> made two changes that broke things its author's earlier video had done
28> fine. One left the bot walking back down every intra-room staircase it had
29> just climbed (0001); the other cleared the Y button on the very frame the
30> bot pressed it to shoot an arrow, so the Armos Knights never took one
31> (0004). Upstream had killed them a month earlier, before the line existed.
32
33> **Aside: the gap after 0016 is not missing patches.** From 0030 the patches
34> came from a separate line of work (movement and combat), numbered apart so
35> that two streams of patches could not collide on a number.
36
37> **Try it.** `ls` this folder, open any patch, and search the patched file
38> for `Carried patch (jev)`. Then build: `nix develop -c buck2 build
39> //third-party/c:patched` applies all of them, in name order, and fails if
40> any no longer applies.
41
42## For the people who maintain it
43
44### The patches
45
46| Patch | Upstream files | What it changes | Evidence in [research/zbanks-alttp.md](../../../research/zbanks-alttp.md) |
47| --- | --- | --- | --- |
48| [0001](0001-follow-targets-on-intra-room-stairs.patch) | `alttp.c` | `bcb2537`'s early return for `$B0 != 0` also caught intra-room stairs, which count their steps in `$B0`; the bot never consumed the targets it climbed past and walked back down. | "The stairs" |
49| [0002](0002-goal-choice-hook.patch) | `ap_plan.c` | `ap_goal_choose_hook`: a host may make the goal choice. NULL by default, which is upstream exactly. This is where Jev plugs in (chapter 5). | "Jev at the goal choice" |
50| [0003](0003-anti-fairy-circle.patch) | `ap_snes.h`, `ap_map.c`, `ap_plan.c` | Eastern Palace `$B8`: the anti-fairy circle is an invulnerable obstacle, not an enemy to walk into; the room gets a kill-all script in upstream's own table; kill-all no longer gives up the first frame an enemy is out of reach. | "Eastern Palace `$B8`" |
51| [0004](0004-bow-shot-survives-follow-targets.patch) | `ap_map.c` | `ap_follow_targets` no longer clears the Y that kill-all's bow shot just pressed. | "The Armos Knights" |
52| [0005](0005-green-pendant-is-bit-4.patch) | `ap_req.c` | The green pendant is bit `0x04` of `$7EF374`, as the game and the Randomizer test it; upstream's `0x01` is the red one, which left Sahasrahla unsatisfiable. | "Sahasrahla" |
53| [0006](0006-walk-up-to-a-blocking-npc.patch) | `ap_map.c`, `ap_plan.c` | The bot can walk up to a solid talking NPC (Sahasrahla) and away again. Both exemptions are gated on `SPRITE_ATTR_TALK`, after the first version made an unrelated sprite transparent to the pathfinder at the castle passage door. | "The boots", "The castle passage door" |
54| [0007](0007-talk-to-an-npc-until-it-gives.patch) | `ap_plan.c` | A talk lasts until the NPC's text is done and counts only an item actually given, then Link steps off the NPC. | "The boots" |
55| [0008](0008-text-box-gets-a-in-any-state.patch) | `alttp.c` | An open text box always gets A, even while Link is mid-dash. | "The boots" |
56| [0009](0009-pegasus-boots-dash.patch) | `ap_map.c` | A Pegasus Boots dash for `SCRIPT_SEQUENCE`: four new characters (`8`/`2`/`4`/`6`, numpad directions) hold A with a direction, and `ap_follow_targets` no longer clears a dash's A on plain floor. | "The Book of Mudora" |
57| [0010](0010-book-of-mudora-goal.patch) | `ap_map.c`, `ap_plan.c` | A goal for the Library's shelf (room `$0107`), its approach point derived from ROM data, gated on the boots. Proven to attach and gate; not yet proven to land the book. | "The Book of Mudora" |
58| [0011](0011-shopkeeper-blocks-in-room-0123.patch) | `ap_snes.h` | Room `$0123`'s per-room override for sprite `0xBB`/`0x0200` keeps `SPRITE_ATTR_BLKF`, so the pathfinder stops routing through its real hitbox. | "The door D 0x80 stall in room $0123" |
59| [0012](0012-dam-push-block-not-a-hammer-peg.patch) | `ap_map.c` | In the Dam's block-puzzle room (`$010B`), raw tile `0x27` is a push block, not a hammer peg. | "The Dam Chest push block" |
60| [0013](0013-big-chest-needs-the-big-key.patch) | `ap_plan.c` | A big chest's goal is unsatisfiable until its dungeon's big key is held. | "The Eastern Palace big chest" |
61| [0014](0014-door-with-no-vestibule-in-room-0089.patch) | `ap_map.c` | Room `$0089`'s north door has no floor before its transition, so its approach point is the door's own tile. | "A door with no vestibule ($0089)" |
62| [0015](0015-never-push-a-block-into-a-wall.patch) | `ap_map.c` | General: a push that jams (`push_timer` running, Link not moving) marks that cell a wall for the rest of the room visit. | "Never push a block into a wall" |
63| [0016](0016-hc-routines-already-done-in-open-mode.patch) | `ap_plan.c` | Hyrule Castle routines are done in open mode; any routine whose screen's chests are all open is complete. | "A routine already done, or already claimed, is never offered again" |
64| [0030](0030-hammer-peg-indoors-general.patch) | `ap_map.c` | General form of 0012: indoors, raw tile `0x27` is never a hammer peg, by the game's own rule. | "The hammer swings at bare floor" |
65| [0031](0031-dash-as-path-action.patch) | `ap_snes.h`, `ap_map.c` | With the boots, a path may cross bonk rocks (tile `0x57`), and the step onto one is a dash. | not yet written up there |
66| [0032](0032-glove-gating-general.patch) | `ap_plan.c` | The glove a liftable needs comes from its tile's own `LFT1`/`LFT2` bits, not one hard-coded tile id. | not yet written up there |
67
68`CLAUDE.md` beside this has each patch's full account: the run, the frame,
69the measurement, and why no host fix could do it.
70
71| Path | What |
72| --- | --- |
73| `NNNN-*.patch` | The patches, applied in name order by `//third-party/c:patched`. |
74| [README.md](README.md) | This chapter. |
75| [CLAUDE.md](CLAUDE.md) | Every patch's evidence, and the open bugs that are not patches yet. |
76
77← Previous: [Chapter 17, c/](../) · Up: [c](../) · Next: [Chapter 19, rust/](../../rust/) →