Пример #1
0
/*
============
BG_PlayerTouchesItem

Items can be picked up without actually touching their physical bounds to make
grabbing them easier
============
*/
qboolean	BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime ) {
	vec3_t		origin;

	BG_EvaluateTrajectory( &item->pos, atTime, origin );

	// we are ignoring ducked differences here
	if ( ps->origin[0] - origin[0] > 44
		|| ps->origin[0] - origin[0] < -50
		|| ps->origin[1] - origin[1] > 36
		|| ps->origin[1] - origin[1] < -36
		|| ps->origin[2] - origin[2] > 36
		|| ps->origin[2] - origin[2] < -36 ) {
		return qfalse;
	}

	return qtrue;
}
Пример #2
0
int qlua_setpos(lua_State *L) {
	centity_t	*luaentity;
	vec3_t		origin;

	luaL_checktype(L,1,LUA_TUSERDATA);
	luaL_checktype(L,2,LUA_TVECTOR);

	luaentity = lua_toentity(L,1);
	if(luaentity != NULL) {
			BG_EvaluateTrajectory( &luaentity->currentState.pos, cg.time, origin );
			lua_tovector(L,2,luaentity->currentState.pos.trBase);
			luaentity->currentState.pos.trDuration += (cg.time - luaentity->currentState.pos.trTime);
			luaentity->currentState.pos.trTime = cg.time;
			
			VectorCopy(luaentity->currentState.pos.trBase, luaentity->currentState.origin);
		return 1;
	}
	return 0;
}
Пример #3
0
/*
================
G_ExplodeMissile

Explode a missile without an impact
================
*/
void G_ExplodeMissile( gentity_t *ent ) {
	vec3_t		dir;
	vec3_t		origin;

	BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
	SnapVector( origin );
	G_SetOrigin( ent, origin );

	// we don't have a valid direction, so just point straight up
	dir[0] = dir[1] = 0;
	dir[2] = 1;

	ent->s.eType = ET_GENERAL;
	G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( dir ) );

	ent->freeAfterEvent = qtrue;

	ent->takedamage = qfalse;
	// splash damage
	if ( ent->splashDamage ) {
		//NOTE: vehicle missiles don't have an ent->parent set, so check that here and set it
		if ( ent->s.eType == ET_MISSILE//missile
			&& (ent->s.eFlags&EF_JETPACK_ACTIVE)//vehicle missile
			&& ent->r.ownerNum < MAX_CLIENTS )//valid client owner
		{//set my parent to my owner for purposes of damage credit...
			ent->parent = &g_entities[ent->r.ownerNum];
		}
		if( G_RadiusDamage( ent->r.currentOrigin, ent->parent, ent->splashDamage, ent->splashRadius, ent, 
				ent, ent->splashMethodOfDeath ) ) 
		{
			if (ent->parent)
			{
				g_entities[ent->parent->s.number].client->accuracy_hits++;
			}
			else if (ent->activator)
			{
				g_entities[ent->activator->s.number].client->accuracy_hits++;
			}
		}
	}

	trap_LinkEntity( ent );
}
Пример #4
0
/*
==================
CG_AddMoveScaleFade
==================
*/
static void CG_AddMoveScaleFade( localEntity_t *le ) {
	refEntity_t	*re;
	float		c;
	vec3_t		delta;
	float		len;

	re = &le->refEntity;

	// fade / grow time
//	c = ( le->endTime - cg.time ) * le->lifeRate;
	if ( le->fadeInTime > le->startTime && cg.time < le->fadeInTime ) {
		// fade / grow time
		c = 1.0 - (float) ( le->fadeInTime - cg.time ) / ( le->fadeInTime - le->startTime );
	}
	else {
		// fade / grow time
		c = ( le->endTime - cg.time ) * le->lifeRate;
	}

	// Ridah, spark
	if ( !( le->leFlags & LEF_NOFADEALPHA ) )
	// done.
	re->shaderRGBA[3] = 0xff * c * le->color[3];

	if ( !( le->leFlags & LEF_PUFF_DONT_SCALE ) ) {
		c = ( le->endTime - cg.time ) * le->lifeRate;
		re->radius = le->radius * ( 1.0 - c ) + 8;
	}

	BG_EvaluateTrajectory( &le->pos, cg.time, re->origin );

	// if the view would be "inside" the sprite, kill the sprite
	// so it doesn't add too much overdraw
	VectorSubtract( re->origin, cg.refdef.vieworg, delta );
	len = VectorLength( delta );
	if ( len < le->radius ) {
		CG_FreeLocalEntity( le );
		return;
	}

	trap_R_AddRefEntityToScene( re );
}
Пример #5
0
/*
=======================================================================================================================================
CG_BubbleThink
=======================================================================================================================================
*/
void CG_BubbleThink(localEntity_t *le) {
	int contents;
	vec3_t newOrigin;
	trace_t trace;

	// calculate new position
	BG_EvaluateTrajectory(&le->pos, cg.time, newOrigin);
	// trace a line from previous position to new position
	CG_Trace(&trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID);

	contents = CG_PointContents(trace.endpos, -1);

	if (!(contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))) {
		// bubble isn't in liquid anymore, remove it
		CG_FreeLocalEntity(le);
		return;
	}

	CG_AddMoveScaleFade(le);
}
Пример #6
0
/*
=======================================================================================================================================
CG_BloodTrail

Leave expanding blood puffs behind gibs.
=======================================================================================================================================
*/
void CG_BloodTrail(localEntity_t *le) {
	int t;
	int t2;
	int step;
	vec3_t newOrigin;
	localEntity_t *blood;

	step = 150;
	t = step * ((cg.time - cg.frametime + step) / step);
	t2 = step * (cg.time / step);

	for (; t <= t2; t += step) {
		BG_EvaluateTrajectory(&le->pos, t, newOrigin);

		blood = CG_SmokePuff(newOrigin, vec3_origin, 20, 1, 1, 1, 1, 2000, t, 0, 0, cgs.media.bloodTrailShader);
		// use the optimized version
		blood->leType = LE_FALL_SCALE_FADE;
		// drop a total of 40 units over its lifetime
		blood->pos.trDelta[2] = 40;
	}
}
Пример #7
0
/***
Stops rotational movement on ent immediately.
@function HaltAngles
@param ent Entity or entity number.
@return Success or failure.
*/
static int Mover_HaltAngles(lua_State * L)
{
	lent_t			*lent;
	gentity_t       *ent = NULL;
	int				id = 0;

	if(lua_isnumber(L, 1)) {
		id = luaL_checkint(L, 1);
		if(id < 0 || id > MAX_GENTITIES - 1) {
			lua_pushboolean(L, qfalse);
			return 1;
		}
		ent = &g_entities[id];
		if(ent) {
			lua_pushboolean(L, qfalse);
			return 1;
		}
	} else {
		lent = Lua_GetEntity(L, 1);
		if(lent == NULL || lent->e == NULL) {
			lua_pushboolean(L, qfalse);
			return 1;
		}
		ent = lent->e;
	}

	LUA_DEBUG("Mover_HaltAngles - start: ent=%d", ent->s.number);
	if(ent)
	{
		BG_EvaluateTrajectory(&ent->s.apos, level.time, ent->s.apos.trBase);
		ent->s.apos.trType = TR_STATIONARY;
		ent->s.apos.trTime = level.time;
		trap_LinkEntity(ent);
		LUA_DEBUG("Mover_HaltAngles - return: halted ent");
	}

	lua_pushboolean(L, qtrue);
	return 1;
}
Пример #8
0
/*
==============
CG_CheckEvents

==============
*/
void CG_CheckEvents( centity_t *cent )
{
	// check for event-only entities
	if ( cent->currentState.eType > ET_EVENTS )
	{
		if ( cent->previousEvent )
		{
			return;	// already fired
		}
		cent->previousEvent = 1;

		// if this is a player event set the entity number of the client entity number
		if ( cent->currentState.eFlags & EF_PLAYER_EVENT )
		{
			cent->currentState.number = cent->currentState.otherEntityNum;
		}

		cent->currentState.event = cent->currentState.eType - ET_EVENTS;
	} 
	else 
	{
		// check for events riding with another entity
		if ( cent->currentState.event == cent->previousEvent )
		{
			return;
		}
		cent->previousEvent = cent->currentState.event;
		if ( ( cent->currentState.event & ~EV_EVENT_BITS ) == 0 )
		{
			return;
		}
	}

	// calculate the position at exactly the frame time
	BG_EvaluateTrajectory( &cent->currentState.pos, cg.snap->serverTime, cent->lerpOrigin );
	CG_SetEntitySoundPosition( cent );

	CG_EntityEvent( cent, cent->lerpOrigin );
}
Пример #9
0
/***
Stops translational movement on ent immediately.
@function Halt
@param ent Entity or entity number.
@return Success or failure.
*/
static int Mover_Halt(lua_State *L) {
	lent_t		*lent;
	gentity_t	*ent = NULL;
	int			id = 0;
	
	if(lua_isnumber(L, 1)) {
		id =  luaL_checkint(L, 1);
		if(id < 0 || id > MAX_GENTITIES - 1) {
			lua_pushboolean(L, qfalse);
			return 1;
		}
		ent = &g_entities[id];
		if(ent == NULL) {
			lua_pushboolean(L, qfalse);
			return 1;
		}
	} else {
		lent = Lua_GetEntity(L, 1);
		if(lent == NULL || lent->e == NULL) {
			lua_pushboolean(L, qfalse);
			return 1;
		}
		ent = lent->e;
	}

	LUA_DEBUG("Mover_Halt - start: end=%d", ent->s.number);
	BG_EvaluateTrajectory(&ent->s.pos, level.time, ent->r.currentOrigin);
	VectorCopy(ent->r.currentOrigin, ent->s.pos.trBase);
	ent->s.pos.trType = TR_STATIONARY;
	ent->s.pos.trTime = level.time;
	ent->nextthink = 0;
	ent->think = NULL;
	ent->nextTrain = NULL;
	trap_LinkEntity(ent);
	LUA_DEBUG("Mover_Halt - return: halted ent");
	lua_pushboolean(L, qtrue);
	return 1;
}
Пример #10
0
static void CG_AddMoveScaleFade( localEntity_t *le ) {
	refEntity_t	*re;
	float		c;
	vector3		delta;
	float		len;
	refdef_t *refdef = CG_GetRefdef();

	re = &le->refEntity;

	if ( le->fadeInTime > le->startTime && cg.time < le->fadeInTime ) {
		// fade / grow time
		c = 1.0f - (float)(le->fadeInTime - cg.time) / (le->fadeInTime - le->startTime);
	}
	else {
		// fade / grow time
		c = (le->endTime - cg.time) * le->lifeRate;
	}

	re->shaderRGBA[3] = 0xff * c * le->color[3];

	if ( !(le->leFlags & LEF_PUFF_DONT_SCALE) ) {
		re->radius = le->radius * (1.0f - c) + 8;
	}

	BG_EvaluateTrajectory( &le->pos, cg.time, &re->origin );

	// if the view would be "inside" the sprite, kill the sprite
	// so it doesn't add too much overdraw
	VectorSubtract( &re->origin, &refdef->vieworg, &delta );
	len = VectorLength( &delta );
	if ( len < le->radius ) {
		CG_FreeLocalEntity( le );
		return;
	}

	SE_R_AddRefEntityToScene( re, MAX_CLIENTS );
}
Пример #11
0
void
G_minethink(gentity_t *ent)
{
  trace_t tr;
  vec3_t end, origin, dir;
  gentity_t *traceEnt;

  ent->nextthink = level.time + 100;

  BG_EvaluateTrajectory(&ent->s.pos, level.time, origin);
  SnapVector(origin);
  G_SetOrigin(ent, origin);

  // set aiming directions
  VectorCopy(origin,end);
  end[2] += 10;//aim up

  trap_Trace(&tr, origin, NULL, NULL, end, ent->s.number, MASK_SHOT);
  if (tr.surfaceFlags & SURF_NOIMPACT)
    return;

  traceEnt = &g_entities[tr.entityNum];

  dir[0] = dir[1] = 0;
  dir[2] = 1;

  if (traceEnt->client && (traceEnt->r.svFlags & SVF_BOT)
      && traceEnt->health > 0 && traceEnt->client->ps.stats[STAT_PTEAM] == PTE_ALIENS)//FIRE IN ZE HOLE!
  {//Might want to check team too
    ent->s.eType = ET_GENERAL;
    G_AddEvent(ent, EV_MISSILE_MISS, DirToByte(dir));
    ent->freeAfterEvent = qtrue;
    G_RadiusDamage(ent->r.currentOrigin, ent->parent, ent->splashDamage, ent->splashRadius, ent, ent->splashMethodOfDeath);
    ent->parent->numMines -= 1;
    trap_LinkEntity(ent);
  }
}
Пример #12
0
/*
================
G_ExplodeMissile

Explode a missile without an impact
================
*/
void G_ExplodeMissile( gentity_t *ent ) {
    vec3_t		dir;
    vec3_t		origin;

    BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
    SnapVector( origin );
    G_SetOrigin( ent, origin );

    // we don't have a valid direction, so just point straight up
    dir[0] = dir[1] = 0;
    dir[2] = 1;

    ent->s.eType = ET_GENERAL;
    G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( dir ) );

    ent->freeAfterEvent = qtrue;

    ent->takedamage = qfalse;
    // splash damage
    if ( ent->splashDamage ) {
        if( G_RadiusDamage( ent->r.currentOrigin, ent->parent, ent->splashDamage, ent->splashRadius, ent,
                            ent, ent->splashMethodOfDeath ) )
        {
            if (ent->parent)
            {
                g_entities[ent->parent->s.number].client->accuracy_hits++;
            }
            else if (ent->activator)
            {
                g_entities[ent->activator->s.number].client->accuracy_hits++;
            }
        }
    }

    trap->LinkEntity( (sharedEntity_t *)ent );
}
Пример #13
0
/*
==================
CG_AddMoveScaleFade
==================
*/
static void CG_AddMoveScaleFade( localEntity_t *le ) {
	refEntity_t	*re;
	gfixed		c;
	bvec3_t		delta;
	bfixed		len;

	re = &le->refEntity;

	if ( le->fadeInTime > le->startTime && cg.time < le->fadeInTime ) {
		// fade / grow time
		c = GFIXED_1 - MAKE_GFIXED( le->fadeInTime - cg.time ) / MAKE_GFIXED( le->fadeInTime - le->startTime );
	}
	else {
		// fade / grow time
		c = MAKE_GFIXED( le->endTime - cg.time ) * le->lifeRate;
	}

	re->shaderRGBA[3] = FIXED_TO_INT( GFIXED(255,0) * c * le->color[3] );

	if ( !( le->leFlags & LEF_PUFF_DONT_SCALE ) ) {
		re->radius = (le->radius * ( GFIXED_1 - c )) + BFIXED(8,0);
	}

	BG_EvaluateTrajectory( &le->pos, cg.time, re->origin );

	// if the view would be "inside" the sprite, kill the sprite
	// so it doesn't add too much overdraw
	VectorSubtract( re->origin, cg.refdef.vieworg, delta );
	len = FIXED_VEC3LEN( delta );
	if ( len < le->radius ) {
		CG_FreeLocalEntity( le );
		return;
	}

	_CG_trap_R_AddRefEntityToScene( re );
}
Пример #14
0
/*
================
CG_AddSparkElements
================
*/
void CG_AddSparkElements( localEntity_t *le ) {
	vec3_t	newOrigin;
	trace_t	trace;
	float	time;
	float	lifeFrac;

	time = (float)(cg.time - cg.frametime);

	while (1) {
		// calculate new position
		BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin );

//		if ((le->endTime - le->startTime) > 500) {

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

			// if stuck, kill it
			if (trace.startsolid) {
				// HACK, some walls screw up, so just pass through if starting in a solid
				VectorCopy( newOrigin, trace.endpos );
				trace.fraction = 1.0;
			}

			// moved some distance
			VectorCopy( trace.endpos, le->refEntity.origin );
/*
		} else
		{	// just move it there

			VectorCopy( newOrigin, le->refEntity.origin );
			trace.fraction = 1.0;

		}
*/
		time += cg.frametime * trace.fraction;

		lifeFrac = (float)(cg.time - le->startTime) / (float)(le->endTime - le->startTime);

		// add a trail
		le->headJuncIndex = CG_AddSparkJunc( le->headJuncIndex,
									le->refEntity.customShader,
									le->refEntity.origin,
									200,
									1.0 - lifeFrac,	// start alpha
									0.0,//1.0 - lifeFrac,	// end alpha
									lifeFrac * 2.0 * (((le->endTime - le->startTime) > 400)+1)*1.5,
									lifeFrac * 2.0 * (((le->endTime - le->startTime) > 400)+1)*1.5 );

		// if it is in a nodrop zone, remove it
		// this keeps gibs from waiting at the bottom of pits of death
		// and floating levels
// for some reason SFM1.BSP is one big NODROP zone
//		if ( trap_CM_PointContents( le->refEntity.origin, 0 ) & CONTENTS_NODROP ) {
//			CG_FreeLocalEntity( le );
//			return;
//		}

		if (trace.fraction < 1.0) {
			// just kill it
			CG_FreeLocalEntity( le );
			return;
/*
			// reflect the velocity on the trace plane
			CG_ReflectVelocity( le, &trace );
			// the intersection is a fraction of the frametime
			le->pos.trTime = (int)time;
*/
		}

		if ( trace.fraction == 1.0 || time >= (float)cg.time ) {
			return;
		}
	}

}
Пример #15
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 );
*/
	}
}
Пример #16
0
/*
================
CG_AddFragment
================
*/
void CG_AddFragment( localEntity_t *le ) {
	vec3_t	newOrigin;
	trace_t	trace;
	refEntity_t		*re;
	float	flameAlpha = 0.0; // TTimo: init
	vec3_t	flameDir;
	qboolean	hasFlame = qfalse;
	int i;

	// Ridah
	re = &le->refEntity;
	if (!re->fadeStartTime || re->fadeEndTime < le->endTime) {
		if (le->endTime - cg.time > 5000) {
			re->fadeStartTime = le->endTime - 5000;
		} else {
			re->fadeStartTime = le->endTime - 1000;
		}
		re->fadeEndTime = le->endTime;
	}

	// Ridah, flaming gibs
	if (le->onFireStart && (le->onFireStart < cg.time && le->onFireEnd > cg.time)) {
		hasFlame = qtrue;
		// calc the alpha
		flameAlpha = 1.0 - ((float)(cg.time - le->onFireStart)/(float)(le->onFireEnd - le->onFireStart));
		if (flameAlpha < 0.0) flameAlpha = 0.0;
		if (flameAlpha > 1.0) flameAlpha = 1.0;
		trap_S_AddLoopingSound( -1, le->refEntity.origin, vec3_origin, cgs.media.flameCrackSound, (int)(20.0*flameAlpha) );
	}

//----(SA)	added
	if(le->leFlags & LEF_SMOKING) {
		float		alpha;
		refEntity_t	flash;

		// create a little less smoke

		//	TODO: FIXME: this is not quite right, because it'll become fps dependant - in a bad way.
		//		the slower the fps, the /more/ smoke there'll be, probably driving the fps lower.
		if(!(rand()%5)) {
			alpha = 1.0 - ((float)(cg.time - le->startTime)/(float)(le->endTime - le->startTime));
			alpha *= 0.25f;
			memset (&flash, 0, sizeof (flash));
			CG_PositionEntityOnTag( &flash, &le->refEntity, "tag_flash", 0, NULL);
			CG_ParticleImpactSmokePuffExtended(cgs.media.smokeParticleShader, flash.origin, 1000, 8, 20, 20, alpha);
		}
	}
//----(SA)	end

	if ( le->pos.trType == TR_STATIONARY ) {
		int		t;

		// Ridah, add the flame
		if (hasFlame) {
			refEntity_t backupEnt;

			backupEnt = le->refEntity;

			VectorClear( flameDir );
			flameDir[2] = 1;

			le->refEntity.shaderRGBA[3] = (unsigned char)(255.0*flameAlpha);
			VectorCopy( flameDir, le->refEntity.fireRiseDir );
			le->refEntity.customShader = cgs.media.onFireShader;
			trap_R_AddRefEntityToScene( &le->refEntity );
			le->refEntity.customShader = cgs.media.onFireShader2;
			trap_R_AddRefEntityToScene( &le->refEntity );

			le->refEntity = backupEnt;
		}
		
		t = le->endTime - cg.time;
		trap_R_AddRefEntityToScene( &le->refEntity );

		return;

	} else if ( le->pos.trType == TR_GRAVITY_PAUSED ) {
		int		t;

		// Ridah, add the flame
		if (hasFlame) {
			refEntity_t backupEnt;

			backupEnt = le->refEntity;

			VectorClear( flameDir );
			flameDir[2] = 1;

			le->refEntity.shaderRGBA[3] = (unsigned char)(255.0*flameAlpha);
			VectorCopy( flameDir, le->refEntity.fireRiseDir );
			le->refEntity.customShader = cgs.media.onFireShader;
			trap_R_AddRefEntityToScene( &le->refEntity );
			le->refEntity.customShader = cgs.media.onFireShader2;
			trap_R_AddRefEntityToScene( &le->refEntity );

			le->refEntity = backupEnt;
		}
		
		t = le->endTime - cg.time;
		trap_R_AddRefEntityToScene( &le->refEntity );


		// trace a line from previous position down, to see if I should start falling again

		VectorCopy(le->refEntity.origin, newOrigin);
		newOrigin [2] -= 5;
		CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_MISSILECLIP );

		if(trace.fraction == 1.0)	// it's clear, start moving again
		{
			VectorClear(le->pos.trDelta);
			VectorClear(le->angles.trDelta);
			le->pos.trType = TR_GRAVITY;	// nothing below me, start falling again
		}

		else
			return;
	}

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

	if (hasFlame) {
		// calc the flame dir
		VectorSubtract( le->refEntity.origin, newOrigin, flameDir );
		if (VectorLength( flameDir ) == 0) {
			flameDir[2] = 1;
			// play a burning sound when not moving
			trap_S_AddLoopingSound( 0, newOrigin, vec3_origin, cgs.media.flameSound, (int)(0.3*255.0*flameAlpha) );
		} else {
			VectorNormalize( flameDir );
			// play a flame blow sound when moving
			trap_S_AddLoopingSound( 0, newOrigin, vec3_origin, cgs.media.flameBlowSound, (int)(0.3*255.0*flameAlpha) );
		}
	}


	// trace a line from previous position to new position
	CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID );
	if ( trace.fraction == 1.0 ) {
		// still in free fall
		VectorCopy( newOrigin, le->refEntity.origin );

		if ( le->leFlags & LEF_TUMBLE || le->angles.trType == TR_LINEAR) {
			vec3_t angles;

			BG_EvaluateTrajectory( &le->angles, cg.time, angles );
			AnglesToAxis( angles, le->refEntity.axis );
			if (le->sizeScale && le->sizeScale != 1.0) {
				for (i=0;i<3;i++) VectorScale( le->refEntity.axis[i], le->sizeScale, le->refEntity.axis[i] );
			}
		}

		// Ridah, add the flame
		if (hasFlame) {
			refEntity_t backupEnt;

			backupEnt = le->refEntity;

			le->refEntity.shaderRGBA[3] = (unsigned char)(255.0*flameAlpha);
			VectorCopy( flameDir, le->refEntity.fireRiseDir );
			le->refEntity.customShader = cgs.media.onFireShader;
			trap_R_AddRefEntityToScene( &le->refEntity );
			le->refEntity.customShader = cgs.media.onFireShader2;
			trap_R_AddRefEntityToScene( &le->refEntity );

			le->refEntity = backupEnt;
		}

		trap_R_AddRefEntityToScene( &le->refEntity );

		// add a blood trail
		if ( le->leBounceSoundType == LEBS_BLOOD ) {
			CG_BloodTrail( le );
		}
		
		return;
	}

	// if it is in a nodrop zone, remove it
	// this keeps gibs from waiting at the bottom of pits of death
	// and floating levels
	if ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) {
		CG_FreeLocalEntity( le );
		return;
	}

	// do a bouncy sound
	CG_FragmentBounceSound( le, &trace );

	// reflect the velocity on the trace plane
	CG_ReflectVelocity( le, &trace );

	// break on contact?
	if (le->breakCount) {
		clientInfo_t	*ci;
		int				clientNum;
		localEntity_t	*nle;
		vec3_t			dir;

		clientNum = le->ownerNum;
		if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
			CG_Error( "Bad clientNum on player entity");
		}
		ci = &cgs.clientinfo[ clientNum ];

		// spawn some new fragments
		for (i=0;i<=le->breakCount;i++) {
			nle = CG_AllocLocalEntity();
			memcpy( &(nle->leType), &(le->leType), sizeof(localEntity_t) - 2*sizeof(localEntity_t *) );
			if (nle->breakCount-- < 2)
				nle->refEntity.hModel = ci->gibModels[rand()%2];
			else
				nle->refEntity.hModel = ci->gibModels[rand()%4];
			// make it smaller
			nle->endTime = cg.time + 5000 + rand()%2000;
			nle->sizeScale *= 0.8;
			if (nle->sizeScale < 0.7) {
				nle->sizeScale = 0.7;
				nle->leBounceSoundType = 0;
			}
			// move us a bit
			VectorNormalize2( nle->pos.trDelta, dir );
			VectorMA( trace.endpos, 4.0*le->sizeScale*i, dir, nle->pos.trBase );
			// randomize vel a bit
			VectorMA( nle->pos.trDelta, VectorLength(nle->pos.trDelta)*0.3, bytedirs[rand()%NUMVERTEXNORMALS], nle->pos.trDelta );
		}
		// we're done
		CG_FreeLocalEntity( le );
		return;
	}

	if (le->pos.trType == TR_STATIONARY && le->leMarkType == LEMT_BLOOD) 
	{
		// RF, disabled for performance reasons in boss1
		//if (le->leBounceSoundType)
		//	CG_BloodPool (le, cgs.media.bloodPool, &trace);		
				
		// leave a mark
		if (le->leMarkType)
			CG_FragmentBounceMark( le, &trace );
	}

	// Ridah, add the flame
	if (hasFlame) {
		refEntity_t backupEnt;

		backupEnt = le->refEntity;

		le->refEntity.shaderRGBA[3] = (unsigned char)(255.0*flameAlpha);
		VectorCopy( flameDir, le->refEntity.fireRiseDir );
		le->refEntity.customShader = cgs.media.onFireShader;
		trap_R_AddRefEntityToScene( &le->refEntity );
		le->refEntity.customShader = cgs.media.onFireShader2;
		trap_R_AddRefEntityToScene( &le->refEntity );

		le->refEntity = backupEnt;
	}

	trap_R_AddRefEntityToScene( &le->refEntity );
}
Пример #17
0
//-----------------------------------------------------
static void turret_aim( gentity_t *self )
//-----------------------------------------------------
{
	vec3_t	enemyDir, org, org2;
	vec3_t	desiredAngles, setAngle;
	float	diffYaw = 0.0f, diffPitch = 0.0f, turnSpeed;
	const float pitchCap = 40.0f;
	gentity_t *top = &g_entities[self->r.ownerNum];
	if ( !top )
	{
		return;
	}

	// move our gun base yaw to where we should be at this time....
	BG_EvaluateTrajectory( &top->s.apos, level.time, top->r.currentAngles );
	top->r.currentAngles[YAW] = AngleNormalize180( top->r.currentAngles[YAW] );
	top->r.currentAngles[PITCH] = AngleNormalize180( top->r.currentAngles[PITCH] );
	turnSpeed = top->speed;

	if ( self->painDebounceTime > level.time )
	{
		desiredAngles[YAW] = top->r.currentAngles[YAW]+flrand(-45,45);
		desiredAngles[PITCH] = top->r.currentAngles[PITCH]+flrand(-10,10);

		if (desiredAngles[PITCH] < -pitchCap)
		{
			desiredAngles[PITCH] = -pitchCap;
		}
		else if (desiredAngles[PITCH] > pitchCap)
		{
			desiredAngles[PITCH] = pitchCap;
		}

		diffYaw = AngleSubtract( desiredAngles[YAW], top->r.currentAngles[YAW] );
		diffPitch = AngleSubtract( desiredAngles[PITCH], top->r.currentAngles[PITCH] );
		turnSpeed = flrand( -5, 5 );
	}
	else if ( self->enemy )
	{
		// ...then we'll calculate what new aim adjustments we should attempt to make this frame
		// Aim at enemy
		VectorCopy( self->enemy->r.currentOrigin, org );
		org[2]+=self->enemy->r.maxs[2]*0.5f;
		if (self->enemy->s.eType == ET_NPC &&
			self->enemy->s.NPC_class == CLASS_VEHICLE &&
			self->enemy->m_pVehicle &&
			self->enemy->m_pVehicle->m_pVehicleInfo->type == VH_WALKER)
		{ //hack!
			org[2] += 32.0f;
		}
		/*
		mdxaBone_t	boltMatrix;

		// Getting the "eye" here
		gi.G2API_GetBoltMatrix( self->ghoul2, self->playerModel, 
					self->torsoBolt,
					&boltMatrix, self->r.currentAngles, self->s.origin, (cg.time?cg.time:level.time),
					NULL, self->s.modelScale );

		gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, org2 );
		*/
		VectorCopy( top->r.currentOrigin, org2 );

		VectorSubtract( org, org2, enemyDir );
		vectoangles( enemyDir, desiredAngles );
		desiredAngles[PITCH] = AngleNormalize180(desiredAngles[PITCH]);

		if (desiredAngles[PITCH] < -pitchCap)
		{
			desiredAngles[PITCH] = -pitchCap;
		}
		else if (desiredAngles[PITCH] > pitchCap)
		{
			desiredAngles[PITCH] = pitchCap;
		}

		diffYaw = AngleSubtract( desiredAngles[YAW], top->r.currentAngles[YAW] );
		diffPitch = AngleSubtract( desiredAngles[PITCH], top->r.currentAngles[PITCH] );
	}
	else
	{//FIXME: Pan back and forth in original facing
		// no enemy, so make us slowly sweep back and forth as if searching for a new one
		desiredAngles[YAW] = sin( level.time * 0.0001f + top->count );
		desiredAngles[YAW] *=  60.0f;
		desiredAngles[YAW] += self->s.angles[YAW];
		desiredAngles[YAW] = AngleNormalize180( desiredAngles[YAW] );
		diffYaw = AngleSubtract( desiredAngles[YAW], top->r.currentAngles[YAW] );
		diffPitch = AngleSubtract( 0, top->r.currentAngles[PITCH] );
		turnSpeed = 1.0f;
	}

	if ( diffYaw )
	{
		// cap max speed....
		if ( fabs(diffYaw) > turnSpeed )
		{
			diffYaw = ( diffYaw >= 0 ? turnSpeed : -turnSpeed );
		}
	}
	if ( diffPitch )
	{
		if ( fabs(diffPitch) > turnSpeed )
		{
			// cap max speed
			diffPitch = (diffPitch > 0.0f ? turnSpeed : -turnSpeed );
		}
	}
	// ...then set up our desired yaw
	VectorSet( setAngle, diffPitch, diffYaw, 0 );

	VectorCopy( top->r.currentAngles, top->s.apos.trBase );
	VectorScale( setAngle, (1000/FRAMETIME), top->s.apos.trDelta );
	top->s.apos.trTime = level.time;
	top->s.apos.trType = TR_LINEAR_STOP;
	top->s.apos.trDuration = FRAMETIME;

	if ( diffYaw || diffPitch )
	{
		top->s.loopSound = G_SoundIndex( "sound/vehicles/weapons/hoth_turret/turn.wav" );
	}
	else
	{
		top->s.loopSound = 0;
	}
}
Пример #18
0
/*
================
G_RunMissile
================
*/
void G_RunMissile( gentity_t *ent ) {
    vec3_t		origin, groundSpot;
    trace_t		tr;
    int			passent;
    qboolean	isKnockedSaber = qfalse;

    if (ent->neverFree && ent->s.weapon == WP_SABER && (ent->flags & FL_BOUNCE_HALF))
    {
        isKnockedSaber = qtrue;
        ent->s.pos.trType = TR_GRAVITY;
    }

    // get current position
    BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );


    //If its a rocket, and older than 500ms, make it solid to the shooter.
    if ((g_tweakWeapons.integer & WT_SOLID_ROCKET) && (ent->s.weapon == WP_ROCKET_LAUNCHER) && (!ent->raceModeShooter) && (ent->nextthink - level.time < 9500)) {
        ent->r.ownerNum = ENTITYNUM_WORLD;
    }

    // if this missile bounced off an invulnerability sphere
    if ( ent->target_ent ) {
        passent = ent->target_ent->s.number;
    }
    else {
        // ignore interactions with the missile owner
        if ( (ent->r.svFlags&SVF_OWNERNOTSHARED)
                && (ent->s.eFlags&EF_JETPACK_ACTIVE) )
        {   //A vehicle missile that should be solid to its owner
            //I don't care about hitting my owner
            passent = ent->s.number;
        }
        else
        {
            passent = ent->r.ownerNum;
        }
    }
    // trace a line from the previous position to the current position
    if (d_projectileGhoul2Collision.integer == 1) //JAPRO - Serverside - Weapons - New Hitbox Option
    {
        JP_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask, qfalse, G2TRFLAG_DOGHOULTRACE|G2TRFLAG_GETSURFINDEX|G2TRFLAG_THICK|G2TRFLAG_HITCORPSES, g_g2TraceLod.integer );

        if (tr.fraction != 1.0 && tr.entityNum < ENTITYNUM_WORLD)
        {
            gentity_t *g2Hit = &g_entities[tr.entityNum];

            if (g2Hit->inuse && g2Hit->client && g2Hit->ghoul2)
            {   //since we used G2TRFLAG_GETSURFINDEX, tr.surfaceFlags will actually contain the index of the surface on the ghoul2 model we collided with.
                g2Hit->client->g2LastSurfaceHit = tr.surfaceFlags;
                g2Hit->client->g2LastSurfaceTime = level.time;
            }

            if (g2Hit->ghoul2)
            {
                tr.surfaceFlags = 0; //clear the surface flags after, since we actually care about them in here.
            }
        }
    }
    else
    {
        JP_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask, qfalse, 0, 0 );
    }

    if ( tr.startsolid || tr.allsolid ) {
        // make sure the tr.entityNum is set to the entity we're stuck in
        JP_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask, qfalse, 0, 0 );
        tr.fraction = 0;
    }
    else {
        VectorCopy( tr.endpos, ent->r.currentOrigin );
    }

    if (ent->passThroughNum && tr.entityNum == (ent->passThroughNum-1))
    {
        VectorCopy( origin, ent->r.currentOrigin );
        trap->LinkEntity( (sharedEntity_t *)ent );
        goto passthrough;
    }

    trap->LinkEntity( (sharedEntity_t *)ent );

    if (ent->s.weapon == G2_MODEL_PART && !ent->bounceCount)
    {
        vec3_t lowerOrg;
        trace_t trG;

        VectorCopy(ent->r.currentOrigin, lowerOrg);
        lowerOrg[2] -= 1;
        JP_Trace( &trG, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, lowerOrg, passent, ent->clipmask, qfalse, 0, 0 );

        VectorCopy(trG.endpos, groundSpot);

        if (!trG.startsolid && !trG.allsolid && trG.entityNum == ENTITYNUM_WORLD)
        {
            ent->s.groundEntityNum = trG.entityNum;
        }
        else
        {
            ent->s.groundEntityNum = ENTITYNUM_NONE;
        }
    }

    if (tr.fraction != 1) { //Hit something maybe
        qboolean skip = qfalse;

        gentity_t *other = &g_entities[tr.entityNum]; //Check to see if we hit a lightsaber and they are in another dimension, if so dont do the hit code..
        if (other && other->r.contents & CONTENTS_LIGHTSABER)
        {
            gentity_t *otherOwner = &g_entities[other->r.ownerNum];
            gentity_t *owner = &g_entities[ent->r.ownerNum];
            /*
            if (owner->s.bolt1 && !otherOwner->s.bolt1)//We are dueling/racing and they are not
            	skip = qtrue;
            else if (!owner->s.bolt1 && otherOwner->s.bolt1)//They are dueling/racing and we are not
            	skip = qtrue;
            */
            if (owner->s.bolt1 != otherOwner->s.bolt1) //Dont impact if its from another dimension
                skip = qtrue;
        }

        if ( tr.fraction != 1 && !skip) {

            // never explode or bounce on sky
            if ( tr.surfaceFlags & SURF_NOIMPACT ) {
                // If grapple, reset owner
                if (ent->parent && ent->parent->client && ent->parent->client->hook == ent) {
                    ent->parent->client->hook = NULL;
                }

                if ((ent->s.weapon == WP_SABER && ent->isSaberEntity) || isKnockedSaber)
                {
                    G_RunThink( ent );
                    return;
                }
                else if (ent->s.weapon != G2_MODEL_PART)
                {
                    G_FreeEntity( ent );
                    return;
                }
            }

            if (ent->s.weapon > WP_NONE && ent->s.weapon < WP_NUM_WEAPONS &&
                    (tr.entityNum < MAX_CLIENTS || g_entities[tr.entityNum].s.eType == ET_NPC))
            {   //player or NPC, try making a mark on him
                //copy current pos to s.origin, and current projected traj to origin2
                VectorCopy(ent->r.currentOrigin, ent->s.origin);
                BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->s.origin2 );

                if (VectorCompare(ent->s.origin, ent->s.origin2))
                {
                    ent->s.origin2[2] += 2.0f; //whatever, at least it won't mess up.
                }
            }

            G_MissileImpact( ent, &tr );

            if (tr.entityNum == ent->s.otherEntityNum)
            {   //if the impact event other and the trace ent match then it's ok to do the g2 mark
                ent->s.trickedentindex = 1;
            }

            if ( ent->s.eType != ET_MISSILE && ent->s.weapon != G2_MODEL_PART )
            {
                return;		// exploded
            }
        }
    }

