/************************ [On Percieve] ****************************************
    Filename: j_ai_onpercieve or nw_c2_default2
************************* [On Percieve] ****************************************
    If the target is an enemy, attack
    Will determine combat round on that person, is an enemy, basically.
    Includes shouting for a big radius - if the spawn in condition is set to this.

    NOTE: Debug strings in this file will be uncommented for speed by default.
          - It is one of the most intensive scripts as it runs so often.
          - Attempted to optimise as much as possible.
************************* [History] ********************************************
    1.3 - We include j_inc_other_ai to initiate combat (or go into combat again)
                - j_inc_other_ai holds all other needed functions/integers ETC.
        - Turn off hide things.
        - Added "Only attack if attacked"
        - Removed special conversation things. Almost no one uses them, and the taunt system is easier.
        - Should now search around if they move to a dead body, and only once they get there.
************************* [Workings] *******************************************
    It fires:

    - When a creature enters it perception range (Set in creature properties) and
      is seen or heard.
    - When a creature uses invisiblity/leaves the area in the creatures perception
      range
    - When a creature appears suddenly, already in the perception range (not
      the other way round, normally)
    - When a creature moves out of the creatures perception range, and therefore
      becomes unseen.
************************* [Arguments] ******************************************
    Arguments: GetLastPerceived, GetLastPerceptionSeen, GetLastPerceptionHeard,
               GetLastPerceptionVanished, GetLastPerceptionInaudible.
************************* [On Percieve] ***************************************/

#include "j_inc_other_ai"

