Beispiel #1
0
// Returns distance or 9999 if invalid for some reason
static float
Cam_TryFlyby (player_state_t * self, player_state_t * player, vec3_t vec,
			  qboolean checkvis)
{
	float       len;
	trace_t     trace;
	vec3_t      v;

	vectoangles (vec, v);
	VectorCopy (v, pmove.angles);
	VectorNormalize (vec);
	VectorMultAdd (player->pls.origin, 800, vec, v);
	// v is endpos
	// fake a player move
	trace = Cam_DoTrace (player->pls.origin, v);
	if ( /* trace.inopen || */ trace.inwater)
		return 9999;
	VectorCopy (trace.endpos, vec);
	len = VectorDistance (trace.endpos, player->pls.origin);

	if (len < 32 || len > 800)
		return 9999;
	if (checkvis) {
		trace = Cam_DoTrace (self->pls.origin, vec);
		if (trace.fraction != 1 || trace.inwater)
			return 9999;

		len = VectorDistance (trace.endpos, self->pls.origin);
	}

	return len;
}
char *AIFunc_Heinrich_MeleeStart(cast_state_t *cs) {
	gentity_t *ent = &g_entities[cs->entityNum];
	gentity_t *enemy = &g_entities[cs->enemyNum];
	int rnd;
	static int lastStomp;

	if (cs->enemyNum < 0) {
		return NULL;
	}
	// record weapon fire
	cs->weaponFireTimes[cs->weaponNum] = level.time;
	// face them
	AICast_AimAtEnemy(cs);
	// clear flags
	cs->aiFlags &= ~(AIFL_MISCFLAG1|AIFL_MISCFLAG2);
	// decide which attack to use
	if (VectorDistance(ent->r.currentOrigin, enemy->r.currentOrigin) < 60) {
		rnd = 0;   // sword slash up close
	} else if (VectorDistance(ent->r.currentOrigin, enemy->r.currentOrigin) >= HEINRICH_SLASH_RANGE) {
		rnd = 1;   // too far away, stomp
	} else {
		// pick at random
		rnd = rand() % 2;
	}

	switch (rnd) {
	case 0:
	{
		int rnd = rand() % 3;

		switch (rnd) {
		case 0:
			return AIFunc_Heinrich_SwordSideSlashStart(cs);
		case 1:
			return AIFunc_Heinrich_SwordKnockbackStart(cs);
		case 2:
			return AIFunc_Heinrich_SwordLungeStart(cs);
		}
	}

	case 1:
		// dont do stomp too often
		if (lastStomp > level.time - 12000) { // plenty of time to let debris disappear
			return NULL;
		}

		lastStomp = level.time;
		cs->aiFlags |= AIFL_SPECIAL_FUNC;
		// sound
		G_AddEvent(ent, EV_GENERAL_SOUND, heinrichSoundIndex[HEINRICH_EARTHQUAKE_START]);
		// play the anim
		BG_PlayAnimName(&ent->client->ps, "attack7", ANIM_BP_BOTH, qtrue, qfalse, qtrue);
		// start the func
		cs->aifunc = AIFunc_Heinrich_Earthquake;
		return "AIFunc_Heinrich_Earthquake";
	}
	// shutup compiler
	return NULL;
}
Beispiel #3
0
/*
=============
AI_AvoidDangerousEntity

  Alerts all AI in vaccinity of the given ent, so they can flee if possible
=============
*/
void AI_AvoidDangerousEntity( edict_t *ent )
{
	int i;
	float	old_time;

	if (deathmatch->value)
		return;

	ent->s.origin[2] += 4;
	old_time = level.time;

	for (i=1; i<level.num_characters; i++)
	{
		if (!level.characters[i] || level.characters[i]->health <= 0)
			continue;

		if (level.characters[i] == ent)
			continue;

		if (!ent->client && VectorDistance( level.characters[i]->s.origin, ent->s.origin ) > ent->dmg_radius*2)
			continue;

		// if they are already fleeing this ent, check our fleeing position
		if (level.characters[i]->cast_info.aiflags & AI_TAKE_COVER)
		{
			if (level.characters[i]->combat_goalent && !CanDamage( level.characters[i]->combat_goalent, ent ))
				continue;
		}

		if (!gi.inPVS( level.characters[i]->s.origin, ent->s.origin ))
			continue;

		if ((VectorDistance( level.characters[i]->s.origin, ent->s.origin ) > 64) && !CanDamage( level.characters[i], ent))
			continue;

//		gi.dprintf( "RUN FOR YOUR LIVES!!!!\n" );

		level.characters[i]->last_gethidepos = 0;
		level.time -= 0.1;		// so we bypass speed optimization

		AI_ForceTakeCover( level.characters[i], ent, (ent->client == NULL) );
		ent->noise_time = level.time;

	}

	level.time = old_time;
	ent->s.origin[2] -= 4;
}
Beispiel #4
0
void CCam::satchelCam(camInfo_t *ci)
{
	int satchelEntityNum = Engine.findSatchel();

	// If don't find satchel or is out of range to fire
	if (satchelEntityNum == -1 || VectorDistance(eth32.cg.refdef->vieworg, eth32.cg.gentity[satchelEntityNum].lerpOrigin) > 2000)
		return;

	int w = ci->x2 - ci->x1;
	int h = ci->y2 - ci->y1;

	// Set the view
	memcpy(&camRefDef, &eth32.cg.refdef, sizeof(refdef_t));
	// fov
	camRefDef.fov_x = (w>h) ? ci->fov : ci->fov * w / h;
	camRefDef.fov_y = (h>w) ? ci->fov : ci->fov * h / w;
	// origin
	VectorCopy(eth32.cg.gentity[satchelEntityNum].lerpOrigin, camRefDef.vieworg);

	camRefDef.vieworg[ROLL] += ci->distance;
	// view angle
	vec3_t camAngle;
	VectorCopy(eth32.cg.refdefViewAngles, camAngle);
	camAngle[PITCH] = ci->angle;
	AnglesToAxis(camAngle, camRefDef.viewaxis);

	// Draw the spycam
	drawCam(ci->x1, ci->y1, w, h, &camRefDef, qfalse);
}
Beispiel #5
0
void cashroll_animate( edict_t *self )
{
	// reduce XY velocity (air friction)
	self->velocity[0] *= 0.9;
	self->velocity[1] *= 0.9;

	if (level.time > (self->timestamp))
	{
		cash_kill( self );
		return;
	}

	if (self->movetype != MOVETYPE_NONE)
	{

		if (VectorDistance( self->s.origin, self->pos1 ) < 1)
			self->count++;
		else
			self->count = 0;

		VectorCopy( self->s.origin, self->pos1 );

		if (self->count > 2)	// rested for 2 frames
		{
			VectorClear( self->velocity );
			VectorClear( self->avelocity );
			self->s.angles[PITCH] = 0;
			self->s.angles[ROLL] = 0;

			self->movetype = MOVETYPE_NONE;
		}
	}

	self->nextthink = level.time + 0.1;
}
Beispiel #6
0
void R_MeshQueue_AddTransparent(dptransparentsortcategory_t category, const vec3_t center, void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist), const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
{
	meshqueue_t *mq;
	if (mqt_count >= mqt_total || !mqt_array)
	{
		int newtotal = max(1024, mqt_total * 2);
		meshqueue_t *newarray = (meshqueue_t *)Mem_Alloc(cls.permanentmempool, newtotal * sizeof(meshqueue_t));
		if (mqt_array)
		{
			memcpy(newarray, mqt_array, mqt_total * sizeof(meshqueue_t));
			Mem_Free(mqt_array);
		}
		mqt_array = newarray;
		mqt_total = newtotal;
	}
	mq = &mqt_array[mqt_count++];
	mq->callback = callback;
	mq->ent = ent;
	mq->surfacenumber = surfacenumber;
	mq->rtlight = rtlight;
	mq->category = category;
	if (r_transparent_useplanardistance.integer)
		mq->dist = DotProduct(center, r_refdef.view.forward) - mqt_viewplanedist;
	else
		mq->dist = VectorDistance(center, r_refdef.view.origin);
	mq->next = NULL;
	mqt_viewmaxdist = max(mqt_viewmaxdist, mq->dist);
}
Beispiel #7
0
itementity_t *CItemMng::SearchShortestEntity( vec3_t pos )
{
	itementity_t *entity;
	float minDist, dist;
	
	int selected = -1;
	
	minDist = 100000000.0f;
	entity = m_linked;

	while( entity )
	{
		dist = VectorDistance( pos, entity->origin );
		if( dist < minDist )
		{
			minDist = dist;
			selected = entity->idx;
		}

		entity = entity->next;
	}

	if( selected < 0 ) return NULL;
	return &m_entities[ selected ];
}
char *AIFunc_Heinrich_RaiseDead(cast_state_t *cs) {
	int i;
	gentity_t *ent = &g_entities[cs->entityNum];
	gentity_t *enemy = &g_entities[cs->enemyNum];
	gentity_t *trav, *closest;
	float closestDist, dist;
	cs->aiFlags |= AIFL_SPECIAL_FUNC;

	if (cs->enemyNum < 0) {
		if (!ent->client->ps.torsoTimer) {
			return AIFunc_DefaultStart(cs);
		}

		return NULL;
	}
	// record weapon fire
	cs->weaponFireTimes[cs->weaponNum] = level.time;

	if (!ent->client->ps.torsoTimer) {
		return AIFunc_DefaultStart(cs);
	}

	if (ent->count2 && lastRaise < level.time - HEINRICH_RAISEDEAD_DELAY) {
		lastRaise = level.time;
		// summons the closest warrior
		closest = NULL;
		closestDist = 0;   // shutup the compiler
		for (i = 0, trav = g_entities; i < level.maxclients; i++, trav++) {
			if (!trav->inuse) {
				continue;
			}

			if (!trav->aiInactive) {
				continue;
			}

			if (trav->aiCharacter != AICHAR_WARZOMBIE) {
				continue;
			}

			dist = VectorDistance(trav->s.pos.trBase, enemy->r.currentOrigin);

			if (!closest || dist < closestDist) {
				closest = trav;
				closestDist = dist;
			}
		}

		if (closest) {
			closest->AIScript_AlertEntity(closest);
			// make them aware of the player
			AICast_UpdateVisibility(closest, enemy, qtrue, qtrue);
			// reduce the count
			ent->count2--;
		}
	}

	return NULL;
}
char *AIFunc_ZombieFlameAttack( cast_state_t *cs ) {
	gentity_t *ent;
	//
	ent = &g_entities[cs->entityNum];
	//
	ent->s.onFireEnd = level.time + 2000;
	//
	if ( ent->health < 0 ) {
		ent->s.onFireEnd = 0;
		return AIFunc_DefaultStart( cs );
	}
	//
	if ( cs->bs->enemy < 0 ) {
		ent->s.onFireEnd = level.time + 1500;
		ent->client->ps.torsoTimer = 0;
		ent->client->ps.legsTimer = 0;
		return AIFunc_DefaultStart( cs );
	}

	// if outside range, move closer
	if ( VectorDistance( cs->bs->origin, cs->vislist[cs->bs->enemy].visible_pos ) > ZOMBIE_FLAME_RADIUS ) {
		ent->s.onFireEnd = level.time + 1500;
		ent->client->ps.torsoTimer = 0;
		ent->client->ps.legsTimer = 0;
		return AIFunc_DefaultStart( cs );
	}
	// we are firing this weapon, so record it
	cs->weaponFireTimes[WP_MONSTER_ATTACK1] = level.time;
	// once an attack has started, only abort once the player leaves our view, or time runs out
	if ( cs->thinkFuncChangeTime < level.time - ZOMBIE_FLAME_DURATION ) {

		// finish this attack
		ent->client->ps.torsoTimer = 0;
		ent->client->ps.legsTimer = 0;
		return AIFunc_DefaultStart( cs );

	} else {

		ent->client->ps.torsoTimer = 400;
		//ent->client->ps.legsTimer = 400;

		// draw the client-side effect
		ent->client->ps.eFlags |= EF_MONSTER_EFFECT3;

		// keep facing them
		AICast_AimAtEnemy( cs );

		// look slightly downwards since animation is facing upwards slightly
		cs->bs->ideal_viewangles[PITCH] += 10;
	}
	//
	//
	return NULL;
}
Beispiel #10
0
qboolean TooCloseToOtherSpawnpoint ( int flagnum, vec3_t origin )
{
	int i = 0;

	for (i = 0;i < flag_list[flagnum].num_spawnpoints;i++)
	{
		if (VectorDistance(flag_list[flagnum].spawnpoints[i], origin) < 64)
			return qtrue;
	}

	return qfalse;
}
Beispiel #11
0
static void LookingAtEnemyLogic(gedict_t* self) {
	if (Visible_360(self, self->fb.look_object)) {
		if (self->fb.look_object == &g_edicts[self->s.v.enemy]) {
			self->fb.enemy_dist = VectorDistance (self->fb.look_object->s.v.origin, self->s.v.origin);
		}
		else if (PAST(enemy_time)) {
			ClearLookObject(self);
		}
	}
	else {
		ClearLookObject(self);
	}
}
Beispiel #12
0
void GTH_GetRealPosition( vec3_t position, float dist )
{
	vec3_t pos;
	float realDist;
	
	realDist = VectorDistance( position, g_pApp->m_myCharacter->position );

	if( dist > realDist ) return;

	VectorSubtract( pos, position, g_pApp->m_myCharacter->position );
	VectorNormalize( pos );
	VectorScale( pos, pos, dist );
	VectorAdd( position, pos, g_pApp->m_myCharacter->position );
}
Beispiel #13
0
void AI_CheckMakeEnemy( edict_t *self, edict_t *other )
{
	if (other != self->enemy && other->cast_group != self->cast_group && other->enemy == self)
	{	// make them our enemy now
		
		if (	!self->enemy
			||	!(self->cast_info.aiflags & AI_MELEE)
			||	VectorDistance(self->s.origin, other->s.origin) < 128)
		{
			if (level.global_cast_memory[self->character_index][other->character_index])
				self->enemy = other;
		}
	}
}
Beispiel #14
0
qboolean R_Shader_IsLightInScopeByLeaf( unsigned int lightIndex, mleaf_t *leaf ) {
	const R_ShaderLight *light = GetLightFromIndex( lightIndex );

	if( !light->active ) {
		return false;
	}

	if( !R_Shader_IsLightVisibleFromLeaf( light, leaf ) ) {
		return false;
	}

	// bounding sphere check
	{		
		vec3_t midPoint;
		float boundingSphereRadius;
		
		VectorLerp( &leaf->minmaxs[ 0 ], 0.5f, &leaf->minmaxs[ 3 ], midPoint );
		boundingSphereRadius = VectorDistance( &leaf->minmaxs[ 0 ], midPoint );
		if( VectorDistance( light->origin, midPoint ) > light->maxDistance + boundingSphereRadius ) {
			return false;
		}
	}
	return true;
}
Beispiel #15
0
qboolean R_Shader_IsLightInScopeByPoint( unsigned int lightIndex, const vec3_t renderOrigin ) {
	const R_ShaderLight *light = GetLightFromIndex( lightIndex );
	mleaf_t *leaf;
	if( !light->active ) {
		return false;
	}

	if( VectorDistance( light->origin, renderOrigin ) > light->maxDistance ) {
		return false;
	}

	leaf = Mod_PointInLeaf( (float*)renderOrigin, cl.worldmodel );
	if( leaf == NULL ) {
		return true;
	}

	return R_Shader_IsLightVisibleFromLeaf( light, leaf );
}
Beispiel #16
0
const char *AIFunc_Heinrich_SpawnSpiritsStart( cast_state_t *cs ) {
	gentity_t   *ent = &g_entities[cs->entityNum];
	gentity_t *trav, *spirits;
	float circleDist;
	//
	// enable all the spirit spawners
	trav = NULL;
	// TTimo: gcc: suggest () around assignment used as truth value
	while ( ( trav = G_Find( trav, FOFS( classname ), "func_bats" ) ) ) {
		if ( !trav->active && trav->spawnflags & 4 ) {
			trav->active = 1;   // let them release spirits now
		}
	}
	// is the player outside the circle?
	trav = NULL;
	// TTimo: gcc: suggest () around assignment used as truth value
	while ( ( trav = G_Find( trav, FOFS( classname ), "func_bats" ) ) ) {
		if ( trav->spawnflags & 4 ) {
			spirits = trav;
			circleDist = trav->radius;
			trav = G_Find( NULL, FOFS( targetname ), trav->target );
			if ( trav ) {
				if ( VectorDistance( g_entities[0].s.pos.trBase, trav->s.origin ) > circleDist ) {
					cs->aiFlags &= ~AIFL_MISCFLAG1;
					ent->count2 = 0;
					cs->aiFlags |= AIFL_SPECIAL_FUNC;
					// start the animation
					BG_PlayAnimName( &ent->client->ps, "attack4", ANIM_BP_BOTH, qtrue, qfalse, qtrue );
					// play the sound
					G_AddEvent( ent, EV_GENERAL_SOUND, heinrichSoundIndex[HEINRICH_RAISEDEAD_START] );
					// start the func
					cs->aifunc = AIFunc_Heinrich_RaiseDead; // just do raise dead, without raising any warriors
					return "AIFunc_Heinrich_RaiseDead";
				}
			}
			break;
		}
	}
	//
	return NULL;
}
Beispiel #17
0
int CCam::nearestEntity(void)
{

	distance = 100000;
	for(int i = 0; i < numFramePlayers; i++)
	{
		int clientNum = framePlayers[i];
		player_t *player = &eth32.cg.players[clientNum];

		float d = VectorDistance(eth32.cg.refdef->vieworg, player->orHead.origin);

		if(!player->friendly)
		{
			if(d < distance)
			{
				distance = d;
				return player->clientNum;
			}
		}
	}
	return -1;
}
Beispiel #18
0
static void demoEffectDrawPath( demoEffectPoint_t *point, const vec4_t color) {
	int i;
	polyVert_t verts[4];
	qboolean skipFirst = qtrue;
	vec3_t origin, lastOrigin; 
	demoEffectPoint_t *match[4];
	vec3_t control[4];
	float lerp, lerpFactor;
	int len, steps;
	int times[4] = {0, 1, 2, 3};

	demoEffectPointMatch( point, CAM_ORIGIN, match );
	if (match[1] != point)
		return;
	if (!match[2])
		return;
	demoEffectMatchOrigin( match, control );
	
	len = VectorDistance( control[1], control[2] );
	steps = len / 25;
	if (steps < 5) 
		steps = 5;
	demoDrawSetupVerts( verts, color );
	lerpFactor = 0.9999f / steps;

	for ( i = 0; i <= steps; i++) {
		lerp = i * lerpFactor;
		VectorTimeSpline( lerp, times, control[0], origin, 3);
		if (skipFirst) {
			skipFirst = qfalse;
			VectorCopy( origin, lastOrigin );
			continue;
		}
		demoDrawRawLine( origin, lastOrigin, 1, verts );
		VectorCopy( origin, lastOrigin);
	}
}
Beispiel #19
0
void ForceEnergy(Particle *p1, Particle *p2, int pbc_x, int pbc_y){
  if(pbc_x != 0) p1->position.x -= GRIDSIZE;
  if(pbc_y != 0) p1->position.y -= GRIDSIZE;
  
  double distance = VectorDistance(p1->position, p2->position);
  if (distance >= RCUT) {
    if(pbc_x != 0) p1->position.x += GRIDSIZE;
    if(pbc_y != 0) p1->position.y += GRIDSIZE;
    return;
  }
  double force = (2.0*REPULSIVE_CST*fabs(distance-RCUT)/SQR(RCUT));
  
  Vector relative_position;
  relative_position.x = (p1->position.x - p2->position.x);
  relative_position.y = (p1->position.y - p2->position.y);

  Vector forceVector;
  forceVector.x = relative_position.x * force/distance;
  forceVector.y = relative_position.y * force/distance;
  
  p1->force[1].x += forceVector.x;
  p1->force[1].y += forceVector.y;

  p2->force[1].x -= forceVector.x;
  p2->force[1].y -= forceVector.y;

  // Potential and pressure are summed over all particles later,
  // there is no need to explicitly save p2->potential or p2->pressure
  p1->potential += REPULSIVE_CST*SQR(distance-RCUT)/SQR(RCUT);
  p1->pressure_contribution += 2*(forceVector.x*relative_position.x + forceVector.y*relative_position.y) / (2 * SQR(GRIDSIZE));
  
  int rdf_bin_index = NUMBER_OF_BINS*distance/RCUT;
  p1->radial_distribution[rdf_bin_index] += 2;

  if(pbc_x != 0) p1->position.x += GRIDSIZE;
  if(pbc_y != 0) p1->position.y += GRIDSIZE;
}
Beispiel #20
0
void GTH_GetRealMousePosition( vec3_t mousePos, vec3_t position )
{
	vec3_t pos;
	float dist;

	dist = VectorDistance( mousePos, g_pApp->m_myCharacter->position );
	dist -= g_cgv.mouseClickEventDistance;

	if( g_cgv.clickEvent == GTH_CEV_CHAR_IDLE || g_cgv.clickEvent == GTH_CEV_CHAR_NONE ) 
	{
		VectorCopy( position, mousePos );
		return;
	}
	else if( dist < 0.0f )
	{
		VectorCopy( position, g_pApp->m_myCharacter->position );
		return;
	}

	VectorSubtract( pos, mousePos, g_pApp->m_myCharacter->position );
	VectorNormalize( pos );
	VectorScale( pos, pos, dist );
	VectorAdd( position, pos, g_pApp->m_myCharacter->position );
}
Beispiel #21
0
int Aimbot::FindTarget() // This is the aim filter, here we pick the best possible aim target avaible
{
	// Invalidate target
	int iTarget = INVALID_TARGET;
	float flClosestTarget = 99999999.0f;

	// Loop players and get best target
	for (int i = 0; i <= MAX_CLIENTS; ++i)
	{
		// Valid
		if (ValidAimTarget(i) == false)
			continue;

		// Go by distance
		float flDistance = VectorDistance(g_Local.EyePosition, g_Player[i].AimOrigin);
		if (flDistance < flClosestTarget)
		{
			iTarget = i;
			flClosestTarget = flDistance;
		}
	}

	return iTarget;
}
Beispiel #22
0
qboolean CG_DisguiseMapCheck(mapEntityData_t *mEnt)
{
	if (mEnt->data < 0 || mEnt->data >= 64)
	{
		return qfalse;
	}

	if (!cgs.clientinfo[mEnt->data].infoValid)
	{
		return qfalse;
	}

	if (!(cg_entities[mEnt->data].currentState.powerups & (1 << PW_OPS_DISGUISED)))
	{
		return qfalse;
	}

	if (VectorDistance(cg.snap->ps.origin, cg_entities[mEnt->data].lerpOrigin) < 512)
	{
		return qfalse;
	}

	return qtrue;
}
Beispiel #23
0
void CG_AddTrailToScene(trailJunc_t *trail, int iteration, int numJuncs)
{
#define MAX_TRAIL_VERTS     2048
	polyVert_t verts[MAX_TRAIL_VERTS];
	polyVert_t outVerts[MAX_TRAIL_VERTS * 3];
	int k, i, n, l, numOutVerts;
	polyVert_t mid;
	float mod[4];
	float sInc = 0.0f, s = 0.0f;   // TTimo: init
	trailJunc_t *j, *jNext;
	vec3_t fwd, up, p, v;
	(void)fwd; // Ignore compiler warning -- Justasic
	// clipping vars
#define TRAIL_FADE_CLOSE_DIST   64.0
#define TRAIL_FADE_FAR_SCALE    4.0
	vec3_t viewProj;
	float viewDist, fadeAlpha;

	// add spark shader at head position
	if(trail->flags & TJFL_SPARKHEADFLARE)
	{
		j = trail;
		VectorCopy(j->pos, p);
		VectorMA(p, -j->width * 2, vup, p);
		VectorMA(p, -j->width * 2, vright, p);
		VectorCopy(p, verts[0].xyz);
		verts[0].st[0] = 0;
		verts[0].st[1] = 0;
		verts[0].modulate[0] = 255;
		verts[0].modulate[1] = 255;
		verts[0].modulate[2] = 255;
		verts[0].modulate[3] = (unsigned char)(j->alpha * 255.0);

		VectorCopy(j->pos, p);
		VectorMA(p, -j->width * 2, vup, p);
		VectorMA(p, j->width * 2, vright, p);
		VectorCopy(p, verts[1].xyz);
		verts[1].st[0] = 0;
		verts[1].st[1] = 1;
		verts[1].modulate[0] = 255;
		verts[1].modulate[1] = 255;
		verts[1].modulate[2] = 255;
		verts[1].modulate[3] = (unsigned char)(j->alpha * 255.0);

		VectorCopy(j->pos, p);
		VectorMA(p, j->width * 2, vup, p);
		VectorMA(p, j->width * 2, vright, p);
		VectorCopy(p, verts[2].xyz);
		verts[2].st[0] = 1;
		verts[2].st[1] = 1;
		verts[2].modulate[0] = 255;
		verts[2].modulate[1] = 255;
		verts[2].modulate[2] = 255;
		verts[2].modulate[3] = (unsigned char)(j->alpha * 255.0);

		VectorCopy(j->pos, p);
		VectorMA(p,  j->width * 2, vup, p);
		VectorMA(p, -j->width * 2, vright, p);
		VectorCopy(p, verts[3].xyz);
		verts[3].st[0] = 1;
		verts[3].st[1] = 0;
		verts[3].modulate[0] = 255;
		verts[3].modulate[1] = 255;
		verts[3].modulate[2] = 255;
		verts[3].modulate[3] = (unsigned char)(j->alpha * 255.0);

		trap_R_AddPolyToScene(cgs.media.sparkFlareShader, 4, verts);
	}

//	if (trail->flags & TJFL_CROSSOVER && iteration < 1) {
//		iteration = 1;
//	}

	if(!numJuncs)
	{
		// first count the number of juncs in the trail
		j = trail;
		numJuncs = 0;
		sInc = 0;

		while(j)
		{
			numJuncs++;

			// check for a dead next junc
			if(!j->inuse && j->nextJunc && !j->nextJunc->inuse)
			{
				CG_KillTrail(j);
			}
			else if(j->nextJunc && j->nextJunc->freed)
			{
				// not sure how this can happen, but it does, and causes infinite loops
				j->nextJunc = NULL;
			}

			if(j->nextJunc)
			{
				sInc += VectorDistance(j->nextJunc->pos, j->pos);
			}

			j = j->nextJunc;
		}
	}

	if(numJuncs < 2)
	{
		return;
	}

	if(trail->sType == STYPE_STRETCH)
	{
		//sInc = ((1.0 - 0.1) / (float)(numJuncs)); // hack, the end of funnel shows a bit of the start (looping)
		s = 0.05;
		//s = 0.05;
	}
	else if(trail->sType == STYPE_REPEAT)
	{
		s = trail->sTex;
	}

	// now traverse the list
	j = trail;
	jNext = j->nextJunc;
	i = 0;

	while(jNext)
	{

		// first get the directional vectors to the next junc
		VectorSubtract(jNext->pos, j->pos, fwd);
		GetPerpendicularViewVector(cg.refdef.vieworg, j->pos, jNext->pos, up);

		// if it's a crossover, draw it twice
		if(j->flags & TJFL_CROSSOVER)
		{
			if(iteration > 0)
			{
				ProjectPointOntoVector(cg.refdef.vieworg, j->pos, jNext->pos, viewProj);
				VectorSubtract(cg.refdef.vieworg, viewProj, v);
				VectorNormalize(v);

				if(iteration == 1)
				{
					VectorMA(up, 0.3, v, up);
				}
				else
				{
					VectorMA(up, -0.3, v, up);
				}

				VectorNormalize(up);
			}
		}
		// do fading when moving towards the projection point onto the trail segment vector
		else if(!(j->flags & TJFL_NOCULL) && (j->widthEnd > 4 || jNext->widthEnd > 4))
		{
			ProjectPointOntoVector(cg.refdef.vieworg, j->pos, jNext->pos, viewProj);
			viewDist = Distance(viewProj, cg.refdef.vieworg);

			if(viewDist < (TRAIL_FADE_CLOSE_DIST * TRAIL_FADE_FAR_SCALE))
			{
				if(viewDist < TRAIL_FADE_CLOSE_DIST)
				{
					fadeAlpha = 0.0;
				}
				else
				{
					fadeAlpha = (viewDist - TRAIL_FADE_CLOSE_DIST) / (TRAIL_FADE_CLOSE_DIST * TRAIL_FADE_FAR_SCALE);
				}

				if(fadeAlpha < j->alpha)
				{
					j->alpha = fadeAlpha;
				}

				if(fadeAlpha < jNext->alpha)
				{
					jNext->alpha = fadeAlpha;
				}
			}
		}

		// now output the QUAD for this segment

		// 1 ----
		VectorMA(j->pos, 0.5 * j->width, up, p);
		VectorCopy(p, verts[i].xyz);
		verts[i].st[0] = s;
		verts[i].st[1] = 1.0;

		for(k = 0; k < 3; k++)
			verts[i].modulate[k] = (unsigned char)(j->color[k] * 255.0);

		verts[i].modulate[3] = (unsigned char)(j->alpha * 255.0);

		// blend this with the previous junc
		if(j != trail)
		{
			VectorAdd(verts[i].xyz, verts[i - 1].xyz, verts[i].xyz);
			VectorScale(verts[i].xyz, 0.5, verts[i].xyz);
			VectorCopy(verts[i].xyz, verts[i - 1].xyz);
		}
		else if(j->flags & TJFL_FADEIN)
		{
			verts[i].modulate[3] = 0;   // fade in
		}

		i++;

		// 2 ----
		VectorMA(p, -1 * j->width, up, p);
		VectorCopy(p, verts[i].xyz);
		verts[i].st[0] = s;
		verts[i].st[1] = 0.0;

		for(k = 0; k < 3; k++)
			verts[i].modulate[k] = (unsigned char)(j->color[k] * 255.0);

		verts[i].modulate[3] = (unsigned char)(j->alpha * 255.0);

		// blend this with the previous junc
		if(j != trail)
		{
			VectorAdd(verts[i].xyz, verts[i - 3].xyz, verts[i].xyz);
			VectorScale(verts[i].xyz, 0.5, verts[i].xyz);
			VectorCopy(verts[i].xyz, verts[i - 3].xyz);
		}
		else if(j->flags & TJFL_FADEIN)
		{
			verts[i].modulate[3] = 0;   // fade in
		}

		i++;

		if(trail->sType == STYPE_REPEAT)
		{
			s = jNext->sTex;
		}
		else
		{
			//s += sInc;
			s += VectorDistance(j->pos, jNext->pos) / sInc;

			if(s > 1.0)
			{
				s = 1.0;
			}
		}

		// 3 ----
		VectorMA(jNext->pos, -0.5 * jNext->width, up, p);
		VectorCopy(p, verts[i].xyz);
		verts[i].st[0] = s;
		verts[i].st[1] = 0.0;

		for(k = 0; k < 3; k++)
			verts[i].modulate[k] = (unsigned char)(jNext->color[k] * 255.0);

		verts[i].modulate[3] = (unsigned char)(jNext->alpha * 255.0);
		i++;

		// 4 ----
		VectorMA(p, jNext->width, up, p);
		VectorCopy(p, verts[i].xyz);
		verts[i].st[0] = s;
		verts[i].st[1] = 1.0;

		for(k = 0; k < 3; k++)
			verts[i].modulate[k] = (unsigned char)(jNext->color[k] * 255.0);

		verts[i].modulate[3] = (unsigned char)(jNext->alpha * 255.0);
		i++;

		if(i + 4 > MAX_TRAIL_VERTS)
		{
			break;
		}

		j = jNext;
		jNext = j->nextJunc;
	}

	if(trail->flags & TJFL_FIXDISTORT)
	{
		// build the list of outVerts, by dividing up the QUAD's into 4 Tri's each, so as to allow
		//  any shaped (convex) Quad without bilinear distortion
		for(k = 0, numOutVerts = 0; k < i; k += 4)
		{
			VectorCopy(verts[k].xyz, mid.xyz);
			mid.st[0] = verts[k].st[0];
			mid.st[1] = verts[k].st[1];

			for(l = 0; l < 4; l++)
			{
				mod[l] = (float)verts[k].modulate[l];
			}

			for(n = 1; n < 4; n++)
			{
				VectorAdd(verts[k + n].xyz, mid.xyz, mid.xyz);
				mid.st[0] += verts[k + n].st[0];
				mid.st[1] += verts[k + n].st[1];

				for(l = 0; l < 4; l++)
				{
					mod[l] += (float)verts[k + n].modulate[l];
				}
			}

			VectorScale(mid.xyz, 0.25, mid.xyz);
			mid.st[0] *= 0.25;
			mid.st[1] *= 0.25;

			for(l = 0; l < 4; l++)
			{
				mid.modulate[l] = (unsigned char)(mod[l] / 4.0);
			}

			// now output the tri's
			for(n = 0; n < 4; n++)
			{
				outVerts[numOutVerts++] = verts[k + n];
				outVerts[numOutVerts++] = mid;

				if(n < 3)
				{
					outVerts[numOutVerts++] = verts[k + n + 1];
				}
				else
				{
					outVerts[numOutVerts++] = verts[k];
				}
			}

		}

		if(!(trail->flags & TJFL_NOPOLYMERGE))
		{
			trap_R_AddPolysToScene(trail->shader, 3, &outVerts[0], numOutVerts / 3);
		}
		else
		{
			int k;

			for(k = 0; k < numOutVerts / 3; k++)
			{
				trap_R_AddPolyToScene(trail->shader, 3, &outVerts[k * 3]);
			}
		}
	}
	else
	{
		// send the polygons
		// FIXME: is it possible to send a GL_STRIP here? We are actually sending 2x the verts we really need to
		if(!(trail->flags & TJFL_NOPOLYMERGE))
		{
			trap_R_AddPolysToScene(trail->shader, 4, &verts[0], i / 4);
		}
		else
		{
			int k;

			for(k = 0; k < i / 4; k++)
			{
				trap_R_AddPolyToScene(trail->shader, 4, &verts[k * 4]);
			}
		}
	}

	// do we need to make another pass?
	if(trail->flags & TJFL_CROSSOVER)
	{
		if(iteration < 2)
		{
			CG_AddTrailToScene(trail, iteration + 1, numJuncs);
		}
	}

}
Beispiel #24
0
/*
============
AICast_Blocked
============
*/
void AICast_Blocked( cast_state_t *cs, bot_moveresult_t *moveresult, int activate, bot_goal_t *goal ) {
	vec3_t pos, dir;
	aicast_predictmove_t move;
	usercmd_t ucmd;
	bot_input_t bi;
	cast_state_t *ocs;
	int i, blockEnt = -1;
	bot_goal_t ogoal;

	if ( cs->blockedAvoidTime < level.time ) {
		if ( cs->blockedAvoidTime < level.time - 300 ) {
			if ( VectorCompare( cs->bs->cur_ps.velocity, vec3_origin ) && !cs->bs->lastucmd.forwardmove && !cs->bs->lastucmd.rightmove ) {
				// not moving, don't bother checking
				cs->blockedAvoidTime = level.time - 1;
				return;
			}
			// are we going to hit someone soon?
			trap_EA_GetInput( cs->entityNum, (float) level.time / 1000, &bi );
			AICast_InputToUserCommand( cs, &bi, &ucmd, cs->bs->cur_ps.delta_angles );
			AICast_PredictMovement( cs, 1, 0.6, &move, &ucmd, ( goal && goal->entitynum > -1 ) ? goal->entitynum : cs->entityNum );

			// blocked if we hit a client (or non-stationary mover) other than our enemy or goal
			if ( move.stopevent != PREDICTSTOP_HITCLIENT ) {
				// not blocked
				cs->blockedAvoidTime = level.time - 1;
				return;
			}

			// if we stopped passed our goal, ignore it
			if ( goal ) {
				if ( VectorDistance( cs->bs->origin, goal->origin ) < VectorDistance( cs->bs->origin, move.endpos ) ) {
					vec3_t v1, v2;
					VectorSubtract( goal->origin, cs->bs->origin, v1 );
					VectorSubtract( goal->origin, move.endpos, v2 );
					VectorNormalize( v1 );
					VectorNormalize( v2 );
					if ( DotProduct( v1, v2 ) < 0 ) {
						// we went passed the goal, so assume we can reach it
						cs->blockedAvoidTime = level.time - 1;
						return;
					}
				}
			}

			// try and get them to move, in case we can't get around them
			blockEnt = -1;
			for ( i = 0; i < move.numtouch; i++ ) {
				if ( move.touchents[i] >= MAX_CLIENTS ) {
					if ( !Q_stricmp( g_entities[move.touchents[i]].classname, "script_mover" ) ) {
						// avoid script_mover's
						blockEnt = move.touchents[i];
					}
					// if we are close to the impact point, then avoid this entity
					else if ( VectorDistance( cs->bs->origin, move.endpos ) < 10 ) {
						//G_Printf("AI (%s) avoiding %s\n", g_entities[cs->entityNum].aiName, g_entities[move.touchents[i]].classname );
						blockEnt = move.touchents[i];
					}
					continue;
				}
				//
				ocs = AICast_GetCastState( move.touchents[i] );
				if ( !ocs->bs ) {
					blockEnt = move.touchents[i];
				}
				// reject this blocker if we are following or going to them
				else if ( cs->followEntity != ocs->entityNum ) {
					// if they are moving away from us already, let them go
					if ( VectorLength( ocs->bs->cur_ps.velocity ) > 10 ) {
						vec3_t v1, v2;

						VectorSubtract( ocs->bs->origin, cs->bs->origin, v2 );
						VectorNormalize( v2 );
						VectorNormalize2( ocs->bs->cur_ps.velocity, v1 );

						if ( DotProduct( v1, v2 ) > 0.0 ) {
							continue;
						}
					}
					//
					// if they recently were asked to avoid us, then they're probably not listening
					if ( ocs->obstructingTime > level.time - 500 ) {
						blockEnt = move.touchents[i];
					}
					//
					// if they are not avoiding, ignore
					if ( !( ocs->aiFlags & AIFL_NOAVOID ) ) {
						continue;
					}
					//
					// they should avoid us
					if ( ocs->leaderNum >= 0 ) {
						ogoal.entitynum = ocs->leaderNum;
						VectorCopy( g_entities[ocs->leaderNum].r.currentOrigin, ogoal.origin );
						if ( AICast_GetAvoid( ocs, &ogoal, ocs->obstructingPos, qfalse, cs->entityNum ) ) {
							// give them time to move somewhere else
							ocs->obstructingTime = level.time + 1000;
						} else {
							// make sure they don't call GetAvoid() for another few frames to let others avoid also
							ocs->obstructingTime = level.time - 1;
							blockEnt = move.touchents[i];
						}
					} else {
						if ( AICast_GetAvoid( ocs, NULL, ocs->obstructingPos, qfalse, cs->entityNum ) ) {
							// give them time to move somewhere else
							ocs->obstructingTime = level.time + 1000;
						} else {
							// make sure they don't call GetAvoid() for another few frames to let others avoid also
							ocs->obstructingTime = level.time - 1;
							blockEnt = move.touchents[i];
						}
					}
				}
			}

		} else {
			return;
		}

		if ( blockEnt < 0 ) {
			// nothing found to be worth avoding
			cs->blockedAvoidTime = level.time - 1;
			return;
		}

		// something is blocking our path
		if ( g_entities[blockEnt].aiName && g_entities[blockEnt].client ) {
			int oldId = cs->castScriptStatus.scriptId;
			AICast_ScriptEvent( cs, "blocked", g_entities[blockEnt].aiName );
			if ( oldId != cs->castScriptStatus.scriptId ) {
				// the script has changed, so assume the scripting is handling the avoidance
				return;
			}
		}

		// avoid geometry and props, but assume clients will get out the way
		if ( /*blockEnt > MAX_CLIENTS &&*/ AICast_GetAvoid( cs, goal, pos, qfalse, blockEnt ) ) {
			VectorSubtract( pos, cs->bs->cur_ps.origin, dir );
			VectorNormalize( dir );
			cs->blockedAvoidYaw = vectoyaw( dir );
			if ( blockEnt >= MAX_CLIENTS ) {
				cs->blockedAvoidTime = level.time + 100 + rand() % 200;
			} else {
				cs->blockedAvoidTime = level.time + 300 + rand() % 400;
			}
		} else {
			cs->blockedAvoidTime = level.time - 1;    // don't look again for another few frames
			return;
		}
	}

	VectorClear( pos );
	pos[YAW] = cs->blockedAvoidYaw;
	AngleVectors( pos, dir, NULL, NULL );

	if ( moveresult->flags & MOVERESULT_ONTOPOFOBSTACLE ) {
		trap_EA_Jump( cs->bs->entitynum );
	}

	trap_EA_Move( cs->bs->entitynum, dir, 200 ); //400);

	vectoangles( dir, cs->bs->ideal_viewangles );
	cs->bs->ideal_viewangles[2] *= 0.5;
}
Beispiel #25
0
void SV_LinkEdict(edict_t *ent)
{
	guard(SV_LinkEdict);

	int		i, j, k;

	//!! HOOK - move outside ?
	if (bspfile.type != map_q2)
	{
		if (ent->s.modelindex >= 0 && ent->s.modelindex < MAX_MODELS)
		{
			// link model hook
			const char *modelName = sv.configstrings[CS_MODELS + ent->s.modelindex];
			if (!strcmp(modelName, "models/objects/dmspot/tris.md2"))
			{
				// teleporter (source+target) was found
//				appPrintf(S_CYAN"teleport: %g %g %g\n", VECTOR_ARG(ent->s.origin));
				return;			// simply do not link model; trigger entity will be added anyway
			}
		}
	}

	if (ent->area.prev)
		SV_UnlinkEdict(ent);	// unlink from old position (i.e. relink edict)

	if (ent == ge->edicts)
		return;					// don't add the world

	if (!ent->inuse)
		return;

	entityHull_t &ex = ents[NUM_FOR_EDICT(ent)];
	memset(&ex, 0, sizeof(entityHull_t));
	ex.owner = ent;
	ex.axis.FromEuler(ent->s.angles);

	// set the size
	VectorSubtract(ent->bounds.maxs, ent->bounds.mins, ent->size);

	// encode the size into the entity_state for client prediction
	if (ent->solid == SOLID_BBOX)
	{
		// assume that x/y are equal and symetric
		i = appRound(ent->bounds.maxs[0] / 8);
		// z is not symetric
		j = appRound(-ent->bounds.mins[2] / 8);
		// and z maxs can be negative...
		k = appRound((ent->bounds.maxs[2] + 32) / 8);
		// original Q2 have bounded i/j/k/ with lower margin==1 (for client prediction only); this will
		// produce incorrect collision test when bbox mins/maxs is (0,0,0)
		i = bound(i, 0, 31);		// mins/maxs[0,1] range is -248..0/0..248
		j = bound(j, 0, 31);		// mins[2] range is [-248..0]
		k = bound(k, 0, 63);		// maxs[2] range is [-32..472]

		// if SVF_DEADMONSTER, s.solid should be 0
		ent->s.solid = (ent->svflags & SVF_DEADMONSTER) ? 0 : (k<<10) | (j<<5) | i;

		i *= 8;
		j *= 8;
		k *= 8;
		ex.bounds.mins.Set(-i, -i, -j);
		ex.bounds.maxs.Set(i, i, k - 32);
		ex.bounds.GetCenter(ex.center);
		ex.center.Add(ent->s.origin);
		ex.model  = NULL;
		ex.radius = VectorDistance(ex.bounds.maxs, ex.bounds.mins) / 2;
	}
	else if (ent->solid == SOLID_BSP)
	{
		ex.model = sv.models[ent->s.modelindex];
		if (!ex.model) Com_DropError("MOVETYPE_PUSH with a non bsp model");
		CVec3	v;
		ex.model->bounds.GetCenter(v);
		UnTransformPoint(ent->s.origin, ex.axis, v, ex.center);
		ex.radius = ex.model->radius;

		ent->s.solid = 31;		// a SOLID_BBOX will never create this value (mins=(-248,-248,0) maxs=(248,248,-32))
	}
	else if (ent->solid == SOLID_TRIGGER)
	{
		ent->s.solid = 0;
		// check for model link
		ex.model = sv.models[ent->s.modelindex];
		if (!ex.model)
		{
			// model not attached by game, check entstring
			//?? can optimize: add 'bool spawningEnts', set to 'true' before SpawnEntities()
			//?? and 'false' after; skip code below when 'false'
			for (triggerModelLink_t *link = bspfile.modelLinks; link; link = link->next)
#define CMP(n)	(fabs(ent->s.origin[n] - link->origin[n]) < 0.5f)
				if (CMP(0) && CMP(1) && CMP(2))
				{
					CBspModel *model = CM_InlineModel(link->modelIdx);
					VectorSubtract(model->bounds.maxs, ent->s.origin, ent->bounds.maxs);
					VectorSubtract(model->bounds.mins, ent->s.origin, ent->bounds.mins);
					break;
				}
#undef CMP
		}
	}
	else
		ent->s.solid = 0;

	// set the abs box
	if (ent->solid == SOLID_BSP && (ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2]))
	{
		// expand for rotation
		for (i = 0; i < 3 ; i++)
		{
			ent->absBounds.mins[i] = ex.center[i] - ex.radius;
			ent->absBounds.maxs[i] = ex.center[i] + ex.radius;
		}
	}
	else
	{	// normal
		VectorAdd(ent->s.origin, ent->bounds.mins, ent->absBounds.mins);
		VectorAdd(ent->s.origin, ent->bounds.maxs, ent->absBounds.maxs);
	}

	// because movement is clipped an epsilon away from an actual edge,
	// we must fully check even when bounding boxes don't quite touch
	for (i = 0; i < 3; i++)
	{
		ent->absBounds.mins[i] -= 1;
		ent->absBounds.maxs[i] += 1;
	}

	// link to PVS leafs
	ent->num_clusters = 0;
	ent->zonenum      = 0;
	ent->zonenum2     = 0;

	// get all leafs, including solids
	CBspLeaf *leafs[MAX_TOTAL_ENT_LEAFS];
	int topnode;
	int num_leafs = CM_BoxLeafs(ent->absBounds, ARRAY_ARG(leafs), &topnode);

	// set zones
	int clusters[MAX_TOTAL_ENT_LEAFS];
	for (i = 0; i < num_leafs; i++)
	{
		clusters[i] = leafs[i]->cluster;
		int zone = leafs[i]->zone;
		if (zone)
		{	// doors may legally straggle two zones,
			// but nothing should evern need more than that
			if (ent->zonenum && ent->zonenum != zone)
			{
				if (ent->zonenum2 && ent->zonenum2 != zone && sv.state == ss_loading)
					Com_DPrintf("Object touching 3 zones at %g %g %g\n", VECTOR_ARG(ent->absBounds.mins));
				ent->zonenum2 = zone;
			}
			else
				ent->zonenum = zone;
		}
	}

	if (num_leafs >= MAX_TOTAL_ENT_LEAFS)
	{	// assume we missed some leafs, and mark by headnode
		ent->num_clusters = -1;
		ent->headnode     = topnode;
	}
	else
	{
		ent->num_clusters = 0;
		for (i = 0; i < num_leafs; i++)
		{
			if (clusters[i] == -1)
				continue;		// not a visible leaf
			for (j = 0; j < i; j++)
				if (clusters[j] == clusters[i])
					break;
			if (j == i)
			{
				if (ent->num_clusters == MAX_ENT_CLUSTERS)
				{	// assume we missed some leafs, and mark by headnode
					ent->num_clusters = -1;
					ent->headnode     = topnode;
					break;
				}

				ent->clusternums[ent->num_clusters++] = clusters[i];
			}
		}
	}

	// if first time, make sure old_origin is valid
	if (!ent->linkcount)
		ent->s.old_origin = ent->s.origin;
	ent->linkcount++;

	if (ent->solid == SOLID_NOT)
		return;

	// find the first node that the ent's box crosses
	areanode_t *node = areaNodes;
	while (node->axis != -1)
	{
		if (ent->absBounds.mins[node->axis] > node->dist)
			node = node->children[0];
		else if (ent->absBounds.maxs[node->axis] < node->dist)
			node = node->children[1];
		else
			break;		// crosses the node
	}

	// link it in
	areanode_t *node2 = node;
	if (ent->solid == SOLID_TRIGGER)
	{
		InsertLinkBefore(ent->area, node->trigEdicts);
		for ( ; node2; node2 = node2->parent)
			node2->numTrigEdicts++;
	}
	else
	{
		InsertLinkBefore(ent->area, node->solidEdicts);
		for ( ; node2; node2 = node2->parent)
			node2->numSolidEdicts++;
	}
	ex.area = node;

	unguard;
}
Beispiel #26
0
void SV_Physics_Step (edict_t *ent)
{
	qboolean	wasonground;
	qboolean	hitsound = false;
	float		*vel;
	float		speed, newspeed, control;
	float		friction;
	edict_t		*groundentity;
	int			mask;
	int			retval;
	vec3_t		oldpos;

	// BEGIN:	Xatrix/Ridah
	vec3_t	old_vel;
	// END:		Xatrix/Ridah

	// Joseph
	if (ent->fallerflag)
	{
		// Fix if sitting off center
		think_checkedges(ent);
	}
	
	// airborn monsters should always check for ground
	if (!ent->groundentity)
		M_CheckGround (ent);

	groundentity = ent->groundentity;

	SV_CheckVelocity (ent);

	if (groundentity)
		wasonground = true;
	else
		wasonground = false;
		
	if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2])
		SV_AddRotationalFriction (ent);

	// add gravity except:
	//   flying monsters
	//   swimming monsters who are in the water
	if (! wasonground)
		if (!(ent->flags & FL_FLY))
			if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2)))
			{
				if (ent->velocity[2] < sv_gravity->value*-0.1)
					hitsound = true;
// Ridah, 1-may-99, disabled this to prevent guys getting stuck in water
//				if (ent->waterlevel == 0)
					SV_AddGravity (ent);
			}
