#ifndef STEVENTBASE_H
#define STEVENTBASE_H

//-----------------------------
// Event definitions
//-----------------------------
#define EVT_COUNT_TYPE				5
#define EVT_COUNT_SUBTYPE				12

// Game events
#define EVT_GAME_LEVEL_LOADED			0x1000
#define EVT_GAME_LEVEL_ENDED			0x1001
#define EVT_GAME_THINK				0x1002

// Player events
#define EVT_PLAYER_JOIN				0x2000
#define EVT_PLAYER_LEFT				0x2001
#define EVT_PLAYER_BANDWIDTH			0x2002
#define	EVT_PLAYER_CHAT				0x2003
#define EVT_PLAYER_RADIO				0x2004
#define EVT_PLAYER_SUICIDE			0x2005
#define EVT_PLAYER_TEAMCHANGE			0x2006
#define EVT_PLAYER_SERIALHASH			0x2007
#define EVT_PLAYER_RAWDAMAGE			0x2008
#define EVT_PLAYER_PURCHASE			0x2009
#define EVT_PLAYER_SPAWN				0x2010
#define EVT_PLAYER_CONNECT			0x2011

// Object events
#define EVT_OBJECT_CREATE				0x3000
#define EVT_OBJECT_INIT				0x3001
#define EVT_OBJECT_DAMAGE				0x3002
#define EVT_OBJECT_KILL				0x3003
#define EVT_OBJECT_SQUISH				0x3004
#define EVT_OBJECT_TRANSITION			0x3005
#define EVT_OBJECT_JUMP_START			0x3006
#define EVT_OBJECT_JUMP_COMPLETE		0x3007
#define EVT_OBJECT_C4_CREATE			0x3008
#define EVT_OBJECT_C4_DETONATE		0x3009
#define EVT_OBJECT_POWERUP_GRANT		0x3010
#define EVT_OBJECT_FIRE				0x3011

// Network events
#define EVT_NET_WOLPAGE				0x4000
#define EVT_NET_SERIAL_AUTH			0x4001

// BHS events
#define EVT_BHS_POKE					0x5000
#define EVT_BHS_VERSION				0x5001

// Priority definitions
#define EVT_PRIORITY_TOP				INT_MAX
#define EVT_PRIORITY_DEFAULT			0
#define EVT_PRIORITY_LOWEST			INT_MIN

// Marco to define a skippable event
#define EVT_SKIPPABLE() \
private: \
	class stEventSkippable { \
		bool m_continue; \
	public: \
		stEventSkippable() { this->m_continue = true; }; \
		bool CanContinue() { return this->m_continue; }; \
		void Skip() { this->m_continue = false; }; \
	}; \
	stEventSkippable m_skip; \
public: \
	void Skip() { this->m_skip.Skip(); }; \
	bool CanContinue() { return this->m_skip.CanContinue(); }; \
	bool Skippable() { return true; };


// Forward
class gzPlayer;


/**************/
/* Event base */
/**************/
class gzEventBase {
	double m_dataDouble;
	int m_dataInt;
	int m_eventType;
public:
	gzEventBase()
	{
		this->m_dataDouble	= 0.0f;
		this->m_dataInt		= 0;
		this->m_eventType	= -1;
	};
	inline double GetDouble()
	{
		return this->m_dataDouble;
	};
	inline void SetDouble(double data)
	{
		this->m_dataDouble = data;
	};
	inline int GetInt()
	{
		return this->m_dataInt;
	};
	inline void SetInt(int data)
	{
		this->m_dataInt = data;
	};
	inline int GetEventType()
	{
		return this->m_eventType;
	};
	inline void SetEventType(int type)
	{
		this->m_eventType = type;
	};
	virtual bool CanContinue()
	{
		return true;
	};
	virtual bool Skippable()
	{
		return false;
	};
};


/*****************/
/* Player events */
/*****************/
class gzEventPlayerBase : public gzEventBase {
	nc_cPlayer *m_player;
public:
	inline nc_cPlayer *GetPlayer()
	{
		return this->m_player;
	};
	inline void SetPlayer(nc_cPlayer *player)
	{
		this->m_player = player;
	};
};

class gzEventPlayerPurchase : public gzEventPlayerBase {
public:
	nc_BaseControllerClass *m_base;
	unsigned int m_originalCost;
	unsigned int m_cost;
	unsigned long m_presetId;
	int m_retCode;

	EVT_SKIPPABLE();
};

class gzEventPlayerChat : public gzEventPlayerBase {
public:
	nc_TextMessageEnum m_type;
	aWideString m_message;
	int m_sender;
	int m_receiver;

