/******************************************************************
  
  Module:  areaeffect.h
  
  Author: Sean Craig
  
  Description:  System for active spells and explosions with area 
  effects.
  
  Copyright 2005 Sony Online Entertainment.  All rights reserved.
  
*******************************************************************/

#ifndef AREAEFFECT_H
#define AREAEFFECT_H

//-------------------------------------------------------- Includes

#include "gameobj.h"
#include "rulepacket.h"
#include "SyEmbeddedList.h"

//-------------------------------------------------------- Typedefs
//---------------------------------------------- Class Declarations
class Titan;


class cAreaEffect;

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

          void  SetOwner(cAreaEffect * owner){mpOwner = owner;};
  virtual bool  OnEnter(tGameObjectID id) { return true; }; // true if effect works on this target
  virtual void  Update(float time){}; // global 
  virtual void  Update(tGameObjectID id,float time){}; // victim-specific
  virtual void  OnExit(tGameObjectID id){};
  virtual void  ProcessPacket(cRulePacket* packet) {}

  void  SetSource(tGameObjectID source) { mSource = source; };
  void  SetPercentChance(int chance)  { mPercentChance = chance; }
  void  SetTargetRace(tGameID race) { mTargetRace = race; };

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static const int     mCLASSID        =  0xFFFFB001;

  static const SyPropID PropId_SourceID       = 0x0000;
  static const SyPropID PropId_PercentChance  = 0x0001;
  static const SyPropID PropId_TargetRace     = 0x0002;

protected:
  bool TargetHasBlocked(cGameObject* pTarget);
  bool TargetMatchesRace(cGameObject* pTarget);

  tGameObjectID     mSource;
  cAreaEffect      *mpOwner;
  int               mPercentChance;
  tGameID           mTargetRace;
};

class cGameEffect_ScriptCall : public cGameEffect
{
public:
  cGameEffect_ScriptCall();

  void SetOwner(tGameObjectID id) {mOwner = id;};
  virtual bool  OnEnter(tGameObjectID id);
  virtual void  OnExit(tGameObjectID id);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID        =  0xFFFFB002;

  static const SyPropID PropId_OwnerID       = 0x1000;

protected:
  tGameObjectID     mOwner;
};

class cGameEffect_Damage : public cGameEffect
{
public:
  cGameEffect_Damage();

  void  SetDamage(int damage,eDamageType damageType);
  
  virtual bool  OnEnter(tGameObjectID id);
  virtual void  Update(float time);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID        =  0xFFFFB003;

  static const SyPropID PropId_Damage       = 0x1000;
  static const SyPropID PropId_DamageType   = 0x1001;

protected:
  int               mDamage;
  eDamageType       mDamageType;
};

class cGameEffect_Heal : public cGameEffect
{
public:
  cGameEffect_Heal();

          void  SetHealing(int amount, bool bIsPctMaxHealth = false);
  virtual bool  OnEnter(tGameObjectID id);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID        =  0xFFFFB004;

  static const SyPropID PropId_Healing      = 0x1000;
  static const SyPropID PropId_IsPctMaxHealth = 0x1001;

protected:
  int     mHealing;
  bool    mbIsPctMaxHealth;
};

class cGameEffect_ManaCost : public cGameEffect
{
public:
  cGameEffect_ManaCost();
  
          void  SetCost(int damage, bool bIsPctMaxMana = false);
  virtual bool  OnEnter(tGameObjectID id);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID          =  0xFFFFB005;

  static const SyPropID PropId_Cost      = 0x1000;
  static const SyPropID PropId_IsPctMaxMana = 0x1001;

protected:
  int    mCost;
  bool   mbIsPctMaxMana;
};

class cGameEffect_Kill : public cGameEffect
{
public:
  cGameEffect_Kill();

  virtual bool  OnEnter(tGameObjectID id);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID          =  0xFFFFB006;
protected:
};


class cGameEffect_Attack : public cGameEffect
{
public:
  cGameEffect_Attack();

          void  SetAttackIndex(int index){mAttackIndex = index;};
  virtual bool  OnEnter(tGameObjectID id);
  virtual void  Update(float time);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID             =  0xFFFFB007;

  static const SyPropID PropId_AttackIndex  = 0x1000;

protected:
  int               mAttackIndex;
};

class cGameEffect_Knockback : public cGameEffect
{
public:
  cGameEffect_Knockback();

