Patch by Watermelon: Projectile fixes 5h (slightly modified by me)

1.Fixed a crash when firing the 2nd/3rd indirect weapon in combFire in 
combat.c.
2.Fixed target prediction finally(confused by x,y,z in pie and x,y,z in game 
and swapped the sin and cos and never thought droid->sMove.dir is in 
degree's ...) AA weapons can hit VTOL's relatively easy now due to this 
change.
3.Added smoke to AA gun bullet explosion effect even if it hits the target.
4.Fixed a bug which prevents AA weapon area of effect damage from working 
properly(VTOL's was excluded in area effect damage check in original 
project_Impact function),the 25% chance of AOE damage of AA weapons defined 
in weapons.txt should work now.
5.Changed units hitbox radius to use unit pie imd:
avg(imd.xmax + imd.zmax) for 2D radius
(imd.zmax + component.imd.zmax) for height(z) radius
6.Fixed crashes when firing at baba people,baba vehicle in singleplayer 
campaign(thanks to hikaru-orly for the crash reports)


git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@873 4a71c877-e1ca-e34f-864e-861f7616d084
master
Dennis Schridde 2006-12-01 21:50:58 +00:00
parent b8046b4aa6
commit 7b7348e580
2 changed files with 366 additions and 249 deletions

View File

@ -179,13 +179,13 @@ void combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
if ( (psAttacker->type == OBJ_DROID) &&
!vtolDroid((DROID *)psAttacker) &&
(proj_Direct(psStats) ||
(actionInsideMinRange(psDroid, psDroid->psActionTarget[weapon_slot]) > 1))
(actionInsideMinRange(psDroid, psDroid->psActionTarget[0]) & (1 << (1 + weapon_slot))))
)
{
if(!visibleObjWallBlock(psAttacker, psTarget))
{
// Can't see the target - can't hit it with direct fire
DBP3(("directLOS failed\n"));
debug(LOG_NEVER, "directLOS failed\n");
return;
}
}
@ -197,7 +197,7 @@ void combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
if (!visibleObjWallBlock(psAttacker, psTarget))
{
// Can't see the target - can't hit it with direct fire
DBP3(("directLOS failed\n"));
debug(LOG_NEVER, "directLOS failed\n");
return;
}
}
@ -206,7 +206,7 @@ void combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
if (!visibleObject(psAttacker, psTarget))
{
// Can't see the target - can't hit it with direct fire
DBP3(("directLOS failed\n"));
debug(LOG_NEVER, "directLOS failed\n");
return;
}
}
@ -215,7 +215,7 @@ void combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
if (!psTarget->visible[psAttacker->player])
{
// Can't get an indirect LOS - can't hit it with the weapon
DBP3(("indirectLOS failed\n"));
debug(LOG_NEVER, "indirectLOS failed\n");
return;
}
}
@ -337,7 +337,7 @@ void combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
hitMod = 50*hitMod/100;
}
DBP3(("%s Hit mod %d : ", psStats->pName, hitMod));
debug(LOG_NEVER, "%s Hit mod %d : ", psStats->pName, hitMod);
/* Now see if the target is in range - also check not too near*/
xDiff = abs(psAttacker->x - psTarget->x);
@ -369,32 +369,22 @@ void combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
//Watermelon:Target prediction
if(psTarget->type == OBJ_DROID)
{
if (vtolDroid((DROID *)psTarget))
{
predictX = (cos((FRACT)((DROID *)psTarget)->direction) * moveCalcDroidSpeed((DROID *)psTarget) * dist) /psStats->flightSpeed;
predictX += psTarget->x;
predictY = (sin((FRACT)((DROID *)psTarget)->direction) * moveCalcDroidSpeed((DROID *)psTarget) * dist) /psStats->flightSpeed;
predictY += psTarget->y;
}
else
{
predictX = (cos((FRACT)((DROID *)psTarget)->sMove.dir) * ((DROID *)psTarget)->sMove.speed * dist) /psStats->flightSpeed;
predictX += psTarget->x;
predictY = (sin((FRACT)((DROID *)psTarget)->sMove.dir) * ((DROID *)psTarget)->sMove.speed * dist) /psStats->flightSpeed;
predictY += psTarget->y;
}
predictX = (sinf(((float)pi/180)*(((DROID *)psTarget)->sMove.dir)) * ((DROID *)psTarget)->sMove.speed * dist) /psStats->flightSpeed;
predictX += psTarget->x;
predictY = (cosf(((float)pi/180)*(((DROID *)psTarget)->sMove.dir)) * ((DROID *)psTarget)->sMove.speed * dist) /psStats->flightSpeed;
predictY += psTarget->y;
}
else
{
predictX = psTarget->x;
predictY = psTarget->y;
}
DBP3(("Shot hit (%d)\n", dice));
debug(LOG_NEVER, "Shot hit (%d)\n", dice);
if (!proj_SendProjectile(psWeap, psAttacker, psAttacker->player,
predictX, predictY, psTarget->z, psTarget, FALSE, FALSE, weapon_slot))
{
/* Out of memory - we can safely ignore this */
DBP3(("Out of memory"));
debug(LOG_NEVER, "Out of memory");
return;
}
}
@ -430,32 +420,22 @@ void combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
//Watermelon:Target prediction
if(psTarget->type == OBJ_DROID)
{
if (vtolDroid((DROID *)psTarget))
{
predictX = (cos((FRACT)((DROID *)psTarget)->direction) * moveCalcDroidSpeed((DROID *)psTarget) * dist) /psStats->flightSpeed;
predictX += psTarget->x;
predictY = (sin((FRACT)((DROID *)psTarget)->direction) * moveCalcDroidSpeed((DROID *)psTarget) * dist) /psStats->flightSpeed;
predictY += psTarget->y;
}
else
{
predictX = (cos((FRACT)((DROID *)psTarget)->sMove.dir) * ((DROID *)psTarget)->sMove.speed * dist) /psStats->flightSpeed;
predictX += psTarget->x;
predictY = (sin((FRACT)((DROID *)psTarget)->sMove.dir) * ((DROID *)psTarget)->sMove.speed * dist) /psStats->flightSpeed;
predictY += psTarget->y;
}
predictX = (sinf(((float)pi/180)*(((DROID *)psTarget)->sMove.dir)) * ((DROID *)psTarget)->sMove.speed * dist) /psStats->flightSpeed;
predictX += psTarget->x;
predictY = (cosf(((float)pi/180)*(((DROID *)psTarget)->sMove.dir)) * ((DROID *)psTarget)->sMove.speed * dist) /psStats->flightSpeed;
predictY += psTarget->y;
}
else
{
predictX = psTarget->x;
predictY = psTarget->y;
}
DBP3(("Shot hit (%d)\n", dice));
debug(LOG_NEVER, "Shot hit (%d)\n", dice);
if (!proj_SendProjectile(psWeap, psAttacker, psAttacker->player,
predictX, predictY, psTarget->z, psTarget, FALSE, FALSE, weapon_slot))
{
/* Out of memory - we can safely ignore this */
DBP3(("Out of memory"));
debug(LOG_NEVER, "Out of memory");
return;
}
}
@ -467,7 +447,7 @@ void combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
else
{
/* Out of range */
DBP3(("Out of range\n"));
debug(LOG_NEVER, "Out of range\n");
return;
}
@ -475,7 +455,7 @@ void combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
missed:
/* Deal with a missed shot */
DBP3(("Missed shot (%d)\n", dice));
debug(LOG_NEVER, "Missed shot (%d)\n", dice);
/*
// Approximate the distance between the attacker and target
@ -499,8 +479,8 @@ missed:
missX = aScatterDir[missDir].x * missDist + psTarget->x + minOffset;
missY = aScatterDir[missDir].y * missDist + psTarget->y + minOffset;
DBP3(("Miss Loc: w(%4d,%4d), t(%3d,%3d)\n",
missX, missY, missX>>TILE_SHIFT, missY>>TILE_SHIFT));
debug(LOG_NEVER, "Miss Loc: w(%4d,%4d), t(%3d,%3d)\n",
missX, missY, missX>>TILE_SHIFT, missY>>TILE_SHIFT);
// decide if a miss is visible
bMissVisible = FALSE;
@ -513,7 +493,7 @@ missed:
if (!proj_SendProjectile( psWeap, psAttacker, psAttacker->player, missX,missY, psTarget->z, NULL, bMissVisible, FALSE, weapon_slot) )
{
/* Out of memory */
DBP3(("Out of memory"));
debug(LOG_NEVER, "Out of memory");
return;
}

