Author Topic: AI: Light Shy Behavior  (Read 471 times)

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
AI: Light Shy Behavior
« on: May 29, 2011, 02:30:20 am »


               [This thread resulted in my Light Shy AI available on the vault. I will document changes to the scripts in this thread as long as people seem interested - or at least I am.]

Is there an efficient way to enable an NPC to perceive "light"?

I am looking for a means to make certain creatures avoid light, and others to be attracted by it. The only ways I can conceive of doing this appear resource intensive. For example, cycling through the items wieded/worn by a perceived PC and looking for a light property.
               
               

               


                     Modifié par henesua, 13 mars 2012 - 09:55 .
                     
                  


            

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
AI: Light Shy Behavior
« Reply #1 on: May 29, 2011, 04:42:47 am »


               Hmm...That's kinda the only way I can think to do it too. There is one function with the "x2_inc_itemprop" include script that will let you check to see if the player has an item property on any of his items (IPGetHasItemPropertyOnCharacter) which you could use directly in the OnPerceived script, but I beleive that would still do the same thing you already suggested, cycle through all euqipped items looking for an item property. Bioware just already did all the work for you.

But to make it less intensive, one other thing you could do would be to put an int variable on a player when they equip something with a light property and then remove it when they unequip the item. That way you only need to check to see if the perceived player has the variable instead of cycling through all the items and properties.

Something like so for the PlayerEquip:

void main()
{
    object oItem = GetPCItemLastEquipped();
    object oPC   = GetPCItemLastEquippedBy();
    int iLight = GetItemHasItemProperty(oItem, ITEM_PROPERTY_LIGHT);

    if (iLight == TRUE)
    {
        SetLocalInt(oPC, "LIGHT", TRUE);
    }
}

And then something kinda like so for the PlayerUnEquip:

void main()
{
    object oItem = GetPCItemLastUnequipped();
    object oPC   = GetPCItemLastUnequippedBy();
    int iLight = GetItemHasItemProperty(oItem, ITEM_PROPERTY_LIGHT);

    if (iLight == TRUE)
    {
        SetLocalInt(oPC, "LIGHT", FALSE);
    }
}

Then again you might run into problems with the above method when players have more than one item with a light property. So you will probably have to cycle through equipped item in the PlayerUnequip script to see if any of the other items have any light properties before you set the "LIGHT" int to FALSE.

Just some ideas. Hope they help and good luck.
               
               

               


                     Modifié par GhostOfGod, 29 mai 2011 - 04:04 .
                     
                  


            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
AI: Light Shy Behavior
« Reply #2 on: May 29, 2011, 12:43:58 pm »


               That is a good idea. Thank you. I didn't think of that yesterday.
               
               

               
            

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
AI: Light Shy Behavior
« Reply #3 on: May 29, 2011, 05:13:13 pm »


               Oh hey. If you're still keeping tabs on this thread I thought of a better way than doing the True of False method. Just increase or decrease the integer variable. Every time someone equips an item with light property, ++ the int. If they unequip then -- the int. And as long as you keep that variable persistent(database item or what not) then you don't have to mess with looping through equipped items at all. Then you still just check for 0/false in the OnPerceived script.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
AI: Light Shy Behavior
« Reply #4 on: May 29, 2011, 06:31:25 pm »


               

GhostOfGod wrote...

 And as long as you keep that variable persistent(database item or what not) then you don't have to mess with looping through equipped items at all. .


Be carefull with keeping the variable persistent.  The Equip event will still fire onClient enter.
               
               

               
            

Legacy_Fester Pot

  • Hero Member
  • *****
  • Posts: 1698
  • Karma: +0/-0
AI: Light Shy Behavior
« Reply #5 on: May 29, 2011, 06:32:16 pm »


               Could this be used to check for the Light spell being activated on the player as well?

FP!
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
AI: Light Shy Behavior
« Reply #6 on: May 30, 2011, 12:51:07 am »


                AI is more complicated than I thought. I'm currently wrestling with making light shyness a special behavior, having defined this special behavior in DetermineSpecialBehavior(). Currently light shyness is only signaled when the PC attacks the creature while holding a light. I wanted the OnPerception event to signal it, but it isn't working so far.

However I have successfully kept track of whether the PC has an active light source.

Important: Instances where the PC casts the spell on itself rather than on an item have to be treated specially, and tracked in a different way. You simply look for the spell effect

if( GetHasSpellEffect(SPELL_LIGHT, oNearest) )
      iLightBrightness = 3;


