Author Topic: NPC Combat Behavior - NPC should not attack while fleeing  (Read 483 times)

Legacy_chlorinesea

  • Newbie
  • *
  • Posts: 16
  • Karma: +0/-0
NPC Combat Behavior - NPC should not attack while fleeing
« on: March 16, 2011, 10:29:14 am »


               Alright, so I am making a boss monster. He has two "modes" like a megaman boss might. Let's call them "normal" and "ghost" mode. In normal mode, NPC behaves as normal. He attacks mainly with spells. If the PCs are too close to him when his heartbeat script fires, he will activate ghost mode, travel to a random waypoint, and return to normal mode.

NPC is marked "plot" while in ghost mode and cannot be damaged by PCs. I don't want him attacking from ghost mode, he is only supposed to flee, not throw off spells while no one can hit him. I tried adding a check to his heartbeat that says he should do nothing if he's in ghost mode, but it didn't seem to change anything.

Right now I have everything controlled through a custom heartbeat script, and have left the other scripts as default. I have a variable defined so I can check what mode the NPC is in. All I really need is a push in the right direction of where I should put the check for "if he's in ghost mode, do nothing. Else, attack as usual!"

I'm sorry if this is horribly obvious. I'm a little new to scripting and everything I've been able to google up has been based on how many hit points the NPC has, not whether or not the NPC has a variable marked to ____ or not. I don't think "ondamaged" will work here... I really need like... "onTryToAttack" and that isn't one of the options.

Help? '<img'>
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
NPC Combat Behavior - NPC should not attack while fleeing
« Reply #1 on: March 16, 2011, 03:32:33 pm »


               Do for him complete AI, few tips are here: http://social.biowar...3/index/6374290
then you will be able to do it properly, its also the best possible way, making a new set of ai isnt good idea since whole AI is in numerous includes...
               
               

               


                     Modifié par ShaDoOoW, 16 mars 2011 - 03:32 .
                     
                  


            

Legacy_chlorinesea

  • Newbie
  • *
  • Posts: 16
  • Karma: +0/-0
NPC Combat Behavior - NPC should not attack while fleeing
« Reply #2 on: March 16, 2011, 07:06:44 pm »


               Thank you, I was afraid that was the answer. I'm trying to keep the number of scripts used to an absolute minimum since the module is already pretty big and it's just one (REALLY COOL) boss.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
NPC Combat Behavior - NPC should not attack while fleeing
« Reply #3 on: March 16, 2011, 08:22:01 pm »


               

chlorinesea wrote...

Thank you, I was afraid that was the answer. I'm trying to keep the number of scripts used to an absolute minimum since the module is already pretty big and it's just one (REALLY COOL) boss.



There should not be a problem with the number of scripts.  It should all go in one Script.  The AI script for the boss.  Anyhing you have added  in the HB script should just be moved to the AI script. 
               
               

               
            

Legacy_chlorinesea

  • Newbie
  • *
  • Posts: 16
  • Karma: +0/-0
NPC Combat Behavior - NPC should not attack while fleeing
« Reply #4 on: March 16, 2011, 09:31:29 pm »


               I've sort of got it working now. He has an AI script which goes in basically everything, a heartbeat which controls which form he's in, and an onSpawn which just makes him stand on his starting waypoint and look dramatic.

I'm actually trying to write a script to choose the farthest waypoint, rather than a random one. Is there a quick/easy way to do this? Right now I have this huge nested mess of checking distances to other distances and I'm sure there must be a better way.
               
               

               
            

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
NPC Combat Behavior - NPC should not attack while fleeing
« Reply #5 on: March 16, 2011, 09:57:38 pm »


               Not 100% sure but I think using something like this would return the furthest one away:


void main()
{
    int iInt = 1;
    object oWaypoint = GetNearestObjectByTag("WP Tag", OBJECT_SELF, iInt);
    while (GetIsObjectValid(oWaypoint))
    {
        iInt++;
        oWaypoint = GetNearestObjectByTag("WP Tag", OBJECT_SELF, iInt);
    }
}

Hope that works for ya. Good luck.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
NPC Combat Behavior - NPC should not attack while fleeing
« Reply #6 on: March 16, 2011, 11:56:25 pm »


               

GhostOfGod wrote...

Not 100% sure but I think using something like this would return the furthest one away:


void main()
{
    int iInt = 1;
    object oWaypoint = GetNearestObjectByTag("WP Tag", OBJECT_SELF, iInt);
    while (GetIsObjectValid(oWaypoint))
    {
        iInt++;
        oWaypoint = GetNearestObjectByTag("WP Tag", OBJECT_SELF, iInt);
    }
}

Hope that works for ya. Good luck.

Im glag you are not 100% on that Ghost,  Your loop will return OBJECT_INVALID, After all if the object was valid it would loop again untill it wa not valid.  
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
NPC Combat Behavior - NPC should not attack while fleeing
« Reply #7 on: March 17, 2011, 12:53:33 am »


               Her is how I see the script being laied out to do what you are asking.


