553 lines · 10.2 KB · C
RawDownload
// g_utils.c -- misc utility functions for game module #include <u.h>#include <libc.h>#include <stdio.h>#include "../dat.h"#include "../fns.h"  void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result){	result[0] = point[0] + forward[0] * distance[0] + right[0] * distance[1];	result[1] = point[1] + forward[1] * distance[0] + right[1] * distance[1];	result[2] = point[2] + forward[2] * distance[0] + right[2] * distance[1] + distance[2];}  /*=============G_Find Searches all active entities for the next one that holdsthe matching string at fieldofs (use the FOFS() macro) in the structure. Searches beginning at the edict after from, or the beginning if NULLNULL will be returned if the end of the list is reached. =============*/edict_t *G_Find (edict_t *from, int fieldofs, char *match){	char	*s; 	if (!from)		from = g_edicts;	else		from++; 	for ( ; from < &g_edicts[globals.num_edicts] ; from++)	{		if (!from->inuse)			continue;		s = *(char **) ((byte *)from + fieldofs);		if (!s)			continue;		if (!cistrcmp (s, match))			return from;	} 	return NULL;}  /*=================findradius Returns entities that have origins within a spherical area findradius (origin, radius)=================*/edict_t *findradius (edict_t *from, vec3_t org, float rad){	vec3_t	eorg;	int		j; 	if (!from)		from = g_edicts;	else		from++;	for ( ; from < &g_edicts[globals.num_edicts]; from++)	{		if (!from->inuse)			continue;		if (from->solid == SOLID_NOT)			continue;		for (j=0 ; j<3 ; j++)			eorg[j] = org[j] - (from->s.origin[j] + (from->mins[j] + from->maxs[j])*0.5);		if (VectorLength(eorg) > rad)			continue;		return from;	} 	return NULL;}  /*=============G_PickTarget Searches all active entities for the next one that holdsthe matching string at fieldofs (use the FOFS() macro) in the structure. Searches beginning at the edict after from, or the beginning if NULLNULL will be returned if the end of the list is reached. =============*/#define MAXCHOICES	8 edict_t *G_PickTarget (char *targetname){	edict_t	*ent = NULL;	int		num_choices = 0;	edict_t	*choice[MAXCHOICES]; 	if (!targetname)	{		gi.dprintf("G_PickTarget called with NULL targetname\n");		return NULL;	} 	while(1)	{		ent = G_Find (ent, FOFS(targetname), targetname);		if (!ent)			break;		choice[num_choices++] = ent;		if (num_choices == MAXCHOICES)			break;	} 	if (!num_choices)	{		gi.dprintf("G_PickTarget: target %s not found\n", targetname);		return NULL;	} 	return choice[rand() % num_choices];}   void Think_Delay (edict_t *ent){	G_UseTargets (ent, ent->activator);	G_FreeEdict (ent);} /*==============================G_UseTargets the global "activator" should be set to the entity that initiated the firing. If self.delay is set, a DelayedUse entity will be created that will actuallydo the SUB_UseTargets after that many seconds have passed. Centerprints any self.message to the activator. Search for (string)targetname in all entities thatmatch (string)self.target and call their .use function ==============================*/void G_UseTargets (edict_t *ent, edict_t *activator){	edict_t		*t; //// check for a delay//	if (ent->delay)	{	// create a temp object to fire at a later time		t = G_Spawn();		t->classname = "DelayedUse";		t->nextthink = level.time + ent->delay;		t->think = Think_Delay;		t->activator = activator;		if (!activator)			gi.dprintf ("Think_Delay with no activator\n");		t->message = ent->message;		t->target = ent->target;		t->killtarget = ent->killtarget;		return;	}		//// print the message//	if ((ent->message) && !(activator->svflags & SVF_MONSTER))	{		gi.centerprintf (activator, "%s", ent->message);		if (ent->noise_index)			gi.sound (activator, CHAN_AUTO, ent->noise_index, 1, ATTN_NORM, 0);		else			gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0);	} //// kill killtargets//	if (ent->killtarget)	{		t = NULL;		while ((t = G_Find (t, FOFS(targetname), ent->killtarget)))		{			G_FreeEdict (t);			if (!ent->inuse)			{				gi.dprintf("entity was removed while using killtargets\n");				return;			}		}	} //// fire targets//	if (ent->target)	{		t = NULL;		while ((t = G_Find (t, FOFS(targetname), ent->target)))		{			// doors fire area portals in a specific way			if (!cistrcmp(t->classname, "func_areaportal") &&				(!cistrcmp(ent->classname, "func_door") || !cistrcmp(ent->classname, "func_door_rotating")))				continue; 			if (t == ent)			{				gi.dprintf ("WARNING: Entity used itself.\n");			}			else			{				if (t->use)					t->use (t, ent, activator);			}			if (!ent->inuse)			{				gi.dprintf("entity was removed while using targets\n");				return;			}		}	}}  /*=============TempVector This is just a convenience functionfor making temporary vectors for function calls=============*/float	*tv (float x, float y, float z){	static	int		index;	static	vec3_t	vecs[8];	float	*v; 	// use an array so that multiple tempvectors won't collide	// for a while	v = vecs[index];	index = (index + 1)&7; 	v[0] = x;	v[1] = y;	v[2] = z; 	return v;}  /*=============VectorToString This is just a convenience functionfor printing vectors=============*/char	*vtos (vec3_t v){	static	int		index;	static	char	str[8][32];	char	*s; 	// use an array so that multiple vtos won't collide	s = str[index];	index = (index + 1)&7; 	Com_sprintf (s, 32, "(%i %i %i)", (int)v[0], (int)v[1], (int)v[2]); 	return s;}  vec3_t VEC_UP		= {0, -1, 0};vec3_t MOVEDIR_UP	= {0, 0, 1};vec3_t VEC_DOWN		= {0, -2, 0};vec3_t MOVEDIR_DOWN	= {0, 0, -1}; void G_SetMovedir (vec3_t angles, vec3_t movedir){	if (VectorCompare (angles, VEC_UP))	{		VectorCopy (MOVEDIR_UP, movedir);	}	else if (VectorCompare (angles, VEC_DOWN))	{		VectorCopy (MOVEDIR_DOWN, movedir);	}	else	{		AngleVectors (angles, movedir, NULL, NULL);	} 	VectorClear (angles);}  float vectoyaw (vec3_t vec){	float	yaw;		if (/*vec[YAW] == 0 &&*/ vec[PITCH] == 0) 	{		yaw = 0;		if (vec[YAW] > 0)			yaw = 90;		else if (vec[YAW] < 0)			yaw = -90;	} 	else	{		yaw = (int) (atan2(vec[YAW], vec[PITCH]) * 180 / M_PI);		if (yaw < 0)			yaw += 360;	} 	return yaw;}  void vectoangles (vec3_t value1, vec3_t angles){	float	forward;	float	yaw, pitch;		if (value1[1] == 0 && value1[0] == 0)	{		yaw = 0;		if (value1[2] > 0)			pitch = 90;		else			pitch = 270;	}	else	{		if (value1[0])			yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);		else if (value1[1] > 0)			yaw = 90;		else			yaw = -90;		if (yaw < 0)			yaw += 360; 		forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);		pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);		if (pitch < 0)			pitch += 360;	} 	angles[PITCH] = -pitch;	angles[YAW] = yaw;	angles[ROLL] = 0;} char *G_CopyString (char *in){	char	*out;		out = gi.TagMalloc (strlen(in)+1, TAG_LEVEL);	strcpy (out, in);	return out;}  void G_InitEdict (edict_t *e){	e->inuse = true;	e->classname = "noclass";	e->gravity = 1.0;	e->s.number = e - g_edicts;} /*=================G_Spawn Either finds a free edict, or allocates a new one.Try to avoid reusing an entity that was recently freed, because itcan cause the client to think the entity morphed into something elseinstead of being removed and recreated, which can cause interpolatedangles and bad trails.=================*/edict_t *G_Spawn (void){	int			i;	edict_t		*e; 	e = &g_edicts[(int)maxclients->value+1];	for ( i=maxclients->value+1 ; i<globals.num_edicts ; i++, e++)	{		// the first couple seconds of server time can involve a lot of		// freeing and allocating, so relax the replacement policy		if (!e->inuse && ( e->freetime < 2 || level.time - e->freetime > 0.5 ) )		{			G_InitEdict (e);			return e;		}	}		if (i == game.maxentities)		gi.error ("ED_Alloc: no free edicts");			globals.num_edicts++;	G_InitEdict (e);	return e;} /*=================G_FreeEdict Marks the edict as free=================*/void G_FreeEdict (edict_t *ed){	gi.unlinkentity (ed);		// unlink from world 	if ((ed - g_edicts) <= (maxclients->value + BODY_QUEUE_SIZE))	{//		gi.dprintf("tried to free special edict\n");		return;	} 	memset (ed, 0, sizeof(*ed));	ed->classname = "freed";	ed->freetime = level.time;	ed->inuse = false;}  /*============G_TouchTriggers ============*/void	G_TouchTriggers (edict_t *ent){	int			i, num;	edict_t		*touch[MAX_EDICTS], *hit; 	// dead things don't activate triggers!	if ((ent->client || (ent->svflags & SVF_MONSTER)) && (ent->health <= 0))		return; 	num = gi.BoxEdicts (ent->absmin, ent->absmax, touch		, MAX_EDICTS, AREA_TRIGGERS); 	// be careful, it is possible to have an entity in this	// list removed before we get to it (killtriggered)	for (i=0 ; i<num ; i++)	{		hit = touch[i];		if (!hit->inuse)			continue;		if (!hit->touch)			continue;		hit->touch (hit, ent, NULL, NULL);	}} /*============G_TouchSolids Call after linking a new trigger in during gameplayto force all entities it covers to immediately touch it============*/void	G_TouchSolids (edict_t *ent){	int			i, num;	edict_t		*touch[MAX_EDICTS], *hit; 	num = gi.BoxEdicts (ent->absmin, ent->absmax, touch		, MAX_EDICTS, AREA_SOLID); 

Lines 1–500 of 553.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t