  void  SetLocation(const SyVect3 &location) {mLocation= location;};
  void  SetAmount(float xz,float y){mXZAmount = xz;mYAmount = y;};
  void  SetKnockdown(bool bKnockdown, float time) {mbKnockdown = bKnockdown; mKnockdownTime = time;}

  virtual bool  OnEnter(tGameObjectID id);
  virtual void  Update(float time);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID             =  0xFFFFB008;

  static const SyPropID PropId_Location     = 0x1000;
  static const SyPropID PropId_XZAmount     = 0x1001;
  static const SyPropID PropId_YAmount      = 0x1002;
  static const SyPropID PropId_Knockdown    = 0x1003;
  static const SyPropID PropId_KnockdownTime = 0x1004;

protected:

  SyVect3           mLocation;
  float             mXZAmount;
  float             mYAmount;
  bool              mbKnockdown;
  float             mKnockdownTime;
};

class cGameEffect_Vortex : public cGameEffect
{
public:
  cGameEffect_Vortex();

  void  SetLocation(const SyVect3 &location) {mLocation= location;};
  void  SetSpeed(float speed){mSpeed = speed;};

  virtual void  Update(tGameObjectID id,float time);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID             =  0xFFFFB009;

  static const SyPropID PropId_Location     = 0x1000;
  static const SyPropID PropId_Speed        = 0x1001;

protected:
  SyVect3           mLocation;
  float             mSpeed;
};

class cGameEffect_AddCondition : public cGameEffect
{
public:
  cGameEffect_AddCondition();

          void  SetCondition(const char* name,
                             tGameID spellID,
                             tGameID mItemMasterID,
                             bool bAreaOnly, 
                             float duration,
                             tGameID effectID,
                             int strength,
                             int param = 0);

  virtual bool  OnEnter(tGameObjectID id);
  virtual void  OnExit(tGameObjectID id);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID              =  0xFFFFB00A;

  static const SyPropID PropId_ConditionName = 0x1000;
  static const SyPropID PropId_SpellID       = 0x1001;
  static const SyPropID PropId_Duration      = 0x1002;
  static const SyPropID PropId_EffectID      = 0x1003;
  static const SyPropID PropId_Strength      = 0x1004;
  static const SyPropID PropId_Param         = 0x1005;
  static const SyPropID PropId_AreaOnly      = 0x1006;
  static const SyPropID PropId_ItemMasterID  = 0x1007;

protected:
  SyString mConditionName;
  tGameID mSpellID;
  float mDuration;
  tGameID mEffectID;
  int mStrength;
  int mParam;
  bool mbAreaOnly;
  tGameID mItemMasterID;
};

// this 'wakes up' physics so that crates staked on other crates know to fall, for example.
class cGameEffect_Nudge : public cGameEffect
{
public:
  cGameEffect_Nudge();

  virtual bool  OnEnter(tGameObjectID id);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID        =  0xFFFFB00B;

protected:
};

class cGameEffect_Resurrect : public cGameEffect
{
public:
  cGameEffect_Resurrect();

  virtual bool  OnEnter(tGameObjectID id);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID          =  0xFFFFB00D;
protected:
};

// this levitates debris
class cGameEffect_Levitate : public cGameEffect  
{
public:
  cGameEffect_Levitate();

  virtual void  Update(float time); // global 

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID        =  0xFFFFB00E;

  static const SyPropID PropId_LevitateID  = 0x0001;

protected:

  int               mLevitateID;
};


class cGameEffect_CastSpell : public cGameEffect
{
public:
  cGameEffect_CastSpell();

  void  SetSpell(tGameID spellID) { mSpellID = spellID; }
  virtual bool  OnEnter(tGameObjectID id);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID              =  0xFFFFB00F;

  static const SyPropID PropId_SpellID       = 0x1000;

protected:
  tGameID mSpellID;
};

class cGameEffect_AddEssence : public cGameEffect
{
public:
  cGameEffect_AddEssence();

  void  SetAmount(int amount) { mAmt = amount; }
  virtual bool  OnEnter(tGameObjectID id);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID          =  0xFFFFB010;

  static const SyPropID PropId_Amt      = 0x1000;

protected:
  int               mAmt;
};

//----------------------------------------------------------Area Effects

typedef tGameID tEffectID;

class cAreaEffect : public SyPropObject
{
public:
  cAreaEffect(); 
  virtual ~cAreaEffect();

