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-861f7616d084
master
Roman C 2006-11-05 18:26:56 +00:00
parent 0fcdc8184e
commit 90077ff547
4 changed files with 430 additions and 13 deletions

View File

@ -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));

View File

@ -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);
}
}
}

View File

@ -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_ */

View File

@ -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;