Patch by Watermelon: New hit-system with target prediction
git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@819 4a71c877-e1ca-e34f-864e-861f7616d084master
parent
0fcdc8184e
commit
90077ff547
49
src/combat.c
49
src/combat.c
|
@ -84,7 +84,7 @@ BOOL combShutdown(void)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Watermelon:real projectile
|
||||||
/* Fire a weapon at something */
|
/* Fire a weapon at something */
|
||||||
void combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget)
|
void combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget)
|
||||||
{
|
{
|
||||||
|
@ -99,6 +99,13 @@ void combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget)
|
||||||
DROID *psDroid = NULL;
|
DROID *psDroid = NULL;
|
||||||
SDWORD level, cmdLevel;
|
SDWORD level, cmdLevel;
|
||||||
BOOL bMissVisible;
|
BOOL bMissVisible;
|
||||||
|
//Watermelon:minOffset
|
||||||
|
int minOffset = 5;
|
||||||
|
//Watermelon:predicted X,Y offset per sec
|
||||||
|
SDWORD predictX;
|
||||||
|
SDWORD predictY;
|
||||||
|
//Watermelon:dirty dist
|
||||||
|
SDWORD dist;
|
||||||
|
|
||||||
ASSERT( PTRVALID(psWeap, sizeof(WEAPON)),
|
ASSERT( PTRVALID(psWeap, sizeof(WEAPON)),
|
||||||
"combFire: Invalid weapon pointer" );
|
"combFire: Invalid weapon pointer" );
|
||||||
|
@ -336,6 +343,8 @@ void combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget)
|
||||||
xDiff = abs(psAttacker->x - psTarget->x);
|
xDiff = abs(psAttacker->x - psTarget->x);
|
||||||
yDiff = abs(psAttacker->y - psTarget->y);
|
yDiff = abs(psAttacker->y - psTarget->y);
|
||||||
distSquared = xDiff*xDiff + yDiff*yDiff;
|
distSquared = xDiff*xDiff + yDiff*yDiff;
|
||||||
|
//Watermelon:dirty dist
|
||||||
|
dist = dirtySqrt(psAttacker->x,psAttacker->y,psTarget->x,psTarget->y);
|
||||||
longRange = proj_GetLongRange(psStats, (SDWORD)psAttacker->z-(SDWORD)psTarget->z);
|
longRange = proj_GetLongRange(psStats, (SDWORD)psAttacker->z-(SDWORD)psTarget->z);
|
||||||
if (distSquared <= (psStats->shortRange * psStats->shortRange) AND
|
if (distSquared <= (psStats->shortRange * psStats->shortRange) AND
|
||||||
distSquared >= (psStats->minRange * psStats->minRange))
|
distSquared >= (psStats->minRange * psStats->minRange))
|
||||||
|
@ -357,9 +366,22 @@ void combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget)
|
||||||
if (dice <= (weaponShortHit(psStats,psAttacker->player) * hitMod /100) + hitInc)
|
if (dice <= (weaponShortHit(psStats,psAttacker->player) * hitMod /100) + hitInc)
|
||||||
{
|
{
|
||||||
/* Kerrrbaaang !!!!! a hit */
|
/* Kerrrbaaang !!!!! a hit */
|
||||||
|
//Watermelon:Target prediction
|
||||||
|
if(psTarget->type == OBJ_DROID)
|
||||||
|
{
|
||||||
|
predictX = (cos(((DROID *)psTarget)->sMove.dir) * ((DROID *)psTarget)->sMove.speed * sqrt(distSquared)) /psStats->flightSpeed;
|
||||||
|
predictX += psTarget->x;
|
||||||
|
predictY = (sin(((DROID *)psTarget)->sMove.dir) * ((DROID *)psTarget)->sMove.speed * sqrt(distSquared)) /psStats->flightSpeed;
|
||||||
|
predictY += psTarget->y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
predictX = psTarget->x;
|
||||||
|
predictY = psTarget->y;
|
||||||
|
}
|
||||||
DBP3(("Shot hit (%d)\n", dice));
|
DBP3(("Shot hit (%d)\n", dice));
|
||||||
if (!proj_SendProjectile(psWeap, psAttacker, psAttacker->player,
|
if (!proj_SendProjectile(psWeap, psAttacker, psAttacker->player,
|
||||||
psTarget->x, psTarget->y, psTarget->z, psTarget, FALSE))
|
predictX, predictY, psTarget->z, psTarget, FALSE))
|
||||||
{
|
{
|
||||||
/* Out of memory - we can safely ignore this */
|
/* Out of memory - we can safely ignore this */
|
||||||
DBP3(("Out of memory"));
|
DBP3(("Out of memory"));
|
||||||
|
@ -395,9 +417,22 @@ void combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget)
|
||||||
if (dice <= (weaponLongHit(psStats,psAttacker->player) * hitMod /100) + hitInc)
|
if (dice <= (weaponLongHit(psStats,psAttacker->player) * hitMod /100) + hitInc)
|
||||||
{
|
{
|
||||||
/* Kerrrbaaang !!!!! a hit */
|
/* Kerrrbaaang !!!!! a hit */
|
||||||
|
//Watermelon:Target prediction
|
||||||
|
if(psTarget->type == OBJ_DROID)
|
||||||
|
{
|
||||||
|
predictX = (cos(((DROID *)psTarget)->sMove.dir) * ((DROID *)psTarget)->sMove.speed * sqrt(distSquared)) /psStats->flightSpeed;
|
||||||
|
predictX += psTarget->x;
|
||||||
|
predictY = (sin(((DROID *)psTarget)->sMove.dir) * ((DROID *)psTarget)->sMove.speed * sqrt(distSquared)) /psStats->flightSpeed;
|
||||||
|
predictY += psTarget->y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
predictX = psTarget->x;
|
||||||
|
predictY = psTarget->y;
|
||||||
|
}
|
||||||
DBP3(("Shot hit (%d)\n", dice));
|
DBP3(("Shot hit (%d)\n", dice));
|
||||||
if (!proj_SendProjectile(psWeap, psAttacker, psAttacker->player,
|
if (!proj_SendProjectile(psWeap, psAttacker, psAttacker->player,
|
||||||
psTarget->x, psTarget->y, psTarget->z, psTarget, FALSE))
|
predictX, predictY, psTarget->z, psTarget, FALSE))
|
||||||
{
|
{
|
||||||
/* Out of memory - we can safely ignore this */
|
/* Out of memory - we can safely ignore this */
|
||||||
DBP3(("Out of memory"));
|
DBP3(("Out of memory"));
|
||||||
|
@ -422,6 +457,7 @@ missed:
|
||||||
/* Deal with a missed shot */
|
/* Deal with a missed shot */
|
||||||
DBP3(("Missed shot (%d)\n", dice));
|
DBP3(("Missed shot (%d)\n", dice));
|
||||||
|
|
||||||
|
/*
|
||||||
// Approximate the distance between the attacker and target
|
// Approximate the distance between the attacker and target
|
||||||
xDiff = ABSDIF(psAttacker->x,psTarget->x);
|
xDiff = ABSDIF(psAttacker->x,psTarget->x);
|
||||||
yDiff = ABSDIF(psAttacker->y,psTarget->y);
|
yDiff = ABSDIF(psAttacker->y,psTarget->y);
|
||||||
|
@ -436,6 +472,13 @@ missed:
|
||||||
missDir = rand() % BUL_MAXSCATTERDIR;
|
missDir = rand() % BUL_MAXSCATTERDIR;
|
||||||
missX = aScatterDir[missDir].x * (rand() % missDist) + psTarget->x;
|
missX = aScatterDir[missDir].x * (rand() % missDist) + psTarget->x;
|
||||||
missY = aScatterDir[missDir].y * (rand() % missDist) + psTarget->y;
|
missY = aScatterDir[missDir].y * (rand() % missDist) + psTarget->y;
|
||||||
|
*/
|
||||||
|
//Watermelon:add a more 'accurate' miss
|
||||||
|
missDist = 2 * (100 - (weaponLongHit(psStats,psAttacker->player) * hitMod /100) + hitInc);
|
||||||
|
missDir = rand() % BUL_MAXSCATTERDIR;
|
||||||
|
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",
|
DBP3(("Miss Loc: w(%4d,%4d), t(%3d,%3d)\n",
|
||||||
missX, missY, missX>>TILE_SHIFT, missY>>TILE_SHIFT));
|
missX, missY, missX>>TILE_SHIFT, missY>>TILE_SHIFT));
|
||||||
|
|
||||||
|
|
371
src/projectile.c
371
src/projectile.c
|
@ -41,6 +41,8 @@
|
||||||
#include "multiplay.h"
|
#include "multiplay.h"
|
||||||
#include "multistat.h"
|
#include "multistat.h"
|
||||||
|
|
||||||
|
// Watermelon:I need this one for map grid iteration
|
||||||
|
#include "mapgrid.h"
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
/* max number of slots in hash table - prime numbers are best because hash
|
/* max number of slots in hash table - prime numbers are best because hash
|
||||||
|
@ -69,6 +71,45 @@
|
||||||
/*#define GFX_VISIBLE(psObj) ((psObj->psSource != NULL) AND psObj->psSource->visible[selectedPlayer]) OR \
|
/*#define GFX_VISIBLE(psObj) ((psObj->psSource != NULL) AND psObj->psSource->visible[selectedPlayer]) OR \
|
||||||
((psObj->psDest != NULL) AND psObj->psDest->visible[selectedPlayer] )*/
|
((psObj->psDest != NULL) AND psObj->psDest->visible[selectedPlayer] )*/
|
||||||
|
|
||||||
|
// Watermelon:they are from droid.c
|
||||||
|
/* The range for neighbouring objects */
|
||||||
|
#define PROJ_NAYBOR_RANGE (TILE_UNITS*4)
|
||||||
|
|
||||||
|
// macro to see if an object is in NAYBOR_RANGE
|
||||||
|
// used by projGetNayb
|
||||||
|
#define IN_PROJ_NAYBOR_RANGE(psTempObj) \
|
||||||
|
xdiff = dx - (SDWORD)psTempObj->x; \
|
||||||
|
if (xdiff < 0) \
|
||||||
|
{ \
|
||||||
|
xdiff = -xdiff; \
|
||||||
|
} \
|
||||||
|
if (xdiff > PROJ_NAYBOR_RANGE) \
|
||||||
|
{ \
|
||||||
|
continue; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
ydiff = dy - (SDWORD)psTempObj->y; \
|
||||||
|
if (ydiff < 0) \
|
||||||
|
{ \
|
||||||
|
ydiff = -ydiff; \
|
||||||
|
} \
|
||||||
|
if (ydiff > PROJ_NAYBOR_RANGE) \
|
||||||
|
{ \
|
||||||
|
continue; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
distSqr = xdiff*xdiff + ydiff*ydiff; \
|
||||||
|
if (distSqr > PROJ_NAYBOR_RANGE*PROJ_NAYBOR_RANGE) \
|
||||||
|
{ \
|
||||||
|
continue; \
|
||||||
|
} \
|
||||||
|
|
||||||
|
// Watermelon:neighbour global info ripped from droid.c
|
||||||
|
PROJ_NAYBOR_INFO asProjNaybors[MAX_NAYBORS];
|
||||||
|
UDWORD numProjNaybors=0;
|
||||||
|
|
||||||
|
static BASE_OBJECT *CurrentProjNaybors = NULL;
|
||||||
|
static UDWORD projnayborTime = 0;
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
|
@ -570,6 +611,23 @@ proj_InFlightDirectFunc( PROJ_OBJECT *psObj )
|
||||||
SDWORD dx, dy, dz, iX, iY, dist, xdiff,ydiff;
|
SDWORD dx, dy, dz, iX, iY, dist, xdiff,ydiff;
|
||||||
SDWORD rad;
|
SDWORD rad;
|
||||||
iVector pos;
|
iVector pos;
|
||||||
|
//Watermelon:int i
|
||||||
|
int i;
|
||||||
|
//Watermelon:2 temp BASE_OBJECT pointer
|
||||||
|
BASE_OBJECT *psTempObj;
|
||||||
|
BASE_OBJECT *psNewTarget;
|
||||||
|
//Watermelon:Vector z diff not used atm
|
||||||
|
SDWORD zdiff;
|
||||||
|
//Watermelon:Missile or not
|
||||||
|
BOOL bMissile;
|
||||||
|
//Watermelon:extended 'lifespan' of a projectile
|
||||||
|
//no more disappeared projectiles.
|
||||||
|
SDWORD extendRad;
|
||||||
|
//Watermelon:given explosive weapons some 'hit collision' bonus
|
||||||
|
//esp the AAGun,or it will never hit anything with the new hit system
|
||||||
|
int wpRadius = 1;
|
||||||
|
|
||||||
|
bMissile = FALSE;
|
||||||
|
|
||||||
ASSERT( PTRVALID(psObj, sizeof(PROJ_OBJECT)),
|
ASSERT( PTRVALID(psObj, sizeof(PROJ_OBJECT)),
|
||||||
"proj_InFlightDirectFunc: invalid projectile pointer" );
|
"proj_InFlightDirectFunc: invalid projectile pointer" );
|
||||||
|
@ -631,8 +689,8 @@ proj_InFlightDirectFunc( PROJ_OBJECT *psObj )
|
||||||
// ffs
|
// ffs
|
||||||
// rad = fastRoot(dx,dy);
|
// rad = fastRoot(dx,dy);
|
||||||
rad = (SDWORD)iSQRT( dx*dx + dy*dy );
|
rad = (SDWORD)iSQRT( dx*dx + dy*dy );
|
||||||
|
//Watermelon:extended life span
|
||||||
|
extendRad = (SDWORD)rad * 1.5f;
|
||||||
|
|
||||||
|
|
||||||
if (rad == 0)
|
if (rad == 0)
|
||||||
|
@ -716,6 +774,80 @@ proj_InFlightDirectFunc( PROJ_OBJECT *psObj )
|
||||||
pos.z = psObj->y;
|
pos.z = psObj->y;
|
||||||
addEffect(&pos,EFFECT_SMOKE,SMOKE_TYPE_TRAIL,FALSE,NULL,0);
|
addEffect(&pos,EFFECT_SMOKE,SMOKE_TYPE_TRAIL,FALSE,NULL,0);
|
||||||
}
|
}
|
||||||
|
bMissile = TRUE;
|
||||||
|
wpRadius = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Watermelon:weapon radius,or the 'real' projectile will never hit a moving target with the changes...
|
||||||
|
if (psStats->weaponSubClass == WSC_MGUN ||
|
||||||
|
psStats->weaponSubClass == WSC_FLAME ||
|
||||||
|
psStats->weaponSubClass == WSC_COMMAND)
|
||||||
|
{
|
||||||
|
wpRadius = 2;
|
||||||
|
//Watermelon:extended life span
|
||||||
|
extendRad = (SDWORD)rad * 1.2f;
|
||||||
|
}
|
||||||
|
else if (psStats->weaponSubClass == WSC_CANNON ||
|
||||||
|
psStats->weaponSubClass == WSC_ENERGY ||
|
||||||
|
psStats->weaponSubClass == WSC_GAUSS ||
|
||||||
|
psStats->weaponSubClass == WSC_BOMB ||
|
||||||
|
psStats->weaponSubClass == WSC_ELECTRONIC ||
|
||||||
|
psStats->weaponSubClass == WSC_EMP)
|
||||||
|
{
|
||||||
|
wpRadius = 3;
|
||||||
|
//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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Watermelon:test test
|
||||||
|
for (i = 0;i < numProjNaybors;i++)
|
||||||
|
{
|
||||||
|
//if (asProjNaybors[i].psObj == psObj->psDest)
|
||||||
|
//{
|
||||||
|
//continue;
|
||||||
|
//}
|
||||||
|
|
||||||
|
if (asProjNaybors[i].psObj->player != psObj->player &&
|
||||||
|
(asProjNaybors[i].psObj->type == OBJ_DROID ||
|
||||||
|
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;
|
||||||
|
//Watermelon;so a projectile wont collide with another projectile unless it's a counter-missile weapon
|
||||||
|
if ( psTempObj->type == OBJ_BULLET )
|
||||||
|
{
|
||||||
|
if ( !bMissile || (((PROJ_OBJECT *)psTempObj)->psWStats->weaponSubClass != WSC_COUNTER) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xdiff = (SDWORD)psObj->x - (SDWORD)psTempObj->x;
|
||||||
|
ydiff = (SDWORD)psObj->y - (SDWORD)psTempObj->y;
|
||||||
|
zdiff = (SDWORD)psObj->z - (SDWORD)psTempObj->z;
|
||||||
|
|
||||||
|
//Watermelon:dont apply the 'hitbox' bonus if the target is a building
|
||||||
|
if ( psTempObj->type == OBJ_STRUCTURE )
|
||||||
|
{
|
||||||
|
wpRadius = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((xdiff*xdiff + ydiff*ydiff) < (wpRadius * (SDWORD)(establishTargetRadius(psTempObj)) * (SDWORD)(establishTargetRadius(psTempObj))) )
|
||||||
|
{
|
||||||
|
psNewTarget = psTempObj;
|
||||||
|
psObj->psDest = psNewTarget;
|
||||||
|
psObj->state = PROJ_IMPACT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See if effect has finished */
|
/* See if effect has finished */
|
||||||
|
@ -728,13 +860,34 @@ proj_InFlightDirectFunc( PROJ_OBJECT *psObj )
|
||||||
psObj->state = PROJ_IMPACT;
|
psObj->state = PROJ_IMPACT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( dist > (rad-(SDWORD)psObj->targetRadius ) )
|
else if ( dist > (extendRad-(SDWORD)psObj->targetRadius ) )
|
||||||
{
|
{
|
||||||
/* It's damage time */
|
/* It's damage time */
|
||||||
// psObj->x = psObj->tarX; // leave it there, but use tarX and tarY for damage
|
// psObj->x = psObj->tarX; // leave it there, but use tarX and tarY for damage
|
||||||
// psObj->y = psObj->tarY;
|
// psObj->y = psObj->tarY;
|
||||||
|
if (psObj->psDest)
|
||||||
|
{
|
||||||
|
xdiff = (SDWORD)psObj->x - (SDWORD)psObj->psDest->x;
|
||||||
|
ydiff = (SDWORD)psObj->y - (SDWORD)psObj->psDest->y;
|
||||||
|
//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)) ) )
|
||||||
|
{
|
||||||
psObj->state = PROJ_IMPACT;
|
psObj->state = PROJ_IMPACT;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Watermelon:missed.you can now 'dodge' projectile by micro,so cyborgs should be more useful now
|
||||||
|
psObj->state = PROJ_IMPACT;
|
||||||
|
psObj->psDest = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Watermelon:missed. you can now 'dodge' projectile by micro,so cyborgs should be more useful now
|
||||||
|
psObj->state = PROJ_IMPACT;
|
||||||
|
psObj->psDest = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if CHECK_PROJ_ABOVE_GROUND
|
#if CHECK_PROJ_ABOVE_GROUND
|
||||||
/* check not trying to travel through terrain - if so count as a miss */
|
/* check not trying to travel through terrain - if so count as a miss */
|
||||||
|
@ -767,6 +920,12 @@ proj_InFlightIndirectFunc( PROJ_OBJECT *psObj )
|
||||||
iVector pos;
|
iVector pos;
|
||||||
FRACT fVVert;
|
FRACT fVVert;
|
||||||
BOOL bOver = FALSE;
|
BOOL bOver = FALSE;
|
||||||
|
//Watermelon:psTempObj,psNewTarget,i,xdiff,ydiff,zdiff
|
||||||
|
BASE_OBJECT *psTempObj;
|
||||||
|
BASE_OBJECT *psNewTarget;
|
||||||
|
int i;
|
||||||
|
SDWORD xdiff,ydiff,zdiff,extendRad;
|
||||||
|
int wpRadius = 9;
|
||||||
|
|
||||||
ASSERT( PTRVALID(psObj, sizeof(PROJ_OBJECT)),
|
ASSERT( PTRVALID(psObj, sizeof(PROJ_OBJECT)),
|
||||||
"proj_InFlightIndirectFunc: invalid projectile pointer" );
|
"proj_InFlightIndirectFunc: invalid projectile pointer" );
|
||||||
|
@ -781,7 +940,9 @@ proj_InFlightIndirectFunc( PROJ_OBJECT *psObj )
|
||||||
dy = (SDWORD)psObj->tarY-(SDWORD)psObj->startY;
|
dy = (SDWORD)psObj->tarY-(SDWORD)psObj->startY;
|
||||||
|
|
||||||
// ffs
|
// ffs
|
||||||
iRad = fastRoot(dx,dy);
|
//Watermelon:this is too inaccurate for a 'real' projectle
|
||||||
|
//iRad = fastRoot(dx,dy);
|
||||||
|
iRad = (SDWORD)iSQRT( dx*dx + dy*dy );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -815,6 +976,8 @@ proj_InFlightIndirectFunc( PROJ_OBJECT *psObj )
|
||||||
fVVert = MAKEFRACT(psObj->vZ - (iTime*ACC_GRAVITY/GAME_TICKS_PER_SEC));
|
fVVert = MAKEFRACT(psObj->vZ - (iTime*ACC_GRAVITY/GAME_TICKS_PER_SEC));
|
||||||
psObj->pitch = (SWORD)( RAD_TO_DEG(atan2(fVVert, psObj->vXY)) );
|
psObj->pitch = (SWORD)( RAD_TO_DEG(atan2(fVVert, psObj->vXY)) );
|
||||||
|
|
||||||
|
//Watermelon:extended life span for artillery projectile
|
||||||
|
extendRad = (SDWORD)iRad * 1.2f;
|
||||||
|
|
||||||
if(psStats->weaponSubClass == WSC_FLAME)
|
if(psStats->weaponSubClass == WSC_FLAME)
|
||||||
{
|
{
|
||||||
|
@ -868,8 +1031,51 @@ proj_InFlightIndirectFunc( PROJ_OBJECT *psObj )
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
//Watermelon:test test
|
||||||
|
for (i = 0;i < numProjNaybors;i++)
|
||||||
|
{
|
||||||
|
//if (asProjNaybors[i].psObj == psObj->psDest)
|
||||||
|
//{
|
||||||
|
//continue;
|
||||||
|
//}
|
||||||
|
|
||||||
|
if (asProjNaybors[i].psObj->player != psObj->player &&
|
||||||
|
(asProjNaybors[i].psObj->type == OBJ_DROID ||
|
||||||
|
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;
|
||||||
|
//Watermelon;dont collide with any other projectiles
|
||||||
|
if ( psTempObj->type == OBJ_BULLET )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
xdiff = (SDWORD)psObj->x - (SDWORD)psTempObj->x;
|
||||||
|
ydiff = (SDWORD)psObj->y - (SDWORD)psTempObj->y;
|
||||||
|
zdiff = (SDWORD)psObj->z - (SDWORD)psTempObj->z;
|
||||||
|
|
||||||
|
//Watermelon:dont apply the 'hitbox' bonus if the target is a building
|
||||||
|
if ( psTempObj->type == OBJ_STRUCTURE )
|
||||||
|
{
|
||||||
|
wpRadius = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((xdiff*xdiff + ydiff*ydiff) < (wpRadius * (SDWORD)(establishTargetRadius(psTempObj)) * (SDWORD)(establishTargetRadius(psTempObj))) &&
|
||||||
|
zdiff < 20 )
|
||||||
|
{
|
||||||
|
psNewTarget = psTempObj;
|
||||||
|
psObj->psDest = psNewTarget;
|
||||||
|
psObj->state = PROJ_IMPACT;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* See if effect has finished */
|
/* See if effect has finished */
|
||||||
if ( iDist > (iRad-(SDWORD)psObj->targetRadius) )
|
if ( iDist > (extendRad-(SDWORD)psObj->targetRadius) )
|
||||||
{
|
{
|
||||||
pos.x = psObj->x;
|
pos.x = psObj->x;
|
||||||
pos.z = psObj->y;
|
pos.z = psObj->y;
|
||||||
|
@ -878,10 +1084,41 @@ proj_InFlightIndirectFunc( PROJ_OBJECT *psObj )
|
||||||
/* It's damage time */
|
/* It's damage time */
|
||||||
// psObj->x = psObj->tarX; // leave it where it is, but use tarX, tarY for damage
|
// psObj->x = psObj->tarX; // leave it where it is, but use tarX, tarY for damage
|
||||||
// psObj->y = psObj->tarY;
|
// psObj->y = psObj->tarY;
|
||||||
|
//Watermelon:'real' check
|
||||||
|
if ( psObj->psDest )
|
||||||
|
{
|
||||||
psObj->z = (UWORD)(pos.y + 8);//map_Height(psObj->x,psObj->y) + 8; // bring up the impact explosion
|
psObj->z = (UWORD)(pos.y + 8);//map_Height(psObj->x,psObj->y) + 8; // bring up the impact explosion
|
||||||
psObj->state = PROJ_IMPACT;
|
psObj->state = PROJ_IMPACT;
|
||||||
|
xdiff = (SDWORD)psObj->x - (SDWORD)psObj->psDest->x;
|
||||||
|
ydiff = (SDWORD)psObj->y - (SDWORD)psObj->psDest->y;
|
||||||
|
zdiff = (SDWORD)psObj->z - (SDWORD)psObj->psDest->z;
|
||||||
|
|
||||||
|
//Watermelon:dont apply the 'hitbox' bonus if the target is a building
|
||||||
|
if ( psObj->psDest->type == OBJ_STRUCTURE )
|
||||||
|
{
|
||||||
|
wpRadius = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((xdiff*xdiff + ydiff*ydiff) < (wpRadius * (SDWORD)(establishTargetRadius(psObj->psDest)) * (SDWORD)(establishTargetRadius(psObj->psDest))) &&
|
||||||
|
zdiff < 20 )
|
||||||
|
{
|
||||||
|
psObj->state = PROJ_IMPACT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
psObj->state = PROJ_IMPACT;
|
||||||
|
psObj->psDest = NULL;
|
||||||
|
}
|
||||||
bOver = TRUE;
|
bOver = TRUE;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
psObj->state = PROJ_IMPACT;
|
||||||
|
/* miss registered if NULL target */
|
||||||
|
psObj->psDest = NULL;
|
||||||
|
bOver = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if CHECK_PROJ_ABOVE_GROUND
|
#if CHECK_PROJ_ABOVE_GROUND
|
||||||
/* check not trying to travel through terrain - if so count as a miss */
|
/* check not trying to travel through terrain - if so count as a miss */
|
||||||
|
@ -1595,6 +1832,13 @@ proj_Update( PROJ_OBJECT *psObj )
|
||||||
psObj->psDest = NULL;
|
psObj->psDest = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Watermelon:get naybors
|
||||||
|
//if(psObj->psWStats->weaponSubClass == WSC_ROCKET OR psObj->psWStats->weaponSubClass == WSC_MISSILE OR
|
||||||
|
//psObj->psWStats->weaponSubClass == WSC_SLOWROCKET OR psObj->psWStats->weaponSubClass == WSC_SLOWMISSILE)
|
||||||
|
//{
|
||||||
|
projGetNaybors((BASE_OBJECT *)psObj);
|
||||||
|
//}
|
||||||
|
|
||||||
switch (psObj->state)
|
switch (psObj->state)
|
||||||
{
|
{
|
||||||
case PROJ_INFLIGHT:
|
case PROJ_INFLIGHT:
|
||||||
|
@ -1773,11 +2017,14 @@ SDWORD proj_GetLongRange(WEAPON_STATS *psStats, SDWORD dz)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
//Watemelon:added case for OBJ_BULLET
|
||||||
UDWORD establishTargetRadius( BASE_OBJECT *psTarget )
|
UDWORD establishTargetRadius( BASE_OBJECT *psTarget )
|
||||||
{
|
{
|
||||||
UDWORD radius;
|
UDWORD radius;
|
||||||
STRUCTURE *psStructure;
|
STRUCTURE *psStructure;
|
||||||
FEATURE *psFeat;
|
FEATURE *psFeat;
|
||||||
|
//Watermelon:droid pointer
|
||||||
|
DROID *psDroid = NULL;
|
||||||
|
|
||||||
radius = 0;
|
radius = 0;
|
||||||
|
|
||||||
|
@ -1790,7 +2037,32 @@ FEATURE *psFeat;
|
||||||
switch(psTarget->type)
|
switch(psTarget->type)
|
||||||
{
|
{
|
||||||
case OBJ_DROID:
|
case OBJ_DROID:
|
||||||
|
psDroid = (DROID *)psTarget;
|
||||||
|
switch(psDroid->droidType)
|
||||||
|
{
|
||||||
|
case DROID_WEAPON:
|
||||||
|
case DROID_SENSOR:
|
||||||
|
case DROID_ECM:
|
||||||
|
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;
|
||||||
|
break;
|
||||||
|
case DROID_DEFAULT:
|
||||||
|
case DROID_TRANSPORTER:
|
||||||
|
default:
|
||||||
radius = TILE_UNITS/4; // how will we arrive at this?
|
radius = TILE_UNITS/4; // how will we arrive at this?
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case OBJ_STRUCTURE:
|
case OBJ_STRUCTURE:
|
||||||
psStructure = (STRUCTURE*)psTarget;
|
psStructure = (STRUCTURE*)psTarget;
|
||||||
|
@ -1801,6 +2073,9 @@ FEATURE *psFeat;
|
||||||
psFeat = (FEATURE *)psTarget;
|
psFeat = (FEATURE *)psTarget;
|
||||||
radius = ((max(psFeat->psStats->baseBreadth,psFeat->psStats->baseWidth)) * TILE_UNITS)/2;
|
radius = ((max(psFeat->psStats->baseBreadth,psFeat->psStats->baseWidth)) * TILE_UNITS)/2;
|
||||||
break;
|
break;
|
||||||
|
case OBJ_BULLET:
|
||||||
|
//Watermelon 1/2 radius of a droid?
|
||||||
|
radius = TILE_UNITS/8;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1960,7 +2235,93 @@ void objectShimmy(BASE_OBJECT *psObj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Watermelon:addProjNaybor ripped from droid.c
|
||||||
|
/* Add a new object to the projectile naybor list */
|
||||||
|
static void addProjNaybor(BASE_OBJECT *psObj, UDWORD distSqr)
|
||||||
|
{
|
||||||
|
UDWORD pos;
|
||||||
|
|
||||||
|
if (numProjNaybors >= MAX_NAYBORS)
|
||||||
|
{
|
||||||
|
// DBPRINTF(("Naybor list maxed out for id %d\n", psObj->id));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (numProjNaybors == 0)
|
||||||
|
{
|
||||||
|
// No objects in the list
|
||||||
|
asProjNaybors[0].psObj = psObj;
|
||||||
|
asProjNaybors[0].distSqr = distSqr;
|
||||||
|
numProjNaybors++;
|
||||||
|
}
|
||||||
|
else if (distSqr >= asProjNaybors[numProjNaybors-1].distSqr)
|
||||||
|
{
|
||||||
|
// Simple case - this is the most distant object
|
||||||
|
asProjNaybors[numProjNaybors].psObj = psObj;
|
||||||
|
asProjNaybors[numProjNaybors].distSqr = distSqr;
|
||||||
|
numProjNaybors++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Move all the objects further away up the list
|
||||||
|
pos = numProjNaybors;
|
||||||
|
while (pos > 0 && asProjNaybors[pos - 1].distSqr > distSqr)
|
||||||
|
{
|
||||||
|
memcpy(asProjNaybors + pos, asProjNaybors + (pos - 1), sizeof(PROJ_NAYBOR_INFO));
|
||||||
|
pos --;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the object at the correct position
|
||||||
|
asProjNaybors[pos].psObj = psObj;
|
||||||
|
asProjNaybors[pos].distSqr = distSqr;
|
||||||
|
numProjNaybors++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT( numProjNaybors <= MAX_NAYBORS,
|
||||||
|
"addNaybor: numNaybors > MAX_NAYBORS" );
|
||||||
|
}
|
||||||
|
|
||||||
|
//Watermelon: projGetNaybors ripped from droid.c
|
||||||
|
/* Find all the objects close to the projectile */
|
||||||
|
void projGetNaybors(PROJ_OBJECT *psObj)
|
||||||
|
{
|
||||||
|
// DROID *psCurrD;
|
||||||
|
// STRUCTURE *psCurrS;
|
||||||
|
// FEATURE *psCurrF;
|
||||||
|
SDWORD xdiff, ydiff;
|
||||||
|
// UDWORD player;
|
||||||
|
UDWORD dx,dy, distSqr;
|
||||||
|
//Watermelon:renamed to psTempObj from psObj
|
||||||
|
BASE_OBJECT *psTempObj;
|
||||||
|
|
||||||
|
// Ensure only called max of once per droid per game cycle.
|
||||||
|
if(CurrentProjNaybors == (BASE_OBJECT *)psObj && projnayborTime == gameTime) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CurrentProjNaybors = (BASE_OBJECT *)psObj;
|
||||||
|
projnayborTime = gameTime;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// reset the naybor array
|
||||||
|
numProjNaybors = 0;
|
||||||
|
#ifdef DEBUG
|
||||||
|
memset(asProjNaybors, 0xcd, sizeof(asProjNaybors));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// search for naybor objects
|
||||||
|
dx = ((BASE_OBJECT *)psObj)->x;
|
||||||
|
dy = ((BASE_OBJECT *)psObj)->y;
|
||||||
|
|
||||||
|
gridStartIterate((SDWORD)dx, (SDWORD)dy);
|
||||||
|
for (psTempObj = gridIterate(); psTempObj != NULL; psTempObj = gridIterate())
|
||||||
|
{
|
||||||
|
if (psTempObj != (BASE_OBJECT *)psObj)
|
||||||
|
{
|
||||||
|
IN_PROJ_NAYBOR_RANGE(psTempObj);
|
||||||
|
|
||||||
|
addProjNaybor(psTempObj, distSqr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,14 @@ BOOL proj_Direct(WEAPON_STATS *psStats);
|
||||||
// return the maximum range for a weapon
|
// return the maximum range for a weapon
|
||||||
SDWORD proj_GetLongRange(WEAPON_STATS *psStats, SDWORD dz);
|
SDWORD proj_GetLongRange(WEAPON_STATS *psStats, SDWORD dz);
|
||||||
|
|
||||||
|
// Watermelon:neighbour info ripped from droiddef.h
|
||||||
|
/* Info stored for each projectile neighbour */
|
||||||
|
typedef struct _proj_naybor_info
|
||||||
|
{
|
||||||
|
BASE_OBJECT *psObj; // The neighbouring object
|
||||||
|
UDWORD distSqr; // The square of the distance to the object
|
||||||
|
//UDWORD dist; // The distance to the object
|
||||||
|
} PROJ_NAYBOR_INFO;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// The fattest macro around - change this little bastard at your peril
|
// The fattest macro around - change this little bastard at your peril
|
||||||
|
@ -95,6 +103,9 @@ extern BOOL gfxVisible(PROJ_OBJECT *psObj);
|
||||||
extern BOOL justBeenHitByEW ( BASE_OBJECT *psObj );
|
extern BOOL justBeenHitByEW ( BASE_OBJECT *psObj );
|
||||||
extern void objectShimmy ( BASE_OBJECT *psObj );
|
extern void objectShimmy ( BASE_OBJECT *psObj );
|
||||||
|
|
||||||
|
// Watermelon:naybor related functions
|
||||||
|
extern void addProjNaybor(BASE_OBJECT *psObj, UDWORD distSqr);
|
||||||
|
extern void projGetNaybors(PROJ_OBJECT *psObj);
|
||||||
|
|
||||||
|
|
||||||
#endif /* _PROJECTILE_H_ */
|
#endif /* _PROJECTILE_H_ */
|
||||||
|
|
|
@ -117,6 +117,7 @@ typedef enum _weapon_class
|
||||||
} WEAPON_CLASS;
|
} WEAPON_CLASS;
|
||||||
|
|
||||||
// weapon subclasses used to define which weapons are affected by weapon upgrade functions
|
// weapon subclasses used to define which weapons are affected by weapon upgrade functions
|
||||||
|
// Watermelon:added a new subclass to do some tests
|
||||||
typedef enum _weapon_subclass
|
typedef enum _weapon_subclass
|
||||||
{
|
{
|
||||||
WSC_MGUN,
|
WSC_MGUN,
|
||||||
|
@ -138,6 +139,7 @@ typedef enum _weapon_subclass
|
||||||
WSC_BOMB,
|
WSC_BOMB,
|
||||||
WSC_COMMAND,
|
WSC_COMMAND,
|
||||||
WSC_EMP,
|
WSC_EMP,
|
||||||
|
WSC_COUNTER,
|
||||||
|
|
||||||
NUM_WEAPON_SUBCLASS,
|
NUM_WEAPON_SUBCLASS,
|
||||||
} WEAPON_SUBCLASS;
|
} WEAPON_SUBCLASS;
|
||||||
|
|
Loading…
Reference in New Issue