After these changes, the 2 functions look like attached, with the also attached differences.
static void proj_InFlightDirectFunc( PROJECTILE *psProj )
{
/* we want a delay between Las-Sats firing and actually hitting in multiPlayer
magic number but that's how long the audio countdown message lasts! */
const unsigned int LAS_SAT_DELAY = 8;
int timeSoFar;
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;
// Projectile is missile:
bool bMissile = false;
WEAPON_STATS *psStats;
CHECK_PROJECTILE(psProj);
timeSoFar = gameTime - psProj->born;
psStats = psProj->psWStats;
ASSERT( psStats != NULL,
"proj_InFlightDirectFunc: Invalid weapon stats pointer" );
/* we want a delay between Las-Sats firing and actually hitting in multiPlayer
magic number but that's how long the audio countdown message lasts! */
if ( bMultiPlayer && psStats->weaponSubClass == WSC_LAS_SAT &&
timeSoFar < LAS_SAT_DELAY * GAME_TICKS_PER_SEC )
{
return;
}
/* Calculate extended lifespan where appropriate */
switch (psStats->weaponSubClass)
{
case WSC_MGUN:
case WSC_COMMAND:
distanceExtensionFactor = 1.2f;
break;
case WSC_CANNON:
case WSC_BOMB:
case WSC_ELECTRONIC:
case WSC_EMP:
case WSC_FLAME:
case WSC_ENERGY:
case WSC_GAUSS:
distanceExtensionFactor = 1.5f;
break;
case WSC_AAGUN: // No extended distance
distanceExtensionFactor = 1.0f;
break;
case WSC_ROCKET:
case WSC_MISSILE:
case WSC_SLOWROCKET:
case WSC_SLOWMISSILE:
bMissile = true; // Take the same extended targetDistance as artillery
case WSC_COUNTER:
case WSC_MORTARS:
case WSC_HOWITZERS:
case WSC_LAS_SAT:
distanceExtensionFactor = 1.5f;
break;
default:
// NUM_WEAPON_SUBCLASS and INVALID_SUBCLASS
break;
}
/* Do movement */
{
unsigned int targetDistance, currentDistance;
/* Calculate movement vector: */
if ( psStats->movementModel == MM_HOMINGDIRECT && psProj->psDest )
{
/* If it's homing and it has a target (not a miss)... */
move.x = psProj->psDest->pos.x - psProj->startX;
move.y = psProj->psDest->pos.y - psProj->startY;
move.z = psProj->psDest->pos.z - psProj->srcHeight;
}
else
{
move.x = psProj->tarX - psProj->startX;
move.y = psProj->tarY - psProj->startY;
move.z = psProj->altChange;
}
targetDistance = sqrtf( move.x*move.x + move.y*move.y );
currentDistance = timeSoFar * psStats->flightSpeed / GAME_TICKS_PER_SEC;
// Prevent div by zero:
if ( targetDistance == 0 )
targetDistance = 1;
distanceRatio = (float)currentDistance / targetDistance;
distancePercent = PERCENT(currentDistance, targetDistance);
{
/* Calculate next position */
Vector3uw nextPos = {
psProj->startX + (distanceRatio * move.x),
psProj->startY + (distanceRatio * move.y),
psProj->srcHeight + (distanceRatio * move.z)
};
/* 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;
}
/* Update position */
psProj->pos = nextPos;
}
}
for (i = 0; i < numProjNaybors; i++)
{
BASE_OBJECT *psTempObj = asProjNaybors[i].psObj;
CHECK_OBJECT(psTempObj);
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 &&
!( bMissile || ((PROJECTILE *)psTempObj)->psWStats->weaponSubClass == WSC_COUNTER ) )
{
// A projectile should not collide with another projectile unless it's a counter-missile weapon
continue;
}
if ( psTempObj->type == OBJ_FEATURE &&
!((FEATURE *)psTempObj)->psStats->damageable )
{
// Ignore oil resources, artifacts and other pickups
continue;
}
if ( psTempObj->player == psProj->player ||
aiCheckAlliances(psTempObj->player, psProj->player) )
{
// No friendly fire
continue;
}
if ( psStats->surfaceToAir == SHOOT_IN_AIR &&
( psTempObj->type == OBJ_STRUCTURE ||
psTempObj->type == OBJ_FEATURE ||
( psTempObj->type == OBJ_DROID && !vtolDroid((DROID *)psTempObj) )
) )
{
// AA weapons should not hit buildings and non-vtol droids
continue;
}
{
// 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 };
Vector3i diff = Vector3i_Sub(posProj, posTemp);
unsigned int targetHeight = establishTargetHeight(psTempObj);
unsigned int targetRadius = establishTargetRadius(psTempObj);
/* Height is always positive */
diff.z = abs(diff.z);
/* We hit! */
if ( diff.z < targetHeight &&
(diff.x*diff.x + diff.y*diff.y) < targetRadius * targetRadius )
{
setProjectileDestination(psProj, psTempObj);
/* 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
};
newDest.x = clip(newDest.x, 0, world_coord(mapWidth - 1));
newDest.y = clip(newDest.y, 0, world_coord(mapHeight - 1));
//Watermelon:just assume we damaged the chosen target
setProjectileDamaged(psProj, psTempObj);
proj_SendProjectile( &asWeap, (BASE_OBJECT*)psProj, psProj->player, newDest, NULL, true, -1 );
}
psProj->state = PROJ_IMPACT;
return;
}
}
}
if ( distanceRatio > distanceExtensionFactor || /* We've traveled our maximum range */
!mapObjIsAboveGround( (BASE_OBJECT *) psProj ) ) /* trying to travel through terrain */
{
/* Miss due to range or height */
psProj->state = PROJ_IMPACT;
setProjectileDestination(psProj, NULL); /* miss registered if NULL target */
return;
}
/* Paint effects if visible */
if ( gfxVisible(psProj) )
{
switch (psStats->weaponSubClass)
{
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:
/* add smoke trail to indirect weapons firing directly */
if ( !proj_Direct(psStats) )
{
Vector3i pos = { psProj->pos.x, psProj->pos.z+4, psProj->pos.y };
addEffect(&pos,EFFECT_SMOKE,SMOKE_TYPE_TRAIL,false,NULL,0);
}
/* Otherwise no effect */
break;
}
}
}
static void proj_InFlightIndirectFunc( PROJECTILE *psProj )
{
/* 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)
*/
int timeSoFar;
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;
CHECK_PROJECTILE(psProj);
timeSoFar = gameTime - psProj->born;
psStats = psProj->psWStats;
ASSERT( psStats != NULL,
"proj_InFlightIndirectFunc: Invalid weapon stats pointer" );
/* Calculate extended lifespan where appropriate */
distanceExtensionFactor = 1.2f;
/* Do movement */
{
unsigned int targetDistance, currentDistance;
/* 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".
targetDistance = sqrtf( move.x*move.x + move.y*move.y );
currentDistance = timeSoFar * psProj->vXY / GAME_TICKS_PER_SEC; // FIXME ARTILLERY
// Prevent div by zero:
if ( targetDistance == 0 )
targetDistance = 1;
distanceRatio = (float)currentDistance / targetDistance;
distancePercent = PERCENT(currentDistance, targetDistance);
{
/* Calculate next position */
Vector3uw nextPos = {
psProj->startX + (distanceRatio * move.x),
psProj->startY + (distanceRatio * move.y),
psProj->srcHeight + move.z
};
/* 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;
}
/* Update position */
psProj->pos = nextPos;
}
}
/* Update pitch */
{
float fVVert = psProj->vZ - (timeSoFar * ACC_GRAVITY / GAME_TICKS_PER_SEC);
psProj->pitch = rad2degf(atan2f(fVVert, psProj->vXY));
}
for (i = 0; i < numProjNaybors; i++)
{
BASE_OBJECT *psTempObj = asProjNaybors[i].psObj;
CHECK_OBJECT(psTempObj);
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;
}
if ( psTempObj->type == OBJ_FEATURE &&
!((FEATURE *)psTempObj)->psStats->damageable )
{
// Ignore oil resources, artifacts and other pickups
continue;
}
if ( psTempObj->player == psProj->player ||
aiCheckAlliances(psTempObj->player, psProj->player) )
{
// No friendly fire
continue;
}
{
// 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 };
Vector3i diff = Vector3i_Sub(posProj, posTemp);
unsigned int targetHeight = establishTargetHeight(psTempObj);
unsigned int targetRadius = establishTargetRadius(psTempObj);
/* Height is always positive */
diff.z = abs(diff.z);
/* We hit! */
if ( diff.z < targetHeight &&
(diff.x*diff.x + diff.y*diff.y) < targetRadius * targetRadius )
{
setProjectileDestination(psProj, psTempObj);
/* 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
};
newDest.x = clip(newDest.x, 0, world_coord(mapWidth - 1));
newDest.y = clip(newDest.y, 0, world_coord(mapHeight - 1));
//Watermelon:just assume we damaged the chosen target
setProjectileDamaged(psProj, psTempObj);
proj_SendProjectile( &asWeap, (BASE_OBJECT*)psProj, psProj->player, newDest, NULL, true, -1 );
}
psProj->state = PROJ_IMPACT;
return;
}
}
}
if ( distanceRatio > distanceExtensionFactor || /* We've traveled our maximum range */
!mapObjIsAboveGround( (BASE_OBJECT *) psProj ) ) /* trying to travel through terrain */
{
/* Miss due to range or height */
psProj->state = PROJ_IMPACT;
setProjectileDestination(psProj, NULL); /* miss registered if NULL target */
return;
}
/* Paint effects if visible */
if ( gfxVisible(psProj) )
{
switch (psStats->weaponSubClass)
{
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;
}
}
}
--- proj_direct.c 2008-05-22 23:25:00.000000000 +0200
+++ proj_indirect.c 2008-05-22 23:24:36.000000000 +0200
@@ -1,16 +1,17 @@
-static void proj_InFlightDirectFunc( PROJECTILE *psProj )
+static void proj_InFlightIndirectFunc( PROJECTILE *psProj )
{
- /* we want a delay between Las-Sats firing and actually hitting in multiPlayer
- magic number but that's how long the audio countdown message lasts! */
- const unsigned int LAS_SAT_DELAY = 8;
+ /* 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)
+ */
+
int timeSoFar;
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;
- // Projectile is missile:
- bool bMissile = false;
WEAPON_STATS *psStats;
CHECK_PROJECTILE(psProj);
@@ -19,72 +20,22 @@
psStats = psProj->psWStats;
ASSERT( psStats != NULL,
- "proj_InFlightDirectFunc: Invalid weapon stats pointer" );
-
- /* we want a delay between Las-Sats firing and actually hitting in multiPlayer
- magic number but that's how long the audio countdown message lasts! */
- if ( bMultiPlayer && psStats->weaponSubClass == WSC_LAS_SAT &&
- timeSoFar < LAS_SAT_DELAY * GAME_TICKS_PER_SEC )
- {
- return;
- }
+ "proj_InFlightIndirectFunc: Invalid weapon stats pointer" );
/* Calculate extended lifespan where appropriate */
- switch (psStats->weaponSubClass)
- {
- case WSC_MGUN:
- case WSC_COMMAND:
- distanceExtensionFactor = 1.2f;
- break;
- case WSC_CANNON:
- case WSC_BOMB:
- case WSC_ELECTRONIC:
- case WSC_EMP:
- case WSC_FLAME:
- case WSC_ENERGY:
- case WSC_GAUSS:
- distanceExtensionFactor = 1.5f;
- break;
- case WSC_AAGUN: // No extended distance
- distanceExtensionFactor = 1.0f;
- break;
- case WSC_ROCKET:
- case WSC_MISSILE:
- case WSC_SLOWROCKET:
- case WSC_SLOWMISSILE:
- bMissile = true; // Take the same extended targetDistance as artillery
- case WSC_COUNTER:
- case WSC_MORTARS:
- case WSC_HOWITZERS:
- case WSC_LAS_SAT:
- distanceExtensionFactor = 1.5f;
- break;
- default:
- // NUM_WEAPON_SUBCLASS and INVALID_SUBCLASS
- break;
- }
+ distanceExtensionFactor = 1.2f;
/* Do movement */
{
unsigned int targetDistance, currentDistance;
/* Calculate movement vector: */
- if ( psStats->movementModel == MM_HOMINGDIRECT && psProj->psDest )
- {
- /* If it's homing and it has a target (not a miss)... */
- move.x = psProj->psDest->pos.x - psProj->startX;
- move.y = psProj->psDest->pos.y - psProj->startY;
- move.z = psProj->psDest->pos.z - psProj->srcHeight;
- }
- else
- {
- move.x = psProj->tarX - psProj->startX;
- move.y = psProj->tarY - psProj->startY;
- move.z = psProj->altChange;
- }
+ 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".
targetDistance = sqrtf( move.x*move.x + move.y*move.y );
- currentDistance = timeSoFar * psStats->flightSpeed / GAME_TICKS_PER_SEC;
+ currentDistance = timeSoFar * psProj->vXY / GAME_TICKS_PER_SEC; // FIXME ARTILLERY
// Prevent div by zero:
if ( targetDistance == 0 )
@@ -98,7 +49,7 @@
Vector3uw nextPos = {
psProj->startX + (distanceRatio * move.x),
psProj->startY + (distanceRatio * move.y),
- psProj->srcHeight + (distanceRatio * move.z)
+ psProj->srcHeight + move.z
};
/* impact if about to go off map else update coordinates */
@@ -115,6 +66,12 @@
}
}
+ /* Update pitch */
+ {
+ float fVVert = psProj->vZ - (timeSoFar * ACC_GRAVITY / GAME_TICKS_PER_SEC);
+ psProj->pitch = rad2degf(atan2f(fVVert, psProj->vXY));
+ }
+
for (i = 0; i < numProjNaybors; i++)
{
BASE_OBJECT *psTempObj = asProjNaybors[i].psObj;
@@ -133,10 +90,10 @@
continue;
}
- if ( psTempObj->type == OBJ_PROJECTILE &&
- !( bMissile || ((PROJECTILE *)psTempObj)->psWStats->weaponSubClass == WSC_COUNTER ) )
+ 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;
}
@@ -154,16 +111,6 @@
continue;
}
- if ( psStats->surfaceToAir == SHOOT_IN_AIR &&
- ( psTempObj->type == OBJ_STRUCTURE ||
- psTempObj->type == OBJ_FEATURE ||
- ( psTempObj->type == OBJ_DROID && !vtolDroid((DROID *)psTempObj) )
- ) )
- {
- // AA weapons should not hit buildings and non-vtol droids
- continue;
- }
-
{
// FIXME HACK Needed since we got those ugly Vector3uw floating around in BASE_OBJECT...
Vector3i
@@ -250,14 +197,10 @@
addEffect(&pos,EFFECT_SMOKE,SMOKE_TYPE_TRAIL,false,NULL,0);
} break;
default:
- /* add smoke trail to indirect weapons firing directly */
- if ( !proj_Direct(psStats) )
- {
- Vector3i pos = { psProj->pos.x, psProj->pos.z+4, psProj->pos.y };
- addEffect(&pos,EFFECT_SMOKE,SMOKE_TYPE_TRAIL,false,NULL,0);
- }
- /* Otherwise no effect */
- break;
+ {
+ Vector3i pos = { psProj->pos.x, psProj->pos.z+4, psProj->pos.y };
+ addEffect(&pos,EFFECT_SMOKE,SMOKE_TYPE_TRAIL,false,NULL,0);
+ } break;
}
}
}
signature.asc
Description: This is a digitally signed message part.
_______________________________________________ Warzone-dev mailing list [email protected] https://mail.gna.org/listinfo/warzone-dev