passthrough:
    if ( ent->s.pos.trType == TR_STATIONARY && (ent->s.eFlags&EF_MISSILE_STICK) )
    {   //stuck missiles should check some special stuff
        G_RunStuckMissile( ent );
        return;
    }

    if (ent->s.weapon == G2_MODEL_PART)
    {
        if (ent->s.groundEntityNum == ENTITYNUM_WORLD)
        {
            ent->s.pos.trType = TR_LINEAR;
            VectorClear(ent->s.pos.trDelta);
            ent->s.pos.trTime = level.time;

            VectorCopy(groundSpot, ent->s.pos.trBase);
            VectorCopy(groundSpot, ent->r.currentOrigin);

            if (ent->s.apos.trType != TR_STATIONARY)
            {
                ent->s.apos.trType = TR_STATIONARY;
                ent->s.apos.trTime = level.time;

                ent->s.apos.trBase[ROLL] = 0;
                ent->s.apos.trBase[PITCH] = 0;
            }
        }
    }
    // check think function after bouncing
    G_RunThink( ent );
}
Пример #19
0
//TODO:  When transition to 0 grav, push away from surface you were resting on
//TODO:  When free-floating in air, apply some friction to your trDelta (based on mass?)
void G_RunObject( gentity_t *ent ) {
	vector3		origin, oldOrg;
	trace_t		tr;
	gentity_t	*traceEnt = NULL;

	//FIXME: floaters need to stop floating up after a while, even if gravity stays negative?
	if ( ent->s.pos.trType == TR_STATIONARY )//g_gravity.value <= 0 &&
	{
		ent->s.pos.trType = TR_GRAVITY;
		VectorCopy( &ent->r.currentOrigin, &ent->s.pos.trBase );
		ent->s.pos.trTime = level.previousTime;//?necc?
		if ( !g_gravity.value ) {
			ent->s.pos.trDelta.z += 100;
		}
	}

	ent->nextthink = level.time + FRAMETIME;

	VectorCopy( &ent->r.currentOrigin, &oldOrg );
	// get current position
	BG_EvaluateTrajectory( &ent->s.pos, level.time, &origin );
	//Get current angles?
	BG_EvaluateTrajectory( &ent->s.apos, level.time, &ent->r.currentAngles );

	if ( VectorCompare( &ent->r.currentOrigin, &origin ) ) {//error - didn't move at all!
		return;
	}
	// trace a line from the previous position to the current position,
	// ignoring interactions with the missile owner
	trap->Trace( &tr, &ent->r.currentOrigin, &ent->r.mins, &ent->r.maxs, &origin, ent->parent ? ent->parent->s.number : ent->s.number, ent->clipmask, qfalse, 0, 0 );

	if ( !tr.startsolid && !tr.allsolid && tr.fraction ) {
		VectorCopy( &tr.endpos, &ent->r.currentOrigin );
		trap->LinkEntity( (sharedEntity_t *)ent );
	}
	else
		//if ( tr.startsolid )
	{
		tr.fraction = 0;
	}

	G_MoverTouchPushTriggers( ent, &oldOrg );
	/*
	if ( !(ent->s.eFlags & EF_TELEPORT_BIT) && !(ent->svFlags & SVF_NO_TELEPORT) )
	{
	G_MoverTouchTeleportTriggers( ent, oldOrg );
	if ( ent->s.eFlags & EF_TELEPORT_BIT )
	{//was teleported
	return;
	}
	}
	else
	{
	ent->s.eFlags &= ~EF_TELEPORT_BIT;
	}
	*/

	if ( tr.fraction == 1 ) {
		if ( g_gravity.value <= 0 ) {
			if ( ent->s.apos.trType == TR_STATIONARY ) {
				VectorCopy( &ent->r.currentAngles, &ent->s.apos.trBase );
				ent->s.apos.trType = TR_LINEAR;
				ent->s.apos.trDelta.y = flrand( -300, 300 );
				ent->s.apos.trDelta.x = flrand( -10, 10 );
				ent->s.apos.trDelta.z = flrand( -10, 10 );
				ent->s.apos.trTime = level.time;
			}
		}
		//friction in zero-G
		if ( !g_gravity.value ) {
			float friction = 0.975f;
			//friction -= ent->mass/1000.0f;
			if ( friction < 0.1f ) {
				friction = 0.1f;
			}

			VectorScale( &ent->s.pos.trDelta, friction, &ent->s.pos.trDelta );
			VectorCopy( &ent->r.currentOrigin, &ent->s.pos.trBase );
			ent->s.pos.trTime = level.time;
		}
		return;
	}

	//hit something

	//Do impact damage
	traceEnt = &g_entities[tr.entityNum];
	if ( tr.fraction || (traceEnt && traceEnt->takedamage) ) {
		if ( !VectorCompare( &ent->r.currentOrigin, &oldOrg ) ) {//moved and impacted
			if ( (traceEnt && traceEnt->takedamage) ) {//hurt someone
				//				G_Sound( ent, G_SoundIndex( "sound/movers/objects/objectHurt.wav" ) );
			}
			//			G_Sound( ent, G_SoundIndex( "sound/movers/objects/objectHit.wav" ) );
		}

		if ( ent->s.weapon != WP_SABER ) {
			DoImpact( ent, traceEnt, qtrue );
		}
	}

	if ( !ent || (ent->takedamage&&ent->health <= 0) ) {//been destroyed by impact
		//chunks?
		//		G_Sound( ent, G_SoundIndex( "sound/movers/objects/objectBreak.wav" ) );
		return;
	}

	//do impact physics
	if ( ent->s.pos.trType == TR_GRAVITY )//tr.fraction < 1.0f &&
	{//FIXME: only do this if no trDelta
		if ( g_gravity.value <= 0 || tr.plane.normal.z < 0.7f ) {
			if ( ent->flags&(FL_BOUNCE | FL_BOUNCE_HALF) ) {
				if ( tr.fraction <= 0.0f ) {
					VectorCopy( &tr.endpos, &ent->r.currentOrigin );
					VectorCopy( &tr.endpos, &ent->s.pos.trBase );
					VectorClear( &ent->s.pos.trDelta );
					ent->s.pos.trTime = level.time;
				}
				else {
					G_BounceObject( ent, &tr );
				}
			}
			else {//slide down?
				//FIXME: slide off the slope
			}
		}
		else {
			ent->s.apos.trType = TR_STATIONARY;
			pitch_roll_for_slope( ent, &tr.plane.normal );
			//ent->r.currentAngles[0] = 0;//FIXME: match to slope
			//ent->r.currentAngles[2] = 0;//FIXME: match to slope
			VectorCopy( &ent->r.currentAngles, &ent->s.apos.trBase );
			//okay, we hit the floor, might as well stop or prediction will
			//make us go through the floor!
			//FIXME: this means we can't fall if something is pulled out from under us...
			G_StopObjectMoving( ent );
		}
	}
	else if ( ent->s.weapon != WP_SABER ) {
		ent->s.apos.trType = TR_STATIONARY;
		pitch_roll_for_slope( ent, &tr.plane.normal );
		//ent->r.currentAngles[0] = 0;//FIXME: match to slope
		//ent->r.currentAngles[2] = 0;//FIXME: match to slope
		VectorCopy( &ent->r.currentAngles, &ent->s.apos.trBase );
	}

	//call touch func
	ent->touch( ent, &g_entities[tr.entityNum], &tr );
}
Пример #20
0
void CCam::mortarCam(camInfo_t *ci)
{
	if (eth32.cg.snap->ps.ammo == 0)
		return;

// Set mortar trajectory from current view
	vec3_t angles, forward;
	VectorCopy(eth32.cg.refdef->viewaxis[ROLL], forward);
	VectorCopy(eth32.cg.snap->ps.viewangles, angles);
	angles[PITCH] -= 60.f;
	AngleVectors(angles, forward, NULL, NULL);
	forward[0] *= 3000 * 1.1f;
	forward[1] *= 3000 * 1.1f;
	forward[2] *= 1500 * 1.1f;

	trajectory_t mortarTrajectory;
	mortarTrajectory.trType = TR_GRAVITY;
	mortarTrajectory.trTime = eth32.cg.time;
	VectorCopy(eth32.cg.muzzle, mortarTrajectory.trBase);
	VectorCopy(forward, mortarTrajectory.trDelta);

	// Calculate mortar impact
	int timeOffset = 0;
	trace_t mortarTrace;
	vec3_t mortarImpact;
	VectorCopy(mortarTrajectory.trBase, mortarImpact);
	#define TIME_STEP 20
	while (timeOffset < 10000) {
		vec3_t nextPos;
		timeOffset += TIME_STEP;
		BG_EvaluateTrajectory(&mortarTrajectory, eth32.cg.time + timeOffset, nextPos, qfalse, 0);
		orig_CG_Trace(&mortarTrace, mortarImpact, 0, 0, nextPos, eth32.cg.snap->ps.clientNum, MASK_MISSILESHOT);
		if ((mortarTrace.fraction != 1)
				// Stop if we hit sky
				&& !((mortarTrace.surfaceFlags & SURF_NODRAW) || (mortarTrace.surfaceFlags & SURF_NOIMPACT))
				&& (mortarTrace.contents != 0)) {
			break;
		}
		VectorCopy(nextPos, mortarImpact);
	}

	memcpy(&camRefDef, &eth32.cg.refdef, sizeof(refdef_t));

	// kobject: add some angles
	vec3_t	dpos;
	vec3_t	camOrg;

	dpos[0] = eth32.cg.refdef->vieworg[0]-mortarImpact[0];
	dpos[1] = eth32.cg.refdef->vieworg[1]-mortarImpact[1];
	dpos[2] = 0.0f;
	VectorNormalizeFast( dpos );
	VectorCopy( mortarImpact, camOrg );
	VectorMA( camOrg, ci->distance * sinf(ci->angle * M_PI/180.0), zAxis, camOrg );
	VectorMA( camOrg, ci->distance * cosf(ci->angle * M_PI/180.0), dpos, camOrg );

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

	camRefDef.fov_x = (w>h) ? ci->fov : ci->fov * w / h;
	camRefDef.fov_y = (h>w) ? ci->fov : ci->fov * h / w;

	VectorCopy(camOrg, camRefDef.vieworg);

	vec3_t camAngle;
	VectorCopy(eth32.cg.refdefViewAngles, camAngle);
	camAngle[PITCH] = ci->angle;

	AnglesToAxis(camAngle, camRefDef.viewaxis);

	drawCam(ci->x1, ci->y1, w, h, &camRefDef, qtrue);

	// Draw impact time
	sprintf(this->str, "^7Impact Time: ^b%.1f ^7seconds", (float)timeOffset / 1000.0f);
	Draw.Text(ci->x1 + (w / 2) - (TEXTWIDTH(this->str) / 2), ci->y1 + h - 22 , 0.24f, str, GUI_FONTCOLOR1, qfalse, qtrue, &eth32.cg.media.fontArial, true);

}
Пример #21
0
/*
================
CG_AddFragment
================
*/
void CG_AddFragment( localEntity_t *le ) {
	vec3_t	newOrigin;
	trace_t	trace;

	if ( le->pos.trType == TR_STATIONARY ) {
		// sink into the ground if near the removal time
		int		t;
		float	oldZ;
		
		t = le->endTime - cg.time;
		if ( t < SINK_TIME ) {
			// we must use an explicit lighting origin, otherwise the
			// lighting would be lost as soon as the origin went
			// into the ground
			VectorCopy( le->refEntity.origin, le->refEntity.lightingOrigin );
			le->refEntity.renderfx |= RF_LIGHTING_ORIGIN;
			oldZ = le->refEntity.origin[2];
			le->refEntity.origin[2] -= 16 * ( 1.0 - (float)t / SINK_TIME );
			CG_AddRefEntityWithMinLight( &le->refEntity );
			le->refEntity.origin[2] = oldZ;
		} else {
			CG_AddRefEntityWithMinLight( &le->refEntity );
		}

		return;
	}

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

	// trace a line from previous position to new position
	CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID );
	if ( trace.fraction == 1.0 ) {
		// still in free fall
		VectorCopy( newOrigin, le->refEntity.origin );

		if ( le->leFlags & LEF_TUMBLE ) {
			vec3_t angles;

			BG_EvaluateTrajectory( &le->angles, cg.time, angles );
			AnglesToAxis( angles, le->refEntity.axis );
		}

		CG_AddRefEntityWithMinLight( &le->refEntity );

		// add a blood trail
		if ( le->leBounceSoundType == LEBS_BLOOD ) {
			CG_BloodTrail( le );
		}

		return;
	}

	// if it is in a nodrop zone, remove it
	// this keeps gibs from waiting at the bottom of pits of death
	// and floating levels
	if ( CG_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) {
		CG_FreeLocalEntity( le );
		return;
	}

	// leave a mark
	CG_FragmentBounceMark( le, &trace );

	// do a bouncy sound
	CG_FragmentBounceSound( le, &trace );

	// reflect the velocity on the trace plane
	CG_ReflectVelocity( le, &trace );

	CG_AddRefEntityWithMinLight( &le->refEntity );
}
Пример #22
0
/*
================
G_RunItem

================
*/
void G_RunItem( gentity_t *ent ) {
	vec3_t origin;
	trace_t tr;
	int contents;
	int mask;

	// if its groundentity has been set to none, it may have been pushed off an edge
	if ( ent->s.groundEntityNum == ENTITYNUM_NONE ) {
		if ( ent->s.pos.trType != TR_GRAVITY ) {
			ent->s.pos.trType = TR_GRAVITY;
			ent->s.pos.trTime = level.time;
		}
	}

	if ( ent->s.pos.trType == TR_STATIONARY || ent->s.pos.trType == TR_GRAVITY_PAUSED ) { //----(SA)
		// check think function
		G_RunThink( ent );
		return;
	}

	// get current position
	BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );

	// trace a line from the previous position to the current position
	if ( ent->clipmask ) {
		mask = ent->clipmask;
	} else {
		mask = MASK_SOLID;
	}
	trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin,
				ent->r.ownerNum, mask );

	if ( ent->isProp && ent->takedamage ) {
		G_RunItemProp( ent, origin );
	}

	VectorCopy( tr.endpos, ent->r.currentOrigin );

	if ( tr.startsolid ) {
		tr.fraction = 0;
	}

	trap_LinkEntity( ent ); // FIXME: avoid this for stationary?

	// check think function
	G_RunThink( ent );

	if ( tr.fraction == 1 ) {
		return;
	}

	// if it is in a nodrop volume, remove it
	contents = trap_PointContents( ent->r.currentOrigin, -1 );
	if ( contents & CONTENTS_NODROP ) {
		if ( ent->item && ent->item->giType == IT_TEAM ) {
			Team_FreeEntity( ent );
		} else {
			G_FreeEntity( ent );
		}
		return;
	}

	G_BounceItem( ent, &tr );
}
Пример #23
0
void G_MissileImpact( gentity_t *ent, trace_t *trace ) {
#else
void G_MissileImpact( gentity_t *ent, trace_t *trace, int shaderNum ) {
#endif
	gentity_t		*other;
	qboolean		hitClient = qfalse;
#ifndef SMOKINGUNS
#ifdef MISSIONPACK
	vec3_t			forward, impactpoint, bouncedir;
	int				eFlags;
#endif
#else
	qboolean		hitKnife  = qfalse;
	vec3_t			bottledirs[ALC_COUNT];
#endif
	other = &g_entities[trace->entityNum];

#ifndef SMOKINGUNS
	// check for bounce
	if ( !other->takedamage &&
		( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) ) ) {
		G_BounceMissile( ent, trace );
		G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
		return;
	}

#ifdef MISSIONPACK
	if ( other->takedamage ) {
		if ( ent->s.weapon != WP_PROX_LAUNCHER ) {
			if ( other->client && other->client->invulnerabilityTime > level.time ) {
				//
				VectorCopy( ent->s.pos.trDelta, forward );
				VectorNormalize( forward );
				if (G_InvulnerabilityEffect( other, forward, ent->s.pos.trBase, impactpoint, bouncedir )) {
					VectorCopy( bouncedir, trace->plane.normal );
					eFlags = ent->s.eFlags & EF_BOUNCE_HALF;
					ent->s.eFlags &= ~EF_BOUNCE_HALF;
					G_BounceMissile( ent, trace );
					ent->s.eFlags |= eFlags;
				}
				ent->target_ent = other;
				return;
			}
		}
	}
#endif
	// impact damage
	if (other->takedamage) {
#else
	if(other->takedamage)
		hitKnife = qtrue;

	// check for bounce
	if ( ( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) ) ) {
		G_BounceMissile( ent, trace );
		return;
	}

	if (other->takedamage && ent->s.weapon != WP_DYNAMITE) {
#endif
		// FIXME: wrong damage direction?
		if ( ent->damage ) {
			vec3_t	velocity;

			if( LogAccuracyHit( other, &g_entities[ent->r.ownerNum] ) ) {
				g_entities[ent->r.ownerNum].client->accuracy_hits++;
				hitClient = qtrue;
			}
			BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
			if ( VectorLength( velocity ) == 0 ) {
				velocity[2] = 1;	// stepped on a grenade
			}
#ifndef SMOKINGUNS
			G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity,
				ent->s.origin, ent->damage,
				0, ent->methodOfDeath);
#else

			// you can't make dynamite exploding by using a knife
			if(!(ent->s.weapon == WP_KNIFE && other->s.weapon == WP_DYNAMITE &&
				other->s.eType == ET_ITEM)){

				// prepare breakable, if not already initialized
				if(!(other->flags & FL_BREAKABLE_INIT))
					G_BreakablePrepare(other, shaderNum);

				G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity,
					ent->s.origin, ent->damage,
					0, ent->methodOfDeath);
			}
#endif
		}
	}

