//-----------------------------------------------------------------------------
//
//  $Logfile:: /game/trigger.h                                                $
// $Revision:: 3                                                              $
//   $Author:: Burger                                                         $
//     $Date:: 12/27/00 8:34p                                                 $
//
// Copyright (C) 1997 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source is may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
//
// DESCRIPTION:
// Environment based triggers.
//

#ifndef __TRIGGER_H__
#define __TRIGGER_H__

#include "g_local.h"
#include "entity.h"
#include "archive.h"

class ScriptMaster;

extern Event EV_Trigger_ActivateTargets;
extern Event EV_Trigger_SetWait;
extern Event EV_Trigger_SetDelay;
extern Event EV_Trigger_SetCount;
extern Event EV_Trigger_SetMessage;
extern Event EV_Trigger_SetNoise;
extern Event EV_Trigger_SetKey;
extern Event EV_Trigger_Effect;
extern Event EV_Trigger_StartThread;
extern Event EV_Trigger_SetThread; //###
extern Event EV_Trigger_SetKey;

#define TRIGGER_PLAYERS         4
#define TRIGGER_MONSTERS        8
#define TRIGGER_PROJECTILES 16
#define TRIGGER_HOVERBIKES 32 //###

class Trigger : public Entity
{
protected:
	float wait;
	float delay;
	float trigger_time;
	qboolean triggerActivated;
	int count;
	str noise;
	str message;
	str key;
	str thread;
	EntityPtr activator;
	int respondto;

public:
	CLASS_PROTOTYPE( Trigger );

	Trigger();
	virtual ~Trigger();

	void            Touch( Event* ev );
	void            EventSetWait( Event* ev );
	void            EventSetDelay( Event* ev );
	void            EventSetCount( Event* ev );
	void            EventSetKey( Event* ev );

	void            EventSetMessage( Event* ev );
	void        SetTriggerTime( float t )
	{
		trigger_time = t;
	}
	void            SetMessage( const char* message );
	str&         Message( void );

	void            EventSetNoise( Event* ev );
	void            SetNoise( const char* text );
	str&         Noise( void );

	void        StartThread( Event* ev );
	void        EventSetThread( Event* ev ); //###
	void            TriggerStuff( Event* ev );
	void            ActivateTargets( Event* ev );
	virtual void Archive( Archiver& arc );
	virtual void Unarchive( Archiver& arc );
};


class TouchField : public Trigger
{
private:
	Event ontouch;
	EntityPtr owner;

public:
	CLASS_PROTOTYPE( TouchField );

	virtual void    Setup( Entity* ownerentity, Event ontouch, Vector min, Vector max, int respondto );
	void                SendEvent( Event* ev );
	virtual void   Archive( Archiver& arc );
	virtual void   Unarchive( Archiver& arc );
};

inline void TouchField::Archive( Archiver& arc )
{
	Trigger::Archive( arc );
	arc.WriteEvent( ontouch );
	arc.WriteSafePointer( owner );
}

inline void TouchField::Unarchive( Archiver& arc )
{
	Trigger::Unarchive( arc );
	arc.ReadEvent( &ontouch );
	arc.ReadSafePointer( &owner );
}

typedef SafePtr<TouchField> TouchFieldPtr;

class TriggerOnce : public Trigger
{
public:
	CLASS_PROTOTYPE( TriggerOnce );
	TriggerOnce();
};

class TriggerRelay : public Trigger
{
public:
	CLASS_PROTOTYPE( TriggerRelay );

	TriggerRelay();
};

class DamageThreshold : public Trigger
{
protected:
	int damage_taken;

public:
	CLASS_PROTOTYPE( DamageThreshold );

	virtual void    DamageEvent( Event* ev );
	void                Setup( Event* ev );
	DamageThreshold();
	virtual void   Archive( Archiver& arc );
	virtual void   Unarchive( Archiver& arc );
};

inline void DamageThreshold::Archive( Archiver& arc )
{
	Trigger::Archive( arc );
	arc.WriteInteger( damage_taken );
}

inline void DamageThreshold::Unarchive( Archiver& arc )
{
	Trigger::Unarchive( arc );
	damage_taken = arc.ReadInteger();
}

