* @brief Finds and sets the nearest valid entity as the creature's enemy. * * Searches through all active creatures and the player to find the closest * valid target. Used for creature-vs-creature combat and targeting systems. * * @param item The creature looking for a target. * @param keyObjectIds List of object IDs to specifically target or ignore. * @param ignoreKeyObjectIds If true, ign
| 323 | * @param ignoreKeyObjectIds If true, ignores objects in keyObjectIds; if false, ONLY targets them. |
| 324 | */ |
| 325 | void TargetNearestEntity(ItemInfo& item, const std::vector<GAME_OBJECT_ID>& keyObjectIds, bool ignoreKeyObjectIds) |
| 326 | { |
| 327 | auto& creature = *GetCreatureInfo(&item); |
| 328 | creature.Enemy = nullptr; |
| 329 | |
| 330 | float closestDistSqr = FLT_MAX; |
| 331 | for (auto creatureIndex : ActiveCreatures) |
| 332 | { |
| 333 | // Don't target itself. |
| 334 | if (creatureIndex == item.Index) |
| 335 | continue; |
| 336 | |
| 337 | auto& targetItem = g_Level.Items[creatureIndex]; |
| 338 | |
| 339 | // Don't target same object type. |
| 340 | if (item.ObjectNumber == targetItem.ObjectNumber) |
| 341 | continue; |
| 342 | |
| 343 | // Ignore or specifically target key object IDs. |
| 344 | if (!keyObjectIds.empty() && (ignoreKeyObjectIds ? Contains(keyObjectIds, targetItem.ObjectNumber) : !Contains(keyObjectIds, targetItem.ObjectNumber))) |
| 345 | continue; |
| 346 | |
| 347 | // Ignore undead enemies (can't be damaged normally). |
| 348 | if (Objects[targetItem.ObjectNumber].damageType != DamageMode::Any) |
| 349 | continue; |
| 350 | |
| 351 | if (&targetItem != &item && targetItem.HitPoints > 0 && targetItem.Status != ITEM_INVISIBLE) |
| 352 | { |
| 353 | float distSqr = Vector3i::DistanceSquared(item.Pose.Position, targetItem.Pose.Position); |
| 354 | if (distSqr < closestDistSqr) |
| 355 | { |
| 356 | creature.Enemy = &targetItem; |
| 357 | closestDistSqr = distSqr; |
| 358 | } |
| 359 | } |
| 360 | } |
| 361 | |
| 362 | // Handle player as special case (not in ActiveCreatures list). |
| 363 | if (!keyObjectIds.empty() && (ignoreKeyObjectIds ? Contains(keyObjectIds, ID_LARA) : !Contains(keyObjectIds, ID_LARA))) |
| 364 | return; |
| 365 | |
| 366 | float distToPlayerSqr = Vector3i::DistanceSquared(item.Pose.Position, LaraItem->Pose.Position); |
| 367 | if (distToPlayerSqr < closestDistSqr) |
| 368 | creature.Enemy = LaraItem; |
| 369 | } |
| 370 | |
| 371 | /** |
| 372 | * @brief Sets a specific item as the creature's AI target. |
no test coverage detected