| ⋯ 105 unchanged lines |
| 106 | 106 | | h: number; |
| 107 | 107 | | } |
| 108 | 108 | | |
| 109 | + | /** One throw, as the overlay wants to see it: let go of at (x, y) along |
| 110 | + | * (fx, fy), and actually sent along (vx, vy). `how` says why they differ. */ |
| 111 | + | export interface ThrowMark { |
| 112 | + | x: number; |
| 113 | + | y: number; |
| 114 | + | fx: number; |
| 115 | + | fy: number; |
| 116 | + | vx: number; |
| 117 | + | vy: number; |
| 118 | + | how: string; |
| 119 | + | } |
| 120 | + | |
| 109 | 121 | | /** A throw that has been let go of, waiting for the discard it belongs to. */ |
| 110 | 122 | | interface Release { |
| 111 | 123 | | seat: SeatId; |
| ⋯ 35 unchanged lines |
| 147 | 159 | | /** Tiles on their way off the table. Drawn, but out of the physics. */ |
| 148 | 160 | | private leaving: Leaving[] = []; |
| 149 | 161 | | /** |
| 162 | + | * The last few throws: where each was let go of, the line it was let go |
| 163 | + | * *along*, and the line it actually left on. |
| 164 | + | * |
| 165 | + | * Read by the collider overlay and by nothing else. A throw is not always |
| 166 | + | * sent where it was aimed — a flick with standing wall in front of it is |
| 167 | + | * lobbed rather than slid, and one whose line misses the square altogether is |
| 168 | + | * re-aimed at the middle of it — and a tile that leaves on a line nobody |
| 169 | + | * threw reads exactly like a tile that bounced off something invisible. |
| 170 | + | */ |
| 171 | + | throws: ThrowMark[] = []; |
| 172 | + | /** |
| 150 | 173 | | * Sandbox throws: real tiles in the real world, but belonging to no discard, |
| 151 | 174 | | * so the reconciler never looks at them — nothing in `entries` means nothing |
| 152 | 175 | | * to cull. See `throwLoose`. |
| ⋯ 469 unchanged lines |
| 622 | 645 | | const speed = Math.hypot(vx, vy); |
| 623 | 646 | | let flipTurns = 0; |
| 624 | 647 | | let flipOver = 0; |
| 648 | + | let how = set ? 'slide, from inside the square' : 'slide'; |
| 625 | 649 | | |
| 626 | 650 | | if (!slide) { |
| 627 | 651 | | // Lofted over a standing wall, and it has to come *down* inside the |
| ⋯ 5 unchanged lines |
| 633 | 657 | | // limp one drops in over the near wall, a hard one carries to the far |
| 634 | 658 | | // side and barges through whatever is lying there, and neither of them |
| 635 | 659 | | // can leave the tile outside. |
| 660 | + | how = 'lob'; |
| 636 | 661 | | const dir = speed > 0 ? { x: vx / speed, y: vy / speed } : { x: 0, y: -1 }; |
| 637 | 662 | | const span = spanThrough(geo.pool, thrown, dir); |
| 638 | 663 | | const centre = centreOf(geo.pool); |
| ⋯ 3 unchanged lines |
| 642 | 667 | | carry = Math.min(Math.max(near, carry), Math.max(near, span.far - geo.tile.h)); |
| 643 | 668 | | } else { |
| 644 | 669 | | // Flicked somewhere that is not the square at all — put it in anyway. |
| 670 | + | how = 'lob, RE-AIMED at the middle'; |
| 645 | 671 | | carry = Math.hypot(centre.x - thrown.x, centre.y - thrown.y); |
| 646 | 672 | | dir.x = (centre.x - thrown.x) / (carry || 1); |
| 647 | 673 | | dir.y = (centre.y - thrown.y) / (carry || 1); |
| ⋯ 14 unchanged lines |
| 662 | 688 | | } |
| 663 | 689 | | if (!TUMBLE) flipTurns = 0; |
| 664 | 690 | | |
| 691 | + | this.throws.push({ x: thrown.x, y: thrown.y, fx: thrown.vx, fy: thrown.vy, vx, vy, how }); |
| 692 | + | if (this.throws.length > 6) this.throws.shift(); |
| 693 | + | |
| 665 | 694 | | return addBody(this.world!, { |
| 666 | 695 | | tile: tile, |
| 667 | 696 | | seat: thrown.seat, |
| ⋯ 81 unchanged lines |