Tremulous Forum

Mods => Modding Center => Topic started by: Redman on September 18, 2009, 09:51:43 pm

Title: Trapper prediction
Post by: Redman on September 18, 2009, 09:51:43 pm
Hello.

I'm trying to make a little mod for my server. I started with new buildable. It's normal trapper, but it kills.
The problem is I want to remove its prediction. I really don't know how this piece of code works, so i'm asking your for help :)

Code: [Select]
//==================================================================================

#define ARET_ACCURACY 10 // lower is better

/*
================
Aret_FireOnEnemy

Used by Aret_Think to fire at enemy
================
*/
void Aret_FireOnEnemy( gentity_t *self, int firespeed, float range )
{
  gentity_t *enemy = self->enemy;
  vec3_t    dirToTarget;
  vec3_t    halfAcceleration, thirdJerk;
  float     distanceToTarget = BG_FindRangeForBuildable( self->s.modelindex );
  int       lowMsec = 0;
  int       highMsec = (int)( (
    ( ( distanceToTarget * ARETM_SPEED ) +
      ( distanceToTarget * BG_FindSpeedForClass( enemy->client->ps.stats[ STAT_PCLASS ] ) ) ) /
    ( LOCKBLOB_SPEED * ARETM_SPEED ) ) * 1000.0f );
    
  VectorScale( enemy->acceleration, 1.0f / 2.0f, halfAcceleration );
  VectorScale( enemy->jerk, 1.0f / 3.0f, thirdJerk );

  // highMsec and lowMsec can only move toward
  // one another, so the loop must terminate
  while( highMsec - lowMsec > ARET_ACCURACY )
  {
    int   partitionMsec = ( highMsec + lowMsec ) / 2;
    float time = (float)partitionMsec / 1000.0f;
    float projectileDistance = ARETM_SPEED * time;

    VectorMA( enemy->s.pos.trBase, time, enemy->s.pos.trDelta, dirToTarget );
    VectorMA( dirToTarget, time * time, halfAcceleration, dirToTarget );
    VectorMA( dirToTarget, time * time * time, thirdJerk, dirToTarget );
    VectorSubtract( dirToTarget, self->s.pos.trBase, dirToTarget );
    distanceToTarget = VectorLength( dirToTarget );

    if( projectileDistance < distanceToTarget )
      lowMsec = partitionMsec;
    else if( projectileDistance > distanceToTarget )
      highMsec = partitionMsec;
    else if( projectileDistance == distanceToTarget )
      break; // unlikely to happen
  }

  VectorNormalize( dirToTarget );
  vectoangles( dirToTarget, self->turretAim );

  //fire at target
  FireWeapon( self );
  G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
  self->count = level.time + firespeed;
}

(note: ARETM_* means its missile, ARET_* the buildable)

Thanks for reading.
Title: Re: Trapper prediction
Post by: gimhael on September 19, 2009, 07:32:24 am
The key is the loop. It tries to predict the time and position where the trapper projectile hits the enemy if it keeps moving/accelerating in the same way.
It is basically a binary search which checks how far will the enemy be from the trapper at time <time>. If this distance is larger than the distance of the trapper projectile, try a later time, if it is smaller try an earlier time. If it is equal, we found our target.

Code: [Select]
  while( highMsec - lowMsec > ARET_ACCURACY )
  {
    // always consider the time in the middle of the interval
    int   partitionMsec = ( highMsec + lowMsec ) / 2;
    float time = (float)partitionMsec / 1000.0f;

    // the projectile moves at constant speed ARETM_SPEED, so it's distance will be ARETM_SPEED * time
    float projectileDistance = ARETM_SPEED * time;

    // the enemy may accelerate, so use the speed, acceleration and jerk to predict it's position in dirToTarget
    VectorMA( enemy->s.pos.trBase, time, enemy->s.pos.trDelta, dirToTarget );
    VectorMA( dirToTarget, time * time, halfAcceleration, dirToTarget );
    VectorMA( dirToTarget, time * time * time, thirdJerk, dirToTarget );

    // Compute the difference vector and calculate it's length to find the distance of the enemy
    VectorSubtract( dirToTarget, self->s.pos.trBase, dirToTarget );
    distanceToTarget = VectorLength( dirToTarget );

    if( projectileDistance < distanceToTarget )
      // the enemy is too far away, we have to find a later time
      lowMsec = partitionMsec;
    else if( projectileDistance > distanceToTarget )
      // the enemy is too near, we have to find an earlier time
      highMsec = partitionMsec;
    else if( projectileDistance == distanceToTarget )
      // GOTCHA!
      break; // unlikely to happen
  }

The rest is just starting the projectile:
Code: [Select]
  // store the direction for the projectile
  VectorNormalize( dirToTarget );
  vectoangles( dirToTarget, self->turretAim );

  //fire at target
  FireWeapon( self );
  // start the attack animation
  G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
  // remember time for next shot
  self->count = level.time + firespeed;

So if you want to change the prediction, just change the 3 VectorMA instructions. If you keep just the first, you get a simple linear prediction, or you could use VectorCopy(enemy->s.pos.trBase, dirToTarget) to have no prediction at all.
Title: Re: Trapper prediction
Post by: Redman on September 19, 2009, 09:49:12 am
Code: [Select]
    //VectorMA( enemy->s.pos.trBase, time, enemy->s.pos.trDelta, dirToTarget );
    //VectorMA( dirToTarget, time * time, halfAcceleration, dirToTarget );
    //VectorMA( dirToTarget, time * time * time, thirdJerk, dirToTarget );
   
    VectorSubtract( dirToTarget, self->s.pos.trBase, dirToTarget );
    distanceToTarget = VectorLength( dirToTarget );
    VectorCopy(enemy->s.pos.trBase, dirToTarget);

I think I didn't understand you. In game when it saw me it started shooting somewhere at wall. It killed my egg :( (BTW. How to make projectiles don't damage aliens and their buildings?)