/*
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.hpp"	/* defs shared with qcc */
#include "progdefs.hpp"	/* 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
{
	bool	free;
	link_t		area;			/* linked to a division node or leaf */

	int		wid;
	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 */
	unsigned char	scale;			/* Quakespasm: added for model scale support. */
	bool	sendinterval;		/* johnfitz -- send time until nextthink to client for better lerp timing */
	float		oldframe;
	float		oldthinktime;

	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	int		pr_edict_size;	/* in bytes */


void PR_Init (void);

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

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

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);

void ED_ParseEdict(std::istringstream &ss, edict_t *ent);

void ED_WriteGlobals (FILE *f);
void ED_ParseGlobals (std::istringstream &ss);

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);
int NUM_FOR_EDICT(edict_t*);

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

#define	EDICT_TO_PROG(e)	(int)((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]))

#define NUM_TYPE_SIZES 8
extern const int	type_size[NUM_TYPE_SIZES];

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

/* for 2021 re-release */
typedef struct {
	const char *name;
	int first_statement;
	int patch_statement;
} exbuiltin_t;

extern	int		pr_argc;

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

extern	unsigned short	pr_crc;

FUNC_NORETURN void PR_RunError (const char *error, ...) FUNC_PRINTF(1,2);
#ifdef __WATCOMC__
#pragma aux PR_RunError aborts;
#endif

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

eval_t *GetEdictFieldValue(edict_t *ed, const char *field);

#endif	/* QUAKE_PROGS_H */
