| 239 | } |
| 240 | |
| 241 | void UpdateFishSwarm() |
| 242 | { |
| 243 | constexpr auto WATER_SURFACE_OFFSET = CLICK(0.5f); |
| 244 | constexpr auto FLEE_VEL = 20.0f; |
| 245 | constexpr auto TARGET_REACHED_TOLERANCE = BLOCK(0.5f); |
| 246 | |
| 247 | static const auto SPHERE = BoundingSphere(Vector3::Zero, BLOCK(1 / 8.0f)); |
| 248 | |
| 249 | if (FishSwarm.empty()) |
| 250 | return; |
| 251 | |
| 252 | const auto& playerItem = *LaraItem; |
| 253 | const auto& player = GetLaraInfo(playerItem); |
| 254 | |
| 255 | const FishData* closestFishPtr = nullptr; |
| 256 | float minDistToTarget = FLT_MAX; |
| 257 | int minDist = INT_MAX; |
| 258 | |
| 259 | int fishID = 0; |
| 260 | for (auto& fish : FishSwarm) |
| 261 | { |
| 262 | if (fish.Life <= 0.0f) |
| 263 | continue; |
| 264 | |
| 265 | auto& leaderItem = *fish.LeaderItemPtr; |
| 266 | |
| 267 | if (!TriggerActive(&leaderItem)) |
| 268 | { |
| 269 | // Remove all fishes associated with this item. |
| 270 | RemoveFishSwarm(leaderItem); |
| 271 | |
| 272 | // Reset ItemFlags. |
| 273 | if (leaderItem.HitPoints == NOT_TARGETABLE) |
| 274 | leaderItem.HitPoints = leaderItem.ItemFlags[5]; |
| 275 | |
| 276 | leaderItem.Pose.Position = leaderItem.StartPose.Position; |
| 277 | leaderItem.ItemFlags[5] = 0; |
| 278 | return; |
| 279 | } |
| 280 | |
| 281 | fish.StoreInterpolationData(); |
| 282 | |
| 283 | // Increase separation distance for each fish. |
| 284 | float separationDist = FISH_BASE_SEPARATION_DISTANCE + (fishID * 3); |
| 285 | fishID += 1; |
| 286 | |
| 287 | if (!leaderItem.ItemFlags[2] && fish.TargetItemPtr == fish.LeaderItemPtr) |
| 288 | { |
| 289 | if (!fish.IsPatrolling) |
| 290 | { |
| 291 | fish.TargetItemPtr->Pose.Position = GetFishStartPosition(leaderItem); |
| 292 | |
| 293 | if (fish.TargetItemPtr->Pose.Position != Vector3::Zero) |
| 294 | leaderItem.ItemFlags[2] = 1; |
| 295 | } |
| 296 | } |
| 297 | |
| 298 | int enemyVel = (fish.TargetItemPtr != fish.LeaderItemPtr) ? 16.0f : 26.0f; |
no test coverage detected