#ifndef SMOKINGUNS
	if( ent->s.weapon == WP_PROX_LAUNCHER ) {
		if( ent->s.pos.trType != TR_GRAVITY ) {
			return;
		}

		// if it's a player, stick it on to them (flag them and remove this entity)
		if( other->s.eType == ET_PLAYER && other->health > 0 ) {
			ProximityMine_Player( ent, other );
			return;
		}

		SnapVectorTowards( trace->endpos, ent->s.pos.trBase );
		G_SetOrigin( ent, trace->endpos );
		ent->s.pos.trType = TR_STATIONARY;
		VectorClear( ent->s.pos.trDelta );

		G_AddEvent( ent, EV_PROXIMITY_MINE_STICK, trace->surfaceFlags );

		ent->think = ProximityMine_Activate;
		ent->nextthink = level.time + 2000;

		vectoangles( trace->plane.normal, ent->s.angles );
		ent->s.angles[0] += 90;

		// link the prox mine to the other entity
		ent->enemy = other;
		ent->die = ProximityMine_Die;
		VectorCopy(trace->plane.normal, ent->movedir);
		VectorSet(ent->r.mins, -4, -4, -4);
		VectorSet(ent->r.maxs, 4, 4, 4);
		trap_LinkEntity(ent);

		return;
	}

	if (!strcmp(ent->classname, "hook")) {
		gentity_t *nent;
		vec3_t v;

		nent = G_Spawn();
		if ( other->takedamage && other->client ) {

			G_AddEvent( nent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
			nent->s.otherEntityNum = other->s.number;

			ent->enemy = other;

			v[0] = other->r.currentOrigin[0] + (other->r.mins[0] + other->r.maxs[0]) * 0.5;
			v[1] = other->r.currentOrigin[1] + (other->r.mins[1] + other->r.maxs[1]) * 0.5;
			v[2] = other->r.currentOrigin[2] + (other->r.mins[2] + other->r.maxs[2]) * 0.5;

			SnapVectorTowards( v, ent->s.pos.trBase );	// save net bandwidth
		} else {
			VectorCopy(trace->endpos, v);
			G_AddEvent( nent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
			ent->enemy = NULL;
		}

		SnapVectorTowards( v, ent->s.pos.trBase );	// save net bandwidth

		nent->freeAfterEvent = qtrue;
		// change over to a normal entity right at the point of impact
		nent->s.eType = ET_GENERAL;
		ent->s.eType = ET_GRAPPLE;

		G_SetOrigin( ent, v );
		G_SetOrigin( nent, v );

		ent->think = Weapon_HookThink;
		ent->nextthink = level.time + FRAMETIME;

		ent->parent->client->ps.pm_flags |= PMF_GRAPPLE_PULL;
		VectorCopy( ent->r.currentOrigin, ent->parent->client->ps.grapplePoint);

		trap_LinkEntity( ent );
		trap_LinkEntity( nent );

		return;
	}
#endif

	// is it cheaper in bandwidth to just remove this ent and create a new
	// one, rather than changing the missile into the explosion?

#ifndef SMOKINGUNS
	if ( other->takedamage && other->client ) {
#else
	// alcoohol impact
	if( !Q_stricmp(ent->classname, "alcohol")){
		// no event
		//G_AddEvent( ent, EV_MISSILE_ALCOHOL, DirToByte( trace->plane.normal));
	} else if( !Q_stricmp(ent->classname, "molotov")){
		// we have to launch the whiskey drops
		int i;

		// set the directions
		for(i = 0; i < ALC_COUNT; i++){
			int temp;

			VectorSet(bottledirs[i], (rand()%10)-5, (rand()%10)-5, (rand()%10)-3);

			// direction has to be exactly the same (client and server)
			temp = DirToByte(bottledirs[i]);
			ByteToDir(temp, bottledirs[i]);
		}

		// dirs
		BG_DirsToEntityState(&ent->s, bottledirs);

		// burning
		if(ent->s.apos.trDelta[0])
			G_AddEvent( ent, EV_MISSILE_FIRE, DirToByte( trace->plane.normal));
		// not burning
		else
			G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal));
	} else if ( other->takedamage && other->client ) {
#endif
		G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
		ent->s.otherEntityNum = other->s.number;
#ifndef SMOKINGUNS
	} else if( trace->surfaceFlags & SURF_METALSTEPS ) {
#else
	} else if( trace->surfaceFlags & SURF_METAL ) {
#endif
		G_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( trace->plane.normal ) );
	} else {
		G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
	}

