////////////////////////////////////////////////////////////////////////////////
//
//  Olander's AI
//  nw_c2_default1
//  by Don Anderson
//  dandersonru@msn.com
//
//  OnHeartbeat
//
////////////////////////////////////////////////////////////////////////////////

#include "oai_inc_ai"

void main()
{
    object oNPC = OBJECT_SELF;

    // dk: 10-Dec-2005 skip if performing special action
    if(GetAIOff()) return;
	
    //Skip if in combat
    if(GetAttemptedAttackTarget() != OBJECT_INVALID
      || GetAttackTarget() != OBJECT_INVALID
      || GetAttemptedSpellTarget() != OBJECT_INVALID
      || GetIsObjectValid(GetNearestSeenEnemy())) return;

    //Guard Check
    int nGuard = GetLocalInt(oNPC,"OAI_GUARD");
    if(nGuard == 1) { OAI_GuardCheck(oNPC); return; }

/******************************************************************************/
//:: TAVERNS / INNS

    object oTavern = GetNearestObjectByTag("NW_TAVERN",oNPC,1);
    string sTag = GetTag(oNPC);

    //Cook Check
    int nCook = GetLocalInt(oNPC,"OAI_COOK");
    if(GetIsObjectValid(oTavern) && nCook == 1) { OAI_Cooks(oNPC); return; }

    //Barmaid Check
    int nBarmaid = GetLocalInt(oNPC,"OAI_BARMAID");
    if(GetIsObjectValid(oTavern) && nBarmaid == 1) { OAI_Barmaid(oNPC); return; }

    //Stripper Check
    int nStripper = GetLocalInt(oNPC,"OAI_STRIPPER");
    if(GetIsObjectValid(oTavern) && nStripper == 1) { OAI_Stripper(oNPC); return; }

    //Bar Chatter Check
    if(GetIsObjectValid(oTavern)
      && sTag != "PackAnimal"
      && sTag != "Horse")
    { OAI_BarChatter(oNPC); return; }

/******************************************************************************/
//:: CUSTOM HB SYSTEMS


    //Custom Scripts you Need to Execute
    ExecuteScript("oai_cust_hb", OBJECT_SELF);


//:: CUSTOM HB SYSTEMS
/******************************************************************************/

    //Trolls
    if(GetBattleCondition(OAI_ROLE_TROLL)) TrollHB();

/******************************************************************************/
//:: SEARCHING

    // No regular hearbeat for a little while if we are searching
    // Searching values over 10 means we are running at the target
    // This section dontinues any search or chase operation we were performing that
    // may have been inturrupted somehow.
    int nSearch = GetLocalInt(OBJECT_SELF, "OAI_SEARCHING");

    // If searching then we need to think about our search
    if(nSearch > 0)
    {
      location oLoc = GetLocalLocation(OBJECT_SELF, "OAI_SEARCH_LOC");

      // Are we close enough to finish our search?
      if (!GetIsObjectValid(GetAreaFromLocation(oLoc))
        || GetDistanceBetweenLocations(GetLocation(OBJECT_SELF), oLoc) < 2.0)
      {
        nSearch = 0;
      }

      //Decrement search count
      else nSearch--;

      //If last round of searching then cancel search
      if(nSearch < 1 || nSearch == 10) DeleteLocalInt(OBJECT_SELF, "OAI_SEARCHING");

      //Falls through to normal hearbeat
      else
      {
        // Make sure we continue the search if not doing anything
        SetLocalInt(OBJECT_SELF, "OAI_SEARCHING", nSearch);
        if(GetCurrentAction() == ACTION_INVALID)
        {
          if(nSearch == 2 || nSearch == 12)
          {
            ActionForceMoveToLocation(oLoc, nSearch > 10, 4.0);
          }
          else
          {
            ActionMoveToLocation(oLoc, nSearch > 10);
            ActionDoCommand(OAI_DetermineCombatRound());
          }
        }
        return;
      }
    }

//:: SEARCHING
/******************************************************************************/

/******************************************************************************/
//:: LIGHT SOURCES

    // Light sources will be wielded at night if all the conditions are met
    //  - if we have one
    //  - we are basically humanoid
    //  - it is night or we are below ground
    //  - the area we are in does not have the "NOTORCH" int set
    object oWeapon;
    int bCheckLightUser;
    switch (GetRacialType(OBJECT_SELF))
    {
        case RACIAL_TYPE_DWARF:
        case RACIAL_TYPE_ELF:
        case RACIAL_TYPE_GNOME:
        case RACIAL_TYPE_HALFELF:
        case RACIAL_TYPE_HALFLING:
        case RACIAL_TYPE_HALFORC:
        case RACIAL_TYPE_HUMAN:
        case RACIAL_TYPE_HUMANOID_GOBLINOID:
        case RACIAL_TYPE_HUMANOID_ORC:
        case RACIAL_TYPE_HUMANOID_REPTILIAN:
            bCheckLightUser = TRUE;
            break;
        default:
            bCheckLightUser = FALSE;
    }

    if(bCheckLightUser)
    {
        int bWeildingLightSource = FALSE;
        oWeapon = GetItemInSlot(INVENTORY_SLOT_LEFTHAND,OBJECT_SELF);

        //Are we wielding a light source right now
        if(GetIsObjectValid(oWeapon))
        {
          bWeildingLightSource = GetModPropertyForItem(oWeapon, PROP_LIGHT, PROPV_LIGHT);
        }

        //If day (and in above ground setting), loose any wielded light source
        if(GetIsDay() && GetIsAreaAboveGround(GetArea(OBJECT_SELF)))
        {
          if(bWeildingLightSource)
          {
            ClearAllActions();
            ActionUnequipItem(oWeapon);
            oWeapon = GetLocalObject(OBJECT_SELF, "OAI_LH_MELEE");

            //Reweild any prior item
            if(GetIsObjectValid(oWeapon)) ActionEquipItem(oWeapon, INVENTORY_SLOT_LEFTHAND);
            return;
          }
        }

        //Try to wield a light source if we have one
        else if(!bWeildingLightSource && d4() == 1 && !GetLocalInt(GetArea(OBJECT_SELF),"NOTORCH"))
        {
          object oLight = GetModItemWithProperty(OBJECT_SELF, PROP_LIGHT, PROPV_LIGHT);

          //Found a Light Source
          if(GetIsObjectValid(oLight))
          {
            ClearAllActions();

            //Existing Something in Left Hand
            if(GetIsObjectValid(oWeapon)) ActionUnequipItem(oWeapon);

            ActionEquipItem(oLight, INVENTORY_SLOT_LEFTHAND);
            return;
          }
        }
    }

//:: LIGHT SOURCES
/******************************************************************************/

/******************************************************************************/
//:: WEAPONS

    //Sheath our weapons if weilded (based on chance to stop all NPCs doing at same time)
    if(d100() <= 50)
    {
      // Unweild weapons if not needed
      oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,OBJECT_SELF);
      if(IsWeapon(oWeapon)) OAI_UnequipWeapons();
    }

