# UNDF: UNDF-2026-000000975 --- a/src/projectiledef.h +++ b/src/projectiledef.h @@ -22,7 +22,7 @@ #ifndef __INCLUDED_PROJECTILEDEF_H__ #define __INCLUDED_PROJECTILEDEF_H__ -#include "basedef.h" +#include "basedef.h" // SIMPLE_OBJECT, BASE_OBJECT, OBJ_PROJECTILE #include "lib/gamelib/gtime.h" -#include +#include enum PROJ_STATE @@ -49,7 +49,7 @@ WEAPON_STATS *psWStats; ///< firing weapon stats BASE_OBJECT *psSource; ///< what fired the projectile BASE_OBJECT *psDest; ///< target of this projectile - std::vector psDamaged; ///< the targets that have already been dealt damage to (don't damage the same target twice) + std::unordered_set psDamaged; ///< the targets that have already been dealt damage to (O(1) lookup instead of O(N) linear scan) Vector3i src = Vector3i(0, 0, 0); ///< Where projectile started Vector3i dst = Vector3i(0, 0, 0); ///< The target coordinates --- a/src/projectile.cpp +++ b/src/projectile.cpp @@ -376,7 +376,7 @@ psProj->rot.direction, psProj->rot.pitch, psProj->rot.roll, psProj->state, (int)psProj->expectedDamageCaused, - (int)psProj->psDamaged.size(), + (int)psProj->psDamaged.size(), // unchanged: .size() works on unordered_set }; _syncDebugIntList(function, "%c projectile = p%d;pos(%d,%d,%d),rot(%d,%d,%d),state%d,expectedDamageCaused%d,numberDamaged%u", list, ARRAY_SIZE(list)); } @@ -869,7 +869,7 @@ BASE_OBJECT *psTempObj = *gi; CHECK_OBJECT(psTempObj); - if (std::find(psProj->psDamaged.begin(), psProj->psDamaged.end(), psTempObj) != psProj->psDamaged.end()) + if (psProj->psDamaged.count(psTempObj) != 0) { // Dont damage one target twice continue; @@ -950,7 +950,7 @@ asWeap.nStat = psStats - asWeaponStats.data(); // Assume we damaged the chosen target - psProj->psDamaged.push_back(closestCollisionObject); + psProj->psDamaged.insert(closestCollisionObject); spawnedProjectile = proj_SendProjectileInternal(&asWeap, psProj, psProj->player, psProj->dst, nullptr, true, -1); } @@ -1290,7 +1290,7 @@ if (relativeDamage >= 0) // So long as the target wasn't killed { - psObj->psDamaged.push_back(psObj->psDest); + psObj->psDamaged.insert(psObj->psDest); } } } @@ -1396,7 +1396,10 @@ setProjectileDestination(psObj, nullptr); } // Remove dead objects from psDamaged. - psDamaged.erase(std::remove_if(psDamaged.begin(), psDamaged.end(), [](const BASE_OBJECT *psObj) { return ::isDead(psObj); }), psDamaged.end()); + for (auto it = psDamaged.begin(); it != psDamaged.end(); ) + { + it = ::isDead(*it) ? psDamaged.erase(it) : std::next(it); + } // This extra check fixes a crash in cam2, mission1 if (worldOnMap(psObj->pos.x, psObj->pos.y) == false) @@ -1954,9 +1957,9 @@ checkObject(psProjectile->psSource, location_description, function, recurse - 1); } - for (unsigned n = 0; n != psProjectile->psDamaged.size(); ++n) + for (const auto *psObj : psProjectile->psDamaged) { - checkObject(psProjectile->psDamaged[n], location_description, function, recurse - 1); + checkObject(psObj, location_description, function, recurse - 1); } }