#ifndef SMOKINGUNS
	ent->freeAfterEvent = qtrue;

	// change over to a normal entity right at the point of impact
	ent->s.eType = ET_GENERAL;
#else
	if(Q_stricmp(ent->classname, "knife")){
		ent->freeAfterEvent = qtrue;
		// change over to a normal entity right at the point of impact
		ent->s.eType = ET_GENERAL;
	} else {
		vec3_t dir;
		gitem_t			*item;

		item = BG_FindItemForWeapon(WP_KNIFE);

		ent->s.modelindex = item-bg_itemlist;
		ent->s.modelindex2 = 1;

		ent->item = item;

		ent->s.eType = ET_ITEM;
		ent->s.pos.trType = TR_GRAVITY;
		ent->physicsBounce = 0.01f;
		ent->r.contents = CONTENTS_TRIGGER;

		ent->touch = Touch_Item;
		ent->nextthink = level.time + 100;
		ent->think = G_KnifeThink;
		ent->wait = level.time + 30000;
		ent->flags |= FL_THROWN_ITEM;

		vectoangles(ent->s.pos.trDelta, dir);

		VectorCopy(dir, ent->s.apos.trBase);
		VectorCopy(dir, ent->r.currentAngles);
	}
	//modified by Spoon END
#endif

	SnapVectorTowards( trace->endpos, ent->s.pos.trBase );	// save net bandwidth

	G_SetOrigin( ent, trace->endpos );

	// splash damage (doesn't apply to person directly hit)
	if ( ent->splashDamage ) {
		if( G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius,
			other, ent->splashMethodOfDeath ) ) {
			if( !hitClient ) {
				g_entities[ent->r.ownerNum].client->accuracy_hits++;
			}
		}
	}

	// spawn alcohol missiles