iLightBrightness is a value that I either store on the individual wielding/exhibiting the light or use immediately when determining whether an individual has a light.
               
               

               


                     Modifié par henesua, 29 mai 2011 - 11:57 .
                     
                  


            

Legacy_ffbj

  • Hero Member
  • *****
  • Posts: 1097
  • Karma: +0/-0
AI: Light Shy Behavior
« Reply #7 on: May 30, 2011, 04:59:45 pm »


               This should probably only matter at night or in underground areas.  Also which creatures are light sensitive?  I suppose there could be a variable on the creature indicating it is light sensitive.  I did a little something like this in that rats will run away from you if you have torch equipped.  Not fearful of light perse, but fire.
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
AI: Light Shy Behavior
« Reply #8 on: May 30, 2011, 05:06:26 pm »


               When I have ironed out the kinks I'll share the code. But the short of it is that I am using "Special Behavior". I created a new special behavior flag that I call light shyness, and flag them with in their onspawn event. For an existing example you can check out the herbivore/omnivore/carnivore code.

For the most part, you are right that this is most important in dark areas of the underground. I am particularly focusing on spiders right now. And giving the PC a candle that is consumed over time. When the candle burns out.... the spiders rush in.
               
               

               
            

Legacy_ffbj

  • Hero Member
  • *****
  • Posts: 1097
  • Karma: +0/-0
AI: Light Shy Behavior
« Reply #9 on: May 30, 2011, 05:13:34 pm »


               lol.  "I sit beside my only candle, which is so little light to guide my way. Now my story unfolds before my candle, which gets shorter every hour as it reaches for the day"...and then the spiders eat me.
               
               

               


                     Modifié par ffbj, 30 mai 2011 - 04:14 .
                     
                  


            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
AI: Light Shy Behavior
« Reply #10 on: May 31, 2011, 03:45:41 am »


                After all that mess trying to get this to work as Special Behavior... it didn't work. So I modified all the relevant AI scripts. Here's an example mdified HB script:

//::///////////////////////////////////////////////
//:: Name ag_ai_shyl_hb
/*
   Modified OnHeartbeat AI script
   Originals x2_def_heartbeat NW_C2_DEFAULT1

   This script causes NPCs to perform default animations
   while not otherwise engaged.

   Creatures shy of light will move away from sources of light that they perceive
*/
//:://////////////////////////////////////////////
//:: Created By: Naomi Novik (12/22/2002)
//:: Modified: The Magus (2011 may 30) special ai for light shy creatures
//:://////////////////////////////////////////////

#include "ag_inc_shylight"