  virtual void Update(float time);
  virtual bool IsExpired();
  virtual bool IsLineOfSightBlocked(const SyVect3& start, const SyVect3& end, SyVect3& hit) { return false; }

          void AddGameEffect(cGameEffect *effect);
          void SetSource(tGameObjectID id) {mSource = id;};
          void SetSpellID(tGameID id) {mSpellID = id;};
          void SetDuration(float t) { mDuration = t; }
          float GetDuration() { return mDuration; }
          void ProcessPacket(cRulePacket *packet);

          tEffectID GetID() const {return mID;};                 
          void      SetID(tEffectID id){mID = id;};

          tGameObjectID GetSource() { return mSource; };
          tGameID GetSpellID() { return mSpellID; };

  virtual bool IgnoreSource()   {return mbIgnoreSource;}
          void SetIgnoreSource(bool bIgnore)  {mbIgnoreSource = bIgnore;}

          void Explosion(); // knock back debris; called from effectm calls virtual DoExplosion

  virtual void DoExplosion(tGameID debrisFXID){}; 
  virtual void Levitate(){}; // levitate debris; called from effect 

  void SetMaxTargets(int numTargets) { mMaxTargets = numTargets; }
  void SetMovesWithObject(tGameObjectID id, float forwardOffset = 0.0f);
  virtual void SetAINegativeAreaEffect(bool bNotifyAI) {}

  void SetTerminateOnSourceDeath(bool bTerminate) { mbTerminateOnSourceDeath = bTerminate; }
  void ExitAll();

  enum EffectTargetFaction
  {
    EFFECT_FACTION_ANY,
    EFFECT_FACTION_ALLIES, // players and friendly NPCs
    EFFECT_FACTION_ALLIES_AND_PROPS, // players and friendly NPCs and damageable props
    EFFECT_FACTION_PLAYERS,
    EFFECT_FACTION_MONSTERS,
    EFFECT_FACTION_MONSTERS_AND_PROPS, // unfriendly NPCs and damageable props
    EFFECT_FACTION_CHARACTERS, // don't test props
  };

  void SetEffectTargetFaction(EffectTargetFaction e) {mEffectTargets = e;}

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static const int     mCLASSID          =  0xFFFFAA01;

  static const SyPropID PropId_Included  = 0x0000;
  static const SyPropID PropId_Effects   = 0x0001;
  static const SyPropID PropId_Source    = 0x0002;
  static const SyPropID PropId_SpellID   = 0x0003;
  static const SyPropID PropId_EffectTargets = 0x0004;
  static const SyPropID PropId_ID        = 0x0005;
  static const SyPropID PropId_Duration  = 0x0006;
  static const SyPropID PropId_TerminateOnSourceDeath = 0x0007;
  static const SyPropID PropId_IgnoreSource = 0x0008;
  static const SyPropID PropId_MaxTargets   = 0x0009;
  static const SyPropID PropId_MovesWithObject  = 0x000A;
  static const SyPropID PropId_MovesWithForwardOffset  = 0x000B;
  static const SyPropID PropId_Explosion = 0x000C;

          void  UpdateExtents();
          float GetMinX(){return mMinX;};
          float GetMaxX(){return mMaxX;};

          void  AddObject(cGameObject *obj);
          void  AddAllOpenObjects();
          void  UpdateIncluded(float time);
          void MarkForDelete() { mbMarkedForDelete = true; }
          bool IsMarkedForDelete() { return mbMarkedForDelete; }

protected:



  virtual bool  IsIncluded(cGameObject *obj);
  virtual bool  IsInside(cGameObject *obj)=0;
  virtual bool  IsTargetedFaction(cGameObject *obj);
  virtual void  UpdateMovesWithObject() {}
          void  OnEnter(cGameObject* obj); 
          void  OnExit(cGameObject* obj); 
          void  UpdateEffect(cGameObject* obj,float time);
          void  PlayImpactFX(cGameObject* obj);

  virtual SyVect3 GetCenter()=0;
  virtual float GetRadius()=0;