#ifdef SMOKINGUNS
	if(!Q_stricmp(ent->classname, "molotov")){
		BottleBreak( ent, trace->endpos, trace->plane.normal, bottledirs);
	}
#endif

	trap_LinkEntity( ent );
}

/*
================
G_RunMissile
================
*/
void G_RunMissile( gentity_t *ent ) {
	vec3_t		origin;
	trace_t		tr;
	int			passent;
#ifdef SMOKINGUNS
	int			shaderNum;
	gentity_t	*traceEnt;
#endif

	// get current position
	BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );

	// if this missile bounced off an invulnerability sphere
	if ( ent->target_ent ) {
		passent = ent->target_ent->s.number;
	}
#ifndef SMOKINGUNS
	// prox mines that left the owner bbox will attach to anything, even the owner
	else if (ent->s.weapon == WP_PROX_LAUNCHER && ent->count) {
		passent = ENTITYNUM_NONE;
	}
#endif
	else {
		// ignore interactions with the missile owner
		passent = ent->r.ownerNum;
	}
	// trace a line from the previous position to the current position
#ifndef SMOKINGUNS
	trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask );
#else
	shaderNum = trap_Trace_New2( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask );
	traceEnt = &g_entities[tr.entityNum];
#endif

	if ( tr.startsolid || tr.allsolid ) {
		// make sure the tr.entityNum is set to the entity we're stuck in
#ifndef SMOKINGUNS
		trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask );
#else
		trap_Trace_New( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask );
