示例#1
0
void CM_AddFacetBevels( facet_t *facet ) {

	int i, j, k, l;
	int axis, dir, order, flipped;
	float plane[4], d, newplane[4];
	winding_t *w, *w2;
	vec3_t mins, maxs, vec, vec2;

#ifndef ADDBEVELS
	return;
#endif

	Vector4Copy( planes[ facet->surfacePlane ].plane, plane );

	w = BaseWindingForPlane( plane,  plane[3] );
	for ( j = 0 ; j < facet->numBorders && w ; j++ ) {
		if ( facet->borderPlanes[j] == facet->surfacePlane ) {
			continue;
		}
		Vector4Copy( planes[ facet->borderPlanes[j] ].plane, plane );

		if ( !facet->borderInward[j] ) {
			VectorSubtract( vec3_origin, plane, plane );
			plane[3] = -plane[3];
		}

		ChopWindingInPlace( &w, plane, plane[3], 0.1f );
	}
	if ( !w ) {
		return;
	}

	WindingBounds( w, mins, maxs );

	// add the axial planes
	order = 0;
	for ( axis = 0 ; axis < 3 ; axis++ )
	{
		for ( dir = -1 ; dir <= 1 ; dir += 2, order++ )
		{
			VectorClear( plane );
			plane[axis] = dir;
			if ( dir == 1 ) {
				plane[3] = maxs[axis];
			} else {
				plane[3] = -mins[axis];
			}
			//if it's the surface plane
			if ( CM_PlaneEqual( &planes[facet->surfacePlane], plane, &flipped ) ) {
				continue;
			}
			// see if the plane is allready present
			for ( i = 0 ; i < facet->numBorders ; i++ ) {
				if ( CM_PlaneEqual( &planes[facet->borderPlanes[i]], plane, &flipped ) ) {
					break;
				}
			}

			if ( i == facet->numBorders ) {
				if ( facet->numBorders > 4 + 6 + 16 ) {
					Com_Printf( "ERROR: too many bevels\n" );
				}
				facet->borderPlanes[facet->numBorders] = CM_FindPlane2( plane, &flipped );
				facet->borderNoAdjust[facet->numBorders] = 0;
				facet->borderInward[facet->numBorders] = flipped;
				facet->numBorders++;
			}
		}
	}
	//
	// add the edge bevels
	//
	// test the non-axial plane edges
	for ( j = 0 ; j < w->numpoints ; j++ )
	{
		k = ( j + 1 ) % w->numpoints;
		VectorSubtract( w->p[j], w->p[k], vec );
		//if it's a degenerate edge
		if ( VectorNormalize( vec ) < 0.5 ) {
			continue;
		}
		CM_SnapVector( vec );
		for ( k = 0; k < 3 ; k++ )
			if ( vec[k] == -1 || vec[k] == 1 ) {
				break;
			}           // axial
		if ( k < 3 ) {
			continue;   // only test non-axial edges

		}
		// try the six possible slanted axials from this edge
		for ( axis = 0 ; axis < 3 ; axis++ )
		{
			for ( dir = -1 ; dir <= 1 ; dir += 2 )
			{
				// construct a plane
				VectorClear( vec2 );
				vec2[axis] = dir;
				CrossProduct( vec, vec2, plane );
				if ( VectorNormalize( plane ) < 0.5 ) {
					continue;
				}
				plane[3] = DotProduct( w->p[j], plane );

				// if all the points of the facet winding are
				// behind this plane, it is a proper edge bevel
				for ( l = 0 ; l < w->numpoints ; l++ )
				{
					d = DotProduct( w->p[l], plane ) - plane[3];
					if ( d > 0.1 ) {
						break;  // point in front
					}
				}
				if ( l < w->numpoints ) {
					continue;
				}

				//if it's the surface plane
				if ( CM_PlaneEqual( &planes[facet->surfacePlane], plane, &flipped ) ) {
					continue;
				}
				// see if the plane is allready present
				for ( i = 0 ; i < facet->numBorders ; i++ ) {
					if ( CM_PlaneEqual( &planes[facet->borderPlanes[i]], plane, &flipped ) ) {
						break;
					}
				}

				if ( i == facet->numBorders ) {
					if ( facet->numBorders > 4 + 6 + 16 ) {
						Com_Printf( "ERROR: too many bevels\n" );
					}
					facet->borderPlanes[facet->numBorders] = CM_FindPlane2( plane, &flipped );

					for ( k = 0 ; k < facet->numBorders ; k++ ) {
						if ( facet->borderPlanes[facet->numBorders] ==
							 facet->borderPlanes[k] ) {
							Com_Printf( "WARNING: bevel plane already used\n" );
						}
					}

					facet->borderNoAdjust[facet->numBorders] = 0;
					facet->borderInward[facet->numBorders] = flipped;
					//
					w2 = CopyWinding( w );
					Vector4Copy( planes[facet->borderPlanes[facet->numBorders]].plane, newplane );
					if ( !facet->borderInward[facet->numBorders] ) {
						VectorNegate( newplane, newplane );
						newplane[3] = -newplane[3];
					} //end if
					ChopWindingInPlace( &w2, newplane, newplane[3], 0.1f );
					if ( !w2 ) {
						// TTimo - can't stand this, useless and noisy
						//Com_DPrintf("WARNING: CM_AddFacetBevels... invalid bevel\n");
						continue;
					} else {
						FreeWinding( w2 );
					}
					//
					facet->numBorders++;
					//already got a bevel
//					break;
				}
			}
		}
	}
	FreeWinding( w );

#ifndef BSPC
	//add opposite plane
	facet->borderPlanes[facet->numBorders] = facet->surfacePlane;
	facet->borderNoAdjust[facet->numBorders] = 0;
	facet->borderInward[facet->numBorders] = qtrue;
	facet->numBorders++;
#endif //BSPC

}
示例#2
0
/*
==============
ClientEndFrame

Called at the end of each server frame for each connected client
A fast client will have multiple ClientThink for each ClientEdFrame,
while a slow client may have multiple ClientEndFrame between ClientThink.
==============
*/
void ClientEndFrame( gentity_t *ent ) {
	int			i;
	clientPersistant_t	*pers;

	if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {
		SpectatorClientEndFrame( ent );
		return;
	}

	pers = &ent->client->pers;

	// turn off any expired powerups
	for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
		if ( ent->client->ps.powerups[ i ] < level.time ) {
			ent->client->ps.powerups[ i ] = 0;
		}
	}

	// save network bandwidth
#if 0
	if ( !g_synchronousClients->integer && (ent->client->ps.pm_type == PM_NORMAL || ent->client->ps.pm_type == PM_FLOAT) ) {
		// FIXME: this must change eventually for non-sync demo recording
		VectorClear( ent->client->ps.viewangles );
	}
#endif

	//
	// If the end of unit layout is displayed, don't give
	// the player any normal movement attributes
	//
	if ( level.intermissiontime ) {
		return;
	}

	// burn from lava, etc
	P_WorldEffects (ent);

	// apply all the damage taken this frame
	P_DamageFeedback (ent);

	// add the EF_CONNECTION flag if we haven't gotten commands recently
	if ( level.time - ent->client->lastCmdTime > 1000 ) {
		ent->s.eFlags |= EF_CONNECTION;
	} else {
		ent->s.eFlags &= ~EF_CONNECTION;
	}

	ent->client->ps.stats[STAT_HEALTH] = ent->health;	// FIXME: get rid of ent->health...

	G_SetClientSound (ent);

	// set the latest infor
	if (g_smoothClients.integer) {
		BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue );
	}
	else {
		BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue );
	}
	SendPendingPredictableEvents( &ent->client->ps );

	// set the bit for the reachability area the client is currently in
