/******************************************************************
  
  Module:  physics.h
  
  Author: Sean Craig
  
  Description: Classes responsible for moving objects through the 
  world and colliding them with the rest of the world.  Velocities
  can be set from an animation or forces in the world. 

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

#ifndef PHYSICS_H
#define PHYSICS_H

//-------------------------------------------------------- Includes
#include "SyPropObject.h"
#include "SyCollSurfType.h"
#include "gameobj.h"
#include "rulepacket.h"

//-------------------------------------------------------- Typedefs
//---------------------------------------------- Class Declarations
class cGameObject;
class SyScene;
class SyCollSphere;


class cPhysics : public SyPropObject
{
public:
  typedef enum _eLocomotionMethod
  {
    LOCO_ANIMATION,
    LOCO_JUMP,
    LOCO_PUSHED,
    LOCO_PROJECTILE,
    LOCO_CUTSCENE
  } eLocomotionMethod;

  static const float GRAVITY;

  cPhysics();
  virtual ~cPhysics(){};

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


  // public interface

  virtual void Init();
  virtual void Exit(){};
  virtual void Reset(){};
  virtual void Update(float time){};
  virtual bool CheckForDelete(){return false;}; // this is the ONLY place where objects can delete themselves.

  virtual const SyVect3 &GetVelocity();
  virtual void SetVelocity(const SyVect3& velocity);

  void SetOwner(cGameObject *);
  void SetCollideable(bool collide);
  virtual float GetCollisionRadius(){return 0.0f;};

  virtual eLocomotionMethod GetLocomotion(){return LOCO_PUSHED;};

  virtual void NetworkSetLocation(const SyVect3 &location);
  virtual void NetworkSetHeading(float heading);
  virtual void NetworkSetVelocity(const SyVect3 &velocity){};


  virtual const SyVect3 &GetRenderLocation();
  virtual float          GetRenderHeading();
  
  virtual bool           SetSafeLocation(const SyVect3 &loc); // finds a safe location near this spot

  virtual void           Knockback(const SyVect3 &source_loc,float XZamount,float Yamount){};
protected:
  bool               mCollideable;
  cGameObject       *mOwner;
};


class cPhysicsStatic : public cPhysics
{
public:
  cPhysicsStatic();
  /* Property Class Support */
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID       =  0xFFFF5002;


  // public interface

};

// moving objects (such as game items)
class cPhysicsDynamic : public cPhysics
{
public:
  cPhysicsDynamic();
  /* Property Class Support */
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID      =  0xFFFF5007;

  bool                 Push(float time,SyVect3 &displacement);
  virtual void         Update(float time);
  void                 SetVelocity(const SyVect3 &velocity);

  int                  CalcFloor( SyVect3&        Point, 
    SyScene&        Scene, 
    SyVect3&        Floor, 
    SyVect3&        FloorNormal,
    SyCollSurfType& FloorSurfaceType ,
    float           radius,
    float           height);

protected:

  virtual void         CollisionTest(float time,SyVect3 &displacement);
  bool                 mIsMoving;
  SyVect3              mVelocity;

};

// barrels, sometimes immoveable things
class cPhysicsProp : public cPhysicsDynamic
{
public:
  cPhysicsProp();
  /* Property Class Support */
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID         =  0xFFFF5006;


protected:
  virtual void         CollisionTest(float time,SyVect3 &displacement);

};

class cPhysicsAnimated : public cPhysicsDynamic
{
public:

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


  
  // public interface
  virtual void Init();
  virtual void  Update(float time);
  virtual float GetCollisionRadius(){return mCollisionRadius;};
  virtual void Reset();
  virtual void Jump(const SyVect3 &force);
  virtual void Impulse(const SyVect3 &force);
  virtual const SyVect3 &GetVelocity() {return mVelocity;};
  virtual eLocomotionMethod GetLocomotion(){return meLocomotion;};
          void SetLocomotion(eLocomotionMethod eLM){meLocomotion = eLM;};

  virtual void NetworkSetLocation(const SyVect3 &location);
  virtual void NetworkSetVelocity(const SyVect3 &velocity){mVelocity = velocity;};

  virtual const SyVect3 &GetRenderLocation(){return mRenderLocation;};
  virtual float          GetRenderHeading(){return mRenderHeading;};

  virtual bool           IsPushing(){return mPushing;};
  virtual cGameObject*   GetPushingTarget(){return mPushingTarget;};



  virtual bool           SetSafeLocation(const SyVect3 &loc); // finds a safe location near this spot
  virtual void           Knockback(const SyVect3 &source_loc,float XZamount,float Yamount);

protected:

  virtual void         CollisionTest(float time,SyVect3 &displacement);
          bool         CheckLocation(const SyVect3 &loc);
          void         _CollisionTestWorld(float time, SyVect3 &Start,SyVect3 &End);
          bool         PushTarget(float time, SyVect3 &destination,SyCollSphere &CollSphere);


          int                  CalcFloor( SyVect3&        Point, 
    SyScene&        Scene, 
    SyVect3&        Floor, 
    SyVect3&        FloorNormal,
    SyCollSurfType& FloorSurfaceType);

  eLocomotionMethod    meLocomotion;
  float32              mCollisionHeight;
  float32              mCollisionRadius;
  float32              mHeight;               // The height of the character in meters
  float32              mFloorCollRadius;     // Radius of collision sphere used during floor/ceiling checks
  float32              mMinStepSize;              // Minimum distance to step up or down
  float32              mMaxStepSize;              // Maximum distance to step up or down
  SyVect3              mVelocity;
  SyVect3              mJumpStartVel;
  SyVect3              mJumpPushVel;
  bool                 mPushing;  // true if we're currently pushing up against with something (forces a walk)
  cGameObject*         mPushingTarget;

  // network variables

  SyVect3              mRenderLocation;
  SyVect3              mRenderOffset;
  float                mRenderHeading;

  float                mNetworkUpdateTime;
  int                  mRecursionDepth;

};

class cPhysicsProjectile : public cPhysics
{
public:
  cPhysicsProjectile();
  /* Property Class Support */
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID   =  0xFFFF5005;


  virtual void Update(float time);
  virtual eLocomotionMethod GetLocomotion(){return LOCO_PROJECTILE;};
  virtual bool CheckForDelete(); // this is the ONLY place where objects can delete themselves.

  virtual const SyVect3 &GetVelocity() { return mVelocity; }
  virtual void SetVelocity(const SyVect3& velocity) { mVelocity = velocity; }

  void Launch(cGameObject *src,const SyVect3 &target);
  tGameObjectID GetSourceID() { return mSourceID; }
 
  static void Shoot(tGameID projectileMasterID, cGameObject* pOwner, const SyVect3& targetPos, cGameObject* pTarget = NULL);

protected:

  void                 CollisionTest(float time,SyVect3 &displacement);
  int                  CalcFloor( SyVect3&        Point, 
                                  SyScene&        Scene, 
                                  SyVect3&        Floor, 
                                  SyVect3&        FloorNormal,
                                  SyCollSurfType& FloorSurfaceType );

protected:
  tGameObjectID        mSourceID;
  SyVect3              mVelocity;
  bool                 mGravity;
  float                mAge; // to expire old projectiles
  bool                 mHitGround;
  float                mHeadingTowards; // towards target
  cGameObject         *mLastHit; // last entity hit, to prevent multiple hits 
  cDamagePacket        mDmgPacket;
};

//------------------------------------------- Function Declarations
void RegPropClasses_Physics();
//--------------------------------------------------------- Globals
//------------------------------------------------ Inline Functions

#endif