class TriggerSecret : public TriggerOnce
{
public:
	CLASS_PROTOTYPE( TriggerSecret );

	TriggerSecret();
	void    FoundSecret( Event* ev );
	void    Activate( Event* ev );
};

class TriggerPush : public Trigger
{
protected:
	float speed;
	Vector pushvelocity;
	qboolean pushon; //###

public:
	CLASS_PROTOTYPE( TriggerPush );

	TriggerPush();
	void        Push( Event* ev );
	void        Toggle( Event* ev );
	virtual void Archive( Archiver& arc );
	virtual void Unarchive( Archiver& arc );
};

inline void TriggerPush::Archive( Archiver& arc )
{
	Trigger::Archive( arc );
	arc.WriteFloat( speed );
	arc.WriteVector( pushvelocity );
	arc.WriteBoolean( pushon ); //###
}

inline void TriggerPush::Unarchive( Archiver& arc )
{
	Trigger::Unarchive( arc );
	speed = arc.ReadFloat();
	arc.ReadVector( &pushvelocity );
	pushon = arc.ReadBoolean(); //###
}

class TriggerPushAny : public Trigger
{
protected:
	float speed;
	Vector pushvelocity;

public:
	CLASS_PROTOTYPE( TriggerPushAny );

	TriggerPushAny();
	void        Push( Event* ev );
	virtual void Archive( Archiver& arc );
	virtual void Unarchive( Archiver& arc );
};

inline void TriggerPushAny::Archive( Archiver& arc )
{
	Trigger::Archive( arc );
	arc.WriteFloat( speed );
	arc.WriteVector( pushvelocity );
}

inline void TriggerPushAny::Unarchive( Archiver& arc )
{
	Trigger::Unarchive( arc );
	speed = arc.ReadFloat();
	arc.ReadVector( &pushvelocity );
}

class TriggerPlaySound : public Trigger
{
protected:
	int state;
	float attenuation;
	float volume;
	int channel;
	qboolean ambient;
	float fadetime;
	float timeofs;
	float pitch;

public:
	CLASS_PROTOTYPE( TriggerPlaySound );

	TriggerPlaySound();
	void    ToggleSound( Event* ev );
	void    SetVolume( Event* ev );
	void    SetAttenuation( Event* ev );
	void    SetChannel( Event* ev );
	virtual void Archive( Archiver& arc );
	virtual void Unarchive( Archiver& arc );
};

inline void TriggerPlaySound::Archive( Archiver& arc )
{
	Trigger::Archive( arc );
	arc.WriteInteger( state );
	arc.WriteFloat( attenuation );
	arc.WriteFloat( volume );
	arc.WriteInteger( channel );
	arc.WriteBoolean( ambient );
	arc.WriteFloat( fadetime );
	arc.WriteFloat( timeofs );
	arc.WriteFloat( pitch );
}

inline void TriggerPlaySound::Unarchive( Archiver& arc )
{
	Trigger::Unarchive( arc );
	state = arc.ReadInteger();
	attenuation = arc.ReadFloat();
	volume = arc.ReadFloat();
	channel = arc.ReadInteger();
	ambient = arc.ReadBoolean();
	fadetime = arc.ReadFloat();
	timeofs = arc.ReadFloat();
	pitch = arc.ReadFloat();

	//
	// see if its a toggle sound, if it is, lets start its sound again
	//
	if( spawnflags & 128 )
	{
		//
		// invert state so that final state will be right
		//
		state = !state;
		ToggleSound( NULL );
	}
}


class TriggerSpeaker : public TriggerPlaySound
{
public:
	CLASS_PROTOTYPE( TriggerSpeaker );

	TriggerSpeaker();
};

class RandomSpeaker : public TriggerSpeaker
{
protected:
	float mindelay;
	float maxdelay;

public:
	CLASS_PROTOTYPE( RandomSpeaker );

	RandomSpeaker();
	void  TriggerSound( Event* ev );
	void  ScheduleSound( void );
	virtual void Archive( Archiver& arc );
	virtual void Unarchive( Archiver& arc );
};