const string sbCont =  "X2_SPECIAL_COMBAT_AI_SCRIPT_OK";
void main()
{
  object oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY);

  //If an enemy is too close.
  if (GetDistanceBetween(oEnemy,OBJECT_SELF) < 5.0)
  {
    //If Plot is set I am already a ghost and the enemy is still to close.
    //If it is not set I need to go ghost.
    if(!GetPlotFlag())
    {
        // Enter your code to go ghost .

       // Stop anything from doing damage to me while im in ghost form.
       SetPlotFlag(OBJECT_SELF,TRUE);
    }

    // Enter code to jump waypoints here.

    // Stop the rest of the Combat AI From Running.
    SetLocalInt(OBJECT_SELF,sbCont,TRUE);
  }

 // If the Plot flag is set  I am ghost. 
  // and need to change back. 
  if(GetPlotFlag())
  {
     // Enter Code to remove your ghost effect here.

     // Allow myself to be damaged.
     SetPlotFlag(OBJECT_SELF,FALSE);

     // Either ENTER tailored made combat options here and set
     // SetLocalInt(OBJECT_SELF,sbCont,TRUE);
     //To stop the normal AI or leave the line above commented out to let the
     //Normal AI take over.
  }



Then all you need to do to get it to work is set a local string called "X2_SPECIAL_COMBAT_AI_SCRIPT" to the name of whatever name you compiled the script to.   You can set the string in either the toolset or via script.  Of cource yo would need to change the other scripts thet you have changed back to there defaults.  
               
               

               


                     Modifié par Lightfoot8, 17 mars 2011 - 12:56 .
                     
                  


            

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
NPC Combat Behavior - NPC should not attack while fleeing
« Reply #8 on: March 17, 2011, 01:24:20 am »


               

Lightfoot8 wrote...

Im glag you are not 100% on that Ghost,  Your loop will return OBJECT_INVALID, After all if the object was valid it would loop again untill it wa not valid.  


Whoops. Some crappy logic on my part.

How bout this(or am I just getting silly now?):

void main()
{
    int iInt = 1;
    object oWaypoint = GetNearestObjectByTag("WP Tag", OBJECT_SELF, iInt);
    object oFurthestWP;

    while (GetIsObjectValid(oWaypoint))
    {
        iInt++;
        object oWaypoint = GetNearestObjectByTag("WP Tag", OBJECT_SELF, iInt);
        if (!GetIsObjectValid(oWaypoint))
        {
            iInt--;
            oFurthestWP = GetNearestObjectByTag("WP Tag", OBJECT_SELF, iInt);
        }
    }

    ActionJumpToObject(oFurthestWP);
}

Hopefully I thought that through correctly this time. '<img'>
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
NPC Combat Behavior - NPC should not attack while fleeing
« Reply #9 on: March 17, 2011, 02:14:40 am »


               

GhostOfGod wrote...

Lightfoot8 wrote...

Im glag you are not 100% on that Ghost,  Your loop will return OBJECT_INVALID, After all if the object was valid it would loop again untill it wa not valid.  


Whoops. Some crappy logic on my part.

How bout this(or am I just getting silly now?):

void main()
{
    int iInt = 1;
    object oWaypoint = GetNearestObjectByTag("WP Tag", OBJECT_SELF, iInt);
    object oFurthestWP;

    while (GetIsObjectValid(oWaypoint))
    {
        iInt++;
        object oWaypoint = GetNearestObjectByTag("WP Tag", OBJECT_SELF, iInt);
        if (!GetIsObjectValid(oWaypoint))
        {
            iInt--;
            oFurthestWP = GetNearestObjectByTag("WP Tag", OBJECT_SELF, iInt);
        }
    }

    ActionJumpToObject(oFurthestWP);
}

Hopefully I thought that through correctly this time. '<img'>


Yes looks like it would work. except for redifining oWaypoint again it would be a different object(being in a differant name space) then the one used by the check in youe while loop. 

  but would not this be simpler. 

  void main()
{
    int iInt = 1;
    object oWaypoint = GetNearestObjectByTag("WP Tag", OBJECT_SELF, iInt);
    object oFurthestWP;
    int iDistance;

    while (GetIsObjectValid(oWaypoint))
    {
        iInt++;
        oFurthestWP = oWaypoint;       
        oWaypoint = GetNearestObjectByTag("WP Tag", OBJECT_SELF, iInt);
    }

    ActionJumpToObject(oFurthestWP);
}

 
 


But I still think one thing is being overlooked.  The fact is that after one or two jumps, if not before, the Boss is going to only jump between the two waypoints that are furthest apart.  It kind of would make it a moot point to have more then two waypoints.   A better solution would be to get the waypoint that is Furthest away from an enemy.  Like this:

void main()
{
    int iInt = 1;
    object oWaypoint = GetNearestObjectByTag("WP Tag", OBJECT_SELF, iInt);
    object oFurthestWP, oClosestEnemy;
    float iDistanceCheck,iGreatestDistance;

    while (GetIsObjectValid(oWaypoint))
    {
        iInt++;
        oClosestEnemy = GetNearestCreature  ( CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oWaypoint);
        iDistanceCheck = GetDistanceBetween( oClosestEnemy,oWaypoint);
        if (iDistanceCheck>iGreatestDistance)
        {
           oFurthestWP = oWaypoint;
           iGreatestDistance = iDistanceCheck;
        }
        oWaypoint = GetNearestObjectByTag("WP Tag", OBJECT_SELF, iInt);
    }

    ActionJumpToObject(oFurthestWP);
}
  