#endif
		tr.fraction = 0;
	}
	else {
		VectorCopy( tr.endpos, ent->r.currentOrigin );
	}

	trap_LinkEntity( ent );

	if ( tr.fraction != 1 ) {

#ifdef SMOKINGUNS
		VectorCopy(origin, ent->s.origin2);
#endif

		// never explode or bounce on sky
		if ( tr.surfaceFlags & SURF_NOIMPACT ) {
			// If grapple, reset owner
			if (ent->parent && ent->parent->client && ent->parent->client->hook == ent) {
				ent->parent->client->hook = NULL;
			}

			// if its a dynamite or molotov let it move 10 seconds before deleting it
#ifdef SMOKINGUNS
			if(ent->s.weapon == WP_DYNAMITE || ent->s.weapon == WP_MOLOTOV
				|| ent->s.weapon == WP_KNIFE){

				if(ent->mappart >= level.time && ent->mappart){
					goto think;
				} else if(ent->mappart){
					ent->mappart = 0;
				} else {
					ent->mappart = level.time + 5000;
					goto think;
				}
			}
#endif
			G_FreeEntity( ent );
			return;
		}
#ifndef SMOKINGUNS
		G_MissileImpact( ent, &tr );
		if ( ent->s.eType != ET_MISSILE ) {
#else
		G_MissileImpact( ent, &tr, shaderNum );
		if ( ent->s.eType != ET_MISSILE && ent->s.eType != ET_ITEM) {
#endif
			return;		// exploded
		}
	}
#ifndef SMOKINGUNS
	// if the prox mine wasn't yet outside the player body
	if (ent->s.weapon == WP_PROX_LAUNCHER && !ent->count) {
		// check if the prox mine is outside the owner bbox
		trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, ENTITYNUM_NONE, ent->clipmask );
		if (!tr.startsolid || tr.entityNum != ent->r.ownerNum) {
			ent->count = 1;
		}
	}
#endif

think:
	// check think function after bouncing
	G_RunThink( ent );
}


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

#ifndef SMOKINGUNS
/*
=================
fire_plasma

=================
*/
gentity_t *fire_plasma (gentity_t *self, vec3_t start, vec3_t dir) {
	gentity_t	*bolt;

	VectorNormalize (dir);

	bolt = G_Spawn();
	bolt->classname = "plasma";
	bolt->nextthink = level.time + 10000;
	bolt->think = G_ExplodeMissile;
	bolt->s.eType = ET_MISSILE;
	bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
	bolt->s.weapon = WP_PLASMAGUN;
	bolt->r.ownerNum = self->s.number;
	bolt->parent = self;
	bolt->damage = 20;
	bolt->splashDamage = 15;
	bolt->splashRadius = 20;
	bolt->methodOfDeath = MOD_PLASMA;
	bolt->splashMethodOfDeath = MOD_PLASMA_SPLASH;
	bolt->clipmask = MASK_SHOT;
	bolt->target_ent = NULL;

	bolt->s.pos.trType = TR_LINEAR;
	bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;		// move a bit on the very first frame
	VectorCopy( start, bolt->s.pos.trBase );
	VectorScale( dir, 2000, bolt->s.pos.trDelta );
	SnapVector( bolt->s.pos.trDelta );			// save net bandwidth

	VectorCopy (start, bolt->r.currentOrigin);

	return bolt;
}

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


/*
=================
fire_grenade
=================
*/
gentity_t *fire_grenade (gentity_t *self, vec3_t start, vec3_t dir) {
	gentity_t	*bolt;

	VectorNormalize (dir);

	bolt = G_Spawn();
	bolt->classname = "grenade";
	bolt->nextthink = level.time + 2500;
	bolt->think = G_ExplodeMissile;
	bolt->s.eType = ET_MISSILE;
	bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
	bolt->s.weapon = WP_GRENADE_LAUNCHER;
	bolt->s.eFlags = EF_BOUNCE_HALF;
	bolt->r.ownerNum = self->s.number;
	bolt->parent = self;
	bolt->damage = 100;
	bolt->splashDamage = 100;
	bolt->splashRadius = 150;
	bolt->methodOfDeath = MOD_GRENADE;
	bolt->splashMethodOfDeath = MOD_GRENADE_SPLASH;
	bolt->clipmask = MASK_SHOT;
	bolt->target_ent = NULL;

	bolt->s.pos.trType = TR_GRAVITY;
	bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;		// move a bit on the very first frame
	VectorCopy( start, bolt->s.pos.trBase );
	VectorScale( dir, 700, bolt->s.pos.trDelta );
	SnapVector( bolt->s.pos.trDelta );			// save net bandwidth

	VectorCopy (start, bolt->r.currentOrigin);

	return bolt;
}
Пример #24
0
static qboolean NPC_Jump( vec3_t dest, int goalEntNum )
{//FIXME: if land on enemy, knock him down & jump off again
	float	targetDist, travelTime, impactDist, bestImpactDist = Q3_INFINITE;//fireSpeed, 
	float originalShotSpeed, shotSpeed, speedStep = 50.0f, minShotSpeed = 30.0f, maxShotSpeed = 500.0f;
	qboolean belowBlocked = qfalse, aboveBlocked = qfalse;
	vec3_t	targetDir, shotVel, failCase; 
	trace_t	trace;
	trajectory_t	tr;
	qboolean	blocked;
	int		elapsedTime, timeStep = 250, hitCount = 0, aboveTries = 0, belowTries = 0, maxHits = 10;
	vec3_t	lastPos, testPos, bottom;

	VectorSubtract( dest, NPC->r.currentOrigin, targetDir );
	targetDist = VectorNormalize( targetDir );
	//make our shotSpeed reliant on the distance
	originalShotSpeed = targetDist;//DistanceHorizontal( dest, NPC->currentOrigin )/2.0f;
	if ( originalShotSpeed > maxShotSpeed )
	{
		originalShotSpeed = maxShotSpeed;
	}
	else if ( originalShotSpeed < minShotSpeed )
	{
		originalShotSpeed = minShotSpeed;
	}
	shotSpeed = originalShotSpeed;

	while ( hitCount < maxHits )
	{
		VectorScale( targetDir, shotSpeed, shotVel );
		travelTime = targetDist/shotSpeed;
		shotVel[2] += travelTime * 0.5 * NPC->client->ps.gravity;

		if ( !hitCount )		
		{//save the first one as the worst case scenario
			VectorCopy( shotVel, failCase );
		}

		if ( 1 )//tracePath )
		{//do a rough trace of the path
			blocked = qfalse;

			VectorCopy( NPC->r.currentOrigin, tr.trBase );
			VectorCopy( shotVel, tr.trDelta );
			tr.trType = TR_GRAVITY;
			tr.trTime = level.time;
			travelTime *= 1000.0f;
			VectorCopy( NPC->r.currentOrigin, lastPos );
			
			//This may be kind of wasteful, especially on long throws... use larger steps?  Divide the travelTime into a certain hard number of slices?  Trace just to apex and down?
			for ( elapsedTime = timeStep; elapsedTime < floor(travelTime)+timeStep; elapsedTime += timeStep )
			{
				if ( (float)elapsedTime > travelTime )
				{//cap it
					elapsedTime = floor( travelTime );
				}
				BG_EvaluateTrajectory( &tr, level.time + elapsedTime, testPos );
				//F**K IT, always check for do not enter...
				trap_Trace( &trace, lastPos, NPC->r.mins, NPC->r.maxs, testPos, NPC->s.number, NPC->clipmask|CONTENTS_BOTCLIP );
				/*
				if ( testPos[2] < lastPos[2] 
					&& elapsedTime < floor( travelTime ) )
				{//going down, haven't reached end, ignore botclip
					gi.trace( &trace, lastPos, NPC->mins, NPC->maxs, testPos, NPC->s.number, NPC->clipmask );
				}
				else
				{//going up, check for botclip
					gi.trace( &trace, lastPos, NPC->mins, NPC->maxs, testPos, NPC->s.number, NPC->clipmask|CONTENTS_BOTCLIP );
				}
				*/

				if ( trace.allsolid || trace.startsolid )
				{//started in solid
					if ( NAVDEBUG_showCollision )
					{
						G_DrawEdge( lastPos, trace.endpos, EDGE_RED_TWOSECOND );
					}
					return qfalse;//you're hosed, dude
				}
				if ( trace.fraction < 1.0f )
				{//hit something
					if ( NAVDEBUG_showCollision )
					{
						G_DrawEdge( lastPos, trace.endpos, EDGE_RED_TWOSECOND );	// TryJump
					}
					if ( trace.entityNum == goalEntNum )
					{//hit the enemy, that's bad!
						blocked = qtrue;
						/*
						if ( g_entities[goalEntNum].client && g_entities[goalEntNum].client->ps.groundEntityNum == ENTITYNUM_NONE )
						{//bah, would collide in mid-air, no good
							blocked = qtrue;
						}
						else
						{//he's on the ground, good enough, I guess
							//Hmm, don't want to land on him, though...?
						}
						*/
						break;
					}
					else 
					{
						if ( trace.contents & CONTENTS_BOTCLIP )
						{//hit a do-not-enter brush
							blocked = qtrue;
							break;
						}
						if ( trace.plane.normal[2] > 0.7 && DistanceSquared( trace.endpos, dest ) < 4096 )//hit within 64 of desired location, should be okay
						{//close enough!
							break;
						}
						else
						{//FIXME: maybe find the extents of this brush and go above or below it on next try somehow?
							impactDist = DistanceSquared( trace.endpos, dest );
							if ( impactDist < bestImpactDist )
							{
								bestImpactDist = impactDist;
								VectorCopy( shotVel, failCase );
							}
							blocked = qtrue;
							break;
						}
					}
				}
				else
				{
					if ( NAVDEBUG_showCollision )
					{
						G_DrawEdge( lastPos, testPos, EDGE_WHITE_TWOSECOND );	// TryJump
					}
				}
				if ( elapsedTime == floor( travelTime ) )
				{//reached end, all clear
					if ( trace.fraction >= 1.0f )
					{//hmm, make sure we'll land on the ground...
						//FIXME: do we care how far below ourselves or our dest we'll land?
						VectorCopy( trace.endpos, bottom );
						bottom[2] -= 128;
						trap_Trace( &trace, trace.endpos, NPC->r.mins, NPC->r.maxs, bottom, NPC->s.number, NPC->clipmask );
						if ( trace.fraction >= 1.0f )
						{//would fall too far
							blocked = qtrue;
						}
					}
					break;
				}
				else
				{
					//all clear, try next slice
					VectorCopy( testPos, lastPos );
				}
			}
			if ( blocked )
			{//hit something, adjust speed (which will change arc)
				hitCount++;
				//alternate back and forth between trying an arc slightly above or below the ideal
				if ( (hitCount%2) && !belowBlocked )
				{//odd
					belowTries++;
					shotSpeed = originalShotSpeed - (belowTries*speedStep);
				}
				else if ( !aboveBlocked )
				{//even
					aboveTries++;
					shotSpeed = originalShotSpeed + (aboveTries*speedStep);
				}
				else
				{//can't go any higher or lower
					hitCount = maxHits;
					break;
				}
				if ( shotSpeed > maxShotSpeed )
				{
					shotSpeed = maxShotSpeed;
					aboveBlocked = qtrue;
				}
				else if ( shotSpeed < minShotSpeed )
				{
					shotSpeed = minShotSpeed;
					belowBlocked = qtrue;
				}
			}
			else
			{//made it!
				break;
			}
		}
		else
		{//no need to check the path, go with first calc
			break;
		}
	}

	if ( hitCount >= maxHits )
	{//NOTE: worst case scenario, use the one that impacted closest to the target (or just use the first try...?)
		return qfalse;
		//NOTE: or try failcase?
		//VectorCopy( failCase, NPC->client->ps.velocity );
		//return qtrue;
	}
	VectorCopy( shotVel, NPC->client->ps.velocity );
	return qtrue;
}
Пример #25
0
/*
================
G_RunMissile
================
*/
void G_RunMissile( gentity_t *ent ) {
    vec3_t		origin, groundSpot;
    trace_t		tr;
    int			passent;
    qboolean	isKnockedSaber = qfalse;

    if (ent->neverFree && ent->s.weapon == WP_SABER && (ent->flags & FL_BOUNCE_HALF))
    {
        isKnockedSaber = qtrue;
        ent->s.pos.trType = TR_GRAVITY;
    }

    // get current position
    BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );

    // if this missile bounced off an invulnerability sphere
    if ( ent->target_ent ) {
        passent = ent->target_ent->s.number;
    }
    else {
        // ignore interactions with the missile owner
        if ( (ent->r.svFlags&SVF_OWNERNOTSHARED)
                && (ent->s.eFlags&EF_JETPACK_ACTIVE) )
        {   //A vehicle missile that should be solid to its owner
            //I don't care about hitting my owner
            passent = ent->s.number;
        }
        else
        {
            passent = ent->r.ownerNum;
        }
    }
    // trace a line from the previous position to the current position
    if (d_projectileGhoul2Collision.integer)
    {
        trap->Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask, qfalse, G2TRFLAG_DOGHOULTRACE|G2TRFLAG_GETSURFINDEX|G2TRFLAG_THICK|G2TRFLAG_HITCORPSES, g_g2TraceLod.integer );

        if (tr.fraction != 1.0 && tr.entityNum < ENTITYNUM_WORLD)
        {
            gentity_t *g2Hit = &g_entities[tr.entityNum];

            if (g2Hit->inuse && g2Hit->client && g2Hit->ghoul2)
            {   //since we used G2TRFLAG_GETSURFINDEX, tr.surfaceFlags will actually contain the index of the surface on the ghoul2 model we collided with.
                g2Hit->client->g2LastSurfaceHit = tr.surfaceFlags;
                g2Hit->client->g2LastSurfaceTime = level.time;
            }

            if (g2Hit->ghoul2)
            {
                tr.surfaceFlags = 0; //clear the surface flags after, since we actually care about them in here.
            }
        }
    }
    else
    {
        trap->Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask, qfalse, 0, 0 );
    }

    if ( tr.startsolid || tr.allsolid ) {
        // make sure the tr.entityNum is set to the entity we're stuck in
        trap->Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask, qfalse, 0, 0 );
        tr.fraction = 0;
    }
    else {
        VectorCopy( tr.endpos, ent->r.currentOrigin );
    }

    if (ent->passThroughNum && tr.entityNum == (ent->passThroughNum-1))
    {
        VectorCopy( origin, ent->r.currentOrigin );
        trap->LinkEntity( (sharedEntity_t *)ent );
        goto passthrough;
    }

    trap->LinkEntity( (sharedEntity_t *)ent );

    if (ent->s.weapon == G2_MODEL_PART && !ent->bounceCount)
    {
        vec3_t lowerOrg;
        trace_t trG;

        VectorCopy(ent->r.currentOrigin, lowerOrg);
        lowerOrg[2] -= 1;
        trap->Trace( &trG, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, lowerOrg, passent, ent->clipmask, qfalse, 0, 0 );

        VectorCopy(trG.endpos, groundSpot);

        if (!trG.startsolid && !trG.allsolid && trG.entityNum == ENTITYNUM_WORLD)
        {
            ent->s.groundEntityNum = trG.entityNum;
        }
        else
        {
            ent->s.groundEntityNum = ENTITYNUM_NONE;
        }
    }

    if ( tr.fraction != 1) {
        // never explode or bounce on sky
        if ( tr.surfaceFlags & SURF_NOIMPACT ) {
            // If grapple, reset owner
            if (ent->parent && ent->parent->client && ent->parent->client->hook == ent) {
                ent->parent->client->hook = NULL;
            }

            if ((ent->s.weapon == WP_SABER && ent->isSaberEntity) || isKnockedSaber)
            {
                G_RunThink( ent );
                return;
            }
            else if (ent->s.weapon != G2_MODEL_PART)
            {
                G_FreeEntity( ent );
                return;
            }
        }

#if 0 //will get stomped with missile impact event...
        if (ent->s.weapon > WP_NONE && ent->s.weapon < WP_NUM_WEAPONS &&
                (tr.entityNum < MAX_CLIENTS || g_entities[tr.entityNum].s.eType == ET_NPC))
        {   //player or NPC, try making a mark on him
            /*
            gentity_t *evEnt = G_TempEntity(ent->r.currentOrigin, EV_GHOUL2_MARK);

            evEnt->s.owner = tr.entityNum; //the entity the mark should be placed on
            evEnt->s.weapon = ent->s.weapon; //the weapon used (to determine mark type)
            VectorCopy(ent->r.currentOrigin, evEnt->s.origin); //the point of impact

            //origin2 gets the predicted trajectory-based position.
            BG_EvaluateTrajectory( &ent->s.pos, level.time, evEnt->s.origin2 );

            //If they are the same, there will be problems.
            if (VectorCompare(evEnt->s.origin, evEnt->s.origin2))
            {
            	evEnt->s.origin2[2] += 2; //whatever, at least it won't mess up.
            }
            */
            //ok, let's try adding it to the missile ent instead (tempents bad!)
            G_AddEvent(ent, EV_GHOUL2_MARK, 0);

            //copy current pos to s.origin, and current projected traj to origin2
            VectorCopy(ent->r.currentOrigin, ent->s.origin);
            BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->s.origin2 );

            //the index for whoever we are hitting
            ent->s.otherEntityNum = tr.entityNum;

            if (VectorCompare(ent->s.origin, ent->s.origin2))
            {
                ent->s.origin2[2] += 2.0f; //whatever, at least it won't mess up.
            }
        }
