Warp sight honors "as though they were adjacent" — diagonals included
Playtesting caught the gap with a sticky wand: a target visible through the opening but one square off the corridor axis was refused. The colinear-only model was stricter than the rulebook, whose actual instruction is to treat the connected edges as adjacent boards with a straight center-to-center line — and a straight line through a one-cell opening may run diagonally, exactly as through a doorway. hasWarpLineOfSight now abuts the far side virtually at the mouth (rotating when the pairing turns a corner, as aisle warps do), finds where the center-to-center line crosses the rim, requires that crossing to fall strictly within the open mouth (corner-grazing stays blocked — the strict reading), and checks the two legs against real walls on each side of the seam. hasLineOfSight's core became a shared segmentClear to serve both legs. The colinear corridor cases remain as the special case they always were; a new test pins that off-axis squares are visible through mouths. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
53edf9734e
commit
8af8962330
@@ -140,3 +140,101 @@
|
||||
[ 555769ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 557346ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 558933ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 560699ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 562433ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 564351ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 566850ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 571504ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 576704ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 580031ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 586469ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 591484ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 597562ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 601328ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 604230ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 610716ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 614756ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 619191ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 622632ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 628757ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 633165ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 635772ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 641787ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 646319ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 650540ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 653919ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 659958ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 663089ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 664597ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 666107ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 667620ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 669125ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 670630ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 672135ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 673660ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 675188ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 676720ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 678303ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 679929ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 681713ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 683638ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 686042ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 688483ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 694213ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 700120ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 705030ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 708102ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 713737ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 718257ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 723483ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 726575ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 731009ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 733615ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 739850ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 743296ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 747591ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 750935ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 753792ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 759827ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 765846ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 770080ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 776003ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 781143ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 785813ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 790908ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 794723ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 799978ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 802566ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 808697ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 812967ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 817030ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 820028ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 826526ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 829216ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 833505ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 838637ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 843812ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 849871ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 854886ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 860741ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 865567ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 869130ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 874426ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 880608ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 885176ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 888150ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 891310ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 894480ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 899982ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 904792ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 908807ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 914072ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 916853ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 920114ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 925647ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 930995ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 934357ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 937913ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 941634ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 947338ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
[ 950320ms] [ERROR] WebSocket connection to 'ws://127.0.0.1:8899/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED @ http://127.0.0.1:8899/assets/index-Di4XAJUy.js:1
|
||||
|
||||
@@ -268,14 +268,23 @@ export function hasLineOfSight(
|
||||
blockedCells?: Record<string, true>,
|
||||
): boolean {
|
||||
if (cellKey(from) === cellKey(to)) return true;
|
||||
// Centers of cells: (x + 0.5, y + 0.5).
|
||||
const x0 = from.x + 0.5, y0 = from.y + 0.5;
|
||||
const x1 = to.x + 0.5, y1 = to.y + 0.5;
|
||||
return segmentClear(
|
||||
board, from.x + 0.5, from.y + 0.5, to.x + 0.5, to.y + 0.5,
|
||||
blockedCells, [cellKey(from), cellKey(to)],
|
||||
);
|
||||
}
|
||||
|
||||
/** Is this raw sight segment unobstructed by walls or solid cells? */
|
||||
function segmentClear(
|
||||
board: AssembledBoard,
|
||||
x0: number, y0: number, x1: number, y1: number,
|
||||
blockedCells: Record<string, true> | undefined,
|
||||
skipCells: string[],
|
||||
): boolean {
|
||||
if (blockedCells) {
|
||||
for (const key of Object.keys(blockedCells)) {
|
||||
if (skipCells.includes(key)) continue;
|
||||
const [bx, by] = key.split(",").map(Number) as [number, number];
|
||||
if ((bx === from.x && by === from.y) || (bx === to.x && by === to.y)) continue;
|
||||
// The sight line is blocked if it crosses any side of the solid cell.
|
||||
const sides: [number, number, number, number][] = [
|
||||
[bx, by, bx + 1, by],
|
||||
@@ -334,12 +343,14 @@ function onSegment(ax: number, ay: number, bx: number, by: number, px: number, p
|
||||
}
|
||||
|
||||
/**
|
||||
* Straight-corridor sight through a wraparound opening. Rulebook: "If
|
||||
* casting a spell, or checking line of sight through the AUTO WARP, treat
|
||||
* it as a straight line, and the two connected boards as though they were
|
||||
* adjacent" — and the lettered openings reconnect board edges the same way
|
||||
* ("you will reenter at point A"). The line must run down the corridor, out
|
||||
* one mouth, and straight in through the paired mouth: no diagonals.
|
||||
* Sight through a wraparound opening. Rulebook: "If casting a spell, or
|
||||
* checking line of sight through the AUTO WARP, treat it as a straight
|
||||
* line, and the two connected boards as though they were adjacent" — and
|
||||
* the lettered openings reconnect edges the same way. So the far side is
|
||||
* virtually abutted at the mouth (rotated if the pairing turns a corner,
|
||||
* as the aisle warps do), and the center-to-center line must pass through
|
||||
* the one-cell opening: diagonals through the gap are as legal as they are
|
||||
* through any doorway.
|
||||
*/
|
||||
export function hasWarpLineOfSight(
|
||||
board: AssembledBoard,
|
||||
@@ -347,31 +358,65 @@ export function hasWarpLineOfSight(
|
||||
to: Cell,
|
||||
blockedCells?: Record<string, true>,
|
||||
): boolean {
|
||||
const DIR: Record<Side, { x: number; y: number }> = {
|
||||
N: { x: 0, y: -1 }, S: { x: 0, y: 1 }, E: { x: 1, y: 0 }, W: { x: -1, y: 0 },
|
||||
};
|
||||
const EPS = 1e-9;
|
||||
for (const w of board.warps) {
|
||||
const mouthA = w.from.cell;
|
||||
const out = w.from.side;
|
||||
const sideA = w.from.side;
|
||||
const mouthB = w.to.cell;
|
||||
const inward = opposite(w.to.side);
|
||||
// The viewer stands in mouth A's corridor, on the interior side.
|
||||
const fromAligned = out === "N" || out === "S" ? from.x === mouthA.x : from.y === mouthA.y;
|
||||
if (!fromAligned) continue;
|
||||
const fromInterior =
|
||||
out === "N" ? from.y >= mouthA.y : out === "S" ? from.y <= mouthA.y :
|
||||
out === "E" ? from.x <= mouthA.x : from.x >= mouthA.x;
|
||||
if (!fromInterior) continue;
|
||||
// The target sits in mouth B's corridor, from the mouth inward.
|
||||
const toAligned = inward === "N" || inward === "S" ? to.x === mouthB.x : to.y === mouthB.y;
|
||||
if (!toAligned) continue;
|
||||
const toInterior =
|
||||
inward === "N" ? to.y <= mouthB.y : inward === "S" ? to.y >= mouthB.y :
|
||||
inward === "E" ? to.x >= mouthB.x : to.x <= mouthB.x;
|
||||
if (!toInterior) continue;
|
||||
// A filled mouth blocks the tunnel unless the viewer/target IS the mouth.
|
||||
// A filled mouth chokes the tunnel unless the viewer/target IS the mouth.
|
||||
if (blockedCells?.[cellKey(mouthA)] && cellKey(from) !== cellKey(mouthA)) continue;
|
||||
if (blockedCells?.[cellKey(mouthB)] && cellKey(to) !== cellKey(mouthB)) continue;
|
||||
|
||||
// Rotation taking the far board's inward direction onto sideA.
|
||||
const u = DIR[inward], v = DIR[sideA];
|
||||
const cos = u.x * v.x + u.y * v.y;
|
||||
const sin = u.x * v.y - u.y * v.x;
|
||||
const centerB = { x: mouthB.x + 0.5, y: mouthB.y + 0.5 };
|
||||
const nA = neighbor(mouthA, sideA);
|
||||
const anchor = { x: nA.x + 0.5, y: nA.y + 0.5 };
|
||||
const T = (p: { x: number; y: number }) => ({
|
||||
x: cos * (p.x - centerB.x) - sin * (p.y - centerB.y) + anchor.x,
|
||||
y: sin * (p.x - centerB.x) + cos * (p.y - centerB.y) + anchor.y,
|
||||
});
|
||||
const Tinv = (p: { x: number; y: number }) => ({
|
||||
x: cos * (p.x - anchor.x) + sin * (p.y - anchor.y) + centerB.x,
|
||||
y: -sin * (p.x - anchor.x) + cos * (p.y - anchor.y) + centerB.y,
|
||||
});
|
||||
|
||||
const c0 = { x: from.x + 0.5, y: from.y + 0.5 };
|
||||
const c1 = T({ x: to.x + 0.5, y: to.y + 0.5 });
|
||||
|
||||
// The line must cross the rim through the open mouth of A.
|
||||
let t: number, off: number, P: { x: number; y: number };
|
||||
if (sideA === "E" || sideA === "W") {
|
||||
const rimX = sideA === "E" ? mouthA.x + 1 : mouthA.x;
|
||||
if (Math.abs(c1.x - c0.x) < EPS) continue;
|
||||
t = (rimX - c0.x) / (c1.x - c0.x);
|
||||
const y = c0.y + t * (c1.y - c0.y);
|
||||
off = y - mouthA.y;
|
||||
P = { x: rimX, y };
|
||||
} else {
|
||||
const rimY = sideA === "S" ? mouthA.y + 1 : mouthA.y;
|
||||
if (Math.abs(c1.y - c0.y) < EPS) continue;
|
||||
t = (rimY - c0.y) / (c1.y - c0.y);
|
||||
const x = c0.x + t * (c1.x - c0.x);
|
||||
off = x - mouthA.x;
|
||||
P = { x, y: rimY };
|
||||
}
|
||||
if (t <= EPS || t >= 1 - EPS) continue;
|
||||
// Grazing the mouth's corners counts as blocked — strict reading.
|
||||
if (off <= EPS || off >= 1 - EPS) continue;
|
||||
|
||||
const Pfar = Tinv(P);
|
||||
if (
|
||||
hasLineOfSight(board, from, mouthA, blockedCells) &&
|
||||
hasLineOfSight(board, mouthB, to, blockedCells)
|
||||
segmentClear(board, c0.x, c0.y, P.x, P.y, blockedCells,
|
||||
[cellKey(from), cellKey(mouthA)]) &&
|
||||
segmentClear(board, Pfar.x, Pfar.y, to.x + 0.5, to.y + 0.5, blockedCells,
|
||||
[cellKey(to), cellKey(mouthB)])
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -236,3 +236,30 @@ describe("setup diagram pairings (rulebook Set-Up Diagram)", () => {
|
||||
expect(bent(r.state.board.warps).length).toBe(0); // "only opposite board edges connect"
|
||||
});
|
||||
});
|
||||
|
||||
describe("sight through warps treats the boards as adjacent", () => {
|
||||
const twoSector: SectorPlacement[] = [
|
||||
{ boardId: "board-a", origin: { x: 0, y: 0 }, rotation: 0 },
|
||||
{ boardId: "board-b", origin: { x: 0, y: 5 }, rotation: 0 },
|
||||
];
|
||||
|
||||
it("diagonal lines pass through the one-cell mouth like any doorway", () => {
|
||||
const board = assembleBoard(twoSector);
|
||||
// From SOME warp mouth, at least one square off the straight corridor
|
||||
// axis must be visible through the opening — the adjacency promise.
|
||||
let offAxis = 0;
|
||||
for (const w of board.warps) {
|
||||
const mouth = w.from.cell;
|
||||
const axisVertical = w.from.side === "N" || w.from.side === "S";
|
||||
for (const key of Object.keys(board.cells)) {
|
||||
const [x, y] = key.split(",").map(Number) as [number, number];
|
||||
const onAxis = axisVertical ? x === mouth.x : y === mouth.y;
|
||||
if (onAxis) continue;
|
||||
if (!hasLineOfSight(board, mouth, { x, y }) && sightBetween(board, mouth, { x, y })) {
|
||||
offAxis++;
|
||||
}
|
||||
}
|
||||
}
|
||||
expect(offAxis).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user