| 686 | } |
| 687 | |
| 688 | CornerTestResult TestItemAtNextCornerPosition(ItemInfo* item, CollisionInfo* coll, float angle, bool outer) |
| 689 | { |
| 690 | auto* lara = GetLaraInfo(item); |
| 691 | |
| 692 | auto result = CornerTestResult(); |
| 693 | |
| 694 | // Determine real turning angle |
| 695 | auto turnAngle = outer ? angle : -angle; |
| 696 | |
| 697 | // Backup previous position into array |
| 698 | Pose pos[3] = { item->Pose, item->Pose, item->Pose }; |
| 699 | |
| 700 | // Do a two-step rotation check. First step is real resulting position, and second step is probing |
| 701 | // position. We need this because checking at exact ending position does not always return |
| 702 | // correct results with nearest ledge angle. |
| 703 | |
| 704 | for (int i = 0; i < 2; i++) |
| 705 | { |
| 706 | // Determine collision box anchor point and rotate collision box around this anchor point. |
| 707 | // Then determine new test position from centerpoint of new collision box position. |
| 708 | |
| 709 | // Push back item a bit to compensate for possible edge ledge cases |
| 710 | pos[i].Position.x -= round((coll->Setup.Radius * (outer ? -0.2f : 0.2f)) * phd_sin(pos[i].Orientation.y)); |
| 711 | pos[i].Position.z -= round((coll->Setup.Radius * (outer ? -0.2f : 0.2f)) * phd_cos(pos[i].Orientation.y)); |
| 712 | |
| 713 | // Move item at the distance of full collision diameter plus half-radius margin to movement direction |
| 714 | pos[i].Position.x += round((coll->Setup.Radius * (i == 0 ? 2.0f : 2.5f)) * phd_sin(lara->Control.MoveAngle)); |
| 715 | pos[i].Position.z += round((coll->Setup.Radius * (i == 0 ? 2.0f : 2.5f)) * phd_cos(lara->Control.MoveAngle)); |
| 716 | |
| 717 | // Determine anchor point |
| 718 | auto cX = pos[i].Position.x + round(coll->Setup.Radius * phd_sin(pos[i].Orientation.y)); |
| 719 | auto cZ = pos[i].Position.z + round(coll->Setup.Radius * phd_cos(pos[i].Orientation.y)); |
| 720 | cX += (coll->Setup.Radius * phd_sin(pos[i].Orientation.y + ANGLE(90.0f * -std::copysign(1.0f, angle)))); |
| 721 | cZ += (coll->Setup.Radius * phd_cos(pos[i].Orientation.y + ANGLE(90.0f * -std::copysign(1.0f, angle)))); |
| 722 | |
| 723 | // Determine distance from anchor point to new item position |
| 724 | auto dist = Vector2(pos[i].Position.x, pos[i].Position.z) - Vector2(cX, cZ); |
| 725 | auto s = phd_sin(ANGLE(turnAngle)); |
| 726 | auto c = phd_cos(ANGLE(turnAngle)); |
| 727 | |
| 728 | // Shift item to a new anchor point |
| 729 | pos[i].Position.x = dist.x * c - dist.y * s + cX; |
| 730 | pos[i].Position.z = dist.x * s + dist.y * c + cZ; |
| 731 | |
| 732 | // Virtually rotate item to new angle |
| 733 | short newAngle = pos[i].Orientation.y - ANGLE(turnAngle); |
| 734 | pos[i].Orientation.y = newAngle; |
| 735 | |
| 736 | // Snap to nearest ledge, if any. |
| 737 | item->Pose = pos[i]; |
| 738 | SnapItemToLedge(item, coll, item->Pose.Orientation.y); |
| 739 | |
| 740 | // Copy resulting position to an array and restore original item position. |
| 741 | pos[i] = item->Pose; |
| 742 | item->Pose = pos[2]; |
| 743 | |
| 744 | if (i == 1) // Both passes finished, construct the result. |
| 745 | { |
no test coverage detected