inline void RandomSpeaker::Archive( Archiver& arc )
{
	TriggerSpeaker::Archive( arc );
	arc.WriteFloat( mindelay );
	arc.WriteFloat( maxdelay );
}

inline void RandomSpeaker::Unarchive( Archiver& arc )
{
	TriggerSpeaker::Unarchive( arc );
	mindelay = arc.ReadFloat();
	maxdelay = arc.ReadFloat();
}

class TriggerChangeLevel : public Trigger
{
protected:
	str map;
	str spawnspot;
	str changethread;

public:
	CLASS_PROTOTYPE( TriggerChangeLevel );

	TriggerChangeLevel();
	void            ChangeLevel( Event* ev );
	const char* Map( void );
	const char* SpawnSpot( void );
	virtual void Archive( Archiver& arc );
	virtual void Unarchive( Archiver& arc );
};

inline void TriggerChangeLevel::Archive( Archiver& arc )
{
	Trigger::Archive( arc );

	arc.WriteString( map );
	arc.WriteString( spawnspot );
	arc.WriteString( changethread );
}

inline void TriggerChangeLevel::Unarchive( Archiver& arc )
{
	Trigger::Unarchive( arc );

	arc.ReadString( &map );
	arc.ReadString( &spawnspot );
	arc.ReadString( &changethread );
}

class TriggerExit : public Trigger
{
//###
private:
	qboolean togglestate;
//###
public:
	CLASS_PROTOTYPE( TriggerExit );

	TriggerExit();
	void DisplayExitSign( Event* ev );
	//###
	virtual void ToggleState( Event* ev );
	virtual void Archive( Archiver& arc );
	virtual void Unarchive( Archiver& arc );
	//###
};

//###
inline void TriggerExit::Archive( Archiver& arc )
{
	Trigger::Archive( arc );

	arc.WriteBoolean( togglestate );
}

inline void TriggerExit::Unarchive( Archiver& arc )
{
	Trigger::Unarchive( arc );

	togglestate = arc.ReadBoolean();
}
//###

class TriggerUse : public Trigger
{
public:
	CLASS_PROTOTYPE( TriggerUse );

	TriggerUse();
};

class TriggerUseOnce : public TriggerUse
{
public:
	CLASS_PROTOTYPE( TriggerUseOnce );

	TriggerUseOnce();
};

class TriggerHurt : public TriggerUse
{
protected:
	float damage;

	void        Hurt( Event* ev );
	void        SetDamage( Event* ev );

public:
	CLASS_PROTOTYPE( TriggerHurt );

	TriggerHurt();
	virtual void Archive( Archiver& arc );
	virtual void Unarchive( Archiver& arc );
};

inline void TriggerHurt::Archive( Archiver& arc )
{
	Trigger::Archive( arc );

	arc.WriteFloat( damage );
}

inline void TriggerHurt::Unarchive( Archiver& arc )
{
	Trigger::Unarchive( arc );

	damage = arc.ReadFloat();
}

class TriggerDamageTargets : public Trigger
{
protected:
	float damage;

	void            DamageTargets( Event* ev );

public:
	CLASS_PROTOTYPE( TriggerDamageTargets );

	TriggerDamageTargets();
	void           PassDamage( Event* ev );
	virtual void Archive( Archiver& arc );
	virtual void Unarchive( Archiver& arc );
};

inline void TriggerDamageTargets::Archive( Archiver& arc )
{
	Trigger::Archive( arc );

	arc.WriteFloat( damage );
}

inline void TriggerDamageTargets::Unarchive( Archiver& arc )
{
	Trigger::Unarchive( arc );

	damage = arc.ReadFloat();
}

class TriggerFixedDamageTargets : public TriggerDamageTargets
{
public:
	CLASS_PROTOTYPE( TriggerFixedDamageTargets );
};

class TriggerParticles : public Trigger
{
protected:
	Vector dir;
	int particlestyle;
	int count;
	//###
	float particletime;
	int particlesize;
	int particlegrowrate;
	str spawntarget;
	int particlespeed;
	int particlespread;
	Vector particleaccel;
	float attenuation;
	//###

public:
	CLASS_PROTOTYPE( TriggerParticles );