  SyVector<tGameObjectID>  mIncluded;
  SyVector<cGameEffect *>  mEffects;
  tGameObjectID            mSource;
  tGameID                  mSpellID;
  EffectTargetFaction      mEffectTargets;
  tEffectID                mID;
  float                    mDuration;
  int                      mLevitationID;
  int                      mMaxTargets;
  bool                     mbTerminateOnSourceDeath;
  bool                     mbIgnoreSource;
  bool                     mbExplodedThisFrame;
  bool                     mbMarkedForDelete;
  tGameObjectID            mMovesWithObject;
  float                    mMovesWithFwdOffset;
  float                    mBirthtime;
  int                      mFXHandle;

  float                    mMinX;
  float                    mMaxX;

public:
  SyEmbeddedListLink<cAreaEffect> mMaxXLink;  // link to other objects of the same time 
  SyEmbeddedListLink<cAreaEffect> mMinXLink;  // link to other objects of the same time 
  SyEmbeddedListLink<cAreaEffect> mOpenLink;  // link to other objects of the same time 
};

class cAreaEffect_SingleTarget  : public cAreaEffect
{
public:
  cAreaEffect_SingleTarget();

  virtual void  Update(float time);
  virtual bool  IgnoreSource()   {return false;}
  void          SetTarget(tGameObjectID id) {mTargetID = id;};

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID          =  0xFFFFAA02;

  static const SyPropID PropId_TargetID  = 0x1000;

protected:
  virtual bool  IsInside(cGameObject *obj);
  virtual SyVect3 GetCenter(){return SyVect3(0,0,0);};
  virtual float  GetRadius(){return -1.0f;};

  tGameObjectID   mTargetID;
};

class cAreaEffect_Radius  : public cAreaEffect
{
public:
  cAreaEffect_Radius();
  virtual ~cAreaEffect_Radius();

  void          SetLocation(const SyVect3  &loc){mLocation = loc;};
  void          SetRadius(float radius){mRadius= radius;};
  virtual void  SetAINegativeAreaEffect(bool bNotifyAI);
  virtual bool  IsLineOfSightBlocked(const SyVect3& start, const SyVect3& end, SyVect3& hit);

  virtual void  Update(float time);

  virtual void DoExplosion(tGameID debrisFXID); 
  virtual void Levitate(); // levitate debris; called from effect 

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID          =  0xFFFFAA03;

  static const SyPropID PropId_Location  = 0x1000;
  static const SyPropID PropId_Radius    = 0x1001;
  static const SyPropID PropId_NotifyAI  = 0x1002;

protected:
  virtual bool  IsInside(cGameObject *obj);
  virtual void  UpdateMovesWithObject();
  virtual SyVect3 GetCenter(){return mLocation;}
  virtual float  GetRadius(){return mRadius;};

  SyVect3       mLocation;
  float         mRadius;
  bool          mbNotifyAI;
};

class cAreaEffect_PowerUp  : public cAreaEffect_Radius
{
public:
  cAreaEffect_PowerUp();

  virtual bool  IsExpired();

  void TestHealth(bool bEnable) { mbTestHealth = bEnable; }
  void TestMana(bool bEnable) { mbTestMana = bEnable; }
  void TestEssence(bool bEnable) { mbTestEssence = bEnable; }

  void SetProjectileID(tGameObjectID id) { mProjectileID = id; }

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID             =  0xFFFFAA04;

  static const SyPropID PropId_ProjectileID = 0x2000;
  static const SyPropID PropId_TestHealth   = 0x2001;
  static const SyPropID PropId_TestMana     = 0x2002;
  static const SyPropID PropId_TestEssence  = 0x2003;
  static const SyPropID PropId_Used         = 0x2004;

protected:
  virtual bool  IsInside(cGameObject *obj);
  virtual float  GetRadius(){return mRadius * 5.0f;}; // fudge for moving powerup?


  tGameObjectID mProjectileID;
  bool mbTestHealth;
  bool mbTestMana;
  bool mbTestEssence;
  bool mbUsed;
};


class cAreaEffect_Burst  : public cAreaEffect_Radius
{
public:
  cAreaEffect_Burst();

  virtual void  Update(float time);

  void          SetSpeed(float speed){mSpeed = speed;};
  void          SetMaxRadius(float maxRadius){mMaxRadius = maxRadius;};

  virtual bool  IsExpired();

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID           =  0xFFFFAA06;

  static const SyPropID PropId_Speed      = 0x2000;
  static const SyPropID PropId_MaxRadius  = 0x2001;

protected:
  float         mSpeed;
  float         mMaxRadius;
};


class cAreaEffect_3DBBox  : public cAreaEffect
{
public:
  cAreaEffect_3DBBox();

