A pet NPC that attacks enemies on command.

Aerisetta

Active member

Wondering if I can get some help on this.

in this video, the player is controlling the Blue Hoodie guy who punches.

There is a succbus with a scythe who follows him around (the pet)
Right now, the Succubus is a NPC entity that is hostile and chasing the player.
However, she cannot damage the player and only damages enemies (this is correct).
Right now, the succubus NPC does not follow the player's command, it is actually just attacking the player but hitting the enemies.

What I would like is.
  1. the succubus continues to follow the player.
  2. The succubus does NOT attack on it's own
  3. When the player presses a button, the succubus will dash towards the enemy attack with an attack.
  4. The succubus then returns to following the player.
  5. I want the succubus to do the attack without the player doing any animation change
Thanks
 
Not hard to do at all. You've already got most of it taken care of by setting the NPC up.

the succubus continues to follow the player.

The succubus does NOT attack on it's own

Set hostile to none. I also like to remove any attacks, specials, and freespecials just to have a clean model, but it's not a requirement. The NPC will now just follow you around.

When the player presses a button, the succubus will dash towards the enemy attack with an attack.

This could start to get into one of those "if you have to ask an open ended question, then you aren't ready for the specifics". As in, are you wanting to reactivate the AI so it intelligently chases down a target? Or just a straight running dash (kind of like Galford's dog)? The latter is pretty simple to do, the former gets a little tricky.

The succubus then returns to following the player.

Nothing special about that, assuming a straight up dash attack. When the attack is over, the AI will handle returning on its own. If it's the more complex intelligent chase down, then unsettling the flags we have to mess with will also do it.

That's just a matter of putting the command into a key script, and not tying the key to other actions, or canceling those actions in the key script. You get the acting entity ("self"), and assuming you spawned the NPC using summon, you can get the NPC entity pointer by looking at self's child property. Then it's just like any other entity script. You make the child play an animation that has the attack in it.

I don't want to assume you didn't think of the gotchas, but since you didn't mention them... You'll want to check for conditions to make it not look, well, stupid. Like, only executing the command if the NPC is within a certain range. Think again of Poppy - Galford can't command her if she's busy doing an attack, out of her heel position, or shaking off a hit.

That should prime you for the more specific questions,
DC
 
I've made some scripts for this kinda of stuff - in fact, to control any entity when I want to.
All those scripts must go in your animationscript file and choose which ones fits you better

1 - changeEntAnim
Force a specific entity, by its model name ("default name"), to go to a specific animation.
No check done, so the entity will stop anithing it is done to execute it (it only checks it the target is alive)
Warning: this works by brute force, so it will make ALL entities with the same name to execute the animation

C-like:
void changeEntAnim(char target_name, int Ani)
{// Make a specific entity to change to a desired animation
//Douglas Baldan - 2018.07.21
    int i;
    for (i = 0; i < openborvariant("count_entities"); ++i)
    {
        void ent = getentity(i);
        if ( getentityproperty(ent, "exists") && !getentityproperty(ent, "dead"))
           {
                   if ( getentityproperty(ent,"model") == target_name)
            {
                changeentityproperty(ent, "animation", openborconstant(Ani));
                continue;
            }
        } else continue;
    }
    return;  
}
Usage
@cmd changeEntAnim "dog" "ANI_FOLLOW1"
Will make the target entity to go to FOLLOW1 animation.
If you have two entities called "dog" but one has the alias "wolf", both will be affected.

*ps I am aware of the bad memory usage by not using openborconstant, I just don't have time to update my code as I write this

2 - changeEntAnim2
Does the same of above, but checking for an animation (it checks if the animation is different than a specific one. If you want to check if its the same of the specific one, just revert the logic from != to ==)

C-like:
void changeEntAnim2(char target_name, int Ani, int AniCheck)
{// Make a specific entity to change to a desired animation, with animation check
//Douglas Baldan - 2018.07.21
    int i;
    for (i = 0; i < openborvariant("count_entities"); ++i)
    {
        void ent = getentity(i);
        if ( getentityproperty(ent, "exists") )
           {
                   if ( getentityproperty(ent,"model") == target_name && getentityproperty(ent,"animation") != AniCheck)
            {
                changeentityproperty(ent, "animation", openborconstant(Ani));
                continue;
            }
        } else continue;
    }
    return;  
}

Usage
@cmd changeEntAnim "dog" "ANI_FOLLOW1" "ANI_IDLE"
Will make the target entity to go to FOLLOW1 animation, but only if it isn't on the IDLE animation.
If you have two entities called "dog" but one has the alias "wolf", both will be affected.

The next two does the same as above, but they check for the entity alias instead of its default name.
IOW, If you have two entities called "dog" but one has the alias "wolf", just the "wolf" will be affected

C-like:
void changeAliasAnim(char target_name, int Ani)
{// Make a specific entity to change to a desired animation
//Douglas Baldan - 2018.07.21
  int i;
  for (i = 0; i < openborvariant("count_entities"); ++i)
  {
      void ent = getentity(i);
    if ( getentityproperty(ent, "exists") )
      {
            if ( getentityproperty(ent,"name") == target_name)
      {
        changeentityproperty(ent, "animation", openborconstant(Ani));
        continue;
      }
    } else continue;
  }
  return;
}


void changeAliasAnim2(char target_name, int Ani, int AniCheck)
{// Make a specific entity to change to a desired animation, with animation check
//Douglas Baldan - 2018.07.21
  int i;
  for (i = 0; i < openborvariant("count_entities"); ++i)
  {
      void ent = getentity(i);
    if ( getentityproperty(ent, "exists") )
      {
            if ( getentityproperty(ent,"name") == target_name && getentityproperty(ent,"animation") != AniCheck)
      {
        changeentityproperty(ent, "animation", openborconstant(Ani));
        continue;
      }
    } else continue;
  }
  return;
}
 
C-like:
void changeEntAnim(char target_name, int Ani)
{// Make a specific entity to change to a desired animation
//Douglas Baldan - 2018.07.21
int i;
for (i = 0; i < openborvariant("count_entities"); ++i)
{
void ent = getentity(i);
if ( getentityproperty(ent, "exists") && !getentityproperty(ent, "dead"))
{
if ( getentityproperty(ent,"model") == target_name)
{
changeentityproperty(ent, "animation", openborconstant(Ani));
continue;
}
} else continue;
}
return;
}
Usage

@O Ilusionista,

For controlling an NPC from its parent, you can massively optimize this and ensure it doesn't affect the wrong entity by looking for the parent (or if a projectile, owner) property instead and comparing it to the calling entity. As is, you're doing the slowest comparison (string vs string) possible on every on screen entity until you find the one you are looking for. By replacing that with parent vs. caller, you perform a pointer comparison instead, which is dozens of times faster to do. It's also more accurate, since there's no chance of name conflicts:

C:
void changeChildAnim(void parent, int Ani)

{// Make a specific entity to change to a desired animation

//Douglas Baldan - 2018.07.21

    int i;

    for (i = 0; i < openborvariant("count_entities"); ++i){

        void ent = getentity(i);

        if ( getentityproperty(ent, "exists") && !getentityproperty(ent, "dead")){

            if ( getentityproperty(ent,"parent") == parent){
            
                changeentityproperty(ent, "animation", openborconstant(Ani));
                continue;
            }

        } else continue;

    }

    return;
}
 
What I would like is to have also:
  1. When the player presses a button, the succubus has as hostile the enemy.
  2. The succubus then returns to following the player when the player represses the same button (hostile becomes none).
  3. I want the succubus attacks with the player doing any animation change
 
Back
Top Bottom