Fix projectile crash. Iteration became screwed up sometimes when a projectile

object was free()d and its memory was overwritten before we had time to iterate
to the next object in the list. Now we delay free() until after updates are done.


git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@2073 4a71c877-e1ca-e34f-864e-861f7616d084
master
Per Inge Mathisen 2007-07-13 20:55:50 +00:00
parent aa061810a5
commit bc383a6997
2 changed files with 34 additions and 36 deletions

View File

@ -222,38 +222,6 @@ static void proj_Free(PROJECTILE *psObj)
free(psObj);
}
// Take a projectile out of the global list and shoot it...
static void proj_Destroy(PROJECTILE *psObj)
{
PROJECTILE *psCurr = psProjectileList, *psPrev = NULL;
CHECK_PROJECTILE(psObj);
// is it the first node?
if (psCurr == psObj)
{
psProjectileList = psCurr->psNext;
proj_Free(psCurr);
return;
}
// is in list
while (psCurr)
{
psPrev = psCurr;
psCurr = psCurr->psNext;
if (psCurr == psObj)
{
psPrev->psNext = psCurr->psNext;
proj_Free(psCurr);
return;
}
}
// oops
ASSERT(!"projectile not found", "projectile not in global list");
}
/***************************************************************************/
// Reset the first/next methods, and give out the first projectile in the list.
@ -392,6 +360,7 @@ proj_SendProjectile( WEAPON *psWeap, BASE_OBJECT *psAttacker, SDWORD player,
psObj->psDamaged = NULL; // must initialize these to NULL first!
psObj->psSource = NULL;
psObj->psDest = NULL;
psObj->died = 0;
setProjectileDestination(psObj, psTarget);
ASSERT(!psTarget || !psTarget->died, "Aiming at dead target!");
@ -1362,7 +1331,7 @@ proj_ImpactFunc( PROJECTILE *psObj )
&& ((FEATURE *)psObj->psDest)->psStats->damageable == 0)
{
debug(LOG_NEVER, "proj_ImpactFunc: trying to damage non-damageable target,projectile removed");
proj_Destroy(psObj);
psObj->died = gameTime;
return;
}
@ -1451,7 +1420,7 @@ proj_ImpactFunc( PROJECTILE *psObj )
// If the projectile does no splash damage and does not set fire to things
if ((psStats->radius == 0) && (psStats->incenTime == 0) )
{
proj_Destroy(psObj);
psObj->died = gameTime;
return;
}
@ -1736,7 +1705,7 @@ proj_PostImpactFunc( PROJECTILE *psObj )
/* Time to finish postimpact effect? */
if (age > (SDWORD)psStats->radiusLife && age > (SDWORD)psStats->incenTime)
{
proj_Destroy(psObj);
psObj->died = gameTime;
return;
}
@ -1812,12 +1781,40 @@ proj_Update( PROJECTILE *psObj )
void
proj_UpdateAll( void )
{
PROJECTILE *psObj;
PROJECTILE *psObj, *psPrev;
for (psObj = psProjectileList; psObj != NULL; psObj = psObj->psNext)
{
proj_Update( psObj );
}
// Now delete any dead projectiles
psObj = psProjectileList;
// is the first node dead?
while (psObj && psObj == psProjectileList && psObj->died)
{
psProjectileList = psObj->psNext;
proj_Free(psObj);
psObj = psProjectileList;
}
// first object is now either NULL or not dead, so we have time to set this below
psPrev = NULL;
// are any in the list dead?
while (psObj)
{
if (psObj->died)
{
psPrev->psNext = psObj->psNext;
proj_Free(psObj);
psObj = psPrev->psNext;
} else {
psPrev = psObj;
psObj = psObj->psNext;
}
}
}
/***************************************************************************/

View File

@ -70,6 +70,7 @@ typedef struct PROJECTILE
SDWORD altChange; /* Change in altitude */
UDWORD born;
UDWORD targetRadius; // needed to backtrack the projectiles.
UDWORD died;
PROJECTILE_FUNC pInFlightFunc;
}