Beispiel #1
0
void turret_breach_think(edict_t * self)
{
    edict_t *ent;
    vec3_t current_angles;
    vec3_t delta;

    VectorCopy(self->s.angles, current_angles);
    AnglesNormalize(current_angles);

    AnglesNormalize(self->move_angles);
    if (self->move_angles[PITCH] > 180)
        self->move_angles[PITCH] -= 360;

    // clamp angles to mins & maxs
    if (self->move_angles[PITCH] > self->pos1[PITCH])
        self->move_angles[PITCH] = self->pos1[PITCH];
    else if (self->move_angles[PITCH] < self->pos2[PITCH])
        self->move_angles[PITCH] = self->pos2[PITCH];

    if ((self->move_angles[YAW] < self->pos1[YAW])
            || (self->move_angles[YAW] > self->pos2[YAW])) {
        float dmin, dmax;

        dmin = fabs(self->pos1[YAW] - self->move_angles[YAW]);
        if (dmin < -180)
            dmin += 360;
        else if (dmin > 180)
            dmin -= 360;
        dmax = fabs(self->pos2[YAW] - self->move_angles[YAW]);
        if (dmax < -180)
            dmax += 360;
        else if (dmax > 180)
            dmax -= 360;
        if (fabs(dmin) < fabs(dmax))
            self->move_angles[YAW] = self->pos1[YAW];
        else
            self->move_angles[YAW] = self->pos2[YAW];
    }

    VectorSubtract(self->move_angles, current_angles, delta);
    if (delta[0] < -180)
        delta[0] += 360;
    else if (delta[0] > 180)
        delta[0] -= 360;
    if (delta[1] < -180)
        delta[1] += 360;
    else if (delta[1] > 180)
        delta[1] -= 360;
    delta[2] = 0;

    if (delta[0] > self->speed * FRAMETIME)
        delta[0] = self->speed * FRAMETIME;
    if (delta[0] < -1 * self->speed * FRAMETIME)
        delta[0] = -1 * self->speed * FRAMETIME;
    if (delta[1] > self->speed * FRAMETIME)
        delta[1] = self->speed * FRAMETIME;
    if (delta[1] < -1 * self->speed * FRAMETIME)
        delta[1] = -1 * self->speed * FRAMETIME;

    VectorScale(delta, 1.0 / FRAMETIME, self->avelocity);

    self->nextthink = level.time + FRAMETIME;

    for (ent = self->teammaster; ent; ent = ent->teamchain)
        ent->avelocity[1] = self->avelocity[1];

    // if we have adriver, adjust his velocities
    if (self->owner) {
        float angle;
        float target_z;
        float diff;
        vec3_t target;
        vec3_t dir;

        // angular is easy, just copy ours
        self->owner->avelocity[0] = self->avelocity[0];
        self->owner->avelocity[1] = self->avelocity[1];

        // x & y
        angle = self->s.angles[1] + self->owner->move_origin[1];
        angle *= (M_PI * 2 / 360);
        target[0] =
            SnapToEights(self->s.origin[0] +
                         cos(angle) * self->owner->move_origin[0]);
        target[1] =
            SnapToEights(self->s.origin[1] +
                         sin(angle) * self->owner->move_origin[0]);
        target[2] = self->owner->s.origin[2];

        VectorSubtract(target, self->owner->s.origin, dir);
        self->owner->velocity[0] = dir[0] * 1.0 / FRAMETIME;
        self->owner->velocity[1] = dir[1] * 1.0 / FRAMETIME;

        // z
        angle = self->s.angles[PITCH] * (M_PI * 2 / 360);
        target_z =
            SnapToEights(self->s.origin[2] +
                         self->owner->move_origin[0] * tan(angle) +
                         self->owner->move_origin[2]);

        diff = target_z - self->owner->s.origin[2];
        self->owner->velocity[2] = diff * 1.0 / FRAMETIME;

        if (self->spawnflags & 65536) {
            turret_breach_fire(self);
            self->spawnflags &= ~65536;
        }
    }
}
Beispiel #2
0
void T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod)
{
	gclient_t	*client;
	int			take;
	int			save;
	int			asave;
	int			psave;
	int			te_sparks;

	if (!targ->takedamage)
		return;

	if(mod == MOD_CRUSH)
	{
		//bot's state change
		if((targ->svflags & SVF_MONSTER) && targ->client)
		{
			if((targ->client->zc.waitin_obj == inflictor && targ->client->zc.zcstate)
				|| targ->groundentity == inflictor)
			{
//				gi.bprintf(PRINT_HIGH,"MOOOOOOOOOOOOOOOOOOOO\n");
				targ->client->zc.zcstate |= STS_W_DONT;
			}
		}
	}

	// friendly fire avoidance
	// if enabled you can't hurt teammates (but you can hurt yourself)
	// knockback still occurs
	if ((targ != attacker) && ((deathmatch->value && ((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS))) || coop->value))
	{
		if (OnSameTeam (targ, attacker))
		{
			if ((int)(dmflags->value) & DF_NO_FRIENDLY_FIRE)
				damage = 0;
			else
				mod |= MOD_FRIENDLY_FIRE;
		}
		else if(targ->client && !(targ->svflags & SVF_MONSTER))
		{
			if(attacker->client) targ->client->zc.first_target = attacker;
		}
	}
	meansOfDeath = mod;

	// easy mode takes half damage
	if (skill->value == 0 && deathmatch->value == 0 && targ->client)
	{
		damage *= 0.5;
		if (!damage)
			damage = 1;
	}

	client = targ->client;

	if (dflags & DAMAGE_BULLET)
		te_sparks = TE_BULLET_SPARKS;
	else
		te_sparks = TE_SPARKS;

	VectorNormalize(dir);

// bonus damage for suprising a monster
	if (!(dflags & DAMAGE_RADIUS) && (targ->svflags & SVF_MONSTER) && (attacker->client) && (!targ->enemy) && (targ->health > 0))
		damage *= 2;

//ZOID
//strength tech
	damage = CTFApplyStrength(attacker, damage);
//ZOID

	if (targ->flags & FL_NO_KNOCKBACK)
		knockback = 0;

// figure momentum add
	if (!(dflags & DAMAGE_NO_KNOCKBACK))
	{
		if ((knockback) && (targ->movetype != MOVETYPE_NONE) && (targ->movetype != MOVETYPE_BOUNCE) && (targ->movetype != MOVETYPE_PUSH) && (targ->movetype != MOVETYPE_STOP))
		{
			vec3_t	kvel;
			float	mass;

			if (targ->mass < 50)
				mass = 50;
			else
				mass = targ->mass;

			if (targ->client  && attacker == targ)
				VectorScale (dir, 1600.0 * (float)knockback / mass, kvel);	// the rocket jump hack...
			else
				VectorScale (dir, 500.0 * (float)knockback / mass, kvel);

			VectorAdd (targ->velocity, kvel, targ->velocity);
		}
	}

	take = damage;
	save = 0;

	// check for godmode
	if ( (targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION) )
	{
		take = 0;
		save = damage;
		SpawnDamage (te_sparks, point, normal, save);
	}

	// check for invincibility
	if ((client && client->invincible_framenum > level.framenum ) && !(dflags & DAMAGE_NO_PROTECTION))
	{
		if (targ->pain_debounce_time < level.time)
		{
			gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect3.wav"), 1, ATTN_NORM, 0);
//			gi.sound(targ, CHAN_ITEM, gi.soundindex("items/protect4.wav"), 1, ATTN_NORM, 0);
			targ->pain_debounce_time = level.time + 2;
		}
		take = 0;
		save = damage;
	}

//ZOID
//team armor protect
	if (ctf->value && targ->client && attacker->client &&
		targ->client->resp.ctf_team == attacker->client->resp.ctf_team &&
		targ != attacker && ((int)dmflags->value & DF_ARMOR_PROTECT)) {
		psave = asave = 0;
	} else {
//ZOID

		psave = CheckPowerArmor (targ, point, normal, take, dflags);
		take -= psave;

		asave = CheckArmor (targ, point, normal, take, te_sparks, dflags);
		take -= asave;
	}
	//treat cheat/powerup savings the same as armor
	asave += save;

//ZOID
//resistance tech
	take = CTFApplyResistance(targ, take);
//ZOID

	// team damage avoidance
	if (!(dflags & DAMAGE_NO_PROTECTION) && CheckTeamDamage (targ, attacker))
		return;

//ZOID
	CTFCheckHurtCarrier(targ, attacker);
//ZOID

// do the damage
	if (take)
	{
		if ((targ->svflags & SVF_MONSTER) || (client))
		{
			SpawnDamage (TE_BLOOD, point, normal, take);
			if(client && (targ->svflags & SVF_MONSTER) && attacker)
			{
				if(client->zc.battlemode & FIRE_CHIKEN) client->zc.battlemode &= ~FIRE_CHIKEN;

				if(mod == MOD_RAILGUN 
				|| mod == MOD_BFG_LASER
				|| mod == MOD_ROCKET
				|| mod == MOD_BLASTER
				|| mod == MOD_RIPPER
				|| mod == MOD_HYPERBLASTER
				|| mod == MOD_PHALANX)
				{
					if(attacker->client
						&& (9 * random() < Bot[client->zc.botindex].param[BOP_REACTION])
						&& !client->zc.first_target)
					{
						if(!OnSameTeam (targ, attacker)) client->zc.first_target = attacker;
					}
				}
			}
		}
		else
			SpawnDamage (te_sparks, point, normal, take);


		targ->health = targ->health - take;
			
		if (targ->health <= 0)
		{
			if ((targ->svflags & SVF_MONSTER) || (client))
				targ->flags |= FL_NO_KNOCKBACK;
			Killed (targ, inflictor, attacker, take, point);
			return;
		}
	}

	if (client)
	{
		if (!(targ->flags & FL_GODMODE) && (take))
			targ->pain (targ, attacker, knockback, take);
	}
	else if (take)
	{
		if (targ->pain)
			targ->pain (targ, attacker, knockback, take);
	}

	// add to the damage inflicted on a player this frame
	// the total will be turned into screen blends and view angle kicks
	// at the end of the frame
	if (client)
	{
		client->damage_parmor += psave;
		client->damage_armor += asave;
		client->damage_blood += take;
		client->damage_knockback += knockback;
		VectorCopy (point, client->damage_from);
	}
}
Beispiel #3
0
/*QUAKED func_explosive (0 .5 .8) ? Trigger_Spawn ANIMATED ANIMATED_FAST INACTIVE
Any brush that you want to explode or break apart.  If you want an
ex0plosion, set dmg and it will do a radius explosion of that amount
at the center of the bursh.

If targeted it will not be shootable.

INACTIVE - specifies that the entity is not explodable until triggered. If you use this you must
target the entity you want to trigger it. This is the only entity approved to activate it.

health defaults to 100.

mass defaults to 75.  This determines how much debris is emitted when
it explodes.  You get one large chunk per 100 of mass (up to 8) and
one small chunk per 25 of mass (up to 16).  So 800 gives the most.
*/
void func_explosive_explode (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
	vec3_t	origin;
	vec3_t	chunkorigin;
	vec3_t	size;
	int		count;
	int		mass;
	edict_t	*master;
	qboolean	done = false;

	// bmodel origins are (0 0 0), we need to adjust that here
	VectorScale (self->size, 0.5, size);
	VectorAdd (self->absmin, size, origin);
	VectorCopy (origin, self->s.origin);

	self->takedamage = DAMAGE_NO;

	if (self->dmg)
		T_RadiusDamage (self, attacker, self->dmg, NULL, self->dmg+40, MOD_EXPLOSIVE);

	VectorSubtract (self->s.origin, inflictor->s.origin, self->velocity);
	VectorNormalize (self->velocity);
	VectorScale (self->velocity, 150, self->velocity);

	// start chunks towards the center
	VectorScale (size, 0.5, size);

	mass = self->mass;
	if (!mass)
		mass = 75;

	// big chunks
	if (mass >= 100)
	{
		count = mass / 100;
		if (count > 8)
			count = 8;
		while(count--)
		{
			chunkorigin[0] = origin[0] + crandom() * size[0];
			chunkorigin[1] = origin[1] + crandom() * size[1];
			chunkorigin[2] = origin[2] + crandom() * size[2];
			ThrowDebris (self, "models/objects/debris1/tris.md2", 1, chunkorigin);
		}
	}

	// small chunks
	count = mass / 25;
	if (count > 16)
		count = 16;
	while(count--)
	{
		chunkorigin[0] = origin[0] + crandom() * size[0];
		chunkorigin[1] = origin[1] + crandom() * size[1];
		chunkorigin[2] = origin[2] + crandom() * size[2];
		ThrowDebris (self, "models/objects/debris2/tris.md2", 2, chunkorigin);
	}

	// PMM - if we're part of a train, clean ourselves out of it
	if (self->flags & FL_TEAMSLAVE)
	{
		if (self->teammaster)
		{
			master = self->teammaster;
			if(master && master->inuse)		// because mappers (other than jim (usually)) are stupid....
			{
				while (!done)
				{
					if (master->teamchain == self)
					{
						master->teamchain = self->teamchain;
						done = true;
					}
					master = master->teamchain;
				}
			}
		}
	}

	G_UseTargets (self, attacker);

	if (self->dmg)
		BecomeExplosion1 (self);
	else
		G_FreeEdict (self);
}
Beispiel #4
0
static qboolean MakeTextureMatrix(vec4_t texMat[2], vec4_t projection, decalVert_t *a, decalVert_t *b, decalVert_t *c)
{
	int     i, j;
	double  bb, s, t, d;
	dvec3_t pa, pb, pc;
	dvec3_t bary, origin, xyz;
	vec3_t  vecs[3], axis[3], lengths;

	/* project triangle onto plane of projection */
	d = DotProduct(a->xyz, projection) - projection[3];
	VectorMA(a->xyz, -d, projection, pa);
	d = DotProduct(b->xyz, projection) - projection[3];
	VectorMA(b->xyz, -d, projection, pb);
	d = DotProduct(c->xyz, projection) - projection[3];
	VectorMA(c->xyz, -d, projection, pc);

	/* calculate barycentric basis for the triangle */
	bb = (b->st[0] - a->st[0]) * (c->st[1] - a->st[1]) - (c->st[0] - a->st[0]) * (b->st[1] - a->st[1]);
	if (fabs(bb) < 0.00000001f)
	{
		return qfalse;
	}

	/* calculate texture origin */
	s       = 0.0f;
	t       = 0.0f;
	bary[0] = ((b->st[0] - s) * (c->st[1] - t) - (c->st[0] - s) * (b->st[1] - t)) / bb;
	bary[1] = ((c->st[0] - s) * (a->st[1] - t) - (a->st[0] - s) * (c->st[1] - t)) / bb;
	bary[2] = ((a->st[0] - s) * (b->st[1] - t) - (b->st[0] - s) * (a->st[1] - t)) / bb;

	origin[0] = bary[0] * pa[0] + bary[1] * pb[0] + bary[2] * pc[0];
	origin[1] = bary[0] * pa[1] + bary[1] * pb[1] + bary[2] * pc[1];
	origin[2] = bary[0] * pa[2] + bary[1] * pb[2] + bary[2] * pc[2];

	/* calculate s vector */
	s       = 1.0f;
	t       = 0.0f;
	bary[0] = ((b->st[0] - s) * (c->st[1] - t) - (c->st[0] - s) * (b->st[1] - t)) / bb;
	bary[1] = ((c->st[0] - s) * (a->st[1] - t) - (a->st[0] - s) * (c->st[1] - t)) / bb;
	bary[2] = ((a->st[0] - s) * (b->st[1] - t) - (b->st[0] - s) * (a->st[1] - t)) / bb;

	xyz[0] = bary[0] * pa[0] + bary[1] * pb[0] + bary[2] * pc[0];
	xyz[1] = bary[0] * pa[1] + bary[1] * pb[1] + bary[2] * pc[1];
	xyz[2] = bary[0] * pa[2] + bary[1] * pb[2] + bary[2] * pc[2];

	VectorSubtract(xyz, origin, vecs[0]);

	/* calculate t vector */
	s       = 0.0f;
	t       = 1.0f;
	bary[0] = ((b->st[0] - s) * (c->st[1] - t) - (c->st[0] - s) * (b->st[1] - t)) / bb;
	bary[1] = ((c->st[0] - s) * (a->st[1] - t) - (a->st[0] - s) * (c->st[1] - t)) / bb;
	bary[2] = ((a->st[0] - s) * (b->st[1] - t) - (b->st[0] - s) * (a->st[1] - t)) / bb;

	xyz[0] = bary[0] * pa[0] + bary[1] * pb[0] + bary[2] * pc[0];
	xyz[1] = bary[0] * pa[1] + bary[1] * pb[1] + bary[2] * pc[1];
	xyz[2] = bary[0] * pa[2] + bary[1] * pb[2] + bary[2] * pc[2];

	VectorSubtract(xyz, origin, vecs[1]);

	/* calcuate r vector */
	VectorScale(projection, -1.0f, vecs[2]);

	/* calculate transform axis */
	for (i = 0; i < 3; i++)
		lengths[i] = VectorNormalize2(vecs[i], axis[i]);

	for (i = 0; i < 2; i++)
		for (j = 0; j < 3; j++)
			texMat[i][j] = lengths[i] > 0.0f ? (axis[i][j] / lengths[i]) : 0.0f;
	texMat[0][3] = a->st[0] - DotProduct(pa, texMat[0]);
	texMat[1][3] = a->st[1] - DotProduct(pa, texMat[1]);

	/* disco */
	return qtrue;
}
Beispiel #5
0
qboolean	PM_SlideMove( qboolean gravity ) {
	int			bumpcount, numbumps;
	vec3_t		dir;
	float		d;
	int			numplanes;
	vec3_t		normal, planes[MAX_CLIP_PLANES];
	vec3_t		primal_velocity;
	vec3_t		clipVelocity;
	int			i, j, k;
	trace_t	trace;
	vec3_t		end;
	float		time_left;
	float		into;
	vec3_t		endVelocity;
	vec3_t		endClipVelocity;
	//qboolean	damageSelf = qtrue;
	
	numbumps = 4;

	VectorCopy (pm->ps->velocity, primal_velocity);

	if ( gravity ) {
		VectorCopy( pm->ps->velocity, endVelocity );
		endVelocity[2] -= pm->ps->gravity * pml.frametime+3;
		//[JetpackChange1.3]
		if(pm->ps->pm_type == PM_JETPACK && pm->cmd.upmove <= 0 && !(pm->ps->pm_flags & PMF_DUCKED))
			endVelocity[2] -= endVelocity[2]/100*20;
		//[/JetpackChange1.3]
		pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5;
		primal_velocity[2] = endVelocity[2];
		if ( pml.groundPlane ) {
			if ( PM_GroundSlideOkay( pml.groundTrace.plane.normal[2] ) )
			{// slide along the ground plane
				PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, 
					pm->ps->velocity, OVERCLIP );
			}
		}
	}

	time_left = pml.frametime;

	// never turn against the ground plane
	if ( pml.groundPlane ) {
		numplanes = 1;
		VectorCopy( pml.groundTrace.plane.normal, planes[0] );
		if ( !PM_GroundSlideOkay( planes[0][2] ) )
		{
			planes[0][2] = 0;
			VectorNormalize( planes[0] );
		}
	} else {
		numplanes = 0;
	}

	// never turn against original velocity
	VectorNormalize2( pm->ps->velocity, planes[numplanes] );
	numplanes++;

	for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) {

		// calculate position we are trying to move to
		VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );

		// see if we can make it there
		pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask);

		if (trace.allsolid) {
			// entity is completely trapped in another solid
			pm->ps->velocity[2] = 0;	// don't build up falling damage, but allow sideways acceleration
			return qtrue;
		}

		if (trace.fraction > 0) {
			// actually covered some distance
			VectorCopy (trace.endpos, pm->ps->origin);
		}

		if (trace.fraction == 1) {
			 break;		// moved the entire distance
		}

		// save entity for contact
		PM_AddTouchEnt( trace.entityNum );

		if (pm->ps->clientNum >= MAX_CLIENTS)
		{
			bgEntity_t *pEnt = pm_entSelf;

			if (pEnt && pEnt->s.eType == ET_NPC && pEnt->s.NPC_class == CLASS_VEHICLE &&
				pEnt->m_pVehicle)
			{ //do vehicle impact stuff then
				PM_VehicleImpact(pEnt, &trace);
			}
		}