//	i = trap_AAS_PointReachabilityAreaIndex( ent->client->ps.origin );
//	ent->client->areabits[i >> 3] |= 1 << (i & 7);
}
示例#3
0
文件: g_weapon.c 项目: ZFect/yquake2
void
bfg_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
	if (!self || !other)
	{
		G_FreeEdict(self);
		return;
	}

	if (other == self->owner)
	{
		return;
	}

	if (surf && (surf->flags & SURF_SKY))
	{
		G_FreeEdict(self);
		return;
	}

	if (self->owner && self->owner->client)
	{
		PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
	}

	/* core explosion - prevents firing it into the wall/floor */
	if (other->takedamage)
	{
		if (plane)
		{
			T_Damage(other, self, self->owner, self->velocity, self->s.origin,
					plane->normal, 200, 0, 0, MOD_BFG_BLAST);
		}
		else
		{
			T_Damage(other, self, self->owner, self->velocity, self->s.origin,
					vec3_origin, 200, 0, 0, MOD_BFG_BLAST);
		}
	}

	T_RadiusDamage(self, self->owner, 200, other, 100, MOD_BFG_BLAST);

	gi.sound(self, CHAN_VOICE, gi.soundindex(
					"weapons/bfg__x1b.wav"), 1, ATTN_NORM, 0);
	self->solid = SOLID_NOT;
	self->touch = NULL;
	VectorMA(self->s.origin, -1 * FRAMETIME, self->velocity, self->s.origin);
	VectorClear(self->velocity);
	self->s.modelindex = gi.modelindex("sprites/s_bfg3.sp2");
	self->s.frame = 0;
	self->s.sound = 0;
	self->s.effects &= ~EF_ANIM_ALLFAST;
	self->think = bfg_explode;
	self->nextthink = level.time + FRAMETIME;
	self->enemy = other;

	gi.WriteByte(svc_temp_entity);
	gi.WriteByte(TE_BFG_BIGEXPLOSION);
	gi.WritePosition(self->s.origin);
	gi.multicast(self->s.origin, MULTICAST_PVS);
}
qboolean PM_AdjustAngleForWallRun( gentity_t *ent, usercmd_t *ucmd, qboolean doMove )
{
	if (( ent->client->ps.legsAnim == BOTH_WALL_RUN_RIGHT || ent->client->ps.legsAnim == BOTH_WALL_RUN_LEFT ) && ent->client->ps.legsAnimTimer > 500 )
	{//wall-running and not at end of anim
		//stick to wall, if there is one
		vec3_t	rt, traceTo, mins = {ent->mins[0],ent->mins[1],0}, maxs = {ent->maxs[0],ent->maxs[1],24}, fwdAngles = {0, ent->client->ps.viewangles[YAW], 0};		
		trace_t	trace;
		float	dist, yawAdjust;

		AngleVectors( fwdAngles, NULL, rt, NULL );
		if ( ent->client->ps.legsAnim == BOTH_WALL_RUN_RIGHT )
		{
			dist = 128;
			yawAdjust = -90;
		}
		else
		{
			dist = -128;
			yawAdjust = 90;
		}
		VectorMA( ent->currentOrigin, dist, rt, traceTo );
		gi.trace( &trace, ent->currentOrigin, mins, maxs, traceTo, ent->s.number, ent->clipmask );
		if ( trace.fraction < 1.0f && trace.plane.normal[2] == 0.0f )
		{//still a vertical wall there
			//FIXME: don't pull around 90 turns
			//FIXME: simulate stepping up steps here, somehow?
			if ( ent->s.number || !player_locked )
			{
				if ( ent->client->ps.legsAnim == BOTH_WALL_RUN_RIGHT )
				{
					ucmd->rightmove = 127;
				}
				else
				{
					ucmd->rightmove = -127;
				}
			}
			if ( ucmd->upmove < 0 )
			{
				ucmd->upmove = 0;
			}
			if ( ent->NPC )
			{//invalid now
				VectorClear( ent->client->ps.moveDir );
			}
			//make me face perpendicular to the wall
			ent->client->ps.viewangles[YAW] = vectoyaw( trace.plane.normal )+yawAdjust;
			if ( ent->client->ps.viewEntity <= 0 || ent->client->ps.viewEntity >= ENTITYNUM_WORLD )
			{//don't clamp angles when looking through a viewEntity
				SetClientViewAngle( ent, ent->client->ps.viewangles );
			}
			ucmd->angles[YAW] = ANGLE2SHORT( ent->client->ps.viewangles[YAW] ) - ent->client->ps.delta_angles[YAW];
			if ( ent->s.number || !player_locked )
			{
				if ( doMove )
				{
					//push me forward
					vec3_t	fwd;
					float	zVel = ent->client->ps.velocity[2];
					if ( zVel > forceJumpStrength[FORCE_LEVEL_2]/2.0f )
					{
						zVel = forceJumpStrength[FORCE_LEVEL_2]/2.0f;
					}
					if ( ent->client->ps.legsAnimTimer > 500 )
					{//not at end of anim yet
						fwdAngles[YAW] = ent->client->ps.viewangles[YAW];
						AngleVectors( fwdAngles, fwd, NULL, NULL );
						//FIXME: or MA?
						float speed = 175;
						if ( ucmd->forwardmove < 0 )
						{//slower
							speed = 100;
						}
						else if ( ucmd->forwardmove > 0 )
						{
							speed = 250;//running speed
						}
						VectorScale( fwd, speed, ent->client->ps.velocity );
					}
					ent->client->ps.velocity[2] = zVel;//preserve z velocity
					VectorMA( ent->client->ps.velocity, -128, trace.plane.normal, ent->client->ps.velocity );
					//pull me toward the wall, too
					//VectorMA( ent->client->ps.velocity, dist, rt, ent->client->ps.velocity );
				}
			}
			ucmd->forwardmove = 0;
			return qtrue;
		}
		else if ( doMove )
		{//stop it
			if ( ent->client->ps.legsAnim == BOTH_WALL_RUN_RIGHT )
			{
				NPC_SetAnim( ent, SETANIM_BOTH, BOTH_WALL_RUN_RIGHT_STOP, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
			}
			else if ( ent->client->ps.legsAnim == BOTH_WALL_RUN_LEFT )
			{
				NPC_SetAnim( ent, SETANIM_BOTH, BOTH_WALL_RUN_LEFT_STOP, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
			}
		}
	}
	return qfalse;
}
示例#5
0
/*
* CopyToBodyQue
*/
static edict_t *CopyToBodyQue( edict_t *ent, edict_t *attacker, int damage )
{
	edict_t	*body;
	int contents;

	if( GS_RaceGametype() )
		return NULL;

	contents = G_PointContents( ent->s.origin );
	if( contents & CONTENTS_NODROP )
		return NULL;

	G_Client_UnlinkBodies( ent );

	// grab a body que and cycle to the next one
	body = &game.edicts[gs.maxclients + level.body_que + 1];
	level.body_que = ( level.body_que + 1 ) % BODY_QUEUE_SIZE;

	// send an effect on the removed body
	if( body->s.modelindex && body->s.type == ET_CORPSE )
		ThrowSmallPileOfGibs( body, 10 );

	GClip_UnlinkEntity( body );

	memset( body, 0, sizeof( edict_t ) ); //clean up garbage

	//init body edict
	G_InitEdict( body );
	body->classname = "body";
	body->health = ent->health;
	body->mass = ent->mass;
	body->r.owner = ent->r.owner;
	body->s.type = ent->s.type;
	body->s.team = ent->s.team;
	body->s.effects = 0;
	body->r.svflags = SVF_CORPSE;
	body->r.svflags &= ~SVF_NOCLIENT;
	body->activator = ent;
	if( g_deadbody_followkiller->integer )
		body->enemy = attacker;

	//use flat yaw
	body->s.angles[PITCH] = 0;
	body->s.angles[ROLL] = 0;
	body->s.angles[YAW] = ent->s.angles[YAW];
	body->s.modelindex2 = 0; // <-  is bodyOwner when in ET_CORPSE, but not in ET_GENERIC or ET_PLAYER
	body->s.weapon = 0;

	//copy player position and box size
	VectorCopy( ent->s.old_origin, body->s.old_origin );
	VectorCopy( ent->s.origin, body->s.origin );
	VectorCopy( ent->s.origin, body->olds.origin );
	VectorCopy( ent->r.mins, body->r.mins );
	VectorCopy( ent->r.maxs, body->r.maxs );
	VectorCopy( ent->r.absmin, body->r.absmin );
	VectorCopy( ent->r.absmax, body->r.absmax );
	VectorCopy( ent->r.size, body->r.size );
	VectorCopy( ent->velocity, body->velocity );
	body->r.maxs[2] = body->r.mins[2] + 8;

	body->r.solid = SOLID_YES;
	body->takedamage = DAMAGE_YES;
	body->r.clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP;
	body->movetype = MOVETYPE_TOSS;
	body->die = body_die;
	body->think = body_think; // body self destruction countdown

	if( ent->health < GIB_HEALTH
		|| meansOfDeath == MOD_ELECTROBOLT_S /* electrobolt always gibs */ )
	{
		ThrowSmallPileOfGibs( body, damage );

		// reset gib impulse
		VectorClear( body->velocity );
		ThrowClientHead( body, damage ); // sets ET_GIB

		body->s.frame = 0;
		body->nextThink = level.time + 3000 + random() * 3000;
		body->deadflag = DEAD_DEAD;
	}
	else if( ent->s.type == ET_PLAYER )
	{
		// copy the model
		body->s.type = ET_CORPSE;
		body->s.modelindex = ent->s.modelindex;
		body->s.bodyOwner = ent->s.number; // bodyOwner is the same as modelindex2
		body->s.skinnum = ent->s.skinnum;
		body->s.teleported = true;

		// launch the death animation on the body
		{
			static int i;
			i = ( i+1 )%3;
			G_AddEvent( body, EV_DIE, i, true );
			switch( i )
			{
			default:
			case 0:
				body->s.frame = ( ( BOTH_DEAD1&0x3F )|( BOTH_DEAD1&0x3F )<<6|( 0 &0xF )<<12 );
				break;
			case 1:
				body->s.frame = ( ( BOTH_DEAD2&0x3F )|( BOTH_DEAD2&0x3F )<<6|( 0 &0xF )<<12 );
				break;
			case 2:
				body->s.frame = ( ( BOTH_DEAD3&0x3F )|( BOTH_DEAD3&0x3F )<<6|( 0 &0xF )<<12 );
				break;
			}
		}

		body->think = body_ready;
		body->takedamage = DAMAGE_NO;
		body->r.solid = SOLID_NOT;
		body->nextThink = level.time + 500; // make damageable in 0.5 seconds
	}
	else // wasn't a player, just copy it's model
	{
		VectorClear( body->velocity );
		body->s.modelindex = ent->s.modelindex;
		body->s.frame = ent->s.frame;
		body->nextThink = level.time + 5000 + random()*10000;
	}

	GClip_LinkEntity( body );
	return body;
}
示例#6
0
/*
=================
ClientEndServerFrame

Called for each player at the end of the server frame
and right after spawning
=================
*/
void ClientEndServerFrame (edict_t *ent)
{
    float	bobtime;
    int		i;

    current_player = ent;
    current_client = ent->client;

    //
    // If the origin or velocity have changed since ClientThink(),
    // update the pmove values.  This will happen when the client
    // is pushed by a bmodel or kicked by an explosion.
    //
    // If it wasn't updated here, the view position would lag a frame
    // behind the body position when pushed -- "sinking into plats"
    //
    for (i=0 ; i<3 ; i++)
    {
        current_client->ps.pmove.origin[i] = ent->s.origin[i]*8.0;
        current_client->ps.pmove.velocity[i] = ent->velocity[i]*8.0;
    }

    //
    // If the end of unit layout is displayed, don't give
    // the player any normal movement attributes
    //
    if (level.intermissiontime)
    {
        // FIXME: add view drifting here?
        current_client->ps.blend[3] = 0;
        current_client->ps.fov = 90;
        G_SetStats (ent);
        return;
    }

    AngleVectors (ent->client->v_angle, forward, right, up);

    // burn from lava, etc
    P_WorldEffects ();

    //
    // set model angles from view angles so other things in
    // the world can tell which direction you are looking
    //
    if (ent->client->v_angle[PITCH] > 180)
        ent->s.angles[PITCH] = (-360 + ent->client->v_angle[PITCH])/3;
    else
        ent->s.angles[PITCH] = ent->client->v_angle[PITCH]/3;
    ent->s.angles[YAW] = ent->client->v_angle[YAW];
    ent->s.angles[ROLL] = 0;
    ent->s.angles[ROLL] = SV_CalcRoll (ent->s.angles, ent->velocity)*4;

    //
    // calculate speed and cycle to be used for
    // all cyclic walking effects
    //
    xyspeed = sqrt(ent->velocity[0]*ent->velocity[0] + ent->velocity[1]*ent->velocity[1]);

    if (xyspeed < 5)
    {
        bobmove = 0;
        current_client->bobtime = 0;	// start at beginning of cycle again
    }
    else if (ent->groundentity)
    {   // so bobbing only cycles when on ground
        if (xyspeed > 210)
            bobmove = 0.25;
        else if (xyspeed > 100)
            bobmove = 0.125;
        else
            bobmove = 0.0625;
    }

    bobtime = (current_client->bobtime += bobmove);

    if (current_client->ps.pmove.pm_flags & PMF_DUCKED)
        bobtime *= 4;

    bobcycle = (int)bobtime;
    bobfracsin = fabs(sin(bobtime*M_PI));

    // detect hitting the floor
    P_FallingDamage (ent);

    // apply all the damage taken this frame
    P_DamageFeedback (ent);

    // determine the view offsets
    SV_CalcViewOffset (ent);

    // determine the gun offsets
    SV_CalcGunOffset (ent);

    // determine the full screen color blend
    // must be after viewoffset, so eye contents can be
    // accurately determined
    // FIXME: with client prediction, the contents
    // should be determined by the client
    SV_CalcBlend (ent);

    // chase cam stuff
    if (ent->client->resp.spectator)
        G_SetSpectatorStats(ent);
    else
        G_SetStats (ent);

    G_CheckChaseStats(ent);

    G_SetClientEvent (ent);

    G_SetClientEffects (ent);

    G_SetClientSound (ent);

    G_SetClientFrame (ent);

    VectorCopy (ent->velocity, ent->client->oldvelocity);
    VectorCopy (ent->client->ps.viewangles, ent->client->oldviewangles);

    // clear weapon kicks
    VectorClear (ent->client->kick_origin);
    VectorClear (ent->client->kick_angles);

    // if the scoreboard is up, update it
    if (ent->client->showscores && !(level.framenum & 31) )
    {
        DeathmatchScoreboardMessage (ent, ent->enemy);
        gi.unicast (ent, false);
    }
}
示例#7
0
/*
==============
SV_CalcGunOffset
==============
*/
void SV_CalcGunOffset (edict_t *ent)
{
    int		i;
    float	delta;
    //ROGUE
    static gitem_t	*heatbeam;

    if (!heatbeam)
        heatbeam = FindItemByClassname ("weapon_plasmabeam");

    //ROGUE - heatbeam shouldn't bob so the beam looks right
    if (ent->client->pers.weapon != heatbeam)
    {
        // ROGUE
        // gun angles from bobbing
        ent->client->ps.gunangles[ROLL] = xyspeed * bobfracsin * 0.005;
        ent->client->ps.gunangles[YAW] = xyspeed * bobfracsin * 0.01;
        if (bobcycle & 1)
        {
            ent->client->ps.gunangles[ROLL] = -ent->client->ps.gunangles[ROLL];
            ent->client->ps.gunangles[YAW] = -ent->client->ps.gunangles[YAW];
        }

        ent->client->ps.gunangles[PITCH] = xyspeed * bobfracsin * 0.005;

        // gun angles from delta movement
        for (i=0 ; i<3 ; i++)
        {
            delta = ent->client->oldviewangles[i] - ent->client->ps.viewangles[i];
            if (delta > 180)
                delta -= 360;
            if (delta < -180)
                delta += 360;
            if (delta > 45)
                delta = 45;
            if (delta < -45)
                delta = -45;
            if (i == YAW)
                ent->client->ps.gunangles[ROLL] += 0.1*delta;
            ent->client->ps.gunangles[i] += 0.2 * delta;
        }
    }
    // ROGUE
    else
    {
        for (i=0; i<3; i++)
            ent->client->ps.gunangles[i] = 0;
    }
    //ROGUE

    // gun height
    VectorClear (ent->client->ps.gunoffset);
//	ent->ps->gunorigin[2] += bob;

    // gun_x / gun_y / gun_z are development tools
    for (i=0 ; i<3 ; i++)
    {
        ent->client->ps.gunoffset[i] += forward[i]*(gun_y->value);
        ent->client->ps.gunoffset[i] += right[i]*gun_x->value;
        ent->client->ps.gunoffset[i] += up[i]* (-gun_z->value);
    }
}
示例#8
0
文件: p_client.c 项目: AJenbo/Quake-2
/*
===========
PutClientInServer

Called when a player connects to a server or respawns in
a deathmatch.
============
*/
void PutClientInServer (edict_t *ent)
{
	vec3_t	mins = {-16, -16, -24};
	vec3_t	maxs = {16, 16, 32};
	int		index;
	vec3_t	spawn_origin, spawn_angles;
	gclient_t	*client;
	int		i;
	client_persistant_t	saved;
	client_respawn_t	resp;

	// find a spawn point
	// do it before setting health back up, so farthest
	// ranging doesn't count this client
	SelectSpawnPoint (ent, spawn_origin, spawn_angles);

	index = ent-g_edicts-1;
	client = ent->client;

	// deathmatch wipes most client data every spawn
	if (deathmatch->value)
	{
		char		userinfo[MAX_INFO_STRING];

		resp = client->resp;
		memcpy (userinfo, client->pers.userinfo, sizeof(userinfo));
		InitClientPersistant (client);
		ClientUserinfoChanged (ent, userinfo);
	}
	else if (coop->value)
	{
//		int			n;
		char		userinfo[MAX_INFO_STRING];

		resp = client->resp;
		memcpy (userinfo, client->pers.userinfo, sizeof(userinfo));
		// this is kind of ugly, but it's how we want to handle keys in coop
//		for (n = 0; n < game.num_items; n++)
//		{
//			if (itemlist[n].flags & IT_KEY)
//				resp.coop_respawn.inventory[n] = client->pers.inventory[n];
//		}
		resp.coop_respawn.game_helpchanged = client->pers.game_helpchanged;
		resp.coop_respawn.helpchanged = client->pers.helpchanged;
		client->pers = resp.coop_respawn;
		ClientUserinfoChanged (ent, userinfo);
		if (resp.score > client->pers.score)
			client->pers.score = resp.score;
	}
	else
	{
		memset (&resp, 0, sizeof(resp));
	}

	// clear everything but the persistant data
	saved = client->pers;
	memset (client, 0, sizeof(*client));
	client->pers = saved;
	if (client->pers.health <= 0)
		InitClientPersistant(client);
	client->resp = resp;

	// copy some data from the client to the entity
	FetchClientEntData (ent);

	// clear entity values
	ent->groundentity = NULL;
	ent->client = &game.clients[index];
	ent->takedamage = DAMAGE_AIM;
	ent->movetype = MOVETYPE_WALK;
	ent->viewheight = 22;
	ent->inuse = true;
	ent->classname = "player";
	ent->mass = 200;
	ent->solid = SOLID_BBOX;
	ent->deadflag = DEAD_NO;
	ent->air_finished = level.time + 12;
	ent->clipmask = MASK_PLAYERSOLID;
	ent->model = "players/male/tris.md2";
	ent->pain = player_pain;
	ent->die = player_die;
	ent->waterlevel = 0;
	ent->watertype = 0;
	ent->flags &= ~FL_NO_KNOCKBACK;
	ent->svflags &= ~SVF_DEADMONSTER;

	VectorCopy (mins, ent->mins);
	VectorCopy (maxs, ent->maxs);
	VectorClear (ent->velocity);

	// clear playerstate values
	memset (&ent->client->ps, 0, sizeof(client->ps));

	client->ps.pmove.origin[0] = spawn_origin[0]*8;
	client->ps.pmove.origin[1] = spawn_origin[1]*8;
	client->ps.pmove.origin[2] = spawn_origin[2]*8;

	if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV))
	{
		client->ps.fov = 90;
	}
	else
	{
		client->ps.fov = atoi(Info_ValueForKey(client->pers.userinfo, "fov"));
		if (client->ps.fov < 1)
			client->ps.fov = 90;
		else if (client->ps.fov > 160)
			client->ps.fov = 160;
	}

	client->ps.gunindex = gi.modelindex(client->pers.weapon->view_model);

	// clear entity state values
	ent->s.effects = 0;
	ent->s.modelindex = 255;		// will use the skin specified model
	ent->s.modelindex2 = 255;		// custom gun model
	// sknum is player num and weapon number
	// weapon number will be added in changeweapon
	ent->s.skinnum = ent - g_edicts - 1;

	ent->s.frame = 0;
	VectorCopy (spawn_origin, ent->s.origin);
	ent->s.origin[2] += 1;	// make sure off ground
	VectorCopy (ent->s.origin, ent->s.old_origin);

	// set the delta angle
	for (i=0 ; i<3 ; i++)
	{
		client->ps.pmove.delta_angles[i] = ANGLE2SHORT(spawn_angles[i] - client->resp.cmd_angles[i]);
	}

	ent->s.angles[PITCH] = 0;
	ent->s.angles[YAW] = spawn_angles[YAW];
	ent->s.angles[ROLL] = 0;
	VectorCopy (ent->s.angles, client->ps.viewangles);
	VectorCopy (ent->s.angles, client->v_angle);

	// spawn a spectator
	if (client->pers.spectator) {
		client->chase_target = NULL;

		client->resp.spectator = true;

		ent->movetype = MOVETYPE_NOCLIP;
		ent->solid = SOLID_NOT;
		ent->svflags |= SVF_NOCLIENT;
		ent->client->ps.gunindex = 0;
		gi.linkentity (ent);
		return;
	} else
		client->resp.spectator = false;

	if (!KillBox (ent))
	{	// could't spawn in?
	}

	gi.linkentity (ent);

	// force the current weapon up
	client->newweapon = client->pers.weapon;
	ChangeWeapon (ent);
}
示例#9
0
文件: p_client.c 项目: AJenbo/Quake-2
/*
==================
player_die
==================
*/
void player_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
	int		n;

	VectorClear (self->avelocity);

	self->takedamage = DAMAGE_YES;
	self->movetype = MOVETYPE_TOSS;

	self->s.modelindex2 = 0;	// remove linked weapon model

	self->s.angles[0] = 0;
	self->s.angles[2] = 0;

	self->s.sound = 0;
	self->client->weapon_sound = 0;

	self->maxs[2] = -8;