/*
	// friction for flying monsters that have been given vertical velocity
	if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0))
	{
		speed = fabs(ent->velocity[2]);
		control = speed < sv_stopspeed ? sv_stopspeed : speed;
		friction = sv_friction/3;
		newspeed = speed - (FRAMETIME * control * friction);
		if (newspeed < 0)
			newspeed = 0;
		newspeed /= speed;
		ent->velocity[2] *= newspeed;
	}
*/
	// friction for flying monsters that have been given vertical velocity
	if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0))
	{
		speed = fabs(ent->velocity[2]);
		control = speed < sv_stopspeed ? sv_stopspeed : speed;
		newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel);
		if (newspeed < 0)
			newspeed = 0;
		newspeed /= speed;
		ent->velocity[2] *= newspeed;
	}

	if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0])
	{
		// apply friction
		// let dead monsters who aren't completely onground slide
		if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY)))
			if (!(ent->health <= 0.0 && !M_CheckBottom(ent)))
			{
				vel = ent->velocity;
				speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
				if (speed)
				{
					friction = sv_friction;

					control = speed < sv_stopspeed ? sv_stopspeed : speed;
					newspeed = speed - FRAMETIME*control*friction;

					if (newspeed < 0)
						newspeed = 0;
					newspeed /= speed;

					vel[0] *= newspeed;
					vel[1] *= newspeed;
				}
			}

		// BEGIN:	Xatrix/Ridah
		// JOSEPH 26-APR-99
		if ((ent->svflags & SVF_MONSTER) || (ent->monsterprop))
		// END JOSEPH
		{
//			if (ent->cast_info.aiflags & AI_PLAYERCLIP)
				mask = MASK_PLAYERSOLID | CONTENTS_MONSTERCLIP;
//			else
//				mask = MASK_MONSTERSOLID;
		}
		else
			mask = MASK_SOLID;

		VectorCopy (ent->velocity, old_vel);
		// END:		Xatrix/Ridah

		VectorCopy (ent->s.origin, oldpos );

		retval = SV_FlyMove (ent, FRAMETIME, mask);