  void          SetMinMax(const SyVect3  &min,const SyVect3 &max){mMin = min;mMax = max;};

  virtual void  Update(float time);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID          =  0xFFFFAA05;

  static const SyPropID PropId_Min       = 0x1000;
  static const SyPropID PropId_Max       = 0x1001;

protected:

  virtual bool  IsInside(cGameObject *obj);
  virtual SyVect3 GetCenter();
  virtual float  GetRadius();

  SyVect3       mMin;
  SyVect3       mMax;
};

class cAreaEffect_Chain : public cAreaEffect
{                                                   
public:
  cAreaEffect_Chain();

  virtual void  Update(float time);
  void SetTargetDelay(float time) { mTargetDelay = time; mTargetDelayTimer = time; }
  void SetMaxDistance(float dist) { mMaxDist = dist; }

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID                  =  0xFFFFAA07;

  static const SyPropID PropId_TargetDelay       = 0x1000;
  static const SyPropID PropId_TargetDelayTimer  = 0x1001;
  static const SyPropID PropId_MaxDist           = 0x1002;
  static const SyPropID PropId_NextTargetID      = 0x1003;

protected:
  virtual bool  IsInside(cGameObject *obj);
  virtual tGameObjectID SelectNextTarget(); 
  virtual SyVect3 GetCenter();
  virtual float  GetRadius();

  float mTargetDelay, mTargetDelayTimer;
  float mMaxDist;
  tGameObjectID mNextTargetID;
};


class cAreaEffect_Arc  : public cAreaEffect
{
public:
  cAreaEffect_Arc();

  void          SetArc(const SyVect3 &loc, 
                       float speed,
                       float radius, 
                       float start,
                       float end,
                       float length);

  virtual void  Update(float time);
  virtual bool  IsExpired();

  virtual void  DoExplosion(tGameID debrisFXID);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID               =  0xFFFFAA08;

  static const SyPropID PropId_Speed          = 0x1000;
  static const SyPropID PropId_Radius         = 0x1001;
  static const SyPropID PropId_Start          = 0x1002;
  static const SyPropID PropId_Loc            = 0x1003;
  static const SyPropID PropId_End            = 0x1004;
  static const SyPropID PropId_Cur            = 0x1005;
  static const SyPropID PropId_Length         = 0x1006;

protected:

  virtual bool  IsInside(cGameObject *obj);
  virtual void  UpdateMovesWithObject();
  virtual SyVect3 GetCenter(){return mLoc;};
  virtual float  GetRadius(){return mRadius + 2.0f;};

  float         mSpeed;
  float         mRadius;
  float         mStart;
  SyVect3       mLoc;
  float         mEnd;

  float         mCur;
  float         mLength;
};

class cAreaEffect_WaveAngle  : public cAreaEffect
{
public:
  cAreaEffect_WaveAngle();

  virtual void  Update(float time);

  void SetWave(const SyVect3& start, const SyVect3& dir, float speed, float range, float angle, float width);
  virtual bool  IsExpired();

  virtual void  DoExplosion(tGameID debrisFXID);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID           =  0xFFFFAA09;

  static const SyPropID PropId_StartLoc   = 0x1000;
  static const SyPropID PropId_Dir        = 0x1001;
  static const SyPropID PropId_Speed      = 0x1002;
  static const SyPropID PropId_Range      = 0x1003;
  static const SyPropID PropId_Angle      = 0x1004;
  static const SyPropID PropId_Width      = 0x1005;
  static const SyPropID PropId_Dist       = 0x1006;

protected:

  virtual bool  IsInside(cGameObject *obj);
  virtual void  UpdateMovesWithObject();
  virtual SyVect3 GetCenter(){return mStartLoc;};
  virtual float  GetRadius(){return mRange;};

  SyVect3       mStartLoc;
  SyVect3       mDir;
  float         mSpeed;
  float         mRange;
  float         mAngle;
  float         mWidth;
  float         mDist;
};

class cAreaEffect_Trail  : public cAreaEffect
{
public:
  cAreaEffect_Trail();

  virtual void  Update(float time);

  void SetWidth(float w) { mWidth = w; }
  void SetLength(float l) { mLength = l; }

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID               =  0xFFFFAA0A;