//	self->solid = SOLID_NOT;
	self->svflags |= SVF_DEADMONSTER;

	if (!self->deadflag)
	{
		self->client->respawn_time = level.time + 1.0;
		LookAtKiller (self, inflictor, attacker);
		self->client->ps.pmove.pm_type = PM_DEAD;
		ClientObituary (self, inflictor, attacker);
		TossClientWeapon (self);
		if (deathmatch->value)
			Cmd_Help_f (self);		// show scores

		// clear inventory
		// this is kind of ugly, but it's how we want to handle keys in coop
		for (n = 0; n < game.num_items; n++)
		{
			if (coop->value && itemlist[n].flags & IT_KEY)
				self->client->resp.coop_respawn.inventory[n] = self->client->pers.inventory[n];
			self->client->pers.inventory[n] = 0;
		}
	}

	// remove powerups
	self->client->quad_framenum = 0;
	self->client->invincible_framenum = 0;
	self->client->breather_framenum = 0;
	self->client->enviro_framenum = 0;
	self->flags &= ~FL_POWER_ARMOR;

	if (self->health < -40)
	{	// gib
		gi.sound (self, CHAN_BODY, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
		for (n= 0; n < 4; n++)
			ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
		ThrowClientHead (self, damage);

		self->takedamage = DAMAGE_NO;
	}
	else
	{	// normal death
		if (!self->deadflag)
		{
			static int i;

			i = (i+1)%3;
			// start a death animation
			self->client->anim_priority = ANIM_DEATH;
			if (self->client->ps.pmove.pm_flags & PMF_DUCKED)
			{
				self->s.frame = FRAME_crdeath1-1;
				self->client->anim_end = FRAME_crdeath5;
			}
			else switch (i)
			{
			case 0:
				self->s.frame = FRAME_death101-1;
				self->client->anim_end = FRAME_death106;
				break;
			case 1:
				self->s.frame = FRAME_death201-1;
				self->client->anim_end = FRAME_death206;
				break;
			case 2:
				self->s.frame = FRAME_death301-1;
				self->client->anim_end = FRAME_death308;
				break;
			}
			gi.sound (self, CHAN_VOICE, gi.soundindex(va("*death%i.wav", (rand()%4)+1)), 1, ATTN_NORM, 0);
		}
	}

	self->deadflag = DEAD_DEAD;

	gi.linkentity (self);
}
示例#10
0
void CL_Heatbeam (vec3_t start, vec3_t end)
{
	vec3_t		move;
	vec3_t		vec;
	float		len;
	int			j;
	cparticle_t	*p;
	vec3_t		forward, right, up;
	int			i;
	float		d, c, s;
	vec3_t		dir;
	float		ltime;
	float		step = 32.0, rstep;
	float		start_pt;
	float		rot;

	VectorCopy (start, move);
	VectorSubtract (end, start, vec);
	len = VectorNormalize (vec);

//	MakeNormalVectors (vec, right, up);
	VectorCopy (cl.v_forward, forward);
	VectorCopy (cl.v_right, right);
	VectorCopy (cl.v_up, up);
	VectorMA (move, -0.5, right, move);
	VectorMA (move, -0.5, up, move);

	for (i=0; i<8; i++)
	{
		if (!free_particles)
			return;

		p = free_particles;
		free_particles = p->next;
		p->next = active_particles;
		active_particles = p;
		
		p->time = cl.time;
		VectorClear (p->accel);
		
		d = crand()*M_PI;
		c = cos(d)*30;
		s = sin(d)*30;

		p->alpha = 1.0;
		p->alphavel = -5.0 / (1+frand());
		p->color = 223 - (rand()&7);

		for (j=0 ; j<3 ; j++)
		{
			p->org[j] = move[j];
		}
		VectorScale (vec, 450, p->vel);
		VectorMA (p->vel, c, right, p->vel);
		VectorMA (p->vel, s, up, p->vel);
	}
/*

	ltime = (float) cl.time/1000.0;
	start_pt = fmod(ltime*16.0,step);
	VectorMA (move, start_pt, vec, move);

	VectorScale (vec, step, vec);

//	Com_Printf ("%f\n", ltime);
	rstep = M_PI/12.0;
	for (i=start_pt ; i<len ; i+=step)
	{
		if (i>step*5) // don't bother after the 5th ring
			break;

		for (rot = 0; rot < M_PI*2; rot += rstep)
		{
			if (!free_particles)
				return;

			p = free_particles;
			free_particles = p->next;
			p->next = active_particles;
			active_particles = p;
			
			p->time = cl.time;
			VectorClear (p->accel);
//			rot+= fmod(ltime, 12.0)*M_PI;
//			c = cos(rot)/2.0;
//			s = sin(rot)/2.0;
			c = cos(rot)/1.5;
			s = sin(rot)/1.5;
			
			// trim it so it looks like it's starting at the origin
			if (i < 10)
			{
				VectorScale (right, c*(i/10.0), dir);
				VectorMA (dir, s*(i/10.0), up, dir);
			}
			else
			{
				VectorScale (right, c, dir);
				VectorMA (dir, s, up, dir);
			}
		
			p->alpha = 0.5;
	//		p->alphavel = -1.0 / (1+frand()*0.2);
			p->alphavel = -1000.0;
	//		p->color = 0x74 + (rand()&7);
			p->color = 223 - (rand()&7);
			for (j=0 ; j<3 ; j++)
			{
				p->org[j] = move[j] + dir[j]*3;
	//			p->vel[j] = dir[j]*6;
				p->vel[j] = 0;
			}
		}
		VectorAdd (move, vec, move);
	}
*/
}
示例#11
0
/*
===============
R_RocketTrail

===============
*/
void R_RocketTrail (vec3_t start, vec3_t end, int type)
{
	vec3_t	vec, dist;
	float	len, size, lifetime;
	int			j;
	particle_t	*p;
	static int tracercount;

	VectorSubtract (end, start, vec);
	len = VectorNormalize (vec);
	dist[0] = vec[0];
	dist[1] = vec[1];
	dist[2] = vec[2];
	size = 1;
	lifetime = 2;
	switch (type)
	{
		case 9:
		// Spit
			break;

		case 8:
		// Ice
			size *= 5 * 3;
			dist[0] *= 5 * 3;
			dist[1] *= 5 * 3;
			dist[2] *= 5 * 3;
			break;

		case rt_acidball:
		// Ice
			size = 5;
			lifetime = .8;
			break;

		default:
			size = 3;
			dist[0] *= 3;
			dist[1] *= 3;
			dist[2] *= 3;
			break;
	}

	while (len > 0)
	{
		len -= size;

		p = AllocParticle();
		if (!p)
			return;

		VectorClear (p->vel);
		p->die = cl.time + lifetime;

		switch (type)
		{
			case rt_rocket_trail:
			// rocket trail
				p->ramp = rand() & 3;
				p->color = ramp3[(int)p->ramp];
				p->type = pt_fire;
				for (j = 0; j < 3; j++)
					p->org[j] = start[j] + ((rand() % 6) - 3);
				break;

			case rt_smoke:
			// smoke smoke
				p->ramp = (rand() & 3) + 2;
				p->color = ramp3[(int)p->ramp];
				p->type = pt_fire;
				for (j = 0; j < 3; j++)
					p->org[j] = start[j] + ((rand() % 6) - 3);
				break;

			case rt_blood:
			// blood
				p->type = pt_slowgrav;
				p->color = 134 + (rand() & 7);
				for (j = 0; j < 3; j++)
					p->org[j] = start[j] + ((rand() % 6) - 3);
				break;

			case rt_tracer:;
			case rt_tracer2:;
			// tracer
				p->die = cl.time + 0.5;
				p->type = pt_static;
				if (type == 3)
					p->color = 130 + (rand() & 6);	// 243 + (rand() & 3);
				else
					p->color = 230 + ((tracercount & 4) << 1);

				tracercount++;

				VectorCopy (start, p->org);
				if (tracercount & 1)
				{
					p->vel[0] = 30 * vec[1];
					p->vel[1] = 30 * -vec[0];
				}
				else
				{
					p->vel[0] = 30 * -vec[1];
					p->vel[1] = 30 * vec[0];
				}
				break;

			case rt_slight_blood:
			// slight blood
				p->type = pt_slowgrav;
				p->color = 134 + (rand() & 7);
				for (j = 0; j < 3; j++)
					p->org[j] = start[j] + ((rand() % 6) - 3);
				len -= size;
				break;

			case rt_bloodshot:
			// bloodshot trail
				p->type = pt_darken;
				p->color = 136 + (rand() & 5);
				for (j = 0; j < 3; j++)
					p->org[j] = start[j] + ((rand() & 3) - 2);
				len -= size;
				break;

			case rt_voor_trail:
			// voor trail
				p->color = 9*16 + 8 + (rand() & 3);
				p->type = pt_static;
				p->die = cl.time + 0.3;
				for (j = 0; j < 3; j++)
					p->org[j] = start[j] + ((rand() & 15) - 8);
				break;

			case rt_fireball:
			// Fireball
				p->ramp = rand() & 3;
				p->color = ramp4[(int)(p->ramp)];
				p->type = pt_fireball;
				for (j = 0; j < 3; j++)
					p->org[j] = start[j] + ((rand() & 3) - 2);
				p->org[2] += 2;	// compensate for model
				p->vel[0] = (rand() % 200) - 100;
				p->vel[1] = (rand() % 200) - 100;
				p->vel[2] = (rand() % 200) - 100;
				break;

			case rt_acidball:
			// Acid ball
				p->ramp = rand() & 3;
				p->color = ramp10[(int)(p->ramp)];
				p->type = pt_acidball;
				p->die = cl.time + 0.5;
				for (j = 0; j < 3; j++)
					p->org[j] = start[j] + ((rand() & 3) - 2);
				p->org[2] += 2;	// compensate for model
				p->vel[0] = (rand() % 40) - 20;
				p->vel[1] = (rand() % 40) - 20;
				p->vel[2] = (rand() % 40) - 20;
				break;

			case rt_ice:
			// Ice
				p->ramp = rand() & 3;
				p->color = ramp5[(int)(p->ramp)];
				p->type = pt_ice;
				for (j = 0; j < 3; j++)
					p->org[j] = start[j] + ((rand() & 3) - 2);
				p->org[2] += 2;	// compensate for model
				p->vel[0] = (rand() % 16) - 8;
				p->vel[1] = (rand() % 16) - 8;
				p->vel[2] = (rand() % 20) - 40;
				break;

			case rt_spit:
			// Spit
				p->ramp = rand() & 3;
				p->color = ramp6[(int)(p->ramp)];
				p->type = pt_spit;
				for (j = 0; j < 3; j++)
					p->org[j] = start[j] + ((rand() & 3) - 2);
				p->org[2] += 2;	// compensate for model
				p->vel[0] = (rand() % 10) - 5;
				p->vel[1] = (rand() % 10) - 5;
				p->vel[2] = (rand() % 10);
				break;

			case rt_spell:
			// Spell
				p->ramp = rand() & 3;
				p->color = ramp6[(int)(p->ramp)];
				p->type = pt_spell;
				for (j = 0; j < 3; j++)
					p->org[j] = start[j] + ((rand() & 3) - 2);
				p->vel[0] = (rand() % 10) - 5;
				p->vel[1] = (rand() % 10) - 5;
				p->vel[2] = (rand() % 10);
				p->vel[0] = vec[0] * -10;
				p->vel[1] = vec[1] * -10;
				p->vel[2] = vec[2] * -10;
				break;

			case rt_vorpal:
			// vorpal missile
				p->type = pt_vorpal;
				p->color = 44 + (rand() & 3) + 256;
				for (j = 0; j < 2; j++)
					p->org[j] = start[j] + ((rand() % 48) - 24);

				p->org[2] = start[2] + ((rand() & 15) - 8);

				break;

			case rt_setstaff:
			// set staff
				p->type = pt_setstaff;
				p->color = ramp9[0];
				p->ramp = rand() & 3;

				for (j = 0; j < 2; j++)
					p->org[j] = start[j] + ((rand() % 6) - 3);

				p->org[2] = start[2] + ((rand() % 10) - 5);

				p->vel[0] = (rand() & 7) - 4;
				p->vel[1] = (rand() & 7) - 4;
				break;

			case rt_magicmissile:
			// magic missile
				p->type = pt_magicmissile;
				p->color = 148 + (rand() & 11);
				p->ramp = rand() & 3;
				for (j = 0; j < 2; j++)
					p->org[j] = start[j] + ((rand() % 48) - 24);

				p->org[2] = start[2] + ((rand() % 48) - 24);

				p->vel[2] = -((rand() & 15) + 8);
				break;

			case rt_boneshard:
			// bone shard
				p->type = pt_boneshard;
				p->color = 368 + (rand() & 16);
				for (j = 0; j < 2; j++)
					p->org[j] = start[j] + ((rand() % 48) - 24);

				p->org[2] = start[2] + ((rand() % 48) - 24);

				p->vel[2] = -((rand() & 15) + 8);
				break;

			case rt_scarab:
			// scarab staff
				p->type = pt_scarab;
				p->color = 250 + (rand() & 3);
				for (j = 0; j < 3; j++)
					p->org[j] = start[j] + (rand() & 7);

				p->vel[2] = -(rand() & 7);
				break;
		}

		VectorAdd (start, dist, start);
	}
}
示例#12
0
//void CL_Heatbeam (vec3_t start, vec3_t end)
void CL_Heatbeam (vec3_t start, vec3_t forward)
{
	vec3_t		move;
	vec3_t		vec;
	float		len;
	int			j;
	cparticle_t	*p;
	vec3_t		right, up;
	int			i;
	float		c, s;
	vec3_t		dir;
	float		ltime;
	float		step = 32.0, rstep;
	float		start_pt;
	float		rot;
	float		variance;
	vec3_t		end;

	VectorMA (start, 4096, forward, end);

	VectorCopy (start, move);
	VectorSubtract (end, start, vec);
	len = VectorNormalize (vec);

	// FIXME - pmm - these might end up using old values?
//	MakeNormalVectors (vec, right, up);
	VectorCopy (cl.v_right, right);
	VectorCopy (cl.v_up, up);
	if (vidref_val == VIDREF_GL)
	{ // GL mode
		VectorMA (move, -0.5, right, move);
		VectorMA (move, -0.5, up, move);
	}
	// otherwise assume SOFT

	ltime = (float) cl.time/1000.0;
	start_pt = fmod(ltime*96.0,step);
	VectorMA (move, start_pt, vec, move);

	VectorScale (vec, step, vec);

//	Com_Printf ("%f\n", ltime);
	rstep = M_PI/10.0;
	for (i=start_pt ; i<len ; i+=step)
	{
		if (i>step*5) // don't bother after the 5th ring
			break;

		for (rot = 0; rot < M_PI*2; rot += rstep)
		{

			if (!free_particles)
				return;

			p = free_particles;
			free_particles = p->next;
			p->next = active_particles;
			active_particles = p;
			
			p->time = cl.time;
			VectorClear (p->accel);
//			rot+= fmod(ltime, 12.0)*M_PI;
//			c = cos(rot)/2.0;
//			s = sin(rot)/2.0;
//			variance = 0.4 + ((float)rand()/(float)RAND_MAX) *0.2;
			variance = 0.5;
			c = cos(rot)*variance;
			s = sin(rot)*variance;
			
			// trim it so it looks like it's starting at the origin
			if (i < 10)
			{
				VectorScale (right, c*(i/10.0), dir);
				VectorMA (dir, s*(i/10.0), up, dir);
			}
			else
			{
				VectorScale (right, c, dir);
				VectorMA (dir, s, up, dir);
			}
		
			p->alpha = 0.5;
	//		p->alphavel = -1.0 / (1+frand()*0.2);
			p->alphavel = -1000.0;
	//		p->color = 0x74 + (rand()&7);
			p->color = 223 - (rand()&7);
			for (j=0 ; j<3 ; j++)
			{
				p->org[j] = move[j] + dir[j]*3;
	//			p->vel[j] = dir[j]*6;
				p->vel[j] = 0;
			}
		}
		VectorAdd (move, vec, move);
	}
}
示例#13
0
void CL_Heatbeam (vec3_t start, vec3_t end)
{
	vec3_t		move;
	vec3_t		vec;
	float		len;
	int			j,k;
	cparticle_t	*p;
	vec3_t		right, up;
	int			i;
	float		d, c, s;
	vec3_t		dir;
	float		ltime;
	float		step = 5.0;

	VectorCopy (start, move);
	VectorSubtract (end, start, vec);
	len = VectorNormalize (vec);

//	MakeNormalVectors (vec, right, up);
	VectorCopy (cl.v_right, right);
	VectorCopy (cl.v_up, up);
	VectorMA (move, -1, right, move);
	VectorMA (move, -1, up, move);

	VectorScale (vec, step, vec);
	ltime = (float) cl.time/1000.0;

//	for (i=0 ; i<len ; i++)
	for (i=0 ; i<len ; i+=step)
	{
		d = i * 0.1 - fmod(ltime,16.0)*M_PI;
		c = cos(d)/1.75;
		s = sin(d)/1.75;
#ifdef DOUBLE_SCREW		
		for (k=-1; k<2; k+=2)
		{
#else
		k=1;
#endif
			if (!free_particles)
				return;

			p = free_particles;
			free_particles = p->next;
			p->next = active_particles;
			active_particles = p;
			
			p->time = cl.time;
			VectorClear (p->accel);

			p->alpha = 0.5;
	//		p->alphavel = -1.0 / (1+frand()*0.2);
			// only last one frame!
			p->alphavel = INSTANT_PARTICLE;
	//		p->color = 0x74 + (rand()&7);
//			p->color = 223 - (rand()&7);
			p->color = 223;
//			p->color = 240;

			// trim it so it looks like it's starting at the origin
			if (i < 10)
			{
				VectorScale (right, c*(i/10.0)*k, dir);
				VectorMA (dir, s*(i/10.0)*k, up, dir);
			}
			else
			{
				VectorScale (right, c*k, dir);
				VectorMA (dir, s*k, up, dir);
			}
			
			for (j=0 ; j<3 ; j++)
			{
				p->org[j] = move[j] + dir[j]*3;
	//			p->vel[j] = dir[j]*6;
				p->vel[j] = 0;
			}
#ifdef DOUBLE_SCREW
		}
#endif
		VectorAdd (move, vec, move);
	}
}
示例#14
0
//===========================================================================
// recursive subdivision of the line by the BSP tree.
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
aas_trace_t AAS_TraceClientBBox( vec3_t start, vec3_t end, int presencetype,
								 int passent ) {
	int side, nodenum, tmpplanenum;
	float front, back, frac;
	vec3_t cur_start, cur_end, cur_mid, v1, v2;
	aas_tracestack_t tracestack[127];
	aas_tracestack_t *tstack_p;
	aas_node_t *aasnode;
	aas_plane_t *plane;
	aas_trace_t trace;

	//clear the trace structure
	memset( &trace, 0, sizeof( aas_trace_t ) );

	if ( !( *aasworld ).loaded ) {
		return trace;
	}

	tstack_p = tracestack;
	//we start with the whole line on the stack
	VectorCopy( start, tstack_p->start );
	VectorCopy( end, tstack_p->end );
	tstack_p->planenum = 0;
	//start with node 1 because node zero is a dummy for a solid leaf
	tstack_p->nodenum = 1;      //starting at the root of the tree
	tstack_p++;

	while ( 1 )
	{
		//pop up the stack
		tstack_p--;
		//if the trace stack is empty (ended up with a piece of the
		//line to be traced in an area)
		if ( tstack_p < tracestack ) {
			tstack_p++;
			//nothing was hit
			trace.startsolid = qfalse;
			trace.fraction = 1.0;
			//endpos is the end of the line
			VectorCopy( end, trace.endpos );
			//nothing hit
			trace.ent = 0;
			trace.area = 0;
			trace.planenum = 0;
			return trace;
		} //end if
		  //number of the current node to test the line against
		nodenum = tstack_p->nodenum;
		//if it is an area
		if ( nodenum < 0 ) {
#ifdef AAS_SAMPLE_DEBUG
			if ( -nodenum > ( *aasworld ).numareasettings ) {
				botimport.Print( PRT_ERROR, "AAS_TraceBoundingBox: -nodenum out of range\n" );
				return trace;
			} //end if
#endif //AAS_SAMPLE_DEBUG
			//botimport.Print(PRT_MESSAGE, "areanum = %d, must be %d\n", -nodenum, AAS_PointAreaNum(start));
			//if can't enter the area because it hasn't got the right presence type
			if ( !( ( *aasworld ).areasettings[-nodenum].presencetype & presencetype ) ) {
				//if the start point is still the initial start point
				//NOTE: no need for epsilons because the points will be
				//exactly the same when they're both the start point
				if ( tstack_p->start[0] == start[0] &&
					 tstack_p->start[1] == start[1] &&
					 tstack_p->start[2] == start[2] )
				{
					trace.startsolid = qtrue;
					trace.fraction = 0.0;
					VectorClear(v1);
				} //end if
				else
				{
					trace.startsolid = qfalse;
					VectorSubtract( end, start, v1 );
					VectorSubtract( tstack_p->start, start, v2 );
					trace.fraction = VectorLength( v2 ) / VectorNormalize( v1 );
					VectorMA( tstack_p->start, -0.125, v1, tstack_p->start );
				} //end else
				VectorCopy( tstack_p->start, trace.endpos );
				trace.ent = 0;
				trace.area = -nodenum;
//				VectorSubtract(end, start, v1);
				trace.planenum = tstack_p->planenum;
				//always take the plane with normal facing towards the trace start
				plane = &( *aasworld ).planes[trace.planenum];
				if ( DotProduct( v1, plane->normal ) > 0 ) {
					trace.planenum ^= 1;
				}
				return trace;
			} //end if
			else
			{
				if ( passent >= 0 ) {
					if ( AAS_AreaEntityCollision( -nodenum, tstack_p->start,
												  tstack_p->end, presencetype, passent,
												  &trace ) ) {
						if ( !trace.startsolid ) {
							VectorSubtract( end, start, v1 );
							VectorSubtract( trace.endpos, start, v2 );
							trace.fraction = VectorLength( v2 ) / VectorLength( v1 );
						} //end if
						return trace;
					} //end if
				} //end if
			} //end else
			trace.lastarea = -nodenum;
			continue;
		} //end if
		  //if it is a solid leaf
		if ( !nodenum ) {
			//if the start point is still the initial start point
			//NOTE: no need for epsilons because the points will be
			//exactly the same when they're both the start point
			if ( tstack_p->start[0] == start[0] &&
				 tstack_p->start[1] == start[1] &&
				 tstack_p->start[2] == start[2] )
			{
				trace.startsolid = qtrue;
				trace.fraction = 0.0;
				VectorClear(v1);
			} //end if
			else
			{
				trace.startsolid = qfalse;
				VectorSubtract( end, start, v1 );
				VectorSubtract( tstack_p->start, start, v2 );
				trace.fraction = VectorLength( v2 ) / VectorNormalize( v1 );
				VectorMA( tstack_p->start, -0.125, v1, tstack_p->start );
			} //end else
			VectorCopy( tstack_p->start, trace.endpos );
			trace.ent = 0;
			trace.area = 0; //hit solid leaf
//			VectorSubtract(end, start, v1);
			trace.planenum = tstack_p->planenum;
			//always take the plane with normal facing towards the trace start
			plane = &( *aasworld ).planes[trace.planenum];
			if ( DotProduct( v1, plane->normal ) > 0 ) {
				trace.planenum ^= 1;
			}
			return trace;
		} //end if
#ifdef AAS_SAMPLE_DEBUG
		if ( nodenum > ( *aasworld ).numnodes ) {
			botimport.Print( PRT_ERROR, "AAS_TraceBoundingBox: nodenum out of range\n" );
			return trace;
		} //end if
#endif //AAS_SAMPLE_DEBUG
	   //the node to test against
		aasnode = &( *aasworld ).nodes[nodenum];
		//start point of current line to test against node
		VectorCopy( tstack_p->start, cur_start );
		//end point of the current line to test against node
		VectorCopy( tstack_p->end, cur_end );
		//the current node plane
		plane = &( *aasworld ).planes[aasnode->planenum];

		switch ( plane->type )
		{/*FIXME: wtf doesn't this work? obviously the axial node planes aren't always facing positive!!!
			//check for axial planes
			case PLANE_X:
			{
				front = cur_start[0] - plane->dist;
				back = cur_end[0] - plane->dist;
				break;
			} //end case
			case PLANE_Y:
			{
				front = cur_start[1] - plane->dist;
				back = cur_end[1] - plane->dist;
				break;
			} //end case
			case PLANE_Z:
			{
				front = cur_start[2] - plane->dist;
				back = cur_end[2] - plane->dist;
				break;
			} //end case*/
		default:     //gee it's not an axial plane
		{
			front = DotProduct( cur_start, plane->normal ) - plane->dist;
			back = DotProduct( cur_end, plane->normal ) - plane->dist;
			break;
		}     //end default
		} //end switch

		//calculate the hitpoint with the node (split point of the line)
		//put the crosspoint TRACEPLANE_EPSILON pixels on the near side
		if ( front < 0 ) {
			frac = ( front + TRACEPLANE_EPSILON ) / ( front - back );
		} else { frac = ( front - TRACEPLANE_EPSILON ) / ( front - back );}
		//if the whole to be traced line is totally at the front of this node
		//only go down the tree with the front child
		if ( ( front >= -ON_EPSILON && back >= -ON_EPSILON ) ) {
			//keep the current start and end point on the stack
			//and go down the tree with the front child
			tstack_p->nodenum = aasnode->children[0];
			tstack_p++;
			if ( tstack_p >= &tracestack[127] ) {
				botimport.Print( PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n" );
				return trace;
			} //end if
		} //end if
		  //if the whole to be traced line is totally at the back of this node
		  //only go down the tree with the back child
		else if ( ( front < ON_EPSILON && back < ON_EPSILON ) ) {
			//keep the current start and end point on the stack
			//and go down the tree with the back child
			tstack_p->nodenum = aasnode->children[1];
			tstack_p++;
			if ( tstack_p >= &tracestack[127] ) {
				botimport.Print( PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n" );
				return trace;
			} //end if
		} //end if
		  //go down the tree both at the front and back of the node
		else
		{
			tmpplanenum = tstack_p->planenum;
			//
			if ( frac < 0 ) {
				frac = 0.001; //0
			} else if ( frac > 1 )                         {
				frac = 0.999; //1
			}
			//frac = front / (front-back);
			//
			cur_mid[0] = cur_start[0] + ( cur_end[0] - cur_start[0] ) * frac;
			cur_mid[1] = cur_start[1] + ( cur_end[1] - cur_start[1] ) * frac;
			cur_mid[2] = cur_start[2] + ( cur_end[2] - cur_start[2] ) * frac;

//			AAS_DrawPlaneCross(cur_mid, plane->normal, plane->dist, plane->type, LINECOLOR_RED);
			//side the front part of the line is on
			side = front < 0;
			//first put the end part of the line on the stack (back side)
			VectorCopy( cur_mid, tstack_p->start );
			//not necesary to store because still on stack
			//VectorCopy(cur_end, tstack_p->end);
			tstack_p->planenum = aasnode->planenum;
			tstack_p->nodenum = aasnode->children[!side];
			tstack_p++;
			if ( tstack_p >= &tracestack[127] ) {
				botimport.Print( PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n" );
				return trace;
			} //end if
			  //now put the part near the start of the line on the stack so we will
			  //continue with thats part first. This way we'll find the first
			  //hit of the bbox
			VectorCopy( cur_start, tstack_p->start );
			VectorCopy( cur_mid, tstack_p->end );
			tstack_p->planenum = tmpplanenum;
			tstack_p->nodenum = aasnode->children[side];
			tstack_p++;
			if ( tstack_p >= &tracestack[127] ) {
				botimport.Print( PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n" );
				return trace;
			} //end if
		} //end else
	} //end while
//	return trace;
} //end of the function AAS_TraceClientBBox
示例#15
0
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void AAS_ShowReachability(aas_reachability_t *reach)
{
	vec3_t dir, cmdmove, velocity;
	float speed, zvel;
	aas_clientmove_t move;
	int contentmask = BOTMASK_SOLID; // ZTM: FIXME: Get contentmask from Game VM!

	AAS_ShowAreaPolygons(reach->areanum, 5, qtrue);
	//AAS_ShowArea(reach->areanum, qtrue);
	AAS_DrawArrow(reach->start, reach->end, LINECOLOR_BLUE, LINECOLOR_YELLOW);
	//
	if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP ||
		(reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_WALKOFFLEDGE)
	{
		AAS_HorizontalVelocityForJump(aassettings.phys_jumpvel, reach->start, reach->end, &speed);
		//
		VectorSubtract(reach->end, reach->start, dir);
		dir[2] = 0;
		VectorNormalize(dir);
		//set the velocity
		VectorScale(dir, speed, velocity);
		//set the command movement
		VectorClear(cmdmove);
		cmdmove[2] = aassettings.phys_jumpvel;
		//
		AAS_PredictPlayerMovement(&move, -1, reach->start, PRESENCE_NORMAL, qtrue,
									velocity, cmdmove, 3, 30, 0.1f,
									SE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME|
									SE_ENTERLAVA|SE_HITGROUNDDAMAGE,
									0, qtrue, contentmask);
		//
		if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP)
		{
			AAS_JumpReachRunStart(reach, dir, contentmask);
			AAS_DrawCross(dir, 4, LINECOLOR_BLUE);
		} //end if
	} //end if
	else if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_ROCKETJUMP)
	{
		zvel = AAS_RocketJumpZVelocity(reach->start, contentmask);
		AAS_HorizontalVelocityForJump(zvel, reach->start, reach->end, &speed);
		//
		VectorSubtract(reach->end, reach->start, dir);
		dir[2] = 0;
		VectorNormalize(dir);
		//get command movement
		VectorScale(dir, speed, cmdmove);
		VectorSet(velocity, 0, 0, zvel);
		//
		AAS_PredictPlayerMovement(&move, -1, reach->start, PRESENCE_NORMAL, qtrue,
									velocity, cmdmove, 30, 30, 0.1f,
									SE_ENTERWATER|SE_ENTERSLIME|
									SE_ENTERLAVA|SE_HITGROUNDDAMAGE|
									SE_TOUCHJUMPPAD|SE_HITGROUNDAREA,
									reach->areanum, qtrue, contentmask);
	} //end else if
	else if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMPPAD)
	{
		VectorSet(cmdmove, 0, 0, 0);
		//
		VectorSubtract(reach->end, reach->start, dir);
		dir[2] = 0;
		VectorNormalize(dir);
		//set the velocity
		//NOTE: the edgenum is the horizontal velocity
		VectorScale(dir, reach->edgenum, velocity);
		//NOTE: the facenum is the Z velocity
		velocity[2] = reach->facenum;
		//
		AAS_PredictPlayerMovement(&move, -1, reach->start, PRESENCE_NORMAL, qtrue,
									velocity, cmdmove, 30, 30, 0.1f,
									SE_ENTERWATER|SE_ENTERSLIME|
									SE_ENTERLAVA|SE_HITGROUNDDAMAGE|
									SE_TOUCHJUMPPAD|SE_HITGROUNDAREA,
									reach->areanum, qtrue, contentmask);
	} //end else if
} //end of the function AAS_ShowReachability
/*
=============
DeformText

Change a polygon into a bunch of text polygons
=============
*/
void DeformText(const char *text)
{
	int    i;
	vec3_t origin, width, height;
	int    len;
	int    ch;
	byte   color[4];
	float  bottom, top;
	vec3_t mid;
	int    row, col;
	float  frow, fcol, size;

	height[0] = 0;
	height[1] = 0;
	height[2] = -1;
	CrossProduct(tess.normal[0].v, height, width);

	// find the midpoint of the box
	VectorClear(mid);
	bottom = 999999;
	top    = -999999;
	for (i = 0 ; i < 4 ; i++)
	{
		VectorAdd(tess.xyz[i].v, mid, mid);
		if (tess.xyz[i].v[2] < bottom)
		{
			bottom = tess.xyz[i].v[2];
		}
		if (tess.xyz[i].v[2] > top)
		{
			top = tess.xyz[i].v[2];
		}
	}
	VectorScale(mid, 0.25f, origin);

	// determine the individual character size
	height[0] = 0;
	height[1] = 0;
	height[2] = (top - bottom) * 0.5f;

	VectorScale(width, height[2] * -0.75f, width);

	// determine the starting position
	len = strlen(text);
	VectorMA(origin, (len - 1), width, origin);

	// clear the shader indexes
	tess.numIndexes  = 0;
	tess.numVertexes = 0;

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

	// draw each character
	for (i = 0 ; i < len ; i++)
	{
		ch  = text[i];
		ch &= 255;

		if (ch != ' ')
		{
			row = ch >> 4;
			col = ch & 15;

			frow = row * 0.0625f;
			fcol = col * 0.0625f;
			size = 0.0625f;

			RB_AddQuadStampExt(origin, width, height, color, fcol, frow, fcol + size, frow + size);
		}
		VectorMA(origin, -2, width, origin);
	}
示例#17
0
文件: g_weapon.c 项目: aroth/LosGRQ
void fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage)
{
	edict_t	*rocket;
	edict_t *rocket2;

	rocket = G_Spawn();
	VectorCopy (start, rocket->s.origin);
	VectorCopy (dir, rocket->movedir);
	vectoangles (dir, rocket->s.angles);
	VectorScale (dir, speed, rocket->velocity);
	rocket->movetype = MOVETYPE_FLYMISSILE;
	rocket->clipmask = MASK_SHOT;
	rocket->solid = SOLID_BBOX;
	rocket->s.effects |= EF_ROCKET;
	VectorClear (rocket->mins);
	VectorClear (rocket->maxs);
	rocket->s.modelindex = gi.modelindex("models/objects/bomb/tris.md2");
	rocket->owner = self;
	rocket->touch = rocket_touch;
	rocket->nextthink = level.time + 8000/speed;
	rocket->think = G_FreeEdict;
	rocket->dmg = damage;
	rocket->radius_dmg = radius_damage;
	rocket->dmg_radius = damage_radius;
	rocket->s.sound = gi.soundindex ("weapons/rockfly.wav");
	rocket->classname = "rocket";

	if (self->client)
		check_dodge (self, rocket->s.origin, dir, speed);

	gi.linkentity (rocket);

		/*
	// rocket 2

	rocket2 = G_Spawn();
	VectorCopy (start, rocket2->s.origin);
	VectorCopy (dir, rocket2->movedir);
	vectoangles (dir, rocket2->s.angles);
	VectorScale (dir, speed - 100, rocket2->velocity);
	rocket2->movetype = MOVETYPE_FLYMISSILE;
	rocket2->clipmask = MASK_SHOT;
	rocket2->solid = SOLID_BBOX;
	rocket2->s.effects |= EF_ROCKET;
	VectorClear (rocket2->mins);
	VectorClear (rocket2->maxs);
	rocket2->s.modelindex = gi.modelindex("models/objects/bomb/tris.md2");
	rocket2->owner = self;
	rocket2->touch = rocket_touch;
	rocket2->nextthink = level.time + 8000/speed;
	rocket2->think = G_FreeEdict;
	rocket2->dmg = damage;
	rocket2->radius_dmg = radius_damage;
	rocket2->dmg_radius = damage_radius;
	rocket2->s.sound = gi.soundindex ("weapons/rockfly.wav");
	rocket2->classname = "rocket";

	if (self->client)
		check_dodge (self, rocket2->s.origin, dir, speed);

	gi.linkentity (rocket2);
	*/

}
示例#18
0
//----------------------------------------------------------
void SP_emplaced_eweb( gentity_t *ent )
{
	char name[] = "models/map_objects/hoth/eweb_model.glm";

	ent->svFlags |= SVF_PLAYER_USABLE;
	ent->contents = CONTENTS_BODY;

	if ( ent->spawnflags & EMPLACED_INACTIVE )
	{
		ent->svFlags |= SVF_INACTIVE;
	}

	VectorSet( ent->mins, -12, -12, -24 );
	VectorSet( ent->maxs, 12, 12, 24 );

	ent->takedamage = qtrue;

	if ( ( ent->spawnflags & EWEB_INVULNERABLE ))
	{
		ent->flags |= FL_GODMODE;
	}

	ent->s.radius = 80;
	ent->spawnflags |= 4; // deadsolid

	//ent->e_ThinkFunc = thinkF_NULL;
	ent->e_PainFunc = painF_eweb_pain;
	ent->e_DieFunc  = dieF_eweb_die;

	G_EffectIndex( "emplaced/explode" );
	G_EffectIndex( "emplaced/dead_smoke" );

	G_SoundIndex( "sound/weapons/eweb/eweb_aim.wav" );
	G_SoundIndex( "sound/weapons/eweb/eweb_dismount.mp3" );
	//G_SoundIndex( "sound/weapons/eweb/eweb_empty.wav" );
	G_SoundIndex( "sound/weapons/eweb/eweb_fire.wav" );
	G_SoundIndex( "sound/weapons/eweb/eweb_hitplayer.wav" );
	G_SoundIndex( "sound/weapons/eweb/eweb_hitsurface.wav" );
	//G_SoundIndex( "sound/weapons/eweb/eweb_load.wav" );
	G_SoundIndex( "sound/weapons/eweb/eweb_mount.mp3" );

	// Set up our defaults and override with custom amounts as necessary
	G_SpawnInt( "count", "999", &ent->count );
	G_SpawnInt( "health", "250", &ent->health );
	G_SpawnInt( "splashDamage", "40", &ent->splashDamage );
	G_SpawnInt( "splashRadius", "100", &ent->splashRadius );
	G_SpawnFloat( "delay", "200", &ent->random ); // NOTE: spawning into a different field!!
	G_SpawnFloat( "wait", "800", &ent->wait );

	ent->max_health = ent->health;
	ent->dflags |= DAMAGE_CUSTOM_HUD; // dumb, but we draw a custom hud

	ent->s.modelindex = G_ModelIndex( name );
	ent->playerModel = gi.G2API_InitGhoul2Model( ent->ghoul2, name, ent->s.modelindex, NULL_HANDLE, NULL_HANDLE, 0, 0 );

	// Activate our tags and bones
	ent->handLBolt = gi.G2API_AddBolt( &ent->ghoul2[ent->playerModel], "*cannonflash" ); //muzzle bolt
	ent->headBolt = gi.G2API_AddBolt( &ent->ghoul2[ent->playerModel], "cannon_Xrot" ); //for placing the owner relative to rotation
	ent->rootBone = gi.G2API_GetBoneIndex( &ent->ghoul2[ent->playerModel], "model_root", qtrue );
	ent->lowerLumbarBone = gi.G2API_GetBoneIndex( &ent->ghoul2[ent->playerModel], "cannon_Yrot", qtrue );
	ent->upperLumbarBone = gi.G2API_GetBoneIndex( &ent->ghoul2[ent->playerModel], "cannon_Xrot", qtrue );
	gi.G2API_SetBoneAnglesIndex( &ent->ghoul2[ent->playerModel], ent->lowerLumbarBone, vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Z, NEGATIVE_X, NEGATIVE_Y, NULL, 0, 0); 
	gi.G2API_SetBoneAnglesIndex( &ent->ghoul2[ent->playerModel], ent->upperLumbarBone, vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Z, NEGATIVE_X, NEGATIVE_Y, NULL, 0, 0); 
	//gi.G2API_SetBoneAngles( &ent->ghoul2[0], "cannon_Yrot", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, NULL); 
	//set the constraints for this guy as an emplaced weapon, and his constraint angles
	//ent->s.origin2[0] = 60.0f; //60 degrees in either direction

	RegisterItem( FindItemForWeapon( WP_EMPLACED_GUN ));
	ent->s.weapon = WP_EMPLACED_GUN;

	G_SetOrigin( ent, ent->s.origin );
	G_SetAngles( ent, ent->s.angles );
	VectorCopy( ent->s.angles, ent->lastAngles );

	// store base angles for later
	VectorClear( ent->pos1 );

	ent->e_UseFunc = useF_eweb_use;
	ent->bounceCount = 1;//to distinguish it from the emplaced gun

	gi.linkentity (ent);
}
示例#19
0
/*
===============
SV_CalcViewOffset

Auto pitching on slopes?

  fall from 128: 400 = 160000
  fall from 256: 580 = 336400
  fall from 384: 720 = 518400
  fall from 512: 800 = 640000
  fall from 640: 960 =

  damage = deltavelocity*deltavelocity  * 0.0001

===============
*/
void SV_CalcViewOffset (edict_t *ent)
{
    float		*angles;
    float		bob;
    float		ratio;
    float		delta;
    vec3_t		v;


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

    // base angles
    angles = ent->client->ps.kick_angles;

    // if dead, fix the angle and don't add any kick
    if (ent->deadflag)
    {
        VectorClear (angles);

        if(ent->flags & FL_SAM_RAIMI)
        {
            ent->client->ps.viewangles[ROLL] = 0;
            ent->client->ps.viewangles[PITCH] = 0;
        }
        else
        {
            ent->client->ps.viewangles[ROLL] = 40;
            ent->client->ps.viewangles[PITCH] = -15;
        }
        ent->client->ps.viewangles[YAW] = ent->client->killer_yaw;
    }
    else
    {
        // add angles based on weapon kick

        VectorCopy (ent->client->kick_angles, angles);

        // add angles based on damage kick

        ratio = (ent->client->v_dmg_time - level.time) / DAMAGE_TIME;
        if (ratio < 0)
        {
            ratio = 0;
            ent->client->v_dmg_pitch = 0;
            ent->client->v_dmg_roll = 0;
        }
        angles[PITCH] += ratio * ent->client->v_dmg_pitch;
        angles[ROLL] += ratio * ent->client->v_dmg_roll;

        // add pitch based on fall kick

        ratio = (ent->client->fall_time - level.time) / FALL_TIME;
        if (ratio < 0)
            ratio = 0;
        angles[PITCH] += ratio * ent->client->fall_value;

        // add angles based on velocity

        delta = DotProduct (ent->velocity, forward);
        angles[PITCH] += delta*run_pitch->value;

        delta = DotProduct (ent->velocity, right);
        angles[ROLL] += delta*run_roll->value;

        // add angles based on bob

        delta = bobfracsin * bob_pitch->value * xyspeed;
        if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
            delta *= 6;		// crouching
        angles[PITCH] += delta;
        delta = bobfracsin * bob_roll->value * xyspeed;
        if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
            delta *= 6;		// crouching
        if (bobcycle & 1)
            delta = -delta;
        angles[ROLL] += delta;
    }

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

    // base origin

    VectorClear (v);

    // add view height

    v[2] += ent->viewheight;

    // add fall height

    ratio = (ent->client->fall_time - level.time) / FALL_TIME;
    if (ratio < 0)
        ratio = 0;
    v[2] -= ratio * ent->client->fall_value * 0.4;

    // add bob height

    bob = bobfracsin * xyspeed * bob_up->value;
    if (bob > 6)
        bob = 6;
    //gi.DebugGraph (bob *2, 255);
    v[2] += bob;

    // add kick offset

    VectorAdd (v, ent->client->kick_origin, v);

    // absolutely bound offsets
    // so the view can never be outside the player box

    if (v[0] < -14)
        v[0] = -14;
    else if (v[0] > 14)
        v[0] = 14;
    if (v[1] < -14)
        v[1] = -14;
    else if (v[1] > 14)
        v[1] = 14;
    if (v[2] < -22)
        v[2] = -22;
    else if (v[2] > 30)
        v[2] = 30;

    VectorCopy (v, ent->client->ps.viewoffset);
}
示例#20
0
/*
==============
RE_BuildSkeleton
==============
*/
int RE_BuildSkeleton(refSkeleton_t * skel, qhandle_t hAnim, int startFrame, int endFrame, float frac, qboolean clearOrigin)
{
	skelAnimation_t *skelAnim;

	skelAnim = R_GetAnimationByHandle(hAnim);

	if(skelAnim->type == AT_MD5 && skelAnim->md5)
	{
		int             i;
		md5Animation_t *anim;
		md5Channel_t   *channel;
		md5Frame_t     *newFrame, *oldFrame;
		vec3_t          newOrigin, oldOrigin, lerpedOrigin;
		quat_t          newQuat, oldQuat, lerpedQuat;
		int             componentsApplied;

		anim = skelAnim->md5;

		// Validate the frames so there is no chance of a crash.
		// This will write directly into the entity structure, so
		// when the surfaces are rendered, they don't need to be
		// range checked again.
		/*
		   if((startFrame >= anim->numFrames) || (startFrame < 0) || (endFrame >= anim->numFrames) || (endFrame < 0))
		   {
		   ri.Printf(PRINT_DEVELOPER, "RE_BuildSkeleton: no such frame %d to %d for '%s'\n", startFrame, endFrame, anim->name);
		   //startFrame = 0;
		   //endFrame = 0;
		   }
		 */

		Q_clamp(startFrame, 0, anim->numFrames - 1);
		Q_clamp(endFrame, 0, anim->numFrames - 1);

		// compute frame pointers
		oldFrame = &anim->frames[startFrame];
		newFrame = &anim->frames[endFrame];

		// calculate a bounding box in the current coordinate system
		for(i = 0; i < 3; i++)
		{
			skel->bounds[0][i] =
				oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i];
			skel->bounds[1][i] =
				oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i];
		}

		for(i = 0, channel = anim->channels; i < anim->numChannels; i++, channel++)
		{
			// set baseframe values
			VectorCopy(channel->baseOrigin, newOrigin);
			VectorCopy(channel->baseOrigin, oldOrigin);

			QuatCopy(channel->baseQuat, newQuat);
			QuatCopy(channel->baseQuat, oldQuat);

			componentsApplied = 0;

			// update tranlation bits
			if(channel->componentsBits & COMPONENT_BIT_TX)
			{
				oldOrigin[0] = oldFrame->components[channel->componentsOffset + componentsApplied];
				newOrigin[0] = newFrame->components[channel->componentsOffset + componentsApplied];
				componentsApplied++;
			}

			if(channel->componentsBits & COMPONENT_BIT_TY)
			{
				oldOrigin[1] = oldFrame->components[channel->componentsOffset + componentsApplied];
				newOrigin[1] = newFrame->components[channel->componentsOffset + componentsApplied];
				componentsApplied++;
			}

			if(channel->componentsBits & COMPONENT_BIT_TZ)
			{
				oldOrigin[2] = oldFrame->components[channel->componentsOffset + componentsApplied];
				newOrigin[2] = newFrame->components[channel->componentsOffset + componentsApplied];
				componentsApplied++;
			}

			// update quaternion rotation bits
			if(channel->componentsBits & COMPONENT_BIT_QX)
			{
				((vec_t *) oldQuat)[0] = oldFrame->components[channel->componentsOffset + componentsApplied];
				((vec_t *) newQuat)[0] = newFrame->components[channel->componentsOffset + componentsApplied];
				componentsApplied++;
			}

			if(channel->componentsBits & COMPONENT_BIT_QY)
			{
				((vec_t *) oldQuat)[1] = oldFrame->components[channel->componentsOffset + componentsApplied];
				((vec_t *) newQuat)[1] = newFrame->components[channel->componentsOffset + componentsApplied];
				componentsApplied++;
			}

			if(channel->componentsBits & COMPONENT_BIT_QZ)
			{
				((vec_t *) oldQuat)[2] = oldFrame->components[channel->componentsOffset + componentsApplied];
				((vec_t *) newQuat)[2] = newFrame->components[channel->componentsOffset + componentsApplied];
			}

			QuatCalcW(oldQuat);
			QuatNormalize(oldQuat);

			QuatCalcW(newQuat);
			QuatNormalize(newQuat);

#if 1
			VectorLerp(oldOrigin, newOrigin, frac, lerpedOrigin);
			QuatSlerp(oldQuat, newQuat, frac, lerpedQuat);
#else
			VectorCopy(newOrigin, lerpedOrigin);
			QuatCopy(newQuat, lerpedQuat);
#endif

			// copy lerped information to the bone + extra data
			skel->bones[i].parentIndex = channel->parentIndex;

			if(channel->parentIndex < 0 && clearOrigin)
			{
				VectorClear(skel->bones[i].origin);
				QuatClear(skel->bones[i].rotation);

				// move bounding box back
				VectorSubtract(skel->bounds[0], lerpedOrigin, skel->bounds[0]);
				VectorSubtract(skel->bounds[1], lerpedOrigin, skel->bounds[1]);
			}
			else
			{
				VectorCopy(lerpedOrigin, skel->bones[i].origin);
			}

			QuatCopy(lerpedQuat, skel->bones[i].rotation);

#if defined(REFBONE_NAMES)
			Q_strncpyz(skel->bones[i].name, channel->name, sizeof(skel->bones[i].name));
#endif
		}

		skel->numBones = anim->numChannels;
		skel->type = SK_RELATIVE;
		return qtrue;
	}
	else if(skelAnim->type == AT_PSA && skelAnim->psa)
	{
		int             i;
		psaAnimation_t *anim;
		axAnimationKey_t *newKey, *oldKey;
		axReferenceBone_t *refBone;
		vec3_t          newOrigin, oldOrigin, lerpedOrigin;
		quat_t          newQuat, oldQuat, lerpedQuat;
		refSkeleton_t   skeleton;

		anim = skelAnim->psa;

		Q_clamp(startFrame, 0, anim->info.numRawFrames - 1);
		Q_clamp(endFrame, 0, anim->info.numRawFrames - 1);

		ClearBounds(skel->bounds[0], skel->bounds[1]);

		skel->numBones = anim->info.numBones;
		for(i = 0, refBone = anim->bones; i < anim->info.numBones; i++, refBone++)
		{
			oldKey = &anim->keys[startFrame * anim->info.numBones + i];
			newKey = &anim->keys[endFrame * anim->info.numBones + i];

			VectorCopy(newKey->position, newOrigin);
			VectorCopy(oldKey->position, oldOrigin);

			QuatCopy(newKey->quat, newQuat);
			QuatCopy(oldKey->quat, oldQuat);

			//QuatCalcW(oldQuat);
			//QuatNormalize(oldQuat);

			//QuatCalcW(newQuat);
			//QuatNormalize(newQuat);

			VectorLerp(oldOrigin, newOrigin, frac, lerpedOrigin);
			QuatSlerp(oldQuat, newQuat, frac, lerpedQuat);

			// copy lerped information to the bone + extra data
			skel->bones[i].parentIndex = refBone->parentIndex;

			if(refBone->parentIndex < 0 && clearOrigin)
			{
				VectorClear(skel->bones[i].origin);
				QuatClear(skel->bones[i].rotation);

				// move bounding box back
				VectorSubtract(skel->bounds[0], lerpedOrigin, skel->bounds[0]);
				VectorSubtract(skel->bounds[1], lerpedOrigin, skel->bounds[1]);
			}
			else
			{
				VectorCopy(lerpedOrigin, skel->bones[i].origin);
			}

			QuatCopy(lerpedQuat, skel->bones[i].rotation);

#if defined(REFBONE_NAMES)
			Q_strncpyz(skel->bones[i].name, refBone->name, sizeof(skel->bones[i].name));
#endif

			// calculate absolute values for the bounding box approximation
			VectorCopy(skel->bones[i].origin, skeleton.bones[i].origin);
			QuatCopy(skel->bones[i].rotation, skeleton.bones[i].rotation);

			if(refBone->parentIndex >= 0)
			{
				vec3_t          rotated;
				quat_t          quat;
				refBone_t      *parent;
				refBone_t      *bone;

				bone = &skeleton.bones[i];
				parent = &skeleton.bones[refBone->parentIndex];

				QuatTransformVector(parent->rotation, bone->origin, rotated);

				VectorAdd(parent->origin, rotated, bone->origin);

				QuatMultiply1(parent->rotation, bone->rotation, quat);
				QuatCopy(quat, bone->rotation);

				AddPointToBounds(bone->origin, skel->bounds[0], skel->bounds[1]);
			}
		}

		skel->numBones = anim->info.numBones;
		skel->type = SK_RELATIVE;
		return qtrue;
	}

	//ri.Printf(PRINT_WARNING, "RE_BuildSkeleton: bad animation '%s' with handle %i\n", anim->name, hAnim);

	// FIXME: clear existing bones and bounds?
	return qfalse;
}
示例#21
0
/*
===============
P_DamageFeedback

Handles color blends and view kicks
===============
*/
void P_DamageFeedback (edict_t *player)
{
    gclient_t	*client;
    float	side;
    float	realcount, count, kick;
    vec3_t	v;
    int		r, l;
    static	vec3_t	power_color = {0.0, 1.0, 0.0};
    static	vec3_t	acolor = {1.0, 1.0, 1.0};
    static	vec3_t	bcolor = {1.0, 0.0, 0.0};

    client = player->client;

    // flash the backgrounds behind the status numbers
    client->ps.stats[STAT_FLASHES] = 0;
    if (client->damage_blood)
        client->ps.stats[STAT_FLASHES] |= 1;
    if (client->damage_armor && !(player->flags & FL_GODMODE) && (client->invincible_framenum <= level.framenum))
        client->ps.stats[STAT_FLASHES] |= 2;

    // total points of damage shot at the player this frame
    count = (client->damage_blood + client->damage_armor + client->damage_parmor);
    if (count == 0)
        return;		// didn't take any damage

    // start a pain animation if still in the player model
    if (client->anim_priority < ANIM_PAIN && player->s.modelindex == 255)
    {
        static int		i;

        client->anim_priority = ANIM_PAIN;
        if (client->ps.pmove.pm_flags & PMF_DUCKED)
        {
            player->s.frame = FRAME_crpain1-1;
            client->anim_end = FRAME_crpain4;
        }
        else
        {
            i = (i+1)%3;
            switch (i)
            {
            case 0:
                player->s.frame = FRAME_pain101-1;
                client->anim_end = FRAME_pain104;
                break;
            case 1:
                player->s.frame = FRAME_pain201-1;
                client->anim_end = FRAME_pain204;
                break;
            case 2:
                player->s.frame = FRAME_pain301-1;
                client->anim_end = FRAME_pain304;
                break;
            }
        }
    }

    realcount = count;
    if (count < 10)
        count = 10;	// always make a visible effect

    // play an apropriate pain sound
    if ((level.time > player->pain_debounce_time) && !(player->flags & FL_GODMODE) && (client->invincible_framenum <= level.framenum))
    {
        r = 1 + (rand()&1);
        player->pain_debounce_time = level.time + 0.7;
        if (player->health < 25)
            l = 25;
        else if (player->health < 50)
            l = 50;
        else if (player->health < 75)
            l = 75;
        else
            l = 100;
        gi.sound (player, CHAN_VOICE, gi.soundindex(va("*pain%i_%i.wav", l, r)), 1, ATTN_NORM, 0);
    }

    // the total alpha of the blend is always proportional to count
    if (client->damage_alpha < 0)
        client->damage_alpha = 0;
    client->damage_alpha += count*0.01;
    if (client->damage_alpha < 0.2)
        client->damage_alpha = 0.2;
    if (client->damage_alpha > 0.6)
        client->damage_alpha = 0.6;		// don't go too saturated

    // the color of the blend will vary based on how much was absorbed
    // by different armors
    VectorClear (v);
    if (client->damage_parmor)
        VectorMA (v, (float)client->damage_parmor/realcount, power_color, v);
    if (client->damage_armor)
        VectorMA (v, (float)client->damage_armor/realcount,  acolor, v);
    if (client->damage_blood)
        VectorMA (v, (float)client->damage_blood/realcount,  bcolor, v);
    VectorCopy (v, client->damage_blend);


    //
    // calculate view angle kicks
    //
    kick = abs(client->damage_knockback);
    if (kick && player->health > 0)	// kick of 0 means no view adjust at all
    {
        kick = kick * 100 / player->health;

        if (kick < count*0.5)
            kick = count*0.5;
        if (kick > 50)
            kick = 50;

        VectorSubtract (client->damage_from, player->s.origin, v);
        VectorNormalize (v);

        side = DotProduct (v, right);
        client->v_dmg_roll = kick*side*0.3;

        side = -DotProduct (v, forward);
        client->v_dmg_pitch = kick*side*0.3;

        client->v_dmg_time = level.time + DAMAGE_TIME;
    }

    //
    // clear totals
    //
    client->damage_blood = 0;
    client->damage_armor = 0;
    client->damage_parmor = 0;
    client->damage_knockback = 0;
}
示例#22
0
文件: cl_fx.c 项目: luaman/qforge-2
/*
===============
CL_DiminishingTrail
 
===============
*/
void CL_DiminishingTrail(vec3_t start, vec3_t end, centity_t *old, int flags){
	vec3_t	move;
	vec3_t	vec;
	float	len;
	int	j;
	cparticle_t	*p;
	float	dec;
	float	orgscale;
	float	velscale;
	
	VectorCopy(start, move);
	VectorSubtract(end, start, vec);
	len = VectorNormalize(vec);
	
	dec = 0.5;
	VectorScale(vec, dec, vec);
	
	if(old->trailcount > 900){
		orgscale = 4;
		velscale = 15;
	} else if(old->trailcount > 800){
		orgscale = 2;
		velscale = 10;
	} else {
		orgscale = 1;
		velscale = 5;
	}
	
	while(len > 0){
		len -= dec;
		
		if(!free_particles)
			return;
			
		// drop less particles as it flies
		if((rand()&1023) < old->trailcount){
			p = free_particles;
			free_particles = p->next;
			p->next = active_particles;
			active_particles = p;
			VectorClear(p->accel);
			
			p->time = cl.time;
			
			if(flags & EF_GIB){
				p->alpha = 1.0;
				p->alphavel = -1.0 /(1 + frand() * 0.4);
				p->color = 0xe8 +(rand() & 7);
				for(j = 0; j < 3; j++){
					p->org[j] = move[j] + crand() * orgscale;
					p->vel[j] = crand() * velscale;
					p->accel[j] = 0;
				}
				p->vel[2] -= PARTICLE_GRAVITY;
			} else if(flags & EF_GREENGIB){
				p->alpha = 1.0;
				p->alphavel = -1.0 /(1 + frand() * 0.4);
				p->color = 0xdb +(rand() & 7);
				for(j = 0; j < 3; j++){
					p->org[j] = move[j] + crand() * orgscale;
					p->vel[j] = crand() * velscale;
					p->accel[j] = 0;
				}
				p->vel[2] -= PARTICLE_GRAVITY;
			} else {
				p->alpha = 1.0;
				p->alphavel = -1.0 /(1 + frand() * 0.2);
				p->color = 4 +(rand() & 7);
				for(j = 0; j < 3; j++){
					p->org[j] = move[j] + crand() * orgscale;
					p->vel[j] = crand() * velscale;
				}
				p->accel[2] = 20;
			}
		}
		
		old->trailcount -= 5;
		if(old->trailcount < 100)
			old->trailcount = 100;
		VectorAdd(move, vec, move);
	}
}
示例#23
0
//==========================================
// BOT_DMclass_CombatMovement
//
// NOTE: Very simple for now, just a basic move about avoidance.
//       Change this routine for more advanced attack movement.
//==========================================
void BOT_DMclass_CombatMovement( edict_t *self, usercmd_t *ucmd )
{
	float c;
	float dist;
	bool rocket = false;
	vec3_t away_from_rocket = { 0, 0, 0 };

	if( !self->enemy || self->ai->rush_item )
	{
		BOT_DMclass_Move( self, ucmd );
		return;
	}

	if( self->ai->pers.skillLevel >= 0.25f ) 
		rocket = BOT_DMclass_FindRocket( self, away_from_rocket );

	dist = DistanceFast( self->s.origin, self->enemy->s.origin );
	c = random();

	if( level.time > self->ai->combatmovepush_timeout )
	{
		bool canMOVELEFT, canMOVERIGHT, canMOVEFRONT, canMOVEBACK;

		canMOVELEFT = AI_CanMove( self, BOT_MOVE_LEFT );
		canMOVERIGHT = AI_CanMove( self, BOT_MOVE_RIGHT );
		canMOVEFRONT = AI_CanMove( self, BOT_MOVE_FORWARD );
		canMOVEBACK = AI_CanMove( self, BOT_MOVE_BACK );

		self->ai->combatmovepush_timeout = level.time + AI_COMBATMOVE_TIMEOUT;
		VectorClear( self->ai->combatmovepushes );

		if( rocket )
		{
			//VectorScale(away_from_rocket,1,self->ai->combatmovepushes);
			if( away_from_rocket[0] )
			{
				if( ( away_from_rocket[0] < 0 ) && canMOVEBACK )
					self->ai->combatmovepushes[0] = -1;
				else if( ( away_from_rocket[0] > 0 ) && canMOVEFRONT )
					self->ai->combatmovepushes[0] = 1;
			}
			if( away_from_rocket[1] )
			{
				if( ( away_from_rocket[1] < 0 ) && canMOVELEFT )
					self->ai->combatmovepushes[1] = -1;
				else if( ( away_from_rocket[1] > 0 ) && canMOVERIGHT )
					self->ai->combatmovepushes[1] = 1;
			}

			ucmd->buttons |= BUTTON_SPECIAL;
		}
		else
			if( dist < 150 ) // range = AIWEAP_MELEE_RANGE;
			{
				if( self->s.weapon == WEAP_GUNBLADE ) // go into him!
				{
					ucmd->buttons &= ~BUTTON_ATTACK; // remove pressing fire
					if( canMOVEFRONT )  // move to your enemy
						self->ai->combatmovepushes[0] = 1;
					else if( c <= 0.5 && canMOVELEFT )
						self->ai->combatmovepushes[1] = -1;
					else if( canMOVERIGHT )
						self->ai->combatmovepushes[1] = 1;
				}
				else
				{
					//priorize sides
					if( canMOVELEFT || canMOVERIGHT )
					{
						if( canMOVELEFT && canMOVERIGHT )
						{
							self->ai->combatmovepushes[1] = c < 0.5 ? -1 : 1;
						}
						else if( canMOVELEFT )
						{
							self->ai->combatmovepushes[1] = -1;
						}
						else
						{
							self->ai->combatmovepushes[1] = 1;
						}
					}

					if( c < 0.3 && canMOVEBACK )
						self->ai->combatmovepushes[0] = -1;
				}

			}
			else if( dist < 500 ) //AIWEAP_SHORT_RANGE limit is Grenade Laucher range
			{
				if( canMOVELEFT || canMOVERIGHT )
				{
					if( canMOVELEFT && canMOVERIGHT )
					{
						self->ai->combatmovepushes[1] = c < 0.5 ? -1 : 1;
					}
					else if( canMOVELEFT )
					{
						self->ai->combatmovepushes[1] = -1;
					}
					else
					{
						self->ai->combatmovepushes[1] = 1;
					}
				}

				if( c < 0.3 && canMOVEFRONT )
				{
					self->ai->combatmovepushes[0] = 1;
				}

			}
			else if( dist < 900 )
			{
				if( canMOVELEFT || canMOVERIGHT )
				{
					if( canMOVELEFT && canMOVERIGHT )
					{
						self->ai->combatmovepushes[1] = c < 0.5 ? -1 : 1;
					}
					else if( canMOVELEFT )
					{
						self->ai->combatmovepushes[1] = -1;
					}
					else
					{
						self->ai->combatmovepushes[1] = 1;
					}
				}
			}
			else //range = AIWEAP_LONG_RANGE;
			{
				if( c < 0.75 && ( canMOVELEFT || canMOVERIGHT ) )
				{
					if( canMOVELEFT && canMOVERIGHT )
					{
						self->ai->combatmovepushes[1] = c < 0.5 ? -1 : 1;
					}
					else if( canMOVELEFT )
					{
						self->ai->combatmovepushes[1] = -1;
					}
					else
					{
						self->ai->combatmovepushes[1] = 1;
					}
				}
			}
	}

	if( !rocket && ( self->health < 25 || ( dist >= 500 && c < 0.2 ) || ( dist >= 1000 && c < 0.5 ) ) )
	{
		BOT_DMclass_Move( self, ucmd );
	}

	if( !self->ai->camp_item )
	{
		ucmd->forwardmove = self->ai->combatmovepushes[0];
	}
	ucmd->sidemove = self->ai->combatmovepushes[1];
	ucmd->upmove = self->ai->combatmovepushes[2];
}
示例#24
0
文件: cl_fx.c 项目: luaman/qforge-2
/*
===============
CL_RailTrail
 
===============
*/
void CL_RailTrail(vec3_t start, vec3_t end){
	vec3_t	move;
	vec3_t	vec;
	float	len;
	int	j;
	cparticle_t	*p;
	float	dec;
	vec3_t	right, up;
	int	i;
	float	d, c, s;
	vec3_t	dir;
	byte	clr = 0x74;
	
	VectorCopy(start, move);
	VectorSubtract(end, start, vec);
	len = VectorNormalize(vec);
	
	MakeNormalVectors(vec, right, up);
	
	for(i = 0; i < len; i++){
		if(!free_particles)
			return;
			
		p = free_particles;
		free_particles = p->next;
		p->next = active_particles;
		active_particles = p;
		
		p->time = cl.time;
		VectorClear(p->accel);
		
		d = i * 0.1;
		c = cos(d);
		s = sin(d);
		
		VectorScale(right, c, dir);
		VectorMA(dir, s, up, dir);
		
		p->alpha = 1.0;
		p->alphavel = -1.0 /(1 + frand() * 0.2);
		p->color = clr +(rand() & 7);
		for(j = 0; j < 3; j++){
			p->org[j] = move[j] + dir[j] * 3;
			p->vel[j] = dir[j] * 6;
		}
		
		VectorAdd(move, vec, move);
	}
	
	dec = 0.75;
	VectorScale(vec, dec, vec);
	VectorCopy(start, move);
	
	while(len > 0){
		len -= dec;
		
		if(!free_particles)
			return;
		p = free_particles;
		free_particles = p->next;
		p->next = active_particles;
		active_particles = p;
		
		p->time = cl.time;
		VectorClear(p->accel);
		
		p->alpha = 1.0;
		p->alphavel = -1.0 /(0.6 + frand() * 0.2);
		p->color = 0x0 +(rand() & 15);
		
		for(j = 0; j < 3; j++){
			p->org[j] = move[j] + crand() * 3;
			p->vel[j] = crand() * 3;
			p->accel[j] = 0;
		}
		
		VectorAdd(move, vec, move);
	}
}
示例#25
0
/*
* G_ClientRespawn
*/
void G_ClientRespawn( edict_t *self, bool ghost )
{
	int i;
	edict_t *spawnpoint;
	vec3_t hull_mins, hull_maxs;
	vec3_t spawn_origin, spawn_angles;
	gclient_t *client;
	int old_team;

	G_SpawnQueue_RemoveClient( self );

	self->r.svflags &= ~SVF_NOCLIENT;

	//if invalid be spectator
	if( self->r.client->team < 0 || self->r.client->team >= GS_MAX_TEAMS )
		self->r.client->team = TEAM_SPECTATOR;

	// force ghost always to true when in spectator team
	if( self->r.client->team == TEAM_SPECTATOR )
		ghost = true;

	old_team = self->s.team;
	if( self->r.client->teamstate.is_coach )
		ghost = true;

	GClip_UnlinkEntity( self );

	client = self->r.client;

	memset( &client->resp, 0, sizeof( client->resp ) );
	memset( &client->ps, 0, sizeof( client->ps ) );
	client->resp.timeStamp = level.time;
	client->resp.gunbladeChargeTimeStamp = level.time;
	client->ps.playerNum = PLAYERNUM( self );

	// clear entity values
	memset( &self->snap, 0, sizeof( self->snap ) );
	memset( &self->s, 0, sizeof( self->s ) );
	memset( &self->olds, 0, sizeof( self->olds ) );
	memset( &self->invpak, 0, sizeof( self->invpak ) );

	self->s.number = self->olds.number = ENTNUM( self );

	// relink client struct
	self->r.client = &game.clients[PLAYERNUM( self )];

	// update team
	self->s.team = client->team;

	self->deadflag = DEAD_NO;
	self->s.type = ET_PLAYER;
	self->groundentity = NULL;
	self->takedamage = DAMAGE_AIM;
	self->think = player_think;
	self->pain = player_pain;
	self->die = player_die;
	self->viewheight = playerbox_stand_viewheight;
	self->r.inuse = true;
	self->mass = PLAYER_MASS;
	self->air_finished = level.time + ( 12 * 1000 );
	self->r.clipmask = MASK_PLAYERSOLID;
	self->waterlevel = 0;
	self->watertype = 0;
	self->flags &= ~FL_NO_KNOCKBACK;
	self->r.svflags &= ~SVF_CORPSE;
	self->enemy = NULL;
	self->r.owner = NULL;
	self->max_health = 100;
	self->health = self->max_health;

	if( AI_GetType( self->ai ) == AI_ISBOT )
	{
		self->think = NULL;
		self->classname = "bot";
	}
	else if( self->r.svflags & SVF_FAKECLIENT )
		self->classname = "fakeclient";
	else
		self->classname = "player";

	VectorCopy( playerbox_stand_mins, self->r.mins );
	VectorCopy( playerbox_stand_maxs, self->r.maxs );
	VectorClear( self->velocity );
	VectorClear( self->avelocity );

	VectorCopy( self->r.mins, hull_mins );
	VectorCopy( self->r.maxs, hull_maxs );
	trap_CM_RoundUpToHullSize( hull_mins, hull_maxs, NULL );
	if( self->r.maxs[2] > hull_maxs[2] )
		self->viewheight -= (self->r.maxs[2] - hull_maxs[2]);

	client->ps.POVnum = ENTNUM( self );

	// set movement info
	client->ps.pmove.stats[PM_STAT_MAXSPEED] = (short)DEFAULT_PLAYERSPEED;
	client->ps.pmove.stats[PM_STAT_JUMPSPEED] = (short)DEFAULT_JUMPSPEED;
	client->ps.pmove.stats[PM_STAT_DASHSPEED] = (short)DEFAULT_DASHSPEED;

	if( ghost )
	{
		self->r.solid = SOLID_NOT;
		self->movetype = MOVETYPE_NOCLIP;
		if( self->s.team == TEAM_SPECTATOR )
			self->r.svflags |= SVF_NOCLIENT;
	}
	else
	{
		self->r.client->resp.takeStun = true;
		self->r.solid = SOLID_YES;
		self->movetype = MOVETYPE_PLAYER;
		client->ps.pmove.stats[PM_STAT_FEATURES] = static_cast<unsigned short>(PMFEAT_DEFAULT);
		if( !g_allow_bunny->integer )
			client->ps.pmove.stats[PM_STAT_FEATURES] &= ~( PMFEAT_AIRCONTROL|PMFEAT_FWDBUNNY );
	}

	ClientUserinfoChanged( self, client->userinfo );

	if( old_team != self->s.team )
		G_Teams_UpdateMembersList();

	SelectSpawnPoint( self, &spawnpoint, spawn_origin, spawn_angles );
	VectorCopy( spawn_origin, client->ps.pmove.origin );
	VectorCopy( spawn_origin, self->s.origin );
	VectorCopy( self->s.origin, self->s.old_origin );

	// set angles
	self->s.angles[PITCH] = 0;
	self->s.angles[YAW] = anglemod( spawn_angles[YAW] );
	self->s.angles[ROLL] = 0;
	VectorCopy( self->s.angles, client->ps.viewangles );

	// set the delta angle
	for( i = 0; i < 3; i++ )
		client->ps.pmove.delta_angles[i] = ANGLE2SHORT( client->ps.viewangles[i] ) - client->ucmd.angles[i];

	// don't put spectators in the game
	if( !ghost )
	{
		if( KillBox( self ) )
		{
		}
	}

	self->s.attenuation = ATTN_NORM;

	self->s.teleported = true;

	// hold in place briefly
	client->ps.pmove.pm_flags = PMF_TIME_TELEPORT;
	client->ps.pmove.pm_time = 14;
	client->ps.pmove.stats[PM_STAT_NOUSERCONTROL] = CLIENT_RESPAWN_FREEZE_DELAY;
	client->ps.pmove.stats[PM_STAT_NOAUTOATTACK] = 1000;

	// set race stats to invisible
	client->ps.stats[STAT_TIME_SELF] = STAT_NOTSET;
	client->ps.stats[STAT_TIME_BEST] = STAT_NOTSET;
	client->ps.stats[STAT_TIME_RECORD] = STAT_NOTSET;
	client->ps.stats[STAT_TIME_ALPHA] = STAT_NOTSET;
	client->ps.stats[STAT_TIME_BETA] = STAT_NOTSET;

	BOT_Respawn( self );

	self->r.client->level.respawnCount++;

	G_UseTargets( spawnpoint, self );

	GClip_LinkEntity( self );

	// let the gametypes perform their changes
	if( game.asEngine != NULL )
		GT_asCallPlayerRespawn( self, old_team, self->s.team );
	else
		G_Gametype_GENERIC_ClientRespawn( self, old_team, self->s.team );
}
示例#26
0
文件: cl_fx.c 项目: luaman/qforge-2
// RAFAEL
void CL_TrapParticles(entity_t *ent){
	vec3_t	move;
	vec3_t	vec;
	vec3_t	start, end;
	float	len;
	int	j;
	cparticle_t	*p;
	int	dec;
	
	ent->origin[2] -= 14;
	VectorCopy(ent->origin, start);
	VectorCopy(ent->origin, end);
	end[2] += 64;
	
	VectorCopy(start, move);
	VectorSubtract(end, start, vec);
	len = VectorNormalize(vec);
	
	dec = 5;
	VectorScale(vec, 5, vec);
	
	// FIXME: this is a really silly way to have a loop
	while(len > 0){
		len -= dec;
		
		if(!free_particles)
			return;
		p = free_particles;
		free_particles = p->next;
		p->next = active_particles;
		active_particles = p;
		VectorClear(p->accel);
		
		p->time = cl.time;
		
		p->alpha = 1.0;
		p->alphavel = -1.0 /(0.3 + frand() * 0.2);
		p->color = 0xe0;
		for(j = 0; j < 3; j++){
			p->org[j] = move[j] + crand();
			p->vel[j] = crand() * 15;
			p->accel[j] = 0;
		}
		p->accel[2] = PARTICLE_GRAVITY;
		
		VectorAdd(move, vec, move);
	}
	
	{
	
	
		int	i, j, k;
		cparticle_t	*p;
		float	vel;
		vec3_t	dir;
		vec3_t	org;
		
		
		ent->origin[2] += 14;
		VectorCopy(ent->origin, org);
		
		
		for(i = -2; i <= 2; i += 4)
			for(j = -2; j <= 2; j += 4)
				for(k = -2; k <= 4; k += 4){
					if(!free_particles)
						return;
					p = free_particles;
					free_particles = p->next;
					p->next = active_particles;
					active_particles = p;
					
					p->time = cl.time;
					p->color = 0xe0 +(rand() & 3);
					
					p->alpha = 1.0;
					p->alphavel = -1.0 /(0.3 +(rand() & 7) * 0.02);
					
					p->org[0] = org[0] + i +((rand() & 23) * crand());
					p->org[1] = org[1] + j +((rand() & 23) * crand());
					p->org[2] = org[2] + k +((rand() & 23) * crand());
					
					dir[0] = j * 8;
					dir[1] = i * 8;
					dir[2] = k * 8;
					
					VectorNormalize(dir);
					vel = 50 +(rand() & 63);
					VectorScale(dir, vel, p->vel);
					
					p->accel[0] = p->accel[1] = 0;
					p->accel[2] = -PARTICLE_GRAVITY;
				}
	}
}
示例#27
0
/*
==============
ClientThink

This will be called once for each client frame, which will
usually be a couple times for each server frame on fast clients.

If "g_synchronousClients 1" is set, this will be called exactly
once for each server frame, which makes for smooth demo recording.
==============
*/
void ClientThink_real( gentity_t *ent ) {
	gclient_t	*client;
	pmove_t		pm;
	int			oldEventSequence;
	int			msec;
	int			i;
	usercmd_t	*ucmd;

	client = ent->client;

	// don't think if the client is not yet connected (and thus not yet spawned in)
	if (client->pers.connected != CON_CONNECTED) {
		return;
	}
	// mark the time, so the connection sprite can be removed
	ucmd = &ent->client->pers.cmd;

	// sanity check the command time to prevent speedup cheating
	if ( ucmd->serverTime > level.time + 200 ) {
		ucmd->serverTime = level.time + 200;
//		G_Printf("serverTime <<<<<\n" );
	}
	if ( ucmd->serverTime < level.time - 1000 ) {
		ucmd->serverTime = level.time - 1000;
//		G_Printf("serverTime >>>>>\n" );
	}

	msec = ucmd->serverTime - client->ps.commandTime;
	// following others may result in bad times, but we still want
	// to check for follow toggles
	if ( msec < 1 && client->sess.spectatorState != SPECTATOR_FOLLOW ) {
		return;
	}
	if ( msec > 200 ) {
		msec = 200;
	}

	if ( pmove_msec.integer < 8 ) {
		trap_Cvar_Set("pmove_msec", "8");
	}
	else if (pmove_msec.integer > 33) {
		trap_Cvar_Set("pmove_msec", "33");
	}

	if ( pmove_fixed.integer || client->pers.pmoveFixed ) {
		ucmd->serverTime = ((ucmd->serverTime + pmove_msec.integer-1) / pmove_msec.integer) * pmove_msec.integer;
		//if (ucmd->serverTime - client->ps.commandTime <= 0)
		//	return;
	}

	//
	// check for exiting intermission
	//
	if ( level.intermissiontime ) {
		ClientIntermissionThink( client );
		return;
	}

	// spectators don't do much
	if ( client->sess.sessionTeam == TEAM_SPECTATOR ) {
		if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) {
			return;
		}
		SpectatorThink( ent, ucmd );
		return;
	}

	if (ent && ent->client && (ent->client->ps.eFlags & EF_INVULNERABLE))
	{
		if (ent->client->invulnerableTimer <= level.time)
		{
			ent->client->ps.eFlags &= ~EF_INVULNERABLE;
		}
	}

	// check for inactivity timer, but never drop the local client of a non-dedicated server
	if ( !ClientInactivityTimer( client ) ) {
		return;
	}

	// clear the rewards if time
	if ( level.time > client->rewardTime ) {
		client->ps.eFlags &= ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND | EF_AWARD_CAP );
	}

	if ( client->noclip ) {
		client->ps.pm_type = PM_NOCLIP;
	} else if ( client->ps.eFlags & EF_DISINTEGRATION ) {
		client->ps.pm_type = PM_NOCLIP;
	} else if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
		client->ps.pm_type = PM_DEAD;
	} else {
		if (client->ps.forceGripChangeMovetype)
		{
			client->ps.pm_type = client->ps.forceGripChangeMovetype;
		}
		else
		{
			client->ps.pm_type = PM_NORMAL;
		}
	}

	client->ps.gravity = g_gravity.value;

	// set speed
	client->ps.speed = g_speed.value;
	client->ps.basespeed = g_speed.value;

	if (ent->client->ps.duelInProgress)
	{
		gentity_t *duelAgainst = &g_entities[ent->client->ps.duelIndex];

		//Keep the time updated, so once this duel ends this player can't engage in a duel for another
		//10 seconds. This will give other people a chance to engage in duels in case this player wants
		//to engage again right after he's done fighting and someone else is waiting.
		ent->client->ps.fd.privateDuelTime = level.time + 10000;

		if (ent->client->ps.duelTime < level.time)
		{
			//Bring out the sabers
			if (ent->client->ps.weapon == WP_SABER && ent->client->ps.saberHolstered &&
				ent->client->ps.duelTime)
			{
				if (!saberOffSound || !saberOnSound)
				{
					saberOffSound = G_SoundIndex("sound/weapons/saber/saberoffquick.wav");
					saberOnSound = G_SoundIndex("sound/weapons/saber/saberon.wav");
				}

				ent->client->ps.saberHolstered = qfalse;
				G_Sound(ent, CHAN_AUTO, saberOnSound);

				G_AddEvent(ent, EV_PRIVATE_DUEL, 2);

				ent->client->ps.duelTime = 0;
			}

			if (duelAgainst && duelAgainst->client && duelAgainst->inuse &&
				duelAgainst->client->ps.weapon == WP_SABER && duelAgainst->client->ps.saberHolstered &&
				duelAgainst->client->ps.duelTime)
			{
				if (!saberOffSound || !saberOnSound)
				{
					saberOffSound = G_SoundIndex("sound/weapons/saber/saberoffquick.wav");
					saberOnSound = G_SoundIndex("sound/weapons/saber/saberon.wav");
				}

				duelAgainst->client->ps.saberHolstered = qfalse;
				G_Sound(duelAgainst, CHAN_AUTO, saberOnSound);

				G_AddEvent(duelAgainst, EV_PRIVATE_DUEL, 2);

				duelAgainst->client->ps.duelTime = 0;
			}
		}
		else
		{
			client->ps.speed = 0;
			client->ps.basespeed = 0;
			ucmd->forwardmove = 0;
			ucmd->rightmove = 0;
			ucmd->upmove = 0;
		}

		if (!duelAgainst || !duelAgainst->client || !duelAgainst->inuse ||
			duelAgainst->client->ps.duelIndex != ent->s.number)
		{
			ent->client->ps.duelInProgress = 0;
			G_AddEvent(ent, EV_PRIVATE_DUEL, 0);
		}
		else if (duelAgainst->health < 1 || duelAgainst->client->ps.stats[STAT_HEALTH] < 1)
		{
			ent->client->ps.duelInProgress = 0;
			duelAgainst->client->ps.duelInProgress = 0;

			G_AddEvent(ent, EV_PRIVATE_DUEL, 0);
			G_AddEvent(duelAgainst, EV_PRIVATE_DUEL, 0);

			//Winner gets full health.. providing he's still alive
			if (ent->health > 0 && ent->client->ps.stats[STAT_HEALTH] > 0)
			{
				if (ent->health < ent->client->ps.stats[STAT_MAX_HEALTH])
				{
					ent->client->ps.stats[STAT_HEALTH] = ent->health = ent->client->ps.stats[STAT_MAX_HEALTH];
				}

				if (g_spawnInvulnerability.integer)
				{
					ent->client->ps.eFlags |= EF_INVULNERABLE;
					ent->client->invulnerableTimer = level.time + g_spawnInvulnerability.integer;
				}
			}

			/*
			trap_SendServerCommand( ent-g_entities, va("print \"%s %s\n\"", ent->client->pers.netname, G_GetStripEdString("SVINGAME", "PLDUELWINNER")) );
			trap_SendServerCommand( duelAgainst-g_entities, va("print \"%s %s\n\"", ent->client->pers.netname, G_GetStripEdString("SVINGAME", "PLDUELWINNER")) );
			*/
			//Private duel announcements are now made globally because we only want one duel at a time.
			if (ent->health > 0 && ent->client->ps.stats[STAT_HEALTH] > 0)
			{
				trap_SendServerCommand( -1, va("cp \"%s %s %s!\n\"", ent->client->pers.netname, G_GetStripEdString("SVINGAME", "PLDUELWINNER"), duelAgainst->client->pers.netname) );
			}
			else
			{ //it was a draw, because we both managed to die in the same frame
				trap_SendServerCommand( -1, va("cp \"%s\n\"", G_GetStripEdString("SVINGAME", "PLDUELTIE")) );
			}
		}
		else
		{
			vec3_t vSub;
			float subLen = 0;

			VectorSubtract(ent->client->ps.origin, duelAgainst->client->ps.origin, vSub);
			subLen = VectorLength(vSub);

			if (subLen >= 1024)
			{
				ent->client->ps.duelInProgress = 0;
				duelAgainst->client->ps.duelInProgress = 0;

				G_AddEvent(ent, EV_PRIVATE_DUEL, 0);
				G_AddEvent(duelAgainst, EV_PRIVATE_DUEL, 0);

				trap_SendServerCommand( -1, va("print \"%s\n\"", G_GetStripEdString("SVINGAME", "PLDUELSTOP")) );
			}
		}
	}

	/*
	if ( client->ps.powerups[PW_HASTE] ) {
		client->ps.speed *= 1.3;
	}
	*/

	if (client->ps.usingATST && ent->health > 0)
	{ //we have special shot clip boxes as an ATST
		ent->r.contents |= CONTENTS_NOSHOT;
		ATST_ManageDamageBoxes(ent);
	}
	else
	{
		ent->r.contents &= ~CONTENTS_NOSHOT;
		client->damageBoxHandle_Head = 0;
		client->damageBoxHandle_RLeg = 0;
		client->damageBoxHandle_LLeg = 0;
	}

	//rww - moved this stuff into the pmove code so that it's predicted properly
	//BG_AdjustClientSpeed(&client->ps, &client->pers.cmd, level.time);

	// set up for pmove
	oldEventSequence = client->ps.eventSequence;

	memset (&pm, 0, sizeof(pm));

	if ( ent->flags & FL_FORCE_GESTURE ) {
		ent->flags &= ~FL_FORCE_GESTURE;
		ent->client->pers.cmd.buttons |= BUTTON_GESTURE;
	}

	if (ent->client && ent->client->ps.fallingToDeath &&
		(level.time - FALL_FADE_TIME) > ent->client->ps.fallingToDeath)
	{ //die!
		player_die(ent, ent, ent, 100000, MOD_FALLING);
		respawn(ent);
		ent->client->ps.fallingToDeath = 0;

		G_MuteSound(ent->s.number, CHAN_VOICE); //stop screaming, because you are dead!
	}

	if (ent->client->ps.otherKillerTime > level.time &&
		ent->client->ps.groundEntityNum != ENTITYNUM_NONE &&
		ent->client->ps.otherKillerDebounceTime < level.time)
	{
		ent->client->ps.otherKillerTime = 0;
		ent->client->ps.otherKiller = ENTITYNUM_NONE;
	}
	else if (ent->client->ps.otherKillerTime > level.time &&
		ent->client->ps.groundEntityNum == ENTITYNUM_NONE)
	{
		if (ent->client->ps.otherKillerDebounceTime < (level.time + 100))
		{
			ent->client->ps.otherKillerDebounceTime = level.time + 100;
		}
	}