#if 0	// leave this here for now.

		// Ridah, HACK... sometimes they get stuck, we should debug this properly when we get the time
		if (!ValidBoxAtLoc( ent->s.origin, ent->mins, ent->maxs, ent, MASK_SOLID ))
		{	// move back to old position and clear velocity
			int iter=0;

			VectorCopy (oldpos, ent->s.origin);
			VectorClear (ent->velocity);

			// find a good position
			while (!ValidBoxAtLoc( ent->s.origin, ent->mins, ent->maxs, ent, MASK_SOLID ))
			{
				VectorAdd( ent->s.origin, tv((random()-0.5) * 64, (random()-0.5) * 64, (random()-0.5) * 64), ent->s.origin );

				if (++iter > 10)
					break;
			}

//			if (iter <= 4)
//			{	// make sure they're on the ground
//				M_droptofloor( ent );
//			}

			goto exit_vel_check;		// get out of here?
		}
#endif

		// BEGIN:	Xatrix/Ridah
		if (!ent->groundentity || (ent->flags & FL_FLY))
		{
			node_t	*land_node;

			// Ridah, prevent guys getting stuck trying to jump
			if (VectorDistance( ent->s.origin, oldpos ) < 1 && !ent->groundentity && (ent->last_onground < (level.time - 2)))
			{
				ent->velocity[0] = crandom() * 300;
				ent->velocity[1] = crandom() * 300;

				if (ent->velocity[2] < -200)
					ent->velocity[2] = -200;

				ent->velocity[2] += random() * 350;

				ent->nav_data.goal_index = 0;
				ent->last_onground = level.time;
			}

			if (ent->velocity[2] > 80 && retval != 20)
			{	// while rising, maintain XY velocity
				ent->velocity[0] = old_vel[0];
				ent->velocity[1] = old_vel[1];
			}

			// see if we've gone passed the landing position
			if (	!(ent->flags & FL_FLY)
				&&	(retval == -1) && (ent->nav_data.goal_index)
				&&	(land_node = level.node_data->nodes[ent->nav_data.goal_index-1]))
//				&&	(land_node->node_type & NODE_LANDING))
			{
				vec3_t	unit_vel, goal_dir, goal_vec;
				float	vel_scale, dist;

				VectorSubtract( land_node->origin, ent->s.origin, goal_vec );
				goal_vec[2] = 0;
				dist = VectorNormalize2( goal_vec, goal_dir );

				if (dist > 16)
				{

					VectorCopy( ent->velocity, unit_vel );
					unit_vel[2] = 0;
					vel_scale = VectorNormalize( unit_vel );

					if (DotProduct( unit_vel, goal_dir ) < 0.8)
					{	// we've either gone passed, or need some correction
						vec3_t new_pos;
						float	old_z;

						if (VectorLength( goal_vec ) < 40)
						{
							new_pos[0] = land_node->origin[0];
							new_pos[1] = land_node->origin[1];
							new_pos[2] = ent->s.origin[2];

							if (ValidBoxAtLoc( new_pos, ent->mins, ent->maxs, ent, MASK_PLAYERSOLID | MASK_MONSTERSOLID ))
							{	// move there, it's safe, and clear velocity
								VectorCopy( new_pos, ent->s.origin );
								ent->velocity[0] = ent->velocity[1] = 0;

								goto exit_vel_check;
							}
						}

						// we need to adjust our velocity
						if (land_node->origin[2] < (ent->s.origin[2] - 64))
						{
							old_z = ent->velocity[2];
							VectorScale( goal_dir, vel_scale, ent->velocity );
							ent->velocity[2] = old_z;
						}
						
					}

				}
			}	

			if (	(ent->flags & FL_FLY)
				&&	((land_node = level.node_data->nodes[ent->nav_data.goal_index-1]) || ((ent->flags &= ~FL_FLY) && false))
				/*&&	(land_node->node_type & NODE_LANDING)*/)
			{	// if climbing ladder, and we're reached the landing position, stop

				// Ridah, 8-jun-99, make sure dog's don't climb ladders
				if (!ent->gender)
				{
					goto abort_climb;
				}

				if (ent->s.origin[2] > land_node->origin[2])
				{
//gi.dprintf( "-> end of climb\n" );
//					VectorSubtract( land_node->origin, ent->s.origin, ent->velocity );
					AngleVectors( ent->s.angles, ent->velocity, NULL, NULL );
					ent->velocity[2] = 0;
					VectorNormalize( ent->velocity );
					VectorScale( ent->velocity, 96, ent->velocity );

					ent->velocity[2] = 200;

					ent->flags &= ~FL_FLY;
					ent->nav_data.goal_index = 0;		// look for a new node
					ent->nav_data.cache_node = -1;

					if (ent->cast_info.move_end_climb)
						ent->cast_info.currentmove = ent->cast_info.move_end_climb;
				}
				else
				{
					trace_t tr;
					vec3_t	end, goal_vec;

					VectorSubtract( land_node->origin, ent->s.origin, goal_vec );

					ent->velocity[0] = goal_vec[0];
					ent->velocity[1] = goal_vec[1];
					ent->velocity[2] = 120;

					// if another character is above us, abort
					VectorCopy( ent->s.origin, end );
					end[2] += 128;
					tr = gi.trace( ent->s.origin, ent->mins, ent->maxs, end, ent, MASK_PLAYERSOLID | MASK_MONSTERSOLID );
					
					if ((tr.fraction < 1) && (tr.ent->svflags & SVF_MONSTER))
					{

abort_climb:

						AngleVectors( ent->s.angles, goal_vec, NULL, NULL );
						VectorScale( goal_vec, -64, ent->velocity );
						ent->flags &= ~FL_FLY;
						ent->nav_data.goal_index = 0;

						if (ent->cast_info.move_end_climb)
						{
							ent->cast_info.currentmove = ent->cast_info.move_end_climb;
						}
						else if (ent->cast_info.move_jump)
						{
							ent->cast_info.currentmove = ent->cast_info.move_jump;
						}
					}
					else if (ent->s.origin[2] > (land_node->origin[2] - 48))
					{	// we're near the top, stopping climbing anim
//gi.dprintf( "near end of climb\n" );
						if (ent->cast_info.move_end_climb)
							ent->cast_info.currentmove = ent->cast_info.move_end_climb;

						// add some forward momentum
						AngleVectors( ent->s.angles, goal_vec, NULL, NULL );
						VectorMA( ent->velocity, 64, goal_vec, ent->velocity );
					}

				}

			}
		}