//:: WEAPONS
/******************************************************************************/

/******************************************************************************/
//:: BEHAVIOR

    //Here we want to Walk around a bit
    //We need to make sure we have set up our waypoints or not
    //Remember this routine is interupted easily and may not be run yet, so try again
    if(!GetWalkCondition(NW_WALK_FLAG_INITIALIZED))
    {
      WalkWayPoints();
    }
    // dk: special code: not part of OAI. Makes creatures follow assigned leaders
    // with occasional comments voiced in their native tongue (hls_lang)
    else if(GetIsObjectValid(GetLocalObject(OBJECT_SELF, "MyLeader")))
    {
      ExecuteScript("follow_leader", OBJECT_SELF);
    }
    // If we have the 'constant' waypoints flag set, walk to the next
    // waypoint. 0.5% (plus value of 0.1 * CHANCE_SKIPWALK) chance of not waypoint walking
    // The skipping allows way point walkers to occasionally visit shops/toilets and have a break
    else if(GetWalkCondition(NW_WALK_FLAG_CONSTANT)
      && (Random(1000) > GetLocalInt(oNPC, "CHANCE_SKIPWALK") + 4))
    {
      // There is a 15% (plus 5% * value of CHANCE_NOWALK) chance of just standing there
      // These longer the normall pause add a bit of flavour
      if(d20() > GetLocalInt(oNPC, "CHANCE_NOWALK") + 3) WalkWayPoints();
    }

    // This handles special attacking/fleeing behavior
    // for omnivores & herbivores.
    else if(GetBehaviorState(NW_FLAG_BEHAVIOR_OMNIVORE) || GetBehaviorState(NW_FLAG_BEHAVIOR_HERBIVORE))
    {
      OAI_DetermineSpecialBehavior();
    }

    //Now play some Animations
    else if(!IsInConversation(OBJECT_SELF))
    {
      if(GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS)
        || GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS_AVIAN)
        || GetIsEncounterCreature())
      {
        PlayMobileAmbientAnimations();
      }
      else if (GetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS))
      {
        PlayImmobileAmbientAnimations();
      }
    }

//:: BEHAVIOR
/******************************************************************************/

    // Send the user-defined event signal if specified
    // Note Search or Light weild/unweild operations will stop getting here
    // As will certain AIOff situations, so be careful what you use it for.
    if(GetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT))
    {
      SignalEvent(OBJECT_SELF, EventUserDefined(1001));
    }
}