#else
        if (ent->s.weapon > WP_NONE && ent->s.weapon < WP_NUM_WEAPONS &&
                (tr.entityNum < MAX_CLIENTS || g_entities[tr.entityNum].s.eType == ET_NPC))
        {   //player or NPC, try making a mark on him
            //copy current pos to s.origin, and current projected traj to origin2
            VectorCopy(ent->r.currentOrigin, ent->s.origin);
            BG_EvaluateTrajectory( &ent->s.pos, level.time, ent->s.origin2 );

            if (VectorCompare(ent->s.origin, ent->s.origin2))
            {
                ent->s.origin2[2] += 2.0f; //whatever, at least it won't mess up.
            }
        }
#endif

        G_MissileImpact( ent, &tr );

        if (tr.entityNum == ent->s.otherEntityNum)
        {   //if the impact event other and the trace ent match then it's ok to do the g2 mark
            ent->s.trickedentindex = 1;
        }

        if ( ent->s.eType != ET_MISSILE && ent->s.weapon != G2_MODEL_PART )
        {
            return;		// exploded
        }
    }

passthrough:
    if ( ent->s.pos.trType == TR_STATIONARY && (ent->s.eFlags&EF_MISSILE_STICK) )
    {   //stuck missiles should check some special stuff
        G_RunStuckMissile( ent );
        return;
    }

    if (ent->s.weapon == G2_MODEL_PART)
    {
        if (ent->s.groundEntityNum == ENTITYNUM_WORLD)
        {
            ent->s.pos.trType = TR_LINEAR;
            VectorClear(ent->s.pos.trDelta);
            ent->s.pos.trTime = level.time;

            VectorCopy(groundSpot, ent->s.pos.trBase);
            VectorCopy(groundSpot, ent->r.currentOrigin);

            if (ent->s.apos.trType != TR_STATIONARY)
            {
                ent->s.apos.trType = TR_STATIONARY;
                ent->s.apos.trTime = level.time;

                ent->s.apos.trBase[ROLL] = 0;
                ent->s.apos.trBase[PITCH] = 0;
            }
        }
    }

    // check think function after bouncing
    G_RunThink( ent );
}
Пример #26
0
/*
================
G_RunMissile
================
*/
void G_RunMissile( gentity_t *ent ) {
	vec3_t		origin;
	trace_t		tr;
	int			passent;

	// get current position
	BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );

	// if this missile bounced off an invulnerability sphere
	if ( ent->target_ent ) {
		passent = ent->target_ent->s.number;
	}
#ifdef MISSIONPACK
	// prox mines that left the owner bbox will attach to anything, even the owner
	else if (ent->s.weapon == WP_PROX_LAUNCHER && ent->count) {
		passent = ENTITYNUM_NONE;
	}
#endif
	else {
		// ignore interactions with the missile owner
		passent = ent->r.ownerNum;
	}
	// trace a line from the previous position to the current position
	trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask );

	if ( tr.startsolid || tr.allsolid ) {
		// make sure the tr.entityNum is set to the entity we're stuck in
		trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask );
		tr.fraction = 0;
	}
	else {
		VectorCopy( tr.endpos, ent->r.currentOrigin );
	}

	trap_LinkEntity( ent );

	if ( tr.fraction != 1 ) {
		// never explode or bounce on sky
		if ( tr.surfaceFlags & SURF_NOIMPACT ) {
			// If grapple, reset owner
			if (ent->parent && ent->parent->client && ent->parent->client->hook == ent) {
				ent->parent->client->hook = NULL;
			}
			G_FreeEntity( ent );
			return;
		}
		G_MissileImpact( ent, &tr );
		if ( ent->s.eType != ET_MISSILE ) {
			return;		// exploded
		}
	}
#ifdef MISSIONPACK
	// if the prox mine wasn't yet outside the player body
	if (ent->s.weapon == WP_PROX_LAUNCHER && !ent->count) {
		// check if the prox mine is outside the owner bbox
		trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, ENTITYNUM_NONE, ent->clipmask );
		if (!tr.startsolid || tr.entityNum != ent->r.ownerNum) {
			ent->count = 1;
		}
	}
