#ifndef	_COM_H_
#define	_COM_H_

//	for C++ classes that will be used in other DLLs
#ifndef	DllExport_Plus
#define DllExport_Plus __declspec(dllexport)
#endif
//	for functions the Quake engine calls (not in C++)
#ifndef	DllExport
#define DllExport	extern "C"	__declspec( dllexport )
#endif

#include	"vector.h"

///////////////////////////////////////////////////////////////////////////////
//	defines
///////////////////////////////////////////////////////////////////////////////

//	com_heap.cpp
#define	MEM_HUNK		0	// removed each time a level ends
#define	MEM_MALLOC		1	// freeable, removed each time a level ends
#define	MEM_PERMANENT	2	// freeable, lasts between levels, removed when DLLs exit

//	com_vector.cpp
#define M_PI		3.14159265358979323846	// matches value in gcc v2 math.h

//	com_sub.cpp
#define	DAMAGE_NONE				0x00000000
#define	DAMAGE_EXPLOSION		0x00000001
#define	DAMAGE_INERTIAL			0x00000002
#define	DAMAGE_SQUISH			0x00000004
#define	DAMAGE_DROWN			0x00000008
#define	DAMAGE_LAVA				0x00000010
#define	DAMAGE_SLIME 			0x00000020
#define	DAMAGE_FALLING			0x00000040
#define	DAMAGE_POISON			0x00000080
#define	DAMAGE_TELEFRAG			0x00000100
#define	DAMAGE_TRIGGER			0x00000200
#define	DAMAGE_SIDEWINDER		0x00000400

#define	DAMAGE_ONLY_TYPES		0x00FFFFFF	//	mask for all damage types

#define	DAMAGE_NO_VELOCITY		0x01000000	//	Velocity will not be applied
#define	DAMAGE_NO_PROTECTION	0x02000000	//	Nothing will prevent damage, not even llama mode
#define	DAMAGE_DIR_TO_ATTACKER	0x04000000	//	override dir parameter, compute dir from attacker to target
#define	DAMAGE_DIR_TO_INFLICTOR	0x08000000	//	override dir parameter, use velocity of inflictor
#define	DAMAGE_INFLICTOR_VEL	0x10000000	//	override dir parameter, use velocity of inflictor
#define	DAMAGE_NO_BLOOD			0x20000000	//	don't spawn blood particles

#define	DAMAGE_ONLY_FLAGS		0xFF000000	//	mask for all damage flags

#define	PITCH	0
#define	YAW		1
#define	ROLL	2

//	com_friction.cpp
#define	FR_SPIRAL		0x00000001
#define	FR_SEMIFLOAT	0x00000002
#define	FR_FLOAT		0x00000004

///////////////////////////////////////////////////////////////////////////////
//	typedefs
///////////////////////////////////////////////////////////////////////////////

//	com_sub.cpp
typedef struct
{
	// all these fields need to remain the same for compatibility between weapons
	char	*name;
	void	(*use)(struct userInventory_s *ptr, userEntity_t *user);
	void	*(*command)(struct userInventory_s *ptr, char *commandStr, void *data);
	void	*precache;
	void	*dummy2;
	void	*dummy3;
	void	*dummy4;

	// ammount of ammo left
	int		count;
} ammo_t;

typedef struct
{
	// all these fields need to remain the same for compatibility between weapons
	char    *name;
	void    (*use)(struct userInventory_s *ptr, userEntity_t *user);
	void	*(*command)(struct userInventory_s *ptr, char *commandStr, void *data);
	void	*precache;
	void	*dummy3;
	void	*dummy4;

	// pointer to the ammo inventory
	ammo_t	*ammo;
} weapon_t;

//	com_list.cpp
typedef struct	listNode_s
{
	listNode_s	*prev;
	listNode_s	*next;

	char		type;

	void		*ptr;	// pointer to this node's data
} listNode_t;

typedef	struct	listHeader_s
{
	listNode_t	*head;
	listNode_t	*tail;

	int					count;
} listHeader_t;

//	com_friction.cpp
typedef struct
{
	int  	last_content;	// the content type during the last frame
	float	change_time;	// how often the object is affected by friction

	float	size_scale;		// how large the object is, Quake grenade = 1.0
	float	mass_scale;		// how heavy the object is, Quake grenade = 1.0

	//Vector	last_pos;		// origin of the object during the last frame
	Vector	liquid_pos;		// location of the object when it first encountered liquid

	float	max_vel;		// upper limit on object's velocity
	int		flags;			// various attribute flags

	// fields for special movement types
	float	spiral_dir;

	// sounds to play when we enter or leave a content
	char	*enter_sound;
	char	*exit_sound;
} frictionHook_t;

///////////////////////////////////////////////////////////////////////////////
//	common export type
///////////////////////////////////////////////////////////////////////////////

