1159 lines · 25.3 KB · C
RawDownload
// sv_phys.c #include <math.h>#include "quakedef.h" /* pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move. onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSHbonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSScorpses are SOLID_NOT and MOVETYPE_TOSScrates are SOLID_BBOX and MOVETYPE_TOSSwalking monsters are SOLID_SLIDEBOX and MOVETYPE_STEPflying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY solid_edge items only clip against bsp models. */ cvar_t sv_friction = {"sv_friction","4",false,true};cvar_t sv_stopspeed = {"sv_stopspeed","100"};cvar_t sv_gravity = {"sv_gravity","800",false,true};cvar_t sv_maxvelocity = {"sv_maxvelocity","2000"};cvar_t sv_nostep = {"sv_nostep","0"}; #define MOVE_EPSILON 0.01 void SV_Physics_Toss (edict_t *ent); /*================SV_CheckAllEnts================*/void SV_CheckAllEnts (void){	int e;	edict_t *check; // see if any solid entities are inside the final position	check = NEXT_EDICT(sv.edicts);	for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))	{		if (check->free)			continue;		if (check->v.movetype == MOVETYPE_PUSH		|| check->v.movetype == MOVETYPE_NONE		|| check->v.movetype == MOVETYPE_NOCLIP)			continue; 		if (SV_TestEntityPosition (check))			Con_Printf ("entity in invalid position\n");	}} /*================SV_CheckVelocity================*/void SV_CheckVelocity (edict_t *ent){	int i; //// bound velocity//	for (i=0 ; i<3 ; i++)	{		if (IS_NAN(ent->v.velocity[i]))		{			Con_Printf ("Got a NaN velocity on %s\n", PR_GetString(ent->v.classname));			ent->v.velocity[i] = 0;		}		if (IS_NAN(ent->v.origin[i]))		{			Con_Printf ("Got a NaN origin on %s\n", PR_GetString(ent->v.classname));			ent->v.origin[i] = 0;		}		if (ent->v.velocity[i] > sv_maxvelocity.value)			ent->v.velocity[i] = sv_maxvelocity.value;		else if (ent->v.velocity[i] < -sv_maxvelocity.value)			ent->v.velocity[i] = -sv_maxvelocity.value;	}} /*=============SV_RunThink Runs thinking code if time. There is some play in the exact time the thinkfunction will be called, because it is called before any movement is donein a frame. Not used for pushmove objects, because they must be exact.Returns false if the entity removed itself.=============*/bool SV_RunThink (edict_t *ent){	float thinktime; 	thinktime = ent->v.nextthink;	if (thinktime <= 0 || thinktime > sv.time + host_frametime)		return true; 	if (thinktime < sv.time)		thinktime = sv.time; // don't let things stay in the past.								// it is possible to start that way								// by a trigger with a local time.	ent->v.nextthink = 0;	pr_global_struct->time = thinktime;	pr_global_struct->self = EDICT_TO_PROG(ent);	pr_global_struct->other = EDICT_TO_PROG(sv.edicts);	PR_ExecuteProgram (ent->v.think);	return !ent->free;} /*==================SV_Impact Two entities have touched, so run their touch functions==================*/void SV_Impact (edict_t *e1, edict_t *e2){	int old_self, old_other; 	old_self = pr_global_struct->self;	old_other = pr_global_struct->other; 	pr_global_struct->time = sv.time;	if (e1->v.touch && e1->v.solid != SOLID_NOT)	{		pr_global_struct->self = EDICT_TO_PROG(e1);		pr_global_struct->other = EDICT_TO_PROG(e2);		PR_ExecuteProgram (e1->v.touch);	} 	if (e2->v.touch && e2->v.solid != SOLID_NOT)	{		pr_global_struct->self = EDICT_TO_PROG(e2);		pr_global_struct->other = EDICT_TO_PROG(e1);		PR_ExecuteProgram (e2->v.touch);	} 	pr_global_struct->self = old_self;	pr_global_struct->other = old_other;} /*==================ClipVelocity Slide off of the impacting objectreturns the blocked flags (1 = floor, 2 = step / wall)==================*/#define STOP_EPSILON 0.1 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce){	float backoff;	float change;	int i, blocked; 	blocked = 0;	if (normal[2] > 0)		blocked |= 1; // floor	if (!normal[2])		blocked |= 2; // step 	backoff = DotProduct (in, normal) * overbounce; 	for (i=0 ; i<3 ; i++)	{		change = normal[i]*backoff;		out[i] = in[i] - change;		if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)			out[i] = 0;	} 	return blocked;} /*============SV_FlyMove The basic solid body movement clip that slides along multiple planesReturns the clipflags if the velocity was modified (hit something solid)1 = floor2 = wall / step4 = dead stopIf steptrace is not NULL, the trace of any vertical wall hit will be stored============*/#define MAX_CLIP_PLANES 5int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace){	int bumpcount, numbumps;	vec3_t dir;	float d;	int numplanes;	vec3_t planes[MAX_CLIP_PLANES];	vec3_t primal_velocity, original_velocity, new_velocity;	int i, j;	trace_t trace;	vec3_t end;	float time_left;	int blocked; 	numbumps = 4; 	blocked = 0;	VectorCopy (ent->v.velocity, original_velocity);	VectorCopy (ent->v.velocity, primal_velocity);	numplanes = 0; 	time_left = time; 	for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)	{		if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2])			break; 		for (i=0 ; i<3 ; i++)			end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i]; 		trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent); 		if (trace.allsolid)		{ // entity is trapped in another solid			VectorCopy (vec3_origin, ent->v.velocity);			return 3;		} 		if (trace.fraction > 0)		{ // actually covered some distance			VectorCopy (trace.endpos, ent->v.origin);			VectorCopy (ent->v.velocity, original_velocity);			numplanes = 0;		} 		if (trace.fraction == 1)			 break; // moved the entire distance 		if (!trace.ent)			Sys_Error ("SV_FlyMove: !trace.ent"); 		if (trace.plane.normal[2] > 0.7)		{			blocked |= 1; // floor			if (trace.ent->v.solid == SOLID_BSP)			{				ent->v.flags = (int)ent->v.flags | FL_ONGROUND;				ent->v.groundentity = EDICT_TO_PROG(trace.ent);			}		}		if (!trace.plane.normal[2])		{			blocked |= 2; // step			if (steptrace)				*steptrace = trace; // save for player extrafriction		} //// run the impact function//		SV_Impact (ent, trace.ent);		if (ent->free)			break; // removed by the impact function 		time_left -= time_left * trace.fraction; 	// cliped to another plane		if (numplanes >= MAX_CLIP_PLANES)		{ // this shouldn't really happen			VectorCopy (vec3_origin, ent->v.velocity);			return 3;		} 		VectorCopy (trace.plane.normal, planes[numplanes]);		numplanes++; //// modify original_velocity so it parallels all of the clip planes//		for (i=0 ; i<numplanes ; i++)		{			ClipVelocity (original_velocity, planes[i], new_velocity, 1);			for (j=0 ; j<numplanes ; j++)				if (j != i)				{					if (DotProduct (new_velocity, planes[j]) < 0)						break; // not ok				}			if (j == numplanes)				break;		} 		if (i != numplanes)		{ // go along this plane			VectorCopy (new_velocity, ent->v.velocity);		}		else		{ // go along the crease			if (numplanes != 2)			{// Con_Printf ("clip velocity, numplanes == %i\n",numplanes);				VectorCopy (vec3_origin, ent->v.velocity);				return 7;			}			CrossProduct (planes[0], planes[1], dir);			d = DotProduct (dir, ent->v.velocity);			VectorScale (dir, d, ent->v.velocity);		} //// if original velocity is against the original velocity, stop dead// to avoid tiny occilations in sloping corners//		if (DotProduct (ent->v.velocity, primal_velocity) <= 0)		{			VectorCopy (vec3_origin, ent->v.velocity);			return blocked;		}	} 	return blocked;} /*============SV_AddGravity ============*/void SV_AddGravity (edict_t *ent){	float ent_gravity; 	eval_t *val; 	val = GetEdictFieldValue(ent, "gravity");	if (val && val->_float)		ent_gravity = val->_float;	else		ent_gravity = 1.0;	ent->v.velocity[2] -= ent_gravity * sv_gravity.value * host_frametime;} /*=============================================================================== PUSHMOVE ===============================================================================*/ /*============SV_PushEntity Does not change the entities velocity at all============*/trace_t SV_PushEntity (edict_t *ent, vec3_t push){	trace_t trace;	vec3_t end; 	VectorAdd (ent->v.origin, push, end); 	if (ent->v.movetype == MOVETYPE_FLYMISSILE)		trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);	else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)	// only clip against bmodels		trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);	else		trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent); 	VectorCopy (trace.endpos, ent->v.origin);	SV_LinkEdict (ent, true); 	if (trace.ent)		SV_Impact (ent, trace.ent); 	return trace;} /*============SV_PushMove ============*/void SV_PushMove (edict_t *pusher, float movetime){	int i, e;	edict_t *check, *block;	vec3_t mins, maxs, move;	vec3_t entorig, pushorig;	int num_moved;	edict_t *moved_edict[MAX_EDICTS];	vec3_t moved_from[MAX_EDICTS]; 	if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])	{		pusher->v.ltime += movetime;		return;	} 	for (i=0 ; i<3 ; i++)	{		move[i] = pusher->v.velocity[i] * movetime;		mins[i] = pusher->v.absmin[i] + move[i];		maxs[i] = pusher->v.absmax[i] + move[i];	} 	VectorCopy (pusher->v.origin, pushorig); // move the pusher to it's final position 	VectorAdd (pusher->v.origin, move, pusher->v.origin);	pusher->v.ltime += movetime;	SV_LinkEdict (pusher, false); // see if any solid entities are inside the final position	num_moved = 0;	check = NEXT_EDICT(sv.edicts);	for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))	{		if (check->free)			continue;		if (check->v.movetype == MOVETYPE_PUSH		|| check->v.movetype == MOVETYPE_NONE		|| check->v.movetype == MOVETYPE_NOCLIP)			continue; 	// if the entity is standing on the pusher, it will definately be moved		if ( ! ( ((int)check->v.flags & FL_ONGROUND)		&& PROG_TO_EDICT(check->v.groundentity) == pusher) )		{			if ( check->v.absmin[0] >= maxs[0]			|| check->v.absmin[1] >= maxs[1]			|| check->v.absmin[2] >= maxs[2]			|| check->v.absmax[0] <= mins[0]			|| check->v.absmax[1] <= mins[1]			|| check->v.absmax[2] <= mins[2] )				continue; 		// see if the ent's bbox is inside the pusher's final position			if (!SV_TestEntityPosition (check))				continue;		} 	// remove the onground flag for non-players		if (check->v.movetype != MOVETYPE_WALK)			check->v.flags = (int)check->v.flags & ~FL_ONGROUND; 		VectorCopy (check->v.origin, entorig);		VectorCopy (check->v.origin, moved_from[num_moved]);		moved_edict[num_moved] = check;		num_moved++; 		// try moving the contacted entity		pusher->v.solid = SOLID_NOT;		SV_PushEntity (check, move);		pusher->v.solid = SOLID_BSP; 	// if it is still inside the pusher, block		block = SV_TestEntityPosition (check);		if (block)		{ // fail the move			if (check->v.mins[0] == check->v.maxs[0])				continue;			if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)			{ // corpse				check->v.mins[0] = check->v.mins[1] = 0;				VectorCopy (check->v.mins, check->v.maxs);				continue;			} 			VectorCopy (entorig, check->v.origin);			SV_LinkEdict (check, true); 			VectorCopy (pushorig, pusher->v.origin);			SV_LinkEdict (pusher, false);			pusher->v.ltime -= movetime; 			// if the pusher has a "blocked" function, call it			// otherwise, just stay in place until the obstacle is gone			if (pusher->v.blocked)			{				pr_global_struct->self = EDICT_TO_PROG(pusher);				pr_global_struct->other = EDICT_TO_PROG(check);				PR_ExecuteProgram (pusher->v.blocked);

Lines 1–500 of 1159.

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