#endif
	// check think function after bouncing
	G_RunThink( ent );
}
Пример #27
0
void G_RunMissile( gentity_t *ent ) {
	vector3		origin, groundSpot;
	trace_t		tr;
	int			passent;
	qboolean	isKnockedSaber = qfalse;

	if ( ent->neverFree && ent->s.weapon == WP_SABER && (ent->flags & FL_BOUNCE_HALF) ) {
		isKnockedSaber = qtrue;
		ent->s.pos.trType = TR_GRAVITY;
	}

	// get current position
	BG_EvaluateTrajectory( &ent->s.pos, level.time, &origin );

	// if this missile bounced off an invulnerability sphere
	if ( ent->target_ent ) {
		passent = ent->target_ent->s.number;
	}
	else {
		// ignore interactions with the missile owner
		if ( (ent->r.svFlags&SVF_OWNERNOTSHARED)
			&& (ent->s.eFlags&EF_JETPACK_ACTIVE) ) {//A vehicle missile that should be solid to its owner
			//I don't care about hitting my owner
			passent = ent->s.number;
		}
		else {
			passent = ent->r.ownerNum;
		}
	}
	// trace a line from the previous position to the current position
	if ( d_projectileGhoul2Collision.integer ) {
		trap->Trace( &tr, &ent->r.currentOrigin, &ent->r.mins, &ent->r.maxs, &origin, passent, ent->clipmask, qfalse, G2TRFLAG_DOGHOULTRACE | G2TRFLAG_GETSURFINDEX | G2TRFLAG_THICK | G2TRFLAG_HITCORPSES, g_g2TraceLod.integer );

		if ( tr.fraction != 1.0f && tr.entityNum < ENTITYNUM_WORLD ) {
			gentity_t *g2Hit = &g_entities[tr.entityNum];

			if ( g2Hit->inuse && g2Hit->client && g2Hit->ghoul2 ) { //since we used G2TRFLAG_GETSURFINDEX, tr.surfaceFlags will actually contain the index of the surface on the ghoul2 model we collided with.
				g2Hit->client->g2LastSurfaceHit = tr.surfaceFlags;
				g2Hit->client->g2LastSurfaceTime = level.time;
			}

			if ( g2Hit->ghoul2 ) {
				tr.surfaceFlags = 0; //clear the surface flags after, since we actually care about them in here.
			}

			//Raz: Portals!
			if ( g2Hit->s.eType == ET_SPECIAL && g2Hit->s.userInt1 ) {
				if ( g2Hit->touch ) {
					g2Hit->touch( g2Hit, ent, &tr );
				}
				JPLua::Entity_CallFunction( g2Hit, JPLua::JPLUA_ENTITY_TOUCH, (intptr_t)ent, (intptr_t)&tr );
				goto passthrough;
			}
		}
	}
	else {
		trap->Trace( &tr, &ent->r.currentOrigin, &ent->r.mins, &ent->r.maxs, &origin, passent, ent->clipmask, qfalse, 0, 0 );
	}

	if ( tr.startsolid || tr.allsolid ) {
		// make sure the tr.entityNum is set to the entity we're stuck in
		trap->Trace( &tr, &ent->r.currentOrigin, &ent->r.mins, &ent->r.maxs, &ent->r.currentOrigin, passent, ent->clipmask, qfalse, 0, 0 );
		tr.fraction = 0;
	}
	else {
		VectorCopy( &tr.endpos, &ent->r.currentOrigin );
	}

	if ( ent->passThroughNum && tr.entityNum == (ent->passThroughNum - 1) ) {
		VectorCopy( &origin, &ent->r.currentOrigin );
		trap->LinkEntity( (sharedEntity_t *)ent );
		goto passthrough;
	}

	trap->LinkEntity( (sharedEntity_t *)ent );

	if ( ent->s.weapon == G2_MODEL_PART && !ent->bounceCount ) {
		vector3 lowerOrg;
		trace_t trG;

		VectorCopy( &ent->r.currentOrigin, &lowerOrg );
		lowerOrg.z -= 1;
		trap->Trace( &trG, &ent->r.currentOrigin, &ent->r.mins, &ent->r.maxs, &lowerOrg, passent, ent->clipmask, qfalse, 0, 0 );

		VectorCopy( &trG.endpos, &groundSpot );

		if ( !trG.startsolid && !trG.allsolid && trG.entityNum == ENTITYNUM_WORLD ) {
			ent->s.groundEntityNum = trG.entityNum;
		}
		else {
			ent->s.groundEntityNum = ENTITYNUM_NONE;
		}
	}

	if ( ent->parent && ent->parent->client && ent->parent->client->hook && ent->parent->client->hook == ent
		&& (ent->parent->client->ps.duelInProgress
		|| BG_SaberInSpecial( ent->parent->client->ps.saberMove )
		|| !(japp_allowHook.integer & (1 << level.gametype))
		|| ent->parent->client->pers.adminData.isSlept
		|| g_entities[tr.entityNum].client) )
	{
		// not allowed to have hook out
		Weapon_HookFree( ent );
		return;
	}

	if ( tr.fraction != 1 ) {
		// never explode or bounce on sky
		if ( tr.surfaceFlags & SURF_NOIMPACT ) {
			// If grapple, reset owner
			//	if ( ent->parent && ent->parent->client && ent->parent->client->hook == ent )
			//		ent->parent->client->hook = NULL;
			if ( ent->parent && ent->parent->client && ent->parent->client->hook && ent->parent->client->hook == ent ) {
				Weapon_HookFree( ent->parent->client->hook );
			}

			if ( (ent->s.weapon == WP_SABER && ent->isSaberEntity) || isKnockedSaber ) {
				G_RunThink( ent );
				return;
			}
			else if ( ent->s.weapon != G2_MODEL_PART ) {
				G_FreeEntity( ent );
				return;
			}
		}

		if ( ent->s.weapon > WP_NONE && ent->s.weapon < WP_NUM_WEAPONS &&
			(tr.entityNum < MAX_CLIENTS || g_entities[tr.entityNum].s.eType == ET_NPC) ) { //player or NPC, try making a mark on him
			//copy current pos to s.origin, and current projected traj to origin2
			VectorCopy( &ent->r.currentOrigin, &ent->s.origin );
			BG_EvaluateTrajectory( &ent->s.pos, level.time, &ent->s.origin2 );

			if ( VectorCompare( &ent->s.origin, &ent->s.origin2 ) ) {
				ent->s.origin2.z += 2.0f; //whatever, at least it won't mess up.
			}
		}

		G_MissileImpact( ent, &tr );

		if ( tr.entityNum == ent->s.otherEntityNum ) {
			// if the impact event other and the trace ent match then it's ok to do the g2 mark
			ent->s.trickedEntIndex[0] = 1;
		}

		if ( ent->s.eType != ET_MISSILE && ent->s.weapon != G2_MODEL_PART ) {
			return;		// exploded
		}
	}

passthrough:
	if ( ent->s.pos.trType == TR_STATIONARY && (ent->s.eFlags & EF_MISSILE_STICK) ) {
		// stuck missiles should check some special stuff
		G_RunStuckMissile( ent );
		return;
	}

	if ( ent->s.weapon == G2_MODEL_PART ) {
		if ( ent->s.groundEntityNum == ENTITYNUM_WORLD ) {
			ent->s.pos.trType = TR_LINEAR;
			VectorClear( &ent->s.pos.trDelta );
			ent->s.pos.trTime = level.time;

			VectorCopy( &groundSpot, &ent->s.pos.trBase );
			VectorCopy( &groundSpot, &ent->r.currentOrigin );

			if ( ent->s.apos.trType != TR_STATIONARY ) {
				ent->s.apos.trType = TR_STATIONARY;
				ent->s.apos.trTime = level.time;

				ent->s.apos.trBase.roll = 0;
				ent->s.apos.trBase.pitch = 0;
			}
		}
	}

	// check think function after bouncing
	G_RunThink( ent );
}
Пример #28
0
/*
================
CG_AddDebrisElements
================
*/
void CG_AddDebrisElements( localEntity_t *le ) {
	vec3_t	newOrigin;
	trace_t	trace;
	float	lifeFrac;
	int		t, step = 50;

	for (t = le->lastTrailTime + step; t < cg.time; t += step) {
		// calculate new position
		BG_EvaluateTrajectory( &le->pos, t, newOrigin );

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

		// if stuck, kill it
		if (trace.startsolid) {
			// HACK, some walls screw up, so just pass through if starting in a solid
			VectorCopy( newOrigin, trace.endpos );
			trace.fraction = 1.0;
		}

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

		// add a trail
		lifeFrac = (float)(t - le->startTime) / (float)(le->endTime - le->startTime);

#if 0
		// fire
#if 1	// flame
		if (le->effectWidth > 0) {
			le->headJuncIndex = CG_AddSparkJunc( le->headJuncIndex,
										cgs.media.fireTrailShader,
										le->refEntity.origin,
										(int)(500.0 * (0.5 + 0.5*(1.0 - lifeFrac))),	// trail life
										1.0,	// alpha
										0.5,	// end alpha
										3,		// start width
										le->effectWidth );	// end width
#else	// spark line
		if (le->effectWidth > 0) {
			le->headJuncIndex = CG_AddSparkJunc( le->headJuncIndex,
										cgs.media.sparkParticleShader,
										le->refEntity.origin,
										(int)(600.0 * (0.5 + 0.5*(0.5 - lifeFrac))),	// trail life
										1.0 - lifeFrac*2,	// alpha
										0.5 * (1.0 - lifeFrac),	// end alpha
										5.0 * (1.0 - lifeFrac),	// start width
										5.0 * (1.0 - lifeFrac) );	// end width
#endif
		}
#endif

		// smoke
		if (le->effectFlags & 1)
		{
			le->headJuncIndex2 = CG_AddSmokeJunc( le->headJuncIndex2,
										cgs.media.smokeTrailShader,
										le->refEntity.origin,
										(int)(2000.0 * (0.5 + 0.5*(1.0 - lifeFrac))),	// trail life
										1.0 * (trace.fraction == 1.0) * (0.5 + 0.5 * (1.0 - lifeFrac)),	// alpha
										1,		// start width
										(int)(60.0 * (0.5 + 0.5*(1.0 - lifeFrac))) );	// end width
		}

		// if it is in a nodrop zone, remove it
		// this keeps gibs from waiting at the bottom of pits of death
		// and floating levels
//		if ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) {
//			CG_FreeLocalEntity( le );
//			return;
//		}

		if (trace.fraction < 1.0) {
			// reflect the velocity on the trace plane
			CG_ReflectVelocity( le, &trace );
			if (VectorLength(le->pos.trDelta) < 1) {
				CG_FreeLocalEntity( le );
				return;
			}
			// the intersection is a fraction of the frametime
			le->pos.trTime = t;
		}

		le->lastTrailTime = t;
	}

}

// Rafael Shrapnel
/*
===============
CG_AddShrapnel
===============
*/
void CG_AddShrapnel (localEntity_t *le) 
{
	vec3_t	newOrigin;
	trace_t	trace;

	if ( le->pos.trType == TR_STATIONARY ) {
		// sink into the ground if near the removal time
		int		t;
		float	oldZ;
		
		t = le->endTime - cg.time;
		if ( t < SINK_TIME ) {
			// we must use an explicit lighting origin, otherwise the
			// lighting would be lost as soon as the origin went
			// into the ground
			VectorCopy( le->refEntity.origin, le->refEntity.lightingOrigin );
			le->refEntity.renderfx |= RF_LIGHTING_ORIGIN;
			oldZ = le->refEntity.origin[2];
			le->refEntity.origin[2] -= 16 * ( 1.0 - (float)t / SINK_TIME );
			trap_R_AddRefEntityToScene( &le->refEntity );
			le->refEntity.origin[2] = oldZ;
		} else {
			trap_R_AddRefEntityToScene( &le->refEntity );
			CG_AddParticleShrapnel (le);
		}

		return;
	}

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

	// trace a line from previous position to new position
	CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID );
	if ( trace.fraction == 1.0 ) {
		// still in free fall
		VectorCopy( newOrigin, le->refEntity.origin );

		if ( le->leFlags & LEF_TUMBLE ) {
			vec3_t angles;

			BG_EvaluateTrajectory( &le->angles, cg.time, angles );
			AnglesToAxis( angles, le->refEntity.axis );
		}

		trap_R_AddRefEntityToScene( &le->refEntity );
		CG_AddParticleShrapnel (le);
		return;
	}

	// if it is in a nodrop zone, remove it
	// this keeps gibs from waiting at the bottom of pits of death
	// and floating levels
	if ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) {
		CG_FreeLocalEntity( le );
		return;
	}

	// leave a mark
	CG_FragmentBounceMark( le, &trace );

	// do a bouncy sound
	CG_FragmentBounceSound( le, &trace );

	// reflect the velocity on the trace plane
	CG_ReflectVelocity( le, &trace );

	trap_R_AddRefEntityToScene( &le->refEntity );
	CG_AddParticleShrapnel (le);
}
Пример #29
0
/*
================
CG_AddFragment
================
*/
void CG_AddFragment( localEntity_t *le ) {
	vec3_t	newOrigin;
	trace_t	trace;

	if (le->forceAlpha)
	{
		le->refEntity.renderfx |= RF_FORCE_ENT_ALPHA;
		le->refEntity.shaderRGBA[3] = le->forceAlpha;
	}

	if ( le->pos.trType == TR_STATIONARY ) {
		// sink into the ground if near the removal time
		int		t;
		float	t_e;
		
		t = le->endTime - cg.time;
		if ( t < (SINK_TIME*2) ) {
			le->refEntity.renderfx |= RF_FORCE_ENT_ALPHA;
			t_e = (float)((float)(le->endTime - cg.time)/(SINK_TIME*2));
			t_e = (int)((t_e)*255);

			if (t_e > 255)
			{
				t_e = 255;
			}
			if (t_e < 1)
			{
				t_e = 1;
			}

			if (le->refEntity.shaderRGBA[3] && t_e > le->refEntity.shaderRGBA[3])
			{
				t_e = le->refEntity.shaderRGBA[3];
			}

			le->refEntity.shaderRGBA[3] = t_e;

			trap->R_AddRefEntityToScene( &le->refEntity );
		} else {
			trap->R_AddRefEntityToScene( &le->refEntity );
		}

		return;
	}

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

	// trace a line from previous position to new position
	CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID );
	if ( trace.fraction == 1.0 ) {
		// still in free fall
		VectorCopy( newOrigin, le->refEntity.origin );

		if ( le->leFlags & LEF_TUMBLE ) {
			vec3_t angles;

			BG_EvaluateTrajectory( &le->angles, cg.time, angles );
			AnglesToAxis( angles, le->refEntity.axis );
			ScaleModelAxis(&le->refEntity);
		}

		trap->R_AddRefEntityToScene( &le->refEntity );

		// add a blood trail
		if ( le->leBounceSoundType == LEBS_BLOOD ) {
			CG_BloodTrail( le );
		}

		return;
	}

	// if it is in a nodrop zone, remove it
	// this keeps gibs from waiting at the bottom of pits of death
	// and floating levels
	if ( trap->CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) {
		CG_FreeLocalEntity( le );
		return;
	}

	if (!trace.startsolid)
	{
		// leave a mark
		CG_FragmentBounceMark( le, &trace );

		// do a bouncy sound
		CG_FragmentBounceSound( le, &trace );

		if (le->bounceSound)
		{ //specified bounce sound (debris)
			trap->S_StartSound(le->pos.trBase, ENTITYNUM_WORLD, CHAN_AUTO, le->bounceSound);
		}

		// reflect the velocity on the trace plane
		CG_ReflectVelocity( le, &trace );

		trap->R_AddRefEntityToScene( &le->refEntity );
	}
}
Пример #30
0
// use this to change between particle and trail code
//#define BLOOD_PARTICLE_TRAIL
void CG_BloodTrail( localEntity_t *le ) {
	int		t;
	int		t2;
	int		step;
	vec3_t	newOrigin;

#ifndef BLOOD_PARTICLE_TRAIL
	static vec3_t col = {1,1,1};
#endif

centity_t	*cent;
cent = &cg_entities[le->ownerNum];

	if ( !cg_blood.integer ) {
		return;
	}

	// step = 150;
#ifdef BLOOD_PARTICLE_TRAIL
	step = 10;
#else
	// time it takes to move 3 units
	step = (1000*3)/VectorLength(le->pos.trDelta);
#endif

	if (cent && cent->currentState.aiChar == AICHAR_ZOMBIE)
		step = 30;

	t = step * ( (cg.time - cg.frametime + step ) / step );
	t2 = step * ( cg.time / step );

	for ( ; t <= t2; t += step ) {
		BG_EvaluateTrajectory( &le->pos, t, newOrigin );
		
#ifdef BLOOD_PARTICLE_TRAIL
		CG_Particle_Bleed (cgs.media.smokePuffShader, newOrigin, vec3_origin, 0, 500+rand()%200);
#else	
		
		
		if (cent && cent->currentState.aiChar == AICHAR_ZOMBIE)
		{
			CG_Particle_Bleed (cgs.media.smokePuffShader, newOrigin, vec3_origin, 1, 500+rand()%200);
		}
		else
		// Ridah, blood trail using trail code (should be faster since we don't have to spawn as many)
		le->headJuncIndex = CG_AddTrailJunc( le->headJuncIndex,
									cgs.media.bloodTrailShader,
									t,
									STYPE_STRETCH,
									newOrigin,
									180,
									1.0,	// start alpha
									0.0,	// end alpha
									12.0,
									12.0,
									TJFL_NOCULL,
									col, col,
									0, 0 );
#endif

	}
}