  static const SyPropID PropId_SamplePoints   = 0x1000;
  static const SyPropID PropId_Length         = 0x1001;
  static const SyPropID PropId_Width          = 0x1002;
  static const SyPropID PropId_SampleTimer    = 0x1003;

protected:
  virtual bool  IsInside(cGameObject *obj);
  virtual SyVect3 GetCenter();
  virtual float  GetRadius();

  SyVector<SyVect3> mSamplePoints;
  float mLength;
  float mWidth;
  float mSampleTimer;
};

class cAreaEffect_2DOrientedBox  : public cAreaEffect
{
public:
  cAreaEffect_2DOrientedBox();

  void          SetCenter(const SyVect3 &center) {mCenter = center;}
  void          SetHalfLength(const SyVect3 &halfLength);
  void          SetHalfWidth(const SyVect3 &halfWidth);

  virtual void  Update(float time);
  virtual bool  IsLineOfSightBlocked(const SyVect3& start, const SyVect3& end, SyVect3& hit);

  virtual void  DoExplosion(tGameID debrisFXID);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID          =  0xFFFFAA0B;

  static const SyPropID PropId_Center      = 0x1000;
  static const SyPropID PropId_LengthAxis  = 0x1001;
  static const SyPropID PropId_WidthAxis   = 0x1002;
  static const SyPropID PropId_HalfLength  = 0x1003;
  static const SyPropID PropId_HalfWidth   = 0x1004;

protected:
  virtual bool  IsInside(cGameObject *obj);
  virtual void  UpdateMovesWithObject();
  virtual SyVect3 GetCenter(){return mCenter;};
  virtual float  GetRadius();

  SyVect3       mCenter;
  SyVect3       mLengthAxis;
  SyVect3       mWidthAxis;
  float         mHalfLength;
  float         mHalfWidth;
};

class cAreaEffect_Beam  : public cAreaEffect
{
public:
  cAreaEffect_Beam();

  virtual void  Update(float time);

  void SetBeam(const SyVect3& start, const SyVect3& dir, float speed, float range, float width);
  virtual bool  IsExpired();
  virtual void  DoExplosion(tGameID debrisFXID);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID           =  0xFFFFAA0C;

  static const SyPropID PropId_StartLoc   = 0x1000;
  static const SyPropID PropId_ForwardDir = 0x1001;
  static const SyPropID PropId_RightDir   = 0x1002;
  static const SyPropID PropId_Speed      = 0x1003;
  static const SyPropID PropId_Range      = 0x1004;
  static const SyPropID PropId_Width      = 0x1005;
  static const SyPropID PropId_Dist       = 0x1006;

protected:

  virtual bool  IsInside(cGameObject *obj);
  virtual void  UpdateMovesWithObject();
  virtual SyVect3 GetCenter();
  virtual float  GetRadius();

  SyVect3       mStartLoc;
  SyVect3       mForwardDir;
  SyVect3       mRightDir;
  float         mSpeed;
  float         mRange;
  float         mWidth;
  float         mDist;
};

class cAreaEffect_WaveLine  : public cAreaEffect
{
public:
  cAreaEffect_WaveLine();

  virtual void  Update(float time);

  void SetWave(const SyVect3& start, const SyVect3& dir, float speed, float range, float width);
  virtual bool  IsExpired();

  virtual void  DoExplosion(tGameID debrisFXID);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID           =  0xFFFFAA0D;

  static const SyPropID PropId_StartLoc   = 0x1000;
  static const SyPropID PropId_ForwardDir = 0x1001;
  static const SyPropID PropId_RightDir   = 0x1002;
  static const SyPropID PropId_Speed      = 0x1003;
  static const SyPropID PropId_Range      = 0x1004;
  static const SyPropID PropId_Width      = 0x1005;
  static const SyPropID PropId_Dist       = 0x1006;

protected:

  virtual bool  IsInside(cGameObject *obj);
  virtual void  UpdateMovesWithObject();
  virtual SyVect3 GetCenter(){return mStartLoc;};
  virtual float  GetRadius(){return mDist;};

  SyVect3       mStartLoc;
  SyVect3       mForwardDir;
  SyVect3       mRightDir;
  float         mSpeed;
  float         mRange;
  float         mWidth;
  float         mDist;
};

class cAreaEffect_Cone  : public cAreaEffect
{
public:
  cAreaEffect_Cone();

  virtual void  Update(float time);