void main()
{
   // * if not runnning normal or better Ai then exit for performance reasons
   if (GetAILevel() == AI_LEVEL_VERY_LOW) return;

   // Buff ourselves up right away if we should
   if(GetSpawnInCondition(NW_FLAG_FAST_BUFF_ENEMY))
   {
       // This will return TRUE if an enemy was within 40.0 m
       // and we buffed ourselves up instantly to respond --
       // simulates a spellcaster with protections enabled
       // already.
       if(TalentAdvancedBuff(40.0))
       {
           // This is a one-shot deal
           SetSpawnInCondition(NW_FLAG_FAST_BUFF_ENEMY, FALSE);

           // This return means we skip sending the user-defined
           // heartbeat signal in this one case.
           return;
       }
   }


   if(GetHasEffect(EFFECT_TYPE_SLEEP))
   {
       // If we're asleep and this is the result of sleeping
       // at night, apply the floating 'z's visual effect
       // every so often

       if(GetSpawnInCondition(NW_FLAG_SLEEPING_AT_NIGHT))
       {
           effect eVis = EffectVisualEffect(VFX_IMP_SLEEP);
           if(d10() > 6)
           {
               ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF);
           }
       }
   }

   // If we have the 'constant' waypoints flag set, walk to the next waypoint.
   else if ( GetWalkCondition(NW_WALK_FLAG_CONSTANT) )
   {
       WalkWayPoints();
   }

   // Check to see if we should be playing default animations
   // - make sure we don't have any current targets
   else if ( !GetIsObjectValid(GetAttemptedAttackTarget())
         && !GetIsObjectValid(GetAttemptedSpellTarget())
         // && !GetIsPostOrWalking())
         // && !GetIsObjectValid(GetNearestSeenEnemy())
         )
   {
       // Since we aren't doing anything in particular we should be looking out for light sources and enemies
       // variables used in identifying the source of the closest pool of light
       int bAttack = FALSE;
       int nNth    = 1;
       int iLightBrightness;
       int iBrightest;
       float fDistToLight = 0.0;
       float fDistBrightest;
       object oBrightestLight;

       object oNearest = GetNearestCreature(CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, OBJECT_SELF, nNth);
       // loop through seen creatures, looking for sources of light
       while ( GetIsObjectValid(oNearest) )
       {
           iLightBrightness = 0;
           iLightBrightness = GetLightBrightness(oNearest);

           // found a light source
           if (iLightBrightness > 0)
           {
               float fTemp = fDistToLight;
               fDistToLight= GetDistanceToObject(oNearest) - IntToFloat(iLightBrightness*5);

               // compare with previously found lightsources to determine which has the closest pool of light
               if ( fTemp == 0.0 )
               {
                   oBrightestLight = oNearest;
                   fDistBrightest = fDistToLight;
                   iBrightest = iLightBrightness;
               }
               else if ( fDistToLight < fDistBrightest )
               {
                   fDistBrightest = fDistToLight;
                   oBrightestLight = oNearest;
                   iBrightest = iLightBrightness;
               }
               else if ( fDistToLight == fDistBrightest && iBrightest < iLightBrightness )
               {
                   fDistBrightest = fDistToLight;
                   oBrightestLight = oNearest;
                   iBrightest = iLightBrightness;
               }

           }
           else if(GetIsEnemy(oNearest) && !IsInLight(oNearest))
           {
               bAttack = TRUE;
               ClearAllActions();
               DetermineCombatRound(oNearest);
               break;
           }
           oNearest = GetNearestCreature(CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, OBJECT_SELF, ++nNth);
       }

       if( GetIsObjectValid(oBrightestLight) && !bAttack)
       {
           if(GetDistanceToObject(oBrightestLight)<2.1)
           {
               ClearAllActions();
               ActionMoveAwayFromObject(oBrightestLight, TRUE);
           }
           else
           {
               ClearAllActions();
               ActionMoveAwayFromObject(oBrightestLight, FALSE, IntToFloat(iBrightest*5)+1.0);
           }
       }
       else if (!IsInConversation(OBJECT_SELF) && !bAttack)
       {
           if (GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS)
               || GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS_AVIAN)
               || GetIsEncounterCreature())
           {
               PlayMobileAmbientAnimations();
           }
           else if (GetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS))
           {
               PlayImmobileAmbientAnimations();
           }
       }
   }

   // Send the user-defined event signal if specified
   if(GetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT))
   {
       SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_HEARTBEAT));
   }
}
               
               

               


                     Modifié par henesua, 31 mai 2011 - 02:46 .
                     
                  


            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
AI: Light Shy Behavior
« Reply #11 on: May 31, 2011, 03:54:41 pm »


               After posting the above Heart Beat script I made a simple modification that greatly improves the behavior of these light shy creatures in game. Above the command for the creature to walk away I added a command to look at the brightest light source. Very spooky and realistic looking, because the creature does not always need to move away. So you have scores of these critters turning to look at the light. When the pool of light falls on them they move away, but otherwise they keep an eye on you while going about their business. It looks like they are just waiting fo the light source to burn out, and then they'll move in to devour you.
               
               

               


                     Modifié par henesua, 31 mai 2011 - 03:12 .
                     
                  


            

Legacy_Taino

  • Sr. Member
  • ****
  • Posts: 268
  • Karma: +0/-0
AI: Light Shy Behavior
« Reply #12 on: June 01, 2011, 02:33:47 am »


               Nice Idea.
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
AI: Light Shy Behavior
« Reply #13 on: June 02, 2011, 02:43:43 am »


                I posted a clean version of this to the vault.
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
AI: Light Shy Behavior
« Reply #14 on: March 13, 2012, 09:47:09 pm »


               Recent developments in my Arnhiem module have lead me back to the Light Shy AI I developed last year.

In Arnheim, I have a need for campfires and placeable candles to shed light (The candles are items that transform into a placeable version when dropped, and can be picked up again all of which is handled in the module events OnAcquire and OnUnacquire.) so I have structured their local variables to work with the light shy AI scripts. The next step is to alter the loop in the light shy AI so that Placeables as well as Creatures which shed let will be responded to.

The next release will include the ability for light shy creatures to see and react to placeable light sources.

The release is a ways off as all of my efforts are focused on ruinning an event in Arnheim this March. But when the dust settles, I'll update my vault projects including this one with any improvements I have made.