---
 src/projectile.c |  334 +++++++++++++++++++++++------------------------------
 1 files changed, 145 insertions(+), 189 deletions(-)
diff --git a/src/projectile.c b/src/projectile.c
index 15363bf..1389d4c 100644
--- a/src/projectile.c
+++ b/src/projectile.c
@@ -901,253 +901,209 @@ static void proj_InFlightDirectFunc( PROJECTILE *psProj )
 
 /***************************************************************************/
 
-static void proj_InFlightIndirectFunc( PROJECTILE *psObj )
+static void proj_InFlightIndirectFunc( PROJECTILE *psProj )
 {
-	WEAPON_STATS	*psStats;
-	SDWORD			iTime, iRad, iDist, dx, dy, dz, iX, iY;
-	Vector3i pos;
-	float			fVVert;
-	BOOL			bOver = false;
-	BASE_OBJECT		*psNewTarget;
-	UDWORD			i;
-	SDWORD			xdiff,ydiff,extendRad;
-	UDWORD			zdiff;
-	BOOL			bPenetrate;
-	WEAPON			asWeap;
+	/* NOTE Main differences to direct projectiles:
+		- Movement vector / pitch update
+		- No extended radius
+		- Some optimisations by leaving out tests which are never true (homing, AA, counter-missile, lassat)
+	*/
 
-	CHECK_PROJECTILE(psObj);
+	unsigned int timeSoFar;
+	unsigned int distancePercent; /* How far we are 0..100 */
+	float distanceRatio; /* How far we are, 1.0==at target */
+	float distanceExtensionFactor; /* Extended lifespan */
+	Vector3i move;
+	unsigned int i;
+	WEAPON_STATS *psStats;
 
-	psStats = psObj->psWStats;
-	bPenetrate = psStats->penetrate;
+	CHECK_PROJECTILE(psProj);
+
+	timeSoFar = gameTime - psProj->born;
+
+	psStats = psProj->psWStats;
 	ASSERT( psStats != NULL,
 		"proj_InFlightIndirectFunc: Invalid weapon stats pointer" );
 
-	iTime = gameTime - psObj->born;
+	/* Calculate extended lifespan where appropriate */
+	distanceExtensionFactor = 1.2f;
 
-	dx = (SDWORD)psObj->tarX-(SDWORD)psObj->startX;
-	dy = (SDWORD)psObj->tarY-(SDWORD)psObj->startY;
+	/* Do movement */
+	{
+		unsigned int targetDistance, currentDistance;
 
-	// ffs
-	iRad = (SDWORD)sqrtf( dx*dx + dy*dy );
+		/* Calculate movement vector: */
+		move.x = psProj->tarX - psProj->startX;
+		move.y = psProj->tarY - psProj->startY;
+		move.z = (psProj->vZ - (timeSoFar * ACC_GRAVITY / (GAME_TICKS_PER_SEC * 2))) * timeSoFar / GAME_TICKS_PER_SEC; // '2' because we reach our highest point in the mid of flight, when "vZ is 0".
 
-	iDist = iTime * psObj->vXY / GAME_TICKS_PER_SEC;
+		targetDistance = sqrtf( move.x*move.x + move.y*move.y );
+		currentDistance = timeSoFar * psProj->vXY / GAME_TICKS_PER_SEC; // FIXME ARTILLERY
 
-	iX = psObj->startX + (iDist * dx / iRad);
-	iY = psObj->startY + (iDist * dy / iRad);
+		// Prevent div by zero:
+		if ( targetDistance == 0 )
+			targetDistance = 1;
 
-	/* impact if about to go off map else update coordinates */
-	if ( !worldOnMap( iX, iY ) )
-	{
-	  	psObj->state = PROJ_IMPACT;
-		debug( LOG_NEVER, "**** projectile off map - removed ****\n" );
-		return;
-	}
-	else
-	{
-		psObj->pos.x = (UWORD)iX;
-		psObj->pos.y = (UWORD)iY;
-	}
+		distanceRatio = (float)currentDistance / targetDistance;
+		distancePercent = PERCENT(currentDistance, targetDistance);
 
-	dz = (psObj->vZ - (iTime*ACC_GRAVITY/GAME_TICKS_PER_SEC/2)) *
-				iTime / GAME_TICKS_PER_SEC;
-	psObj->pos.z = (UWORD)(psObj->srcHeight + dz);
+		{
+			/* Calculate next position */
+			Vector3uw nextPos = {
+				psProj->startX + (distanceRatio * move.x),
+				psProj->startY + (distanceRatio * move.y),
+				psProj->srcHeight + move.z
+			};
 
-	fVVert = psObj->vZ - (iTime * ACC_GRAVITY / GAME_TICKS_PER_SEC);
-	psObj->pitch = (SWORD)( RAD_TO_DEG(atan2(fVVert, psObj->vXY)) );
+			/* impact if about to go off map else update coordinates */
+			if ( !worldOnMap( nextPos.x, nextPos.y ) )
+			{
+				psProj->state = PROJ_IMPACT;
+				setProjectileDestination(psProj, NULL);
+				debug( LOG_NEVER, "**** projectile off map - removed ****\n" );
+				return;
+			}
 
-	//Watermelon:extended life span for artillery projectile
-	extendRad = (SDWORD)(iRad * 1.2f);
+			/* Update position */
+			psProj->pos = nextPos;
+		}
+	}
 
-	if( gfxVisible(psObj) )
+	/* Update pitch */
 	{
-		switch(psStats->weaponSubClass)
-		{
-			case WSC_MGUN:
-			case WSC_CANNON:
-			case WSC_MORTARS:
-			case WSC_ENERGY:
-			case WSC_GAUSS:
-			case WSC_HOWITZERS:
-			case WSC_AAGUN:
-			case WSC_LAS_SAT:
-			case WSC_BOMB:
-			case WSC_COUNTER:
-			case NUM_WEAPON_SUBCLASS:
-			case INVALID_SUBCLASS:
-				break;
-			case WSC_FLAME:
-				effectGiveAuxVar(PERCENT(iDist,iRad));
-				pos.x = psObj->pos.x;
-				pos.y = psObj->pos.z-8;
-				pos.z = psObj->pos.y;
-				addEffect(&pos,EFFECT_EXPLOSION,EXPLOSION_TYPE_FLAMETHROWER,false,NULL,0);
-				break;
-			case WSC_COMMAND:
-			case WSC_ELECTRONIC:
-			case WSC_EMP:
-				effectGiveAuxVar((PERCENT(iDist,iRad)/2));
-				pos.x = psObj->pos.x;
-				pos.y = psObj->pos.z-8;
-				pos.z = psObj->pos.y;
-				addEffect(&pos,EFFECT_EXPLOSION,EXPLOSION_TYPE_LASER,false,NULL,0);
-				break;
-			case WSC_ROCKET:
-			case WSC_MISSILE:
-			case WSC_SLOWROCKET:
-			case WSC_SLOWMISSILE:
-				pos.x = psObj->pos.x;
-				pos.y = psObj->pos.z+8;
-				pos.z = psObj->pos.y;
-				addEffect(&pos,EFFECT_SMOKE,SMOKE_TYPE_TRAIL,false,NULL,0);
-				break;
-		}
+		float fVVert = psProj->vZ - (timeSoFar * ACC_GRAVITY / GAME_TICKS_PER_SEC);
+		psProj->pitch = rad2degf(atan2f(fVVert, psProj->vXY));
 	}
 
-	//Watermelon:test test
-	for (i = 0;i < numProjNaybors;i++)
+	for (i = 0; i < numProjNaybors; i++)
 	{
 		BASE_OBJECT *psTempObj = asProjNaybors[i].psObj;
 
 		CHECK_OBJECT(psTempObj);
 
-		//Watermelon;dont collide with any other projectiles
+		if ( psTempObj == psProj->psDamaged )
+		{
+			// Dont damage one target twice
+			continue;
+		}
+
+		if ( psTempObj->died )
+		{
+			// Do not damage dead objects further
+			continue;
+		}
+
 		if ( psTempObj->type == OBJ_PROJECTILE )
 		{
+			// A projectile should not collide with another projectile unless it's a counter-missile weapon
+			// FIXME Indirectly firing weapons are never counter-missiles?
 			continue;
 		}
 
-		//Watermelon:ignore oil resource and pickup
 		if ( psTempObj->type == OBJ_FEATURE &&
-			((FEATURE *)psTempObj)->psStats->damageable == 0 )
+			!((FEATURE *)psTempObj)->psStats->damageable )
 		{
+			// Ignore oil resources, artifacts and other pickups
 			continue;
 		}
 
-		if (psTempObj->died)
+		if ( psTempObj->player == psProj->player ||
+			aiCheckAlliances(psTempObj->player, psProj->player) )
 		{
+			// No friendly fire
 			continue;
 		}
 
-		if (psTempObj->player != psObj->player &&
-			(psTempObj->type == OBJ_DROID ||
-			psTempObj->type == OBJ_STRUCTURE ||
-			psTempObj->type == OBJ_PROJECTILE ||
-			psTempObj->type == OBJ_FEATURE) &&
-			!aiCheckAlliances(psTempObj->player,psObj->player))
 		{
-			if ( psTempObj->type == OBJ_STRUCTURE || psTempObj->type == OBJ_FEATURE )
-			{
-				xdiff = (SDWORD)psObj->pos.x - (SDWORD)psTempObj->pos.x;
-				ydiff = (SDWORD)psObj->pos.y - (SDWORD)psTempObj->pos.y;
-				zdiff = abs((UDWORD)psObj->pos.z - (UDWORD)psTempObj->pos.z);
+			// FIXME HACK Needed since we got those ugly Vector3uw floating around in BASE_OBJECT...
+			Vector3i
+				posProj = { psProj->pos.x, psProj->pos.y, psProj->pos.z },
+				posTemp = { psTempObj->pos.x, psTempObj->pos.y, psTempObj->pos.z };
 
-				if ( zdiff < establishTargetHeight(psTempObj) &&
-					(xdiff*xdiff + ydiff*ydiff) < ( (SDWORD)establishTargetRadius(psTempObj) * (SDWORD)establishTargetRadius(psTempObj) ) )
-				{
-					psNewTarget = psTempObj;
-					setProjectileDestination(psObj, psNewTarget);
-		  			psObj->state = PROJ_IMPACT;
-					return;
-				}
-			}
-			else
-			{
-				xdiff = (SDWORD)psObj->pos.x - (SDWORD)psTempObj->pos.x;
-				ydiff = (SDWORD)psObj->pos.y - (SDWORD)psTempObj->pos.y;
-				zdiff = abs((UDWORD)psObj->pos.z - (UDWORD)psTempObj->pos.z);
+			Vector3i diff = Vector3i_Sub(posProj, posTemp);
 
-				if ( zdiff < establishTargetHeight(psTempObj) &&
-					(UDWORD)(xdiff*xdiff + ydiff*ydiff) < ( (SDWORD)establishTargetRadius(psTempObj) * (SDWORD)establishTargetRadius(psTempObj) ) )
-				{
-					psNewTarget = psTempObj;
-					setProjectileDestination(psObj, psNewTarget);
+			unsigned int targetHeight = establishTargetHeight(psTempObj);
+			unsigned int targetRadius = establishTargetRadius(psTempObj);
 
-					if (bPenetrate)
-					{
-						// Determine position to fire a missile at
-						// (must be at least 0 because we don't use signed integers
-						//  this shouldn't be larger than the height and width of the map either)
-						Vector3i target = {
-							psObj->startX + extendRad * dx / iRad,
-							psObj->startY + extendRad * dy / iRad,
-							psObj->pos.z
-						};
-						target.x = clip(target.x, 0, world_coord(mapWidth - 1));
-						target.y = clip(target.y, 0, world_coord(mapHeight - 1));
-
-						asWeap.nStat = psObj->psWStats - asWeaponStats;
-
-						//Watermelon:just assume we damaged the chosen target
-						setProjectileDamaged(psObj, psNewTarget);
-
-						proj_SendProjectile( &asWeap, (BASE_OBJECT*)psObj, psObj->player, target, NULL, true, -1 );
-					}
+			/* Height is always positive */
+			diff.z = abs(diff.z);
 
-					psObj->state = PROJ_IMPACT;
+			/* We hit! */
+			if ( diff.z < targetHeight &&
+				(diff.x*diff.x + diff.y*diff.y) < targetRadius * targetRadius )
+			{
+				setProjectileDestination(psProj, psTempObj);
 
-					return;
-				}
-			}
-		}
-	}
+				/* Buildings cannot be penetrated and we need a penetrating weapon */
+				if ( psTempObj->type == OBJ_DROID && psStats->penetrate )
+				{
+					WEAPON asWeap = { psStats - asWeaponStats, 0, 0, 0, 0 };
+					// Determine position to fire a missile at
+					// (must be at least 0 because we don't use signed integers
+					//  this shouldn't be larger than the height and width of the map either)
+					Vector3i newDest = {
+						psProj->startX + move.x * distanceExtensionFactor,
+						psProj->startY + move.y * distanceExtensionFactor,
+						psProj->srcHeight + move.z * distanceExtensionFactor
+					};
 
-	/* See if effect has finished */
-	if ( iDist > (extendRad - (SDWORD)psObj->targetRadius) )
-	{
-		psObj->state = PROJ_IMPACT;
+					newDest.x = clip(newDest.x, 0, world_coord(mapWidth - 1));
+					newDest.y = clip(newDest.y, 0, world_coord(mapHeight - 1));
 
-		pos.x = psObj->pos.x;
-		pos.z = psObj->pos.y;
-		pos.y = map_Height(pos.x,pos.z) + 8;
+					//Watermelon:just assume we damaged the chosen target
+					setProjectileDamaged(psProj, psTempObj);
 
-		/* It's damage time */
-		//Watermelon:'real' check
-		if ( psObj->psDest )
-		{
-			psObj->pos.z = (UWORD)(pos.y + 8); // bring up the impact explosion
+					proj_SendProjectile( &asWeap, (BASE_OBJECT*)psProj, psProj->player, newDest, NULL, true, -1 );
+				}
 
-			xdiff = (SDWORD)psObj->pos.x - (SDWORD)psObj->psDest->pos.x;
-			ydiff = (SDWORD)psObj->pos.y - (SDWORD)psObj->psDest->pos.y;
-			zdiff = abs((UDWORD)psObj->pos.z - (UDWORD)psObj->psDest->pos.z);
+				psProj->state = PROJ_IMPACT;
 
-			if ( zdiff < establishTargetHeight(psObj->psDest) &&
-				(xdiff*xdiff + ydiff*ydiff) < (SDWORD)( establishTargetRadius(psObj->psDest) * establishTargetRadius(psObj->psDest) ) )
-			{
-				psObj->state = PROJ_IMPACT;
-			}
-			else
-			{
-				setProjectileDestination(psObj, NULL);
+				return;
 			}
 		}
-		bOver = true;
 	}
 
-	/* check not trying to travel through terrain - if so count as a miss */
-	if ( mapObjIsAboveGround( (BASE_OBJECT *) psObj ) == false )
+	if ( distanceRatio > distanceExtensionFactor || /* We've traveled our maximum range */
+		!mapObjIsAboveGround( (BASE_OBJECT *) psProj ) ) /* trying to travel through terrain */
 	{
-		psObj->state = PROJ_IMPACT;
-		/* miss registered if NULL target */
-		setProjectileDestination(psObj, NULL);
-		bOver = true;
+		/* Miss due to range or height */
+		psProj->state = PROJ_IMPACT;
+		setProjectileDestination(psProj, NULL); /* miss registered if NULL target */
+		return;
 	}
 
-	/* Add smoke particle at projectile location (in world coords) */
-	/* Add a trail graphic */
-	/* If it's indirect and not a flamethrower - add a smoke trail! */
-	if ( psStats->weaponSubClass != WSC_FLAME &&
-		psStats->weaponSubClass != WSC_ENERGY &&
-		psStats->weaponSubClass != WSC_COMMAND &&
-		psStats->weaponSubClass != WSC_ELECTRONIC &&
-		psStats->weaponSubClass != WSC_EMP &&
-		!bOver )
+	/* Paint effects if visible */
+	if ( gfxVisible(psProj) )
 	{
-		if(gfxVisible(psObj))
+		switch (psStats->weaponSubClass)
 		{
-			pos.x = psObj->pos.x;
-			pos.y = psObj->pos.z+4;
-			pos.z = psObj->pos.y;
-			addEffect(&pos,EFFECT_SMOKE,SMOKE_TYPE_TRAIL,false,NULL,0);
+			case WSC_FLAME:
+			{
+				Vector3i pos = { psProj->pos.x, psProj->pos.z-8, psProj->pos.y };
+				effectGiveAuxVar(distancePercent);
+				addEffect(&pos,EFFECT_EXPLOSION,EXPLOSION_TYPE_FLAMETHROWER,false,NULL,0);
+			} break;
+			case WSC_COMMAND:
+			case WSC_ELECTRONIC:
+			case WSC_EMP:
+			{
+				Vector3i pos = { psProj->pos.x, psProj->pos.z-8, psProj->pos.y };
+				effectGiveAuxVar(distancePercent/2);
+				addEffect(&pos,EFFECT_EXPLOSION,EXPLOSION_TYPE_LASER,false,NULL,0);
+			} break;
+			case WSC_ROCKET:
+			case WSC_MISSILE:
+			case WSC_SLOWROCKET:
+			case WSC_SLOWMISSILE:
+			{
+				Vector3i pos = { psProj->pos.x, psProj->pos.z+8, psProj->pos.y };
+				addEffect(&pos,EFFECT_SMOKE,SMOKE_TYPE_TRAIL,false,NULL,0);
+			} break;
+			default:
+			{
+				Vector3i pos = { psProj->pos.x, psProj->pos.z+4, psProj->pos.y };
+				addEffect(&pos,EFFECT_SMOKE,SMOKE_TYPE_TRAIL,false,NULL,0);
+			} break;
 		}
 	}
 }
_______________________________________________
Warzone-dev mailing list
Warzone-dev@gna.org
https://mail.gna.org/listinfo/warzone-dev

Reply via email to