#ifdef QAGAME
		else
		{
			if ( PM_ClientImpact( &trace ) )
			{
				continue;
			}
		}
#endif

		time_left -= time_left * trace.fraction;

		if (numplanes >= MAX_CLIP_PLANES) {
			// this shouldn't really happen
			VectorClear( pm->ps->velocity );
			return qtrue;
		}

		VectorCopy( trace.plane.normal, normal );

		if ( !PM_GroundSlideOkay( normal[2] ) )
		{//wall-running
			//never push up off a sloped wall
			normal[2] = 0;
			VectorNormalize( normal );
		}
		//
		// if this is the same plane we hit before, nudge velocity
		// out along it, which fixes some epsilon issues with
		// non-axial planes
		//
		if ( !(pm->ps->pm_flags&PMF_STUCK_TO_WALL) )
		{//no sliding if stuck to wall!
			for ( i = 0 ; i < numplanes ; i++ ) {
				if ( VectorCompare( normal, planes[i] ) ) {//DotProduct( normal, planes[i] ) > 0.99 ) {
					VectorAdd( normal, pm->ps->velocity, pm->ps->velocity );
					break;
				}
			}
			if ( i < numplanes ) {
				continue;
			}
		}
		VectorCopy (normal, planes[numplanes]);
		numplanes++;

		//
		// modify velocity so it parallels all of the clip planes
		//

		// find a plane that it enters
		for ( i = 0 ; i < numplanes ; i++ ) {
			into = DotProduct( pm->ps->velocity, planes[i] );
			if ( into >= 0.1 ) {
				continue;		// move doesn't interact with the plane
			}

			// see how hard we are hitting things
			if ( -into > pml.impactSpeed ) {
				pml.impactSpeed = -into;
			}

			// slide along the plane
			PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP );

			// slide along the plane
			PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP );

			// see if there is a second plane that the new move enters
			for ( j = 0 ; j < numplanes ; j++ ) {
				if ( j == i ) {
					continue;
				}
				if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) {
					continue;		// move doesn't interact with the plane
				}

				// try clipping the move to the plane
				PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP );
				PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP );

				// see if it goes back into the first clip plane
				if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) {
					continue;
				}

				// slide the original velocity along the crease
				CrossProduct (planes[i], planes[j], dir);
				VectorNormalize( dir );
				d = DotProduct( dir, pm->ps->velocity );
				VectorScale( dir, d, clipVelocity );

				CrossProduct (planes[i], planes[j], dir);
				VectorNormalize( dir );
				d = DotProduct( dir, endVelocity );
				VectorScale( dir, d, endClipVelocity );

				// see if there is a third plane the the new move enters
				for ( k = 0 ; k < numplanes ; k++ ) {
					if ( k == i || k == j ) {
						continue;
					}
					if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) {
						continue;		// move doesn't interact with the plane
					}

					// stop dead at a triple plane interaction
					VectorClear( pm->ps->velocity );
					return qtrue;
				}
			}

			// if we have fixed all interactions, try another move
			VectorCopy( clipVelocity, pm->ps->velocity );
			VectorCopy( endClipVelocity, endVelocity );
			break;
		}
	}

	if ( gravity ) {
		VectorCopy( endVelocity, pm->ps->velocity );
	}

	// don't change velocity if in a timer (FIXME: is this correct?)
	if ( pm->ps->pm_time ) {
		VectorCopy( primal_velocity, pm->ps->velocity );
	}

	return (qboolean)( bumpcount != 0 );
}
Beispiel #6
0
void G_RunMissile( gentity_t *ent ) 
{
	vec3_t		oldOrg;
	trace_t		tr;
	int			trHitLoc=HL_NONE;

	if ( (ent->s.eFlags&EF_HELD_BY_SAND_CREATURE) )
	{//in a sand creature's mouth
		if ( ent->activator )
		{
			mdxaBone_t	boltMatrix;
			// Getting the bolt here
			//in hand
			vec3_t scAngles = {0};
			scAngles[YAW] = ent->activator->currentAngles[YAW];
			gi.G2API_GetBoltMatrix( ent->activator->ghoul2, ent->activator->playerModel, ent->activator->gutBolt, 
					&boltMatrix, scAngles, ent->activator->currentOrigin, (cg.time?cg.time:level.time),
					NULL, ent->activator->s.modelScale );
			// Storing ent position, bolt position, and bolt axis
			gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, ent->currentOrigin );
			G_SetOrigin( ent, ent->currentOrigin );
		}
		// check think function
		G_RunThink( ent );
		return;
	}

	VectorCopy( ent->currentOrigin, oldOrg );

	// get current position
	if ( ent->s.pos.trType == TR_INTERPOLATE )
	{//rolling missile?
		//FIXME: WTF?!!  Sticks to stick missiles?
		//FIXME: they stick inside the player
		G_RollMissile( ent );
		if ( ent->s.eType != ET_GENERAL )
		{//didn't explode
			VectorCopy( ent->currentOrigin, ent->s.pos.trBase );
			gi.trace( &tr, oldOrg, ent->mins, ent->maxs, ent->currentOrigin, ent->s.number, ent->clipmask, G2_RETURNONHIT, 10 );
			if ( VectorCompare( ent->s.pos.trDelta, vec3_origin ) )
			{
				//VectorCopy( ent->currentAngles, ent->s.apos.trBase );
				VectorClear( ent->s.apos.trDelta );
			}
			else
			{
				vec3_t	ang, fwdDir, rtDir;
				float	speed;
				
				ent->s.apos.trType = TR_INTERPOLATE;
				VectorSet( ang, 0, ent->s.apos.trBase[1], 0 );
				AngleVectors( ang, fwdDir, rtDir, NULL );
				speed = VectorLength( ent->s.pos.trDelta )*4;

				//HMM, this works along an axis-aligned dir, but not along diagonals
				//This is because when roll gets to 90, pitch becomes yaw, and vice-versa
				//Maybe need to just set the angles directly?
				ent->s.apos.trDelta[0] = DotProduct( fwdDir, ent->s.pos.trDelta );
				ent->s.apos.trDelta[1] = 0;//never spin!
				ent->s.apos.trDelta[2] = DotProduct( rtDir, ent->s.pos.trDelta );

				VectorNormalize( ent->s.apos.trDelta );
				VectorScale( ent->s.apos.trDelta, speed, ent->s.apos.trDelta );

				ent->s.apos.trTime = level.previousTime;
			}
		}
	}
	else
	{
		vec3_t		origin; 
		EvaluateTrajectory( &ent->s.pos, level.time, origin );
		// trace a line from the previous position to the current position,
		// ignoring interactions with the missile owner
		gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, origin, 
			ent->owner ? ent->owner->s.number : ent->s.number, ent->clipmask, G2_COLLIDE, 10 );
		
		if ( tr.entityNum != ENTITYNUM_NONE )
		{
			gentity_t *other = &g_entities[tr.entityNum];
			// check for hitting a lightsaber
			if ( other->contents & CONTENTS_LIGHTSABER )
			{//hit a lightsaber bbox
				if ( other->owner 
					&& other->owner->client 
					&& !other->owner->client->ps.saberInFlight 
					&& ( Q_irand( 0, (other->owner->client->ps.forcePowerLevel[FP_SABER_DEFENSE]*other->owner->client->ps.forcePowerLevel[FP_SABER_DEFENSE]) ) == 0 
						|| !InFront( ent->currentOrigin, other->owner->currentOrigin, other->owner->client->ps.viewangles, SABER_REFLECT_MISSILE_CONE ) ) )//other->owner->s.number == 0 &&
				{//Jedi cannot block shots from behind!
					//re-trace from here, ignoring the lightsaber
					gi.trace( &tr, tr.endpos, ent->mins, ent->maxs, origin, tr.entityNum, ent->clipmask, G2_RETURNONHIT, 10 );
				}
			}
		}

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

	// get current angles
	VectorMA( ent->s.apos.trBase, (level.time - ent->s.apos.trTime) * 0.001, ent->s.apos.trDelta, ent->s.apos.trBase );

	//FIXME: Rolling things hitting G2 polys is weird
	///////////////////////////////////////////////////////
//?	if ( tr.fraction != 1 ) 
	{
	// did we hit or go near a Ghoul2 model?
//		qboolean hitModel = qfalse;
		for (int i=0; i < MAX_G2_COLLISIONS; i++)
		{
			if (tr.G2CollisionMap[i].mEntityNum == -1)
			{
				break;
			}

			CCollisionRecord &coll = tr.G2CollisionMap[i];
			gentity_t	*hitEnt = &g_entities[coll.mEntityNum];

			// process collision records here...
			// make sure we only do this once, not for all the entrance wounds we might generate
			if ((coll.mFlags & G2_FRONTFACE)/* && !(hitModel)*/ && hitEnt->health)
			{
				if (trHitLoc==HL_NONE)
				{
					G_GetHitLocFromSurfName( &g_entities[coll.mEntityNum], gi.G2API_GetSurfaceName( &g_entities[coll.mEntityNum].ghoul2[coll.mModelIndex], coll.mSurfaceIndex ), &trHitLoc, coll.mCollisionPosition, NULL, NULL, ent->methodOfDeath );
				}

				break; // NOTE: the way this whole section was working, it would only get inside of this IF once anyway, might as well break out now
			}
		}
	}
/////////////////////////////////////////////////////////

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

	gi.linkentity( ent );

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

	// check think function
	G_RunThink( ent );

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

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

	AddSightEvent( ent->owner, ent->currentOrigin, 512, AEL_DISCOVERED, 75 );//wakes them up when see a shot passes in front of them
	if ( !Q_irand( 0, 10 ) )
	{//not so often...
		if ( ent->splashDamage && ent->splashRadius )
		{//I'm an exploder, let people around me know danger is coming
			if ( ent->s.weapon == WP_TRIP_MINE )
			{//???
			}
			else 
			{
				if ( ent->s.weapon == WP_ROCKET_LAUNCHER && ent->e_ThinkFunc == thinkF_rocketThink )
				{//homing rocket- run like hell!
					AddSightEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER_GREAT, 50 );
				}
				else
				{
					AddSightEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER, 50 );
				}
				AddSoundEvent( ent->owner, ent->currentOrigin, ent->splashRadius, AEL_DANGER );
			}
		}
		else
		{//makes them run from near misses
			AddSightEvent( ent->owner, ent->currentOrigin, 48, AEL_DANGER, 50 );
		}
	}

	if ( tr.fraction == 1 ) 
	{
		if ( ent->s.weapon == WP_THERMAL && ent->s.pos.trType == TR_INTERPOLATE )
		{//a rolling thermal that didn't hit anything
			G_MissileAddAlerts( ent );
		}
		return;
	}

	// never explode or bounce on sky
	if ( tr.surfaceFlags & SURF_NOIMPACT ) 
	{
		G_FreeEntity( ent );
		return;
	}

	G_MissileImpact( ent, &tr, trHitLoc );
}
Beispiel #7
0
/*
================
G_BounceMissile

================
*/
void G_BounceMissile( gentity_t *ent, trace_t *trace ) {
	vec3_t	velocity;
	float	dot;
	int		hitTime;

	// reflect the velocity on the trace plane
	hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction;
	EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity );
	dot = DotProduct( velocity, trace->plane.normal );
	VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta );

	if ( ent->s.eFlags & EF_BOUNCE_SHRAPNEL ) 
	{
		VectorScale( ent->s.pos.trDelta, 0.25f, ent->s.pos.trDelta );
		ent->s.pos.trType = TR_GRAVITY;

		// check for stop
		if ( trace->plane.normal[2] > 0.7 && ent->s.pos.trDelta[2] < 40 ) //this can happen even on very slightly sloped walls, so changed it from > 0 to > 0.7
		{
			G_SetOrigin( ent, trace->endpos );
			ent->nextthink = level.time + 100;
			return;
		}
	}
	else if ( ent->s.eFlags & EF_BOUNCE_HALF ) 
	{
		VectorScale( ent->s.pos.trDelta, 0.5, ent->s.pos.trDelta );

		// check for stop
		if ( trace->plane.normal[2] > 0.7 && ent->s.pos.trDelta[2] < 40 ) //this can happen even on very slightly sloped walls, so changed it from > 0 to > 0.7
		{
			if ( ent->s.weapon == WP_THERMAL )
			{//roll when you "stop"
				ent->s.pos.trType = TR_INTERPOLATE;
			}
			else
			{
				G_SetOrigin( ent, trace->endpos );
				ent->nextthink = level.time + 500;
				return;
			}
		}

		if ( ent->s.weapon == WP_THERMAL )
		{
			ent->has_bounced = qtrue;
		}
	}

#if 0
	// OLD--this looks so wrong.  It looked wrong in EF.  It just must be wrong.
	VectorAdd( ent->currentOrigin, trace->plane.normal, ent->currentOrigin);

	ent->s.pos.trTime = level.time - 10;
#else
	// NEW--It would seem that we want to set our trBase to the trace endpos
	//	and set the trTime to the actual time of impact....
	VectorAdd( trace->endpos, trace->plane.normal, ent->currentOrigin );
	if ( hitTime >= level.time )
	{//trace fraction must have been 1
		ent->s.pos.trTime = level.time - 10;
	}
	else
	{
		ent->s.pos.trTime = hitTime - 10; // this is kinda dumb hacking, but it pushes the missile away from the impact plane a bit
	}
#endif

	VectorCopy( ent->currentOrigin, ent->s.pos.trBase );
	VectorCopy( trace->plane.normal, ent->pos1 );

	if ( ent->s.weapon != WP_SABER 
		&& ent->s.weapon != WP_THERMAL 
		&& ent->e_clThinkFunc != clThinkF_CG_Limb
		&& ent->e_ThinkFunc != thinkF_LimbThink )
	{//not a saber, bouncing thermal or limb
		//now you can damage the guy you came from
		ent->owner = NULL;
	}
}
/*
=============
SV_Physics_Toss

Toss, bounce, and fly movement.  When onground, do nothing.
=============
*/
void SV_Physics_Toss (edict_t *ent)
{
	trace_t		trace;
	vec3_t		move;
	float		backoff;
	edict_t		*slave;
	qboolean	wasinwater;
	qboolean	isinwater;
	vec3_t		old_origin;

// regular thinking
	SV_RunThink (ent);

	// if not a team captain, so movement will be handled elsewhere
	if ( ent->flags & FL_TEAMSLAVE)
		return;

	if (ent->velocity[2] > 0)
		ent->groundentity = NULL;

// check for the groundentity going away
	if (ent->groundentity)
		if (!ent->groundentity->inuse)
			ent->groundentity = NULL;

// if onground, return without moving
	if ( ent->groundentity )
		return;

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

	SV_CheckVelocity (ent);

// add gravity
	if (ent->movetype != MOVETYPE_FLY
	&& ent->movetype != MOVETYPE_FLYMISSILE
	// RAFAEL
	// move type for rippergun projectile
	&& ent->movetype != MOVETYPE_WALLBOUNCE)
		SV_AddGravity (ent);

// move angles
	VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);

// move origin
	VectorScale (ent->velocity, FRAMETIME, move);
	trace = SV_PushEntity (ent, move);
	if (!ent->inuse)
		return;

	if (trace.fraction < 1)
	{
		// RAFAEL
		if (ent->movetype == MOVETYPE_WALLBOUNCE)
			backoff = 2.0;
		// RAFAEL ( else )		
		else if (ent->movetype == MOVETYPE_BOUNCE)
			backoff = 1.5;
		else
			backoff = 1;

		ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff);

		// RAFAEL
		if (ent->movetype == MOVETYPE_WALLBOUNCE)
			vectoangles (ent->velocity, ent->s.angles);

	// stop if on ground
		// RAFAEL
		if (trace.plane.normal[2] > 0.7 && ent->movetype != MOVETYPE_WALLBOUNCE)
		{		
			if (ent->velocity[2] < 60 || ent->movetype != MOVETYPE_BOUNCE )
			{
				ent->groundentity = trace.ent;
				ent->groundentity_linkcount = trace.ent->linkcount;
				VectorCopy (vec3_origin, ent->velocity);
				VectorCopy (vec3_origin, ent->avelocity);
			}
		}

//		if (ent->touch)
//			ent->touch (ent, trace.ent, &trace.plane, trace.surface);
	}
	
// check for water transition
	wasinwater = (ent->watertype & MASK_WATER);
	ent->watertype = gi.pointcontents (ent->s.origin);
	isinwater = ent->watertype & MASK_WATER;

	if (isinwater)
		ent->waterlevel = 1;
	else
		ent->waterlevel = 0;

	if (!wasinwater && isinwater)
		gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
	else if (wasinwater && !isinwater)
		gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);

