| 863 | } |
| 864 | |
| 865 | void DropPickups(ItemInfo* item, bool disableAlignment) |
| 866 | { |
| 867 | ItemInfo* pickup = nullptr; |
| 868 | |
| 869 | auto bounds = GameBoundingBox(item); |
| 870 | auto extents = bounds.GetExtents(); |
| 871 | auto origin = Geometry::TranslatePoint(item->Pose.Position.ToVector3(), item->Pose.Orientation, bounds.GetCenter()); |
| 872 | auto yPos = GetPointCollision(*item).GetFloorHeight(); |
| 873 | |
| 874 | origin.y = yPos; // Initialize drop origin Y point as floor height at centerpoint, in case all corner tests fail. |
| 875 | |
| 876 | auto collObjects = GetCollidedObjects(*item, true, true); |
| 877 | |
| 878 | short startAngle = ANGLE(Random::GenerateInt(0, 3) * 90.0f); // Randomize start corner. |
| 879 | |
| 880 | // Iterate through 4 corners and find best-fitting position, which is not inside a wall, not on a slope |
| 881 | // and also does not significantly differ in height to an object centerpoint height. |
| 882 | // If all corner tests will fail, a pickup will be spawned at bounding box centerpoint, as it does in tomb4. |
| 883 | |
| 884 | if (!disableAlignment) for (int corner = 0; corner < 4; corner++) |
| 885 | { |
| 886 | auto angle = item->Pose.Orientation; |
| 887 | angle.y += startAngle + corner * ANGLE(90.0f); |
| 888 | |
| 889 | // At first, do an inside-wall test at an extended extent point to make sure player can correctly align. |
| 890 | auto candidatePos = Geometry::TranslatePoint(origin, angle, extents * 1.2f); |
| 891 | candidatePos.y = yPos; |
| 892 | auto collPoint = GetPointCollision(candidatePos, item->RoomNumber); |
| 893 | |
| 894 | // If position is inside a wall or on a slope, don't use it. |
| 895 | if (collPoint.GetFloorHeight() == NO_HEIGHT || collPoint.IsSteepFloor() || collPoint.GetBottomSector().Flags.Death) |
| 896 | continue; |
| 897 | |
| 898 | // Remember floor position for a tested point. |
| 899 | int candidateYPos = collPoint.GetFloorHeight(); |
| 900 | |
| 901 | // Now repeat the same test for original extent point to make sure it's also valid. |
| 902 | candidatePos = Geometry::TranslatePoint(origin, angle, extents); |
| 903 | candidatePos.y = yPos; |
| 904 | collPoint = GetPointCollision(candidatePos, item->RoomNumber); |
| 905 | |
| 906 | // If position is inside a wall or on a slope, don't use it. |
| 907 | if (collPoint.GetFloorHeight() == NO_HEIGHT || collPoint.IsSteepFloor() || collPoint.GetBottomSector().Flags.Death) |
| 908 | continue; |
| 909 | |
| 910 | // If position is not in the same room, don't use it. |
| 911 | if (collPoint.GetRoomNumber() != item->RoomNumber) |
| 912 | continue; |
| 913 | |
| 914 | // Setup a dummy sphere with 1-click diameter for item and static mesh collision tests. |
| 915 | auto sphere = BoundingSphere(candidatePos, CLICK(0.5f)); |
| 916 | bool collidedWithObject = false; |
| 917 | |
| 918 | // Iterate through all found items and statics around, and determine if dummy sphere |
| 919 | // intersects any of those. If so, try other corner. |
| 920 | |
| 921 | for (const auto* itemPtr : collObjects.Items) |
| 922 | { |
no test coverage detected