typedef	struct	comon_export_s
{
//	memory management routines, com_heap.cpp
	void	*(*malloc)					(unsigned long size, char mem_type);
	void	(*free)						(void *ptr);
	void	(*free_most)				(void);
	void	(*free_all)					(void);
	void	(*free_type)				(char mem_type);
	unsigned long	(*count_mem_type)	(char mem_type);
	void	*(*malloc_hook)				(unsigned long size, int mem_type);

//	generic list functions, com_list.cpp
	listHeader_t	*(*list_init)		(listHeader_t *list);
	void			(*list_kill)		(listHeader_t *list);
	listNode_t		*(*list_new_node)	(void);
	void			(*list_add_node)	(void *ptr, listHeader_t *list, char mem_type);
	void			(*list_delete_node)	(listHeader_t *list, listNode_t *node);
	void			(*list_remove_node)	(void *ptr, listHeader_t *list);
	void			*(*list_ptr)		(listNode_t *node);
	listNode_t		*(*list_node_next)	(listNode_t *node);
	listNode_t		*(*list_node_prev)	(listNode_t *node);

//	game functions, com_sub.cpp
	float	(*AngleMod)		(float ang);
	float	(*VecToYaw)		(Vector &vec);
	void	(*VecToAngles)	(Vector &vec1, Vector &vec2);
	float	(*YawDiff)		(float facing_yaw, float to_targ_yaw);
	void	(*BestDelta)	(float start_angle, float end_angle, float *best_delta, float *angle_diff);

	void	(*GetMinsMaxs)	(userEntity_t *self, Vector &org, Vector &mins, Vector &maxs);
	void	(*ChangeYaw)	(userEntity_t *ent);
	void	(*ChangePitch)	(userEntity_t *ent);
	void	(*ChangeRoll)	(userEntity_t *ent);

	void	(*SetMovedir)	(userEntity_t *self);
	void	(*SpawnMarker)	(userEntity_t *self, Vector &org, char *model_name, float time);

//	void	(*Damage)		(userEntity_t *target, userEntity_t *inflictor, userEntity_t *attacker, 
//							float damage, int damage_type);
	void	(*Damage)		(userEntity_t *target, userEntity_t *inflictor, userEntity_t *attacker, 
							vec3_t point_of_impact, vec3_t damage_vec, float damage, unsigned long damage_flags);
	int		(*CanDamage)	(userEntity_t *target, userEntity_t *inflictor);
	int		(*RadiusDamage)	(userEntity_t *inflictor, userEntity_t *attacker, userEntity_t *ignore, 
							float damage, unsigned long damage_flags);
	int		(*ValidTouch)	(userEntity_t *self, userEntity_t *other);
	void	(*UseTargets)	(userEntity_t *self, userEntity_t *other, userEntity_t *activator);
	void	(*Health)		(userEntity_t *self, float give, float max_health);
	void	(*Respawn)		(userEntity_t *self);

// routines for vec3_t (Quake engine) vector types
	void	(*ZeroVector)	(vec3_t v);
	void	(*SetVector)	(vec3_t v, float f1, float f2, float f3);
	void	(*MultVector)	(vec3_t v, float f1, vec3_t v2);
	void	(*CopyVector)	(vec3_t v, vec3_t v2);
	char	*(*vtos)			(vec3_t v);
	char	*(*vtos1)		(Vector v);

	int				(*Visible)				(userEntity_t *self, userEntity_t *ent);
	userEntity_t	*(*FindEntity)			(char *name);
	userEntity_t	*(*FindClosestEntity)	(userEntity_t *self, char *name);
	userEntity_t	*(*FindTarget)			(char *name);
	userEntity_t	*(*DeathmatchSpawnPoint)(char *className);
	userEntity_t	*(*SelectSpawnPoint)	(char *className, char *target);


	void	(*ClientPrint)					(userEntity_t *self, char *msg);
	void	(*AmbientVolume)				(userEntity_t *self, Vector &org, int volume);
	void	(*SetRespawn)					(userEntity_t *self, float time, int reset_ambient, int ambient_vol);

	void	(*CalcBoosts)					(userEntity_t *self);
	void	(*UpdateClientAmmo)				(userEntity_t *self);

	void	(*Showbbox)						(userEntity_t *self, Vector &org, Vector &mins, Vector &maxs);
	int		(*GetFrames)					(userEntity_t *self, char *seq_name, int *startFrame, int *endFrame);

	userEntity_t	*(*ClientVisible)		(userEntity_t *self);

	void	(*Warning)						(char *fmt, ...);
	void	(*Error)						(char *fmt, ...);

	void	(*SetClientModels)				(userEntity_t *self, userEntity_t *head, userEntity_t *torso, 
											userEntity_t *legs, userEntity_t *weapon);
	float	(*AngleDiff)					(float ang1, float ang2);
	void	(*Normal)						(Vector v1, Vector v2, Vector v3, Vector &out);
	void	(*DrawLine)						 (userEntity_t *self, Vector org, Vector end, float lifetime);

	//	FIXME:	merge these with thinkFuncs...
	userEntity_t	*(*SpawnFakeEntity)		(void);
	void			(*RemoveFakeEntity)		(userEntity_t *ent);

	void	(*Poison)						(userEntity_t *target, float damage, float time, float interval);
	void	(*TeleFrag)						(userEntity_t *self, float damage);
	int		(*GenID)						(void);

//	com_friction.cpp
	void			(*friction_apply)		(userEntity_t *self, frictionHook_t *fhook);
	frictionHook_t	*(*friction_init)		(userEntity_t *self, frictionHook_t *fhook);
	void			(*friction_set_sounds)	(userEntity_t *self, frictionHook_t *fhook, char *enter, char *exit);
	void			(*friction_set_physics)	(userEntity_t *self, frictionHook_t *fhook, float size, float mass, 
											float max_vel, int flags);
	void			(*friction_remove)		(frictionHook_t *fhook);
}	common_export_t;

#endif