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;