	TriggerParticles();
	void         SpawnParticles( Event* ev );
	void            SpawnToggleParticles( Event* ev ); //###
	void         SetDirection( Event* ev );
	virtual void Archive( Archiver& arc );
	virtual void Unarchive( Archiver& arc );
};

inline void TriggerParticles::Archive( Archiver& arc )
{
	Trigger::Archive( arc );

	arc.WriteVector( dir );
	arc.WriteInteger( particlestyle );
	arc.WriteInteger( count );
	//###
	arc.WriteFloat( particletime );
	arc.WriteInteger( particlesize );
	arc.WriteInteger( particlegrowrate );
	arc.WriteString( spawntarget );
	arc.WriteInteger( particlespeed );
	arc.WriteInteger( particlespread );
	arc.WriteVector( particleaccel );
	arc.WriteFloat( attenuation );
	//###
}

inline void TriggerParticles::Unarchive( Archiver& arc )
{
	Trigger::Unarchive( arc );

	arc.ReadVector( &dir );
	particlestyle = arc.ReadInteger();
	count = arc.ReadInteger();
	//###
	particletime = arc.ReadFloat();
	particlesize = arc.ReadInteger();
	particlegrowrate = arc.ReadInteger();
	arc.ReadString( &spawntarget );
	particlespeed = arc.ReadInteger();
	particlespread = arc.ReadInteger();
	arc.ReadVector( &particleaccel );
	attenuation = arc.ReadFloat();
	//###
}

class RandomTriggerParticles : public TriggerParticles
{
protected:
	int state;
	float mindelay;
	float maxdelay;

	void  ScheduleParticles( void );
	void  RandomParticles( Event* ev );
	void  ToggleParticles( Event* ev );

public:
	CLASS_PROTOTYPE( RandomTriggerParticles );

	RandomTriggerParticles();
	virtual void Archive( Archiver& arc );
	virtual void Unarchive( Archiver& arc );
};

inline void RandomTriggerParticles::Archive( Archiver& arc )
{
	TriggerParticles::Archive( arc );

	arc.WriteInteger( state );
	arc.WriteFloat( mindelay );
	arc.WriteFloat( maxdelay );
}

inline void RandomTriggerParticles::Unarchive( Archiver& arc )
{
	TriggerParticles::Unarchive( arc );

	state = arc.ReadInteger();
	mindelay = arc.ReadFloat();
	maxdelay = arc.ReadFloat();
}

class TriggerThread : public Trigger
{
public:
	CLASS_PROTOTYPE( TriggerThread );

	TriggerThread();
};

class TriggerCameraUse : public TriggerUse
{
public:
	CLASS_PROTOTYPE( TriggerCameraUse );

	void TriggerCamera( Event* ev );
};

class TriggerMutate : public TriggerUse
{
protected:
	void        Mutate( Event* ev );

public:
	CLASS_PROTOTYPE( TriggerMutate );

	TriggerMutate();
};

class TriggerBox : public Trigger
{
public:
	CLASS_PROTOTYPE( TriggerBox );

	TriggerBox();
};

//### added 2015 stuff
class TriggeredHurt : public TriggerUse
{
protected:
	float damage;
	float hurttime;
	float hurtduration;

	void        Hurt( Event* ev );
	void        SetHurt( Event* ev );
	void        SetDamage( Event* ev );

public:
	CLASS_PROTOTYPE( TriggeredHurt );

	TriggeredHurt();
	virtual void Archive( Archiver& arc );
	virtual void Unarchive( Archiver& arc );
};

inline void TriggeredHurt::Archive( Archiver& arc )
{
	TriggerUse::Archive( arc );

	arc.WriteFloat( damage );
	arc.WriteFloat( hurttime );
	arc.WriteFloat( hurtduration );
}

inline void TriggeredHurt::Unarchive( Archiver& arc )
{
	TriggerUse::Unarchive( arc );

	damage = arc.ReadFloat();
	hurttime = arc.ReadFloat();
	hurtduration = arc.ReadFloat();
}

#endif /* trigger.h */
