/******************************************************************
  
  Module:  script.h
  
  Author: Sean Craig
  
  Description:  

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

#ifndef SCRIPT_H
#define SCRIPT_H

//-------------------------------------------------------- Includes
#include "gameobj.h"
//-------------------------------------------------------- Typedefs
//---------------------------------------------- Class Declarations
static const int SCRIPT_CLASSID                     =  0xFFFF7001;
static const int SCRIPTBLOCK_CLASSID                =  0xFFFF7002;
static const int SCRIPTEVENTHANDLER_CLASSID         =  0xFFFF7003;
static const int SCRIPTRESPONSE_CLASSID             =  0xFFFF7004;
static const int SCRIPTRESPONSE_CHECKSTATE_CLASSID  =  0xFFFF7005;
static const int SCRIPTRESPONSE_ENDIF_CLASSID       =  0xFFFF7006;
static const int SCRIPTRESPONSE_ELSE_CLASSID        =  0xFFFF7007;
static const int SCRIPTRESPONSE_CHANGESTATE_CLASSID =  0xFFFF7008;
static const int SCRIPTRESPONSE_PLAYMUSIC_CLASSID   =  0xFFFF7009;
static const int SCRIPTRESPONSE_PLAYSOUND_CLASSID   =  0xFFFF700A;
static const int SCRIPTRESPONSE_GOTO_CLASSID        =  0xFFFF700B;
static const int SCRIPTRESPONSE_TELEPORTTO_CLASSID  =  0xFFFF700C;
static const int SCRIPTRESPONSE_SETAGGRO_CLASSID    =  0xFFFF700D;
static const int SCRIPTRESPONSE_SPAWN_CLASSID       =  0xFFFF700E;
static const int SCRIPTRESPONSE_GIVEITEM_CLASSID    =  0xFFFF700F;
static const int SCRIPTRESPONSE_DELAY_CLASSID       =  0xFFFF7010;

typedef enum
{
  SS_ON,
  SS_OFF,
  SS_DEAD,
  NUM_SCRIPT_STATES
} eScriptState;


typedef enum
{
  SE_ACTIVATE,  // Character activates an object
  SE_ENTER,     // Character enters a trigger zone
  SE_EXIT,      // Character exits a trigger zone
  SE_STARTUP,   // on level load
  SE_STATE_ENTER, // state entered
  SE_STATE_EXIT, 
  SE_COLLIDE,   // Character collides with an object
} eOldScriptEventType;

class cGameObject;
class cScriptFrame // a script frame contains everything needed to run a script or resume waiting scripts
{
public:
  cScriptFrame();

  tGameObjectID      mSelf;  // game object that owns this script
  tGameObjectID      mActor; // the actor who trigger the script
  eScriptState       mState;
  eOldScriptEventType   mEvent;
  cGameObject*       mOwner;
  int                mResponseIndex; // current response index (almost like a line number)
};


typedef enum
{
  SR_NEXT, // process next response
  SR_EXIT, // done with this script
  SR_SKIP, // proceed to next else or endif block.

} eScriptResult;

class cScriptBlock;

class cScript  : public SyPropObject // one script per object
{
public:
  cScript();
  ~cScript();
  
  /* Property Class Support */
  static int                  InitPropClass();
  static SyPropObject*        Creator();

  void Init() {};
  void Clear();
  void Exit() {};
  void Reset() {};
  void Update( float time );
  void SetOwner( cGameObject* pOwner );

  void Run(cGameObject *actor,eOldScriptEventType event);
  cScriptBlock* GetState( eScriptState state );
  void SetState( eScriptState state ) { mState = state; }

protected:
  eScriptResult Process(cScriptFrame *frame);

  cGameObject*  mOwner; // instance
  cScriptBlock* mStates[NUM_SCRIPT_STATES];
  eScriptState  mState; // instance
  eScriptState  mStartingState; 

  
};


class cScriptEventHandler;
class cScriptBlock   : public SyPropObject // a script block is a set of handlers.  Each script state (off, on, dead) gets one block
{
public:
  cScriptBlock();
  ~cScriptBlock();

  /* Property Class Support */
  static int                  InitPropClass();
  static SyPropObject*        Creator();

  eScriptResult Process(cScriptFrame *frame);

  SyMap<eOldScriptEventType,cScriptEventHandler*>& GetHandlers() { return( mHandlers ); }

protected:
  SyMap<eOldScriptEventType,cScriptEventHandler *>mHandlers;
};



class cScriptResponse;
class cScriptEventHandler : public SyPropObject
{
public:
  cScriptEventHandler();
  ~cScriptEventHandler();
  /* Property Class Support */
  static int                  InitPropClass();
  static SyPropObject*        Creator();

  eScriptResult Process(cScriptFrame *frame);
  eScriptResult Skip(cScriptFrame *frame);

  SyVector<cScriptResponse*>& GetResponses() { return( mResponses ); }

protected:
  SyVector<cScriptResponse *> mResponses;
};

typedef enum
{
  SRT_STATEMENT,
  SRT_CHECK,
  SRT_ENDIF,
  SRT_ELSE
} eScriptResponseType;

class cScriptResponse : public SyPropObject
{
public:
  cScriptResponse();

  /* Property Class Support */
  static int                  InitPropClass();
  static SyPropObject*        Creator();

  virtual eScriptResponseType GetType(){return SRT_STATEMENT;};
  virtual eScriptResult Process(cScriptFrame *frame)=0;
};

typedef enum
{
  ST_SELF,
  ST_ACTOR,
  ST_SPECIFIED,
  NUM_SCRIPT_RESPONSE_TARGETS
} eScriptResponseTarget;