//	WP_ForcePowersUpdate( ent, msec, ucmd); //update any active force powers
//	WP_SaberPositionUpdate(ent, ucmd); //check the server-side saber point, do apprioriate server-side actions (effects are cs-only)

	if ((ent->client->pers.cmd.buttons & BUTTON_USE) && ent->client->ps.useDelay < level.time)
	{
		TryUse(ent);
		ent->client->ps.useDelay = level.time + 100;
	}

	pm.ps = &client->ps;
	pm.cmd = *ucmd;
	if ( pm.ps->pm_type == PM_DEAD ) {
		pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
	}
	else if ( ent->r.svFlags & SVF_BOT ) {
		pm.tracemask = MASK_PLAYERSOLID | CONTENTS_MONSTERCLIP;
	}
	else {
		pm.tracemask = MASK_PLAYERSOLID;
	}
	pm.trace = trap_Trace;
	pm.pointcontents = trap_PointContents;
	pm.debugLevel = g_debugMove.integer;
	pm.noFootsteps = ( g_dmflags.integer & DF_NO_FOOTSTEPS ) > 0;

	pm.pmove_fixed = pmove_fixed.integer | client->pers.pmoveFixed;
	pm.pmove_msec = pmove_msec.integer;

	pm.animations = bgGlobalAnimations;//NULL;

	pm.gametype = g_gametype.integer;

	VectorCopy( client->ps.origin, client->oldOrigin );

	if (level.intermissionQueued != 0 && g_singlePlayer.integer) {
		if ( level.time - level.intermissionQueued >= 1000  ) {
			pm.cmd.buttons = 0;
			pm.cmd.forwardmove = 0;
			pm.cmd.rightmove = 0;
			pm.cmd.upmove = 0;
			if ( level.time - level.intermissionQueued >= 2000 && level.time - level.intermissionQueued <= 2500 ) {
				trap_SendConsoleCommand( EXEC_APPEND, "centerview\n");
			}
			ent->client->ps.pm_type = PM_SPINTERMISSION;
		}
	}

	for ( i = 0 ; i < MAX_CLIENTS ; i++ )
	{
		if (g_entities[i].inuse && g_entities[i].client)
		{
			pm.bgClients[i] = &g_entities[i].client->ps;
		}
	}

	if (ent->client->ps.saberLockTime > level.time)
	{
		gentity_t *blockOpp = &g_entities[ent->client->ps.saberLockEnemy];

		if (blockOpp && blockOpp->inuse && blockOpp->client)
		{
			vec3_t lockDir, lockAng;

			//VectorClear( ent->client->ps.velocity );
			VectorSubtract( blockOpp->r.currentOrigin, ent->r.currentOrigin, lockDir );
			//lockAng[YAW] = vectoyaw( defDir );
			vectoangles(lockDir, lockAng);
			SetClientViewAngle( ent, lockAng );
		}

		if ( ( ent->client->buttons & BUTTON_ATTACK ) && ! ( ent->client->oldbuttons & BUTTON_ATTACK ) )
		{
			ent->client->ps.saberLockHits++;
		}
		if (ent->client->ps.saberLockHits > 2)
		{
			if (!ent->client->ps.saberLockAdvance)
			{
				ent->client->ps.saberLockHits -= 3;
			}
			ent->client->ps.saberLockAdvance = qtrue;
		}
	}
	else
	{
		ent->client->ps.saberLockFrame = 0;
		//check for taunt
		if ( (pm.cmd.generic_cmd == GENCMD_ENGAGE_DUEL) && (g_gametype.integer == GT_TOURNAMENT) )
		{//already in a duel, make it a taunt command
			pm.cmd.buttons |= BUTTON_GESTURE;
		}
	}

	Pmove (&pm);

	if (pm.checkDuelLoss)
	{
		if (pm.checkDuelLoss > 0 && pm.checkDuelLoss <= MAX_CLIENTS)
		{
			gentity_t *clientLost = &g_entities[pm.checkDuelLoss-1];

			if (clientLost && clientLost->inuse && clientLost->client && Q_irand(0, 40) > clientLost->health)
			{
				vec3_t attDir;
				VectorSubtract(ent->client->ps.origin, clientLost->client->ps.origin, attDir);
				VectorNormalize(attDir);

				VectorClear(clientLost->client->ps.velocity);
				clientLost->client->ps.forceHandExtend = HANDEXTEND_NONE;
				clientLost->client->ps.forceHandExtendTime = 0;

				gGAvoidDismember = 1;
				G_Damage(clientLost, ent, ent, attDir, clientLost->client->ps.origin, 9999, DAMAGE_NO_PROTECTION, MOD_SABER);

				if (clientLost->health < 1)
				{
					gGAvoidDismember = 2;
					G_CheckForDismemberment(clientLost, clientLost->client->ps.origin, 999, (clientLost->client->ps.legsAnim&~ANIM_TOGGLEBIT));
				}

				gGAvoidDismember = 0;
			}
		}

		pm.checkDuelLoss = 0;
	}

	switch(pm.cmd.generic_cmd)
	{
	case 0:
		break;
	case GENCMD_SABERSWITCH:
		Cmd_ToggleSaber_f(ent);
		break;
	case GENCMD_ENGAGE_DUEL:
		if ( g_gametype.integer == GT_TOURNAMENT )
		{//already in a duel, made it a taunt command
		}
		else
		{
			Cmd_EngageDuel_f(ent);
		}
		break;
	case GENCMD_FORCE_HEAL:
		ForceHeal(ent);
		break;
	case GENCMD_FORCE_SPEED:
		ForceSpeed(ent, 0);
		break;
	case GENCMD_FORCE_THROW:
		ForceThrow(ent, qfalse);
		break;
	case GENCMD_FORCE_PULL:
		ForceThrow(ent, qtrue);
		break;
	case GENCMD_FORCE_DISTRACT:
		ForceTelepathy(ent);
		break;
	case GENCMD_FORCE_RAGE:
		ForceRage(ent);
		break;
	case GENCMD_FORCE_PROTECT:
		ForceProtect(ent);
		break;
	case GENCMD_FORCE_ABSORB:
		ForceAbsorb(ent);
		break;
	case GENCMD_FORCE_HEALOTHER:
		ForceTeamHeal(ent);
		break;
	case GENCMD_FORCE_FORCEPOWEROTHER:
		ForceTeamForceReplenish(ent);
		break;
	case GENCMD_FORCE_SEEING:
		ForceSeeing(ent);
		break;
	case GENCMD_USE_SEEKER:
		if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_SEEKER)) &&
			G_ItemUsable(&ent->client->ps, HI_SEEKER) )
		{
			ItemUse_Seeker(ent);
			G_AddEvent(ent, EV_USE_ITEM0+HI_SEEKER, 0);
			ent->client->ps.stats[STAT_HOLDABLE_ITEMS] &= ~(1 << HI_SEEKER);
		}
		break;
	case GENCMD_USE_FIELD:
		if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_SHIELD)) &&
			G_ItemUsable(&ent->client->ps, HI_SHIELD) )
		{
			ItemUse_Shield(ent);
			G_AddEvent(ent, EV_USE_ITEM0+HI_SHIELD, 0);
			ent->client->ps.stats[STAT_HOLDABLE_ITEMS] &= ~(1 << HI_SHIELD);
		}
		break;
	case GENCMD_USE_BACTA:
		if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_MEDPAC)) &&
			G_ItemUsable(&ent->client->ps, HI_MEDPAC) )
		{
			ItemUse_MedPack(ent);
			G_AddEvent(ent, EV_USE_ITEM0+HI_MEDPAC, 0);
			ent->client->ps.stats[STAT_HOLDABLE_ITEMS] &= ~(1 << HI_MEDPAC);
		}
		break;
	case GENCMD_USE_ELECTROBINOCULARS:
		if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_BINOCULARS)) &&
			G_ItemUsable(&ent->client->ps, HI_BINOCULARS) )
		{
			ItemUse_Binoculars(ent);
			if (ent->client->ps.zoomMode == 0)
			{
				G_AddEvent(ent, EV_USE_ITEM0+HI_BINOCULARS, 1);
			}
			else
			{
				G_AddEvent(ent, EV_USE_ITEM0+HI_BINOCULARS, 2);
			}
		}
		break;
	case GENCMD_ZOOM:
		if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_BINOCULARS)) &&
			G_ItemUsable(&ent->client->ps, HI_BINOCULARS) )
		{
			ItemUse_Binoculars(ent);
			if (ent->client->ps.zoomMode == 0)
			{
				G_AddEvent(ent, EV_USE_ITEM0+HI_BINOCULARS, 1);
			}
			else
			{
				G_AddEvent(ent, EV_USE_ITEM0+HI_BINOCULARS, 2);
			}
		}
		break;
	case GENCMD_USE_SENTRY:
		if ( (ent->client->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_SENTRY_GUN)) &&
			G_ItemUsable(&ent->client->ps, HI_SENTRY_GUN) )
		{
			ItemUse_Sentry(ent);
			G_AddEvent(ent, EV_USE_ITEM0+HI_SENTRY_GUN, 0);
			ent->client->ps.stats[STAT_HOLDABLE_ITEMS] &= ~(1 << HI_SENTRY_GUN);
		}
		break;
	case GENCMD_SABERATTACKCYCLE:
		Cmd_SaberAttackCycle_f(ent);
		break;
	default:
		break;
	}

	// save results of pmove
	if ( ent->client->ps.eventSequence != oldEventSequence ) {
		ent->eventTime = level.time;
	}
	if (g_smoothClients.integer) {
		BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue );
	}
	else {
		BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue );
	}
	SendPendingPredictableEvents( &ent->client->ps );

	if ( !( ent->client->ps.eFlags & EF_FIRING ) ) {
		client->fireHeld = qfalse;		// for grapple
	}

	// use the snapped origin for linking so it matches client predicted versions
	VectorCopy( ent->s.pos.trBase, ent->r.currentOrigin );

	VectorCopy (pm.mins, ent->r.mins);
	VectorCopy (pm.maxs, ent->r.maxs);

	ent->waterlevel = pm.waterlevel;
	ent->watertype = pm.watertype;

	// execute client events
	ClientEvents( ent, oldEventSequence );

	if ( pm.useEvent )
	{
		//TODO: Use
//		TryUse( ent );
	}

	// link entity now, after any personal teleporters have been used
	trap_LinkEntity (ent);
	if ( !ent->client->noclip ) {
		G_TouchTriggers( ent );
	}

	// NOTE: now copy the exact origin over otherwise clients can be snapped into solid
	VectorCopy( ent->client->ps.origin, ent->r.currentOrigin );

	//test for solid areas in the AAS file