	EVT_SKIPPABLE();
};

class gzEventPlayerRadio : public gzEventPlayerBase {
public:
	int m_team;
	int m_sender;
	int m_radioID;
	int m_key;
	bool m_toTeamOnly;

	EVT_SKIPPABLE();
};

class gzEventPlayerBandwidth : public gzEventPlayerBase {
public:
	gzEventPlayerBandwidth(int bw) { this->SetInt(bw); };

	EVT_SKIPPABLE();
};

class gzEventPlayerSerialHash : public gzEventPlayerBase {
public:
	aString m_hash;
};

class gzEventPlayerConnect : public gzEventBase {
public:
	aIPv4Address m_addr;
	aWideString  m_nick;
	aWideString  m_password;
	unsigned int m_exeKey;
	int m_bandwidth;

	EVT_SKIPPABLE();
};


/*****************/
/* Object events */
/*****************/
class gzEventObjectBase : public gzEventBase {
public:
};

class gzEventObjectCreate : public gzEventObjectBase {
public:
	nc_ScriptableGameObj *m_obj;
};

class gzEventObjectInit : public gzEventObjectBase {
public:
	nc_ScriptableGameObj *m_obj;
};

class gzEventObjectDamage : public gzEventObjectBase {
public:
	nc_DamageableGameObj *m_attacker;
	nc_DamageableGameObj *m_defender;
	float m_damage;
	int m_warhead;

	EVT_SKIPPABLE();
};

class gzEventObjectKill : public gzEventObjectBase {
public:
	nc_DamageableGameObj *m_attacker;
	nc_DamageableGameObj *m_defender;

	EVT_SKIPPABLE();
};

class gzEventObjectFlipKill : public gzEventObjectBase {
public:
	nc_VehicleGameObj *m_vehicle;
	bool m_allowFlipKill;

	EVT_SKIPPABLE();
};

class gzEventObjectTransition : public gzEventObjectBase {
public:
	nc_SoldierGameObj *m_soldier;
	nc_TransitionInstanceClass *m_instance;

	EVT_SKIPPABLE();
};

class gzEventObjectJump : public gzEventObjectBase {
public:
	nc_SoldierGameObj *m_soldier;
};

class gzEventObjectC4Creation : public gzEventObjectBase {
public:
	nc_C4GameObj *m_C4;
};

class gzEventObjectC4Detonation : public gzEventObjectBase {
public:
	nc_C4GameObj *m_C4;
	nc_SmartGameObj *m_explodeBy;

	EVT_SKIPPABLE();
};

class gzEventObjectPowerupGrant : public gzEventObjectBase {
public:
	nc_PowerUpGameObj *m_powerup;
	nc_SoldierGameObj *m_soldier;

	EVT_SKIPPABLE();
};

class gzEventObjectFire : public gzEventObjectBase {
public:
	bool m_primaryFire;
	nc_ArmedGameObj *m_shooter;
	nc_WeaponClass *m_weapon;
};

class gzEventObjectBeaconStateChange : public gzEventObjectBase {
public:
	nc_BeaconGameObj *m_beacon;
	int m_state;
};


/**************/
/* Net events */
/**************/
class gzEventNetBase : public gzEventBase {
public:
};

class gzEventNetWolPage : public gzEventNetBase {
public:
	aString m_sender;
	aString m_message;

	EVT_SKIPPABLE();
};

/*
	This event base on "gzEventPlayer" because "gzEventNet" has nothing to abstract and
	cause conflicts with "gzEventPlayer"
*/
class gzEventNetSerialAuth : public gzEventPlayerBase {
public:
	aString m_message;
};


/******************/
/* BHS.dll events */
/******************/
class gzEventBhsBase : public gzEventBase {
	gzPlayer *m_player;
public:
	gzPlayer *GetPlayer()
	{
		return this->m_player;
	};
	void SetPlayer(gzPlayer *gzData)
	{
		this->m_player = gzData;
	};
};

class gzEventBhsPoke : public gzEventBhsBase {
	nc_PhysicalGameObj *m_pokedObj;
public:
	gzEventBhsPoke(nc_PhysicalGameObj *pokedObj)
	{
		this->m_pokedObj = pokedObj;
	};
	nc_PhysicalGameObj *GetPoked()
	{
		return this->m_pokedObj;
	};
};

class gzEventBhsVersion : public gzEventBhsBase {
	float m_version;
public:
	gzEventBhsVersion(float version)
	{
		this->m_version = version;
	};
	float GetVersion()
	{
		return this->m_version;
	};
};

#endif
