Checking if player is surrounded by two enemies

mersox

Active member
Hi guys, I've hit a wall. I'm looking to find a way to make the player change it's attack if he's surrounded by two enemies: one enemy in front and one behind. A good example is the double kick in Batletoads SNES.

I'm using as a base this script (which works), that detects a nearby enemy (only one enemy):

Code:
void finisher(void AniP, void Ani , int RxMin, int RxMax, int Ry, int Rz, int Type, int Flag)
{// Checks closest enemy's animation & range
// If it's accepted, change animation
// AniP  : Enemy's animation
// Ani   : Animation to change to
// RxMin : Minimum x range
// RxMax : Maximum x range
// Ry    : y range
// Rz    : z range
// Type  : 0 = non targetted , 1 = for targetting, 2 = for grabbing
// Flag  : 0 = facing direction not necessary , 1 = facing direction must be opposite

/*Originally smartbomb by
    Damon Vaughn Caskey
    07152008*/

    void self = getlocalvar("self");            //Caller.
    float x = getentityproperty(self, "x");
    float y = getentityproperty(self, "a");
    float z = getentityproperty(self, "z");
    int dir = getentityproperty(self, "direction");
    void vEntity;                                       //Target entity placeholder.
    int  iEntity;                                       //Entity enumeration holder.
    int  iType;                                         //Entity type.
    int  iMax      = openborvariant("count_entities");         //Entity count.

     //Enumerate and loop through entity collection.
    for(iEntity=0; iEntity<iMax; iEntity++){
      vEntity = getentity(iEntity);                 //Get target entity from current loop.
      iType   = getentityproperty(vEntity, "type"); //Get target type.

      //Enemy type?
      if (iType == openborconstant("TYPE_ENEMY")){
        float Tx = getentityproperty(vEntity, "x");
        float Ty = getentityproperty(vEntity, "a");
    float Tz = getentityproperty(vEntity, "z");
        int Anti = getentityproperty(vEntity, "antigrab");
        int Edir = getentityproperty(vEntity, "direction");
    void EAnim = getentityproperty(vEntity, "animationID");

        if(EAnim == openborconstant(AniP)){
      float Disx = Tx - x;
      float Disy = Ty - y;
      float Disz = Tz - z;

      if(Disz < 0){
        Disz = -Disz;
      }

      if(Disy < 0){
        Disy = -Disy;
      }

      if( Disx >= RxMin && Disx <= RxMax && Disz <= Rz && Disy <= Ry && dir == 1 ) // Target within range on right facing?
      {
        if(Type == 2){
          if(((Flag == 1 && Edir == 0) || Flag == 0) && Anti < 10){
            dasher(0,0,0);
            setlocalvar("Target" + self, vEntity);
            performattack(self, openborconstant(Ani));
          }
        } else {
          if((Flag == 1 && Edir == 0) || Flag == 0){
            if(Type == 1){
              dasher(0,0,0);
              setlocalvar("Target" + self, vEntity);
            }
            performattack(self, openborconstant(Ani));
          }
        }
      } else if( Disx >= -RxMax && Disx <= -RxMin && Disz <= Rz && Disy <= Ry && dir == 0) // Target within range on left facing?
      {
        if(Type == 2){
          if(((Flag == 1 && Edir == 1) || Flag == 0) && Anti < 10){
            dasher(0,0,0);
            setlocalvar("Target" + self, vEntity);
            performattack(self, openborconstant(Ani));
          }
        } else {
          if((Flag == 1 && Edir == 1) || Flag == 0){
            if(Type == 1){
              dasher(0,0,0);
              setlocalvar("Target" + self, vEntity);
            }
            performattack(self, openborconstant(Ani));
          }
        }
      }
        }
      }
    }
}

My logic was to modify it so that when one condition is met (enemy is behind of player), the script starts another search for an enemy on the opposite side of the player. If found, it changes the animation accordingly to a double attack (Ani2). If not, it switches to a back attack (Ani).