exit_vel_check:

		// END:		Xatrix/Ridah

		gi.linkentity (ent);
		G_TouchTriggers (ent);

// Note to Ryan: we can't use this because we are playing specific sounds elsewhere
/*
		if (ent->groundentity)
			if (!wasonground)
				if (hitsound)
					// BEGIN:	Xatrix/Ridah/Navigator/03-apr-1998
					if (!(ent->cast_info.move_run))
					// END:		Xatrix/Ridah/Navigator/03-apr-1998
						gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0);
*/
	}

// regular thinking
	SV_RunThink (ent);
}
Beispiel #27
0
bool AvHOrder::Update()
{
	bool theOrderJustCompleted = false;

	ASSERT(this->GetReceiver() != -1 );
	if(this->GetOrderActive())
	{
		bool theOrderIsComplete = false;
		AvHPlayer* thePlayer = NULL;
		vec3_t theOrderLocation;
		this->GetLocation(theOrderLocation);
		
		EntityInfo theReceiver = this->GetReceiver();
		float theDistance;
		const float kMoveToDistance = 90;
		const float kPickupDistance = 20;
		
		CBaseEntity* theTargetEntity = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(this->mTargetIndex));
		AvHBaseBuildable* theTargetBuildable = dynamic_cast<AvHBaseBuildable*>(theTargetEntity);
		AvHPlayer* theTargetPlayer = dynamic_cast<AvHPlayer*>(theTargetEntity);
		AvHWeldable* theWeldable = dynamic_cast<AvHWeldable*>(theTargetEntity);
		switch(this->mOrderType)
		{
		case ORDERTYPE_UNDEFINED:
		default:
			break;
		
		case ORDERTYPEL_MOVE:
			// set true if all receivers are within a certain distance of move to order
			theTargetPlayer = dynamic_cast<AvHPlayer*>(CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(theReceiver)));
			if(theTargetPlayer)
			{
				theOrderIsComplete = true;
				theDistance = VectorDistance(theTargetPlayer->pev->origin, theOrderLocation);
				if(!theTargetPlayer->GetIsRelevant() || (theDistance > kMoveToDistance))
				{
					theOrderIsComplete = false;
				}
			}

			if(theOrderIsComplete)
			{
				this->mOrderStatus = kOrderStatusComplete;
			}
			break;
		
		case ORDERTYPET_GET:
			// set true if all receivers are within a certain distance of item
			theTargetPlayer = dynamic_cast<AvHPlayer*>(CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex(theReceiver)));
			if(theTargetPlayer)
			{
				// If one of the players in the group is near enough to pick it up
				theDistance = VectorDistance(theTargetPlayer->pev->origin, theOrderLocation);
				if(theTargetPlayer->GetIsRelevant() && (theDistance < kPickupDistance))
				{
					theOrderIsComplete = true;
				}
			}

		
			// If the item is gone, the order is done
			if(!theTargetEntity)
			{
				this->mOrderStatus = kOrderStatusCancelled;
			}
			break;
		
		case ORDERTYPET_ATTACK:
			// set true if target is dead or not relevant
			if(!theTargetEntity || (theTargetPlayer && !theTargetPlayer->GetIsRelevant()))
			{
				this->mOrderStatus = kOrderStatusCancelled;
				theOrderIsComplete = true;
			}
			else if(theTargetEntity && !theTargetEntity->IsAlive())
			{
				this->mOrderStatus = kOrderStatusComplete;
				theOrderIsComplete = true;
			}
			break;
		
		case ORDERTYPET_BUILD:
			if(!theTargetEntity || !theTargetEntity->IsAlive())
			{
				this->mOrderStatus = kOrderStatusCancelled;
				theOrderIsComplete = true;
			}
			else if(theTargetBuildable && theTargetBuildable->GetIsBuilt())
			{
				this->mOrderStatus = kOrderStatusComplete;
				theOrderIsComplete = true;
			}
			else
			{
				if(theTargetEntity)
				{
					bool theIsBuilding;
					bool theIsResearching;
					float thePercentage;
		
					AvHSHUGetBuildResearchState(theTargetEntity->pev->iuser3, theTargetEntity->pev->iuser4, theTargetEntity->pev->fuser1, theIsBuilding, theIsResearching, thePercentage);
					if(!theIsBuilding && (thePercentage == 1.0f))
					{
						this->mOrderStatus = kOrderStatusComplete;
						theOrderIsComplete = true;
					}
				}
			}
			break;
		
		case ORDERTYPET_GUARD:
			theOrderIsComplete = false;
		
			if(!theTargetEntity ||!theTargetEntity->IsAlive())
			{
				this->mOrderStatus = kOrderStatusCancelled;
				theOrderIsComplete = true;
			}
			break;
		
		case ORDERTYPET_WELD:
			//ALERT(at_console, "Checking weldables ");
			// set true when target is fully welded
			if(!theTargetEntity ||!theTargetEntity->IsAlive())
			{
				this->mOrderStatus = kOrderStatusCancelled;
				theOrderIsComplete = true;
			}
			if(theWeldable && theWeldable->GetIsWelded())
			{
				this->mOrderStatus = kOrderStatusComplete;
				theOrderIsComplete = true;
			} 
			else if ( !theWeldable ) 
			{
				if ( theTargetEntity->pev->iuser3 == AVH_USER3_MARINE_PLAYER )
				{
					// Players are welded if they have full armour
					if ( theTargetEntity->pev->armorvalue == AvHPlayerUpgrade::GetMaxArmorLevel(theTargetEntity->pev->iuser4, (AvHUser3)theTargetEntity->pev->iuser3)) 
					{
						this->mOrderStatus = kOrderStatusComplete;
						theOrderIsComplete = true;
					}
				}
				else 
				{
					// Structures are welded if they have full health
					if ( theTargetEntity->pev->health == theTargetEntity->pev->max_health ) 
					{
						this->mOrderStatus = kOrderStatusComplete;
						theOrderIsComplete = true;
					}
				}
			}
			break;
		}

		if(theOrderIsComplete)
		{
			this->SetOrderCompleted();
			theOrderJustCompleted = true;
		}
	}

	return theOrderJustCompleted;
}
Beispiel #28
0
void PreCalculate_Flag_Spawnpoints( int flagnum, vec3_t angles, vec3_t origin )
{
	vec3_t fwd, point;
	int tries = 0, tries2 = 0;
	qboolean visible = qfalse;

	VectorCopy(origin, point);
		
	AngleVectors( angles, fwd, NULL, NULL );

	while (1)//visible == qfalse)
	{// In case we need to try a second spawnpoint.
		int wp = -1;
		vec3_t	playerMins = {-15, -15, DEFAULT_MINS_2};
		vec3_t	playerMaxs = {15, 15, DEFAULT_MAXS_2};

		playerMins[0] = -15;
		playerMins[1] = -15;
		playerMins[2] = -1;
		playerMaxs[0] = 15;
		playerMaxs[1] = 15;
		playerMaxs[2] = 96;//1;

		while (tries < 16)
		{
			tries++;
			tries2 = 0;

			while (tries2 < 64)
			{
				int num_tries; // For secondary spawns. (Behind point).

				tries2++;

				num_tries = tries2;
				if (tries2 <= 16)
				{
				}
				else if (tries2 <= 32)
				{
					num_tries-=16;
				}
				else if (tries2 <= 48)
				{
					num_tries-=32;
				}
				else
				{
					num_tries-=48;
				}
				
				if (wp == -1)
					VectorCopy(origin, point);
				else
					VectorCopy(gWPArray[wp]->origin, point);

				if (tries2 <= 8)
				{
					point[0] += 1+(tries*64);
					point[1] += 1+(num_tries*64);
				}
				else if (tries2 <= 16)
				{
					point[0] += 1+(tries*64);
					point[1] += 1-(num_tries*64);
				}
				else if (tries2 <= 24)
				{
					point[0] += 1-(tries*64);
					point[1] += 1+(num_tries*64);
				}
				else
				{
					point[0] -= 1+(tries*64);
					point[1] -= 1+(num_tries*64);
				}

				//if (CheckAboveOK_Player(point))
				//	point[2] += 32;
				//else
				//	continue;

				point[2] += 16;

				if (wp == -1)
				{
					if (OrgVisibleBox(origin, playerMins, playerMaxs, point, flag_list[flagnum].flagentity->s.number)
						&& CheckBelowOK(point)
						&& !CheckEntitiesInSpot(point) 
						&& VectorDistance(point, origin) > 128
						&& !TooCloseToOtherSpawnpoint(flagnum, point))
					{
						//G_Printf("Adding spawn at %f %f %f.\n", point[0], point[1], point[2]);
						AddFlag_Spawn(flagnum, point, angles);
						//G_Printf("Adding spawn %f %f %f\n", point[0], point[1], point[2]);
						visible = qtrue;
					}
					//else
					//	G_Printf("Not adding spawn at %f %f %f.\n", point[0], point[1], point[2]);
				}
				else
				{
					if (OrgVisibleBox(gWPArray[wp]->origin, playerMins, playerMaxs, point, -1)
						&& CheckBelowOK(point)
						&& !CheckEntitiesInSpot(point) 
						&& VectorDistance(point, origin) > 128
						&& !TooCloseToOtherSpawnpoint(flagnum, point))
					{
						//G_Printf("Adding spawn at %f %f %f.\n", point[0], point[1], point[2]);
						AddFlag_Spawn(flagnum, point, angles);
						//G_Printf("Adding wp spawn %f %f %f\n", point[0], point[1], point[2]);
						visible = qtrue;
					}
				}
			}
		}

		if (visible != qfalse)
			break;
		else
		{
			//if (wp == -1)
				wp = GetNearestVisibleWP(flag_list[flagnum].flagentity->s.origin, flag_list[flagnum].flagentity->s.number);//NAV_FindClosestWaypointForPoint2( flag_list[flagnum].flagentity->s.origin );
			//else
			//	wp = GetNearestVisibleWP(flag_list[flagnum].flagentity->s.origin, flag_list[flagnum].flagentity->s.number);//NAV_FindClosestWaypointForPoint( flag_list[flagnum].flagentity, flag_list[flagnum].flagentity->s.origin );
		}
	}

	G_Printf("^3*** ^3DominancE^5: Added ^7%i^5 spawnpoints at flag #^7%i^5.\n", flag_list[flagnum].num_spawnpoints, flagnum);
}
Beispiel #29
0
/*
==============
AICast_PredictMovement

  Simulates movement over a number of frames, returning the end position
==============
*/
void AICast_PredictMovement( cast_state_t *cs, int numframes, float frametime, aicast_predictmove_t *move, usercmd_t *ucmd, int checkHitEnt ) {
	int frame, i;
	playerState_t ps;
	pmove_t pm;
	trace_t tr;
	vec3_t end, startHitVec, thisHitVec, lastOrg, projPoint;
	qboolean checkReachMarker;

//int pretime = Sys_MilliSeconds();
//G_Printf("PredictMovement: %f duration, %i frames\n", frametime, numframes );
	VectorCopy( vec3_origin, startHitVec );

	if ( cs->bs ) {
		ps = cs->bs->cur_ps;
	} else {
		ps = g_entities[cs->entityNum].client->ps;
	}

	ps.eFlags |= EF_DUMMY_PMOVE;

	move->stopevent = PREDICTSTOP_NONE;

	if ( checkHitEnt >= 0 && !Q_stricmp( g_entities[checkHitEnt].classname, "ai_marker" ) ) {
		checkReachMarker = qtrue;
		VectorSubtract( g_entities[checkHitEnt].r.currentOrigin, ps.origin, startHitVec );
		VectorCopy( ps.origin, lastOrg );
	} else {
		checkReachMarker = qfalse;
	}

	// don't let the frametime be too high
//	while (frametime > 0.2) {
//		numframes *= 2;
//		frametime /= 2;
//	}

	for ( frame = 0; frame < numframes; frame++ )
	{
		memset( &pm, 0, sizeof( pm ) );
		pm.ps = &ps;
		pm.cmd = *ucmd;
		pm.oldcmd = *ucmd;
		pm.ps->commandTime = 0;
		pm.cmd.serverTime = (int)( 1000.0 * frametime );
		pm.tracemask = g_entities[cs->entityNum].clipmask; //MASK_PLAYERSOLID;

		pm.trace = trap_TraceCapsule; //trap_Trace;
		pm.pointcontents = trap_PointContents;
		pm.debugLevel = qfalse;
		pm.noFootsteps = qtrue;
		// RF, not needed for prediction
		//pm.noWeapClips = qtrue;	// (SA) AI's ignore weapon clips

		// perform a pmove
		Pmove( &pm );

		if ( checkHitEnt >= 0 ) {
			// if we've hit the checkent, abort
			if ( checkReachMarker ) {
				VectorSubtract( g_entities[checkHitEnt].r.currentOrigin, pm.ps->origin, thisHitVec );
				if ( DotProduct( startHitVec, thisHitVec ) < 0 ) {
					// project the marker onto the movement vec, and check distance
					ProjectPointOntoVector( g_entities[checkHitEnt].r.currentOrigin, lastOrg, pm.ps->origin, projPoint );
					if ( VectorDistance( g_entities[checkHitEnt].r.currentOrigin, projPoint ) < 8 ) {
						move->stopevent = PREDICTSTOP_HITENT;
						goto done;
					}
				}
				// use this position as the base for the next test
				//VectorCopy( thisHitVec, startHitVec );
				VectorCopy( pm.ps->origin, lastOrg );
			}
			// if we didnt reach the marker, then check for something that blocked us
			for ( i = 0; i < pm.numtouch; i++ ) {
				if ( pm.touchents[i] == pm.ps->groundEntityNum ) {
					continue;
				}
				if ( pm.touchents[i] == checkHitEnt ) {
					move->stopevent = PREDICTSTOP_HITENT;
					goto done;
				} else if ( pm.touchents[i] < MAX_CLIENTS ||
							( pm.touchents[i] != ENTITYNUM_WORLD && ( g_entities[pm.touchents[i]].s.eType != ET_MOVER || g_entities[pm.touchents[i]].moverState != MOVER_POS1 ) ) ) {
					// we have hit another entity, so abort
					move->stopevent = PREDICTSTOP_HITCLIENT;
					goto done;
				} else if ( !Q_stricmp( g_entities[pm.touchents[i]].classname, "script_mover" ) ) {
					// avoid script_mover's
					move->stopevent = PREDICTSTOP_HITCLIENT;
					goto done;
				}
			}
		}
	}

done:

	// hack, if we are above ground, chances are it's because we only did one frame, and gravity isn't applied until
	// after the frame, so try and drop us down some
	if ( move->groundEntityNum == ENTITYNUM_NONE ) {
		VectorCopy( move->endpos, end );
		end[2] -= 32;
		trap_Trace( &tr, move->endpos, pm.mins, pm.maxs, end, pm.ps->clientNum, pm.tracemask );
		if ( !tr.startsolid && !tr.allsolid && tr.fraction < 1 ) {
			VectorCopy( tr.endpos, pm.ps->origin );
			pm.ps->groundEntityNum = tr.entityNum;
		}
	}

	// copy off the results
	VectorCopy( pm.ps->origin, move->endpos );
	move->frames = numframes;
	//move->presencetype = cs->bs->presencetype;
	VectorCopy( pm.ps->velocity, move->velocity );
	move->numtouch = pm.numtouch;
	memcpy( move->touchents, pm.touchents, sizeof( pm.touchents ) );
	move->groundEntityNum = pm.ps->groundEntityNum;

//G_Printf("PredictMovement: %i ms\n", -pretime + Sys_MilliSeconds() );
}
Beispiel #30
0
/*
================
CG_AddClientCritter
================
*/
void CG_AddClientCritter( localEntity_t *le ) {
	vec3_t	newOrigin;
	trace_t	trace;
	int		time, step = 25, i;
	vec3_t	v, ang, v2, oDelta;
	localEntity_t backup;
	float	oldSpeed, enemyDist, of;
	vec3_t	enemyPos;
	float alpha;

	if (cg_entities[le->ownerNum].currentState.otherEntityNum2 == cg.snap->ps.clientNum) {
		VectorCopy( cg.snap->ps.origin, enemyPos );
		enemyPos[2] += cg.snap->ps.viewheight;
	} else {
		VectorCopy( cg_entities[le->ownerNum].currentState.origin2, enemyPos );
	}

	VectorCopy( le->pos.trDelta, oDelta );

	// vary the enemyPos to create a psuedo-randomness
	of = (float)cg.time + le->startTime;
	enemyPos[0] += 12 * (sin(of/100) * cos(of/78));
	enemyPos[1] += 12 * (sin(of/70) * cos(of/82));
	enemyPos[2] += 12 * (sin(of/67) * cos(of/98));

	time = le->lastTrailTime+step;

	while (time <= cg.time) {
		if (time > le->refEntity.fadeStartTime) {
			alpha = (float)(time - le->refEntity.fadeStartTime)/(float)(le->refEntity.fadeEndTime - le->refEntity.fadeStartTime);
			if (alpha < 0) alpha = 0;
			else if (alpha > 1) alpha = 1;
		} else {
			alpha = 1.0;
		}

		// calculate new position
		BG_EvaluateTrajectory( &le->pos, time, newOrigin );

		VectorSubtract( enemyPos, le->refEntity.origin, v );
		enemyDist = VectorNormalize( v );

		// trace a line from previous position to new position
		CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, le->ownerNum, MASK_SHOT );

		// if stuck, kill it
		if (trace.startsolid || (trace.fraction < 1.0)) {
			// kill it
			CG_FreeLocalEntity( le );
			return;
		}

		// moved some distance
		VectorCopy( trace.endpos, le->refEntity.origin );

		if (le->leType == LE_ZOMBIE_SPIRIT) {
			le->headJuncIndex = CG_AddTrailJunc( le->headJuncIndex,
												cgs.media.zombieSpiritTrailShader,
												time,
												STYPE_STRETCH,
												le->refEntity.origin,
												(int)le->effectWidth,	// trail life
												0.3 * alpha,
												0.0,
												le->radius,
												0,
												0,//TJFL_FIXDISTORT,
												colorWhite,
												colorWhite,
												1.0, 1 );
		}

		// tracking factor
		if (le->leType == LE_ZOMBIE_BAT)
			le->bounceFactor = 3.0*(float)step/1000.0;
		else
			le->bounceFactor = 5.0*(float)step/1000.0;
		oldSpeed = VectorLength( le->pos.trDelta );

		// track the enemy
		backup = *le;
		VectorSubtract( enemyPos, le->refEntity.origin, v );
		enemyDist = VectorNormalize( v );

		if (alpha > 0.5 && (le->lastSpiritDmgTime < time - 100) && enemyDist < 24) {
			// inflict the damage!
			CG_ClientDamage( cg_entities[le->ownerNum].currentState.otherEntityNum2, le->ownerNum, CLDMG_SPIRIT );
			le->lastSpiritDmgTime = time;
		}

		VectorMA( le->pos.trDelta, le->bounceFactor*oldSpeed, v, le->pos.trDelta );
		//VectorCopy( v, le->pos.trDelta );
		if (VectorLength(le->pos.trDelta) < 1) {
			CG_FreeLocalEntity( le );
			return;
		}

		le->bounceFactor = 5.0*(float)step/1000.0;	// avoidance factor

		// the intersection is a fraction of the frametime
		le->pos.trTime = time;
		VectorCopy( le->refEntity.origin, le->pos.trBase );
		VectorNormalize( le->pos.trDelta );
		VectorScale( le->pos.trDelta, oldSpeed, le->pos.trDelta );

		// now trace ahead of time, if we're going to hit something, then avoid it
		// only avoid dangers if we don't have direct sight to the enemy
		trap_CM_BoxTrace( &trace, le->refEntity.origin, enemyPos, NULL, NULL, 0, MASK_SOLID );
		if (trace.fraction < 1.0) {
			BG_EvaluateTrajectory( &le->pos, time+1000, newOrigin );

			// if we would go passed the enemy, don't bother
			if (VectorDistance( le->refEntity.origin, enemyPos) > VectorDistance( le->refEntity.origin, newOrigin )) {

				trap_CM_BoxTrace( &trace, le->refEntity.origin, newOrigin, NULL, NULL, 0, MASK_SOLID );

				if (trace.fraction < 1.0) {
					// make sure we are not heading away from the enemy too much
					VectorNormalize2( le->pos.trDelta, v2 );
					if (DotProduct( v, v2 ) > 0.7) {
						// avoid world geometry
						backup = *le;
						le->bounceFactor = (1.0 - trace.fraction)*10.0*(float)step/1000.0;	// tracking and avoidance factor
						// reflect the velocity on the trace plane
						VectorMA( le->pos.trDelta, le->bounceFactor*oldSpeed, trace.plane.normal, le->pos.trDelta );
						if (VectorLength(le->pos.trDelta) < 1) {
							CG_FreeLocalEntity( le );
							return;
						}
						// the intersection is a fraction of the frametime
						le->pos.trTime = time;
						VectorCopy( le->refEntity.origin, le->pos.trBase );
						VectorNormalize( le->pos.trDelta );
						VectorScale( le->pos.trDelta, oldSpeed, le->pos.trDelta );
						//
						// double check end velocity
						VectorNormalize2( le->pos.trDelta, v2 );
						if (DotProduct( v, v2 ) <= 0.2) {
							// restore
							*le = backup;
						}
					}
				}
			}
		}

		// set the angles
		VectorNormalize2( le->pos.trDelta, v );
		// HACK!!! skull model is back-to-front, need to fix
		if (le->leType == LE_ZOMBIE_SPIRIT)
			VectorInverse( v );
		vectoangles( v, ang );
		AnglesToAxis( ang, le->refEntity.axis );
		// lean when turning
		if (le->leType == LE_ZOMBIE_BAT) {
			VectorSubtract( le->pos.trDelta, oDelta, v2 );
			ang[ROLL] = -5.0 * DotProduct( le->refEntity.axis[1], v2 );
			if (fabs(ang[ROLL]) > 80) {
				if (ang[ROLL] > 80) ang[ROLL] = 80;
				else ang[ROLL] = -80;
			}
		}
		AnglesToAxis( ang, le->refEntity.axis );

		// HACK: the skull is slightly higher than the origin
		if (le->leType == LE_ZOMBIE_SPIRIT) {
			// set the size scale
			for (i=0; i<3; i++)
				VectorScale( le->refEntity.axis[i], 0.35, le->refEntity.axis[i] );
			VectorMA( le->refEntity.origin, -10, le->refEntity.axis[2], le->refEntity.origin );
		}

		le->lastTrailTime = time;
		time += step;
	}

	// Bats, set the frame
	if (le->leType == LE_ZOMBIE_BAT) {
		#define	BAT_ANIM_FRAMETIME	30
		le->refEntity.frame = (cg.time/BAT_ANIM_FRAMETIME+1)%19;
		le->refEntity.oldframe = (cg.time/BAT_ANIM_FRAMETIME)%19;
		le->refEntity.backlerp = 1.0 - ((float)(cg.time%BAT_ANIM_FRAMETIME)/(float)BAT_ANIM_FRAMETIME);
	}

	// add the sound
	if (le->loopingSound) {
		if (cg.time > le->refEntity.fadeStartTime)
			trap_S_AddLoopingSound( 0, le->refEntity.origin, vec3_origin, le->loopingSound, 255 - (int)(255.0 * (float)(cg.time - le->refEntity.fadeStartTime) / (float)(le->refEntity.fadeEndTime - le->refEntity.fadeStartTime)) );
		else if (le->startTime + 1000 > cg.time)
			trap_S_AddLoopingSound( 0, le->refEntity.origin, vec3_origin, le->loopingSound, (int)(255.0 * (float)(cg.time - le->startTime) / 1000.0) );
		else
			trap_S_AddLoopingSound( 0, le->refEntity.origin, vec3_origin, le->loopingSound, 255);
	}

	trap_R_AddRefEntityToScene( &le->refEntity );