class cScriptResponseCheckState : public cScriptResponse
{
public:
  cScriptResponseCheckState();

  /* Property Class Support */
  static int                  InitPropClass();
  static SyPropObject*        Creator();

  virtual eScriptResponseType GetType(){return SRT_CHECK;};
  virtual eScriptResult Process(cScriptFrame *frame); // if target.state ==  mState return SR_NEXT, otherwise return SR_SKIP
protected:
  
  eScriptResponseTarget  mTarget;
  tGameObjectID  mSpecified; // if mTarget=ST_SPECIFIED, use this id.  Otherwise use self or actor. 
  eScriptState   mState;
};

class cScriptResponseEndif : public cScriptResponse
{
public:
  cScriptResponseEndif();

  /* Property Class Support */
  static int                  InitPropClass();
  static SyPropObject*        Creator();

protected:
  virtual eScriptResponseType GetType(){return SRT_ENDIF;};
  virtual eScriptResult Process(cScriptFrame *frame){return SR_NEXT;};
};

class cScriptResponseElse : public cScriptResponse
{
public:
  cScriptResponseElse();

  /* Property Class Support */
  static int                  InitPropClass();
  static SyPropObject*        Creator();

protected:
  virtual eScriptResponseType GetType(){return SRT_ELSE;};
  virtual eScriptResult Process(cScriptFrame *frame){return SR_SKIP;}; // only gets called if previous block wasn't skipped
};

class cScriptResponseChangeState : public cScriptResponse
{
public:
  cScriptResponseChangeState();
  /* Property Class Support */
  static int                  InitPropClass();
  static SyPropObject*        Creator();
  virtual eScriptResult Process(cScriptFrame *frame);

protected:
  eScriptResponseTarget  mTarget;
  tGameObjectID          mSpecified; // if mTarget=ST_SPECIFIED, use this id.  Otherwise use self or actor. 
  eScriptState           mState;
};

class cScriptResponsePlayMusic : public cScriptResponse
{
public:
  cScriptResponsePlayMusic();

  /* Property Class Support */
  static int                  InitPropClass();
  static SyPropObject*        Creator();

  virtual eScriptResult Process(cScriptFrame *frame){return SR_NEXT;};
protected:
  SyString               mMusicName;
};

class cScriptResponsePlaySound : public cScriptResponse
{
public:
  cScriptResponsePlaySound();

  /* Property Class Support */
  static int                  InitPropClass();
  static SyPropObject*        Creator();

  virtual eScriptResult Process(cScriptFrame *frame);
protected:
  SyString               mSoundName;
  bool                   mSpacialized; // if true, play at a location in space.  Otherwise, just play sound
  float                  mVolume;
  eScriptResponseTarget  mTarget; // location to play sound
  tGameObjectID          mTargetLocation; // could be a marker
};


class cScriptResponseGoTo : public cScriptResponse // this is an ai walk to command
{
public:
  cScriptResponseGoTo();
  /* Property Class Support */
  static int                  InitPropClass();
  static SyPropObject*        Creator();

  virtual eScriptResult Process(cScriptFrame *frame){return SR_NEXT;};
protected:
  eScriptResponseTarget  mTarget; // location to walk to (could be the actor)
  tGameObjectID          mTargetLocation; // could be a marker
};

class cScriptResponseSetAggro : public cScriptResponse // this makes things angry or friendly
{
public:
  cScriptResponseSetAggro();
  /* Property Class Support */
  static int                  InitPropClass();
  static SyPropObject*        Creator();

  virtual eScriptResult Process(cScriptFrame *frame){return SR_NEXT;};
protected:
  eScriptResponseTarget  mTarget; // location to walk to (could be the actor)
  tGameObjectID          mTargetLocation; // could be a marker
  int                    mAgro;  // 0 for friendly, 100 for hating
};

class cScriptResponseTeleportTo : public cScriptResponse // this is an instanteous move
{
public:
  cScriptResponseTeleportTo();

  /* Property Class Support */
  static int                  InitPropClass();
  static SyPropObject*        Creator();

  virtual eScriptResult Process(cScriptFrame *frame){return SR_NEXT;};
protected:
  tGameObjectID          mTargetLocation; // could be a marker
};

class cScriptResponseSpawn : public cScriptResponse // this is an instanteous move
{
public:
  cScriptResponseSpawn();

  /* Property Class Support */
  static int                  InitPropClass();
  static SyPropObject*        Creator();

  virtual eScriptResult Process(cScriptFrame *frame){return SR_NEXT;};
protected:
  tGameID                mMaster;
  int                    mQuantity;
  tGameObjectID          mTargetLocation; // marker
};

class cScriptResponseGiveItem : public cScriptResponse
{
public:
  cScriptResponseGiveItem();

  /* Property Class Support */
  static int                  InitPropClass();
  static SyPropObject*        Creator();

  virtual eScriptResult Process(cScriptFrame *frame){return SR_NEXT;};
protected:
  eScriptResponseTarget  mTarget;
  tGameObjectID          mSpecified; // if mTarget=ST_SPECIFIED, use this id.  Otherwise use self or actor. 

  tGameID                mItemID;
  int                    mQuantity;
};

class cScriptResponseDelay : public cScriptResponse
{
public:
  cScriptResponseDelay();

  /* Property Class Support */
  static int                  InitPropClass();
  static SyPropObject*        Creator();

  virtual eScriptResult Process(cScriptFrame *frame){return SR_NEXT;};
protected:
  float                       mTime; // in secs.
};
//------------------------------------------- Function Declarations
void RegPropClasses_Script();
//--------------------------------------------------------- Globals
//------------------------------------------------ Inline Functions

#endif
