jevsnes.git / third-party / c / patches / 0006-walk-up-to-a-blocking-npc.patch
0006-walk-up-to-a-blocking-npc.patch66 lines · 4.0 KB · raw
1diff --git a/third-party/c/zbanks-alttp/ap_map.c b/third-party/c/zbanks-alttp/ap_map.c
2--- a/third-party/c/zbanks-alttp/ap_map.c
3+++ b/third-party/c/zbanks-alttp/ap_map.c
4@@ -1236,9 +1236,35 @@
5                     LOG(TERM_BOLD("11:") " " PRIXYV, PRIXYVF(center));
6                 }
7                 */
8+                // Carried patch (jev): a TALK sprite being walked to does not
9+                // block the way to itself. A TALK sprite's node is its own
10+                // box; its hitbox plus this one-cell margin can cover that
11+                // box and ring it (Sahasrahla, 0x16), and then no cell of the
12+                // goal is reachable and the search always fails. Link still
13+                // stops against the sprite, where TALK_NPC presses up and A.
14+                // Gated on SPRITE_ATTR_TALK: an ordinary blocking sprite
15+                // (uncle's room's own furniture, a torch) that merely
16+                // happens to overlap an UNRELATED destination - a door, a
17+                // chest - must stay solid, or the pathfinder reports a route
18+                // through it that the real collision then refuses forever
19+                // (the Hyrule Castle secret passage door froze exactly this
20+                // way: room $0012's own blocking sprite, type 0x73 like
21+                // uncle's but not TALK there, went transparent for a plain
22+                // door pathfind it merely stood near). Evidence:
23+                // ../../research/zbanks-alttp.md, "The castle passage door:
24+                // a second stairs-shaped regression".
25+                const bool talk = ap_sprites[i].attrs & SPRITE_ATTR_TALK;
26+                const bool destination = talk && hb_tl.x <= dst_br.x && hb_br.x >= dst_tl.x &&
27+                    hb_tl.y <= dst_br.y && hb_br.y >= dst_tl.y;
28+                // Carried patch (jev): and Link already standing in the
29+                // margin - against the sprite, where talking to it leaves
30+                // him - would be walled in by it, every search failing and
31+                // every goal unsatisfiable; then only the sprite's own cells
32+                // block. Same TALK gate, same reason.
33+                const int inside = talk && XYIN(src, hb_tl, hb_br);
34                 struct xy ds;
35-                for (ds.x = hb_tl.x; ds.x <= hb_br.x; ds.x++) {
36-                    for (ds.y = hb_tl.y; ds.y <= hb_br.y; ds.y++) {
37+                for (ds.x = hb_tl.x + inside; ds.x <= hb_br.x - inside && !destination; ds.x++) {
38+                    for (ds.y = hb_tl.y + inside; ds.y <= hb_br.y - inside; ds.y++) {
39                         if (!XYUNDER(ds, grid)) {
40                             continue;
41                         }
42diff --git a/third-party/c/zbanks-alttp/ap_plan.c b/third-party/c/zbanks-alttp/ap_plan.c
43--- a/third-party/c/zbanks-alttp/ap_plan.c
44+++ b/third-party/c/zbanks-alttp/ap_plan.c
45@@ -442,6 +442,21 @@
46             }
47             */
48             rc = ap_task_follow_targets(task, joypad);
49+            // Carried patch (jev): a talking sprite's node is its own box,
50+            // and Link cannot stand inside a sprite that blocks him
51+            // (Sahasrahla, 0x16): he stops against it and the targets time
52+            // out. Against it is where TALK_NPC, next, wants him - it presses
53+            // up and A - so within 8 pixels of the box is arrived.
54+            if (rc == RC_FAIL && task->node != NULL && task->node->type == NODE_SPRITE &&
55+                    (ap_sprite_attrs_for_type(task->node->sprite_type, task->node->sprite_subtype,
56+                                              task->node->screen->dungeon_room) & SPRITE_ATTR_TALK)) {
57+                struct xy link = ap_link_xy();
58+                if (link.x + 15 + 8 >= task->node->tl.x && link.x <= task->node->br.x + 8 &&
59+                        link.y + 15 + 8 >= task->node->tl.y && link.y <= task->node->br.y + 8) {
60+                    LOG("Against the NPC; arrived");
61+                    return RC_DONE;
62+                }
63+            }
64             if (rc != RC_INPR) return rc;
65         }
66         break;