/*
Copyright (C) 1996-2001 Id Software, Inc.
Copyright (C) 2002-2009 John Fitzgibbons and others
Copyright (C) 2010-2014 QuakeSpasm developers

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#ifndef _QUAKE_PROGS_H
#define _QUAKE_PROGS_H

#include "pr_comp.h"	/* defs shared with qcc */
#include "progdefs.h"	/* generated by program cdefs */

typedef union eval_s
{
	string_t	string;
	float		_float;
	float		vector[3];
	func_t		function;
	int		_int;
	int		edict;
} eval_t;

#define	MAX_ENT_LEAFS	32
typedef struct edict_s
{
	qboolean	free;
	link_t		area;			/* linked to a division node or leaf */

	unsigned int		num_leafs;
	int		leafnums[MAX_ENT_LEAFS];

	entity_state_t	baseline;
	unsigned char	alpha;			/* johnfitz -- hack to support alpha since it's not part of entvars_t */
	qboolean	sendinterval;		/* johnfitz -- send time until nextthink to client for better lerp timing */

	float		freetime;		/* sv.time when the object was freed */
	entvars_t	v;			/* C exported fields from progs */

	/* other fields from progs come immediately after */
} edict_t;

#define	EDICT_FROM_AREA(l)	STRUCT_FROM_LINK(l,edict_t,area)

//============================================================================

extern	dprograms_t	*progs;
extern	dfunction_t	*pr_functions;
extern	dstatement_t	*pr_statements;
extern	globalvars_t	*pr_global_struct;
extern	float		*pr_globals;	/* same as pr_global_struct */
extern	ddef_t		*pr_fielddefs;	//yay reflection.

extern	int		pr_edict_size;	/* in bytes */


void PR_Init (void);

void PR_ExecuteProgram (func_t fnum);
void PR_LoadProgs (void);

//from pr_ext.c
void PR_EnableExtensions(ddef_t *pr_globaldefs);	//adds in the extra builtins etc
void PR_AutoCvarChanged(cvar_t *var);				//updates the autocvar_ globals when their cvar is changed
void PR_ShutdownExtensions(void);					//nooooes!
void PR_DumpPlatform_f(void);						//console command: writes out a qsextensions.qc file
//special hacks...
int PF_SV_ForceParticlePrecache(const char *s);
int SV_Precache_Model(const char *s);
void PR_spawnfunc_misc_model(edict_t *self);

//from pr_edict, for pr_ext. reflection is messy.
qboolean	ED_ParseEpair (void *base, ddef_t *key, const char *s);
const char *PR_UglyValueString (int type, eval_t *val);
ddef_t *ED_FindField (const char *name);
ddef_t *ED_FindGlobal (const char *name);
dfunction_t *ED_FindFunction (const char *fn_name);

const char *PR_GetString (int num);
int PR_SetEngineString (const char *s);
int PR_AllocString (int bufferlength, char **ptr);
void PR_ClearEngineString(int num);

void PR_Profile_f (void);

edict_t *ED_Alloc (void);
void ED_Free (edict_t *ed);

void ED_Print (edict_t *ed);
void ED_Write (FILE *f, edict_t *ed);
const char *ED_ParseEdict (const char *data, edict_t *ent);

void ED_WriteGlobals (FILE *f);
void ED_ParseGlobals (const char *data);

void ED_LoadFromFile (const char *data);

/*
#define EDICT_NUM(n)		((edict_t *)(sv.edicts+ (n)*pr_edict_size))
#define NUM_FOR_EDICT(e)	(((byte *)(e) - sv.edicts) / pr_edict_size)
*/
edict_t *EDICT_NUM(int n);
int NUM_FOR_EDICT(edict_t *e);

#define	NEXT_EDICT(e)		((edict_t *)( (byte *)e + pr_edict_size))

#define	EDICT_TO_PROG(e)	((byte *)e - (byte *)sv.edicts)
#define PROG_TO_EDICT(e)	((edict_t *)((byte *)sv.edicts + e))

#define	G_FLOAT(o)		(pr_globals[o])
#define	G_INT(o)		(*(int *)&pr_globals[o])
#define	G_EDICT(o)		((edict_t *)((byte *)sv.edicts+ *(int *)&pr_globals[o]))
#define G_EDICTNUM(o)		NUM_FOR_EDICT(G_EDICT(o))
#define	G_VECTOR(o)		(&pr_globals[o])
#define	G_STRING(o)		(PR_GetString(*(string_t *)&pr_globals[o]))
#define	G_FUNCTION(o)		(*(func_t *)&pr_globals[o])

#define	E_FLOAT(e,o)		(((float*)&e->v)[o])
#define	E_INT(e,o)		(*(int *)&((float*)&e->v)[o])
#define	E_VECTOR(e,o)		(&((float*)&e->v)[o])
#define	E_STRING(e,o)		(PR_GetString(*(string_t *)&((float*)&e->v)[o]))

extern	int		type_size[8];

typedef void (*builtin_t) (void);
extern	builtin_t	*pr_builtins;
extern	int		pr_numbuiltins;

extern	int		pr_argc;

extern	qboolean	pr_trace;
extern	dfunction_t	*pr_xfunction;
extern	int		pr_xstatement;

extern	unsigned short	pr_crc;

void PR_RunError (const char *error, ...) __attribute__((__format__(__printf__,1,2), __noreturn__));

void ED_PrintEdicts (void);
void ED_PrintNum (int ent);

eval_t *GetEdictFieldValue(edict_t *ed, int fldofs);	//handles invalid offsets with a null
int ED_FindFieldOffset (const char *name);


//from pr_cmds, no longer static so that pr_ext can use them.
sizebuf_t *WriteDest (void);
char *PR_GetTempString (void);
char *PF_VarString (int	first);
#define	STRINGTEMP_BUFFERS		16
#define	STRINGTEMP_LENGTH		1024
void PF_Fixme(void);	//the 'unimplemented' builtin. woot.

extern struct pr_extfuncs_s
{	//various global qc entry points that might be called by the engine, if set.
	func_t		endframe;
	func_t		parseclientcommand;
} pr_extfuncs;
extern	cvar_t	pr_checkextension;	//if 0, extensions are disabled (unless they'd be fatal, but they're still spammy)

extern struct pr_extfields_s
{	//various fields that might be wanted by the engine. -1 == invalid
	//I should probably use preprocessor magic for this list or something
	int		items2;
	int		gravity;
	int		alpha;
	int		movement;
	int		viewmodelforclient;
	int		traileffectnum;
	int		emiteffectnum;
} pr_extfields;

#endif	/* _QUAKE_PROGS_H */