EDIT:  OOps.  Even mine is messed up.  I'm Finding the enemy of the waypoint not the Boss.   lol.  
               
               

               


                     Modifié par Lightfoot8, 17 mars 2011 - 02:23 .
                     
                  


            

Legacy_chlorinesea

  • Newbie
  • *
  • Posts: 16
  • Karma: +0/-0
NPC Combat Behavior - NPC should not attack while fleeing
« Reply #10 on: March 17, 2011, 04:26:38 am »


               Wow, awesome! I just got back from work to all these replies! '<img'>! I'm
gonna have to sort through these before I have an intelligent reply, but
I wanted to post and say I saw them and you guys are AWESOME.
Especially since this was an additional question from my first one.

Just to be fair and/or get it checked, here's the heartbeat on him at the moment, with my comments and debug stuff still in there. This also still uses randomly generated waypoints instead of farthest away.


#include "zep_inc_monster"

void main()
{
//defining variables
object oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC);
object oWP;
string sState = GetLocalString(OBJECT_SELF, "STATE");
effect eTransform = EffectVisualEffect(36);

//If he's already in wisp form...
if (sState == "WISP")
{
    //... then don't do anything else yet.
    ClearAllActions();
}
//check how close the PC is. If PC is close, then run away, unless you're a wisp.
if ((GetDistanceToObject(oPC) < 5.0) && (sState != "WISP"))
{
    //randomly generate which waypoint to move to.
    int iRandom = Random(7);
    switch (iRandom)
       {
      case 0: oWP = GetWaypointByTag("WP_zcaveboss_01");
            SendMessageToPC(oPC, "WP 1");
          break;
      case 1: oWP = GetWaypointByTag("WP_zcaveboss_02");
            SendMessageToPC(oPC, "WP 2");
          break;
      case 2: oWP = GetWaypointByTag("WP_zcaveboss_03");
            SendMessageToPC(oPC, "WP 3");
          break;
      case 3: oWP = GetWaypointByTag("WP_zcaveboss_04");
            SendMessageToPC(oPC, "WP 4");
          break;
      case 4: oWP = GetWaypointByTag("WP_zcaveboss_05");
            SendMessageToPC(oPC, "WP 5");
          break;
      case 5: oWP = GetWaypointByTag("WP_zcaveboss_06");
            SendMessageToPC(oPC, "WP 6");
          break;
      case 6: oWP = GetWaypointByTag("WP_zcaveboss_07");
            SendMessageToPC(oPC, "WP 7");
          break;
        }
    //howl!
    ActionCastSpellAtObject(SPELLABILITY_HOWL_FEAR, oPC, METAMAGIC_ANY, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
    //turn to purple wisp and become invincible
    ApplyEffectToObject(DURATION_TYPE_INSTANT, eTransform, OBJECT_SELF);
    SetCreatureAppearanceType(OBJECT_SELF, 1996);
    SetPlotFlag(OBJECT_SELF, 1);
    SetLocalString(OBJECT_SELF, "STATE", "WISP");

    //move to randomly generated waypoint
    DelayCommand(1.0, AssignCommand(OBJECT_SELF, ActionMoveToObject(oWP)));

    //wait ten seconds, then return to cerebrilith model and become vulnerable again
    DelayCommand(10.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eTransform, OBJECT_SELF));
    DelayCommand(10.0, AssignCommand(OBJECT_SELF, SetCreatureAppearanceType(OBJECT_SELF, 2016)));
    DelayCommand(10.0, AssignCommand(OBJECT_SELF, SetPlotFlag(OBJECT_SELF, 0)));
    DelayCommand(10.0, AssignCommand(OBJECT_SELF, SetLocalString(OBJECT_SELF, "STATE", "NORMAL")));
}
else SendMessageToPC(oPC, "No nearby threats!");
}

I also got some help from my roommate... she does code professionally, but has never used NWN. She suggested a for loop, which I don't quite remember how to do. Here's her psuedo-code:


object currentfurthestobject = GetWaypointByTag("WP_zcaveboss_0" + 1);
currentfurthestdistance = distanceto first way point

//make a while loop, start from second way point in list
while(theres still way points) //or foreach way point
for(int i = 2; i <= 7; i++)
{
   currentwaypoint = GetWaypointByTag("WP_zcaveboss_0" + i);
   distance = distance to current way point
   if(distance > currentfurthestdistance)
   {
      currentfurthestdistance = distance
      currentfurthestobject = currentwaypoint;
   }    
}

Okay... I'm going to see what I can get working with those resources! Thank you for all your help. '<img'>

Edit: I frankenstein'd a lot of this together and it seems to be working! '<img'> He STILL attacks as a wisp/ghost sometimes, though. I'll have to play with that. Thanks for your help, guys!
               
               

               


                     Modifié par chlorinesea, 17 mars 2011 - 07:57 .