// move teamslaves
	for (slave = ent->teamchain; slave; slave = slave->teamchain)
	{
		VectorCopy (ent->s.origin, slave->s.origin);
		gi.linkentity (slave);
	}
}
Beispiel #9
0
/*
============
CanDamage

Returns true if the inflictor can directly damage the target.  Used for
explosions and melee attacks.
============
*/
qboolean CanDamage(edict_t * targ, edict_t * inflictor)
{
	vec3_t dest;
	trace_t trace;

// bmodels need special checking because their origin is 0,0,0
	if (targ->movetype == MOVETYPE_PUSH) {
		VectorAdd(targ->absmin, targ->absmax, dest);
		VectorScale(dest, 0.5, dest);
		trace =
		    gi.trace(inflictor->s.origin, vec3_origin, vec3_origin,
			     dest, inflictor, MASK_SOLID);
		if (trace.fraction == 1.0)
			return true;
		if (trace.ent == targ)
			return true;
		return false;
	}

	trace =
	    gi.trace(inflictor->s.origin, vec3_origin, vec3_origin,
		     targ->s.origin, inflictor, MASK_SOLID);
	if (trace.fraction == 1.0)
		return true;

	VectorCopy(targ->s.origin, dest);
	dest[0] += 15.0;
	dest[1] += 15.0;
	trace =
	    gi.trace(inflictor->s.origin, vec3_origin, vec3_origin, dest,
		     inflictor, MASK_SOLID);
	if (trace.fraction == 1.0)
		return true;

	VectorCopy(targ->s.origin, dest);
	dest[0] += 15.0;
	dest[1] -= 15.0;
	trace =
	    gi.trace(inflictor->s.origin, vec3_origin, vec3_origin, dest,
		     inflictor, MASK_SOLID);
	if (trace.fraction == 1.0)
		return true;

	VectorCopy(targ->s.origin, dest);
	dest[0] -= 15.0;
	dest[1] += 15.0;
	trace =
	    gi.trace(inflictor->s.origin, vec3_origin, vec3_origin, dest,
		     inflictor, MASK_SOLID);
	if (trace.fraction == 1.0)
		return true;

	VectorCopy(targ->s.origin, dest);
	dest[0] -= 15.0;
	dest[1] -= 15.0;
	trace =
	    gi.trace(inflictor->s.origin, vec3_origin, vec3_origin, dest,
		     inflictor, MASK_SOLID);
	if (trace.fraction == 1.0)
		return true;

	return false;
}
Beispiel #10
0
/*
-------------------------
NPC_BSHowler_Default
-------------------------
*/
void NPC_BSHowler_Default( void )
{
	if ( NPC->client->ps.legsAnim != BOTH_GESTURE1 )
	{
		NPC->count = 0;
	}
	//FIXME: if in jump, do damage in front and maybe knock them down?
	if ( !TIMER_Done( NPC, "attacking" ) )
	{
		if ( NPC->enemy )
		{
			//NPC_FaceEnemy( qfalse );
			Howler_Attack( Distance( NPC->enemy->currentOrigin, NPC->currentOrigin ) );
		}
		else
		{
			//NPC_UpdateAngles( qfalse, qtrue );
			Howler_Attack( 0.0f );
		}
		NPC_UpdateAngles( qfalse, qtrue );
		return;
	}

	if ( NPC->enemy )
	{
		if ( NPCInfo->stats.aggression > 0 )
		{
			if ( TIMER_Done( NPC, "aggressionDecay" ) )
			{
				NPCInfo->stats.aggression--;
				TIMER_Set( NPC, "aggressionDecay", 500 );
			}
		}
		if ( !TIMER_Done( NPC, "flee" ) 
			&& NPC_BSFlee() )	//this can clear ENEMY
		{//successfully trying to run away
			return;
		}
		if ( NPC->enemy == NULL)
		{
			NPC_UpdateAngles( qfalse, qtrue );
			return;
		}
		if ( NPCInfo->localState == LSTATE_FLEE )
		{//we were fleeing, now done (either timer ran out or we cannot flee anymore
			if ( NPC_ClearLOS( NPC->enemy ) )
			{//if enemy is still around, go berzerk
				NPCInfo->localState = LSTATE_BERZERK;
			}
			else
			{//otherwise, lick our wounds?
				NPCInfo->localState = LSTATE_CLEAR;
				TIMER_Set( NPC, "standing", Q_irand( 3000, 10000 ) );
			}
		}
		else if ( NPCInfo->localState == LSTATE_BERZERK )
		{//go nuts!
		}
		else if ( NPCInfo->stats.aggression >= Q_irand( 75, 125 ) )
		{//that's it, go nuts!
			NPCInfo->localState = LSTATE_BERZERK;
		}
		else if ( !TIMER_Done( NPC, "retreating" ) )
		{//trying to back off
			NPC_FaceEnemy( qtrue );
			if ( NPC->client->ps.speed > NPCInfo->stats.walkSpeed )
			{
				NPC->client->ps.speed = NPCInfo->stats.walkSpeed;
			}
			ucmd.buttons |= BUTTON_WALKING;
			if ( Distance( NPC->enemy->currentOrigin, NPC->currentOrigin ) < HOWLER_RETREAT_DIST )
			{//enemy is close
				vec3_t moveDir;
				AngleVectors( NPC->currentAngles, moveDir, NULL, NULL );
				VectorScale( moveDir, -1, moveDir );
				if ( !NAV_DirSafe( NPC, moveDir, 8 ) )
				{//enemy is backing me up against a wall or ledge!  Start to get really mad!
					NPCInfo->stats.aggression += 2;
				}
				else
				{//back off
					ucmd.forwardmove = -127;
				}
				//enemy won't leave me alone, get mad...
				NPCInfo->stats.aggression++;
			}
			return;
		}
		else if ( TIMER_Done( NPC, "standing" ) )
		{//not standing around
			if ( !(NPCInfo->last_ucmd.forwardmove)
				&& !(NPCInfo->last_ucmd.rightmove) )
			{//stood last frame
				if ( TIMER_Done( NPC, "walking" ) 
					&& TIMER_Done( NPC, "running" ) )
				{//not walking or running
					if ( Q_irand( 0, 2 ) )
					{//run for a while
						TIMER_Set( NPC, "walking", Q_irand( 4000, 8000 ) );
					}
					else
					{//walk for a bit
						TIMER_Set( NPC, "running", Q_irand( 2500, 5000 ) );
					}
				}
			}
			else if ( (NPCInfo->last_ucmd.buttons&BUTTON_WALKING) )
			{//walked last frame
				if ( TIMER_Done( NPC, "walking" ) )
				{//just finished walking
					if ( Q_irand( 0, 5 ) || DistanceSquared( NPC->enemy->currentOrigin, NPC->currentOrigin ) < MAX_DISTANCE_SQR )
					{//run for a while
						TIMER_Set( NPC, "running", Q_irand( 4000, 20000 ) );
					}
					else
					{//stand for a bit
						TIMER_Set( NPC, "standing", Q_irand( 2000, 6000 ) );
					}
				}
			}
			else
			{//ran last frame
				if ( TIMER_Done( NPC, "running" ) )
				{//just finished running
					if ( Q_irand( 0, 8 ) || DistanceSquared( NPC->enemy->currentOrigin, NPC->currentOrigin ) < MAX_DISTANCE_SQR )
					{//walk for a while
						TIMER_Set( NPC, "walking", Q_irand( 3000, 10000 ) );
					}
					else
					{//stand for a bit
						TIMER_Set( NPC, "standing", Q_irand( 2000, 6000 ) );
					}
				}
			}
		}
		if ( NPC_ValidEnemy( NPC->enemy ) == qfalse )
		{
			TIMER_Remove( NPC, "lookForNewEnemy" );//make them look again right now
			if ( !NPC->enemy->inuse || level.time - NPC->enemy->s.time > Q_irand( 10000, 15000 ) )
			{//it's been a while since the enemy died, or enemy is completely gone, get bored with him
				NPC->enemy = NULL;
				Howler_Patrol();
				NPC_UpdateAngles( qtrue, qtrue );
				return;
			}
		}
		if ( TIMER_Done( NPC, "lookForNewEnemy" ) )
		{
			gentity_t *sav_enemy = NPC->enemy;//FIXME: what about NPC->lastEnemy?
			NPC->enemy = NULL;
			gentity_t *newEnemy = NPC_CheckEnemy( NPCInfo->confusionTime < level.time, qfalse, qfalse );
			NPC->enemy = sav_enemy;
			if ( newEnemy && newEnemy != sav_enemy )
			{//picked up a new enemy!
				NPC->lastEnemy = NPC->enemy;
				G_SetEnemy( NPC, newEnemy );
				if ( NPC->enemy != NPC->lastEnemy )
				{//clear this so that we only sniff the player the first time we pick them up
					NPC->useDebounceTime = 0;
				}
				//hold this one for at least 5-15 seconds
				TIMER_Set( NPC, "lookForNewEnemy", Q_irand( 5000, 15000 ) );
			}
			else
			{//look again in 2-5 secs
				TIMER_Set( NPC, "lookForNewEnemy", Q_irand( 2000, 5000 ) );
			}
		}
		Howler_Combat();
		if ( TIMER_Done( NPC, "speaking" ) )
		{
			if ( !TIMER_Done( NPC, "standing" )
				|| !TIMER_Done( NPC, "retreating" ))
			{
				G_SoundOnEnt( NPC, CHAN_VOICE, va( "sound/chars/howler/idle_hiss%d.mp3", Q_irand( 1, 2 ) ) );
			}
			else if ( !TIMER_Done( NPC, "walking" ) 
				|| NPCInfo->localState == LSTATE_FLEE )
			{
				G_SoundOnEnt( NPC, CHAN_VOICE, va( "sound/chars/howler/howl_talk%d.mp3", Q_irand( 1, 5 ) ) );
			}
			else
			{
				G_SoundOnEnt( NPC, CHAN_VOICE, va( "sound/chars/howler/howl_yell%d.mp3", Q_irand( 1, 5 ) ) );
			}
			if ( NPCInfo->localState == LSTATE_BERZERK
				|| NPCInfo->localState == LSTATE_FLEE )
			{
				TIMER_Set( NPC, "speaking", Q_irand( 1000, 4000 ) );
			}
			else
			{
				TIMER_Set( NPC, "speaking", Q_irand( 3000, 8000 ) );
			}
		}
		return;
	}
	else
	{
		if ( TIMER_Done( NPC, "speaking" ) )
		{
			if ( !Q_irand( 0, 3 ) )
			{
				G_SoundOnEnt( NPC, CHAN_VOICE, va( "sound/chars/howler/idle_hiss%d.mp3", Q_irand( 1, 2 ) ) );
			}
			else
			{
				G_SoundOnEnt( NPC, CHAN_VOICE, va( "sound/chars/howler/howl_talk%d.mp3", Q_irand( 1, 5 ) ) );
			}
			TIMER_Set( NPC, "speaking", Q_irand( 4000, 12000 ) );
		}
		if ( NPCInfo->stats.aggression > 0 )
		{
			if ( TIMER_Done( NPC, "aggressionDecay" ) )
			{
				NPCInfo->stats.aggression--;
				TIMER_Set( NPC, "aggressionDecay", 200 );
			}
		}
		if ( TIMER_Done( NPC, "standing" ) )
		{//not standing around
			if ( !(NPCInfo->last_ucmd.forwardmove)
				&& !(NPCInfo->last_ucmd.rightmove) )
			{//stood last frame
				if ( TIMER_Done( NPC, "walking" ) 
					&& TIMER_Done( NPC, "running" ) )
				{//not walking or running
					if ( NPCInfo->goalEntity )
					{//have somewhere to go
						if ( Q_irand( 0, 2 ) )
						{//walk for a while
							TIMER_Set( NPC, "walking", Q_irand( 3000, 10000 ) );
						}
						else
						{//run for a bit
							TIMER_Set( NPC, "running", Q_irand( 2500, 5000 ) );
						}
					}
				}
			}
			else if ( (NPCInfo->last_ucmd.buttons&BUTTON_WALKING) )
			{//walked last frame
				if ( TIMER_Done( NPC, "walking" ) )
				{//just finished walking
					if ( Q_irand( 0, 3 ) )
					{//run for a while
						TIMER_Set( NPC, "running", Q_irand( 3000, 6000 ) );
					}
					else
					{//stand for a bit
						TIMER_Set( NPC, "standing", Q_irand( 2500, 5000 ) );
					}
				}
			}
			else
			{//ran last frame
				if ( TIMER_Done( NPC, "running" ) )
				{//just finished running
					if ( Q_irand( 0, 2 ) )
					{//walk for a while
						TIMER_Set( NPC, "walking", Q_irand( 6000, 15000 ) );
					}
					else
					{//stand for a bit
						TIMER_Set( NPC, "standing", Q_irand( 4000, 6000 ) );
					}
				}
			}
		}
		if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
		{
			Howler_Patrol();
		}
		else
		{
			Howler_Idle();
		}
	}

	NPC_UpdateAngles( qfalse, qtrue );
}
int SV_FlyMove (edict_t *ent, float time, int mask)
{
	edict_t		*hit;
	int			bumpcount, numbumps;
	vec3_t		dir;
	float		d;
	int			numplanes;
	vec3_t		planes[MAX_CLIP_PLANES];
	vec3_t		primal_velocity, original_velocity, new_velocity;
	int			i, j;
	trace_t		trace;
	vec3_t		end;
	float		time_left;
	int			blocked;
	
	numbumps = 4;
	
	blocked = 0;
	VectorCopy (ent->velocity, original_velocity);
	VectorCopy (ent->velocity, primal_velocity);
	numplanes = 0;
	
	time_left = time;

	ent->groundentity = NULL;
	for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
	{
		for (i=0 ; i<3 ; i++)
			end[i] = ent->s.origin[i] + time_left * ent->velocity[i];

		trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask);

		if (trace.allsolid)
		{	// entity is trapped in another solid
			VectorCopy (vec3_origin, ent->velocity);
			return 3;
		}

		if (trace.fraction > 0)
		{	// actually covered some distance
			VectorCopy (trace.endpos, ent->s.origin);
			VectorCopy (ent->velocity, original_velocity);
			numplanes = 0;
		}

		if (trace.fraction == 1)
			 break;		// moved the entire distance

		hit = trace.ent;

		if (trace.plane.normal[2] > 0.7)
		{
			blocked |= 1;		// floor
			if ( hit->solid == SOLID_BSP)
			{
				ent->groundentity = hit;
				ent->groundentity_linkcount = hit->linkcount;
			}
		}
		if (!trace.plane.normal[2])
		{
			blocked |= 2;		// step
		}

//
// run the impact function
//
		SV_Impact (ent, &trace);
		if (!ent->inuse)
			break;		// removed by the impact function

		
		time_left -= time_left * trace.fraction;
		
	// cliped to another plane
		if (numplanes >= MAX_CLIP_PLANES)
		{	// this shouldn't really happen
			VectorCopy (vec3_origin, ent->velocity);
			return 3;
		}

		VectorCopy (trace.plane.normal, planes[numplanes]);
		numplanes++;

//
// modify original_velocity so it parallels all of the clip planes
//
		for (i=0 ; i<numplanes ; i++)
		{
			ClipVelocity (original_velocity, planes[i], new_velocity, 1);

			for (j=0 ; j<numplanes ; j++)
				if ((j != i) && !VectorCompare (planes[i], planes[j]))
				{
					if (DotProduct (new_velocity, planes[j]) < 0)
						break;	// not ok
				}
			if (j == numplanes)
				break;
		}
		
		if (i != numplanes)
		{	// go along this plane
			VectorCopy (new_velocity, ent->velocity);
		}
		else
		{	// go along the crease
			if (numplanes != 2)
			{
//				gi.dprintf ("clip velocity, numplanes == %i\n",numplanes);
				VectorCopy (vec3_origin, ent->velocity);
				return 7;
			}
			CrossProduct (planes[0], planes[1], dir);
			d = DotProduct (dir, ent->velocity);
			VectorScale (dir, d, ent->velocity);
		}

//
// if original velocity is against the original velocity, stop dead
// to avoid tiny occilations in sloping corners
//
		if (DotProduct (ent->velocity, primal_velocity) <= 0)
		{
			VectorCopy (vec3_origin, ent->velocity);
			return blocked;
		}
	}

	return blocked;
}
Beispiel #12
0
//------------------------------
static void Howler_Attack( float enemyDist, qboolean howl )
{
	int dmg = (NPCInfo->localState==LSTATE_BERZERK)?5:2;

	if ( !TIMER_Exists( NPC, "attacking" ))
	{
		int attackAnim = BOTH_GESTURE1;
		// Going to do an attack
		if ( NPC->enemy && NPC->enemy->client && PM_InKnockDown( &NPC->enemy->client->ps )
			&& enemyDist <= MIN_DISTANCE )
		{
			attackAnim = BOTH_ATTACK2;
		}
		else if ( !Q_irand( 0, 4 ) || howl )
		{//howl attack
			//G_SoundOnEnt( NPC, CHAN_VOICE, "sound/chars/howler/howl.mp3" );
		}
		else if ( enemyDist > MIN_DISTANCE && Q_irand( 0, 1 ) )
		{//lunge attack
			//jump foward
			vec3_t	fwd, yawAng = {0, NPC->client->ps.viewangles[YAW], 0};
			AngleVectors( yawAng, fwd, NULL, NULL );
			VectorScale( fwd, (enemyDist*3.0f), NPC->client->ps.velocity );
			NPC->client->ps.velocity[2] = 200;
			NPC->client->ps.groundEntityNum = ENTITYNUM_NONE;
			
			attackAnim = BOTH_ATTACK1;
		}
		else
		{//tongue attack
			attackAnim = BOTH_ATTACK2;
		}

		NPC_SetAnim( NPC, SETANIM_BOTH, attackAnim, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD | SETANIM_FLAG_RESTART );
		if ( NPCInfo->localState == LSTATE_BERZERK )
		{//attack again right away
			TIMER_Set( NPC, "attacking", NPC->client->ps.legsAnimTimer );
		}
		else
		{
			TIMER_Set( NPC, "attacking", NPC->client->ps.legsAnimTimer + Q_irand( 0, 1500 ) );//FIXME: base on skill
			TIMER_Set( NPC, "standing", -level.time );
			TIMER_Set( NPC, "walking", -level.time );
			TIMER_Set( NPC, "running", NPC->client->ps.legsAnimTimer + 5000 );
		}

		TIMER_Set( NPC, "attack_dmg", 200 ); // level two damage
	}

	// Need to do delayed damage since the attack animations encapsulate multiple mini-attacks
	switch ( NPC->client->ps.legsAnim )
	{
	case BOTH_ATTACK1:
	case BOTH_MELEE1:
		if ( NPC->client->ps.legsAnimTimer > 650//more than 13 frames left
			&& PM_AnimLength( NPC->client->clientInfo.animFileIndex, (animNumber_t)NPC->client->ps.legsAnim ) - NPC->client->ps.legsAnimTimer >= 800 )//at least 16 frames into anim
		{
			Howler_TryDamage( dmg, qfalse, qfalse );
		}
		break;
	case BOTH_ATTACK2:
	case BOTH_MELEE2:
		if ( NPC->client->ps.legsAnimTimer > 350//more than 7 frames left
			&& PM_AnimLength( NPC->client->clientInfo.animFileIndex, (animNumber_t)NPC->client->ps.legsAnim ) - NPC->client->ps.legsAnimTimer >= 550 )//at least 11 frames into anim
		{
			Howler_TryDamage( dmg, qtrue, qfalse );
		}
		break;
	case BOTH_GESTURE1:
		{
			if ( NPC->client->ps.legsAnimTimer > 1800//more than 36 frames left
				&& PM_AnimLength( NPC->client->clientInfo.animFileIndex, (animNumber_t)NPC->client->ps.legsAnim ) - NPC->client->ps.legsAnimTimer >= 950 )//at least 19 frames into anim
			{
				Howler_Howl();
				if ( !NPC->count )
				{
					G_PlayEffect( G_EffectIndex( "howler/sonic" ), NPC->playerModel, NPC->genericBolt1, NPC->s.number, NPC->currentOrigin, 4750, qtrue );
					G_SoundOnEnt( NPC, CHAN_VOICE, "sound/chars/howler/howl.mp3" );
					NPC->count = 1;
				}
			}
		}
		break;
	default:
		//anims seem to get reset after a load, so just stop attacking and it will restart as needed.
		TIMER_Remove( NPC, "attacking" );
		break;
	}

	// Just using this to remove the attacking flag at the right time
	TIMER_Done2( NPC, "attacking", qtrue );
}
Beispiel #13
0
/*
============
SV_FlyMove

The basic solid body movement clip that slides along multiple planes
*steptrace - if not NULL, the trace results of any vertical wall hit will be stored
Returns the clipflags if the velocity was modified (hit something solid)
1 = floor
2 = wall / step
4 = dead stop
============
*/
int SV_FlyMove( edict_t *ent, float time, trace_t *steptrace )
{
	int	i, j, numplanes, bumpcount, blocked;
	vec3_t	dir, end, planes[MAX_CLIP_PLANES];
	vec3_t	primal_velocity, original_velocity, new_velocity;
	float	d, time_left, allFraction;
	trace_t	trace;

	blocked = 0;
	VectorCopy( ent->v.velocity, original_velocity );
	VectorCopy( ent->v.velocity, primal_velocity );
	numplanes = 0;

	allFraction = 0.0f;
	time_left = time;

	for( bumpcount = 0; bumpcount < MAX_CLIP_PLANES - 1; bumpcount++ )
	{
		if( VectorIsNull( ent->v.velocity ))
			break;

		VectorMA( ent->v.origin, time_left, ent->v.velocity, end );
		trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent );

		allFraction += trace.fraction;

		if( trace.allsolid )
		{	
			// entity is trapped in another solid
			VectorClear( ent->v.velocity );
			return 4;
		}

		if( trace.fraction > 0.0f )
		{	
			// actually covered some distance
			VectorCopy( trace.endpos, ent->v.origin );
			VectorCopy( ent->v.velocity, original_velocity );
			numplanes = 0;
		}

		if( trace.fraction == 1.0f )
			 break; // moved the entire distance

		if( !trace.ent )
			MsgDev( D_ERROR, "SV_FlyMove: trace.ent == NULL\n" );

		if( trace.plane.normal[2] > 0.7f )
		{
			blocked |= 1; // floor

         			if( trace.ent->v.solid == SOLID_BSP || trace.ent->v.solid == SOLID_SLIDEBOX ||
			trace.ent->v.movetype == MOVETYPE_PUSHSTEP || (trace.ent->v.flags & FL_CLIENT))
			{
				ent->v.flags |= FL_ONGROUND;
				ent->v.groundentity = trace.ent;
			}
		}

		if( trace.plane.normal[2] == 0.0f )
		{
			blocked |= 2; // step
			if( steptrace ) *steptrace = trace; // save for player extrafriction
		}

		// run the impact function
		SV_Impact( ent, trace.ent, &trace );

		// break if removed by the impact function
		if( ent->free ) break;

		time_left -= time_left * trace.fraction;

		// clipped to another plane
		if( numplanes >= MAX_CLIP_PLANES )
		{
			// this shouldn't really happen
			VectorClear( ent->v.velocity );
			break;
		}

		VectorCopy( trace.plane.normal, planes[numplanes] );
		numplanes++;

		// modify original_velocity so it parallels all of the clip planes
		for( i = 0; i < numplanes; i++ )
		{
			SV_ClipVelocity( original_velocity, planes[i], new_velocity, 1.0f );

			for( j = 0; j < numplanes; j++ )
			{
				if( j != i )
				{
					if( DotProduct( new_velocity, planes[j] ) < 0.0f )
						break; // not ok
				}
			}

			if( j == numplanes )
				break;
		}

		if( i != numplanes )
		{
			// go along this plane
			VectorCopy( new_velocity, ent->v.velocity );
		}
		else
		{
			// go along the crease
			if( numplanes != 2 )
			{
				VectorClear( ent->v.velocity );
				break;
			}

			CrossProduct( planes[0], planes[1], dir );
			d = DotProduct( dir, ent->v.velocity );
			VectorScale( dir, d, ent->v.velocity );
		}

		// if current velocity is against the original velocity,
		// stop dead to avoid tiny occilations in sloping corners
		if( DotProduct( ent->v.velocity, primal_velocity ) <= 0.0f )
		{
			VectorClear( ent->v.velocity );
			break;
		}
	}

	if( allFraction == 0.0f )
		VectorClear( ent->v.velocity );

	return blocked;
}
Beispiel #14
0
/*
=============
SV_Physics_Toss

Toss, bounce, and fly movement.  When onground, do nothing.
=============
*/
void SV_Physics_Toss( edict_t *ent )
{
	trace_t	trace;
	vec3_t	move;
	float	backoff;
	edict_t	*ground;

	SV_CheckWater( ent );

	// regular thinking
	if( !SV_RunThink( ent )) return;

	ground = ent->v.groundentity;

	if( ent->v.velocity[2] > 0.0f || !SV_IsValidEdict( ground ) || ground->v.flags & (FL_MONSTER|FL_CLIENT) || svgame.globals->changelevel )
	{
		ent->v.flags &= ~FL_ONGROUND;
          }

	// if on ground and not moving, return.
	if( ent->v.flags & FL_ONGROUND && VectorIsNull( ent->v.velocity ))
	{
		VectorClear( ent->v.avelocity );

		if( VectorIsNull( ent->v.basevelocity ))
			return;	// at rest
	}

	SV_CheckVelocity( ent );

	// add gravity
	switch( ent->v.movetype )
	{
	case MOVETYPE_FLY:
	case MOVETYPE_FLYMISSILE:
	case MOVETYPE_BOUNCEMISSILE:
		break;
	default:
		SV_AddGravity( ent );
		break;
	}

	// move angles (with friction)
	switch( ent->v.movetype )
	{
	case MOVETYPE_TOSS:
	case MOVETYPE_BOUNCE:
		SV_AngularMove( ent, host.frametime, ent->v.friction );
		break;         
	default:
		SV_AngularMove( ent, host.frametime, 0.0f );
		break;
	}

	// move origin
	// Base velocity is not properly accounted for since this entity will move again
	// after the bounce without taking it into account
	VectorAdd( ent->v.velocity, ent->v.basevelocity, ent->v.velocity );

	SV_CheckVelocity( ent );
	VectorScale( ent->v.velocity, host.frametime, move );

	VectorSubtract( ent->v.velocity, ent->v.basevelocity, ent->v.velocity );

	trace = SV_PushEntity( ent, move, vec3_origin, NULL );
	if( ent->free ) return;

	SV_CheckVelocity( ent );

	if( trace.allsolid )
	{
		// entity is trapped in another solid
		VectorClear( ent->v.avelocity );
		VectorClear( ent->v.velocity );
		return;
	}

	if( trace.fraction == 1.0f )
	{
		SV_CheckWaterTransition( ent );
		return;
	}

	if( ent->v.movetype == MOVETYPE_BOUNCE )
		backoff = 2.0f - ent->v.friction;
	else if( ent->v.movetype == MOVETYPE_BOUNCEMISSILE )
		backoff = 2.0f;
	else backoff = 1.0f;

	SV_ClipVelocity( ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff );

	// stop if on ground
	if( trace.plane.normal[2] > 0.7f )
	{		
		float	vel;

		VectorAdd( ent->v.velocity, ent->v.basevelocity, move );
		vel = DotProduct( move, move );

		if( ent->v.velocity[2] < sv_gravity->value * host.frametime )
		{
			// we're rolling on the ground, add static friction.
			ent->v.groundentity = trace.ent;
			ent->v.flags |= FL_ONGROUND;
			ent->v.velocity[2] = 0.0f;
		}

		if( vel < 900.0f || ( ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE ))
		{
			ent->v.flags |= FL_ONGROUND;
			ent->v.groundentity = trace.ent;
			VectorClear( ent->v.avelocity );
			VectorClear( ent->v.velocity );
		}
		else
		{
			VectorScale( ent->v.velocity, (1.0f - trace.fraction) * host.frametime * 0.9f, move );
			VectorMA( move, (1.0f - trace.fraction) * host.frametime * 0.9f, ent->v.basevelocity, move );
			trace = SV_PushEntity( ent, move, vec3_origin, NULL );
			if( ent->free ) return;
		}
	}
	
	// check for in water
	SV_CheckWaterTransition( ent );
}
Beispiel #15
0
/*
=================
BaseWindingForPlane
=================
*/
winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist)
{
	int		i, x;
	vec_t	max, v;
	vec3_t	org, vright, vup;
	winding_t	*w;
	
// find the major axis

	max = -BOGUS_RANGE;
	x = -1;
	for (i=0 ; i<3; i++)
	{
		v = fabs(normal[i]);
		if (v > max)
		{
			x = i;
			max = v;
		}
	}
	if (x==-1)
		Error ("BaseWindingForPlane: no axis found");
		
	VectorCopy (vec3_origin, vup);	
	switch (x)
	{
	case 0:
	case 1:
		vup[2] = 1;
		break;		
	case 2:
		vup[0] = 1;
		break;		
	}

	v = DotProduct (vup, normal);
	VectorMA (vup, -v, normal, vup);
	VectorNormalize (vup, vup);
		
	VectorScale (normal, dist, org);
	
	CrossProduct (vup, normal, vright);
	
	VectorScale (vup, 8192, vup);
	VectorScale (vright, 8192, vright);

// project a really big	axis aligned box onto the plane
	w = AllocWinding (4);
	
	VectorSubtract (org, vright, w->p[0]);
	VectorAdd (w->p[0], vup, w->p[0]);
	
	VectorAdd (org, vright, w->p[1]);
	VectorAdd (w->p[1], vup, w->p[1]);
	
	VectorAdd (org, vright, w->p[2]);
	VectorSubtract (w->p[2], vup, w->p[2]);
	
	VectorSubtract (org, vright, w->p[3]);
	VectorSubtract (w->p[3], vup, w->p[3]);
	
	w->numpoints = 4;
	
	return w;	
}
Beispiel #16
0
void T_Damage(edict_t * targ, edict_t * inflictor, edict_t * attacker,
	      vec3_t dir, vec3_t point, vec3_t normal, int damage,
	      int knockback, int dflags, int mod)
{
	gclient_t *client;
	int take;
	int save;
	int asave;
	int psave;
	int te_sparks;

	if (!targ->takedamage)
		return;

	// friendly fire avoidance
	// if enabled you can't hurt teammates (but you can hurt yourself)
	// knockback still occurs
	if ((targ != attacker)
	    &&
	    ((deathmatch->value
	      && ((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS)))
	     || coop->value)) {
		if (OnSameTeam(targ, attacker)) {
			if ((int)(dmflags->value) & DF_NO_FRIENDLY_FIRE)
				damage = 0;
			else
				mod |= MOD_FRIENDLY_FIRE;
		}
	}
	meansOfDeath = mod;

	// easy mode takes half damage
	if (skill->value == 0 && deathmatch->value == 0 && targ->client) {
		damage *= 0.5;
		if (!damage)
			damage = 1;
	}

	client = targ->client;

	if (dflags & DAMAGE_BULLET)
		te_sparks = TE_BULLET_SPARKS;
	else
		te_sparks = TE_SPARKS;

	VectorNormalize(dir);

// bonus damage for suprising a monster
	if (!(dflags & DAMAGE_RADIUS) && (targ->svflags & SVF_MONSTER)
	    && (attacker->client) && (!targ->enemy) && (targ->health > 0))
		damage *= 2;

	if (targ->flags & FL_NO_KNOCKBACK)
		knockback = 0;

// figure momentum add
	if (!(dflags & DAMAGE_NO_KNOCKBACK)) {
		if ((knockback) && (targ->movetype != MOVETYPE_NONE)
		    && (targ->movetype != MOVETYPE_BOUNCE)
		    && (targ->movetype != MOVETYPE_PUSH)
		    && (targ->movetype != MOVETYPE_STOP)) {
			vec3_t kvel;
			float mass;

			if (targ->mass < 50)
				mass = 50;
			else
				mass = targ->mass;

			if (targ->client && attacker == targ)
				VectorScale(dir, 1600.0 * (float)knockback / mass, kvel);	// the rocket jump hack...
			else
				VectorScale(dir,
					    500.0 * (float)knockback / mass,
					    kvel);

			VectorAdd(targ->velocity, kvel, targ->velocity);
		}
	}

	take = damage;
	save = 0;

	// check for godmode
	if ((targ->flags & FL_GODMODE) && !(dflags & DAMAGE_NO_PROTECTION)) {
		take = 0;
		save = damage;
		SpawnDamage(te_sparks, point, normal, save);
	}
	// check for invincibility
	if ((client && client->invincible_framenum > level.framenum)
	    && !(dflags & DAMAGE_NO_PROTECTION)) {
		if (targ->pain_debounce_time < level.time) {
			gi.sound(targ, CHAN_ITEM,
				 gi.soundindex("items/protect4.wav"), 1,
				 ATTN_NORM, 0);
			targ->pain_debounce_time = level.time + 2;
		}
		take = 0;
		save = damage;
	}

	psave = CheckPowerArmor(targ, point, normal, take, dflags);
	take -= psave;

	asave = CheckArmor(targ, point, normal, take, te_sparks, dflags);
	take -= asave;

	//treat cheat/powerup savings the same as armor
	asave += save;

	// team damage avoidance
	if (!(dflags & DAMAGE_NO_PROTECTION) && CheckTeamDamage(targ, attacker))
		return;

// do the damage
	if (take) {
		if ((targ->svflags & SVF_MONSTER) || (client))
			SpawnDamage(TE_BLOOD, point, normal, take);
		else
			SpawnDamage(te_sparks, point, normal, take);

		targ->health = targ->health - take;

		if (targ->health <= 0) {
			if ((targ->svflags & SVF_MONSTER) || (client))
				targ->flags |= FL_NO_KNOCKBACK;
			Killed(targ, inflictor, attacker, take, point);
			return;
		}
	}

	if (targ->svflags & SVF_MONSTER) {
		M_ReactToDamage(targ, attacker);
		if (!(targ->monsterinfo.aiflags & AI_DUCKED) && (take)) {
			targ->pain(targ, attacker, knockback, take);
			// nightmare mode monsters don't go into pain frames often
			if (skill->value == 3)
				targ->pain_debounce_time = level.time + 5;
		}
	} else if (client) {
		if (!(targ->flags & FL_GODMODE) && (take))
			targ->pain(targ, attacker, knockback, take);
	} else if (take) {
		if (targ->pain)
			targ->pain(targ, attacker, knockback, take);
	}
	// add to the damage inflicted on a player this frame
	// the total will be turned into screen blends and view angle kicks
	// at the end of the frame
	if (client) {
		client->damage_parmor += psave;
		client->damage_armor += asave;
		client->damage_blood += take;
		client->damage_knockback += knockback;
		VectorCopy(point, client->damage_from);
	}
}
Beispiel #17
0
void G_RollMissile( gentity_t *ent )
{
	int			bumpcount, numbumps;
	vec3_t		dir;
	float		d;
	int			numplanes;
	vec3_t		planes[MAX_CLIP_PLANES];
	vec3_t		primal_velocity;
	vec3_t		clipVelocity;
	int			i, j, k;
	trace_t	trace;
	vec3_t		end;
	float		time_left;
	float		into;
	vec3_t		endVelocity;
	vec3_t		endClipVelocity;
	pml_t		objPML;
	float		bounceAmt = BUMPCLIP;
	gentity_t	*hitEnt = NULL;

	memset( &objPML, 0, sizeof( objPML ) );
	
	G_GroundTrace( ent, &objPML );

	objPML.frametime = (level.time - level.previousTime)*0.001;
	
	numbumps = 4;

	VectorCopy ( ent->s.pos.trDelta, primal_velocity );

	VectorCopy( ent->s.pos.trDelta, endVelocity );
	endVelocity[2] -= g_gravity->value * objPML.frametime;
	ent->s.pos.trDelta[2] = ( ent->s.pos.trDelta[2] + endVelocity[2] ) * 0.5;
	primal_velocity[2] = endVelocity[2];
	if ( objPML.groundPlane ) 
	{//FIXME: never happens!
		// slide along the ground plane
		G_ClipVelocity( ent->s.pos.trDelta, objPML.groundTrace.plane.normal, ent->s.pos.trDelta, BUMPCLIP ); 
		VectorScale( ent->s.pos.trDelta, 0.9f, ent->s.pos.trDelta );
	}

	time_left = objPML.frametime;

	// never turn against the ground plane
	if ( objPML.groundPlane ) 
	{
		numplanes = 1;
		VectorCopy( objPML.groundTrace.plane.normal, planes[0] );
	} 
	else 
	{
		numplanes = 0;
	}

	// never turn against original velocity
	/*
	VectorNormalize2( ent->s.pos.trDelta, planes[numplanes] );
	numplanes++;
	*/

	for ( bumpcount = 0; bumpcount < numbumps; bumpcount++ ) 
	{
		// calculate position we are trying to move to
		VectorMA( ent->currentOrigin, time_left, ent->s.pos.trDelta, end );

		// see if we can make it there
		gi.trace ( &trace, ent->currentOrigin, ent->mins, ent->maxs, end, ent->s.number, ent->clipmask, G2_RETURNONHIT, 10 );

		//TEMP HACK:
		//had to move this up above the trace.allsolid check now that for some reason ghoul2 impacts tell me I'm allsolid?!
		//this needs to be fixed, really
		if ( trace.entityNum < ENTITYNUM_WORLD )
		{//hit another ent
			hitEnt = &g_entities[trace.entityNum];
			if ( hitEnt && (hitEnt->takedamage || (hitEnt->contents&CONTENTS_LIGHTSABER) ) )
			{
				G_MissileImpact( ent, &trace );
				if ( ent->s.eType == ET_GENERAL )
				{//exploded
					return;
				}
			}
		}

		if ( trace.allsolid )
		{
			// entity is completely trapped in another solid
			//FIXME: this happens a lot now when we hit a G2 ent... WTF?
			ent->s.pos.trDelta[2] = 0;	// don't build up falling damage, but allow sideways acceleration
			return;// qtrue;
		}

		if ( trace.fraction > 0 ) 
		{
			// actually covered some distance
			VectorCopy( trace.endpos, ent->currentOrigin );
		}

		if ( trace.fraction == 1 ) 
		{
			 break;		// moved the entire distance
		}

		//pm->ps->pm_flags |= PMF_BUMPED;

		// save entity for contact
		//PM_AddTouchEnt( trace.entityNum );

		//Hit it
		/*
		if ( PM_ClientImpact( trace.entityNum, qtrue ) )
		{
			continue;
		}
		*/

		time_left -= time_left * trace.fraction;

		if ( numplanes >= MAX_CLIP_PLANES ) 
		{
			// this shouldn't really happen
			VectorClear( ent->s.pos.trDelta );
			return;// qtrue;
		}

		//
		// if this is the same plane we hit before, nudge velocity
		// out along it, which fixes some epsilon issues with
		// non-axial planes
		//
		for ( i = 0 ; i < numplanes ; i++ ) 
		{
			if ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) 
			{
				VectorAdd( trace.plane.normal, ent->s.pos.trDelta, ent->s.pos.trDelta );
				break;
			}
		}
		if ( i < numplanes ) 
		{
			continue;
		}
		VectorCopy( trace.plane.normal, planes[numplanes] );
		numplanes++;

		//
		// modify velocity so it parallels all of the clip planes
		//
		if ( &g_entities[trace.entityNum] != NULL && g_entities[trace.entityNum].client ) 
		{//hit a person, bounce off much less
			bounceAmt = OVERCLIP;
		}
		else
		{
			bounceAmt = BUMPCLIP;
		}

		// find a plane that it enters
		for ( i = 0 ; i < numplanes ; i++ ) 
		{
			into = DotProduct( ent->s.pos.trDelta, planes[i] );
			if ( into >= 0.1 ) 
			{
				continue;		// move doesn't interact with the plane
			}

			// see how hard we are hitting things
			if ( -into > pml.impactSpeed ) 
			{
				pml.impactSpeed = -into;
			}

			// slide along the plane
			G_ClipVelocity( ent->s.pos.trDelta, planes[i], clipVelocity, bounceAmt );

			// slide along the plane
			G_ClipVelocity( endVelocity, planes[i], endClipVelocity, bounceAmt );

			// see if there is a second plane that the new move enters
			for ( j = 0 ; j < numplanes ; j++ ) 
			{
				if ( j == i ) 
				{
					continue;
				}
				if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) 
				{
					continue;		// move doesn't interact with the plane
				}

				// try clipping the move to the plane
				G_ClipVelocity( clipVelocity, planes[j], clipVelocity, bounceAmt );
				G_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, bounceAmt );

				// see if it goes back into the first clip plane
				if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) 
				{
					continue;
				}

				// slide the original velocity along the crease
				CrossProduct (planes[i], planes[j], dir);
				VectorNormalize( dir );
				d = DotProduct( dir, ent->s.pos.trDelta );
				VectorScale( dir, d, clipVelocity );

				CrossProduct (planes[i], planes[j], dir);
				VectorNormalize( dir );
				d = DotProduct( dir, endVelocity );
				VectorScale( dir, d, endClipVelocity );

				// see if there is a third plane the the new move enters
				for ( k = 0 ; k < numplanes ; k++ ) 
				{
					if ( k == i || k == j ) 
					{
						continue;
					}
					if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) 
					{
						continue;		// move doesn't interact with the plane
					}

					// stop dead at a triple plane interaction
					VectorClear( ent->s.pos.trDelta );
					return;// qtrue;
				}
			}

			// if we have fixed all interactions, try another move
			VectorCopy( clipVelocity, ent->s.pos.trDelta );
			VectorCopy( endClipVelocity, endVelocity );
			break;
		}
		VectorScale( endVelocity, 0.975f, endVelocity );
	}

	VectorCopy( endVelocity, ent->s.pos.trDelta );

	// don't change velocity if in a timer (FIXME: is this correct?)
	/*
	if ( pm->ps->pm_time ) 
	{
		VectorCopy( primal_velocity, ent->s.pos.trDelta );
	}
	*/

	return;// ( bumpcount != 0 );
}
Beispiel #18
0
static void CG_RainParticleRender( cg_atmosphericParticle_t *particle ) {
	// Draw a raindrop

	vec3_t forward, right;
	polyVert_t verts[3];
	vec2_t line;
	float len, dist;
	vec3_t start, finish;
	float groundHeight;
//	int			msec = trap_Milliseconds();

//	n_rendertime++;

	if ( particle->active == ACT_NOT ) {
//		rendertime += trap_Milliseconds() - msec;
		return;
	}

	if ( CG_CullPoint( particle->pos ) ) {
		return;
	}

	VectorCopy( particle->pos, start );

	dist = DistanceSquared( particle->pos, cg.refdef.vieworg );

	// Make sure it doesn't clip through surfaces
	groundHeight = BG_GetSkyGroundHeightAtPoint( start );
	len = particle->height;
	if ( start[2] <= groundHeight ) {
		// Stop snow going through surfaces.
		len = particle->height - groundHeight + start[2];
		VectorMA( start, len - particle->height, particle->deltaNormalized, start );
	}

	if ( len <= 0 ) {
//		rendertime += trap_Milliseconds() - msec;
		return;
	}

	// fade nearby rain particles
	if ( dist < Square( 128.f ) ) {
		dist = .25f + .75f * ( dist / Square( 128.f ) );
	} else {
		dist = 1.0f;
	}

	VectorCopy( particle->deltaNormalized, forward );
	VectorMA( start, -len, forward, finish );

	line[0] = DotProduct( forward, cg.refdef.viewaxis[1] );
	line[1] = DotProduct( forward, cg.refdef.viewaxis[2] );

	VectorScale( cg.refdef.viewaxis[1], line[1], right );
	VectorMA( right, -line[0], cg.refdef.viewaxis[2], right );
	VectorNormalize( right );

	// dist = 1.0;

	VectorCopy( finish, verts[0].xyz );
	verts[0].st[0] = 0.5f;
	verts[0].st[1] = 0;
	verts[0].modulate[0] = particle->colour[0];
	verts[0].modulate[1] = particle->colour[1];
	verts[0].modulate[2] = particle->colour[2];
	verts[0].modulate[3] = 100 * dist;

	VectorMA( start, -particle->weight, right, verts[1].xyz );
	verts[1].st[0] = 0;
	verts[1].st[1] = 1;
	verts[1].modulate[0] = particle->colour[0];
	verts[1].modulate[1] = particle->colour[1];
	verts[2].modulate[2] = particle->colour[2];
	verts[1].modulate[3] = 200 * dist;

	VectorMA( start, particle->weight, right, verts[2].xyz );
	verts[2].st[0] = 1;
	verts[2].st[1] = 1;
	verts[2].modulate[0] = particle->colour[0];
	verts[2].modulate[1] = particle->colour[1];
	verts[2].modulate[2] = particle->colour[2];
	verts[2].modulate[3] = 200 * dist;

	CG_AddPolyToPool( *particle->effectshader, verts );

//	rendertime += trap_Milliseconds() - msec;
}
Beispiel #19
0
void G_ReflectMissile( gentity_t *ent, gentity_t *missile, vec3_t forward ) 
{
	vec3_t	bounce_dir;
	int		i;
	float	speed;
	qboolean reflected = qfalse;
	gentity_t	*owner = ent;

	if ( ent->owner )
	{
		owner = ent->owner;
	}

	//save the original speed
	speed = VectorNormalize( missile->s.pos.trDelta );

	if ( ent && owner && owner->client && !owner->client->ps.saberInFlight && 
		(owner->client->ps.forcePowerLevel[FP_SABER_DEFENSE] > FORCE_LEVEL_2 || (owner->client->ps.forcePowerLevel[FP_SABER_DEFENSE]>FORCE_LEVEL_1&&!Q_irand( 0, 3 )) ) )
	{//if high enough defense skill and saber in-hand (100% at level 3, 25% at level 2, 0% at level 1), reflections are perfectly deflected toward an enemy
		gentity_t *enemy;
		if ( owner->enemy && Q_irand( 0, 3 ) )
		{//toward current enemy 75% of the time
			enemy = owner->enemy;
		}
		else
		{//find another enemy
			enemy = Jedi_FindEnemyInCone( owner, owner->enemy, 0.3f );
		}
		if ( enemy )
		{
			vec3_t	bullseye;
			CalcEntitySpot( enemy, SPOT_HEAD, bullseye );
			bullseye[0] += Q_irand( -4, 4 );
			bullseye[1] += Q_irand( -4, 4 );
			bullseye[2] += Q_irand( -16, 4 );
			VectorSubtract( bullseye, missile->currentOrigin, bounce_dir );
			VectorNormalize( bounce_dir );
			if ( !PM_SaberInParry( owner->client->ps.saberMove ) 
				&& !PM_SaberInReflect( owner->client->ps.saberMove ) 
				&& !PM_SaberInIdle( owner->client->ps.saberMove ) )
			{//a bit more wild
				if ( PM_SaberInAttack( owner->client->ps.saberMove )
					|| PM_SaberInTransitionAny( owner->client->ps.saberMove )
					|| PM_SaberInSpecialAttack( owner->client->ps.torsoAnim ) )
				{//moderately more wild
					for ( i = 0; i < 3; i++ )
					{
						bounce_dir[i] += Q_flrand( -0.2f, 0.2f );
					}
				}
				else
				{//mildly more wild
					for ( i = 0; i < 3; i++ )
					{
						bounce_dir[i] += Q_flrand( -0.1f, 0.1f );
					}
				}
			}
			VectorNormalize( bounce_dir );
			reflected = qtrue;
		}
	}
	if ( !reflected )
	{
		if ( missile->owner && missile->s.weapon != WP_SABER )
		{//bounce back at them if you can
			VectorSubtract( missile->owner->currentOrigin, missile->currentOrigin, bounce_dir );
			VectorNormalize( bounce_dir );
		}
		else
		{
			vec3_t missile_dir;

			VectorSubtract( ent->currentOrigin, missile->currentOrigin, missile_dir );
			VectorCopy( missile->s.pos.trDelta, bounce_dir );
			VectorScale( bounce_dir, DotProduct( forward, missile_dir ), bounce_dir );
			VectorNormalize( bounce_dir );
		}
		if ( owner->s.weapon == WP_SABER && owner->client )
		{//saber
			if ( owner->client->ps.saberInFlight )
			{//reflecting off a thrown saber is totally wild
				for ( i = 0; i < 3; i++ )
				{
					bounce_dir[i] += Q_flrand( -0.8f, 0.8f );
				}
			}
			else if ( owner->client->ps.forcePowerLevel[FP_SABER_DEFENSE] <= FORCE_LEVEL_1 )
			{// at level 1
				for ( i = 0; i < 3; i++ )
				{
					bounce_dir[i] += Q_flrand( -0.4f, 0.4f );
				}
			}
			else
			{// at level 2
				for ( i = 0; i < 3; i++ )
				{
					bounce_dir[i] += Q_flrand( -0.2f, 0.2f );
				}
			}
			if ( !PM_SaberInParry( owner->client->ps.saberMove ) 
				&& !PM_SaberInReflect( owner->client->ps.saberMove ) 
				&& !PM_SaberInIdle( owner->client->ps.saberMove ) )
			{//a bit more wild
				if ( PM_SaberInAttack( owner->client->ps.saberMove )
					|| PM_SaberInTransitionAny( owner->client->ps.saberMove )
					|| PM_SaberInSpecialAttack( owner->client->ps.torsoAnim ) )
				{//really wild
					for ( i = 0; i < 3; i++ )
					{
						bounce_dir[i] += Q_flrand( -0.3f, 0.3f );
					}
				}
				else
				{//mildly more wild
					for ( i = 0; i < 3; i++ )
					{
						bounce_dir[i] += Q_flrand( -0.1f, 0.1f );
					}
				}
			}
		}
		else
		{//some other kind of reflection
			for ( i = 0; i < 3; i++ )
			{
				bounce_dir[i] += Q_flrand( -0.2f, 0.2f );
			}
		}
	}
	VectorNormalize( bounce_dir );
	VectorScale( bounce_dir, speed, missile->s.pos.trDelta );
#ifdef _DEBUG
		assert( !_isnan(missile->s.pos.trDelta[0])&&!_isnan(missile->s.pos.trDelta[1])&&!_isnan(missile->s.pos.trDelta[2]));
#endif// _DEBUG
	missile->s.pos.trTime = level.time - 10;		// move a bit on the very first frame
	VectorCopy( missile->currentOrigin, missile->s.pos.trBase );
	if ( missile->s.weapon != WP_SABER )
	{//you are mine, now!
		if ( !missile->lastEnemy )
		{//remember who originally shot this missile
			missile->lastEnemy = missile->owner;
		}
		missile->owner = owner;
	}
	if ( missile->s.weapon == WP_ROCKET_LAUNCHER )
	{//stop homing
		missile->e_ThinkFunc = thinkF_NULL;
	}
}
Beispiel #20
0
static void CG_SnowParticleRender( cg_atmosphericParticle_t *particle ) {
	// Draw a snowflake

	vec3_t forward, right;
	polyVert_t verts[3];
	vec2_t line;
	float len, sinTumbling, cosTumbling, particleWidth, dist;
	vec3_t start, finish;
	float groundHeight;
//	int			msec = trap_Milliseconds();

//	n_rendertime++;

	if ( particle->active == ACT_NOT ) {
//		rendertime += trap_Milliseconds() - msec;
		return;
	}

	if ( CG_CullPoint( particle->pos ) ) {
		return;
	}

	VectorCopy( particle->pos, start );

	sinTumbling = sin( particle->pos[2] * 0.03125f * ( 0.5f * particle->weight ) );
	cosTumbling = cos( ( particle->pos[2] + particle->pos[1] ) * 0.03125f * ( 0.5f * particle->weight ) );
	start[0] += 24 * ( 1 - particle->deltaNormalized[2] ) * sinTumbling;
	start[1] += 24 * ( 1 - particle->deltaNormalized[2] ) * cosTumbling;

	// Make sure it doesn't clip through surfaces
	groundHeight = BG_GetSkyGroundHeightAtPoint( start );
	len = particle->height;
	if ( start[2] <= groundHeight ) {
		// Stop snow going through surfaces.
		len = particle->height - groundHeight + start[2];
		VectorMA( start, len - particle->height, particle->deltaNormalized, start );
	}

	if ( len <= 0 ) {
//		rendertime += trap_Milliseconds() - msec;
		return;
	}

	line[0] = particle->pos[0] - cg.refdef.vieworg[0];
	line[1] = particle->pos[1] - cg.refdef.vieworg[1];

	dist = DistanceSquared( particle->pos, cg.refdef.vieworg );
	// dist becomes scale
	if ( dist > Square( 500.f ) ) {
		dist = 1.f + ( ( dist - Square( 500.f ) ) * ( 10.f / Square( 2000.f ) ) );
	} else {
		dist = 1.f;
	}

	len *= dist;

	VectorCopy( particle->deltaNormalized, forward );
	VectorMA( start, -( len /** sinTumbling*/ ), forward, finish );

	line[0] = DotProduct( forward, cg.refdef.viewaxis[1] );
	line[1] = DotProduct( forward, cg.refdef.viewaxis[2] );

	VectorScale( cg.refdef.viewaxis[1], line[1], right );
	VectorMA( right, -line[0], cg.refdef.viewaxis[2], right );
	VectorNormalize( right );

	particleWidth = dist * ( /*cosTumbling **/ particle->weight );

	VectorMA( finish, -particleWidth, right, verts[0].xyz );
	verts[0].st[0] = 0;
	verts[0].st[1] = 0;
	verts[0].modulate[0] = 255;
	verts[0].modulate[1] = 255;
	verts[0].modulate[2] = 255;
	verts[0].modulate[3] = 255;

	VectorMA( start, -particleWidth, right, verts[1].xyz );
	verts[1].st[0] = 0;
	verts[1].st[1] = 1;
	verts[1].modulate[0] = 255;
	verts[1].modulate[1] = 255;
	verts[1].modulate[2] = 255;
	verts[1].modulate[3] = 255;

	VectorMA( start, particleWidth, right, verts[2].xyz );
	verts[2].st[0] = 1;
	verts[2].st[1] = 1;
	verts[2].modulate[0] = 255;
	verts[2].modulate[1] = 255;
	verts[2].modulate[2] = 255;
	verts[2].modulate[3] = 255;

	CG_AddPolyToPool( *particle->effectshader, verts );

//	rendertime += trap_Milliseconds() - msec;
}
Beispiel #21
0
/*
RE_ProjectDecal()
    creates a new decal projector from a triangle
    projected polygons should be 3 or 4 points
    if a single point is passed in (numPoints == 1) then the decal will be omnidirectional
    omnidirectional decals use points[ 0 ] as center and projection[ 3 ] as radius
    pass in lifeTime < 0 for a temporary mark
*/
void RE_ProjectDecal(qhandle_t hShader, int numPoints, vec3_t *points, vec4_t projection, vec4_t color, int lifeTime, int fadeTime)
{
	static int       totalProjectors = 0;
	int              i;
	float            radius, iDist;
	vec3_t           xyz;
	decalVert_t      dv[4];
	decalProjector_t *dp, temp;

	if (r_numDecalProjectors >= MAX_DECAL_PROJECTORS)
	{
		ri.Printf(PRINT_WARNING, "WARNING: RE_ProjectDecal() Max decal projectors reached (%d)\n", MAX_DECAL_PROJECTORS);
		return;
	}

	/* dummy check */
	if (numPoints != 1 && numPoints != 3 && numPoints != 4)
	{
		ri.Printf(PRINT_WARNING, "WARNING: Invalid number of decal points (%d)\n", numPoints);
		return;
	}

	/* early outs */
	if (lifeTime == 0)
	{
		return;
	}
	if (projection[3] <= 0.0f)
	{
		return;
	}

	/* set times properly */
	if (lifeTime < 0 || fadeTime < 0)
	{
		lifeTime = 0;
		fadeTime = 0;
	}

	/* basic setup */
	temp.shader        = R_GetShaderByHandle(hShader);
	temp.color[0]      = color[0] * 255;
	temp.color[1]      = color[1] * 255;
	temp.color[2]      = color[2] * 255;
	temp.color[3]      = color[3] * 255;
	temp.numPlanes     = numPoints + 2;
	temp.fadeStartTime = tr.refdef.time + lifeTime - fadeTime; /* fixme: stale refdef time */
	temp.fadeEndTime   = temp.fadeStartTime + fadeTime;

	/* set up decal texcoords (fixme: support arbitrary projector st coordinates in trapcall) */
	dv[0].st[0] = 0.0f;
	dv[0].st[1] = 0.0f;
	dv[1].st[0] = 0.0f;
	dv[1].st[1] = 1.0f;
	dv[2].st[0] = 1.0f;
	dv[2].st[1] = 1.0f;
	dv[3].st[0] = 1.0f;
	dv[3].st[1] = 0.0f;

	/* omnidirectional? */
	if (numPoints == 1)
	{
		/* set up omnidirectional */
		numPoints            = 4;
		temp.numPlanes       = 6;
		temp.omnidirectional = qtrue;
		radius               = projection[3];

		Vector4Set(projection, 0.0f, 0.0f, -1.0f, radius * 2.0f);
		iDist = 1.0f / (radius * 2.0f);

		/* set corner */
		VectorSet(xyz, points[0][0] - radius, points[0][1] - radius, points[0][2] + radius);

		/* make x axis texture matrix (yz) */
		VectorSet(temp.texMat[0][0], 0.0f, iDist, 0.0f);
		temp.texMat[0][0][3] = -DotProduct(temp.texMat[0][0], xyz);
		VectorSet(temp.texMat[0][1], 0.0f, 0.0f, iDist);
		temp.texMat[0][1][3] = -DotProduct(temp.texMat[0][1], xyz);

		/* make y axis texture matrix (xz) */
		VectorSet(temp.texMat[1][0], iDist, 0.0f, 0.0f);
		temp.texMat[1][0][3] = -DotProduct(temp.texMat[1][0], xyz);
		VectorSet(temp.texMat[1][1], 0.0f, 0.0f, iDist);
		temp.texMat[1][1][3] = -DotProduct(temp.texMat[1][1], xyz);

		/* make z axis texture matrix (xy) */
		VectorSet(temp.texMat[2][0], iDist, 0.0f, 0.0f);
		temp.texMat[2][0][3] = -DotProduct(temp.texMat[2][0], xyz);
		VectorSet(temp.texMat[2][1], 0.0f, iDist, 0.0f);
		temp.texMat[2][1][3] = -DotProduct(temp.texMat[2][1], xyz);

		/* setup decal points */
		VectorSet(dv[0].xyz, points[0][0] - radius, points[0][1] - radius, points[0][2] + radius);
		VectorSet(dv[1].xyz, points[0][0] - radius, points[0][1] + radius, points[0][2] + radius);
		VectorSet(dv[2].xyz, points[0][0] + radius, points[0][1] + radius, points[0][2] + radius);
		VectorSet(dv[3].xyz, points[0][0] + radius, points[0][1] - radius, points[0][2] + radius);
	}
	else
	{
		/* set up unidirectional */
		temp.omnidirectional = qfalse;

		/* set up decal points */
		VectorCopy(points[0], dv[0].xyz);
		VectorCopy(points[1], dv[1].xyz);
		VectorCopy(points[2], dv[2].xyz);
		VectorCopy(points[3], dv[3].xyz);

		/* make texture matrix */
		if (!MakeTextureMatrix(temp.texMat[0], projection, &dv[0], &dv[1], &dv[2]))
		{
			return;
		}
	}

	/* bound the projector */
	ClearBounds(temp.mins, temp.maxs);
	for (i = 0; i < numPoints; i++)
	{
		AddPointToBounds(dv[i].xyz, temp.mins, temp.maxs);
		VectorMA(dv[i].xyz, projection[3], projection, xyz);
		AddPointToBounds(xyz, temp.mins, temp.maxs);
	}

	/* make bounding sphere */
	VectorAdd(temp.mins, temp.maxs, temp.center);
	VectorScale(temp.center, 0.5f, temp.center);
	VectorSubtract(temp.maxs, temp.center, xyz);
	temp.radius  = VectorLength(xyz);
	temp.radius2 = temp.radius * temp.radius;

	/* make the front plane */
	if (!PlaneFromPoints(temp.planes[0], dv[0].xyz, dv[1].xyz, dv[2].xyz))
	{
		return;
	}

	/* make the back plane */
	VectorSubtract(vec3_origin, temp.planes[0], temp.planes[1]);
	VectorMA(dv[0].xyz, projection[3], projection, xyz);
	temp.planes[1][3] = DotProduct(xyz, temp.planes[1]);

	/* make the side planes */
	for (i = 0; i < numPoints; i++)
	{
		VectorMA(dv[i].xyz, projection[3], projection, xyz);
		if (!PlaneFromPoints(temp.planes[i + 2], dv[(i + 1) % numPoints].xyz, dv[i].xyz, xyz))
		{
			return;
		}
	}

	/* create a new projector */
	dp = &backEndData->decalProjectors[r_numDecalProjectors];
	Com_Memcpy(dp, &temp, sizeof(*dp));
	dp->projectorNum = totalProjectors++;

	/* we have a winner */
	r_numDecalProjectors++;
}
Beispiel #22
0
void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir, 
				   float orientation, float red, float green, float blue, float alpha,
				   qboolean alphaFade, float radius, qboolean temporary, int duration ) {
	vec3_t			axis[3];
	float			texCoordScale;
	vec3_t			originalPoints[4];
	byte			colors[4];
	int				i, j;
	int				numFragments;
	markFragment_t	markFragments[MAX_MARK_FRAGMENTS], *mf;
	vec5_t			markPoints[MAX_MARK_POINTS];	// Ridah, made it vec5_t so it includes S/T
	vec3_t			projection;
	int				multMaxFragments=1;

	if ( !cg_markTime.integer ) {
		return;
	}

	if ( radius <= 0 ) {
		CG_Error( "CG_ImpactMark called with <= 0 radius" );
	}

	// Ridah, if no duration, use the default
	if (duration < 0) {
		if (duration == -2) {
			multMaxFragments = -1;	// use original mapping
		}

//		duration = MARK_TOTAL_TIME;
		duration = cg_markTime.integer;
	}

	// create the texture axis
	VectorNormalize2( dir, axis[0] );
	PerpendicularVector( axis[1], axis[0] );
	RotatePointAroundVector( axis[2], axis[0], axis[1], orientation );
	CrossProduct( axis[0], axis[2], axis[1] );

	texCoordScale = 0.5 * 1.0 / radius;

	// create the full polygon
	for ( i = 0 ; i < 3 ; i++ ) {
		originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i];
		originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i];
		originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i];
		originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i];
	}

	// get the fragments
	//VectorScale( dir, -20, projection );
	VectorScale( dir, radius*2, projection );
	numFragments = trap_CM_MarkFragments( (int)orientation, (void *)originalPoints,
					projection, MAX_MARK_POINTS, (float *)&markPoints[0],
					MAX_MARK_FRAGMENTS*multMaxFragments, markFragments );

	colors[0] = red * 255;
	colors[1] = green * 255;
	colors[2] = blue * 255;
	colors[3] = alpha * 255;

	for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) {
		polyVert_t	*v;
		polyVert_t	verts[MAX_VERTS_ON_POLY];
		markPoly_t	*mark;
		qboolean	hasST;

		// we have an upper limit on the complexity of polygons
		// that we store persistantly
		if ( mf->numPoints > MAX_VERTS_ON_POLY ) {
			mf->numPoints = MAX_VERTS_ON_POLY;
		}
		if (mf->numPoints < 0) {
			hasST = qtrue;
			mf->numPoints *= -1;
		} else {
			hasST = qfalse;
		}
		for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) {
			vec3_t		delta;

			VectorCopy( markPoints[mf->firstPoint + j], v->xyz );

			if (!hasST) {
				VectorSubtract( v->xyz, origin, delta );
				v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale;
				v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale;
			} else {
				v->st[0] = markPoints[mf->firstPoint + j][3];
				v->st[1] = markPoints[mf->firstPoint + j][4];
			}

			*(int *)v->modulate = *(int *)colors;
		}

		// if it is a temporary (shadow) mark, add it immediately and forget about it
		if ( temporary ) {
			trap_R_AddPolyToScene( markShader, mf->numPoints, verts );
			continue;
		}

		// otherwise save it persistantly
		mark = CG_AllocMark(cg.time + duration);
		mark->time = cg.time;
		mark->alphaFade = alphaFade;
		mark->markShader = markShader;
		mark->poly.numVerts = mf->numPoints;
		mark->color[0] = red;
		mark->color[1] = green;
		mark->color[2] = blue;
		mark->color[3] = alpha;
		mark->duration = duration;
		memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) );
	}
}
Beispiel #23
0
void PM_VehicleImpact(bgEntity_t *pEnt, trace_t *trace)
{
	// See if the vehicle has crashed into the ground.
	Vehicle_t *pSelfVeh = pEnt->m_pVehicle;
	float magnitude = VectorLength( pm->ps->velocity ) * pSelfVeh->m_pVehicleInfo->mass / 50.0f;
	qboolean forceSurfDestruction = qfalse;
#ifdef QAGAME
	gentity_t *hitEnt = trace!=NULL?&g_entities[trace->entityNum]:NULL;

	if (!hitEnt || //nothing to hit
		(pSelfVeh && pSelfVeh->m_pPilot &&//I'm a piloted vehicle
		hitEnt && hitEnt->s.eType == ET_MISSILE && hitEnt->inuse &&//that hit a missile
		hitEnt->r.ownerNum == pSelfVeh->m_pPilot->s.number)//and the missile is owned by my pilot
		)
	{//don't hit it
		return;
	}

	if ( pSelfVeh//I have a vehicle struct
		&& pSelfVeh->m_iRemovedSurfaces )//vehicle has bits removed
	{//spiralling to our deaths, explode on any solid impact
		if ( hitEnt->s.NPC_class == CLASS_VEHICLE )
		{//hit another vehicle, explode!
			//Give credit to whoever got me into this death spiral state
			//[Asteroids]
			G_DamageFromKiller( (gentity_t *)pEnt, (gentity_t *)pSelfVeh->m_pParentEntity, (gentity_t *)hitEnt, pm->ps->origin, 999999, DAMAGE_NO_ARMOR, MOD_COLLISION );
			/*
			gentity_t *parent = (gentity_t *)pSelfVeh->m_pParentEntity;
			gentity_t *killer = NULL;
			if (parent->client->ps.otherKiller < ENTITYNUM_WORLD &&
				parent->client->ps.otherKillerTime > level.time)
			{
				gentity_t *potentialKiller = &g_entities[parent->client->ps.otherKiller];

				if (potentialKiller->inuse && potentialKiller->client)
				{ //he's valid I guess
					killer = potentialKiller;
				}
			}
			//FIXME: damage hitEnt, some, too?  Our explosion should hurt them some, but...
			G_Damage( (gentity_t *)pEnt, killer, killer, NULL, pm->ps->origin, 999999, DAMAGE_NO_ARMOR, MOD_FALLING );//FIXME: MOD_IMPACT
			*/
			//[/Asteroids]
			return;
		}
		else if ( !VectorCompare( trace->plane.normal, vec3_origin )
			&& (trace->entityNum == ENTITYNUM_WORLD || hitEnt->r.bmodel ) )
		{//have a valid hit plane and we hit a solid brush
			vec3_t	moveDir;
			float	impactDot;
			VectorCopy( pm->ps->velocity, moveDir );
			VectorNormalize( moveDir );
			impactDot = DotProduct( moveDir, trace->plane.normal );
			if ( impactDot <= -0.7f )//hit rather head-on and hard
			{// Just DIE now
				//Give credit to whoever got me into this death spiral state
				//[Asteroids]
				G_DamageFromKiller( (gentity_t *)pEnt, (gentity_t *)pSelfVeh->m_pParentEntity, (gentity_t *)hitEnt, pm->ps->origin, 999999, DAMAGE_NO_ARMOR, MOD_FALLING );
				/*
				gentity_t *killer = NULL;
				if (parent->client->ps.otherKiller < ENTITYNUM_WORLD &&
					parent->client->ps.otherKillerTime > level.time)
				{
					gentity_t *potentialKiller = &g_entities[parent->client->ps.otherKiller];

					if (potentialKiller->inuse && potentialKiller->client)
					{ //he's valid I guess
						killer = potentialKiller;
					}
				}
				G_Damage( (gentity_t *)pEnt, killer, killer, NULL, pm->ps->origin, 999999, DAMAGE_NO_ARMOR, MOD_FALLING );//FIXME: MOD_IMPACT
				*/
				//[/Asteroids]
				return;
			}
		}
	}
	
	if ( trace->entityNum < ENTITYNUM_WORLD
		&& hitEnt->s.eType == ET_MOVER
		&& hitEnt->s.apos.trType != TR_STATIONARY//rotating
		&& (hitEnt->spawnflags&16) //IMPACT
		&& Q_stricmp( "func_rotating", hitEnt->classname ) == 0 )
	{//hit a func_rotating that is supposed to destroy anything it touches!
		//guarantee the hit will happen, thereby taking off a piece of the ship
		forceSurfDestruction = qtrue;
	}
	else if ( (fabs(pm->ps->velocity[0])+fabs(pm->ps->velocity[1])) < 100.0f
		&& pm->ps->velocity[2] > -100.0f )
#else
	if ( (fabs(pm->ps->velocity[0])+fabs(pm->ps->velocity[1])) < 100.0f
		&& pm->ps->velocity[2] > -100.0f )
#endif
		/*
	if ( (pSelfVeh->m_ulFlags&VEH_GEARSOPEN) 
		&& trace->plane.normal[2] > 0.7f
		&& fabs(pSelfVeh->m_vOrientation[PITCH]) < 0.2f
		&& fabs(pSelfVeh->m_vOrientation[ROLL]) < 0.2f )*/
	{//we're landing, we're cool
		//FIXME: some sort of landing "thump", not the impactFX
		/*
		if ( pSelfVeh->m_pVehicleInfo->iImpactFX )
		{
			vec3_t up = {0,0,1};
#ifdef QAGAME
			G_PlayEffectID( pSelfVeh->m_pVehicleInfo->iImpactFX, pm->ps->origin, up );
#else
			trap_FX_PlayEffectID( pSelfVeh->m_pVehicleInfo->iImpactFX, pm->ps->origin, up, -1, -1 );
#endif
		}
		*/
		//this was annoying me -rww
		//FIXME: this shouldn't even be getting called when the vehicle is at rest!
#ifdef QAGAME
		if (hitEnt && (hitEnt->s.eType == ET_PLAYER || hitEnt->s.eType == ET_NPC) && pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)
		{ //always smack players
		}
		else
#endif
		{
			return;
		}
	}
	if ( pSelfVeh &&
		(pSelfVeh->m_pVehicleInfo->type == VH_SPEEDER || pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER) && //this is kind of weird on tauntauns and atst's..
		(magnitude >= 100||forceSurfDestruction) )
	{
		if ( pEnt->m_pVehicle->m_iHitDebounce < pm->cmd.serverTime 
			|| forceSurfDestruction )
		{//a bit of a hack, may conflict with getting shot, but...
			//FIXME: impact sound and effect should be gotten from g_vehicleInfo...?
			//FIXME: should pass in trace.endpos and trace.plane.normal
			vec3_t	vehUp;
//[Asteroids]
#ifdef QAGAME
			qboolean noDamage = qfalse;
#else
//#ifndef QAGAME
//[/Asteroids]
			bgEntity_t *hitEnt;
#endif

			if ( trace && !pSelfVeh->m_iRemovedSurfaces && !forceSurfDestruction )
			{
				qboolean turnFromImpact = qfalse, turnHitEnt = qfalse;
				float l = pm->ps->speed*0.5f;
				vec3_t	bounceDir;
#ifndef QAGAME
				bgEntity_t *hitEnt = PM_BGEntForNum(trace->entityNum);
#endif
				if ( (trace->entityNum == ENTITYNUM_WORLD || hitEnt->s.solid == SOLID_BMODEL)//bounce off any brush
					 && !VectorCompare(trace->plane.normal, vec3_origin) )//have a valid plane to bounce off of
				{ //bounce off in the opposite direction of the impact
					if (pSelfVeh->m_pVehicleInfo->type == VH_SPEEDER)
					{
						pm->ps->speed *= pml.frametime;
						VectorCopy(trace->plane.normal, bounceDir);
					}
					else if ( trace->plane.normal[2] >= MIN_LANDING_SLOPE//flat enough to land on
						&& pSelfVeh->m_LandTrace.fraction < 1.0f //ground present
						&& pm->ps->speed <= MIN_LANDING_SPEED )
					{//could land here, don't bounce off, in fact, return altogether!
						return;
					}
					else
					{
						if (pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)
						{
							turnFromImpact = qtrue;
						}
						VectorCopy(trace->plane.normal, bounceDir);
					}
				}
				else if ( pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER )
				{//check for impact with another fighter
#ifndef QAGAME
					bgEntity_t *hitEnt = PM_BGEntForNum(trace->entityNum);
#endif
					if ( hitEnt->s.NPC_class == CLASS_VEHICLE
						&& hitEnt->m_pVehicle 
						&& hitEnt->m_pVehicle->m_pVehicleInfo
						&& hitEnt->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER )
					{//two vehicles hit each other, turn away from the impact
						turnFromImpact = qtrue;
						turnHitEnt = qtrue;
#ifndef QAGAME
						VectorSubtract( pm->ps->origin, hitEnt->s.origin, bounceDir );
#else
						VectorSubtract( pm->ps->origin, hitEnt->r.currentOrigin, bounceDir );
#endif
						VectorNormalize( bounceDir );
					}
				}
				if ( turnFromImpact )
				{//bounce off impact surf and turn away
					vec3_t	pushDir={0}, turnAwayAngles, turnDelta;
					float	turnStrength, pitchTurnStrength, yawTurnStrength;
					vec3_t	moveDir;
					float bounceDot, turnDivider;
					//bounce
					if ( !turnHitEnt )
					{//hit wall
						VectorScale(bounceDir, (pm->ps->speed*0.25f/pSelfVeh->m_pVehicleInfo->mass), pushDir);
					}
					else
					{//hit another fighter
#ifndef QAGAME
						VectorScale( bounceDir, (pm->ps->speed+hitEnt->s.speed)*0.5f, bounceDir );
#else
						if ( hitEnt->client )
						{
							VectorScale( bounceDir, (pm->ps->speed+hitEnt->client->ps.speed)*0.5f, pushDir );
						}
						else
						{
							VectorScale( bounceDir, (pm->ps->speed+hitEnt->s.speed)*0.5f, pushDir );
						}
#endif
						VectorScale(pushDir, (l/pSelfVeh->m_pVehicleInfo->mass), pushDir);
						VectorScale(pushDir, 0.1f, pushDir);
					}
					VectorNormalize2( pm->ps->velocity, moveDir );
					bounceDot = DotProduct( moveDir, bounceDir )*-1;
					if ( bounceDot < 0.1f )
					{
						bounceDot = 0.1f;
					}
					VectorScale( pushDir, bounceDot, pushDir );
					VectorAdd(pm->ps->velocity, pushDir, pm->ps->velocity);
					//turn
					turnDivider = (pSelfVeh->m_pVehicleInfo->mass/400.0f);
					if ( turnHitEnt )
					{//don't turn as much when hit another ship
						turnDivider *= 4.0f;
					}
					if ( turnDivider < 0.5f )
					{
						turnDivider = 0.5f;
					}
					turnStrength = (magnitude/2000.0f);
					if ( turnStrength < 0.1f )
					{
						turnStrength = 0.1f;
					}
					else if ( turnStrength > 2.0f )
					{
						turnStrength = 2.0f;
					}
					//get the angles we are going to turn towards
					vectoangles( bounceDir, turnAwayAngles );
					//get the delta from our current angles to those new angles
					AnglesSubtract( turnAwayAngles, pSelfVeh->m_vOrientation, turnDelta );
					//now do pitch
					if ( !bounceDir[2] )
					{//shouldn't be any pitch
					}
					else
					{
						pitchTurnStrength = turnStrength*turnDelta[PITCH];
						if ( pitchTurnStrength > MAX_IMPACT_TURN_ANGLE )
						{
							pitchTurnStrength = MAX_IMPACT_TURN_ANGLE;
						}
						else if ( pitchTurnStrength < -MAX_IMPACT_TURN_ANGLE )
						{
							pitchTurnStrength = -MAX_IMPACT_TURN_ANGLE;
						}
						//pSelfVeh->m_vOrientation[PITCH] = AngleNormalize180(pSelfVeh->m_vOrientation[PITCH]+pitchTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
						pSelfVeh->m_vFullAngleVelocity[PITCH] = AngleNormalize180(pSelfVeh->m_vOrientation[PITCH]+pitchTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
					}
					//now do yaw
					if ( !bounceDir[0] 
						&& !bounceDir[1] )
					{//shouldn't be any yaw
					}
					else
					{
						yawTurnStrength = turnStrength*turnDelta[YAW];
						if ( yawTurnStrength > MAX_IMPACT_TURN_ANGLE )
						{
							yawTurnStrength = MAX_IMPACT_TURN_ANGLE;
						}
						else if ( yawTurnStrength < -MAX_IMPACT_TURN_ANGLE )
						{
							yawTurnStrength = -MAX_IMPACT_TURN_ANGLE;
						}
						//pSelfVeh->m_vOrientation[ROLL] = AngleNormalize180(pSelfVeh->m_vOrientation[ROLL]-yawTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
						pSelfVeh->m_vFullAngleVelocity[ROLL] = AngleNormalize180(pSelfVeh->m_vOrientation[ROLL]-yawTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
					}
					/*
					PM_SetPMViewAngle(pm->ps, pSelfVeh->m_vOrientation, &pSelfVeh->m_ucmd);
					if ( pm_entVeh )
					{//I'm a vehicle, so pm_entVeh is actually my pilot
						bgEntity_t *pilot = pm_entVeh;
						if ( !BG_UnrestrainedPitchRoll( pilot->playerState, pSelfVeh ) )
						{
							//set the rider's viewangles to the vehicle's viewangles
							PM_SetPMViewAngle(pilot->playerState, pSelfVeh->m_vOrientation, &pSelfVeh->m_ucmd);
						}
					}
					*/
#ifdef QAGAME//server-side, turn the guy we hit away from us, too
					if ( turnHitEnt//make the other guy turn and get pushed
						&& hitEnt->client //must be a valid client
						&& !FighterIsLanded( hitEnt->m_pVehicle, &hitEnt->client->ps )//but not if landed
						&& !(hitEnt->spawnflags&2) )//and not if suspended
					{
						l = hitEnt->client->ps.speed;
						//now bounce *them* away and turn them
						//flip the bounceDir
						VectorScale( bounceDir, -1, bounceDir );
						//do bounce
						VectorScale( bounceDir, (pm->ps->speed+l)*0.5f, pushDir );
						VectorScale(pushDir, (l*0.5f/hitEnt->m_pVehicle->m_pVehicleInfo->mass), pushDir);
						VectorNormalize2( hitEnt->client->ps.velocity, moveDir );
						bounceDot = DotProduct( moveDir, bounceDir )*-1;
						if ( bounceDot < 0.1f )
						{
							bounceDot = 0.1f;
						}
						VectorScale( pushDir, bounceDot, pushDir );
						VectorAdd(hitEnt->client->ps.velocity, pushDir, hitEnt->client->ps.velocity);
						//turn
						turnDivider = (hitEnt->m_pVehicle->m_pVehicleInfo->mass/400.0f);
						if ( turnHitEnt )
						{//don't turn as much when hit another ship
							turnDivider *= 4.0f;
						}
						if ( turnDivider < 0.5f )
						{
							turnDivider = 0.5f;
						}
						//get the angles we are going to turn towards
						vectoangles( bounceDir, turnAwayAngles );
						//get the delta from our current angles to those new angles
						AnglesSubtract( turnAwayAngles, hitEnt->m_pVehicle->m_vOrientation, turnDelta );
						//now do pitch
						if ( !bounceDir[2] )
						{//shouldn't be any pitch
						}
						else
						{
							pitchTurnStrength = turnStrength*turnDelta[PITCH];
							if ( pitchTurnStrength > MAX_IMPACT_TURN_ANGLE )
							{
								pitchTurnStrength = MAX_IMPACT_TURN_ANGLE;
							}
							else if ( pitchTurnStrength < -MAX_IMPACT_TURN_ANGLE )
							{
								pitchTurnStrength = -MAX_IMPACT_TURN_ANGLE;
							}
							//hitEnt->m_pVehicle->m_vOrientation[PITCH] = AngleNormalize180(hitEnt->m_pVehicle->m_vOrientation[PITCH]+pitchTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
							hitEnt->m_pVehicle->m_vFullAngleVelocity[PITCH] = AngleNormalize180(hitEnt->m_pVehicle->m_vOrientation[PITCH]+pitchTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
						}
						//now do yaw
						if ( !bounceDir[0] 
							&& !bounceDir[1] )
						{//shouldn't be any yaw
						}
						else
						{
							yawTurnStrength = turnStrength*turnDelta[YAW];
							if ( yawTurnStrength > MAX_IMPACT_TURN_ANGLE )
							{
								yawTurnStrength = MAX_IMPACT_TURN_ANGLE;
							}
							else if ( yawTurnStrength < -MAX_IMPACT_TURN_ANGLE )
							{
								yawTurnStrength = -MAX_IMPACT_TURN_ANGLE;
							}
							
							hitEnt->m_pVehicle->m_vFullAngleVelocity[ROLL] = AngleNormalize180(hitEnt->m_pVehicle->m_vOrientation[ROLL]-yawTurnStrength/turnDivider*pSelfVeh->m_fTimeModifier);
						}
					}
#endif
				}
			}

#ifdef QAGAME
			if (!hitEnt)
			{
				return;
			}

			AngleVectors( pSelfVeh->m_vOrientation, NULL, NULL, vehUp );
			if ( pSelfVeh->m_pVehicleInfo->iImpactFX )
			{
				//G_PlayEffectID( pSelfVeh->m_pVehicleInfo->iImpactFX, pm->ps->origin, vehUp );
				//tempent use bad!
				G_AddEvent((gentity_t *)pEnt, EV_PLAY_EFFECT_ID, pSelfVeh->m_pVehicleInfo->iImpactFX);
			}
			pEnt->m_pVehicle->m_iHitDebounce = pm->cmd.serverTime + 200;
			magnitude /= pSelfVeh->m_pVehicleInfo->toughness * 50.0f; 

			if (hitEnt 
				&& (hitEnt->s.eType != ET_TERRAIN || !(hitEnt->spawnflags & 1) || pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER))
			{ //don't damage the vehicle from terrain that doesn't want to damage vehicles
				//[Asteroids]
				gentity_t *killer = NULL;
				//[/Asteroids]
				if (pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)
				{ //increase the damage...
					float mult = (pSelfVeh->m_vOrientation[PITCH]*0.1f);
					if (mult < 1.0f)
					{
						mult = 1.0f;
					}
					if (hitEnt->inuse && hitEnt->takedamage)
					{ //if the other guy takes damage, don't hurt us a lot for ramming him
						//unless it's a vehicle, then we get 1.5 times damage
						if (hitEnt->s.eType == ET_NPC &&
							hitEnt->s.NPC_class == CLASS_VEHICLE &&
							hitEnt->m_pVehicle)
						{
							mult = 1.5f;
						}
						else
						{
							mult = 0.5f;
						}
					}

					magnitude *= mult;
				}
				pSelfVeh->m_iLastImpactDmg = magnitude;
				//FIXME: what about proper death credit to the guy who shot you down?
				//FIXME: actually damage part of the ship that impacted?
				if ( hitEnt->s.eType == ET_MISSILE )//missile
				{
					//FIX: NEVER do or take impact damage from a missile...
					noDamage = qtrue;
					if ( (hitEnt->s.eFlags&EF_JETPACK_ACTIVE)//vehicle missile
						&& ((gentity_t *)hitEnt)->r.ownerNum < MAX_CLIENTS )//valid client owner
					{//I ran into a missile and died because of the impact, give credit to the missile's owner (PROBLEM: might this ever accidently give improper credit to client 0?)
						/*
						if ( ((gentity_t *)hitEnt)->r.ownerNum == pEnt->s.number )
						{//hit our own missile?  Don't damage ourselves or it... (so we don't kill ourselves!) if it hits *us*, then fine, but not here
							noDamage = qtrue;
						}
						*/
						killer = &g_entities[((gentity_t *)hitEnt)->r.ownerNum];
					}
				}
				if ( !noDamage )
				{
					G_Damage( (gentity_t *)pEnt, ((gentity_t*)hitEnt), killer!=NULL?killer:((gentity_t *)hitEnt), NULL, pm->ps->origin, magnitude*5, DAMAGE_NO_ARMOR, (hitEnt->s.NPC_class==CLASS_VEHICLE?MOD_COLLISION:MOD_FALLING) );//FIXME: MOD_IMPACT
				}
				//G_Damage( (gentity_t *)pEnt, NULL, NULL, NULL, pm->ps->origin, magnitude*5, DAMAGE_NO_ARMOR, MOD_FALLING );//FIXME: MOD_IMPACT
				//[/Asteroids]

				if (pSelfVeh->m_pVehicleInfo->surfDestruction)
				{
					G_FlyVehicleSurfaceDestruction((gentity_t *)pEnt, trace, magnitude, forceSurfDestruction );
				}

				pSelfVeh->m_ulFlags |= VEH_CRASHING;
			}

			if (hitEnt &&
				hitEnt->inuse &&
				hitEnt->takedamage)
			{ //damage this guy because we hit him
				float pmult = 1.0f;
				int finalD;
				gentity_t *attackEnt;

				if ( (hitEnt->s.eType == ET_PLAYER && hitEnt->s.number < MAX_CLIENTS) ||
					 (hitEnt->s.eType == ET_NPC && hitEnt->s.NPC_class != CLASS_VEHICLE) )
				{ //probably a humanoid, or something
					if (pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)
					{ //player die good.. if me fighter
						pmult = 2000.0f;
					}
					else
					{
						pmult = 40.0f;
					}

					if (hitEnt->client &&
						BG_KnockDownable(&hitEnt->client->ps) &&
						G_CanBeEnemy((gentity_t *)pEnt, hitEnt))
					{ //smash!
						if (hitEnt->client->ps.forceHandExtend != HANDEXTEND_KNOCKDOWN)
						{
							hitEnt->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN;
							hitEnt->client->ps.forceHandExtendTime = pm->cmd.serverTime + 1100;
							hitEnt->client->ps.forceDodgeAnim = 0; //this toggles between 1 and 0, when it's 1 we should play the get up anim
						}

						hitEnt->client->ps.otherKiller = pEnt->s.number;
						hitEnt->client->ps.otherKillerTime = pm->cmd.serverTime + 5000;
						hitEnt->client->ps.otherKillerDebounceTime = pm->cmd.serverTime + 100;
						//[Asteroids]
						hitEnt->client->otherKillerMOD = MOD_COLLISION;
						hitEnt->client->otherKillerVehWeapon = 0;
						hitEnt->client->otherKillerWeaponType = WP_NONE;
						//[/Asteroids]

						//add my velocity into his to force him along in the correct direction from impact
						VectorAdd(hitEnt->client->ps.velocity, pm->ps->velocity, hitEnt->client->ps.velocity);
						//upward thrust
						hitEnt->client->ps.velocity[2] += 200.0f;
					}
				}

				if (pSelfVeh->m_pPilot)
				{
					attackEnt = (gentity_t *)pSelfVeh->m_pPilot;
				}
				else
				{
					attackEnt = (gentity_t *)pEnt;
				}

				finalD = magnitude*pmult;
				if (finalD < 1)
				{
					finalD = 1;
				}
				//[/Asteroids]
				if ( !noDamage )
				{
					G_Damage( hitEnt, attackEnt, attackEnt, NULL, pm->ps->origin, finalD, 0, (hitEnt->s.NPC_class==CLASS_VEHICLE?MOD_COLLISION:MOD_FALLING/*MOD_MELEE*/) );//FIXME: MOD_IMPACT
				}
				//[Asteroids]
			}
#else	//this is gonna result in "double effects" for the client doing the prediction.
		//it doesn't look bad though. could just use predicted events, but I'm too lazy.
			hitEnt = PM_BGEntForNum(trace->entityNum);

			if (!hitEnt || hitEnt->s.owner != pEnt->s.number)
			{ //don't hit your own missiles!
				AngleVectors( pSelfVeh->m_vOrientation, NULL, NULL, vehUp );
				pEnt->m_pVehicle->m_iHitDebounce = pm->cmd.serverTime + 200;
				trap_FX_PlayEffectID( pSelfVeh->m_pVehicleInfo->iImpactFX, pm->ps->origin, vehUp, -1, -1 );

				pSelfVeh->m_ulFlags |= VEH_CRASHING;
			}
#endif
		}
	}
}
Beispiel #24
0
/*
===================
ProjectDlightTexture

Perform dynamic lighting with another rendering pass
===================
*/
static void ProjectDlightTexture2( void ) {
	int		i, l;
	vec3_t	origin;
	byte	clipBits[SHADER_MAX_VERTEXES];
	float	texCoordsArray[SHADER_MAX_VERTEXES][2];
	float	oldTexCoordsArray[SHADER_MAX_VERTEXES][2];
	float	vertCoordsArray[SHADER_MAX_VERTEXES][4];
	unsigned int		colorArray[SHADER_MAX_VERTEXES];
	glIndex_t	hitIndexes[SHADER_MAX_INDEXES];
	int		numIndexes;
	float	radius;
	int		fogging;
	shaderStage_t *dStage;
	vec3_t	posa;
	vec3_t	posb;
	vec3_t	posc;
	vec3_t	dist;
	vec3_t	e1;
	vec3_t	e2;
	vec3_t	normal;
	float	fac,modulate;
	vec3_t	floatColor;
	byte colorTemp[4];

	int		needResetVerts=0;

	if ( !backEnd.refdef.num_dlights )
	{
		return;
	}

	for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ )
	{
		dlight_t	*dl;

		if ( !( tess.dlightBits & ( 1 << l ) ) ) {
			continue;	// this surface definately doesn't have any of this light
		}

		dl = &backEnd.refdef.dlights[l];
		VectorCopy( dl->transformed, origin );
		radius = dl->radius;

		int		clipall = 63;
		for ( i = 0 ; i < tess.numVertexes ; i++)
		{
			int		clip;
			VectorSubtract( origin, tess.xyz[i], dist );

			clip = 0;
			if (  dist[0] < -radius )
			{
				clip |= 1;
			}
			else if ( dist[0] > radius )
			{
				clip |= 2;
			}
			if (  dist[1] < -radius )
			{
				clip |= 4;
			}
			else if ( dist[1] > radius )
			{
				clip |= 8;
			}
			if (  dist[2] < -radius )
			{
				clip |= 16;
			}
			else if ( dist[2] > radius )
			{
				clip |= 32;
			}

			clipBits[i] = clip;
			clipall &= clip;
		}
		if ( clipall )
		{
			continue;	// this surface doesn't have any of this light
		}
		floatColor[0] = dl->color[0] * 255.0f;
		floatColor[1] = dl->color[1] * 255.0f;
		floatColor[2] = dl->color[2] * 255.0f;

		// build a list of triangles that need light
		numIndexes = 0;
		for ( i = 0 ; i < tess.numIndexes ; i += 3 )
		{
			int		a, b, c;

			a = tess.indexes[i];
			b = tess.indexes[i+1];
			c = tess.indexes[i+2];
			if ( clipBits[a] & clipBits[b] & clipBits[c] )
			{
				continue;	// not lighted
			}

			// copy the vertex positions
			VectorCopy(tess.xyz[a],posa);
			VectorCopy(tess.xyz[b],posb);
			VectorCopy(tess.xyz[c],posc);

			VectorSubtract( posa, posb,e1);
			VectorSubtract( posc, posb,e2);
			CrossProduct(e1,e2,normal);
// rjr - removed for hacking 			if ( (!r_dlightBacks->integer && DotProduct(normal,origin)-DotProduct(normal,posa) <= 0.0f) || // backface
			if ( DotProduct(normal,origin)-DotProduct(normal,posa) <= 0.0f || // backface
				DotProduct(normal,normal) < 1E-8f) // junk triangle
			{
				continue;
			}
			VectorNormalize(normal);
			fac=DotProduct(normal,origin)-DotProduct(normal,posa);
			if (fac >= radius)  // out of range
			{
				continue;
			}
			modulate = 1.0f-((fac*fac) / (radius*radius));
			fac = 0.5f/sqrtf(radius*radius - fac*fac);

			// save the verts
			VectorCopy(posa,vertCoordsArray[numIndexes]);
			VectorCopy(posb,vertCoordsArray[numIndexes+1]);
			VectorCopy(posc,vertCoordsArray[numIndexes+2]);

			// now we need e1 and e2 to be an orthonormal basis
			if (DotProduct(e1,e1) > DotProduct(e2,e2))
			{
				VectorNormalize(e1);
				CrossProduct(e1,normal,e2);
			}
			else
			{
				VectorNormalize(e2);
				CrossProduct(normal,e2,e1);
			}
			VectorScale(e1,fac,e1);
			VectorScale(e2,fac,e2);

			VectorSubtract( posa, origin,dist);
			texCoordsArray[numIndexes][0]=DotProduct(dist,e1)+0.5f;
			texCoordsArray[numIndexes][1]=DotProduct(dist,e2)+0.5f;

			VectorSubtract( posb, origin,dist);
			texCoordsArray[numIndexes+1][0]=DotProduct(dist,e1)+0.5f;
			texCoordsArray[numIndexes+1][1]=DotProduct(dist,e2)+0.5f;

			VectorSubtract( posc, origin,dist);
			texCoordsArray[numIndexes+2][0]=DotProduct(dist,e1)+0.5f;
			texCoordsArray[numIndexes+2][1]=DotProduct(dist,e2)+0.5f;

			if ((texCoordsArray[numIndexes][0] < 0.0f && texCoordsArray[numIndexes+1][0] < 0.0f && texCoordsArray[numIndexes+2][0] < 0.0f) ||
				(texCoordsArray[numIndexes][0] > 1.0f && texCoordsArray[numIndexes+1][0] > 1.0f && texCoordsArray[numIndexes+2][0] > 1.0f) ||
				(texCoordsArray[numIndexes][1] < 0.0f && texCoordsArray[numIndexes+1][1] < 0.0f && texCoordsArray[numIndexes+2][1] < 0.0f) ||
				(texCoordsArray[numIndexes][1] > 1.0f && texCoordsArray[numIndexes+1][1] > 1.0f && texCoordsArray[numIndexes+2][1] > 1.0f) )
			{
				continue; // didn't end up hitting this tri
			}
			/* old code, get from the svars = wrong
			oldTexCoordsArray[numIndexes][0]=tess.svars.texcoords[0][a][0];
			oldTexCoordsArray[numIndexes][1]=tess.svars.texcoords[0][a][1];
			oldTexCoordsArray[numIndexes+1][0]=tess.svars.texcoords[0][b][0];
			oldTexCoordsArray[numIndexes+1][1]=tess.svars.texcoords[0][b][1];
			oldTexCoordsArray[numIndexes+2][0]=tess.svars.texcoords[0][c][0];
			oldTexCoordsArray[numIndexes+2][1]=tess.svars.texcoords[0][c][1];
			*/
			oldTexCoordsArray[numIndexes][0]=tess.texCoords[a][0][0];
			oldTexCoordsArray[numIndexes][1]=tess.texCoords[a][0][1];
			oldTexCoordsArray[numIndexes+1][0]=tess.texCoords[b][0][0];
			oldTexCoordsArray[numIndexes+1][1]=tess.texCoords[b][0][1];
			oldTexCoordsArray[numIndexes+2][0]=tess.texCoords[c][0][0];
			oldTexCoordsArray[numIndexes+2][1]=tess.texCoords[c][0][1];

			colorTemp[0] = Q_ftol(floatColor[0] * modulate);
			colorTemp[1] = Q_ftol(floatColor[1] * modulate);
			colorTemp[2] = Q_ftol(floatColor[2] * modulate);
			colorTemp[3] = 255;

			byteAlias_t *ba = (byteAlias_t *)&colorTemp;
			colorArray[numIndexes + 0] = ba->ui;
			colorArray[numIndexes + 1] = ba->ui;
			colorArray[numIndexes + 2] = ba->ui;

			hitIndexes[numIndexes] = numIndexes;
			hitIndexes[numIndexes+1] = numIndexes+1;
			hitIndexes[numIndexes+2] = numIndexes+2;
			numIndexes += 3;

			if (numIndexes>=SHADER_MAX_VERTEXES-3)
			{
				break; // we are out of space, so we are done :)
			}
		}

		if ( !numIndexes ) {
			continue;
		}

		//don't have fog enabled when we redraw with alpha test, or it will double over
		//and screw the tri up -rww
		if (r_drawfog->value == 2 &&
			tr.world &&
			(tess.fogNum == tr.world->globalFog || tess.fogNum == tr.world->numfogs))
		{
			fogging = qglIsEnabled(GL_FOG);

			if (fogging)
			{
				qglDisable(GL_FOG);
			}
		}
		else
		{
			fogging = 0;
		}


		dStage = NULL;
		if (tess.shader && qglActiveTextureARB)
		{
			int i = 0;
			while (i < tess.shader->numUnfoggedPasses)
			{
				const int blendBits = (GLS_SRCBLEND_BITS+GLS_DSTBLEND_BITS);
				if (((tess.shader->stages[i].bundle[0].image && !tess.shader->stages[i].bundle[0].isLightmap && !tess.shader->stages[i].bundle[0].numTexMods && tess.shader->stages[i].bundle[0].tcGen != TCGEN_ENVIRONMENT_MAPPED && tess.shader->stages[i].bundle[0].tcGen != TCGEN_FOG) ||
					 (tess.shader->stages[i].bundle[1].image && !tess.shader->stages[i].bundle[1].isLightmap && !tess.shader->stages[i].bundle[1].numTexMods && tess.shader->stages[i].bundle[1].tcGen != TCGEN_ENVIRONMENT_MAPPED && tess.shader->stages[i].bundle[1].tcGen != TCGEN_FOG)) &&
					(tess.shader->stages[i].stateBits & blendBits) == 0 )
				{ //only use non-lightmap opaque stages
                    dStage = &tess.shader->stages[i];
					break;
				}
				i++;
			}
		}
		if (!needResetVerts)
		{
			needResetVerts=1;
			if (qglUnlockArraysEXT)
			{
				qglUnlockArraysEXT();
				GLimp_LogComment( "glUnlockArraysEXT\n" );
			}
		}
		qglVertexPointer (3, GL_FLOAT, 16, vertCoordsArray);	// padded for SIMD

		if (dStage)
		{
			GL_SelectTexture( 0 );
			GL_State(0);
			qglTexCoordPointer( 2, GL_FLOAT, 0, oldTexCoordsArray[0] );
			if (dStage->bundle[0].image && !dStage->bundle[0].isLightmap && !dStage->bundle[0].numTexMods && dStage->bundle[0].tcGen != TCGEN_ENVIRONMENT_MAPPED && dStage->bundle[0].tcGen != TCGEN_FOG)
			{
				R_BindAnimatedImage( &dStage->bundle[0] );
			}
			else
			{
				R_BindAnimatedImage( &dStage->bundle[1] );
			}

			GL_SelectTexture( 1 );
			qglEnable( GL_TEXTURE_2D );
			qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
			qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] );
			qglEnableClientState( GL_COLOR_ARRAY );
			qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray );
			GL_Bind( tr.dlightImage );
			GL_TexEnv( GL_MODULATE );


			GL_State(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL);// | GLS_ATEST_GT_0);

			R_DrawElements( numIndexes, hitIndexes );

			qglDisable( GL_TEXTURE_2D );
			GL_SelectTexture(0);
		}
		else
		{
			qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
			qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] );

			qglEnableClientState( GL_COLOR_ARRAY );
			qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray );

			GL_Bind( tr.dlightImage );
			// include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
			// where they aren't rendered
			if ( dl->additive ) {
				GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
			}
			else {
				GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
			}

			R_DrawElements( numIndexes, hitIndexes );
		}

		if (fogging)
		{
			qglEnable(GL_FOG);
		}

		backEnd.pc.c_totalIndexes += numIndexes;
		backEnd.pc.c_dlightIndexes += numIndexes;
	}
	if (needResetVerts)
	{
		qglVertexPointer (3, GL_FLOAT, 16, tess.xyz);	// padded for SIMD
		if (qglLockArraysEXT)
		{
			qglLockArraysEXT(0, tess.numVertexes);
			GLimp_LogComment( "glLockArraysEXT\n" );
		}
	}
}
Beispiel #25
0
/*
-------------------------
NAVNEW_PushBlocker
-------------------------
*/
void NAVNEW_PushBlocker( gentity_t *self, gentity_t *blocker, vec3_t right, qboolean setBlockedInfo )
{//try pushing blocker to one side
	trace_t	tr;
	vec3_t	mins, end;
	float	rightSucc, leftSucc, moveamt;

	if ( self->NPC->shoveCount > 30 )
	{//don't push for more than 3 seconds;
		return;
	}

	if ( blocker->s.number >= 0 && blocker->s.number < MAX_CLIENTS )
	{//never push the player
		return;
	}

	if ( !blocker->client || !VectorCompare( blocker->client->pushVec, vec3_origin ) )
	{//someone else is pushing him, wait until they give up?
		return;
	}

	VectorCopy( blocker->r.mins, mins );
	mins[2] += STEPSIZE;

	moveamt = (self->r.maxs[1] + blocker->r.maxs[1]) * 1.2;//yes, magic number

	VectorMA( blocker->r.currentOrigin, -moveamt, right, end );
	trap->Trace( &tr, blocker->r.currentOrigin, mins, blocker->r.maxs, end, blocker->s.number, blocker->clipmask|CONTENTS_BOTCLIP, qfalse, 0, 0);
	if ( !tr.startsolid && !tr.allsolid )
	{
		leftSucc = tr.fraction;
	}
	else
	{
		leftSucc = 0.0f;
	}

	if ( leftSucc >= 1.0f )
	{//it's clear, shove him that way
		VectorScale( right, -moveamt, blocker->client->pushVec );
		blocker->client->pushVecTime = level.time + 2000;
	}
	else
	{
		VectorMA( blocker->r.currentOrigin, moveamt, right, end );
		trap->Trace( &tr, blocker->r.currentOrigin, mins, blocker->r.maxs, end, blocker->s.number, blocker->clipmask|CONTENTS_BOTCLIP, qfalse, 0, 0 );
		if ( !tr.startsolid && !tr.allsolid )
		{
			rightSucc = tr.fraction;
		}
		else
		{
			rightSucc = 0.0f;
		}

		if ( leftSucc == 0.0f && rightSucc == 0.0f )
		{//both sides failed
			if ( d_patched.integer )
			{//use patch-style navigation
				blocker->client->pushVecTime = 0;
			}
			return;
		}

		if ( rightSucc >= 1.0f )
		{//it's clear, shove him that way
			VectorScale( right, moveamt, blocker->client->pushVec );
			blocker->client->pushVecTime = level.time + 2000;
		}
		//if neither are enough, we probably can't get around him, but keep trying
		else if ( leftSucc >= rightSucc )
		{//favor the left, all things being equal
			VectorScale( right, -moveamt, blocker->client->pushVec );
			blocker->client->pushVecTime = level.time + 2000;
		}
		else
		{
			VectorScale( right, moveamt, blocker->client->pushVec );
			blocker->client->pushVecTime = level.time + 2000;
		}
	}

	if ( setBlockedInfo )
	{
		//we tried pushing
		self->NPC->shoveCount++;
	}
}
Beispiel #26
0
/*
==============
RB_DrawSun
	(SA) FIXME: sun should render behind clouds, so passing dark areas cover it up
==============
*/
void RB_DrawSun( float scale, shader_t *shader ) {
	float size;
	float dist;
	vec3_t origin, vec1, vec2;
	vec3_t    temp;
//	vec4_t color;

	if ( !shader ) {
		return;
	}

	if ( !backEnd.skyRenderedThisView ) {
		return;
	}

	//qglLoadMatrixf( backEnd.viewParms.world.modelMatrix );
	//qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
	{
		// FIXME: this could be a lot cleaner
		mat4_t translation, modelview;

		Mat4Translation( backEnd.viewParms.or.origin, translation );
		Mat4Multiply( backEnd.viewParms.world.modelMatrix, translation, modelview );
		GL_SetModelviewMatrix( modelview );
	}

	dist =  backEnd.viewParms.zFar / 1.75;      // div sqrt(3)

	// (SA) shrunk the size of the sun
	size = dist * scale;

	VectorScale( tr.sunDirection, dist, origin );
	PerpendicularVector( vec1, tr.sunDirection );
	CrossProduct( tr.sunDirection, vec1, vec2 );

	VectorScale( vec1, size, vec1 );
	VectorScale( vec2, size, vec2 );

	// farthest depth range
	qglDepthRange( 1.0, 1.0 );

	RB_BeginSurface( shader, 0, 0 );

//	color[0] = color[1] = color[2] = color[3] = 1;

	RB_AddQuadStamp(origin, vec1, vec2, colorWhite);

	RB_EndSurface();


	if ( r_drawSun->integer > 1 ) { // draw flare effect
		// (SA) FYI:	This is cheezy and was only a test so far.
		//				If we decide to use the flare business I will /definatly/ improve all this

		// get a point a little closer
		dist = dist * 0.7;
		VectorScale( tr.sunDirection, dist, origin );

		// and make the flare a little smaller
		VectorScale( vec1, 0.5f, vec1 );
		VectorScale( vec2, 0.5f, vec2 );

		// add the vectors to give an 'off angle' result
		VectorAdd( tr.sunDirection, backEnd.viewParms.or.axis[0], temp );
		VectorNormalize( temp );

		// amplify the result
		origin[0] += temp[0] * 500.0;
		origin[1] += temp[1] * 500.0;
		origin[2] += temp[2] * 500.0;

		// (SA) FIXME: todo: flare effect should render last (on top of everything else) and only when sun is in view (sun moving out of camera past degree n should start to cause flare dimming until view angle to sun is off by angle n + x.

		// draw the flare
		RB_BeginSurface( tr.sunflareShader_old[0], 0, 0 );
		RB_AddQuadStamp( origin, vec1, vec2, colorWhite );
		RB_EndSurface();
	}

	// back to normal depth range
	qglDepthRange( 0.0, 1.0 );
}
Beispiel #27
0
void ThrowGib (edict_t *self, char *gibname, int damage, int type)
{
	edict_t *gib;
	vec3_t	vd;
	vec3_t	origin;
	vec3_t	size;
	float	vscale;

	if (!self || !gibname)
	{
		return;
	}

	if (level.framenum > lastgibframe)
	{
		gibsthisframe = 0;
		lastgibframe = level.framenum;
	}

	gibsthisframe++;
	
	if (gibsthisframe > 20)
	{
		return;
	}

	gib = G_Spawn();

	VectorScale (self->size, 0.5, size);
	VectorAdd (self->absmin, size, origin);
	gib->s.origin[0] = origin[0] + crandom() * size[0];
	gib->s.origin[1] = origin[1] + crandom() * size[1];
	gib->s.origin[2] = origin[2] + crandom() * size[2];

	gi.setmodel (gib, gibname);
	gib->solid = SOLID_NOT;
	gib->s.effects |= EF_GIB;
	gib->flags |= FL_NO_KNOCKBACK;
	gib->takedamage = DAMAGE_YES;
	gib->die = gib_die;

	if (type == GIB_ORGANIC)
	{
		gib->movetype = MOVETYPE_TOSS;
		gib->touch = gib_touch;
		vscale = 0.5;
	}
	else
	{
		gib->movetype = MOVETYPE_BOUNCE;
		vscale = 1.0;
	}

	VelocityForDamage (damage, vd);
	VectorMA (self->velocity, vscale, vd, gib->velocity);
	ClipGibVelocity (gib);
	gib->avelocity[0] = random()*600;
	gib->avelocity[1] = random()*600;
	gib->avelocity[2] = random()*600;

	gib->think = G_FreeEdict;
	gib->nextthink = level.time + 10 + random()*10;

//PGM
	gib->s.renderfx |= RF_IR_VISIBLE;
//PGM

	gi.linkentity (gib);
}
Beispiel #28
0
void RT_Flying_MaintainHeight( void )
{	
	float	dif = 0;

	// Update our angles regardless
	NPC_UpdateAngles( qtrue, qtrue );

	if ( NPC->forcePushTime > level.time )
	{//if being pushed, we don't have control over our movement
		return;
	}

	if ( (NPC->client->ps.pm_flags&PMF_TIME_KNOCKBACK) )
	{//don't slow down for a bit
		if ( NPC->client->ps.pm_time > 0 )
		{
			VectorScale( NPC->client->ps.velocity, 0.9f, NPC->client->ps.velocity );
			return;
		}
	}

	/*
	if ( (NPC->client->ps.eFlags&EF_FORCE_GRIPPED) )
	{
		RT_Flying_ApplyFriction( 3.0f );
		return;
	}
	*/
	// If we have an enemy, we should try to hover at or a little below enemy eye level
	if ( NPC->enemy 
		&& (!Q3_TaskIDPending( NPC, TID_MOVE_NAV ) || !NPCInfo->goalEntity ) )
	{
		if (TIMER_Done( NPC, "heightChange" ))
		{
			TIMER_Set( NPC,"heightChange",Q_irand( 1000, 3000 ));
			
			float enemyZHeight = NPC->enemy->currentOrigin[2];
			if ( NPC->enemy->client 
				&& NPC->enemy->client->ps.groundEntityNum == ENTITYNUM_NONE
				&& (NPC->enemy->client->ps.forcePowersActive&(1<<FP_LEVITATION)) )
			{//so we don't go up when they force jump up at us
				enemyZHeight = NPC->enemy->client->ps.forceJumpZStart;
			}

			// Find the height difference
			dif = (enemyZHeight +  Q_flrand( NPC->enemy->maxs[2]/2, NPC->enemy->maxs[2]+8 )) - NPC->currentOrigin[2]; 

			float	difFactor = 10.0f;

			// cap to prevent dramatic height shifts
			if ( fabs( dif ) > 2*difFactor )
			{
				if ( fabs( dif ) > 20*difFactor )
				{
					dif = ( dif < 0 ? -20*difFactor : 20*difFactor );
				}

				NPC->client->ps.velocity[2] = (NPC->client->ps.velocity[2]+dif)/2;
			}
			NPC->client->ps.velocity[2] *= Q_flrand( 0.85f, 1.25f );
		}
		else
		{//don't get too far away from height of enemy...
			float enemyZHeight = NPC->enemy->currentOrigin[2];
			if ( NPC->enemy->client 
				&& NPC->enemy->client->ps.groundEntityNum == ENTITYNUM_NONE
				&& (NPC->enemy->client->ps.forcePowersActive&(1<<FP_LEVITATION)) )
			{//so we don't go up when they force jump up at us
				enemyZHeight = NPC->enemy->client->ps.forceJumpZStart;
			}
			dif = NPC->currentOrigin[2] - (enemyZHeight+64);
			float maxHeight = 200;
			float hDist = DistanceHorizontal( NPC->enemy->currentOrigin, NPC->currentOrigin );
			if ( hDist < 512 )
			{
				maxHeight *= hDist/512;
			}
			if ( dif > maxHeight )
			{
				if ( NPC->client->ps.velocity[2] > 0 )//FIXME: or: we can't see him anymore
				{//slow down
					if ( NPC->client->ps.velocity[2] )
					{
						NPC->client->ps.velocity[2] *= VELOCITY_DECAY;

						if ( fabs( NPC->client->ps.velocity[2] ) < 2 )
						{
							NPC->client->ps.velocity[2] = 0;
						}
					}
				}
				else
				{//start coming back down
					NPC->client->ps.velocity[2] -= 4;
				}
			}
			else if ( dif < -200 && NPC->client->ps.velocity[2] < 0 )//we're way below him
			{
				if ( NPC->client->ps.velocity[2] < 0 )//FIXME: or: we can't see him anymore
				{//slow down
					if ( NPC->client->ps.velocity[2] )
					{
						NPC->client->ps.velocity[2] *= VELOCITY_DECAY;

						if ( fabs( NPC->client->ps.velocity[2] ) > -2 )
						{
							NPC->client->ps.velocity[2] = 0;
						}
					}
				}
				else
				{//start going back up
					NPC->client->ps.velocity[2] += 4;
				}
			}
		}
	}
	else
	{
		gentity_t *goal = NULL;

		if ( NPCInfo->goalEntity )	// Is there a goal?
		{
			goal = NPCInfo->goalEntity;
		}
		else
		{
			goal = NPCInfo->lastGoalEntity;
		}
		if ( goal )
		{
			dif = goal->currentOrigin[2] - NPC->currentOrigin[2];
		}
		else if ( VectorCompare( NPC->pos1, vec3_origin ) )
		{//have a starting position as a reference point
			dif = NPC->pos1[2] - NPC->currentOrigin[2];
		}

		if ( fabs( dif ) > 24 )
		{
			ucmd.upmove = ( ucmd.upmove < 0 ? -4 : 4 );
		}
		else
		{
			if ( NPC->client->ps.velocity[2] )
			{
				NPC->client->ps.velocity[2] *= VELOCITY_DECAY;

				if ( fabs( NPC->client->ps.velocity[2] ) < 2 )
				{
					NPC->client->ps.velocity[2] = 0;
				}
			}
		}
	}

	// Apply friction
	RT_Flying_ApplyFriction( 1.0f );
}
/*
========================
RB_CalcDeformVertexes

========================
*/
void RB_CalcDeformVertexes( deformStage_t *ds ) {
    int i;
    vec3_t offset;
    float scale;
    float   *xyz = ( float * ) tess.xyz;
    float   *normal = ( float * ) tess.normal;
    float   *table;

    // Ridah
    if ( ds->deformationWave.frequency < 0 ) {
        qboolean inverse = qfalse;
        vec3_t worldUp;
        //static vec3_t up = {0,0,1};

        if ( VectorCompare( backEnd.currentEntity->e.fireRiseDir, vec3_origin ) ) {
            VectorSet( backEnd.currentEntity->e.fireRiseDir, 0, 0, 1 );
        }

        // get the world up vector in local coordinates
        if ( backEnd.currentEntity->e.hModel ) {  // world surfaces dont have an axis
            VectorRotate( backEnd.currentEntity->e.fireRiseDir, backEnd.currentEntity->e.axis, worldUp );
        } else {
            VectorCopy( backEnd.currentEntity->e.fireRiseDir, worldUp );
        }
        // don't go so far if sideways, since they must be moving
        VectorScale( worldUp, 0.4 + 0.6 * Q_fabs( backEnd.currentEntity->e.fireRiseDir[2] ), worldUp );

        ds->deformationWave.frequency *= -1;
        if ( ds->deformationWave.frequency > 999 ) {  // hack for negative Z deformation (ack)
            inverse = qtrue;
            ds->deformationWave.frequency -= 999;
        }

        table = TableForFunc( ds->deformationWave.func );

        for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
        {
            float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread;
            float dot;

            scale = WAVEVALUE( table, ds->deformationWave.base,
                               ds->deformationWave.amplitude,
                               ds->deformationWave.phase + off,
                               ds->deformationWave.frequency );

            dot = DotProduct( worldUp, normal );

            if ( dot * scale > 0 ) {
                if ( inverse ) {
                    scale *= -1;
                }
                VectorMA( xyz, dot * scale, worldUp, xyz );
            }
        }

        if ( inverse ) {
            ds->deformationWave.frequency += 999;
        }
        ds->deformationWave.frequency *= -1;
    }
    // done.
    else if ( ds->deformationWave.frequency == 0 ) {
        scale = EvalWaveForm( &ds->deformationWave );

        for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
        {
            VectorScale( normal, scale, offset );

            xyz[0] += offset[0];
            xyz[1] += offset[1];
            xyz[2] += offset[2];
        }
    } else
    {
        table = TableForFunc( ds->deformationWave.func );

        for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
        {
            float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread;

            scale = WAVEVALUE( table, ds->deformationWave.base,
                               ds->deformationWave.amplitude,
                               ds->deformationWave.phase + off,
                               ds->deformationWave.frequency );

            VectorScale( normal, scale, offset );

            xyz[0] += offset[0];
            xyz[1] += offset[1];
            xyz[2] += offset[2];
        }
    }
}
Beispiel #30
0
/* points-as-triangles version */
void R_DrawParticles (void)
{
	particle_t		*p, *kill;
	float			grav;
	int				i;
	float			time2, time3;
	float			time1;
	float			dvel;
	float			frametime;
	vec3_t			up, right;
	float			scale;
	
    GL_Bind(particletexture);
	glEnable (GL_BLEND);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	
	VectorScale (vup, 1.5, up);
	VectorScale (vright, 1.5, right);

	frametime = cl.time - cl.oldtime;
	time3 = frametime * 15;
	time2 = frametime * 10; // 15;
	time1 = frametime * 5;
	grav = frametime * sv_gravity.value * 0.05;
	dvel = 4*frametime;
	
	for ( ;; ) 
	{
		kill = active_particles;
		if (kill && kill->die < cl.time)
		{
			active_particles = kill->next;
			kill->next = free_particles;
			free_particles = kill;
			continue;
		}
		break;
	}
	
	glEnableClientState(GL_VERTEX_ARRAY);
	GLfloat partVerts[340*3*3];
	glVertexPointer(3, GL_FLOAT, sizeof(GLfloat)*3, partVerts);
	GLfloat * verts = partVerts;
	GLubyte partColors[(sizeof(partVerts)/sizeof(GLfloat)/3)*4];
	glEnableClientState(GL_COLOR_ARRAY);
	glColorPointer(4, GL_UNSIGNED_BYTE, 0, partColors);
	GLubyte * colors = partColors;
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	GLfloat texCoords[((sizeof(partVerts)/sizeof(GLfloat))/3)*2];
	const GLfloat texCoordPattern[] = {0, 0, 1, 0, 0, 1};
	for (int i = 0; i <= sizeof(texCoords)/sizeof(GLfloat); i += sizeof(texCoordPattern)/sizeof(GLfloat))
	{
		memcpy(texCoords+i, texCoordPattern, sizeof(texCoordPattern));
	}
	glTexCoordPointer(2, GL_FLOAT, sizeof(GLfloat)*2, texCoords);
	
	for (p = active_particles; p ; p=p->next)
	{
		for ( ;; )
		{
			kill = p->next;
			if (kill && kill->die < cl.time)
			{
				p->next = kill->next;
				kill->next = free_particles;
				free_particles = kill;
				continue;
			}
			break;
		}
		
		// hack a scale up to keep particles from disapearing
		scale = (p->org[0] - r_origin[0])*vpn[0] + (p->org[1] - r_origin[1])*vpn[1]
		+ (p->org[2] - r_origin[2])*vpn[2];
		if (scale < 20)
			scale = 1;
		else
			scale = 1 + scale * 0.004;

		byte * pcolor = (byte *)&d_8to24table[(int)p->color];
		*colors++ = pcolor[0]; *colors++ = pcolor[1]; *colors++ = pcolor[2]; *colors++ = 255;
		*colors++ = pcolor[0]; *colors++ = pcolor[1]; *colors++ = pcolor[2]; *colors++ = 255;
		*colors++ = pcolor[0]; *colors++ = pcolor[1]; *colors++ = pcolor[2]; *colors++ = 255;
		*verts++ = p->org[0]; *verts++ = p->org[1]; *verts++ = p->org[2];
		*verts++ = p->org[0] + up[0]*scale; *verts++ = p->org[1] + up[1]*scale; *verts++ = p->org[2] + up[2]*scale;
		*verts++ = p->org[0] + right[0]*scale; *verts++ =  p->org[1] + right[1]*scale; *verts++ =  p->org[2] + right[2]*scale;
		if (verts - partVerts >= sizeof(partVerts)/sizeof(GLfloat) - 9*sizeof(GLfloat))
		{
			glDrawArrays(GL_TRIANGLES, 0, (verts-partVerts)/3);
			verts = partVerts;
			colors = partColors;
		}
			
		p->org[0] += p->vel[0]*frametime;
		p->org[1] += p->vel[1]*frametime;
		p->org[2] += p->vel[2]*frametime;
		
		switch (p->type)
		{
			case pt_static:
				break;
			case pt_fire:
				p->ramp += time1;
				if (p->ramp >= 6)
					p->die = -1;
				else
					p->color = ramp3[(int)p->ramp];
				p->vel[2] += grav;
				break;
				
			case pt_explode:
				p->ramp += time2;
				if (p->ramp >=8)
					p->die = -1;
				else
					p->color = ramp1[(int)p->ramp];
				for (i=0 ; i<3 ; i++)
					p->vel[i] += p->vel[i]*dvel;
				p->vel[2] -= grav;
				break;
				
			case pt_explode2:
				p->ramp += time3;
				if (p->ramp >=8)
					p->die = -1;
				else
					p->color = ramp2[(int)p->ramp];
				for (i=0 ; i<3 ; i++)
					p->vel[i] -= p->vel[i]*frametime;
				p->vel[2] -= grav;
				break;
				
			case pt_blob:
				for (i=0 ; i<3 ; i++)
					p->vel[i] += p->vel[i]*dvel;
				p->vel[2] -= grav;
				break;
				
			case pt_blob2:
				for (i=0 ; i<2 ; i++)
					p->vel[i] -= p->vel[i]*dvel;
				p->vel[2] -= grav;
				break;
				
			case pt_grav:
				break;
			case pt_slowgrav:
				p->vel[2] -= grav;
				break;
		}
	}
	if (verts > partVerts)
	{
		glDrawArrays(GL_TRIANGLES, 0, (verts-partVerts)/3);
	}
	
	glDisableClientState(GL_COLOR_ARRAY);
	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	
	glDisable (GL_BLEND);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}