void main()
{
    // Percieve pre event.
    if(FireUserEvent(AI_FLAG_UDE_PERCIEVE_PRE_EVENT, EVENT_PERCIEVE_PRE_EVENT))
        // We may exit if it fires
        if(ExitFromUDE(EVENT_PERCIEVE_PRE_EVENT)) return;

    // AI status check. Is the AI on?
    if(GetAIOff()) return;
	
	ExecuteScript("prc_npc_percep", OBJECT_SELF);

	if (GetLevelByClass(CLASS_TYPE_COMMONER) > 0)
	{
		ExecuteScript("oai_default2", OBJECT_SELF);
		return;
    }	

    // Declare main things.
    // - We declare OUTSIDE if's JUST IN CASE!
    object oPerceived = GetLastPerceived();
    object oAttackTarget = GetAttackTarget();
    int bSeen = GetLastPerceptionSeen();
    int bHeard = GetLastPerceptionHeard();

    // Need to be valid and not ignorable.
    if(GetIsObjectValid(oPerceived) &&
      !GetIsDM(oPerceived) &&
      !GetIgnore(oPerceived))
    {
        // First, easy enemy checks.
        if(GetIsEnemy(oPerceived) && !GetFactionEqual(oPerceived))
        {
            // Turn of hiding, a timer to activate Hiding in the main file. This is
            // done in each of the events, with the opposition checking seen/heard.
            TurnOffHiding(oPerceived);

            // Well, are we both inaudible and vanished?
            // * the GetLastPerception should only say what specific event has fired!
            if(GetLastPerceptionInaudible() || GetLastPerceptionVanished())
            {
                // If they just became invisible because of the spell
                // invisiblity, or improved invisiblity...we set a local object.
                // - Beta: Added in ethereal as well.
                if(GetHasEffect(EFFECT_TYPE_INVISIBILITY, oPerceived) ||
                   GetHasEffect(EFFECT_TYPE_ETHEREAL, oPerceived) ||
                   GetStealthMode(oPerceived) == STEALTH_MODE_ACTIVATED)
                {
                    // Set object, AND the location they went invisible!
                    SetAIObject(AI_LAST_TO_GO_INVISIBLE, oPerceived);
                    // We also set thier location for AOE dispelling - same name
                    SetLocalLocation(OBJECT_SELF, AI_LAST_TO_GO_INVISIBLE, GetLocation(oPerceived));
                }

                // If they were our target, follow! >:-D
                // - Optional, on spawn option, for following through areas.
                if(oAttackTarget == oPerceived)
                {
                    // This means they have exited the area! follow!
                    if(GetArea(oPerceived) != GetArea(OBJECT_SELF))
                    {
                        ClearAllActions();
                        // 51: "[Perception] Our Enemy Target changed areas. Stopping, moving too...and attack... [Percieved] " + GetName(oPerceived)
                        DebugActionSpeakByInt(51, oPerceived);
                        // Call to stop silly moving to enemies if we are fleeing
                        ActionMoveToEnemy(oPerceived);
                    }
                    // - Added check for not casting a spell. If we are, we finnish
                    //  (EG: AOE spell) and automatically carry on.
                    else if(GetCurrentAction() != ACTION_CASTSPELL)
                    {
                        ClearAllActions();
                        // 52: "[Perception] Enemy Vanished (Same area) Retargeting/Searching [Percieved] " + GetName(oPerceived)
                        DebugActionSpeakByInt(52, oPerceived);
                        DetermineCombatRound(oPerceived);
                    }
                }
            }// End if just gone out of perception
            // ELSE they have been SEEN or HEARD. We don't check specifics.
            else //if(bSeen || bHeard)
            {
                // If they have been made seen, and they are our attack target,
                // we must re-do combat round - unless we are casting a spell.
                if(bSeen && GetCurrentAction() != ACTION_CASTSPELL &&
                  (oAttackTarget == oPerceived || !GetObjectSeen(oAttackTarget)))
                {
                    AISpeakString(I_WAS_ATTACKED);
                    // 53: "[Perception] Enemy seen, and was old enemy/cannot see current. Re-evaluating (no spell) [Percieved] " + GetName(oPerceived)
                    DebugActionSpeakByInt(53, oPerceived);
                    DetermineCombatRound(oPerceived);
                }
                // Else We check if we are already attacking.
                else if(!CannotPerformCombatRound() &&
                        !GetSpawnInCondition(AI_FLAG_OTHER_ONLY_ATTACK_IF_ATTACKED, AI_OTHER_MASTER))
                {
                    // Special shout, d1000 though!
                    SpeakArrayString(AI_TALK_ON_PERCIEVE_ENEMY, TRUE);

                    // Stop stuff because of facing point - New enemy
                    HideOrClear();

                    // Face the person (this helps stops sneak attacks if we then
                    // cast something on ourselves, ETC).
                    SetFacingPoint(GetPosition(oPerceived));

                    // Get all allies in 60M to come to thier aid. Talkvolume silent
                    // shout does not seem to work well.
                    // - void function. Checks for the spawn int. in it.
                    // - Turns it off in it too
                    // - Variable range On Spawn
                    ShoutBossShout(oPerceived);

                    // Warn others
                    AISpeakString(I_WAS_ATTACKED);
                    // 54: "[Perception] Enemy Seen. Not in combat, attacking. [Percieved] " + GetName(oPerceived)
                    DebugActionSpeakByInt(54, oPerceived);
                    // Note: added ActionDoCommand, so that SetFacingPoint is not
                    // interrupted.
                    ActionDoCommand(DetermineCombatRound(oPerceived));
                }
            }
        }
        // Else, they are an equal faction, or not an enemy (or both)
        else
        {
            // If they are dead, say we saw something on waypoints, we charge in
            // to investigate.
            // * Higher intelligence will buff somewhat as well!
            if(GetIsDead(oPerceived) && (bSeen || bHeard))
            {
                // Warn others
                AISpeakString(I_WAS_ATTACKED);
                // Check if we can attack
                if(!CannotPerformCombatRound())
                {
                    // Hide or clear actions
                    HideOrClear();
                    // 55: "[Perception] Percieved Dead Friend! Moving and Searching [Percieved] " + GetName(oPerceived)
                    DebugActionSpeakByInt(55, oPerceived);
                    ActionMoveToLocation(GetLocation(oPerceived), TRUE);
                    ActionDoCommand(DetermineCombatRound());
                }
            }
            else if(GetIsInCombat(oPerceived) && (bSeen || bHeard))
            {
                // Warn others
                AISpeakString(I_WAS_ATTACKED);
                // Only if we can attack.
                if(!CannotPerformCombatRound())
                {
                    // Hide or clear actions
                    HideOrClear();
                    // 56: "[Perception] Percieved Alive Fighting Friend! Moving to and attacking. [Percieved] " + GetName(oPerceived)
                    DebugActionSpeakByInt(56, oPerceived);
                    ActionMoveToLocation(GetLocation(oPerceived), TRUE);
                    ActionDoCommand(DetermineCombatRound());
                }
            }
        }
    }

    // Fire End of Percieve event
    FireUserEvent(AI_FLAG_UDE_PERCIEVE_EVENT, EVENT_PERCIEVE_EVENT);
}