/******************************************************************
  
  Module:  Intel.h
  
  Author: Sean Craig
  
  Description:   Classes for deciding what a game character should
  do, either through AI, controller input or network update

  
  Copyright 2005 Sony Online Entertainment.  All rights reserved.
  
*******************************************************************/

#ifndef INTEL_H
#define INTEL_H

//-------------------------------------------------------- Includes
#include <stddef.h>
#include "SyPropObject.h"
#include "gameobj.h"
#include "ai.h"
#include "animdefs.h"
#include "TitanI.h"
#include "SyArray.h"
//-------------------------------------------------------- Typedefs
//---------------------------------------------- Class Declarations


class cIntel: public SyPropObject
{
public:
  cIntel();
  virtual ~cIntel(){};                

  /* Property Class Support */
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID        =  0xFFFF1001;

  // public interface

  virtual void Init(){};
  virtual void Exit(){};
  virtual void Reset(){};

  virtual void Open(){};

  void SetOwner(cGameObject *owner){mOwner = owner;};
  virtual void Update(float time)=0;

  virtual tGameObjectID PickAttackTarget(eComboType combo){return ID_NONE;};
  virtual tGameObjectID PickAttackTarget(float dir, float max_distance, float max_angle) {return ID_NONE;}
  virtual tGameObjectID PickAttackTargetRanged(){return ID_NONE;};
  virtual tGameObjectID PickActionTarget(){return ID_NONE;};

  virtual bool IsSpawned() { return true; }

  virtual void          OnHit(tGameObjectID attacker, int damage, float recoveryTime, bool bRanged){};
  virtual void          OnDeath() {};
  virtual void          OnWallCollision(const SyVect3& normal) {};

  virtual bool          IsTargetable(cGameObject* pTarget) {return true;}
  virtual bool          IsFriendly(cGameObject* pTarget) {return false;}

  virtual void          EnterScope() {}   // called when object comes inside update scope radius
  virtual void          ExitScope() {}  // called when object leaves update scope radius
  virtual void          OnLoseOwnership() {}  // called when object is being transfered across the network
  virtual void          OnGainOwnership() {}  // called when object is being given to us across the network

  cGameObject*          FindClosestObject(float minDist, float maxDist, 
                                          bool bIsNPC, bool bIsPlayer, bool bIsProp,
                                          bool bIsFriendly = false,
                                          bool bIsDamaged = false,
                                          bool bIsDead = false);

protected:

  cGameObject       *mOwner;
};


class cIntelEntity : public cIntel
{
public:
  cIntelEntity();

  /* Property Class Support */
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID  =  0xFFFF1002;

  virtual void          Init();
  virtual void          Reset(); // for example, when respawning
  virtual void          Update(float time){};

  virtual tGameObjectID PickAttackTarget(float dir, float max_distance, float max_angle);
  virtual tGameObjectID PickActionTargetDir(float dir);

  virtual const SyVect3 &GetStartLocation(){return mStartLocation;};
  virtual void          SetStartLocation(const SyVect3& loc);
  virtual void          SetStartHeading(float heading);

  virtual bool          IsTargetable(cGameObject* pTarget);
  virtual bool          IsFriendly(cGameObject* pTarget);

  static void           RegisterTuningVariables();

protected:
  void                  CheckWater();


  SyVect3               mStartLocation; 
  float                 mStartHeading;
  int                   mLastWaterType;
};

class cAbilityMaster;

class cIntelPlayer: public cIntelEntity
{
public:
  cIntelPlayer(); 
  virtual ~cIntelPlayer(){};

  /* Property Class Support */
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID  =  0xFFFF1003;

  void                 SetControllerID(int controllerID){mControllerID = controllerID;};
  int                  GetControllerID(){return mControllerID;};

  // public interface
  virtual void          Update(float time);
  virtual void          Reset(); // for example, when respawning

  virtual tGameObjectID PickAttackTarget(eComboType combo);
  virtual tGameObjectID PickActionTarget() { return mActionTarget;};
  virtual tGameObjectID PickAttackTargetRanged();

  float                GetControllerHeading(float time);
  float                GetControllerMagnitude();

  float                GetRightControllerHeading(float time);
  float                GetRightControllerMagnitude();

  void                 UpdateActionTarget(float time);
  void                 UpdateCamera(float time);

  void                 StartRangedAttack();
  void                 CancelRangedAttack();
  void                 EndRangedAttack();

  void                 StartSpellCast(tGameID spellID);
  void                 EndSpellCast();

  void                  MapAbility(TitanButton tb, const cAbilityMaster* pAbility);
  const cAbilityMaster* GetMappedAbility(TitanButton tb);
  void                  AutoMapAbility(const cAbilityMaster* pAbility);
  void                  RemoveMappedAbility(const cAbilityMaster* pAbility);

  static void RegisterTuningVariables();

  bool                  GetStoredRemoteFlag() { return mbRemote; }
  virtual void          OnLoseOwnership();
  virtual void          OnGainOwnership();

protected:
  float                _ControllerHeading(float time, float forward, float right, float* pPrevHeading, float* pHeldDownTime);
  float                _ControllerMagnitude(float forward, float right, float* pHeldDownTime);

  static float  mDeadZone; // dead zone in center of controller, as a fraction

  static float  smLeftStickTapHigh; 
  static float  smLeftStickTapLow; 
  static float  smLeftStickTapMaxTime;
  static float  smLeftStickTapDelayBetween; 