//	BotTestAAS(ent->r.currentOrigin);

	// touch other objects
	ClientImpacts( ent, &pm );

	// save results of triggers and client events
	if (ent->client->ps.eventSequence != oldEventSequence) {
		ent->eventTime = level.time;
	}

	// swap and latch button actions
	client->oldbuttons = client->buttons;
	client->buttons = ucmd->buttons;
	client->latched_buttons |= client->buttons & ~client->oldbuttons;

	// Did we kick someone in our pmove sequence?
	if (client->ps.forceKickFlip)
	{
		gentity_t *faceKicked = &g_entities[client->ps.forceKickFlip-1];

		if (faceKicked && faceKicked->client && (!OnSameTeam(ent, faceKicked) || g_friendlyFire.integer) &&
			(!faceKicked->client->ps.duelInProgress || faceKicked->client->ps.duelIndex == ent->s.number) &&
			(!ent->client->ps.duelInProgress || ent->client->ps.duelIndex == faceKicked->s.number))
		{
			if ( faceKicked && faceKicked->client && faceKicked->health && faceKicked->takedamage )
			{//push them away and do pain
				vec3_t oppDir;
				int strength = (int)VectorNormalize2( client->ps.velocity, oppDir );

				strength *= 0.05;

				VectorScale( oppDir, -1, oppDir );

				G_Damage( faceKicked, ent, ent, oppDir, client->ps.origin, strength, DAMAGE_NO_ARMOR, MOD_MELEE );

				if ( faceKicked->client->ps.weapon != WP_SABER ||
					 faceKicked->client->ps.fd.saberAnimLevel < FORCE_LEVEL_3 ||
					 (!BG_SaberInAttack(faceKicked->client->ps.saberMove) && !PM_SaberInStart(faceKicked->client->ps.saberMove) && !PM_SaberInReturn(faceKicked->client->ps.saberMove) && !PM_SaberInTransition(faceKicked->client->ps.saberMove)) )
				{
					if (faceKicked->health > 0 &&
						faceKicked->client->ps.stats[STAT_HEALTH] > 0 &&
						faceKicked->client->ps.forceHandExtend != HANDEXTEND_KNOCKDOWN)
					{
						if (Q_irand(1, 10) <= 3)
						{ //only actually knock over sometimes, but always do velocity hit
							faceKicked->client->ps.forceHandExtend = HANDEXTEND_KNOCKDOWN;
							faceKicked->client->ps.forceHandExtendTime = level.time + 1100;
							faceKicked->client->ps.forceDodgeAnim = 0; //this toggles between 1 and 0, when it's 1 we should play the get up anim
						}

						faceKicked->client->ps.otherKiller = ent->s.number;
						faceKicked->client->ps.otherKillerTime = level.time + 5000;
						faceKicked->client->ps.otherKillerDebounceTime = level.time + 100;

						faceKicked->client->ps.velocity[0] = oppDir[0]*(strength*40);
						faceKicked->client->ps.velocity[1] = oppDir[1]*(strength*40);
						faceKicked->client->ps.velocity[2] = 200;
					}
				}

				G_Sound( faceKicked, CHAN_AUTO, G_SoundIndex( va("sound/weapons/melee/punch%d", Q_irand(1, 4)) ) );
			}
		}

		client->ps.forceKickFlip = 0;
	}

	// check for respawning
	if ( client->ps.stats[STAT_HEALTH] <= 0 ) {
		// wait for the attack button to be pressed
		if ( level.time > client->respawnTime && !gDoSlowMoDuel ) {
			// forcerespawn is to prevent users from waiting out powerups
			if ( g_forcerespawn.integer > 0 &&
				( level.time - client->respawnTime ) > g_forcerespawn.integer * 1000 ) {
				respawn( ent );
				return;
			}

			// pressing attack or use is the normal respawn method
			if ( ucmd->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) ) {
				respawn( ent );
			}
		}
		else if (gDoSlowMoDuel)
		{
			client->respawnTime = level.time + 1000;
		}
		return;
	}

	// perform once-a-second actions
	ClientTimerActions( ent, msec );

	G_UpdateClientBroadcasts ( ent );
}
示例#28
0
/*
================
G_MissileImpact
================
*/
void G_MissileImpact( gentity_t *ent, trace_t *trace ) {
	gentity_t		*other;
	qboolean		hitClient = qfalse;
	vec3_t			forward, impactpoint, bouncedir;
	int				eFlags;
	other = &g_entities[trace->entityNum];

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

	if ( other->takedamage ) {
		if ( ent->s.weapon != WP_PROX_LAUNCHER ) {
			if ( other->client && other->client->invulnerabilityTime > level.time ) {
              
				//
				VectorCopy( ent->s.pos.trDelta, forward );
				VectorNormalize( forward );
				if (G_InvulnerabilityEffect( other, forward, ent->s.pos.trBase, impactpoint, bouncedir )) {
					VectorCopy( bouncedir, trace->plane.normal );
					eFlags = ent->s.eFlags & EF_BOUNCE_HALF;
					ent->s.eFlags &= ~EF_BOUNCE_HALF;
					G_BounceMissile( ent, trace );
					ent->s.eFlags |= eFlags;
				}
				ent->target_ent = other;
				return;
			}
		}
	}
	// impact damage
	if (other->takedamage) {
		// FIXME: wrong damage direction?
		if ( ent->damage ) {
			vec3_t	velocity;

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

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

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

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

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

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

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

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

		return;
	}

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

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

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

			ent->enemy = other;

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

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

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

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

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

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

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

		trap_LinkEntity( ent );
		trap_LinkEntity( nent );

		return;
	}

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

	if ( other->takedamage && other->client ) {
		G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
		ent->s.otherEntityNum = other->s.number;
	} else if( trace->surfaceFlags & SURF_METALSTEPS ) {
		G_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( trace->plane.normal ) );
	} else {
		G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
	}

	ent->freeAfterEvent = qtrue;

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

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

	G_SetOrigin( ent, trace->endpos );

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

	trap_LinkEntity( ent );
}
示例#29
0
文件: g_weapon.c 项目: ZFect/yquake2
void
fire_blaster(edict_t *self, vec3_t start, vec3_t dir, int damage,
		int speed, int effect, qboolean hyper)
{
	edict_t *bolt;
	trace_t tr;

	if (!self)
	{
		return;
	}

	VectorNormalize(dir);

	bolt = G_Spawn();
	bolt->svflags = SVF_DEADMONSTER;

	/* yes, I know it looks weird that projectiles are deadmonsters
	   what this means is that when prediction is used against the object
	   (blaster/hyperblaster shots), the player won't be solid clipped against
	   the object.  Right now trying to run into a firing hyperblaster
	   is very jerky since you are predicted 'against' the shots. */
	VectorCopy(start, bolt->s.origin);
	VectorCopy(start, bolt->s.old_origin);
	vectoangles(dir, bolt->s.angles);
	VectorScale(dir, speed, bolt->velocity);
	bolt->movetype = MOVETYPE_FLYMISSILE;
	bolt->clipmask = MASK_SHOT;
	bolt->solid = SOLID_BBOX;
	bolt->s.effects |= effect;
	bolt->s.renderfx |= RF_NOSHADOW;
	VectorClear(bolt->mins);
	VectorClear(bolt->maxs);
	bolt->s.modelindex = gi.modelindex("models/objects/laser/tris.md2");
	bolt->s.sound = gi.soundindex("misc/lasfly.wav");
	bolt->owner = self;
	bolt->touch = blaster_touch;
	bolt->nextthink = level.time + 2;
	bolt->think = G_FreeEdict;
	bolt->dmg = damage;
	bolt->classname = "bolt";

	if (hyper)
	{
		bolt->spawnflags = 1;
	}

	gi.linkentity(bolt);

	if (self->client)
	{
		check_dodge(self, bolt->s.origin, dir, speed);
	}

	tr = gi.trace(self->s.origin, NULL, NULL, bolt->s.origin, bolt, MASK_SHOT);

	if (tr.fraction < 1.0)
	{
		VectorMA(bolt->s.origin, -10, dir, bolt->s.origin);
		bolt->touch(bolt, tr.ent, NULL, NULL);
	}
}
示例#30
0
文件: g_misc.c 项目: basecq/q2dos
void teleporter_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
	edict_t		*dest;
	int			i;
	vec3_t		nodeo;

	if (!other->client)
		return;
	dest = G_Find (NULL, FOFS(targetname), self->target);
	if (!dest)
	{
		gi.dprintf(DEVELOPER_MSG_GAME, "Couldn't find destination\n");
		return;
	}

	if (!Bot_FindNode(self, 120, TELEPORT_NODE)
		&& dntg->value)
	{
		//start node
		VectorCopy (other->s.origin, nodeo);
		
		if (!(other->client->ps.pmove.pm_flags & PMF_DUCKED))
		{
			nodeo[2] += 5;
			Bot_PlaceNode(nodeo, TELEPORT_NODE, 0);
		}
		else
			Bot_PlaceNode(nodeo, TELEPORT_NODE, 1);
		
		Bot_CalcNode(other, numnodes);

		//dest node
		VectorCopy (dest->s.origin, nodeo);
		nodeo[2] += 20;
		Bot_PlaceNode(nodeo, NORMAL_NODE, 0);
		Bot_CalcNode(other, numnodes);
		
		//connection
		nodes[numnodes-1].dist[numnodes] = 1;

		nprintf(PRINT_HIGH, "Teleporter nodes placed and connected!\n");
	}

	// unlink to make sure it can't possibly interfere with KillBox
	gi.unlinkentity (other);

	VectorCopy (dest->s.origin, other->s.origin);
	VectorCopy (dest->s.origin, other->s.old_origin);
	other->s.origin[2] += 10;

	// clear the velocity and hold them in place briefly
	VectorClear (other->velocity);
	other->client->ps.pmove.pm_time = 160>>3;		// hold time
	other->client->ps.pmove.pm_flags |= PMF_TIME_TELEPORT;

	// draw the teleport splash at source and on the player
	self->owner->s.event = EV_PLAYER_TELEPORT;
	other->s.event = EV_PLAYER_TELEPORT;

	// set angles
	for (i=0 ; i<3 ; i++)
		other->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(dest->s.angles[i] - other->client->resp.cmd_angles[i]);

	VectorClear (other->s.angles);
	VectorClear (other->client->ps.viewangles);
	VectorClear (other->client->v_angle);

	// kill anything at the destination
	KillBox (other);

	gi.linkentity (other);
}