View File

@ -335,13 +335,13 @@ proj_SendProjectile( WEAPON *psWeap, BASE_OBJECT *psAttacker, SDWORD player,
muzzle.y = (SDWORD)tarY;
muzzle.z = (SDWORD)tarZ;
}
else if (psAttacker->type == OBJ_DROID)
else if (psAttacker->type == OBJ_DROID && weapon_slot >= 0)
{
calcDroidMuzzleLocation( (DROID *) psAttacker, &muzzle, weapon_slot);
/*update attack runs for VTOL droid's each time a shot is fired*/
updateVtolAttackRun((DROID *)psAttacker);
/*update attack runs for VTOL droid's each time a shot is fired*/
updateVtolAttackRun((DROID *)psAttacker);
}
else if (psAttacker->type == OBJ_STRUCTURE)
else if (psAttacker->type == OBJ_STRUCTURE && weapon_slot >= 0)
{
calcStructureMuzzleLocation( (STRUCTURE *) psAttacker, &muzzle, weapon_slot);
}
@ -350,8 +350,6 @@ proj_SendProjectile( WEAPON *psWeap, BASE_OBJECT *psAttacker, SDWORD player,
muzzle.x = psAttacker->x;
muzzle.y = psAttacker->y;
muzzle.z = psAttacker->z;
/* GJ - horrible hack to get droid tower projectiles at correct height */
//muzzle.z = psAttacker->z + psAttacker->sDisplay.imd->ymax;
}
/* Initialise the structure */
@ -393,11 +391,11 @@ proj_SendProjectile( WEAPON *psWeap, BASE_OBJECT *psAttacker, SDWORD player,
case OBJ_FEATURE:
if( ((DROID*)psTarget)->droidType == DROID_PERSON )
{
heightVariance = rand()%8;
heightVariance = rand()%4;
}
else
{
heightVariance = rand()%24;
heightVariance = rand()%8;
}
break;
case OBJ_STRUCTURE:
@ -410,7 +408,6 @@ proj_SendProjectile( WEAPON *psWeap, BASE_OBJECT *psAttacker, SDWORD player,
}
else
{
// tarHeight = map_Height(tarX,tarY);
tarHeight = (SDWORD)tarZ;
scoreUpdateVar(WD_SHOTS_OFF_TARGET);
}
@ -539,16 +536,16 @@ proj_SendProjectile( WEAPON *psWeap, BASE_OBJECT *psAttacker, SDWORD player,
}
/* if droid set muzzle pitch */
//Watermelon:use 0 for now
if (psAttacker != NULL)
//Watermelon:fix turret pitch for more turrets
if (psAttacker != NULL && weapon_slot >= 0)
{
if (psAttacker->type == OBJ_DROID)
{
((DROID *) psAttacker)->turretPitch[0] = psObj->pitch;
((DROID *) psAttacker)->turretPitch[weapon_slot] = psObj->pitch;
}
else if (psAttacker->type == OBJ_STRUCTURE)
{
((STRUCTURE *) psAttacker)->turretPitch[0] = psObj->pitch;
((STRUCTURE *) psAttacker)->turretPitch[weapon_slot] = psObj->pitch;
}
}
@ -639,7 +636,7 @@ proj_InFlightDirectFunc( PROJ_OBJECT *psObj )
//Watermelon:Penetrate or not
BOOL bPenetrate;
WEAPON asWeap;
int HeightBonus;
DROID *psTempDroid;
bMissile = FALSE;
bPenetrate = FALSE;
@ -792,7 +789,7 @@ proj_InFlightDirectFunc( PROJ_OBJECT *psObj )
addEffect(&pos,EFFECT_SMOKE,SMOKE_TYPE_TRAIL,FALSE,NULL,0);
}
bMissile = TRUE;
wpRadius = 4;
wpRadius = 2;
}
//Watermelon:weapon radius,or the 'real' projectile will never hit a moving target with the changes...
@ -811,24 +808,21 @@ proj_InFlightDirectFunc( PROJ_OBJECT *psObj )
psStats->weaponSubClass == WSC_ENERGY ||
psStats->weaponSubClass == WSC_GAUSS)
{
wpRadius = 3;
wpRadius = 2;
//Watermelon:extended life span
extendRad = (SDWORD)(rad * 1.5f);
}
else if (psStats->weaponSubClass == WSC_AAGUN)
{
wpRadius = 16;
//Watermelon:extended life span
extendRad = (SDWORD)rad * 2;
extendRad = rad;
}
//Watermelon:these 3 types of weapon should have the ability to pentrate targets and damage the enemies behind
if (psStats->penetrate)
{
bPenetrate = TRUE;
}
//Watermelon:test test
for (i = 0;i < numProjNaybors;i++)
{
//if (asProjNaybors[i].psObj == psObj->psDest)
@ -841,7 +835,6 @@ proj_InFlightDirectFunc( PROJ_OBJECT *psObj )
asProjNaybors[i].psObj->type == OBJ_STRUCTURE ||
asProjNaybors[i].psObj->type == OBJ_BULLET ||
asProjNaybors[i].psObj->type == OBJ_FEATURE) &&
asProjNaybors[i].psObj->visible[psObj->player] &&
!aiCheckAlliances(asProjNaybors[i].psObj->player,psObj->player))
{
psTempObj = asProjNaybors[i].psObj;
@ -861,7 +854,6 @@ proj_InFlightDirectFunc( PROJ_OBJECT *psObj )
if ( psTempObj->type == OBJ_STRUCTURE || psTempObj->type == OBJ_FEATURE)
{
HeightBonus = 0;
//Watermelon:ignore oil resource and pickup
if ( psTempObj->type == OBJ_FEATURE )
{
@ -881,29 +873,12 @@ proj_InFlightDirectFunc( PROJ_OBJECT *psObj )
ydiff = (SDWORD)psObj->y - (SDWORD)psTempObj->y;
zdiff = abs((SDWORD)psObj->z - (SDWORD)psTempObj->z);
if (psTempObj->type == OBJ_STRUCTURE)
{
//Watermelon:tower and hardpoint are much easier to hit now
if (((STRUCTURE *)psTempObj)->pStructureType->strength == STRENGTH_SOFT ||
((STRUCTURE *)psTempObj)->pStructureType->strength == STRENGTH_HARD)
{
HeightBonus = 100;
}
else if (((STRUCTURE *)psTempObj)->pStructureType->strength == STRENGTH_MEDIUM)
{
HeightBonus = 50;
}
}
if ( (xdiff*xdiff + ydiff*ydiff) < ((SDWORD)(establishTargetRadius(psTempObj)) * (SDWORD)(establishTargetRadius(psTempObj))) &&
zdiff < (50 + HeightBonus) )
zdiff < psTempObj->sDisplay.imd->ymax )
{
if ( psObj->psWStats->surfaceToAir == SHOOT_IN_AIR )
if ( psObj->psWStats->surfaceToAir == SHOOT_IN_AIR && psTempObj->type == OBJ_DROID && !vtolDroid((DROID *)psTempObj))
{
if (psTempObj->type == OBJ_DROID && !vtolDroid((DROID *)psTempObj))
{
continue;
}
continue;
}
if (bPenetrate && psTempObj->type != OBJ_STRUCTURE)
@ -926,25 +901,58 @@ proj_InFlightDirectFunc( PROJ_OBJECT *psObj )
ydiff = (SDWORD)psObj->y - (SDWORD)psTempObj->y;
zdiff = abs((SDWORD)psObj->z - (SDWORD)psTempObj->z);
HeightBonus = 0;
//Watermelon:to make VTOL easier to hit
if (psTempObj->type == OBJ_DROID && vtolDroid((DROID *)psTempObj))
if (psTempObj->type == OBJ_DROID )
{
HeightBonus = 100;
psTempDroid = (DROID *)psTempObj;
//Watermelon:to make VTOL easier to hit
if (vtolDroid(psTempDroid))
{
zdiff -= 100;
}
else if ( !(cyborgDroid(psTempDroid)) && psTempDroid->droidType != DROID_PERSON )
{
// Don't do this for Barbarian Propulsions as they don't possess a turret (and thus have pIMD == NULL)
if (strcmp(asPropulsionStats[psTempDroid->asBits[COMP_PROPULSION].nStat].pName, "BaBaProp"))
{
//appends the turret height to the droid z,since there is no real geometries in wz
if ( psTempDroid->numWeaps > 0 )
{
zdiff -= (asWeaponStats[psTempDroid->asWeaps[0].nStat]).pIMD->ymax;
}
else
{
switch (psTempDroid->droidType)
{
case DROID_CONSTRUCT:
zdiff -= (asConstructStats[psTempDroid->asBits[COMP_CONSTRUCT].nStat]).pIMD->ymax;
break;
case DROID_REPAIR:
zdiff -= (asRepairStats[psTempDroid->asBits[COMP_REPAIRUNIT].nStat]).pIMD->ymax;
break;
case DROID_SENSOR:
zdiff -= (asSensorStats[psTempDroid->asBits[COMP_SENSOR].nStat]).pIMD->ymax;
break;
case DROID_COMMAND:
zdiff -= (asBrainStats[psTempDroid->asBits[COMP_BRAIN].nStat]).pIMD->ymax;
break;
case DROID_ECM:
zdiff -= (asECMStats[psTempDroid->asBits[COMP_ECM].nStat]).pIMD->ymax;
break;
}
}
}
}
}
if ( (xdiff*xdiff + ydiff*ydiff) < (wpRadius * (SDWORD)(establishTargetRadius(psTempObj)) * (SDWORD)(establishTargetRadius(psTempObj))) &&
zdiff < (50 + HeightBonus) )
zdiff < psTempObj->sDisplay.imd->ymax )
{
if ( psObj->psWStats->surfaceToAir == SHOOT_IN_AIR )
if ( psObj->psWStats->surfaceToAir == SHOOT_IN_AIR && psTempObj->type == OBJ_DROID && !vtolDroid((DROID *)psTempObj))
{
if (psTempObj->type == OBJ_DROID && !vtolDroid((DROID *)psTempObj))
{
continue;
}
continue;
}
if (bPenetrate && psTempObj->type != OBJ_STRUCTURE)
if (bPenetrate)
{
//Watermelon:just assume we damaged the chosen target
psObj->psDamaged = psTempObj;
@ -969,7 +977,7 @@ proj_InFlightDirectFunc( PROJ_OBJECT *psObj )
zdiff = abs((SDWORD)psObj->z - (SDWORD)psObj->psDest->z);
if ((xdiff*xdiff + ydiff*ydiff) < ((SDWORD)psObj->targetRadius * (SDWORD)psObj->targetRadius) &&
zdiff < 50)
zdiff < psObj->psDest->sDisplay.imd->ymax)
{
psObj->state = PROJ_IMPACT;
}
@ -987,7 +995,7 @@ proj_InFlightDirectFunc( PROJ_OBJECT *psObj )
//Watermelon:'real' hit check even if the projectile is about to 'timeout'
if ( (xdiff*xdiff + ydiff*ydiff) < (wpRadius * (SDWORD)(establishTargetRadius(psObj->psDest) ) * (SDWORD)(establishTargetRadius(psObj->psDest)) ) &&
zdiff < 25)
zdiff < 50)
{
psObj->state = PROJ_IMPACT;
}
@ -1042,8 +1050,8 @@ proj_InFlightIndirectFunc( PROJ_OBJECT *psObj )
BASE_OBJECT *psNewTarget;
int i;
SDWORD xdiff,ydiff,zdiff,extendRad;
int wpRadius = 9;
int HeightBonus;
int wpRadius = 3;
DROID *psTempDroid;
ASSERT( PTRVALID(psObj, sizeof(PROJ_OBJECT)),
"proj_InFlightIndirectFunc: invalid projectile pointer" );
@ -1162,7 +1170,6 @@ proj_InFlightIndirectFunc( PROJ_OBJECT *psObj )
asProjNaybors[i].psObj->type == OBJ_STRUCTURE ||
asProjNaybors[i].psObj->type == OBJ_BULLET ||
asProjNaybors[i].psObj->type == OBJ_FEATURE) &&
asProjNaybors[i].psObj->visible[psObj->player] &&
!aiCheckAlliances(asProjNaybors[i].psObj->player,psObj->player))
{
psTempObj = asProjNaybors[i].psObj;
@ -1174,7 +1181,6 @@ proj_InFlightIndirectFunc( PROJ_OBJECT *psObj )
if ( psTempObj->type == OBJ_STRUCTURE || psTempObj->type == OBJ_FEATURE )
{
HeightBonus = 0;
//Watermelon:ignore oil resource and pickup
if ( psTempObj->type == OBJ_FEATURE )
{
@ -1188,22 +1194,8 @@ proj_InFlightIndirectFunc( PROJ_OBJECT *psObj )
ydiff = (SDWORD)psObj->y - (SDWORD)psTempObj->y;
zdiff = (SDWORD)psObj->z - (SDWORD)psTempObj->z;
if (psTempObj->type == OBJ_STRUCTURE)
{
//Watermelon:tower and hardpoint are much easier to hit now
if (((STRUCTURE *)psTempObj)->pStructureType->strength == STRENGTH_SOFT ||
((STRUCTURE *)psTempObj)->pStructureType->strength == STRENGTH_HARD)
{
HeightBonus = 100;
}
else if (((STRUCTURE *)psTempObj)->pStructureType->strength == STRENGTH_MEDIUM)
{
HeightBonus = 50;
}
}
if ( (xdiff*xdiff + ydiff*ydiff) < ((SDWORD)(establishTargetRadius(psTempObj)) * (SDWORD)(establishTargetRadius(psTempObj))) &&
zdiff < (50 + HeightBonus) )
zdiff < psTempObj->sDisplay.imd->ymax )
{
psNewTarget = psTempObj;
psObj->psDest = psNewTarget;
@ -1217,8 +1209,51 @@ proj_InFlightIndirectFunc( PROJ_OBJECT *psObj )
ydiff = (SDWORD)psObj->y - (SDWORD)psTempObj->y;
zdiff = (SDWORD)psObj->z - (SDWORD)psTempObj->z;
if (psTempObj->type == OBJ_DROID )
{
psTempDroid = (DROID *)psTempObj;
//Watermelon:to make VTOL easier to hit
if (vtolDroid(psTempDroid))
{
zdiff -= 100;
}
else if ( !(cyborgDroid(psTempDroid)) && psTempDroid->droidType != DROID_PERSON )
{
// Don't do this for Barbarian Propulsions as they don't possess a turret (and thus have pIMD == NULL)
if (strcmp(asPropulsionStats[psTempDroid->asBits[COMP_PROPULSION].nStat].pName, "BaBaProp"))
{
//appends the turret height to the droid z,since there is no real geometries in wz
if ( psTempDroid->numWeaps > 0 )
{
zdiff -= (asWeaponStats[psTempDroid->asWeaps[0].nStat]).pIMD->ymax;
}
else
{
switch (psTempDroid->droidType)
{
case DROID_CONSTRUCT:
zdiff -= (asConstructStats[psTempDroid->asBits[COMP_CONSTRUCT].nStat]).pIMD->ymax;
break;
case DROID_REPAIR:
zdiff -= (asRepairStats[psTempDroid->asBits[COMP_REPAIRUNIT].nStat]).pIMD->ymax;
break;
case DROID_SENSOR:
zdiff -= (asSensorStats[psTempDroid->asBits[COMP_SENSOR].nStat]).pIMD->ymax;
break;
case DROID_COMMAND:
zdiff -= (asBrainStats[psTempDroid->asBits[COMP_BRAIN].nStat]).pIMD->ymax;
break;
case DROID_ECM:
zdiff -= (asECMStats[psTempDroid->asBits[COMP_ECM].nStat]).pIMD->ymax;
break;
}
}
}
}
}
if ((xdiff*xdiff + ydiff*ydiff) < ((wpRadius * (SDWORD)(establishTargetRadius(psTempObj)) * (SDWORD)(establishTargetRadius(psTempObj)))) &&
zdiff < 25 )
zdiff < psTempObj->sDisplay.imd->ymax )
{
psNewTarget = psTempObj;
psObj->psDest = psNewTarget;
@ -1230,7 +1265,7 @@ proj_InFlightIndirectFunc( PROJ_OBJECT *psObj )
}
/* See if effect has finished */
if ( iDist > (extendRad-(SDWORD)psObj->targetRadius) )
if ( iDist > (extendRad - (SDWORD)psObj->targetRadius) )
{
pos.x = psObj->x;
pos.z = psObj->y;
@ -1248,25 +1283,14 @@ proj_InFlightIndirectFunc( PROJ_OBJECT *psObj )
ydiff = (SDWORD)psObj->y - (SDWORD)psObj->psDest->y;
zdiff = abs((SDWORD)psObj->z - (SDWORD)psObj->psDest->z);
HeightBonus = 0;
//Watermelon:dont apply the 'hitbox' bonus if the target is a building
if ( psObj->psDest->type == OBJ_STRUCTURE )
{
//Watermelon:tower and hardpoint are much easier to hit now
if (((STRUCTURE *)psObj->psDest)->pStructureType->strength == STRENGTH_SOFT ||
((STRUCTURE *)psObj->psDest)->pStructureType->strength == STRENGTH_HARD)
{
HeightBonus = 100;
}
else if (((STRUCTURE *)psObj->psDest)->pStructureType->strength == STRENGTH_MEDIUM)
{
HeightBonus = 50;
}
wpRadius = 1;
}
if ((xdiff*xdiff + ydiff*ydiff) < (wpRadius * (SDWORD)(establishTargetRadius(psObj->psDest)) * (SDWORD)(establishTargetRadius(psObj->psDest))) &&
zdiff < (50 + HeightBonus) )
zdiff < psObj->psDest->sDisplay.imd->ymax )
{
psObj->state = PROJ_IMPACT;
}
@ -1333,6 +1357,8 @@ proj_ImpactFunc( PROJ_OBJECT *psObj )
BOOL bKilled;//,bMultiTemp;
iVector position,scatter;
UDWORD damage; //optimisation - were all being calculated twice on PC
//Watermelon: tarZ0,tarZ1,zDiff for AA AOE weapons;
SDWORD tarZ0,tarZ1,zDiff;
ASSERT( PTRVALID(psObj, sizeof(PROJ_OBJECT)),
@ -1487,24 +1513,61 @@ proj_ImpactFunc( PROJ_OBJECT *psObj )
}
else
{
if (psObj->psDest->type == OBJ_FEATURE &&
((FEATURE *)psObj->psDest)->psStats->damageable == 0)
{
debug( LOG_NEVER, "proj_ImpactFunc: trying to damage non-damageable target,projectile removed\n");
if ( hashTable_RemoveElement( g_pProjObjTable, psObj,
(int) psObj, UNUSED_KEY ) == FALSE )
{
debug( LOG_NEVER, "proj_ImpactFunc: couldn't remove projectile from table\n" );
}
return;
}
position.x = psObj->x;
position.z = psObj->y;
position.y = psObj->z;//map_Height(psObj->x, psObj->y) + 24;
scatter.x = psStats->radius; scatter.y = 0; scatter.z = psStats->radius;
if(psStats->facePlayer)
/* Watermelon:gives AA gun explosive field and smoke effect even if it hits the target */
if (psObj->airTarget)
{
// addEffect(&position,EFFECT_EXPLOSION,EXPLOSION_TYPE_SPECIFIED,TRUE,psStats->pTargetHitGraphic);
if ((psStats->surfaceToAir & SHOOT_IN_AIR) &&
!(psStats->surfaceToAir & SHOOT_ON_GROUND) &&
psStats->weaponSubClass == WSC_AAGUN)
{
if(psStats->facePlayer)
{
if(gfxVisible(psObj))
// if(GFX_VISIBLE(psObj))
addMultiEffect(&position,&scatter,EFFECT_EXPLOSION,EXPLOSION_TYPE_SPECIFIED,TRUE,psStats->pTargetHitGraphic,psStats->numExplosions,psStats->lightWorld,psStats->effectSize);
addMultiEffect(&position,&scatter,EFFECT_EXPLOSION,EXPLOSION_TYPE_SPECIFIED,TRUE,psStats->pTargetMissGraphic,psStats->numExplosions,psStats->lightWorld,psStats->effectSize);
}
else
{
if(gfxVisible(psObj))
addMultiEffect(&position,&scatter,EFFECT_EXPLOSION,EXPLOSION_TYPE_NOT_FACING,TRUE,psStats->pTargetMissGraphic,psStats->numExplosions,psStats->lightWorld,psStats->effectSize);
}
/* Add some smoke to flak */
addMultiEffect(&position,&scatter,EFFECT_SMOKE,SMOKE_TYPE_DRIFTING,FALSE,NULL,3,0,0);
}
}
else
{
// addEffect(&position,EFFECT_EXPLOSION,EXPLOSION_TYPE_NOT_FACING,TRUE,psStats->pTargetHitGraphic);
if(gfxVisible(psObj))
// if(GFX_VISIBLE(psObj))
addMultiEffect(&position,&scatter,EFFECT_EXPLOSION,EXPLOSION_TYPE_NOT_FACING,TRUE,psStats->pTargetHitGraphic,psStats->numExplosions,psStats->lightWorld,psStats->effectSize);
if(psStats->facePlayer)
{
// addEffect(&position,EFFECT_EXPLOSION,EXPLOSION_TYPE_SPECIFIED,TRUE,psStats->pTargetHitGraphic);
if(gfxVisible(psObj))
// if(GFX_VISIBLE(psObj))
addMultiEffect(&position,&scatter,EFFECT_EXPLOSION,EXPLOSION_TYPE_SPECIFIED,TRUE,psStats->pTargetHitGraphic,psStats->numExplosions,psStats->lightWorld,psStats->effectSize);
}
else
{
// addEffect(&position,EFFECT_EXPLOSION,EXPLOSION_TYPE_NOT_FACING,TRUE,psStats->pTargetHitGraphic);
if(gfxVisible(psObj))
// if(GFX_VISIBLE(psObj))
addMultiEffect(&position,&scatter,EFFECT_EXPLOSION,EXPLOSION_TYPE_NOT_FACING,TRUE,psStats->pTargetHitGraphic,psStats->numExplosions,psStats->lightWorld,psStats->effectSize);
}
}
/* Do damage to the target */
if (proj_Direct(psStats))
{
@ -1558,8 +1621,8 @@ proj_ImpactFunc( PROJ_OBJECT *psObj )
// bMultiTemp = FALSE;
// }
DBP1(("Damage to object %d, player %d\n",
psObj->psDest->id, psObj->psDest->player));
debug(LOG_NEVER, "Damage to object %d, player %d\n",
psObj->psDest->id, psObj->psDest->player);
/*the damage depends on the weapon effect and the target propulsion type or structure strength*/
bKilled = objectDamage(psObj->psDest,damage , psStats->weaponClass,psStats->weaponSubClass);
@ -1625,8 +1688,8 @@ proj_ImpactFunc( PROJ_OBJECT *psObj )
//my_error("",0,"","Damage to object %d, player %d\n",psObj->psDest->id, psObj->psDest->player);
DBP1(("Damage to object %d, player %d\n",
psObj->psDest->id, psObj->psDest->player));
debug(LOG_NEVER, "Damage to object %d, player %d\n",
psObj->psDest->id, psObj->psDest->player);
//bKilled = psObj->psDest->damage(psObj->psDest, psStats->damage,psStats->weaponClass);
/*bKilled = psObj->psDest->damage(psObj->psDest, calcDamage(
//psStats->damage, psStats->weaponEffect, psObj->psDest),
@ -1726,141 +1789,222 @@ proj_ImpactFunc( PROJ_OBJECT *psObj )
tarY0 = (SDWORD)psObj->y - (SDWORD)psStats->radius;
tarX1 = (SDWORD)psObj->x + (SDWORD)psStats->radius;
tarY1 = (SDWORD)psObj->y + (SDWORD)psStats->radius;
/* Watermelon:height bounding box for airborne units*/
tarZ0 = (SDWORD)psObj->z - (SDWORD)psStats->radius;
tarZ1 = (SDWORD)psObj->z + (SDWORD)psStats->radius;
/* Store the radius squared */
radSquared = psStats->radius * psStats->radius;
radSquared = psStats->radius * psStats->radius * psStats->radius;
/* Do damage to everything in range */
for (i=0; i<MAX_PLAYERS; i++)
/* Watermelon:air suppression */
if (psObj->airTarget)
{
for (psCurrD = apsDroidLists[i]; psCurrD; psCurrD = psNextD)
for (i=0; i<MAX_PLAYERS; i++)
{
/* have to store the next pointer as psCurrD could be destroyed */
psNextD = psCurrD->psNext;
if (vtolDroid(psCurrD) &&
(psCurrD->sMove.Status != MOVEINACTIVE))
for (psCurrD = apsDroidLists[i]; psCurrD; psCurrD = psNextD)
{
// skip VTOLs in the air
continue;
}
/* have to store the next pointer as psCurrD could be destroyed */
psNextD = psCurrD->psNext;
/* see if psCurrD is hit (don't hit main target twice) */
if (((BASE_OBJECT *)psCurrD != psObj->psDest) &&
((SDWORD)psCurrD->x >= tarX0) &&
((SDWORD)psCurrD->x <= tarX1) &&
((SDWORD)psCurrD->y >= tarY0) &&
((SDWORD)psCurrD->y <= tarY1))
{
/* Within the bounding box, now check the radius */
xDiff = psCurrD->x - psObj->x;
yDiff = psCurrD->y - psObj->y;
if ((xDiff*xDiff + yDiff*yDiff) <= radSquared)
/* Watermelon:skip no vtol droids and landed votl's */
if (!vtolDroid(psCurrD) ||
(vtolDroid(psCurrD) && psCurrD->sMove.Status == MOVEINACTIVE))
{
HIT_ROLL(dice);
//if (dice < psStats->radiusHit)
if (dice < weaponRadiusHit(psStats, psObj->player))
continue;
}
/* see if psCurrD is hit (don't hit main target twice) */
if (((BASE_OBJECT *)psCurrD != psObj->psDest) &&
((SDWORD)psCurrD->x >= tarX0) &&
((SDWORD)psCurrD->x <= tarX1) &&
((SDWORD)psCurrD->y >= tarY0) &&
((SDWORD)psCurrD->y <= tarY1) &&
((SDWORD)psCurrD->z >= tarZ0) &&
((SDWORD)psCurrD->z <= tarZ1))
{
/* Within the bounding box, now check the radius */
xDiff = psCurrD->x - psObj->x;
yDiff = psCurrD->y - psObj->y;
zDiff = psCurrD->z - psObj->z;
if ((xDiff*xDiff + yDiff*yDiff + zDiff*zDiff) <= radSquared)
{
DBP1(("Damage to object %d, player %d\n",
psCurrD->id, psCurrD->player));
damage = calcDamage(
weaponRadDamage(psStats, psObj->player),
psStats->weaponEffect, (BASE_OBJECT *)psCurrD);
if(bMultiPlayer)
HIT_ROLL(dice);
//if (dice < psStats->radiusHit)
if (dice < weaponRadiusHit(psStats, psObj->player))
{
if(psObj->psSource && myResponsibility(psObj->psSource->player))
debug(LOG_NEVER, "Damage to object %d, player %d\n",
psCurrD->id, psCurrD->player);
damage = calcDamage(
weaponRadDamage(psStats, psObj->player),
psStats->weaponEffect, (BASE_OBJECT *)psCurrD);
if(bMultiPlayer)
{
updateMultiStatsDamage(psObj->psSource->player,
psCurrD->player, damage);
if(psObj->psSource && myResponsibility(psObj->psSource->player))
{
updateMultiStatsDamage(psObj->psSource->player,
psCurrD->player, damage);
}
turnOffMultiMsg(TRUE);
}
turnOffMultiMsg(TRUE);
}
//bKilled = psCurrD->damage(psCurrD, psStats->radiusDamage, psStats->weaponClass);
/*bKilled = psCurrD->damage(psCurrD, calcDamage(
//psStats->radiusDamage, psStats->weaponEffect,
weaponRadDamage(psStats,psObj->player),
psStats->weaponEffect,
(BASE_OBJECT *)psCurrD), psStats->weaponClass);*/
//bKilled = psCurrD->damage(psCurrD, psStats->radiusDamage, psStats->weaponClass);
/*bKilled = psCurrD->damage(psCurrD, calcDamage(
//psStats->radiusDamage, psStats->weaponEffect,
weaponRadDamage(psStats,psObj->player),
psStats->weaponEffect,
(BASE_OBJECT *)psCurrD), psStats->weaponClass);*/
bKilled = droidDamage(psCurrD, damage, psStats->weaponClass,psStats->weaponSubClass);
bKilled = droidDamage(psCurrD, damage, psStats->weaponClass,psStats->weaponSubClass);
turnOffMultiMsg(FALSE); // multiplay msgs back on.
turnOffMultiMsg(FALSE); // multiplay msgs back on.
if(bKilled)
{
proj_UpdateKills(psObj);
if(bKilled)
{
proj_UpdateKills(psObj);
}
}
}
}
}
}
for (psCurrS = apsStructLists[i]; psCurrS; psCurrS = psNextS)
}
else
{
/* Do damage to everything in range */
for (i=0; i<MAX_PLAYERS; i++)
{
/* have to store the next pointer as psCurrD could be destroyed */
psNextS = psCurrS->psNext;
/* see if psCurrS is hit (don't hit main target twice) */
if (((BASE_OBJECT *)psCurrS != psObj->psDest) &&
((SDWORD)psCurrS->x >= tarX0) &&
((SDWORD)psCurrS->x <= tarX1) &&
((SDWORD)psCurrS->y >= tarY0) &&
((SDWORD)psCurrS->y <= tarY1))
for (psCurrD = apsDroidLists[i]; psCurrD; psCurrD = psNextD)
{
/* Within the bounding box, now check the radius */
xDiff = psCurrS->x - psObj->x;
yDiff = psCurrS->y - psObj->y;
if ((xDiff*xDiff + yDiff*yDiff) <= radSquared)
/* have to store the next pointer as psCurrD could be destroyed */
psNextD = psCurrD->psNext;
if (vtolDroid(psCurrD) &&
(psCurrD->sMove.Status != MOVEINACTIVE))
{
HIT_ROLL(dice);
//if (dice < psStats->radiusHit)
if (dice < weaponRadiusHit(psStats, psObj->player))
// skip VTOLs in the air
continue;
}
/* see if psCurrD is hit (don't hit main target twice) */
if (((BASE_OBJECT *)psCurrD != psObj->psDest) &&
((SDWORD)psCurrD->x >= tarX0) &&
((SDWORD)psCurrD->x <= tarX1) &&
((SDWORD)psCurrD->y >= tarY0) &&
((SDWORD)psCurrD->y <= tarY1))
{
/* Within the bounding box, now check the radius */
xDiff = psCurrD->x - psObj->x;
yDiff = psCurrD->y - psObj->y;
if ((xDiff*xDiff + yDiff*yDiff) <= radSquared)
{
damage = calcDamage(weaponRadDamage(
psStats, psObj->player),
psStats->weaponEffect, (BASE_OBJECT *)psCurrS);
if(bMultiPlayer)
HIT_ROLL(dice);
//if (dice < psStats->radiusHit)
if (dice < weaponRadiusHit(psStats, psObj->player))
{
if(psObj->psSource && myResponsibility(psObj->psSource->player))
debug(LOG_NEVER, "Damage to object %d, player %d\n",
psCurrD->id, psCurrD->player);
damage = calcDamage(
weaponRadDamage(psStats, psObj->player),
psStats->weaponEffect, (BASE_OBJECT *)psCurrD);
if(bMultiPlayer)
{
updateMultiStatsDamage(psObj->psSource->player, psCurrS->player,damage);
if(psObj->psSource && myResponsibility(psObj->psSource->player))
{
updateMultiStatsDamage(psObj->psSource->player,
psCurrD->player, damage);
}
turnOffMultiMsg(TRUE);
}
}
bKilled = structureDamage(psCurrS, damage,
psStats->weaponClass, psStats->weaponSubClass);
if(bKilled)
{
proj_UpdateKills(psObj);
//bKilled = psCurrD->damage(psCurrD, psStats->radiusDamage, psStats->weaponClass);
/*bKilled = psCurrD->damage(psCurrD, calcDamage(
//psStats->radiusDamage, psStats->weaponEffect,
weaponRadDamage(psStats,psObj->player),
psStats->weaponEffect,
(BASE_OBJECT *)psCurrD), psStats->weaponClass);*/
bKilled = droidDamage(psCurrD, damage, psStats->weaponClass,psStats->weaponSubClass);
turnOffMultiMsg(FALSE); // multiplay msgs back on.
if(bKilled)
{
proj_UpdateKills(psObj);
}
}
}
}
}
// Missed by old method, but maybe in landed within the building's footprint(baseplate)
else if(ptInStructure(psCurrS,psObj->x,psObj->y) AND (BASE_OBJECT*)psCurrS!=psObj->psDest)
for (psCurrS = apsStructLists[i]; psCurrS; psCurrS = psNextS)
{
damage = NOMINAL_DAMAGE;
/* have to store the next pointer as psCurrD could be destroyed */
psNextS = psCurrS->psNext;
if(bMultiPlayer)
/* see if psCurrS is hit (don't hit main target twice) */
if (((BASE_OBJECT *)psCurrS != psObj->psDest) &&
((SDWORD)psCurrS->x >= tarX0) &&
((SDWORD)psCurrS->x <= tarX1) &&
((SDWORD)psCurrS->y >= tarY0) &&
((SDWORD)psCurrS->y <= tarY1))
{
if(psObj->psSource && myResponsibility(psObj->psSource->player))
/* Within the bounding box, now check the radius */
xDiff = psCurrS->x - psObj->x;
yDiff = psCurrS->y - psObj->y;
if ((xDiff*xDiff + yDiff*yDiff) <= radSquared)
{
updateMultiStatsDamage(psObj->psSource->player, psCurrS->player,damage);
HIT_ROLL(dice);
//if (dice < psStats->radiusHit)
if (dice < weaponRadiusHit(psStats, psObj->player))
{
damage = calcDamage(weaponRadDamage(
psStats, psObj->player),
psStats->weaponEffect, (BASE_OBJECT *)psCurrS);
if(bMultiPlayer)
{
if(psObj->psSource && myResponsibility(psObj->psSource->player))
{
updateMultiStatsDamage(psObj->psSource->player, psCurrS->player,damage);
}
}
bKilled = structureDamage(psCurrS, damage,
psStats->weaponClass, psStats->weaponSubClass);
if(bKilled)
{
proj_UpdateKills(psObj);
}
}
}
}
bKilled = structureDamage(psCurrS, damage,
psStats->weaponClass, psStats->weaponSubClass);
if(bKilled)
// Missed by old method, but maybe in landed within the building's footprint(baseplate)
else if(ptInStructure(psCurrS,psObj->x,psObj->y) AND (BASE_OBJECT*)psCurrS!=psObj->psDest)
{
proj_UpdateKills(psObj);
damage = NOMINAL_DAMAGE;
if(bMultiPlayer)
{
if(psObj->psSource && myResponsibility(psObj->psSource->player))
{
updateMultiStatsDamage(psObj->psSource->player, psCurrS->player,damage);
}
}
bKilled = structureDamage(psCurrS, damage,
psStats->weaponClass, psStats->weaponSubClass);
if(bKilled)
{
proj_UpdateKills(psObj);
}
}
}
}
@ -1892,8 +2036,8 @@ proj_ImpactFunc( PROJ_OBJECT *psObj )
//if (dice < psStats->radiusHit)
if (dice < weaponRadiusHit(psStats, psObj->player))
{
DBP1(("Damage to object %d, player %d\n",
psCurrF->id, psCurrF->player));
debug(LOG_NEVER, "Damage to object %d, player %d\n",
psCurrF->id, psCurrF->player);
//(void)psCurrF->damage(psCurrF, psStats->radiusDamage, psStats->weaponClass);
//(void)psCurrF->damage(psCurrF, calcDamage(psStats->radiusDamage,
/*(void)psCurrF->damage(psCurrF, calcDamage(weaponRadDamage(
@ -2102,8 +2246,8 @@ proj_checkBurnDamage( BASE_OBJECT *apsList, PROJ_OBJECT *psProj,
- (SDWORD)psCurr->burnDamage;
if (damageToDo > 0)
{
DBP1(("Burn damage of %d to object %d, player %d\n",
damageToDo, psCurr->id, psCurr->player));
debug(LOG_NEVER, "Burn damage of %d to object %d, player %d\n",
damageToDo, psCurr->id, psCurr->player);
// if(bMultiPlayer)
// {
@ -2186,7 +2330,6 @@ UDWORD radius;
STRUCTURE *psStructure;
FEATURE *psFeat;
//Watermelon:droid pointer
DROID *psDroid = NULL;
radius = 0;
@ -2199,8 +2342,7 @@ DROID *psDroid = NULL;
switch(psTarget->type)
{
case OBJ_DROID:
psDroid = (DROID *)psTarget;
switch(psDroid->droidType)
switch(((DROID *)psTarget)->droidType)
{
case DROID_WEAPON:
case DROID_SENSOR:
@ -2208,17 +2350,13 @@ DROID *psDroid = NULL;
case DROID_CONSTRUCT:
case DROID_COMMAND:
case DROID_REPAIR:
//Watermelon:'hitbox' size is now based on body size
//Watermelon:Light:16 Medium:32 Heavy:48 S.Heavy:64
radius = TILE_UNITS/8 + ( (asBodyStats + psDroid->asBits[COMP_BODY].nStat)->size * 16 );
break;
case DROID_PERSON:
case DROID_CYBORG:
case DROID_CYBORG_CONSTRUCT:
case DROID_CYBORG_REPAIR:
case DROID_CYBORG_SUPER:
//Watermelon:cyborg and person have smaller 'hitbox' now
radius = TILE_UNITS/8;
//Watermelon:'hitbox' size is now based on imd size
radius = (psTarget->sDisplay.imd->xmax + psTarget->sDisplay.imd->zmax)/2;
break;
case DROID_DEFAULT:
case DROID_TRANSPORTER:
@ -2490,4 +2628,3 @@ void projGetNaybors(PROJ_OBJECT *psObj)