  int           mControllerID; // which controller controls this player (if local)
  bool          mbRemote;
  float         mLeftStickHeldDownTime;
  float         mLeftStickPrevMag;
  float         mLeftStickHighMagTime;
  float         mLeftStickTapHeading;
  float         mLeftStickTimeSinceTap;
  float         mRightStickHeldDownTime;
  float         mLeftStickPrevHeading;
  float         mRightStickPrevHeading;
  tGameObjectID mActionTarget;
  float         mAmbientMotion;
  SyVect3       mPrevLocation;
  SyVect3       mPrevRHandLoc;
  SyVect3       mPrevLHandLoc;

  bool          mbSelectAttackTarget;
  float         mSelectAttackTargetTime;
  tGameID       mSelectAttackSpellID;
  tGameObjectID mSelectAttackTargetID;
  SyVect3       mSelectAttackLocation;
  float         mTimeSinceSpellCast;


  SyArray<uint32> mMappedAbilityIDs;  
  SyArray<uint32> mMappedAbilityRanks;
};


class cIntelNPC: public cIntelEntity
{
public:
  cIntelNPC();
  virtual ~cIntelNPC();
  /* Property Class Support */
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID     =  0xFFFF1004;

  // public interface
  virtual void          Init();
  virtual void          Exit();
  virtual void          Reset();
  virtual bool IsSpawned() { return mbSpawned; }

  void                  TurnTo(const SyVect3 &lookAt);
  void                  GoTo(const SyVect3 &dest, float speed = 0.75f, bool bKeepFacing = false, float faceHeading = 0.0f);
  bool                  AttackMelee(cGameObject *target, eComboType combo);
  void                  AttackRanged(cGameObject *target);
  void                  AttackRanged(float heading, float pitch, float range);
  void                  Stop();
  void                  Block(float blockTime);
  void                  Jump();
  void                  Dodge(const SyVect3& dir);

  virtual void          Update(float time);
  virtual void          OnHit(tGameObjectID attacker, int damage, float recoveryTime, bool bRanged);
  virtual void          OnWallCollision(const SyVect3& normal);
  virtual void          OnDeath();

  bool                  IsMoving();
  bool                  IsAvoiding();

  cAiInterface*         GetAi() { return mAi; }
  float                 GetSpawnRadius() { return mSpawnRadius; }
  float                 GetSpawnChainRadius() { return mSpawnChainRadius; }
  const SyString&       GetSpawnParent() { return mSpawnParent; }
  void                  SetSpawned(bool bSpawned);

  static void RegisterTuningVariables();

  virtual void          EnterScope();   // called when object comes inside update scope radius
  virtual void          ExitScope();  // called when object leaves update scope radius
  virtual void          OnLoseOwnership();  // called when object is being transfered across the network
  virtual void          OnGainOwnership();  // called when object is being given to us across the network

protected:
  void                  UpdateMove(float time);
  void                  UpdateBlock(float time);
  void                  CalcAvoidDir(const SyVect3& hitNormal);
  void                  RequestLOSToGoal();

  cAiInterface         *mAi;

  // keep track of movement requests
  bool                  mbIsMoving;
  SyVect3               mGoalPos;
  float                 mMoveSpeed;

  // keep track of obstacle avoidance while moving
  bool                  mbIsAvoiding;
  bool                  mbHasLOSToGoal;
  SyVect3               mAvoidDir;
  int                   mLOSTicketToGoal;
  float                 mAvoidTimer;

  bool                  mbIsStuck;
  float                 mStuckTimer;
  SyVect3               mPrevLocation;
  bool                  mbStuckAvoid;

  int                   mLOSTicketLedgeTest;
  bool                  mbHitLedge;

  float                 mBlockTimer;

  float                 mSpawnRadius;
  float                 mSpawnChainRadius;
  SyString              mSpawnParent;
  bool                  mbSpawned;
};
 

class cIntelNone: public cIntel
{
public:
  cIntelNone();
  virtual ~cIntelNone(){};

  /* Property Class Support */
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID    =  0xFFFF1005;

  // public interface


  virtual void Update(float time);
};

class cIntelProp: public cIntel
{
public:
  cIntelProp();
  virtual ~cIntelProp(){};

  /* Property Class Support */
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID    =  0xFFFF1006;

  // public interface
  virtual void Update(float time);
  virtual void Activate();
  virtual void Deactivate();
  virtual bool IsOn(){return mbOn;};

  virtual bool IsTargetable(cGameObject* pTarget);
  virtual bool IsFriendly(cGameObject* pTarget);

  virtual void OnHit(tGameObjectID attacker, int damage, float recoveryTime, bool bRanged);
  virtual void OnDeath();
  virtual void PlayAnim(int index);
private:
  bool mbOn;
};

class cIntelProjectile: public cIntelEntity
{
public:
  cIntelProjectile();
  virtual ~cIntelProjectile(){};

  /* Property Class Support */
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID =  0xFFFF1007;

  // public interface
  virtual void Update(float time);

  void SetTarget(tGameObjectID);

  virtual bool          IsTargetable(cGameObject* pTarget);

private:
  tGameObjectID mTargetID;
  float         mWave;
};

//------------------------------------------- Function Declarations

void RegPropClasses_Intel();
void Intel_RegisterTuningVariables();
//--------------------------------------------------------- Globals
//------------------------------------------------ Inline Functions

#endif