/*
	// HACK: the skull is slightly higher than the origin
	if (le->leType == LE_ZOMBIE_SPIRIT) {
		// set the size scale
		for (i=0; i<3; i++)
			VectorScale( le->refEntity.axis[i], 1.0/0.35, le->refEntity.axis[i] );
		VectorMA( le->refEntity.origin,  10, le->refEntity.axis[2], le->refEntity.origin );
	}
*/
	// Bats, add the flame
	if (le->leType == LE_ZOMBIE_BAT) {
//		float lightSize, alpha;
		//
		le->refEntity.shaderRGBA[3] = 255;
		VectorNormalize2( le->pos.trDelta, v );
		VectorInverse( v );
		v[2] += 1;
		VectorNormalize2( v, le->refEntity.fireRiseDir );

		le->refEntity.customShader = cgs.media.onFireShader2;
		trap_R_AddRefEntityToScene( &le->refEntity );
		le->refEntity.shaderTime = 1434;
		trap_R_AddRefEntityToScene( &le->refEntity );
//		le->refEntity.customShader = cgs.media.onFireShader;
//		le->refEntity.shaderTime = 0;
//		trap_R_AddRefEntityToScene( &le->refEntity );

		le->refEntity.customShader = 0;
		le->refEntity.shaderTime = 0;
/*
		// drop a dlight
		lightSize = 1.0 + 0.2*(sin(1.0*cg.time/50.0) * cos(1.0*cg.time/43.0));
		alpha = 0.2 * (lightSize / 1.2);
		trap_R_AddLightToScene( le->refEntity.origin, 150.0 + 80.0*lightSize, 1.000000*alpha, 0.603922*alpha, 0.207843*alpha, 0 );
		// add some sound
		trap_S_AddLoopingSound( -1, le->refEntity.origin, vec3_origin, cgs.media.flameSound, 100 );
		trap_S_AddLoopingSound( -1, le->refEntity.origin, vec3_origin, cgs.media.flameBlowSound, 100 );
*/
	}
}