  void SetCone(const SyVect3& start, const SyVect3& dir, float range, float angle);
  virtual void  DoExplosion(tGameID debrisFXID);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID           =  0xFFFFAA0E;

  static const SyPropID PropId_StartLoc   = 0x1000;
  static const SyPropID PropId_Dir        = 0x1001;
  static const SyPropID PropId_Range      = 0x1002;
  static const SyPropID PropId_Angle      = 0x1003;

protected:
  bool IsInsideCone(cGameObject* obj);
  virtual bool  IsInside(cGameObject *obj);
  virtual void  UpdateMovesWithObject();
  virtual SyVect3 GetCenter(){return mStartLoc;};
  virtual float  GetRadius(){return mRange;};

  SyVect3       mStartLoc;
  SyVect3       mDir;
  float         mRange;
  float         mAngle;
};

class cAreaEffect_MeteorShower  : public cAreaEffect_Radius
{
public:
  cAreaEffect_MeteorShower();

  virtual void  Update(float time);

  void SetSpell(tGameID spell);

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID           =  0xFFFFAA0F;
  
  static const SyPropID PropId_SpellID = 0x1000;
  static const SyPropID PropId_TimeBetweenShots = 0x1001;

protected:
  tGameID mSpellID;
  float mTimeBetweenShots; 
  float mRandAdditionalTime; 
  float mTimer; 
};

class SySceneQuery;

class cAreaEffectSys : public SyPropObject
{

public:
  cAreaEffectSys();
  ~cAreaEffectSys();

  tEffectID Add(cAreaEffect *effect);    
  void    Clear();
  void    Update(float time);
  void    ProcessPacket(cRulePacket* packet);
  float   GetTotalTime(){return m_TotalTime;};
  cAreaEffect* Fetch(tEffectID id);

  void    Remove(tGameID spellID, tGameObjectID sourceID);
  void    Remove(tEffectID effectID);

  bool    IsLineOfSightBlocked(const SyVect3& start, const SyVect3& end, SyVect3& hit);

//  SySceneQuery *GetQuery() {return m_query;};

  // return singleton instance
  static cAreaEffectSys* Get() { return smpThis; }

  // Reflection Support via SyPropObject
  static int           InitPropClass();
  static SyPropObject* Creator();
  static const int     mCLASSID              =  0xFFFFAAAA;

  static const SyPropID PropId_AreaEffects   = 0x0000;
  static const SyPropID PropId_TotalTime     = 0x0001;
  static const SyPropID PropId_CurID         = 0x0002;

  cAreaEffect *     BeginMin(){return mXMinList.First();};
  cAreaEffect *     NextMin(cAreaEffect *obj){return mXMinList.Next(obj);};
  cAreaEffect *     PrevMin(cAreaEffect *obj){return mXMinList.Prev(obj);};
  cAreaEffect *     BeginMax(){return mXMaxList.First();};
  cAreaEffect *     NextMax(cAreaEffect *obj){return mXMaxList.Next(obj);};
  cAreaEffect *     PrevMax(cAreaEffect *obj){return mXMaxList.Prev(obj);};

  cAreaEffect *     BeginOpen(){return mOpenList.First();};
  cAreaEffect *     NextOpen(cAreaEffect *obj){return mOpenList.Next(obj);};
  void              AddOpen(cAreaEffect *obj){mOpenList.InsertTail(obj);};
  void              RemoveOpen(cAreaEffect *obj){mOpenList.Remove(obj);};
  void              ClearOpen(){mOpenList.RemoveAll();};

  void              ReinsertAfterMin(cAreaEffect *before,cAreaEffect *after);
  void              ReinsertAfterMax(cAreaEffect *before,cAreaEffect *after);

protected:
  static cAreaEffectSys* smpThis;

  SyVector<cAreaEffect *>   mAreaEffects;
  float                     m_TotalTime;
  tEffectID                 m_curID;
//  SySceneQuery             *m_query;

  SyEmbeddedList<cAreaEffect, &cAreaEffect::mMinXLink>                   mXMinList; // used for faster collision detection
  SyEmbeddedList<cAreaEffect, &cAreaEffect::mMaxXLink>                   mXMaxList; // used for faster collision detection
  SyEmbeddedList<cAreaEffect, &cAreaEffect::mOpenLink>                   mOpenList; // used for faster collision detection
};



//------------------------------------------- Function Declarations
//--------------------------------------------------------- Globals
//------------------------------------------------ Inline Functions

#endif                   