This is the script so far (it needs to be expanded to also detect a "flipped" version when player is facing the opposite direction, but that's not important now). This version makes the game close at startup. There's probably an obvious issue I'm not seeing.

Code:
void surroundattack(void Ani, void Ani2, int RxMin, int RxMax, int Ry, int Rz)
{// Checks closest enemy's animation & range
// If it's accepted, change animation
// Ani   : Animation to change to
// RxMin : Minimum x range
// RxMax : Maximum x range
// Ry    : y range
// Rz    : z range


/*Originally smartbomb by
    Damon Vaughn Caskey
    07152008*/

    void self = getlocalvar("self");            //Caller.
    float x = getentityproperty(self, "x");
    float y = getentityproperty(self, "a");
    float z = getentityproperty(self, "z");
    int dir = getentityproperty(self, "direction");
    void vEntity;                                       //Target entity placeholder.
    int  iEntity;                                       //Entity enumeration holder.
    int  iType;                                         //Entity type.

    void vEntity2;                                       //Target entity placeholder (second count).
    int  iEntity2;                                       //Entity enumeration holder (second count).
    int  iType2;                                         //Entity type (second count).

    int  iMax      = openborvariant("count_entities");         //Entity count.

     //Enumerate and loop through entity collection.
    for(iEntity=0; iEntity<iMax; iEntity++){
      vEntity = getentity(iEntity);                 //Get target entity from current loop.
      iType   = getentityproperty(vEntity, "type"); //Get target type.

      //Enemy type?
      if (iType == openborconstant("TYPE_ENEMY")){
        float Tx = getentityproperty(vEntity, "x");
        float Ty = getentityproperty(vEntity, "a");
    float Tz = getentityproperty(vEntity, "z");



        {
      float Disx = Tx - x;
      float Disy = Ty - y;
      float Disz = Tz - z;

      if(Disz < 0){
        Disz = -Disz;
      }

      if(Disy < 0){
        Disy = -Disy;
      }

      if( Disx >= RxMin && Disx <= RxMax && Disz <= Rz && Disy <= Ry && dir == 1 ) // Enemy behind player when right facing?
      {


             //Enumerate and loop through entity collection.
            for(iEntity2=0; iEntity2<iMax; iEntity2++){
              vEntity2 = getentity(iEntity2);                 //Get target entity from current loop.
              iType2   = getentityproperty(vEntity2, "type"); //Get target type.

              //Enemy type?
              if (iType2 == openborconstant("TYPE_ENEMY")){
                float Tx2 = getentityproperty(vEntity2, "x");
                float Ty2 = getentityproperty(vEntity2, "a");
            float Tz2 = getentityproperty(vEntity2, "z");


                {
              float Disx2 = Tx2 - x;
              float Disy2 = Ty2 - y;
              float Disz2 = Tz2 - z;

              if(Disz2 < 0){
                Disz2 = -Disz2;
              }

              if(Disy2 < 0){
                Disy2 = -Disy2;
              }

        if( Disx2 >= -RxMax && Disx2 <= -RxMin && Disz2 <= Rz && Disy2 <= Ry && dir == 1) // Enemy in front of player when right facing?

              {
                    performattack(self, openborconstant(Ani2));
                  }

                                      }
         }
    
        

         else {performattack(self, openborconstant(Ani));
        }
          }
        


        }
      }
    }
}


Here's what the log says:
Script error: data/chars/daniel/daniel.txt, line 137: Unknown error '' (in production 'stmt_list')


^


********** An Error Occurred **********
* Shutting Down *

Fatal Error in load_cached_model, file: data/chars/daniel/daniel.txt, line 661, message: Error parsing function main of animation script in file '%s'!
Total Ram: 8482250752 Bytes ( 8089 MB )
Free Ram: 1427103744 Bytes ( 1360 MB )
Used Ram: 59858944 Bytes ( 57 MB )

Release level data...........
Done!

Release graphics data........ Done!
Release game data............


Release game data............ Done!
Release timer................ Done!
Release input hardware....... Done!
Release sound system......... Done!
Release FileCaching System... Done!

**************** Done *****************

Fatal Error in load_cached_model, file: data/chars/daniel/daniel.txt, line 661, message: Error parsing function main of animation script in file '%s'!

line 661 (counted with notepad) refers to an unrelated section of the player's file that normally has no issues. I don't know what's up with that.

The script is called by the player entity like this:
@cmd surroundattack "ANI_attackbackward" "ANI_attack4" -60 0 0 7

I'm at my wit's end...
 
Are you trying to make one player grab two enemies at the same time for performing a slam?
 
Hi guys, I've hit a wall. I'm looking to find a way to make the player change it's attack if he's surrounded by two enemies: one enemy in front and one behind. A good example is the double kick in Batletoads SNES.

I'm using as a base this script (which works), that detects a nearby enemy (only one enemy):

Code:
void finisher(void AniP, void Ani , int RxMin, int RxMax, int Ry, int Rz, int Type, int Flag)
{// Checks closest enemy's animation & range
// If it's accepted, change animation
// AniP  : Enemy's animation
// Ani   : Animation to change to
// RxMin : Minimum x range
// RxMax : Maximum x range
// Ry    : y range
// Rz    : z range
// Type  : 0 = non targetted , 1 = for targetting, 2 = for grabbing
// Flag  : 0 = facing direction not necessary , 1 = facing direction must be opposite

/*Originally smartbomb by
    Damon Vaughn Caskey
    07152008*/

    void self = getlocalvar("self");            //Caller.
    float x = getentityproperty(self, "x");
    float y = getentityproperty(self, "a");
    float z = getentityproperty(self, "z");
    int dir = getentityproperty(self, "direction");
    void vEntity;                                       //Target entity placeholder.
    int  iEntity;                                       //Entity enumeration holder.
    int  iType;                                         //Entity type.
    int  iMax      = openborvariant("count_entities");         //Entity count.

     //Enumerate and loop through entity collection.
    for(iEntity=0; iEntity<iMax; iEntity++){
      vEntity = getentity(iEntity);                 //Get target entity from current loop.
      iType   = getentityproperty(vEntity, "type"); //Get target type.

      //Enemy type?
      if (iType == openborconstant("TYPE_ENEMY")){
        float Tx = getentityproperty(vEntity, "x");
        float Ty = getentityproperty(vEntity, "a");
    float Tz = getentityproperty(vEntity, "z");
        int Anti = getentityproperty(vEntity, "antigrab");
        int Edir = getentityproperty(vEntity, "direction");
    void EAnim = getentityproperty(vEntity, "animationID");

        if(EAnim == openborconstant(AniP)){
      float Disx = Tx - x;
      float Disy = Ty - y;
      float Disz = Tz - z;

      if(Disz < 0){
        Disz = -Disz;
      }

      if(Disy < 0){
        Disy = -Disy;
      }

      if( Disx >= RxMin && Disx <= RxMax && Disz <= Rz && Disy <= Ry && dir == 1 ) // Target within range on right facing?
      {
        if(Type == 2){
          if(((Flag == 1 && Edir == 0) || Flag == 0) && Anti < 10){
            dasher(0,0,0);
            setlocalvar("Target" + self, vEntity);
            performattack(self, openborconstant(Ani));
          }
        } else {
          if((Flag == 1 && Edir == 0) || Flag == 0){
            if(Type == 1){
              dasher(0,0,0);
              setlocalvar("Target" + self, vEntity);
            }
            performattack(self, openborconstant(Ani));
          }
        }
      } else if( Disx >= -RxMax && Disx <= -RxMin && Disz <= Rz && Disy <= Ry && dir == 0) // Target within range on left facing?
      {
        if(Type == 2){
          if(((Flag == 1 && Edir == 1) || Flag == 0) && Anti < 10){
            dasher(0,0,0);
            setlocalvar("Target" + self, vEntity);
            performattack(self, openborconstant(Ani));
          }
        } else {
          if((Flag == 1 && Edir == 1) || Flag == 0){
            if(Type == 1){
              dasher(0,0,0);
              setlocalvar("Target" + self, vEntity);
            }
            performattack(self, openborconstant(Ani));
          }
        }
      }
        }
      }
    }
}

My logic was to modify it so that when one condition is met (enemy is behind of player), the script starts another search for an enemy on the opposite side of the player. If found, it changes the animation accordingly to a double attack (Ani2). If not, it switches to a back attack (Ani).

This is the script so far (it needs to be expanded to also detect a "flipped" version when player is facing the opposite direction, but that's not important now). This version makes the game close at startup. There's probably an obvious issue I'm not seeing.

Code:
void surroundattack(void Ani, void Ani2, int RxMin, int RxMax, int Ry, int Rz)
{// Checks closest enemy's animation & range
// If it's accepted, change animation
// Ani   : Animation to change to
// RxMin : Minimum x range
// RxMax : Maximum x range
// Ry    : y range
// Rz    : z range


/*Originally smartbomb by
    Damon Vaughn Caskey
    07152008*/

    void self = getlocalvar("self");            //Caller.
    float x = getentityproperty(self, "x");
    float y = getentityproperty(self, "a");
    float z = getentityproperty(self, "z");
    int dir = getentityproperty(self, "direction");
    void vEntity;                                       //Target entity placeholder.
    int  iEntity;                                       //Entity enumeration holder.
    int  iType;                                         //Entity type.

    void vEntity2;                                       //Target entity placeholder (second count).
    int  iEntity2;                                       //Entity enumeration holder (second count).
    int  iType2;                                         //Entity type (second count).

    int  iMax      = openborvariant("count_entities");         //Entity count.

     //Enumerate and loop through entity collection.
    for(iEntity=0; iEntity<iMax; iEntity++){
      vEntity = getentity(iEntity);                 //Get target entity from current loop.
      iType   = getentityproperty(vEntity, "type"); //Get target type.

      //Enemy type?
      if (iType == openborconstant("TYPE_ENEMY")){
        float Tx = getentityproperty(vEntity, "x");
        float Ty = getentityproperty(vEntity, "a");
    float Tz = getentityproperty(vEntity, "z");



        {
      float Disx = Tx - x;
      float Disy = Ty - y;
      float Disz = Tz - z;

      if(Disz < 0){
        Disz = -Disz;
      }

      if(Disy < 0){
        Disy = -Disy;
      }

      if( Disx >= RxMin && Disx <= RxMax && Disz <= Rz && Disy <= Ry && dir == 1 ) // Enemy behind player when right facing?
      {


             //Enumerate and loop through entity collection.
            for(iEntity2=0; iEntity2<iMax; iEntity2++){
              vEntity2 = getentity(iEntity2);                 //Get target entity from current loop.
              iType2   = getentityproperty(vEntity2, "type"); //Get target type.

              //Enemy type?
              if (iType2 == openborconstant("TYPE_ENEMY")){
                float Tx2 = getentityproperty(vEntity2, "x");
                float Ty2 = getentityproperty(vEntity2, "a");
            float Tz2 = getentityproperty(vEntity2, "z");


                {
              float Disx2 = Tx2 - x;
              float Disy2 = Ty2 - y;
              float Disz2 = Tz2 - z;

              if(Disz2 < 0){
                Disz2 = -Disz2;
              }

              if(Disy2 < 0){
                Disy2 = -Disy2;
              }

        if( Disx2 >= -RxMax && Disx2 <= -RxMin && Disz2 <= Rz && Disy2 <= Ry && dir == 1) // Enemy in front of player when right facing?

              {
                    performattack(self, openborconstant(Ani2));
                  }

                                      }
         }
   
       

         else {performattack(self, openborconstant(Ani));
        }
          }
       


        }
      }
    }
}


Here's what the log says:


line 661 (counted with notepad) refers to an unrelated section of the player's file that normally has no issues. I don't know what's up with that.

The script is called by the player entity like this:
@cmd surroundattack "ANI_attackbackward" "ANI_attack4" -60 0 0 7

I'm at my wit's end...

If you want to look for entities on all sides, I would define a range, use a cache, and populate that in the enumeration with entities found within range until the loop stops or the of the entities are on opposing sides. It's still an enumeration, but a bit different than a straight up smartbomb type thing.

What exactly do you need it for, and I'll see about retooling.

DC
 
Error parsing function main of animation script in file '%s'!

Are you using main() in your animation script?

[Next day]
Anyways, I've tried coding this script myself and here's what I got. There are two functions here:
C:
void findEnemyRange(int RxMin, int RxMax, int Rz, int Flag)
{// Checks closest enemy's range
// If it's accepted, return a value. If not returns 0.
// RxMin : Minimum x range
// RxMax : Maximum x range
// Rz    : z range
// Flag  : 0 = returns the enemy , 1 = returns 1.
    void self = getlocalvar("self");            //Caller.
    float x = getentityproperty(self, "x");
    float z = getentityproperty(self, "z");
    int dir = getentityproperty(self, "direction");
    void vEntity;                                       //Target entity placeholder.
    int  iEntity;                                       //Entity enumeration holder.
    int  iType;                                         //Entity type.
    int  iMax  = openborvariant("count_entities");   //Entity count.
    void Res = 0;

    //Enumerate and loop through entity collection.
    for(iEntity=0; iEntity<iMax; iEntity++){
      vEntity = getentity(iEntity);                 //Get target entity from current loop.
      iType   = getentityproperty(vEntity, "type"); //Get target type.

      //Enemy type?
      if(iType == openborconstant("TYPE_ENEMY")){
        float Tx = getentityproperty(vEntity, "x");
    float Tz = getentityproperty(vEntity, "z");
        float Disx = Tx - x;
        float Disz = Tz - z;

        if(Disz < 0){
          Disz = -Disz;
        }

        if(Disx >= RxMin && Disx <= RxMax && Disz <= Rz && dir == 1){ // Target within range on right facing?
          if(Flag == 0){
            Res = vEntity;
            break;
          } else if(Flag == 1){
            Res = 1;
            break;
          }
        } else if(Disx >= -RxMax && Disx <= -RxMin && Disz <= Rz && dir == 0){ // Target within range on left facing?
          if(Flag == 0){
            Res = vEntity;
            break;
          } else if(Flag == 1){
            Res = 1;
            break;
          }
        }
      }
    }

    return Res;
}

void find2Enemies(int RxMin, int RxMax, int Rz, void Ani)
{// Check if there are two enemies within defined range.
// If two enemies are found, change animation.
// RxMin : Minimum x range
// RxMax : Maximum x range
// Rz    : z range
// Ani : Animation to play when specifed entity is valid
    void self = getlocalvar("self");
    int Cd = openborconstant(Ani);
    int Fr = findEnemyRange(RxMin, RxMax, Rz, 1);
    int Bk = findEnemyRange(-RxMax, -RxMin, Rz, 1);
   
    if(Fr+Bk==2){
      performattack(self, Cd);
    }
}

Here's usage example:
Code:
anim    attack1
    delay    7
    offset    50 100
    @cmd    find2Enemies 0 80 10 "ANI_FOLLOW1"
...

When ATTACK1 is performed, the script will check if there are 2 enemies, one at front and another at back within 80 pixels in x axis and 10 pixels in z axis. If there were, change animation into FOLLOW1.
 
Last edited:
Back
Top Bottom