Esempio n. 1
0
//---------------------------------------------------------
gentity_t *WP_FireThermalDetonator( gentity_t *ent, qboolean altFire )
//---------------------------------------------------------
{
	gentity_t	*bolt;
	vec3_t		dir, start;
	float chargeAmount = 1.0f; // default of full charge

	VectorCopy( forward, dir );
	VectorCopy( muzzle, start );

	bolt = G_Spawn();

	bolt->physicsObject = qtrue;

	bolt->classname = "thermal_detonator";
	bolt->think = thermalThinkStandard;
	bolt->nextthink = level.time;
	bolt->touch = Thermal_Touch;

	// How 'bout we give this thing a size...
	VectorSet( bolt->r.mins, -3.0f, -3.0f, -3.0f );
	VectorSet( bolt->r.maxs, 3.0f, 3.0f, 3.0f );
	bolt->clipmask = MASK_SHOT;

	WP_TraceSetStart( ent, start, bolt->r.mins, bolt->r.maxs );//make sure our start point isn't on the other side of a wall

	if ( ent->client )
	{
		chargeAmount = level.time - ent->client->ps.weaponChargeTime;
	}

	// get charge amount
	chargeAmount = chargeAmount / (float)TD_VELOCITY;

	if ( chargeAmount > 1.0f )
	{
		chargeAmount = 1.0f;
	}
	else if ( chargeAmount < TD_MIN_CHARGE )
	{
		chargeAmount = TD_MIN_CHARGE;
	}

	// normal ones bounce, alt ones explode on impact
	bolt->genericValue5 = level.time + TD_TIME; // How long 'til she blows
	bolt->s.pos.trType = TR_GRAVITY;
	bolt->parent = ent;
	bolt->r.ownerNum = ent->s.number;
	VectorScale( dir, TD_VELOCITY * chargeAmount, bolt->s.pos.trDelta );

	if ( ent->health >= 0 )
	{
		bolt->s.pos.trDelta[2] += 120;
	}

	if ( !altFire )
	{
		bolt->flags |= FL_BOUNCE_HALF;
	}

	bolt->s.loopSound = G_SoundIndex( "sound/weapons/thermal/thermloop.wav" );
	bolt->s.loopIsSoundset = qfalse;

	bolt->damage = TD_DAMAGE;
	bolt->dflags = 0;
	bolt->splashDamage = TD_SPLASH_DAM;
	bolt->splashRadius = TD_SPLASH_RAD;

	bolt->s.eType = ET_MISSILE;
	bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
	bolt->s.weapon = WP_THERMAL;

	bolt->methodOfDeath = MOD_THERMAL;
	bolt->splashMethodOfDeath = MOD_THERMAL_SPLASH;

	bolt->s.pos.trTime = level.time;		// move a bit on the very first frame
	VectorCopy( start, bolt->s.pos.trBase );

	SnapVector( bolt->s.pos.trDelta );			// save net bandwidth
	VectorCopy (start, bolt->r.currentOrigin);

	VectorCopy( start, bolt->pos2 );

	bolt->bounceCount = -5;

	return bolt;
}
Esempio n. 2
0
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void AAS_ShowReachability(aas_reachability_t *reach)
{
	vec3_t dir, cmdmove, velocity;
	float speed, zvel;
	aas_clientmove_t move;

	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_PredictClientMovement(&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);
		//
		if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP)
		{
			AAS_JumpReachRunStart(reach, dir);
			AAS_DrawCross(dir, 4, LINECOLOR_BLUE);
		} //end if
	} //end if
	else if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_ROCKETJUMP)
	{
		zvel = AAS_RocketJumpZVelocity(reach->start);
		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_PredictClientMovement(&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);
	} //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_PredictClientMovement(&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);
	} //end else if
} //end of the function AAS_ShowReachability
Esempio n. 3
0
void AAS_AddTeleporterPortals(void)
{
	int j, area2num, facenum, otherareanum;
	char *target, *targetname, *classname;
	bsp_entity_t *entities, *ent, *dest;
	vec3_t origin, destorigin, mins, maxs, end;
	vec3_t bbmins, bbmaxs;
	aas_area_t *area;
	aas_face_t *face;
	aas_trace_t trace;
	aas_link_t *areas, *link;

	entities = AAS_ParseBSPEntities();

	for (ent = entities; ent; ent = ent->next)
	{
		classname = AAS_ValueForBSPEpairKey(ent, "classname");
		if (classname && !strcmp(classname, "misc_teleporter"))
		{
			if (!AAS_VectorForBSPEpairKey(ent, "origin", origin))
			{
				botimport.Print(PRT_ERROR, "teleporter (%s) without origin\n", target);
				continue;
			} //end if
			//
			target = AAS_ValueForBSPEpairKey(ent, "target");
			if (!target)
			{
				botimport.Print(PRT_ERROR, "teleporter (%s) without target\n", target);
				continue;
			} //end if
			for (dest = entities; dest; dest = dest->next)
			{
				classname = AAS_ValueForBSPEpairKey(dest, "classname");
				if (classname && !strcmp(classname, "misc_teleporter_dest"))
				{
					targetname = AAS_ValueForBSPEpairKey(dest, "targetname");
					if (targetname && !strcmp(targetname, target))
					{
						break;
					} //end if
				} //end if
			} //end for
			if (!dest)
			{
				botimport.Print(PRT_ERROR, "teleporter without destination (%s)\n", target);
				continue;
			} //end if
			if (!AAS_VectorForBSPEpairKey(dest, "origin", destorigin))
			{
				botimport.Print(PRT_ERROR, "teleporter destination (%s) without origin\n", target);
				continue;
			} //end if
			destorigin[2] += 24; //just for q2e1m2, the dork has put the telepads in the ground
			VectorCopy(destorigin, end);
			end[2] -= 100;
			trace = AAS_TraceClientBBox(destorigin, end, PRESENCE_CROUCH, -1);
			if (trace.startsolid)
			{
				botimport.Print(PRT_ERROR, "teleporter destination (%s) in solid\n", target);
				continue;
			} //end if
			VectorCopy(trace.endpos, destorigin);
			area2num = AAS_PointAreaNum(destorigin);
			//reset all cluster fields
			for (j = 0; j < aasworld.numareas; j++)
			{
				aasworld.areasettings[j].cluster = 0;
			} //end for
			//
			VectorSet(mins, -8, -8, 8);
			VectorSet(maxs, 8, 8, 24);
			//
			AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bbmins, bbmaxs);
			//
			VectorAdd(origin, mins, mins);
			VectorAdd(origin, maxs, maxs);
			//add bounding box size
			VectorSubtract(mins, bbmaxs, mins);
			VectorSubtract(maxs, bbmins, maxs);
			//link an invalid (-1) entity
			areas = AAS_AASLinkEntity(mins, maxs, -1);
			//
			for (link = areas; link; link = link->next_area)
			{
				if (!AAS_AreaGrounded(link->areanum)) continue;
				//add the teleporter portal mark
				aasworld.areasettings[link->areanum].contents |= AREACONTENTS_CLUSTERPORTAL |
																			AREACONTENTS_TELEPORTAL;
			} //end for
			//
			for (link = areas; link; link = link->next_area)
			{
				if (!AAS_AreaGrounded(link->areanum)) continue;
				//find a non-portal area adjacent to the portal area and flood
				//the cluster from there
				area = &aasworld.areas[link->areanum];
				for (j = 0; j < area->numfaces; j++)
				{
					facenum = abs(aasworld.faceindex[area->firstface + j]);
					face = &aasworld.faces[facenum];
					//
					if (face->frontarea != link->areanum) otherareanum = face->frontarea;
					else otherareanum = face->backarea;
					//
					if (!otherareanum) continue;
					//
					if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL)
					{
						continue;
					} //end if
					//
					AAS_FloodCluster_r(otherareanum, 1);
				} //end for
			} //end for
			//if the teleport destination IS in the same cluster
			if (aasworld.areasettings[area2num].cluster)
			{
				for (link = areas; link; link = link->next_area)
				{
					if (!AAS_AreaGrounded(link->areanum)) continue;
					//add the teleporter portal mark
					aasworld.areasettings[link->areanum].contents &= ~(AREACONTENTS_CLUSTERPORTAL |
																				AREACONTENTS_TELEPORTAL);
				} //end for
			} //end if
		} //end if
	} //end for
	AAS_FreeBSPEntities(entities);
} //end of the function AAS_AddTeleporterPortals
Esempio n. 4
0
/*
===============
CG_OffsetFirstPersonView

===============
*/
static void CG_OffsetFirstPersonView( void )
{
  float         *origin;
  float         *angles;
  float         bob;
  float         ratio;
  float         delta;
  float         speed;
  float         f;
  vec3_t        predictedVelocity;
  int           timeDelta;
  float         bob2;
  vec3_t        normal, baseOrigin;
  playerState_t *ps = &cg.predictedPlayerState;

  if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
  {
    if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
      VectorSet( normal, 0.0f, 0.0f, -1.0f );
    else
      VectorCopy( ps->grapplePoint, normal );
  }
  else
    VectorSet( normal, 0.0f, 0.0f, 1.0f );


  if( cg.snap->ps.pm_type == PM_INTERMISSION )
    return;

  origin = cg.refdef.vieworg;
  angles = cg.refdefViewAngles;

  VectorCopy( origin, baseOrigin );

  // if dead, fix the angle and don't add any kick
  if( cg.snap->ps.stats[ STAT_HEALTH ] <= 0 )
  {
    angles[ ROLL ] = 40;
    angles[ PITCH ] = -15;
    angles[ YAW ] = cg.snap->ps.stats[ STAT_VIEWLOCK ];
    origin[ 2 ] += cg.predictedPlayerState.viewheight;
    return;
  }

  // add angles based on weapon kick
  VectorAdd( angles, cg.kick_angles, angles );

  // add angles based on damage kick
  if( cg.damageTime )
  {
    ratio = cg.time - cg.damageTime;
    if( ratio < DAMAGE_DEFLECT_TIME )
    {
      ratio /= DAMAGE_DEFLECT_TIME;
      angles[ PITCH ] += ratio * cg.v_dmg_pitch;
      angles[ ROLL ] += ratio * cg.v_dmg_roll;
    }
    else
    {
      ratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME;
      if( ratio > 0 )
      {
        angles[ PITCH ] += ratio * cg.v_dmg_pitch;
        angles[ ROLL ] += ratio * cg.v_dmg_roll;
      }
    }
  }

  // add pitch based on fall kick
#if 0
  ratio = ( cg.time - cg.landTime) / FALL_TIME;
  if (ratio < 0)
    ratio = 0;
  angles[PITCH] += ratio * cg.fall_value;
#endif

  // add angles based on velocity
  VectorCopy( cg.predictedPlayerState.velocity, predictedVelocity );

  delta = DotProduct( predictedVelocity, cg.refdef.viewaxis[ 0 ] );
  angles[ PITCH ] += delta * cg_runpitch.value;

  delta = DotProduct( predictedVelocity, cg.refdef.viewaxis[ 1 ] );
  angles[ ROLL ] -= delta * cg_runroll.value;

  // add angles based on bob
  // bob amount is class dependant

  if( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR )
    bob2 = 0.0f;
  else
    bob2 = BG_FindBobForClass( cg.predictedPlayerState.stats[ STAT_PCLASS ] );


#define LEVEL4_FEEDBACK  10.0f

  //give a charging player some feedback
  if( ps->weapon == WP_ALEVEL4 )
  {
    if( ps->stats[ STAT_MISC ] > 0 )
    {
      float fraction = (float)ps->stats[ STAT_MISC ] / (float)LEVEL4_CHARGE_TIME;

      if( fraction > 1.0f )
        fraction = 1.0f;

      bob2 *= ( 1.0f + fraction * LEVEL4_FEEDBACK );
    }
  }

  if( bob2 != 0.0f )
  {
    // make sure the bob is visible even at low speeds
    speed = cg.xyspeed > 200 ? cg.xyspeed : 200;

    delta = cg.bobfracsin * ( bob2 ) * speed;
    if( cg.predictedPlayerState.pm_flags & PMF_DUCKED )
      delta *= 3;   // crouching

    angles[ PITCH ] += delta;
    delta = cg.bobfracsin * ( bob2 ) * speed;
    if( cg.predictedPlayerState.pm_flags & PMF_DUCKED )
      delta *= 3;   // crouching accentuates roll

    if( cg.bobcycle & 1 )
      delta = -delta;

    angles[ ROLL ] += delta;
  }

#define LEVEL3_FEEDBACK  20.0f

  //provide some feedback for pouncing
  if( cg.predictedPlayerState.weapon == WP_ALEVEL3 ||
      cg.predictedPlayerState.weapon == WP_ALEVEL3_UPG )
  {
    if( cg.predictedPlayerState.stats[ STAT_MISC ] > 0 )
    {
      float   fraction1, fraction2;
      vec3_t  forward;

      AngleVectors( angles, forward, NULL, NULL );
      VectorNormalize( forward );

      fraction1 = (float)( cg.time - cg.weapon2Time ) / (float)LEVEL3_POUNCE_CHARGE_TIME;

      if( fraction1 > 1.0f )
        fraction1 = 1.0f;

      fraction2 = -sin( fraction1 * M_PI / 2 );

      VectorMA( origin, LEVEL3_FEEDBACK * fraction2, forward, origin );
    }
  }

#define STRUGGLE_DIST 5.0f
#define STRUGGLE_TIME 250

  //allow the player to struggle a little whilst grabbed
  if( cg.predictedPlayerState.pm_type == PM_GRABBED )
  {
    vec3_t    forward, right, up;
    usercmd_t cmd;
    int       cmdNum;
    float     fFraction, rFraction, uFraction;
    float     fFraction2, rFraction2, uFraction2;

    cmdNum = trap_GetCurrentCmdNumber();
    trap_GetUserCmd( cmdNum, &cmd );

    AngleVectors( angles, forward, right, up );

    fFraction = (float)( cg.time - cg.forwardMoveTime ) / STRUGGLE_TIME;
    rFraction = (float)( cg.time - cg.rightMoveTime ) / STRUGGLE_TIME;
    uFraction = (float)( cg.time - cg.upMoveTime ) / STRUGGLE_TIME;

    if( fFraction > 1.0f )
      fFraction = 1.0f;
    if( rFraction > 1.0f )
      rFraction = 1.0f;
    if( uFraction > 1.0f )
      uFraction = 1.0f;

    fFraction2 = -sin( fFraction * M_PI / 2 );
    rFraction2 = -sin( rFraction * M_PI / 2 );
    uFraction2 = -sin( uFraction * M_PI / 2 );

    if( cmd.forwardmove > 0 )
      VectorMA( origin, STRUGGLE_DIST * fFraction, forward, origin );
    else if( cmd.forwardmove < 0 )
      VectorMA( origin, -STRUGGLE_DIST * fFraction, forward, origin );
    else
      cg.forwardMoveTime = cg.time;

    if( cmd.rightmove > 0 )
      VectorMA( origin, STRUGGLE_DIST * rFraction, right, origin );
    else if( cmd.rightmove < 0 )
      VectorMA( origin, -STRUGGLE_DIST * rFraction, right, origin );
    else
      cg.rightMoveTime = cg.time;

    if( cmd.upmove > 0 )
      VectorMA( origin, STRUGGLE_DIST * uFraction, up, origin );
    else if( cmd.upmove < 0 )
      VectorMA( origin, -STRUGGLE_DIST * uFraction, up, origin );
    else
      cg.upMoveTime = cg.time;
  }

  if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_POISONCLOUDED &&
      !( cg.snap->ps.pm_flags & PMF_FOLLOW ) )
  {
    float fraction = sin( ( (float)cg.time / 1000.0f ) * M_PI * 2 * PCLOUD_ROLL_FREQUENCY );
    float pitchFraction = sin( ( (float)cg.time / 1000.0f ) * M_PI * 5 * PCLOUD_ROLL_FREQUENCY );

    fraction *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)LEVEL1_PCLOUD_TIME );
    pitchFraction *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)LEVEL1_PCLOUD_TIME );

    angles[ ROLL ] += fraction * PCLOUD_ROLL_AMPLITUDE;
    angles[ YAW ] += fraction * PCLOUD_ROLL_AMPLITUDE;
    angles[ PITCH ] += pitchFraction * PCLOUD_ROLL_AMPLITUDE / 2.0f;
  }

  // this *feels* more realisitic for humans
  if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_HUMANS )
  {
    angles[PITCH] += cg.bobfracsin * bob2 * 0.5;

    // heavy breathing effects //FIXME: sound
    if( cg.predictedPlayerState.stats[ STAT_STAMINA ] < 0 )
    {
      float deltaBreath = (float)(
        cg.predictedPlayerState.stats[ STAT_STAMINA ] < 0 ?
        -cg.predictedPlayerState.stats[ STAT_STAMINA ] :
        cg.predictedPlayerState.stats[ STAT_STAMINA ] ) / 200.0;
      float deltaAngle = cos( (float)cg.time/150.0 ) * deltaBreath;

      deltaAngle += ( deltaAngle < 0 ? -deltaAngle : deltaAngle ) * 0.5;

      angles[ PITCH ] -= deltaAngle;
    }

  //ZdrytchX: Personal view bug fix hack [see youtube.com/zdrytchx: mdriver false bullet physics test,
  //you'll see how annoying it is in sniping for me, turns out the correction value for myself is approx
  //-1.19 degrees that actualy changes with pitch... I need to find a way to fix this.]
  //@jkent: Thinking of which, I have an idea: facetracker compatability, haha...
    if( cg_firstpersonanglefix_yaw.value != 0)
    {
        if( cg_firstpersonanglefix_yaw.value > 20) //TODO: make sure we don't cheat here! (doesn't work)
        trap_Cvar_Set( "cg_firstpersonanglefix_yaw.value", "20" );
        else if( cg_firstpersonanglefix_yaw.value < -20)
        trap_Cvar_Set( "cg_firstpersonanglefix_yaw.value", "-20" );
        //Set angle fix! 
        angles[ YAW ] += cg_firstpersonanglefix_yaw.value; //left is positive (backward people's tradition)
    }

    if( cg_firstpersonanglefix_pitch.value != 0)
    {
        if( cg_firstpersonanglefix_pitch.value > 20) //TODO: make sure we don't cheat here! (doesn't work)
        trap_Cvar_Set( "cg_firstpersonanglefix_pitch.value", "20" );
        else if( cg_firstpersonanglefix_pitch.value < -20)
        trap_Cvar_Set( "cg_firstpersonanglefix_pitch.value", "-20" );
        //Set angle fix! 
        angles[ PITCH ] -= cg_firstpersonanglefix_pitch.value; //up is positive
    }

  }

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

  // add view height
  // when wall climbing the viewheight is not straight up
  if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING )
    VectorMA( origin, ps->viewheight, normal, origin );
  else
    origin[ 2 ] += cg.predictedPlayerState.viewheight;

  // smooth out duck height changes
  timeDelta = cg.time - cg.duckTime;
  if( timeDelta < DUCK_TIME)
  {
    cg.refdef.vieworg[ 2 ] -= cg.duckChange
      * ( DUCK_TIME - timeDelta ) / DUCK_TIME;
  }

  // add bob height
  bob = cg.bobfracsin * cg.xyspeed * bob2;

  if( bob > 6 )
    bob = 6;

  // likewise for bob
  if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING )
    VectorMA( origin, bob, normal, origin );
  else
    origin[ 2 ] += bob;


  // add fall height
  delta = cg.time - cg.landTime;

  if( delta < LAND_DEFLECT_TIME )
  {
    f = delta / LAND_DEFLECT_TIME;
    cg.refdef.vieworg[ 2 ] += cg.landChange * f;
  }
  else if( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME )
  {
    delta -= LAND_DEFLECT_TIME;
    f = 1.0 - ( delta / LAND_RETURN_TIME );
    cg.refdef.vieworg[ 2 ] += cg.landChange * f;
  }

  // add step offset
  CG_StepOffset( );

  // add kick offset

  VectorAdd (origin, cg.kick_origin, origin);
}
Esempio n. 5
0
/*
==============
IsHeadShot
==============
*/
qboolean IsHeadShot( gentity_t *targ, gentity_t *attacker, vec3_t dir, vec3_t point, int mod ) {
	gentity_t   *head;
	trace_t tr;
	vec3_t start, end;
	gentity_t   *traceEnt;
	orientation_t or;

	qboolean head_shot_weapon = qfalse;

	// not a player or critter so bail
	if ( !( targ->client ) ) {
		return qfalse;
	}

	if ( targ->health <= 0 ) {
		return qfalse;
	}

	head_shot_weapon = IsHeadShotWeapon( mod, targ, attacker );

	if ( head_shot_weapon ) {
		head = G_Spawn();

		G_SetOrigin( head, targ->r.currentOrigin );

		// RF, if there is a valid tag_head for this entity, then use that
		if ( ( targ->r.svFlags & SVF_CASTAI ) && trap_GetTag( targ->s.number, "tag_head", &or ) ) {
			VectorCopy( or.origin, head->r.currentOrigin );
			VectorMA( head->r.currentOrigin, 6, or.axis[2], head->r.currentOrigin );    // tag is at base of neck
		} else if ( targ->client->ps.pm_flags & PMF_DUCKED ) { // closer fake offset for 'head' box when crouching
			head->r.currentOrigin[2] += targ->client->ps.crouchViewHeight + 8; // JPW NERVE 16 is kludge to get head height to match up
		}
		//else if(targ->client->ps.legsAnim == LEGS_IDLE && targ->aiCharacter == AICHAR_SOLDIER)	// standing with legs bent (about a head shorter than other leg poses)
		//	head->r.currentOrigin[2] += targ->client->ps.viewheight;
		else {
			head->r.currentOrigin[2] += targ->client->ps.viewheight; // JPW NERVE pulled this	// 6 is fudged "head height" value

		}
		VectorCopy( head->r.currentOrigin, head->s.origin );
		VectorCopy( targ->r.currentAngles, head->s.angles );
		VectorCopy( head->s.angles, head->s.apos.trBase );
		VectorCopy( head->s.angles, head->s.apos.trDelta );
		VectorSet( head->r.mins, -6, -6, -6 ); // JPW NERVE changed this z from -12 to -6 for crouching, also removed standing offset
		VectorSet( head->r.maxs, 6, 6, 6 ); // changed this z from 0 to 6
		head->clipmask = CONTENTS_SOLID;
		head->r.contents = CONTENTS_SOLID;

		trap_LinkEntity( head );

		// trace another shot see if we hit the head
		VectorCopy( point, start );
		VectorMA( start, 64, dir, end );
		trap_Trace( &tr, start, NULL, NULL, end, targ->s.number, MASK_SHOT );

		traceEnt = &g_entities[ tr.entityNum ];

		if ( g_debugBullets.integer >= 3 ) {   // show hit player head bb
			gentity_t *tent;
			vec3_t b1, b2;
			VectorCopy( head->r.currentOrigin, b1 );
			VectorCopy( head->r.currentOrigin, b2 );
			VectorAdd( b1, head->r.mins, b1 );
			VectorAdd( b2, head->r.maxs, b2 );
			tent = G_TempEntity( b1, EV_RAILTRAIL );
			VectorCopy( b2, tent->s.origin2 );
			tent->s.dmgFlags = 1;

			// show headshot trace
			// end the headshot trace at the head box if it hits
			if ( tr.fraction != 1 ) {
				VectorMA( start, ( tr.fraction * 64 ), dir, end );
			}
			tent = G_TempEntity( start, EV_RAILTRAIL );
			VectorCopy( end, tent->s.origin2 );
			tent->s.dmgFlags = 0;
		}

		G_FreeEntity( head );

		if ( traceEnt == head ) {
			return qtrue;
		}
	}

	return qfalse;
}
Esempio n. 6
0
/*
=================
R_DrawAliasFrameLerp
=================
*/
void R_DrawAliasFrameLerp (maliasmodel_t *paliashdr, entity_t *e)
{
	int			i, j, k, meshnum;
	maliasframe_t	*frame, *oldframe;
	maliasmesh_t	mesh;
	maliasvertex_t	*v, *ov;
	vec3_t		move, delta, vectors[3];
	vec3_t		curScale, oldScale, curNormal, oldNormal;
	vec3_t		tempNormalsArray[MD3_MAX_VERTS];
	vec2_t		tempSkinCoord;
	vec3_t		meshlight, lightcolor;
	float		alpha, meshalpha, thisalpha, shellscale, frontlerp, backlerp = e->backlerp;
	image_t		*skin;
	renderparms_t	skinParms;
	qboolean	shellModel = e->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM);

	frontlerp = 1.0 - backlerp;

	if (e->flags & RF_TRANSLUCENT)
		alpha = e->alpha;
	else
		alpha = 1.0;

	frame = paliashdr->frames + e->frame;
	oldframe = paliashdr->frames + e->oldframe;

	VectorScale(frame->scale, frontlerp, curScale);
	VectorScale(oldframe->scale, backlerp, oldScale);

	// move should be the delta back to the previous frame * backlerp
	VectorSubtract (e->oldorigin, e->origin, delta);
	AngleVectors (e->angles, vectors[0], vectors[1], vectors[2]);

	move[0] = DotProduct (delta, vectors[0]);	// forward
	move[1] = -DotProduct (delta, vectors[1]);	// left
	move[2] = DotProduct (delta, vectors[2]);	// up

	VectorAdd (move, oldframe->translate, move);

	for (i=0 ; i<3 ; i++)
		move[i] = backlerp*move[i] + frontlerp*frame->translate[i];

	R_SetVertexOverbrights(true);
	R_SetShellBlend (true);

	// new outer loop for whole model
	for (k=0, meshnum=0; k < paliashdr->num_meshes; k++, meshnum++)
	{
		mesh = paliashdr->meshes[k];
		skinParms = mesh.skins[e->skinnum].renderparms;

		// select skin
		if (e->skin)
			skin = e->skin;	// custom player skin
		else
			skin = currentmodel->skins[k][e->skinnum];
		if (!skin)
			skin = r_notexture;
		if ( !shellModel )
			GL_Bind(skin->texnum);
		else if (FlowingShell())
			alpha = 0.7;

		// md3 skin scripting
		if (skinParms.nodraw) 
			continue; // skip this mesh for this skin

		if (skinParms.twosided)
			GL_Disable(GL_CULL_FACE);

		if (skinParms.alphatest && !shellModel)
			GL_Enable(GL_ALPHA_TEST);

		if (skinParms.fullbright)
			VectorSet(meshlight, 1.0f, 1.0f, 1.0f);
		else
			VectorCopy(shadelight, meshlight);

		meshalpha = alpha * skinParms.basealpha;

		if (meshalpha < 1.0f || skinParms.blend)
			GL_Enable (GL_BLEND);
		else
			GL_Disable (GL_BLEND);

		if (skinParms.blend && !shellModel)
			GL_BlendFunc (skinParms.blendfunc_src, skinParms.blendfunc_dst);
		else
			GL_BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		// md3 skin scripting

		v = mesh.vertexes + e->frame*mesh.num_verts;
		ov = mesh.vertexes + e->oldframe*mesh.num_verts;
		rb_vertex = 0;

		for (i=0; i<mesh.num_verts; i++, v++, ov++)
		{
			// lerp verts
			curNormal[0] = r_sinTable[v->normal[0]] * r_cosTable[v->normal[1]];
			curNormal[1] = r_sinTable[v->normal[0]] * r_sinTable[v->normal[1]];
			curNormal[2] = r_cosTable[v->normal[0]];

			oldNormal[0] = r_sinTable[ov->normal[0]] * r_cosTable[ov->normal[1]];
			oldNormal[1] = r_sinTable[ov->normal[0]] * r_sinTable[ov->normal[1]];
			oldNormal[2] = r_cosTable[ov->normal[0]];

			VectorSet ( tempNormalsArray[i],
					curNormal[0] + (oldNormal[0] - curNormal[0])*backlerp,
					curNormal[1] + (oldNormal[1] - curNormal[1])*backlerp,
					curNormal[2] + (oldNormal[2] - curNormal[2])*backlerp );

			if (shellModel) 
				shellscale = (e->flags & RF_WEAPONMODEL) ? WEAPON_SHELL_SCALE: POWERSUIT_SCALE;
			else
				shellscale = 0.0;

			VectorSet ( tempVertexArray[meshnum][i], 
					move[0] + ov->point[0]*oldScale[0] + v->point[0]*curScale[0] + tempNormalsArray[i][0]*shellscale,
					move[1] + ov->point[1]*oldScale[1] + v->point[1]*curScale[1] + tempNormalsArray[i][1]*shellscale,
					move[2] + ov->point[2]*oldScale[2] + v->point[2]*curScale[2] + tempNormalsArray[i][2]*shellscale );

			// calc lighting and alpha
			if (shellModel)
				VectorCopy(meshlight, lightcolor);
			else
				R_LightAliasModel(meshlight, tempNormalsArray[i], lightcolor, v->lightnormalindex, !skinParms.nodiffuse);
			//thisalpha = R_CalcEntAlpha(meshalpha, tempVertexArray[meshnum][i]);
			thisalpha = meshalpha;

			// get tex coords
			if (shellModel && FlowingShell()) {
				tempSkinCoord[0] = (tempVertexArray[meshnum][i][0] + tempVertexArray[meshnum][i][1]) / 40.0 + shellFlowH;
				tempSkinCoord[1] = tempVertexArray[meshnum][i][2] / 40.0 + shellFlowV;
			} else {
				tempSkinCoord[0] = mesh.stcoords[i].st[0];
				tempSkinCoord[1] = mesh.stcoords[i].st[1];
			}

			// add to arrays
			VA_SetElem2(texCoordArray[0][rb_vertex], tempSkinCoord[0], tempSkinCoord[1]);
			VA_SetElem3(vertexArray[rb_vertex], tempVertexArray[meshnum][i][0], tempVertexArray[meshnum][i][1], tempVertexArray[meshnum][i][2]);
			VA_SetElem4(colorArray[rb_vertex], lightcolor[0], lightcolor[1], lightcolor[2], thisalpha);
			rb_vertex++;
		}
		if (!shellModel)
			RB_ModifyTextureCoords (&texCoordArray[0][0][0], &vertexArray[0][0], rb_vertex, skinParms);

		// set indices for each triangle and draw
		rb_index = 0;
		for (j=0; j < mesh.num_tris; j++)
		{
			indexArray[rb_index++] = mesh.indexes[3*j+0];
			indexArray[rb_index++] = mesh.indexes[3*j+1];
			indexArray[rb_index++] = mesh.indexes[3*j+2];
		}
		RB_DrawArrays (GL_TRIANGLES);

		// glow pass
		if (mesh.skins[e->skinnum].glowimage && !shellModel)
		{
			float	glowcolor;
			if (skinParms.glow.type > -1)
				glowcolor = RB_CalcGlowColor (skinParms);
			else
				glowcolor = 1.0;
			qglDisableClientState (GL_COLOR_ARRAY);
			qglColor4f(glowcolor, glowcolor, glowcolor, 1.0);

			GL_Enable (GL_BLEND);
			GL_BlendFunc (GL_ONE, GL_ONE);

			GL_Bind(mesh.skins[e->skinnum].glowimage->texnum);

			RB_DrawArrays (GL_TRIANGLES);

			qglEnableClientState (GL_COLOR_ARRAY);
			qglColor4f(1.0, 1.0, 1.0, 1.0);
		}

		// envmap pass
		if (skinParms.envmap > 0.0f && !shellModel)
		{
			GL_Enable (GL_BLEND);
			GL_BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

			qglTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
			qglTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
			// apply alpha to array
			for (i=0; i<mesh.num_verts; i++) 
				//colorArray[i][3] = R_CalcEntAlpha(meshalpha*skinParms.envmap, tempVertexArray[meshnum][i]);
				colorArray[i][3] = meshalpha*skinParms.envmap;

			GL_Bind(r_envmappic->texnum);

			qglEnable(GL_TEXTURE_GEN_S);
			qglEnable(GL_TEXTURE_GEN_T);

			RB_DrawArrays (GL_TRIANGLES);

			qglDisable(GL_TEXTURE_GEN_S);
			qglDisable(GL_TEXTURE_GEN_T);
		}

		RB_DrawMeshTris (GL_TRIANGLES, 1);

		// md3 skin scripting
		if (skinParms.twosided)
			GL_Enable(GL_CULL_FACE);
		if (skinParms.alphatest && !shellModel)
			GL_Disable(GL_ALPHA_TEST);
		GL_Disable (GL_BLEND);
		// md3 skin scripting

	} // end new outer loop
	
	R_SetShellBlend (false);
	R_SetVertexOverbrights(false);
}
Esempio n. 7
0
/*
===============
CG_CalcViewValues

Sets cg.refdef view values
===============
*/
static int CG_CalcViewValues( void )
{
  playerState_t *ps;

  memset( &cg.refdef, 0, sizeof( cg.refdef ) );

  // calculate size of 3D view
  CG_CalcVrect( );

  ps = &cg.predictedPlayerState;

  // intermission view
  if( ps->pm_type == PM_INTERMISSION )
  {
    VectorCopy( ps->origin, cg.refdef.vieworg );
    VectorCopy( ps->viewangles, cg.refdefViewAngles );
    AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );

    return CG_CalcFov( );
  }

  cg.bobcycle = ( ps->bobCycle & 128 ) >> 7;
  cg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) );
  cg.xyspeed = sqrt( ps->velocity[ 0 ] * ps->velocity[ 0 ] +
    ps->velocity[ 1 ] * ps->velocity[ 1 ] );

  VectorCopy( ps->origin, cg.refdef.vieworg );

  if( BG_ClassHasAbility( ps->stats[ STAT_PCLASS ], SCA_WALLCLIMBER ) )
    CG_smoothWWTransitions( ps, ps->viewangles, cg.refdefViewAngles );
  else if( BG_ClassHasAbility( ps->stats[ STAT_PCLASS ], SCA_WALLJUMPER ) )
    CG_smoothWJTransitions( ps, ps->viewangles, cg.refdefViewAngles );
  else
    VectorCopy( ps->viewangles, cg.refdefViewAngles );

  //clumsy logic, but it needs to be this way round because the CS propogation
  //delay screws things up otherwise
  if( !BG_ClassHasAbility( ps->stats[ STAT_PCLASS ], SCA_WALLJUMPER ) )
  {
    if( !( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) )
      VectorSet( cg.lastNormal, 0.0f, 0.0f, 1.0f );
  }

  // add error decay
  if( cg_errorDecay.value > 0 )
  {
    int   t;
    float f;

    t = cg.time - cg.predictedErrorTime;
    f = ( cg_errorDecay.value - t ) / cg_errorDecay.value;

    if( f > 0 && f < 1 )
      VectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg );
    else
      cg.predictedErrorTime = 0;
  }

  //shut off the poison cloud effect if it's still on the go
  if( cg.snap->ps.stats[ STAT_HEALTH ] <= 0 )
  {
    if( CG_IsParticleSystemValid( &cg.poisonCloudPS ) )
      CG_DestroyParticleSystem( &cg.poisonCloudPS );
  }

  if( cg.renderingThirdPerson )
  {
    // back away from character
    CG_OffsetThirdPersonView( );
  }
  else
  {
    // offset for local bobbing and kicks
    CG_OffsetFirstPersonView( );
  }

  // position eye reletive to origin
  AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis );

  if( cg.hyperspace )
    cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE;

  //draw the surface normal looking at
  if( cg_drawSurfNormal.integer )
    CG_DrawSurfNormal( );

  // field of view
  return CG_CalcFov( );
}
Esempio n. 8
0
/*
==================
CM_Trace
==================
*/
void CM_Trace( trace_t *trace, const vec3_t start, const vec3_t end,
						  const vec3_t mins, const vec3_t maxs,
						  clipHandle_t model, const vec3_t origin, int brushmask, int capsule, sphere_t *sphere ) {
	int			i;
	traceWork_t	tw;
	vec3_t		offset;
	cmodel_t	*cmod;
	clipMap_t	*local = 0;

	cmod = CM_ClipHandleToModel( model, &local );

	local->checkcount++;		// for multi-check avoidance

	c_traces++;				// for statistics, may be zeroed

	// fill in a default trace
	Com_Memset( &tw, 0, sizeof(tw) );
	memset(trace, 0, sizeof(*trace));
	trace->fraction = 1;	// assume it goes the entire distance until shown otherwise
	VectorCopy(origin, tw.modelOrigin);

	if (!local->numNodes) {
		return;	// map not loaded, shouldn't happen
	}

	// allow NULL to be passed in for 0,0,0
	if ( !mins ) {
		mins = vec3_origin;
	}
	if ( !maxs ) {
		maxs = vec3_origin;
	}

	// set basic parms
	tw.contents = brushmask;

	// adjust so that mins and maxs are always symetric, which
	// avoids some complications with plane expanding of rotated
	// bmodels
	for ( i = 0 ; i < 3 ; i++ ) {
		offset[i] = ( mins[i] + maxs[i] ) * 0.5;
		tw.size[0][i] = mins[i] - offset[i];
		tw.size[1][i] = maxs[i] - offset[i];
		tw.start[i] = start[i] + offset[i];
		tw.end[i] = end[i] + offset[i];
	}

	// if a sphere is already specified
	if ( sphere ) {
		tw.sphere = *sphere;
	}
	else {
		tw.sphere.use = (qboolean)capsule;
		tw.sphere.radius = ( tw.size[1][0] > tw.size[1][2] ) ? tw.size[1][2]: tw.size[1][0];
		tw.sphere.halfheight = tw.size[1][2];
		VectorSet( tw.sphere.offset, 0, 0, tw.size[1][2] - tw.sphere.radius );
	}

	tw.maxOffset = tw.size[1][0] + tw.size[1][1] + tw.size[1][2];

	// tw.offsets[signbits] = vector to appropriately corner from origin
	tw.offsets[0][0] = tw.size[0][0];
	tw.offsets[0][1] = tw.size[0][1];
	tw.offsets[0][2] = tw.size[0][2];

	tw.offsets[1][0] = tw.size[1][0];
	tw.offsets[1][1] = tw.size[0][1];
	tw.offsets[1][2] = tw.size[0][2];

	tw.offsets[2][0] = tw.size[0][0];
	tw.offsets[2][1] = tw.size[1][1];
	tw.offsets[2][2] = tw.size[0][2];

	tw.offsets[3][0] = tw.size[1][0];
	tw.offsets[3][1] = tw.size[1][1];
	tw.offsets[3][2] = tw.size[0][2];

	tw.offsets[4][0] = tw.size[0][0];
	tw.offsets[4][1] = tw.size[0][1];
	tw.offsets[4][2] = tw.size[1][2];

	tw.offsets[5][0] = tw.size[1][0];
	tw.offsets[5][1] = tw.size[0][1];
	tw.offsets[5][2] = tw.size[1][2];

	tw.offsets[6][0] = tw.size[0][0];
	tw.offsets[6][1] = tw.size[1][1];
	tw.offsets[6][2] = tw.size[1][2];

	tw.offsets[7][0] = tw.size[1][0];
	tw.offsets[7][1] = tw.size[1][1];
	tw.offsets[7][2] = tw.size[1][2];

	//
	// calculate bounds
	//
	if ( tw.sphere.use ) {
		for ( i = 0 ; i < 3 ; i++ ) {
			if ( tw.start[i] < tw.end[i] ) {
				tw.bounds[0][i] = tw.start[i] - fabs(tw.sphere.offset[i]) - tw.sphere.radius;
				tw.bounds[1][i] = tw.end[i] + fabs(tw.sphere.offset[i]) + tw.sphere.radius;
			} else {
				tw.bounds[0][i] = tw.end[i] - fabs(tw.sphere.offset[i]) - tw.sphere.radius;
				tw.bounds[1][i] = tw.start[i] + fabs(tw.sphere.offset[i]) + tw.sphere.radius;
			}
		}
	}
	else {
		for ( i = 0 ; i < 3 ; i++ ) {
			if ( tw.start[i] < tw.end[i] ) {
				tw.bounds[0][i] = tw.start[i] + tw.size[0][i];
				tw.bounds[1][i] = tw.end[i] + tw.size[1][i];
			} else {
				tw.bounds[0][i] = tw.end[i] + tw.size[0][i];
				tw.bounds[1][i] = tw.start[i] + tw.size[1][i];
			}
		}
	}

	//
	// check for position test special case
	//
	if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2] &&
		tw.size[0][0] == 0 && tw.size[0][1] == 0 && tw.size[0][2] == 0)
	{
		if ( model && cmod->firstNode == -1)
		{
#ifdef ALWAYS_BBOX_VS_BBOX // bk010201 - FIXME - compile time flag?
			if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE)
			{
				tw.sphere.use = qfalse;
				CM_TestInLeaf( &tw, &cmod->leaf );
			}
			else
#elif defined(ALWAYS_CAPSULE_VS_CAPSULE)
			if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE)
			{
				CM_TestCapsuleInCapsule( &tw, model );
			}
			else
#endif
			if ( model == CAPSULE_MODEL_HANDLE )
			{
				if ( tw.sphere.use )
				{
					CM_TestCapsuleInCapsule( &tw, *trace, model );
				}
				else
				{
					CM_TestBoundingBoxInCapsule( &tw, *trace, model );
				}
			}
			else
			{
				CM_TestInLeaf( &tw, *trace, &cmod->leaf, local );
			}
		}
		else if (cmod->firstNode == -1)
		{
			CM_PositionTest( &tw, *trace );
		}
		else
		{
			CM_TraceThroughTree( &tw, *trace, local, cmod->firstNode, 0, 1, tw.start, tw.end );
		}
	}
	else
	{
		//
		// check for point special case
		//
		if ( tw.size[0][0] == 0 && tw.size[0][1] == 0 && tw.size[0][2] == 0 )
		{
			tw.isPoint = qtrue;
			VectorClear( tw.extents );
		}
		else
		{
			tw.isPoint = qfalse;
			tw.extents[0] = tw.size[1][0];
			tw.extents[1] = tw.size[1][1];
			tw.extents[2] = tw.size[1][2];
		}

		//
		// general sweeping through world
		//
		if ( model && cmod->firstNode == -1)
		{
#ifdef ALWAYS_BBOX_VS_BBOX
			if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE)
			{
				tw.sphere.use = qfalse;
				CM_TraceThroughLeaf( &tw, &cmod->leaf );
			}
			else
#elif defined(ALWAYS_CAPSULE_VS_CAPSULE)
			if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE)
			{
				CM_TraceCapsuleThroughCapsule( &tw, model );
			}
			else
#endif
			if ( model == CAPSULE_MODEL_HANDLE )
			{
				if ( tw.sphere.use )
				{
					CM_TraceCapsuleThroughCapsule( &tw, *trace, model );
				}
				else
				{
					CM_TraceBoundingBoxThroughCapsule( &tw, *trace, model );
				}
			}
			else
			{
				CM_TraceThroughLeaf( &tw, *trace, local, &cmod->leaf );
			}
		}
		else
		{
			CM_TraceThroughTree( &tw, *trace, local, cmod->firstNode, 0, 1, tw.start, tw.end );
		}
	}

	// generate endpos from the original, unmodified start/end
	if ( trace->fraction == 1 ) {
		VectorCopy (end, trace->endpos);
	} else {
		for ( i=0 ; i<3 ; i++ ) {
			trace->endpos[i] = start[i] + trace->fraction * (end[i] - start[i]);
		}
	}

        // If allsolid is set (was entirely inside something solid), the plane is not valid.
        // If fraction == 1.0, we never hit anything, and thus the plane is not valid.
        // Otherwise, the normal on the plane should have unit length
        assert(trace->allsolid ||
               trace->fraction == 1.0 ||
               VectorLengthSquared(trace->plane.normal) > 0.9999);
}
Esempio n. 9
0
/*
==================
CM_TransformedBoxTrace

Handles offseting and rotation of the end points for moving and
rotating entities
==================
*/
void CM_TransformedBoxTrace( trace_t *trace, const vec3_t start, const vec3_t end,
						  const vec3_t mins, const vec3_t maxs,
						  clipHandle_t model, int brushmask,
						  const vec3_t origin, const vec3_t angles, int capsule ) {
	vec3_t		start_l, end_l;
	qboolean	rotated;
	vec3_t		offset;
	vec3_t		symetricSize[2];
	matrix3_t	matrix, transpose;
	int			i;
	float		halfwidth;
	float		halfheight;
	float		t;
	sphere_t	sphere;

	if ( !mins ) {
		mins = vec3_origin;
	}
	if ( !maxs ) {
		maxs = vec3_origin;
	}

	// adjust so that mins and maxs are always symetric, which
	// avoids some complications with plane expanding of rotated
	// bmodels
	for ( i = 0 ; i < 3 ; i++ ) {
		offset[i] = ( mins[i] + maxs[i] ) * 0.5;
		symetricSize[0][i] = mins[i] - offset[i];
		symetricSize[1][i] = maxs[i] - offset[i];
		start_l[i] = start[i] + offset[i];
		end_l[i] = end[i] + offset[i];
	}

	// subtract origin offset
	VectorSubtract( start_l, origin, start_l );
	VectorSubtract( end_l, origin, end_l );

	// rotate start and end into the models frame of reference
	if ( model != BOX_MODEL_HANDLE &&
		(angles[0] || angles[1] || angles[2]) ) {
		rotated = qtrue;
	} else {
		rotated = qfalse;
	}

	halfwidth = symetricSize[ 1 ][ 0 ];
	halfheight = symetricSize[ 1 ][ 2 ];

	sphere.use = (qboolean)capsule;
	sphere.radius = ( halfwidth > halfheight ) ? halfheight : halfwidth;
	sphere.halfheight = halfheight;
	t = halfheight - sphere.radius;

	if (rotated) {
		// rotation on trace line (start-end) instead of rotating the bmodel
		// NOTE: This is still incorrect for bounding boxes because the actual bounding
		//		 box that is swept through the model is not rotated. We cannot rotate
		//		 the bounding box or the bmodel because that would make all the brush
		//		 bevels invalid.
		//		 However this is correct for capsules since a capsule itself is rotated too.
		CreateRotationMatrix(angles, matrix);
		RotatePoint(start_l, matrix);
		RotatePoint(end_l, matrix);
		// rotated sphere offset for capsule
		sphere.offset[0] = matrix[0][ 2 ] * t;
		sphere.offset[1] = -matrix[1][ 2 ] * t;
		sphere.offset[2] = matrix[2][ 2 ] * t;
	}
	else {
		VectorSet( sphere.offset, 0, 0, t );
	}

	// sweep the box through the model
	CM_Trace( trace, start_l, end_l, symetricSize[0], symetricSize[1], model, origin, brushmask, capsule, &sphere );

	// if the bmodel was rotated and there was a collision
	if ( rotated && trace->fraction != 1.0 ) {
		// rotation of bmodel collision plane
		TransposeMatrix(matrix, transpose);
		RotatePoint(trace->plane.normal, transpose);
	}

	// re-calculate the end position of the trace because the trace.endpos
	// calculated by CM_Trace could be rotated and have an offset
	trace->endpos[0] = start[0] + trace->fraction * (end[0] - start[0]);
	trace->endpos[1] = start[1] + trace->fraction * (end[1] - start[1]);
	trace->endpos[2] = start[2] + trace->fraction * (end[2] - start[2]);
}
Esempio n. 10
0
/*
=================
P_FallingDamage
=================
*/
void P_FallingDamage(edict_t *ent)
{
    float   delta;
    int     damage;
    vec3_t  dir;

    if (ent->s.modelindex != 255)
        return;     // not in the player model

    if (ent->movetype == MOVETYPE_NOCLIP)
        return;

    if ((ent->client->oldvelocity[2] < 0) && (ent->velocity[2] > ent->client->oldvelocity[2]) && (!ent->groundentity)) {
        delta = ent->client->oldvelocity[2];
    } else {
        if (!ent->groundentity)
            return;
        delta = ent->velocity[2] - ent->client->oldvelocity[2];
    }
    delta = delta * delta * 0.0001f;

    // never take falling damage if completely underwater
    if (ent->waterlevel == 3)
        return;
    if (ent->waterlevel == 2)
        delta *= 0.25f;
    if (ent->waterlevel == 1)
        delta *= 0.5f;

    if (delta < 1)
        return;

    if (delta < 15) {
        ent->s.event = EV_FOOTSTEP;
        return;
    }

    ent->client->fall_value = delta * 0.5f;
    if (ent->client->fall_value > 40)
        ent->client->fall_value = 40;
    ent->client->fall_time = level.time + FALL_TIME;

    if (delta > 30) {
        if (ent->health > 0) {
            if (delta >= 55)
                ent->s.event = EV_FALLFAR;
            else
                ent->s.event = EV_FALL;
        }
        ent->pain_debounce_time = level.time;   // no normal pain sound
        damage = (delta - 30) / 2;
        if (damage < 1)
            damage = 1;
        VectorSet(dir, 0, 0, 1);

        if (!deathmatch->value || !((int)dmflags->value & DF_NO_FALLING))
            T_Damage(ent, world, world, dir, ent->s.origin, vec3_origin, damage, 0, 0, MOD_FALLING);
    } else {
        ent->s.event = EV_FALLSHORT;
        return;
    }
}
Esempio n. 11
0
void SP_monster_soldier_x (edict_t *self)
{
	// Lazarus: special purpose skins
	if ( self->style )
		PatchMonsterModel("models/monsters/soldier/tris.md2");

	self->s.modelindex = gi.modelindex ("models/monsters/soldier/tris.md2");
	self->monsterinfo.scale = MODEL_SCALE;
	VectorSet (self->mins, -16, -16, -24);
	VectorSet (self->maxs, 16, 16, 32);
	self->movetype = MOVETYPE_STEP;
	self->solid = SOLID_BBOX;

	sound_idle =	gi.soundindex ("soldier/solidle1.wav");
	sound_sight1 =	gi.soundindex ("soldier/solsght1.wav");
	sound_sight2 =	gi.soundindex ("soldier/solsrch1.wav");
	sound_cock =	gi.soundindex ("infantry/infatck3.wav");

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

	self->pain = soldier_pain;
	self->die = soldier_die;

	self->monsterinfo.stand = soldier_stand;
	self->monsterinfo.walk = soldier_walk;
	self->monsterinfo.run = soldier_run;
	self->monsterinfo.dodge = soldier_dodge;
	self->monsterinfo.attack = soldier_attack;
	self->monsterinfo.melee = NULL;
	self->monsterinfo.sight = soldier_sight;
	if(monsterjump->value)
	{
		self->monsterinfo.jump = soldier_jump;
		self->monsterinfo.jumpup = 48;
		self->monsterinfo.jumpdn = 160;
	}

	// DWH
	if(self->powerarmor)
	{
		self->monsterinfo.power_armor_type = POWER_ARMOR_SHIELD;
		self->monsterinfo.power_armor_power = self->powerarmor;
	}
	// end DWH

	gi.linkentity (self);

	if(!self->monsterinfo.flies)
		self->monsterinfo.flies = 0.40;

	if(self->health < 0)
	{
		mmove_t	*deathmoves[] = {&soldier_move_death1,
			                     &soldier_move_death2,
								 &soldier_move_death3,
								 &soldier_move_death4,
								 &soldier_move_death5,
								 &soldier_move_death6,
								 NULL};
		M_SetDeath(self,(mmove_t **)&deathmoves);
	}
	walkmonster_start (self);
}
Esempio n. 12
0
/*
====================
RE_GetViewFog
====================
*/
void RE_GetViewFog( const vec3_t origin, fogType_t *type, vec3_t color, float *depthForOpaque, float *density, qboolean inwater ) {
	fogType_t			fogType;
	vec3_t				fogColor;
	float				fogDepthForOpaque;
	float				fogDensity;

	if ( inwater ) {
		fogType = tr.waterFogParms.fogType;
		VectorCopy( tr.waterFogParms.color, fogColor );
		fogDepthForOpaque = tr.waterFogParms.depthForOpaque;
		fogDensity = tr.waterFogParms.density;
	} else {
		fogType = FT_NONE;
		VectorSet( fogColor, 0, 0, 0 );
		fogDepthForOpaque = 0;
		fogDensity = 0;
	}

	if ( tr.world ) {
		int					bmodelNum;
		int					surfaceNum;
		const bmodel_t		*bmodel;
		const msurface_t	*surface;

		for ( bmodelNum = 0, bmodel = tr.world->bmodels; bmodelNum < tr.world->numBModels; bmodelNum++, bmodel++ ) {

			if ( !R_PointInBrush( origin, bmodel ) )
				continue;

			for ( surfaceNum = 0, surface = bmodel->firstSurface; surfaceNum < bmodel->numSurfaces; surfaceNum++, surface++ ) {
				if ( !surface->shader ) {
					continue;
				}

				if ( surface->shader->viewFogParms.fogType != FT_NONE
						|| surface->shader->viewFogParms.color[0]
						|| surface->shader->viewFogParms.color[1]
						|| surface->shader->viewFogParms.color[2] ) {
					fogType = surface->shader->viewFogParms.fogType;
					VectorCopy( surface->shader->viewFogParms.color, fogColor );
					fogDepthForOpaque = surface->shader->viewFogParms.depthForOpaque;
					fogDensity = surface->shader->viewFogParms.density;
					break;
				}
			}

			if ( surfaceNum != bmodel->numSurfaces ) {
				break;
			}
		}
	}

	if (type) {
		*type = fogType;
	}

	if (color) {
		VectorCopy( fogColor, color );
	}

	if (depthForOpaque) {
		*depthForOpaque = fogDepthForOpaque;
	}

	if (density) {
		*density = fogDensity;
	}
}
Esempio n. 13
0
AABB::AABB (const Line &line)
{
	VectorSet(mins, std::min(line.start[0], line.stop[0]), std::min(line.start[1], line.stop[1]), std::min(line.start[2], line.stop[2]));
	VectorSet(maxs, std::max(line.start[0], line.stop[0]), std::max(line.start[1], line.stop[1]), std::max(line.start[2], line.stop[2]));
}
Esempio n. 14
0
/**
 * @brief Called before loading. Used to set default attribute values
 */
static void UI_ModelNodeLoading (uiNode_t *node)
{
	Vector4Set(node->color, 1, 1, 1, 1);
	VectorSet(EXTRADATA(node).scale, 1, 1, 1);
	EXTRADATA(node).clipOverflow = qtrue;
}
Esempio n. 15
0
void DrawTerrain( terrainMesh_t *pm, bool bPoints, bool bShade ) {
	int				i;
	int				w;
	int				h;
	int				x;
	int				y;
	//int			n;
	//float			x1;
	//float			y1;
	float			scale_x;
	float			scale_y;
	//vec3_t		pSelectedPoints[ MAX_TERRA_POINTS ];
	//int			nIndex;
	terravert_t		a0;
	terravert_t		a1;
	terravert_t		a2;
	terravert_t		b0;
	terravert_t		b1;
	terravert_t		b2;
	terrainVert_t	*vert;
	qtexture_t		*texture;

	h = pm->height - 1;
	w = pm->width - 1;
   
	scale_x = pm->scale_x;
	scale_y = pm->scale_y;

	qglShadeModel (GL_SMOOTH);

	if ( bShade ) {
		for( i = 0; i < pm->numtextures; i++ ) {
			texture = pm->textures[ i ];

			qglBindTexture( GL_TEXTURE_2D, texture->texture_number );

			vert = pm->heightmap;
			for( y = 0; y < h; y++ ) {
				qglBegin( GL_TRIANGLES );

				for( x = 0; x < w; x++, vert++ ) {
					Terrain_GetTriangles( pm, x, y, &a0, &a1, &a2, &b0, &b1, &b2, texture );

					// first tri
					if ( a0.rgba[ 3 ] || a1.rgba[ 3 ] || a2.rgba[ 3 ] ) {
						qglColor4fv( a0.rgba );
						qglTexCoord2fv( a0.tc );
						qglVertex3fv( a0.xyz );

						qglColor4fv( a1.rgba );
						qglTexCoord2fv( a1.tc );
						qglVertex3fv( a1.xyz );

						qglColor4fv( a2.rgba );
						qglTexCoord2fv( a2.tc );
						qglVertex3fv( a2.xyz );
					}

					// second tri
					if ( b0.rgba[ 3 ] || b1.rgba[ 3 ] || b2.rgba[ 3 ] ) {
						qglColor4fv( b0.rgba );
						qglTexCoord2fv( b0.tc );
						qglVertex3fv( b0.xyz );

						qglColor4fv( b1.rgba );
						qglTexCoord2fv( b1.tc );
						qglVertex3fv( b1.xyz );

						qglColor4fv( b2.rgba );
						qglTexCoord2fv( b2.tc );
						qglVertex3fv( b2.xyz );
					}
				}

			qglEnd ();
			}
		}
	} else {
		for( i = 0; i < pm->numtextures; i++ ) {
			texture = pm->textures[ i ];

			qglBindTexture( GL_TEXTURE_2D, texture->texture_number );

			vert = pm->heightmap;
			for( y = 0; y < h; y++ ) {
				qglBegin( GL_TRIANGLES );

				for( x = 0; x < w; x++, vert++ ) {
					Terrain_GetTriangles( pm, x, y, &a0, &a1, &a2, &b0, &b1, &b2, texture );

					// first tri
					if ( a0.rgba[ 3 ] || a1.rgba[ 3 ] || a2.rgba[ 3 ] ) {
						qglColor4fv( a0.rgba );
						qglTexCoord2fv( a0.tc );
						qglVertex3fv( a0.xyz );

						qglColor4fv( a1.rgba );
						qglTexCoord2fv( a1.tc );
						qglVertex3fv( a1.xyz );

						qglColor4fv( a2.rgba );
						qglTexCoord2fv( a2.tc );
						qglVertex3fv( a2.xyz );
					}

					// second tri
					if ( b0.rgba[ 3 ] || b1.rgba[ 3 ] || b2.rgba[ 3 ] ) {
						qglColor4fv( b0.rgba );
						qglTexCoord2fv( b0.tc );
						qglVertex3fv( b0.xyz );

						qglColor4fv( b1.rgba );
						qglTexCoord2fv( b1.tc );
						qglVertex3fv( b1.xyz );

						qglColor4fv( b2.rgba );
						qglTexCoord2fv( b2.tc );
						qglVertex3fv( b2.xyz );
					}
				}
				qglEnd ();
			}
		}
	}

	qglPushAttrib( GL_CURRENT_BIT );

	bool bDisabledLighting = qglIsEnabled( GL_LIGHTING );
	if ( bDisabledLighting ) {
		qglDisable( GL_LIGHTING );
	}

#if 0
	terrainVert_t	*currentrow;
	terrainVert_t	*nextrow;
	float			x2;
	float			y2;

	// Draw normals
	qglDisable( GL_TEXTURE_2D );
	qglDisable( GL_BLEND );
	qglColor3f( 1, 1, 1 );
	qglBegin( GL_LINES );

	y2 = pm->origin[ 1 ];
	nextrow = pm->heightmap;
	for( y = 0; y < h; y++ ) {
		y1 = y2;
		y2 += scale_y;

		x2 = pm->origin[ 0 ];
		currentrow = nextrow;
		nextrow = currentrow + pm->width;
		for( x = 0; x < w; x++ ) {
			x1 = x2;
			x2 += scale_x;

			// normals
			qglVertex3f( x1, y1, pm->origin[ 2 ] + currentrow[ x ].height );
			qglVertex3f( x1 + currentrow[ x ].normal[ 0 ] * 16.0f, y1 + currentrow[ x ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + currentrow[ x ].height + currentrow[ x ].normal[ 2 ] * 16.0f );

			qglVertex3f( x2, y1, pm->origin[ 2 ] + currentrow[ x + 1 ].height );
			qglVertex3f( x2 + currentrow[ x + 1 ].normal[ 0 ] * 16.0f, y1 + currentrow[ x + 1 ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + currentrow[ x + 1 ].height + currentrow[ x + 1 ].normal[ 2 ] * 16.0f );

			qglVertex3f( x1, y2, pm->origin[ 2 ] + nextrow[ x ].height );
			qglVertex3f( x1 + nextrow[ x ].normal[ 0 ] * 16.0f, y2 + nextrow[ x ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + nextrow[ x ].height + nextrow[ x ].normal[ 2 ] * 16.0f );

			qglVertex3f( x2, y2, pm->origin[ 2 ] + nextrow[ x + 1 ].height );
			qglVertex3f( x2 + nextrow[ x + 1 ].normal[ 0 ] * 16.0f, y2 + nextrow[ x + 1 ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + nextrow[ x + 1 ].height + nextrow[ x + 1 ].normal[ 2 ] * 16.0f );
		}
	}

	qglEnd ();
	qglEnable( GL_TEXTURE_2D );
#endif

#if 0
	if ( bPoints && ( g_qeglobals.d_select_mode == sel_terrainpoint || g_qeglobals.d_select_mode == sel_area ) ) {
		qglPointSize( 6 );
		qglDisable( GL_TEXTURE_2D );
		qglDisable( GL_BLEND );

		qglBegin( GL_POINTS );

		nIndex = 0;

		qglColor4f( 1, 0, 1, 1 );

		y1 = pm->origin[ 1 ];
		for ( y = 0; y < pm->height; y++, y1 += pm->scale_y ) {
			x1 = pm->origin[ 0 ];
			for( x = 0; x < pm->width; x++, x1 += pm->scale_x ) {
				// FIXME: need to not do loop lookups inside here
				n = Terrain_PointInMoveList( &pm->heightmap[ x + y * pm->width ] );
				if ( n >= 0 ) {
					VectorSet( pSelectedPoints[ nIndex ], x1, y1, pm->heightmap[ x + y * pm->width ].height + pm->origin[ 2 ] );
					nIndex++;
				} else {
					qglVertex3f( x1, y1, pm->origin[ 2 ] + pm->heightmap[ x + y * pm->width ].height );
				}
			}
		}

		qglEnd();
		
		qglEnable( GL_TEXTURE_2D );

		if ( nIndex > 0 ) {
			qglBegin( GL_POINTS );
			qglColor4f( 0, 0, 1, 1 );
			while( nIndex-- > 0 ) {
				qglVertex3fv( pSelectedPoints[ nIndex ] );
			}
		
			qglEnd();
		}
	}
#endif

	if ( g_qeglobals.d_numterrapoints && ( ( g_qeglobals.d_select_mode == sel_terrainpoint ) || ( g_qeglobals.d_select_mode == sel_terraintexture ) ) ) {
#if 0 
		qglPointSize( 6 );
		qglDisable( GL_TEXTURE_2D );
		qglDisable( GL_BLEND );

		qglBegin( GL_POINTS );

		qglColor4f( 1, 0, 1, 1 );

		for( i = 0; i < g_qeglobals.d_numterrapoints; i++ ) {
			qglVertex3fv( g_qeglobals.d_terrapoints[ i ]->xyz );
		}

		qglEnd();
			
		qglEnable( GL_TEXTURE_2D );
#endif

		brush_t			*pb;
		terrainMesh_t	*pm;

		pm = NULL;
		for( pb = active_brushes .next; pb != &active_brushes; pb = pb->next ) {
			if ( pb->terrainBrush ) {
				pm = pb->pTerrain;
				break;
			}
		}

		if ( pm ) {
			qglDisable( GL_TEXTURE_2D );
			qglBegin( GL_TRIANGLES );
			qglEnable( GL_BLEND );

			qglColor4f( 0.25, 0.5, 1, 0.35 );

			for( i = 0; i < g_qeglobals.d_numterrapoints; i++ ) {
				terravert_t		a0;
				terravert_t		a1;
				terravert_t		a2;

				qglColor4f( 0.25, 0.5, 1, g_qeglobals.d_terrapoints[ i ]->scale * 0.75 + 0.25 );
				Terrain_GetTriangle( pm, g_qeglobals.d_terrapoints[ i ]->tri.index * 2, &a0, &a1, &a2 );

				qglVertex3fv( a0.xyz );
				qglVertex3fv( a1.xyz );
				qglVertex3fv( a2.xyz );

				Terrain_GetTriangle( pm, g_qeglobals.d_terrapoints[ i ]->tri.index * 2 + 1, &a0, &a1, &a2 );

				qglVertex3fv( a0.xyz );
				qglVertex3fv( a1.xyz );
				qglVertex3fv( a2.xyz );
			}
			qglEnd();
			
			qglDisable( GL_BLEND );
			qglEnable( GL_TEXTURE_2D );
		}
	}
}
Esempio n. 16
0
/*
================
CM_TraceThroughVerticalCylinder

get the first intersection of the ray with the cylinder
the cylinder extends halfheight above and below the origin
================
*/
void CM_TraceThroughVerticalCylinder( traceWork_t *tw, trace_t &trace, vec3_t origin, float radius, float halfheight, vec3_t start, vec3_t end) {
	float length, scale, fraction, l1, l2;
	float /*a, */b, c, d, sqrtd;
	vec3_t v1, dir, start2d, end2d, org2d, intersection;

	// 2d coordinates
	VectorSet(start2d, start[0], start[1], 0);
	VectorSet(end2d, end[0], end[1], 0);
	VectorSet(org2d, origin[0], origin[1], 0);
	// if between lower and upper cylinder bounds
	if (start[2] <= origin[2] + halfheight &&
				start[2] >= origin[2] - halfheight) {
		// if inside the cylinder
		VectorSubtract(start2d, org2d, dir);
		l1 = VectorLengthSquared(dir);
		if (l1 < Square(radius)) {
			trace.fraction = 0;
			trace.startsolid = qtrue;
			VectorSubtract(end2d, org2d, dir);
			l1 = VectorLengthSquared(dir);
			if (l1 < Square(radius)) {
				trace.allsolid = qtrue;
			}
			return;
		}
	}
	//
	VectorSubtract(end2d, start2d, dir);
	length = VectorNormalize(dir);
	//
	l1 = CM_DistanceFromLineSquared(org2d, start2d, end2d, dir);
	VectorSubtract(end2d, org2d, v1);
	l2 = VectorLengthSquared(v1);
	// if no intersection with the cylinder and the end point is at least an epsilon away
	if (l1 >= Square(radius) && l2 > Square(radius+SURFACE_CLIP_EPSILON)) {
		return;
	}
	//
	//
	// (start[0] - origin[0] - t * dir[0]) ^ 2 + (start[1] - origin[1] - t * dir[1]) ^ 2 = radius ^ 2
	// (v1[0] + t * dir[0]) ^ 2 + (v1[1] + t * dir[1]) ^ 2 = radius ^ 2;
	// v1[0] ^ 2 + 2 * v1[0] * t * dir[0] + (t * dir[0]) ^ 2 +
	//						v1[1] ^ 2 + 2 * v1[1] * t * dir[1] + (t * dir[1]) ^ 2 = radius ^ 2
	// t ^ 2 * (dir[0] ^ 2 + dir[1] ^ 2) + t * (2 * v1[0] * dir[0] + 2 * v1[1] * dir[1]) +
	//						v1[0] ^ 2 + v1[1] ^ 2 - radius ^ 2 = 0
	//
	VectorSubtract(start, origin, v1);
	// dir is normalized so we can use a = 1
	//a = 1.0f;// * (dir[0] * dir[0] + dir[1] * dir[1]);
	b = 2.0f * (v1[0] * dir[0] + v1[1] * dir[1]);
	c = v1[0] * v1[0] + v1[1] * v1[1] - (radius+RADIUS_EPSILON) * (radius+RADIUS_EPSILON);

	d = b * b - 4.0f * c;// * a;
	if (d > 0) {
		sqrtd = sqrtf(d);
		// = (- b + sqrtd) * 0.5f;// / (2.0f * a);
		fraction = (- b - sqrtd) * 0.5f;// / (2.0f * a);
		//
		if (fraction < 0) {
			fraction = 0;
		}
		else {
			fraction /= length;
		}
		if ( fraction < trace.fraction ) {
			VectorSubtract(end, start, dir);
			VectorMA(start, fraction, dir, intersection);
			// if the intersection is between the cylinder lower and upper bound
			if (intersection[2] <= origin[2] + halfheight &&
						intersection[2] >= origin[2] - halfheight) {
				//
				trace.fraction = fraction;
				VectorSubtract(intersection, origin, dir);
				dir[2] = 0;
				#ifdef CAPSULE_DEBUG
					l2 = VectorLength(dir);
					if (l2 <= radius) {
						int bah = 1;
					}
				#endif
				scale = 1 / (radius+RADIUS_EPSILON);
				VectorScale(dir, scale, dir);
				VectorCopy(dir, trace.plane.normal);
				VectorAdd( tw->modelOrigin, intersection, intersection);
				trace.plane.dist = DotProduct(trace.plane.normal, intersection);
				trace.contents = CONTENTS_BODY;
			}
		}
	}
	else if (d == 0) {
		//t[0] = (- b ) / 2 * a;
		// slide along the cylinder
	}
	// no intersection at all
}
Esempio n. 17
0
/*
=============
R_DrawAliasVolumeShadow
based on code from BeefQuake R6
=============
*/
void R_DrawAliasVolumeShadow (maliasmodel_t *paliashdr, vec3_t bbox[8])
{
	vec3_t		light, temp, vecAdd;
	float		dist, highest, lowest, projected_distance;
	float		angle, cosp, sinp, cosy, siny, cosr, sinr, ix, iy, iz;
	int			i, lnum;
	dlight_t	*dl;

	dl = r_newrefdef.dlights;

	VectorSet(vecAdd, 680,0,1024); // set base vector, was 576,0,1024

	// compute average light vector from dlights
	for (i=0, lnum=0; i<r_newrefdef.num_dlights; i++, dl++)
	{
		if (VectorCompare(dl->origin, currententity->origin))
			continue;
		
		VectorSubtract(dl->origin, currententity->origin, temp);
		dist = dl->intensity - VectorLength(temp);
		if (dist <= 0)
			continue;
		
		lnum++;
		// Factor in the intensity of a dlight
		VectorScale (temp, dist*0.25, temp);
		VectorAdd (vecAdd, temp, vecAdd);
	}
	VectorNormalize(vecAdd);
	VectorScale(vecAdd, 1024, vecAdd);

	// get projection distance from lightspot height
	highest = lowest = bbox[0][2];
	for (i=0; i<8; i++) {
		if (bbox[i][2] > highest) highest = bbox[i][2];
		if (bbox[i][2] < lowest) lowest = bbox[i][2];
	}
	projected_distance = (fabs(highest - lightspot[2]) + (highest-lowest)) / vecAdd[2];

	VectorCopy(vecAdd, light);
	
	/*cosy = cos(-currententity->angles[YAW] / 180 * M_PI);
	siny = sin(-currententity->angles[YAW] / 180 * M_PI);

	ix = light[0], iy = light[1];
	light[0] = (cosy * (ix - 0) + siny * (0 - iy) + 0);
	light[1] = (cosy * (iy - 0) + siny * (ix - 0) + 0);
	light[2] += 8;*/

	// reverse-rotate light vector based on angles
	angle = -currententity->angles[PITCH] / 180 * M_PI;
	cosp = cos(angle), sinp = sin(angle);
	angle = -currententity->angles[YAW] / 180 * M_PI;
	cosy = cos(angle), siny = sin(angle);
	angle = currententity->angles[ROLL] / 180 * M_PI; // roll is backwards
	cosr = cos(angle), sinr = sin(angle);

	// rotate for yaw (z axis)
	ix = light[0], iy = light[1];
	light[0] = cosy * ix - siny * iy + 0;
	light[1] = siny * ix + cosy * iy + 0;

	// rotate for pitch (y axis)
	ix = light[0], iz = light[2];
	light[0] = cosp * ix + 0 + sinp * iz;
	light[2] = -sinp * ix + 0 + cosp * iz;

	// rotate for roll (x axis)
	iy = light[1], iz = light[2];
	light[1] = 0 + cosr * iy - sinr * iz;
	light[2] = 0 + sinr * iy + cosr * iz;


	// set up stenciling
	if (!r_shadowvolumes->value)
	{
		qglPushAttrib(GL_STENCIL_BUFFER_BIT); // save stencil buffer
		qglClear(GL_STENCIL_BUFFER_BIT);

		qglColorMask(0,0,0,0);
		GL_DepthMask(0);
		GL_DepthFunc(GL_LESS);

		GL_Enable(GL_STENCIL_TEST);
		qglStencilFunc(GL_ALWAYS, 0, 255);
	//	qglStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
	//	qglStencilMask (255);
	}

	// build shadow volumes and render each to stencil buffer
	for (i=0; i<paliashdr->num_meshes; i++)
	{
		if (paliashdr->meshes[i].skins[currententity->skinnum].renderparms.nodraw
			|| paliashdr->meshes[i].skins[currententity->skinnum].renderparms.alphatest
			|| paliashdr->meshes[i].skins[currententity->skinnum].renderparms.noshadow)
			continue;

		R_BuildShadowVolume (paliashdr, i, light, projected_distance, r_shadowvolumes->value);
		GL_LockArrays (shadow_va);

		if (!r_shadowvolumes->value)
		{
			if (gl_config.atiSeparateStencil && gl_config.extStencilWrap) // Barnes ATI stenciling
			{
				GL_Disable(GL_CULL_FACE);

				qglStencilOpSeparateATI (GL_BACK, GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP); 
				qglStencilOpSeparateATI (GL_FRONT, GL_KEEP, GL_DECR_WRAP_EXT, GL_KEEP);

				R_DrawShadowVolume ();

				GL_Enable(GL_CULL_FACE);
			}
			else if (gl_config.extStencilTwoSide && gl_config.extStencilWrap) // Echon's two-sided stenciling
			{
				GL_Disable(GL_CULL_FACE);
				qglEnable (GL_STENCIL_TEST_TWO_SIDE_EXT);

				qglActiveStencilFaceEXT (GL_BACK);
				qglStencilOp (GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP);
				qglActiveStencilFaceEXT (GL_FRONT);
				qglStencilOp (GL_KEEP, GL_DECR_WRAP_EXT, GL_KEEP);

				R_DrawShadowVolume ();

				qglDisable (GL_STENCIL_TEST_TWO_SIDE_EXT);
				GL_Enable(GL_CULL_FACE);
			}
			else
			{	// increment stencil if backface is behind depthbuffer
				GL_CullFace(GL_BACK); // quake is backwards, this culls front faces
				qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
				R_DrawShadowVolume ();

				// decrement stencil if frontface is behind depthbuffer
				GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
				qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
				R_DrawShadowVolume ();
			}
		}
		else
			R_DrawShadowVolume ();

		GL_UnlockArrays ();
	}

	// end stenciling and draw stenciled volume
	if (!r_shadowvolumes->value)
	{
		GL_CullFace(GL_FRONT);
		GL_Disable(GL_STENCIL_TEST);
		
		GL_DepthFunc(GL_LEQUAL);
		GL_DepthMask(1);
		qglColorMask(1,1,1,1);
		
		// draw shadows for this model now
		R_ShadowBlend (aliasShadowAlpha * currententity->alpha); // was r_shadowalpha->value
		qglPopAttrib(); // restore stencil buffer
	}
}
Esempio n. 18
0
//---------------------------------------------------------
static void WP_BowcasterMainFire( gentity_t *ent )
//---------------------------------------------------------
{
	int			damage	= weaponData[WP_BOWCASTER].damage, count;
	float		vel;
	vec3_t		angs, dir, start;
	gentity_t	*missile;

	VectorCopy( muzzle, start );
	WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall

	// Do the damages
	if ( ent->s.number != 0 )
	{
		if ( g_spskill->integer == 0 )
		{
			damage = BOWCASTER_NPC_DAMAGE_EASY;
		}
		else if ( g_spskill->integer == 1 )
		{
			damage = BOWCASTER_NPC_DAMAGE_NORMAL;
		}
		else
		{
			damage = BOWCASTER_NPC_DAMAGE_HARD;
		}
	}

	count = ( level.time - ent->client->ps.weaponChargeTime ) / BOWCASTER_CHARGE_UNIT;

	if ( count < 1 )
	{
		count = 1;
	}
	else if ( count > 5 )
	{
		count = 5;
	}

	if ( !(count & 1 ))
	{
		// if we aren't odd, knock us down a level
		count--;
	}

//	if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time )
//	{
//		// in overcharge mode, so doing double damage
//		damage *= 2;
//	}

	WP_MissileTargetHint(ent, start, forwardVec);
	for ( int i = 0; i < count; i++ )
	{
		// create a range of different velocities
		vel = BOWCASTER_VELOCITY * ( Q_flrand(-1.0f, 1.0f) * BOWCASTER_VEL_RANGE + 1.0f );

		vectoangles( forwardVec, angs );

		if ( !(ent->client->ps.forcePowersActive&(1<<FP_SEE))
			|| ent->client->ps.forcePowerLevel[FP_SEE] < FORCE_LEVEL_2 )
		{//force sight 2+ gives perfect aim
			//FIXME: maybe force sight level 3 autoaims some?
			// add some slop to the fire direction
			angs[PITCH] += Q_flrand(-1.0f, 1.0f) * BOWCASTER_ALT_SPREAD * 0.2f;
			angs[YAW]	+= ((i+0.5f) * BOWCASTER_ALT_SPREAD - count * 0.5f * BOWCASTER_ALT_SPREAD );
			if ( ent->NPC )
			{
				angs[PITCH] += ( Q_flrand(-1.0f, 1.0f) * (BLASTER_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f) );
				angs[YAW]	+= ( Q_flrand(-1.0f, 1.0f) * (BLASTER_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f) );
			}
		}

		AngleVectors( angs, dir, NULL, NULL );

		missile = CreateMissile( start, dir, vel, 10000, ent );

		missile->classname = "bowcaster_proj";
		missile->s.weapon = WP_BOWCASTER;

		VectorSet( missile->maxs, BOWCASTER_SIZE, BOWCASTER_SIZE, BOWCASTER_SIZE );
		VectorScale( missile->maxs, -1, missile->mins );

//		if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time )
//		{
//			missile->flags |= FL_OVERCHARGED;
//		}

		missile->damage = damage;
		missile->dflags = DAMAGE_DEATH_KNOCKBACK;
		missile->methodOfDeath = MOD_BOWCASTER;
		missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
		missile->splashDamage = weaponData[WP_BOWCASTER].splashDamage;
		missile->splashRadius = weaponData[WP_BOWCASTER].splashRadius;

		// we don't want it to bounce
		missile->bounceCount = 0;
		ent->client->sess.missionStats.shotsFired++;
	}
}
Esempio n. 19
0
static void ForwardDlight( void ) {
	int		l;
	//vec3_t	origin;
	//float	scale;
	float	radius;

	int deformGen;
	vec5_t deformParams;
	
	vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0};
	float eyeT = 0;

	shaderCommands_t *input = &tess;
	shaderStage_t *pStage = tess.xstages[0];

	if ( !backEnd.refdef.num_dlights ) {
		return;
	}
	
	ComputeDeformValues(&deformGen, deformParams);

	ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT, NULL);

	for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {
		dlight_t	*dl;
		shaderProgram_t *sp;
		vec4_t vector;
		vec4_t texMatrix;
		vec4_t texOffTurb;

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

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

		//if (pStage->glslShaderGroup == tr.lightallShader)
		{
			int index = pStage->glslShaderIndex;

			index &= ~LIGHTDEF_LIGHTTYPE_MASK;
			index |= LIGHTDEF_USE_LIGHT_VECTOR;

			sp = &tr.lightallShader[index];
		}

		backEnd.pc.c_lightallDraws++;

		GLSL_BindProgram(sp);

		GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
		GLSL_SetUniformVec3(sp, UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin);
		GLSL_SetUniformVec3(sp, UNIFORM_LOCALVIEWORIGIN, backEnd.or.viewOrigin);

		GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);

		GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
		if (deformGen != DGEN_NONE)
		{
			GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams);
			GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime);
		}

		if ( input->fogNum ) {
			vec4_t fogColorMask;

			GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector);
			GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector);
			GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT);

			ComputeFogColorMask(pStage, fogColorMask);

			GLSL_SetUniformVec4(sp, UNIFORM_FOGCOLORMASK, fogColorMask);
		}

		{
			vec4_t baseColor;
			vec4_t vertColor;

			ComputeShaderColors(pStage, baseColor, vertColor, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);

			GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, baseColor);
			GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, vertColor);
		}

		if (pStage->alphaGen == AGEN_PORTAL)
		{
			GLSL_SetUniformFloat(sp, UNIFORM_PORTALRANGE, tess.shader->portalRange);
		}

		GLSL_SetUniformInt(sp, UNIFORM_COLORGEN, pStage->rgbGen);
		GLSL_SetUniformInt(sp, UNIFORM_ALPHAGEN, pStage->alphaGen);

		GLSL_SetUniformVec3(sp, UNIFORM_DIRECTEDLIGHT, dl->color);

		VectorSet(vector, 0, 0, 0);
		GLSL_SetUniformVec3(sp, UNIFORM_AMBIENTLIGHT, vector);

		VectorCopy(dl->origin, vector);
		vector[3] = 1.0f;
		GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vector);

		GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, radius);

		GLSL_SetUniformVec4(sp, UNIFORM_NORMALSCALE, pStage->normalScale);
		GLSL_SetUniformVec4(sp, UNIFORM_SPECULARSCALE, pStage->specularScale);
		
		// include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
		// where they aren't rendered
		GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );

		GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix);

		if (pStage->bundle[TB_DIFFUSEMAP].image[0])
			R_BindAnimatedImageToTMU( &pStage->bundle[TB_DIFFUSEMAP], TB_DIFFUSEMAP);

		// bind textures that are sampled and used in the glsl shader, and
		// bind whiteImage to textures that are sampled but zeroed in the glsl shader
		//
		// alternatives:
		//  - use the last bound texture
		//     -> costs more to sample a higher res texture then throw out the result
		//  - disable texture sampling in glsl shader with #ifdefs, as before
		//     -> increases the number of shaders that must be compiled
		//

		if (pStage->bundle[TB_NORMALMAP].image[0])
		{
			R_BindAnimatedImageToTMU( &pStage->bundle[TB_NORMALMAP], TB_NORMALMAP);
		}
		else if (r_normalMapping->integer)
			GL_BindToTMU( tr.whiteImage, TB_NORMALMAP );

		if (pStage->bundle[TB_SPECULARMAP].image[0])
		{
			R_BindAnimatedImageToTMU( &pStage->bundle[TB_SPECULARMAP], TB_SPECULARMAP);
		}
		else if (r_specularMapping->integer)
			GL_BindToTMU( tr.whiteImage, TB_SPECULARMAP );

		{
			vec4_t enableTextures;

			VectorSet4(enableTextures, 0.0f, 0.0f, 0.0f, 0.0f);
			GLSL_SetUniformVec4(sp, UNIFORM_ENABLETEXTURES, enableTextures);
		}

		if (r_dlightMode->integer >= 2)
		{
			GL_SelectTexture(TB_SHADOWMAP);
			GL_Bind(tr.shadowCubemaps[l]);
			GL_SelectTexture(0);
		}

		ComputeTexMods( pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb );
		GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix);
		GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, texOffTurb);

		GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen);

		//
		// draw
		//

		if (input->multiDrawPrimitives)
		{
			R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex);
		}
		else
		{
			R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex);
		}

		backEnd.pc.c_totalIndexes += tess.numIndexes;
		backEnd.pc.c_dlightIndexes += tess.numIndexes;
		backEnd.pc.c_dlightVertexes += tess.numVertexes;
	}
}
Esempio n. 20
0
/*
===============
UI_PlayerInfo_SetInfo
===============
*/
void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNumber, qboolean chat ) {
	int			currentAnim;
	weapon_t	weaponNum;
	int			c;

	pi->chat = chat;

	c = (int)trap_Cvar_VariableValue( "color1" );
 
	VectorClear( pi->color1 );

	if( c < 1 || c > 7 ) {
		VectorSet( pi->color1, 1, 1, 1 );
	}
	else {
		if( c & 1 ) {
			pi->color1[2] = 1.0f;
		}

		if( c & 2 ) {
			pi->color1[1] = 1.0f;
		}

		if( c & 4 ) {
			pi->color1[0] = 1.0f;
		}
	}

	pi->c1RGBA[0] = 255 * pi->color1[0];
	pi->c1RGBA[1] = 255 * pi->color1[1];
	pi->c1RGBA[2] = 255 * pi->color1[2];
	pi->c1RGBA[3] = 255;

	// view angles
	VectorCopy( viewAngles, pi->viewAngles );

	// move angles
	VectorCopy( moveAngles, pi->moveAngles );

	if ( pi->newModel ) {
		pi->newModel = qfalse;

		jumpHeight = 0;
		pi->pendingLegsAnim = 0;
		UI_ForceLegsAnim( pi, legsAnim );
		pi->legs.yawAngle = viewAngles[YAW];
		pi->legs.yawing = qfalse;

		pi->pendingTorsoAnim = 0;
		UI_ForceTorsoAnim( pi, torsoAnim );
		pi->torso.yawAngle = viewAngles[YAW];
		pi->torso.yawing = qfalse;

		if ( weaponNumber != WP_NUM_WEAPONS ) {
			pi->weapon = weaponNumber;
			pi->currentWeapon = weaponNumber;
			pi->lastWeapon = weaponNumber;
			pi->pendingWeapon = WP_NUM_WEAPONS;
			pi->weaponTimer = 0;
			UI_PlayerInfo_SetWeapon( pi, pi->weapon );
		}

		return;
	}

	// weapon
	if ( weaponNumber == WP_NUM_WEAPONS ) {
		pi->pendingWeapon = WP_NUM_WEAPONS;
		pi->weaponTimer = 0;
	}
	else if ( weaponNumber != WP_NONE ) {
		pi->pendingWeapon = weaponNumber;
		pi->weaponTimer = dp_realtime + UI_TIMER_WEAPON_DELAY;
	}
	weaponNum = pi->lastWeapon;
	pi->weapon = weaponNum;

	if ( torsoAnim == BOTH_DEATH1 || legsAnim == BOTH_DEATH1 ) {
		torsoAnim = legsAnim = BOTH_DEATH1;
		pi->weapon = pi->currentWeapon = WP_NONE;
		UI_PlayerInfo_SetWeapon( pi, pi->weapon );

		jumpHeight = 0;
		pi->pendingLegsAnim = 0;
		UI_ForceLegsAnim( pi, legsAnim );

		pi->pendingTorsoAnim = 0;
		UI_ForceTorsoAnim( pi, torsoAnim );

		return;
	}

	// leg animation
	currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT;
	if ( legsAnim != LEGS_JUMP && ( currentAnim == LEGS_JUMP || currentAnim == LEGS_LAND ) ) {
		pi->pendingLegsAnim = legsAnim;
	}
	else if ( legsAnim != currentAnim ) {
		jumpHeight = 0;
		pi->pendingLegsAnim = 0;
		UI_ForceLegsAnim( pi, legsAnim );
	}

	// torso animation
	if ( torsoAnim == TORSO_STAND || torsoAnim == TORSO_STAND2 ) {
		if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) {
			torsoAnim = TORSO_STAND2;
		}
		else {
			torsoAnim = TORSO_STAND;
		}
	}

	if ( torsoAnim == TORSO_ATTACK || torsoAnim == TORSO_ATTACK2 ) {
		if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) {
			torsoAnim = TORSO_ATTACK2;
		}
		else {
			torsoAnim = TORSO_ATTACK;
		}
		pi->muzzleFlashTime = dp_realtime + UI_TIMER_MUZZLE_FLASH;
		//FIXME play firing sound here
	}

	currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;

	if ( weaponNum != pi->currentWeapon || currentAnim == TORSO_RAISE || currentAnim == TORSO_DROP ) {
		pi->pendingTorsoAnim = torsoAnim;
	}
	else if ( ( currentAnim == TORSO_GESTURE || currentAnim == TORSO_ATTACK ) && ( torsoAnim != currentAnim ) ) {
		pi->pendingTorsoAnim = torsoAnim;
	}
	else if ( torsoAnim != currentAnim ) {
		pi->pendingTorsoAnim = 0;
		UI_ForceTorsoAnim( pi, torsoAnim );
	}
}
Esempio n. 21
0
static void CG_OffsetThirdPersonView( void )
{
  vec3_t        forward, right, up;
  vec3_t        view;
  vec3_t        focusAngles;
  trace_t       trace;
  static vec3_t mins = { -8, -8, -8 };
  static vec3_t maxs = { 8, 8, 8 };
  vec3_t        focusPoint;
  float         focusDist;
  float         forwardScale, sideScale;
  vec3_t        surfNormal;

  if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING )
  {
    if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
      VectorSet( surfNormal, 0.0f, 0.0f, -1.0f );
    else
      VectorCopy( cg.predictedPlayerState.grapplePoint, surfNormal );
  }
  else
    VectorSet( surfNormal, 0.0f, 0.0f, 1.0f );

  VectorMA( cg.refdef.vieworg, cg.predictedPlayerState.viewheight, surfNormal, cg.refdef.vieworg );

  VectorCopy( cg.refdefViewAngles, focusAngles );

  // if dead, look at killer
  if( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 )
  {
    focusAngles[ YAW ] = cg.predictedPlayerState.stats[ STAT_VIEWLOCK ];
    cg.refdefViewAngles[ YAW ] = cg.predictedPlayerState.stats[ STAT_VIEWLOCK ];
  }

  //if ( focusAngles[PITCH] > 45 ) {
  //  focusAngles[PITCH] = 45;    // don't go too far overhead
  //}
  AngleVectors( focusAngles, forward, NULL, NULL );

  VectorMA( cg.refdef.vieworg, FOCUS_DISTANCE, forward, focusPoint );

  VectorCopy( cg.refdef.vieworg, view );

  VectorMA( view, cg_thirdpersonheight.integer, surfNormal, view ); //12

  //cg.refdefViewAngles[PITCH] *= 0.5;

  AngleVectors( cg.refdefViewAngles, forward, right, up );

  forwardScale = cos( cg_thirdPersonAngle.value / 180 * M_PI );
  sideScale = sin( cg_thirdPersonAngle.value / 180 * M_PI );
  VectorMA( view, -cg_thirdPersonRange.value * forwardScale, forward, view );
  VectorMA( view, -cg_thirdPersonRange.value * sideScale, right, view );

  // trace a ray from the origin to the viewpoint to make sure the view isn't
  // in a solid block.  Use an 8 by 8 block to prevent the view from near clipping anything

  if( !cg_cameraMode.integer )
  {
    CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );

    if( trace.fraction != 1.0 )
    {
      VectorCopy( trace.endpos, view );
      view[ 2 ] += ( 1.0 - trace.fraction ) * 32;
      // try another trace to this position, because a tunnel may have the ceiling
      // close enogh that this is poking out

      CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID );
      VectorCopy( trace.endpos, view );
    }
  }

  VectorCopy( view, cg.refdef.vieworg );

  // select pitch to look at focus point from vieword
  VectorSubtract( focusPoint, cg.refdef.vieworg, focusPoint );
  focusDist = sqrt( focusPoint[ 0 ] * focusPoint[ 0 ] + focusPoint[ 1 ] * focusPoint[ 1 ] );
  if ( focusDist < 1 ) {
    focusDist = 1;  // should never happen
  }
  cg.refdefViewAngles[ PITCH ] = -180 / M_PI * atan2( focusPoint[ 2 ], focusDist );
  cg.refdefViewAngles[ YAW ] -= cg_thirdPersonAngle.value;
}
Esempio n. 22
0
void LoadJTRAIL(edict_t *ent,char filename[MAX_STR_LEN],qboolean pdm,int clean,int colorp,int sizep)
{
	
	FILE *jtrail_file;
	char *token="\0";
	char buf2[1000];
	char message[256];
	int lbuf2,color,mass;
	edict_t *laser = NULL;
	vec3_t start;
	int lasttrailnum=0;
	char JTRAILFile[MAX_STR_LEN];
	int delcount=0;
	char tok[2]="";
	int clean_count=0;
	int total_good_lines=0;
	
	if (TrailsBanned()) return;

	if (pdm)
	{
		if (!Q_stricmp(filename,"lastdemo"))
			sprintf(JTRAILFile, GAMEVERSION "/puppetdemo/%i.pdm",ent->client->resp.id);
		else
			sprintf(JTRAILFile, GAMEVERSION "/puppetdemo/%s-%s.pdm",level.mapname,filename);
	}
	else
		sprintf(JTRAILFile, GAMEVERSION "/jtrail/%s-%s.jtrail",level.mapname,filename);

	jtrail_file = fopen(JTRAILFile, "r");
	if (jtrail_file == NULL)
	{
		if (pdm)
		{
			if (!Q_stricmp(filename,"lastdemo"))
				gi.cprintf(ent,PRINT_HIGH,"\"%i.pdm\" was not found!\n",ent->client->resp.id);
			else
				gi.cprintf(ent,PRINT_HIGH,"\"%s-%s.pdm\" was not found!\n",level.mapname,filename);
		}
		else
			gi.cprintf(ent,PRINT_HIGH,"\"%s-%s.jtrail\" was not found!\n",level.mapname,filename);
		return;
	}
	
    if (pdm)
		tok[0] = ',';	//puppet demos parsed with ','
	else
		tok[0] = ' ';	//trail files parsed with ' '
	tok[1] = '\0';

	//grab the total good lines, for new clean-on-load usage
	while (fgets(buf2, 900, jtrail_file) != NULL)
	{
		if (!(((buf2[0] > '0') && (buf2[0] < '9')) || (buf2[0] == '-')))
			continue;
		total_good_lines++;
	}
	fclose(jtrail_file);

	//reopen the file to start reading again... we know it exists so no check on that
	jtrail_file = fopen(JTRAILFile, "r");
	jtrail_num_lines = 0;
	ltrails++;
	while (fgets(buf2, 900, jtrail_file) != NULL)
	{
		double time;

		if (!(((buf2[0] > '0') && (buf2[0] < '9')) || (buf2[0] == '-')))
			continue;

		if (clean_count != clean)
		{
			if ((jtrail_num_lines != 0) && (jtrail_num_lines != total_good_lines))
			{
				clean_count++;
				continue;
			}
			clean_count++;
		}
		else
			clean_count = 0;

		message[0]='\0';
		lbuf2 = strlen(buf2);
		while (buf2[lbuf2-1] == '\r' || buf2[lbuf2-1] == '\n')
		{
			buf2[lbuf2-1] = 0;
			lbuf2--;
		}
		
		start[0] = start[1] = start[2] = color = mass = 0;

		if (ltnodes <= traillimit->value)
		{
			laser = G_Spawn();
			//		laser->owner = ent;

			ltnodes++;
			laser->classnum = jtrail_num_lines+1;//ltnodes;
			laser->classname = "LaserTrailLink";
			laser->s.frame = 4;
			VectorSet (laser->mins, -8, -8, -8);
			VectorSet (laser->maxs, 8, 8, 8);
			
			//Load Coords
			token = strtok( buf2, tok );
			start[0] = atoi(token);
			token = strtok( NULL, tok );
			if ((token == NULL) && pdm)
				break;
			start[1] = atoi(token);
			token = strtok( NULL, tok );
			start[2] = atoi(token);
			VectorCopy(start,laser->s.origin);

			if (pdm)
			{
				if (colorp == -1)
					laser->s.skinnum = NUMtoCOLOR(1); //color (green)
				else
					laser->s.skinnum = NUMtoCOLOR(colorp);

				if (sizep == -1)
					laser->s.frame = 4; //size
				else
					laser->s.frame = sizep;
				laser->mass = ltrails; //num (never gonna be multiple paths to load this way)
			}
			else
			{
				//Load Color
				token = strtok( NULL, tok );
				color = atoi(token);
				laser->s.skinnum = color;
				
				//Load Size
				token = strtok( NULL, tok );
				color = atoi(token);
				laser->s.frame = color;
				
				//Load Gravity
				token = strtok( NULL, tok );
				color = atoi(token);
				
				if (lasttrailnum != color)
				{
					ltrails++;
					lasttrailnum = color;
				}
				
				laser->mass = color+ltrails;
			}
			
			time = level.time + (jtrail_num_lines/10);
			
			laser->think = DelayLaserLinkOn;//MODIFY ME!!!WHY?!!//DelayMarkerLoad_Think;
			laser->nextthink = time;
			
			gi.linkentity(laser);
		}
		else
		{
			delcount++;
		}
		
		jtrail_num_lines++;
	}

	fclose(jtrail_file);
	
	if (delcount !=0)
	{
		if (delcount == jtrail_num_lines)
			gi.bprintf(PRINT_HIGH,"%s: \"%s\" could not be loaded due to traillimit hit!\n",ent->client->pers.netname,JTRAILFile);
		else
		{
			gi.bprintf(PRINT_HIGH,"%s: \"%s\" was partially loaded due to traillimit hit! (%i/%i link",ent->client->pers.netname,JTRAILFile,jtrail_num_lines-delcount,jtrail_num_lines);
			if (jtrail_num_lines != 1)
				gi.bprintf(PRINT_HIGH,"s");
			if (jtrail_num_lines-delcount > 10)
				gi.bprintf(PRINT_HIGH," (%i in queue))\n",jtrail_num_lines-delcount-10);
			else
				gi.bprintf(PRINT_HIGH,")\n");
		}
	}
	else
	{
		gi.bprintf(PRINT_HIGH,"%s: \"%s\" was loaded successfully! (%i link",ent->client->pers.netname,JTRAILFile,jtrail_num_lines);
		if (jtrail_num_lines != 1)
			gi.bprintf(PRINT_HIGH,"s");
		if (jtrail_num_lines > 10)
			gi.bprintf(PRINT_HIGH," (%i in queue))\n",jtrail_num_lines-10);
		else
			gi.bprintf(PRINT_HIGH,")\n");
	}
}
Esempio n. 23
0
/*
* G_Damage
* targ		entity that is being damaged
* inflictor	entity that is causing the damage
* attacker	entity that caused the inflictor to damage targ
* example: targ=enemy, inflictor=rocket, attacker=player
*
* dir			direction of the attack
* point		point at which the damage is being inflicted
* normal		normal vector from that point
* damage		amount of damage being inflicted
* knockback	force to be applied against targ as a result of the damage
*
* dflags		these flags are used to control how T_Damage works
*/
void G_Damage( edict_t *targ, edict_t *inflictor, edict_t *attacker, const vec3_t pushdir, const vec3_t dmgdir, const vec3_t point, float damage, float knockback, float stun, int dflags, int mod )
{
	gclient_t *client;
	float take;
	float save;
	float asave;
	bool statDmg;

	if( !targ || !targ->takedamage )
		return;

	if( !attacker )
	{
		attacker = world;
		mod = MOD_TRIGGER_HURT;
	}

	meansOfDeath = mod;

	client = targ->r.client;

	// Cgg - race mode: players don't interact with one another
	if( GS_RaceGametype() )
	{
		if( attacker->r.client && targ->r.client && attacker != targ )
			return;
	}

	// push
	if( !( dflags & DAMAGE_NO_KNOCKBACK ) )
		G_KnockBackPush( targ, attacker, pushdir, knockback, dflags );

	// stun
	if( g_allow_stun->integer && !( dflags & (DAMAGE_NO_STUN|FL_GODMODE) )
		&& (int)stun > 0 && targ->r.client && targ->r.client->resp.takeStun &&
		!GS_IsTeamDamage( &targ->s, &attacker->s ) && ( targ != attacker ) )
	{
		if( dflags & DAMAGE_STUN_CLAMP )
		{
			if( targ->r.client->ps.pmove.stats[PM_STAT_STUN] < (int)stun )
				targ->r.client->ps.pmove.stats[PM_STAT_STUN] = (int)stun;
		}
		else
			targ->r.client->ps.pmove.stats[PM_STAT_STUN] += (int)stun;

		clamp( targ->r.client->ps.pmove.stats[PM_STAT_STUN], 0, MAX_STUN_TIME );
	}

	// dont count self-damage cause it just adds the same to both stats
	statDmg = ( attacker != targ ) && ( mod != MOD_TELEFRAG );

	// apply handicap on the damage given
	if( statDmg && attacker->r.client && !GS_Instagib() )
	{
		// handicap is a percentage value
		if( attacker->r.client->handicap != 0 )
			damage *= 1.0 - (attacker->r.client->handicap * 0.01f);
	}

	take = damage;
	save = 0;

	// check for cases where damage is protected
	if( !( dflags & DAMAGE_NO_PROTECTION ) )
	{
		// check for godmode
		if( targ->flags & FL_GODMODE )
		{
			take = 0;
			save = damage;
		}
		// never damage in timeout
		else if( GS_MatchPaused() )
		{
			take = save = 0;
		}
		// ca has self splash damage disabled
		else if( ( dflags & DAMAGE_RADIUS ) && attacker == targ && !GS_SelfDamage() )
		{
			take = save = 0;
		}
		// don't get damage from players in race
		else if( ( GS_RaceGametype() ) && attacker->r.client && targ->r.client &&
			( attacker->r.client != targ->r.client ) )
		{
			take = save = 0;
		}
		// team damage avoidance
		else if( GS_IsTeamDamage( &targ->s, &attacker->s ) && !G_Gametype_CanTeamDamage( dflags ) )
		{
			take = save = 0;
		}
		// apply warShell powerup protection
		else if( targ->r.client && targ->r.client->ps.inventory[POWERUP_SHELL] > 0 )
		{
			// warshell offers full protection in instagib
			if( GS_Instagib() )
			{
				take = 0;
				save = damage;
			}
			else
			{
				take = ( damage * 0.25f );
				save = damage - take;
			}
			// todo : add protection sound
		}
	}

	asave = G_CheckArmor( targ, take, dflags );
	take -= asave;

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

	// APPLY THE DAMAGES

	if( !take && !asave )
		return;

	// do the damage
	if( take <= 0 )
		return;

	// adding damage given/received to stats
	if( statDmg && attacker->r.client && !targ->deadflag && targ->movetype != MOVETYPE_PUSH && targ->s.type != ET_CORPSE )
	{
		attacker->r.client->level.stats.total_damage_given += take + asave;
		teamlist[attacker->s.team].stats.total_damage_given += take + asave;
		if( GS_IsTeamDamage( &targ->s, &attacker->s ) )
		{
			attacker->r.client->level.stats.total_teamdamage_given += take + asave;
			teamlist[attacker->s.team].stats.total_teamdamage_given += take + asave;
		}
	}

	G_Gametype_ScoreEvent( attacker->r.client, "dmg", va( "%i %f %i", targ->s.number, damage, attacker->s.number ) );

	if( statDmg && client )
	{
		client->level.stats.total_damage_received += take + asave;
		teamlist[targ->s.team].stats.total_damage_received += take + asave;
		if( GS_IsTeamDamage( &targ->s, &attacker->s ) )
		{
			client->level.stats.total_teamdamage_received += take + asave;
			teamlist[targ->s.team].stats.total_teamdamage_received += take + asave;
		}
	}

	// accumulate received damage for snapshot effects
	{
		vec3_t dorigin;

		if( inflictor == world && mod == MOD_FALLING ) // it's fall damage
			targ->snap.damage_fall += take + save;

		if( point[0] != 0.0f || point[1] != 0.0f || point[2] != 0.0f )
			VectorCopy( point, dorigin );
		else
			VectorSet( dorigin,
			targ->s.origin[0],
			targ->s.origin[1],
			targ->s.origin[2] + targ->viewheight );

		G_BlendFrameDamage( targ, take, &targ->snap.damage_taken, dorigin, dmgdir, targ->snap.damage_at, targ->snap.damage_dir );
		G_BlendFrameDamage( targ, save, &targ->snap.damage_saved, dorigin, dmgdir, targ->snap.damage_at, targ->snap.damage_dir );

		if( targ->r.client )
		{
			if( mod != MOD_FALLING && mod != MOD_TELEFRAG && mod != MOD_SUICIDE )
			{
				if( inflictor == world || attacker == world )
				{
					// for world inflicted damage use always 'frontal'
					G_ClientAddDamageIndicatorImpact( targ->r.client, take + save, NULL );
				}
				else if( dflags & DAMAGE_RADIUS )
				{
					// for splash hits the direction is from the inflictor origin
					G_ClientAddDamageIndicatorImpact( targ->r.client, take + save, pushdir );
				}
				else
				{	// for direct hits the direction is the projectile direction
					G_ClientAddDamageIndicatorImpact( targ->r.client, take + save, dmgdir );
				}
			}
		}
	}

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

	// add damage done to stats
	if( !GS_IsTeamDamage( &targ->s, &attacker->s ) && statDmg && G_ModToAmmo( mod ) != AMMO_NONE && client && attacker->r.client )
	{
		attacker->r.client->level.stats.accuracy_hits[G_ModToAmmo( mod )-AMMO_GUNBLADE]++;
		attacker->r.client->level.stats.accuracy_damage[G_ModToAmmo( mod )-AMMO_GUNBLADE] += damage;
		teamlist[attacker->s.team].stats.accuracy_hits[G_ModToAmmo( mod )-AMMO_GUNBLADE]++;
		teamlist[attacker->s.team].stats.accuracy_damage[G_ModToAmmo( mod )-AMMO_GUNBLADE] += damage;

		G_AwardPlayerHit( targ, attacker, mod );
	}

	// accumulate given damage for hit sounds
	if( ( take || asave ) && targ != attacker && client && !targ->deadflag )
	{
		if( attacker )
		{
			if( GS_IsTeamDamage( &targ->s, &attacker->s ) )
				attacker->snap.damageteam_given += take + asave; // we want to know how good our hit was, so saved also matters
			else
				attacker->snap.damage_given += take + asave;
		}
	}

	if( G_IsDead( targ ) )
	{
		if( client )
			targ->flags |= FL_NO_KNOCKBACK;
		G_Killed( targ, inflictor, attacker, HEALTH_TO_INT( take ), point, mod );
	}
	else 
	{
		G_CallPain( targ, attacker, knockback, take );
	}
}
Esempio n. 24
0
/*QUAKED monster_floater (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
*/
void SP_monster_floater(edict_t *self)
{
	if (deathmatch->value)
	{
		G_FreeEdict(self);
		return;
	}

	sound_attack2 = gi.soundindex("floater/fltatck2.wav");
	sound_attack3 = gi.soundindex("floater/fltatck3.wav");
	sound_death1 = gi.soundindex("floater/fltdeth1.wav");
	sound_idle = gi.soundindex("floater/fltidle1.wav");
	sound_pain1 = gi.soundindex("floater/fltpain1.wav");
	sound_pain2 = gi.soundindex("floater/fltpain2.wav");
	sound_sight = gi.soundindex("floater/fltsght1.wav");

	gi.soundindex("floater/fltatck1.wav");

	self->s.sound = gi.soundindex("floater/fltsrch1.wav");
	self->movetype = MOVETYPE_STEP;
	self->solid = SOLID_BBOX;

	// Lazarus: special purpose skins
	if (self->style)
	{
		PatchMonsterModel("models/monsters/float/tris.md2");
		self->s.skinnum = self->style * 2;
	}
	
	self->s.modelindex = gi.modelindex("models/monsters/float/tris.md2");
	VectorSet(self->mins, -24, -24, -24);
	VectorSet(self->maxs, 24, 24, 32);

	// Lazarus: mapper-configurable health
	if (!self->health)
		self->health = 200;
	if (!self->gib_health)
		self->gib_health = -80;
	if (!self->mass)
		self->mass = 300;

	self->pain = floater_pain;
	self->die = floater_die;

	self->monsterinfo.stand = floater_stand;
	self->monsterinfo.walk = floater_walk;
	self->monsterinfo.run = floater_run;
//	self->monsterinfo.dodge = floater_dodge;
	self->monsterinfo.attack = floater_attack;
	self->monsterinfo.melee = floater_melee;
	self->monsterinfo.sight = floater_sight;
	self->monsterinfo.idle = floater_idle;

	// Knightmare- added sparks and blood type
	if (!self->blood_type)
		self->blood_type = 2; //sparks
	else
		self->fogclip |= 2; //custom bloodtype flag

	// Lazarus
	if (self->powerarmor)
	{
		self->monsterinfo.power_armor_type = POWER_ARMOR_SHIELD;
		self->monsterinfo.power_armor_power = self->powerarmor;
	}

	self->common_name = "Technician";

	gi.linkentity(self);

	if (self->health < 0)
	{
		mmove_t	*deathmoves[] = { &floater_move_death, NULL };
		if (!M_SetDeath(self, (mmove_t **)&deathmoves))
			self->monsterinfo.currentmove = &floater_move_stand1;
	}
	else
	{
		if (random() <= 0.5)
			self->monsterinfo.currentmove = &floater_move_stand1;
		else
			self->monsterinfo.currentmove = &floater_move_stand2;
	}
	
	self->monsterinfo.scale = MODEL_SCALE;

	flymonster_start(self);
}
Esempio n. 25
0
/*QUAKED monster_mytank_commander (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight
*/
void init_drone_tank (edict_t *self)
{
//	if (deathmatch->value)
//	{
//		G_FreeEdict (self);
//		return;
//	}

	self->s.modelindex = gi.modelindex ("models/monsters/tank/tris.md2");
	VectorSet (self->mins, -24, -24, -16);
	VectorSet (self->maxs, 24, 24, 64);
	self->movetype = MOVETYPE_STEP;
	self->solid = SOLID_BBOX;

	sound_pain = gi.soundindex ("tank/tnkpain2.wav");
	sound_thud = gi.soundindex ("tank/tnkdeth2.wav");
	sound_idle = gi.soundindex ("tank/tnkidle1.wav");
	sound_die = gi.soundindex ("tank/death.wav");
	sound_step = gi.soundindex ("tank/step.wav");
	sound_windup = gi.soundindex ("tank/tnkatck4.wav");
	sound_strike = gi.soundindex ("tank/tnkatck5.wav");
	sound_sight = gi.soundindex ("tank/sight1.wav");

	gi.soundindex ("tank/tnkatck1.wav");
	gi.soundindex ("tank/tnkatk2a.wav");
	gi.soundindex ("tank/tnkatk2b.wav");
	gi.soundindex ("tank/tnkatk2c.wav");
	gi.soundindex ("tank/tnkatk2d.wav");
	gi.soundindex ("tank/tnkatk2e.wav");
	gi.soundindex ("tank/tnkatck3.wav");

//	if (self->activator && self->activator->client)
	self->health = 100 + 65*self->monsterinfo.level;
	//else self->health = 100 + 65*self->monsterinfo.level;

	self->max_health = self->health;
	self->gib_health = -200;

	//if (self->activator && self->activator->client)
	self->monsterinfo.power_armor_power = 200 + 105*self->monsterinfo.level;
	//else self->monsterinfo.power_armor_power = 200 + 105*self->monsterinfo.level;

	self->monsterinfo.power_armor_type = POWER_ARMOR_SHIELD;
	self->monsterinfo.max_armor = self->monsterinfo.power_armor_power;

	self->monsterinfo.control_cost = M_TANK_CONTROL_COST;
	self->monsterinfo.cost = M_TANK_COST;
	self->mtype = M_TANK;
	
	if (random() > 0.5)
		self->item = FindItemByClassname("ammo_bullets");
	else
		self->item = FindItemByClassname("ammo_rockets");

	self->mass = 500;

	//self->pain = mytank_pain;
	self->die = mytank_die;
	//self->touch = mytank_touch;
	self->monsterinfo.stand = mytank_stand;
	self->monsterinfo.walk = tank_walk;
	self->monsterinfo.run = mytank_run;
	self->monsterinfo.dodge = NULL;
	self->monsterinfo.attack = mytank_attack;
	self->monsterinfo.melee = mytank_melee;
	self->monsterinfo.sight = mytank_sight;
	self->monsterinfo.idle = mytank_idle;
	self->monsterinfo.jumpup = 64;
	self->monsterinfo.jumpdn = 512;
	self->monsterinfo.aiflags |= AI_NO_CIRCLE_STRAFE;
	//self->monsterinfo.melee = 1;

	gi.linkentity (self);
	
	self->monsterinfo.currentmove = &mytank_move_stand;
	self->monsterinfo.scale = MODEL_SCALE;

//	walkmonster_start(self);
	self->nextthink = level.time + FRAMETIME;

//	self->activator->num_monsters += self->monsterinfo.control_cost;
}
Esempio n. 26
0
/*
==================
PM_StepSlideMove

==================
*/
void PM_StepSlideMove( qboolean gravity ) { 
	vec3_t		start_o, start_v;
	vec3_t		down_o, down_v;
	trace_t		trace;
//	float		down_dist, up_dist;
//	vec3_t		delta, delta2;
	vec3_t		up, down;
	float		stepSize;
	qboolean	isGiant = qfalse;
	bgEntity_t	*pEnt;
	qboolean skipStep = qfalse;

	VectorCopy (pm->ps->origin, start_o);
	VectorCopy (pm->ps->velocity, start_v);

	if ( BG_InReboundHold( pm->ps->legsAnim ) )
	{
		gravity = qfalse;
	}

	if ( PM_SlideMove( gravity ) == 0 ) {
		return;		// we got exactly where we wanted to go first try	
	}

	pEnt = pm_entSelf;

	if (pm->ps->clientNum >= MAX_CLIENTS)
	{
		if (pEnt && pEnt->s.NPC_class == CLASS_VEHICLE &&
			pEnt->m_pVehicle && pEnt->m_pVehicle->m_pVehicleInfo->hoverHeight > 0)
		{
			return;
		}
	}

	VectorCopy(start_o, down);
	down[2] -= STEPSIZE;
	pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);
	VectorSet(up, 0, 0, 1);
	// never step up when you still have up velocity
	if ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 ||
										DotProduct(trace.plane.normal, up) < 0.7))
	{
		return;
	}

	VectorCopy (pm->ps->origin, down_o);
	VectorCopy (pm->ps->velocity, down_v);

	VectorCopy (start_o, up);

	if (pm->ps->clientNum >= MAX_CLIENTS)
	{
		// apply ground friction, even if on ladder
		if (pEnt &&
			pEnt->s.NPC_class == CLASS_ATST ||
				(pEnt->s.NPC_class == CLASS_VEHICLE &&
					pEnt->m_pVehicle &&
					pEnt->m_pVehicle->m_pVehicleInfo->type == VH_WALKER)
			)
		{//AT-STs can step high
			up[2] += 66.0f;
			isGiant = qtrue;
		}
		else if ( pEnt && pEnt->s.NPC_class == CLASS_RANCOR )
		{//also can step up high
			up[2] += 64.0f;
			isGiant = qtrue;
		}
		else
		{
			up[2] += STEPSIZE;
		}
	}
	else
	{
		up[2] += STEPSIZE;
	}

	// test the player position if they were a stepheight higher
	pm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask);
	if ( trace.allsolid ) {
		if ( pm->debugLevel ) {
			Com_Printf("%i:bend can't step\n", c_pmove);
		}
		return;		// can't step up
	}

	stepSize = trace.endpos[2] - start_o[2];
	// try slidemove from this position
	VectorCopy (trace.endpos, pm->ps->origin);
	VectorCopy (start_v, pm->ps->velocity);

	PM_SlideMove( gravity );

	// push down the final amount
	VectorCopy (pm->ps->origin, down);
	down[2] -= stepSize;
	pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);

	if ( pm->stepSlideFix )
	{
		if ( pm->ps->clientNum < MAX_CLIENTS
			&& trace.plane.normal[2] < MIN_WALK_NORMAL )
		{//normal players cannot step up slopes that are too steep to walk on!
			vec3_t stepVec;
			//okay, the step up ends on a slope that it too steep to step up onto,
			//BUT:
			//If the step looks like this:
			//  (B)\__
			//        \_____(A)
			//Then it might still be okay, so we figure out the slope of the entire move
			//from (A) to (B) and if that slope is walk-upabble, then it's okay
			VectorSubtract( trace.endpos, down_o, stepVec );
			VectorNormalize( stepVec ); 
			if ( stepVec[2] > (1.0f-MIN_WALK_NORMAL) )
			{
				skipStep = qtrue;
			}
		}
	}

	if ( !trace.allsolid 
		&& !skipStep ) //normal players cannot step up slopes that are too steep to walk on!
	{ 
		if ( pm->ps->clientNum >= MAX_CLIENTS//NPC
			&& isGiant 
			&& trace.entityNum < MAX_CLIENTS
			&& pEnt 
			&& pEnt->s.NPC_class == CLASS_RANCOR )
		{//Rancor don't step on clients
			if ( pm->stepSlideFix )
			{
				VectorCopy (down_o, pm->ps->origin);
				VectorCopy (down_v, pm->ps->velocity);
			}
			else
			{
				VectorCopy (start_o, pm->ps->origin);
				VectorCopy (start_v, pm->ps->velocity);
			}
		}
		/*
		else if ( pm->ps->clientNum >= MAX_CLIENTS//NPC
			&& isGiant 
			&& trace.entityNum < MAX_CLIENTS
			&& pEnt 
			&& pEnt->s.NPC_class == CLASS_ATST 
			&& OnSameTeam( pEnt, traceEnt) )
		{//NPC AT-ST's don't step up on allies
			VectorCopy (start_o, pm->ps->origin);
			VectorCopy (start_v, pm->ps->velocity);
		}
		*/
		else
		{
			VectorCopy (trace.endpos, pm->ps->origin);
			if ( pm->stepSlideFix )
			{
				if ( trace.fraction < 1.0 ) {
					PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
				}
			}
		}
	}
	else
	{
		if ( pm->stepSlideFix )
		{
			VectorCopy (down_o, pm->ps->origin);
			VectorCopy (down_v, pm->ps->velocity);
		}
	}
	if ( !pm->stepSlideFix )
	{
		if ( trace.fraction < 1.0 ) {
			PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
		}
	}

#if 0
	// if the down trace can trace back to the original position directly, don't step
	pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, start_o, pm->ps->clientNum, pm->tracemask);
	if ( trace.fraction == 1.0 ) {
		// use the original move
		VectorCopy (down_o, pm->ps->origin);
		VectorCopy (down_v, pm->ps->velocity);
		if ( pm->debugLevel ) {
			Com_Printf("%i:bend\n", c_pmove);
		}
	} else 
#endif
	{
		// use the step move
		float	delta;

		delta = pm->ps->origin[2] - start_o[2];
		if ( delta > 2 ) {
			if ( delta < 7 ) {
				PM_AddEvent( EV_STEP_4 );
			} else if ( delta < 11 ) {
				PM_AddEvent( EV_STEP_8 );
			} else if ( delta < 15 ) {
				PM_AddEvent( EV_STEP_12 );
			} else {
				PM_AddEvent( EV_STEP_16 );
			}
		}
		if ( pm->debugLevel ) {
			Com_Printf("%i:stepped\n", c_pmove);
		}
	}
}
Esempio n. 27
0
void SP_misc_gamemodel( void ) {
	char* model;
	char* skin;
	vec_t angle;
	vec3_t angles;

	vec_t scale;
	vec3_t vScale;

	vec3_t org;

	cg_gamemodel_t* gamemodel;

	int i;

#if 0 // ZTM: Note: Spearmint's game always drops misc_gamemodels. Also, RTCW has targetname set though I'm not sure what, if anything, it's used for.
	if ( CG_SpawnString( "targetname", "", &model ) || CG_SpawnString( "scriptname", "", &model ) || CG_SpawnString( "spawnflags", "", &model ) ) {
		// Gordon: this model may not be static, so let the server handle it
		return;
	}
#endif

	if ( cg.numMiscGameModels >= MAX_STATIC_GAMEMODELS ) {
		CG_Error( "^1MAX_STATIC_GAMEMODELS(%i) hit", MAX_STATIC_GAMEMODELS );
	}

	CG_SpawnString( "model", "", &model );

	CG_SpawnString( "skin", "", &skin );

	CG_SpawnVector( "origin", "0 0 0", org );

	if ( !CG_SpawnVector( "angles", "0 0 0", angles ) ) {
		if ( CG_SpawnFloat( "angle", "0", &angle ) ) {
			angles[YAW] = angle;
		}
	}

	if ( !CG_SpawnVector( "modelscale_vec", "1 1 1", vScale ) ) {
		if ( CG_SpawnFloat( "modelscale", "1", &scale ) ) {
			VectorSet( vScale, scale, scale, scale );
		}
	}

	gamemodel = &cgs.miscGameModels[cg.numMiscGameModels++];
	gamemodel->model = trap_R_RegisterModel( model );

	if ( *skin ) {
		CG_RegisterSkin( skin, &gamemodel->skin, qfalse );
	}

	AnglesToAxis( angles, gamemodel->axes );
	for ( i = 0; i < 3; i++ ) {
		VectorScale( gamemodel->axes[i], vScale[i], gamemodel->axes[i] );
	}
	VectorCopy( org, gamemodel->org );

	if ( gamemodel->model ) {
		vec3_t mins, maxs;

		trap_R_ModelBounds( gamemodel->model, mins, maxs, 0, 0, 0 );

		for ( i = 0; i < 3; i++ ) {
			mins[i] *= vScale[i];
			maxs[i] *= vScale[i];
		}

		gamemodel->radius = RadiusFromBounds( mins, maxs );
	} else {
		gamemodel->radius = 0;
	}
}
Esempio n. 28
0
/*
================
LaunchItem

Spawns an item and tosses it forward
================
*/
gentity_t *LaunchItem( gitem_t *item, vec3_t origin, vec3_t velocity ) {
    gentity_t	*dropped;

    dropped = G_Spawn();

    dropped->s.eType = ET_ITEM;
    dropped->s.modelindex = item - bg_itemlist;	// store item number in modelindex
    dropped->s.modelindex2 = 1; // This is non-zero is it's a dropped item

    dropped->classname = item->classname;
    dropped->item = item;
    VectorSet (dropped->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS);
    VectorSet (dropped->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS);

    // project higher...makes stuff easier to pick up while jumping..
    //dropped->r.maxs[2] += 200; Doens't work?

    dropped->r.contents = CONTENTS_TRIGGER;

    dropped->touch = Touch_Item;

    G_SetOrigin( dropped, origin );
    dropped->s.pos.trType = TR_GRAVITY;
    dropped->s.pos.trTime = level.time;
    VectorCopy( velocity, dropped->s.pos.trDelta );

    dropped->s.eFlags |= EF_BOUNCE_HALF;
#if 1
    if ((g_gametype.integer == GT_CTF || g_gametype.integer == GT_1FCTF)			&& item->giType == IT_TEAM) { // Special case for CTF flags
#else
    if (g_gametype.integer == GT_CTF && item->giType == IT_TEAM) { // Special case for CTF flags
#endif
        dropped->think = Team_DroppedFlagThink;
        dropped->nextthink = level.time + 30000;
        Team_CheckDroppedItem( dropped );
    } else { // auto-remove after 30 seconds
        dropped->think = G_FreeEntity;
        dropped->nextthink = level.time + 30000;
    }

    dropped->flags = FL_DROPPED_ITEM;

    trap_LinkEntity (dropped);

    return dropped;
}

/*
================
Drop_Item

Spawns an item and tosses it forward
================
*/
gentity_t *Drop_Item( gentity_t *ent, gitem_t *item, float angle ) {
    vec3_t	velocity;
    vec3_t	angles;

    VectorCopy( ent->s.apos.trBase, angles );
    angles[YAW] += angle;
    angles[PITCH] = 0;	// always forward

    AngleVectors( angles, velocity, NULL, NULL );
    VectorScale( velocity, 150, velocity );
    velocity[2] += 200 + crandom() * 50;

    return LaunchItem( item, ent->s.pos.trBase, velocity );
}
Esempio n. 29
0
/*QUAKED monster_medic (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight
*/
void SP_monster_medic (edict_t *self)
{
	if (deathmatch->value)
	{
		G_FreeEdict (self);
		return;
	}

	if (world->effects & FX_WORLDSPAWN_CORPSEFADE)
	{
		G_FreeEdict (self);
		return;
	}
	sound_idle1 = gi.soundindex ("medic/idle.wav");
	sound_pain1 = gi.soundindex ("medic/medpain1.wav");
	sound_pain2 = gi.soundindex ("medic/medpain2.wav");
	sound_die = gi.soundindex ("medic/meddeth1.wav");
	sound_sight = gi.soundindex ("medic/medsght1.wav");
	sound_search = gi.soundindex ("medic/medsrch1.wav");
	sound_hook_launch = gi.soundindex ("medic/medatck2.wav");
	sound_hook_hit = gi.soundindex ("medic/medatck3.wav");
	sound_hook_heal = gi.soundindex ("medic/medatck4.wav");
	sound_hook_retract = gi.soundindex ("medic/medatck5.wav");

	gi.soundindex ("medic/medatck1.wav");

	self->movetype = MOVETYPE_STEP;
	self->solid = SOLID_BBOX;

	// Lazarus: special purpose skins
	if ( self->style )
	{
		PatchMonsterModel("models/monsters/medic/tris.md2");
		self->s.skinnum = self->style * 2;
	}
	
	self->s.modelindex = gi.modelindex ("models/monsters/medic/tris.md2");
	VectorSet (self->mins, -24, -24, -24);
	VectorSet (self->maxs, 24, 24, 32);

	// Lazarus: mapper-configurable health
	if(!self->health)
		self->health = 300;
	if(!self->gib_health)
		self->gib_health = -130;
	if(!self->mass)
		self->mass = 400;

	self->pain = medic_pain;
	self->die = medic_die;

	self->monsterinfo.stand = medic_stand;
	self->monsterinfo.walk = medic_walk;
	self->monsterinfo.run = medic_run;
	self->monsterinfo.dodge = medic_dodge;
	self->monsterinfo.attack = medic_attack;
	self->monsterinfo.melee = NULL;
	self->monsterinfo.sight = medic_sight;
	self->monsterinfo.idle = medic_idle;
	self->monsterinfo.search = medic_search;
	self->monsterinfo.checkattack = medic_checkattack;

	// Knightmare- added sparks and blood type
	if (!self->blood_type)
		self->blood_type = 3; //sparks and blood

	// Lazarus
	if(self->powerarmor) {
		self->monsterinfo.power_armor_type = POWER_ARMOR_SHIELD;
		self->monsterinfo.power_armor_power = self->powerarmor;
	}
	if(!self->monsterinfo.flies)
		self->monsterinfo.flies = 0.15;

	gi.linkentity (self);
	self->monsterinfo.currentmove = &medic_move_stand;
	if(self->health < 0)
	{
		mmove_t	*deathmoves[] = {&medic_move_death,
								 NULL};
		M_SetDeath(self,(mmove_t **)&deathmoves);
	}
	self->common_name = "Medic";
	self->monsterinfo.scale = MODEL_SCALE;

	walkmonster_start (self);
}
Esempio n. 30
0
/*
=====================
CG_AddParticleToScene
=====================
*/
void CG_AddParticleToScene (cparticle_t *p, vec3_t org, float alpha)
{

	vec3_t		point;
	polyVert_t	verts[4];
	float		width;
	float		height;
	float		time, time2;
	float		ratio;
	float		invratio;
	vec3_t		color;
	polyVert_t	TRIverts[3];
	vec3_t		rright2, rup2;

	if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY
		|| p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
	{// create a front facing polygon

		if (p->type != P_WEATHER_FLURRY)
		{
			if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
			{
				if (org[2] > p->end)
				{
					p->time = cg.time;
					VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground

					p->org[2] = ( p->start + crandom () * 4 );


					if (p->type == P_BUBBLE_TURBULENT)
					{
						p->vel[0] = crandom() * 4;
						p->vel[1] = crandom() * 4;
					}

				}
			}
			else
			{
				if (org[2] < p->end)
				{
					p->time = cg.time;
					VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground

					while (p->org[2] < p->end)
					{
						p->org[2] += (p->start - p->end);
					}


					if (p->type == P_WEATHER_TURBULENT)
					{
						p->vel[0] = crandom() * 16;
						p->vel[1] = crandom() * 16;
					}

				}
			}


			// Rafael snow pvs check
			if (!p->link)
				return;

			p->alpha = 1;
		}

		// Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp
		if (Distance( cg.snap->ps.origin, org ) > 1024) {
			return;
		}
		// done.

		if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT)
		{
			VectorMA (org, -p->height, pvup, point);
			VectorMA (point, -p->width, pvright, point);
			VectorCopy (point, verts[0].xyz);
			verts[0].st[0] = 0;
			verts[0].st[1] = 0;
			verts[0].modulate[0] = 255;
			verts[0].modulate[1] = 255;
			verts[0].modulate[2] = 255;
			verts[0].modulate[3] = 255 * p->alpha;

			VectorMA (org, -p->height, pvup, point);
			VectorMA (point, p->width, pvright, point);
			VectorCopy (point, verts[1].xyz);
			verts[1].st[0] = 0;
			verts[1].st[1] = 1;
			verts[1].modulate[0] = 255;
			verts[1].modulate[1] = 255;
			verts[1].modulate[2] = 255;
			verts[1].modulate[3] = 255 * p->alpha;

			VectorMA (org, p->height, pvup, point);
			VectorMA (point, p->width, pvright, point);
			VectorCopy (point, verts[2].xyz);
			verts[2].st[0] = 1;
			verts[2].st[1] = 1;
			verts[2].modulate[0] = 255;
			verts[2].modulate[1] = 255;
			verts[2].modulate[2] = 255;
			verts[2].modulate[3] = 255 * p->alpha;

			VectorMA (org, p->height, pvup, point);
			VectorMA (point, -p->width, pvright, point);
			VectorCopy (point, verts[3].xyz);
			verts[3].st[0] = 1;
			verts[3].st[1] = 0;
			verts[3].modulate[0] = 255;
			verts[3].modulate[1] = 255;
			verts[3].modulate[2] = 255;
			verts[3].modulate[3] = 255 * p->alpha;
		}
		else
		{
			VectorMA (org, -p->height, pvup, point);
			VectorMA (point, -p->width, pvright, point);
			VectorCopy( point, TRIverts[0].xyz );
			TRIverts[0].st[0] = 1;
			TRIverts[0].st[1] = 0;
			TRIverts[0].modulate[0] = 255;
			TRIverts[0].modulate[1] = 255;
			TRIverts[0].modulate[2] = 255;
			TRIverts[0].modulate[3] = 255 * p->alpha;

			VectorMA (org, p->height, pvup, point);
			VectorMA (point, -p->width, pvright, point);
			VectorCopy (point, TRIverts[1].xyz);
			TRIverts[1].st[0] = 0;
			TRIverts[1].st[1] = 0;
			TRIverts[1].modulate[0] = 255;
			TRIverts[1].modulate[1] = 255;
			TRIverts[1].modulate[2] = 255;
			TRIverts[1].modulate[3] = 255 * p->alpha;

			VectorMA (org, p->height, pvup, point);
			VectorMA (point, p->width, pvright, point);
			VectorCopy (point, TRIverts[2].xyz);
			TRIverts[2].st[0] = 0;
			TRIverts[2].st[1] = 1;
			TRIverts[2].modulate[0] = 255;
			TRIverts[2].modulate[1] = 255;
			TRIverts[2].modulate[2] = 255;
			TRIverts[2].modulate[3] = 255 * p->alpha;
		}

	}
	else if (p->type == P_SPRITE)
	{
		vec3_t	rr, ru;
		vec3_t	rotate_ang;

		VectorSet (color, 1.0, 1.0, 0.5);
		time = cg.time - p->time;
		time2 = p->endtime - p->time;
		ratio = time / time2;

		width = p->width + ( ratio * ( p->endwidth - p->width) );
		height = p->height + ( ratio * ( p->endheight - p->height) );

		if (p->roll) {
			vectoangles( cg.refdef.viewaxis[0], rotate_ang );
			rotate_ang[ROLL] += p->roll;
			AngleVectors ( rotate_ang, NULL, rr, ru);
		}

		if (p->roll) {
			VectorMA (org, -height, ru, point);
			VectorMA (point, -width, rr, point);
		} else {
			VectorMA (org, -height, pvup, point);
			VectorMA (point, -width, pvright, point);
		}
		VectorCopy (point, verts[0].xyz);
		verts[0].st[0] = 0;
		verts[0].st[1] = 0;
		verts[0].modulate[0] = 255;
		verts[0].modulate[1] = 255;
		verts[0].modulate[2] = 255;
		verts[0].modulate[3] = 255;

		if (p->roll) {
			VectorMA (point, 2*height, ru, point);
		} else {
			VectorMA (point, 2*height, pvup, point);
		}
		VectorCopy (point, verts[1].xyz);
		verts[1].st[0] = 0;
		verts[1].st[1] = 1;
		verts[1].modulate[0] = 255;
		verts[1].modulate[1] = 255;
		verts[1].modulate[2] = 255;
		verts[1].modulate[3] = 255;

		if (p->roll) {
			VectorMA (point, 2*width, rr, point);
		} else {
			VectorMA (point, 2*width, pvright, point);
		}
		VectorCopy (point, verts[2].xyz);
		verts[2].st[0] = 1;
		verts[2].st[1] = 1;
		verts[2].modulate[0] = 255;
		verts[2].modulate[1] = 255;
		verts[2].modulate[2] = 255;
		verts[2].modulate[3] = 255;

		if (p->roll) {
			VectorMA (point, -2*height, ru, point);
		} else {
			VectorMA (point, -2*height, pvup, point);
		}
		VectorCopy (point, verts[3].xyz);
		verts[3].st[0] = 1;
		verts[3].st[1] = 0;
		verts[3].modulate[0] = 255;
		verts[3].modulate[1] = 255;
		verts[3].modulate[2] = 255;
		verts[3].modulate[3] = 255;
	}
	else if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT)
	{// create a front rotating facing polygon

		if ( p->type == P_SMOKE_IMPACT && Distance( cg.snap->ps.origin, org ) > 1024) {
			return;
		}

		if (p->color == BLOODRED)
			VectorSet (color, 0.22f, 0.0f, 0.0f);
		else if (p->color == GREY75)
		{
			float	len;
			float	greyit;
			float	val;
			len = Distance (cg.snap->ps.origin, org);
			if (!len)
				len = 1;

			val = 4096/len;
			greyit = 0.25 * val;
			if (greyit > 0.5)
				greyit = 0.5;

			VectorSet (color, greyit, greyit, greyit);
		}
		else
			VectorSet (color, 1.0, 1.0, 1.0);

		time = cg.time - p->time;
		time2 = p->endtime - p->time;
		ratio = time / time2;

		if (cg.time > p->startfade)
		{
			invratio = 1 - ( (cg.time - p->startfade) / (p->endtime - p->startfade) );

			if (p->color == EMISIVEFADE)
			{
				float fval;
				fval = (invratio * invratio);
				if (fval < 0)
					fval = 0;
				VectorSet (color, fval , fval , fval );
			}
			invratio *= p->alpha;
		}
		else
			invratio = 1 * p->alpha;

		if (invratio > 1)
			invratio = 1;

		width = p->width + ( ratio * ( p->endwidth - p->width) );
		height = p->height + ( ratio * ( p->endheight - p->height) );

		if (p->type != P_SMOKE_IMPACT)
		{
			vec3_t temp;

			vectoangles (rforward, temp);
			p->accumroll += p->roll;
			temp[ROLL] += p->accumroll * 0.1;
			AngleVectors ( temp, NULL, rright2, rup2);
		}
		else
		{
			VectorCopy (rright, rright2);
			VectorCopy (rup, rup2);
		}

		if (p->rotate)
		{
			VectorMA (org, -height, rup2, point);
			VectorMA (point, -width, rright2, point);
		}
		else
		{
			VectorMA (org, -p->height, pvup, point);
			VectorMA (point, -p->width, pvright, point);
		}
		VectorCopy (point, verts[0].xyz);
		verts[0].st[0] = 0;
		verts[0].st[1] = 0;
		verts[0].modulate[0] = 255 * color[0];
		verts[0].modulate[1] = 255 * color[1];
		verts[0].modulate[2] = 255 * color[2];
		verts[0].modulate[3] = 255 * invratio;

		if (p->rotate)
		{
			VectorMA (org, -height, rup2, point);
			VectorMA (point, width, rright2, point);
		}
		else
		{
			VectorMA (org, -p->height, pvup, point);
			VectorMA (point, p->width, pvright, point);
		}
		VectorCopy (point, verts[1].xyz);
		verts[1].st[0] = 0;
		verts[1].st[1] = 1;
		verts[1].modulate[0] = 255 * color[0];
		verts[1].modulate[1] = 255 * color[1];
		verts[1].modulate[2] = 255 * color[2];
		verts[1].modulate[3] = 255 * invratio;

		if (p->rotate)
		{
			VectorMA (org, height, rup2, point);
			VectorMA (point, width, rright2, point);
		}
		else
		{
			VectorMA (org, p->height, pvup, point);
			VectorMA (point, p->width, pvright, point);
		}
		VectorCopy (point, verts[2].xyz);
		verts[2].st[0] = 1;
		verts[2].st[1] = 1;
		verts[2].modulate[0] = 255 * color[0];
		verts[2].modulate[1] = 255 * color[1];
		verts[2].modulate[2] = 255 * color[2];
		verts[2].modulate[3] = 255 * invratio;

		if (p->rotate)
		{
			VectorMA (org, height, rup2, point);
			VectorMA (point, -width, rright2, point);
		}
		else
		{
			VectorMA (org, p->height, pvup, point);
			VectorMA (point, -p->width, pvright, point);
		}
		VectorCopy (point, verts[3].xyz);
		verts[3].st[0] = 1;
		verts[3].st[1] = 0;
		verts[3].modulate[0] = 255 * color[0];
		verts[3].modulate[1] = 255 * color[1];
		verts[3].modulate[2] = 255 * color[2];
		verts[3].modulate[3] = 255  * invratio;

	}
	else if (p->type == P_BLEED)
	{
		vec3_t	rr, ru;
		vec3_t	rotate_ang;
		float	alpha;

		alpha = p->alpha;

		if (p->roll)
		{
			vectoangles( cg.refdef.viewaxis[0], rotate_ang );
			rotate_ang[ROLL] += p->roll;
			AngleVectors ( rotate_ang, NULL, rr, ru);
		}
		else
		{
			VectorCopy (pvup, ru);
			VectorCopy (pvright, rr);
		}

		VectorMA (org, -p->height, ru, point);
		VectorMA (point, -p->width, rr, point);
		VectorCopy (point, verts[0].xyz);
		verts[0].st[0] = 0;
		verts[0].st[1] = 0;
		verts[0].modulate[0] = 111;
		verts[0].modulate[1] = 19;
		verts[0].modulate[2] = 9;
		verts[0].modulate[3] = 255 * alpha;

		VectorMA (org, -p->height, ru, point);
		VectorMA (point, p->width, rr, point);
		VectorCopy (point, verts[1].xyz);
		verts[1].st[0] = 0;
		verts[1].st[1] = 1;
		verts[1].modulate[0] = 111;
		verts[1].modulate[1] = 19;
		verts[1].modulate[2] = 9;
		verts[1].modulate[3] = 255 * alpha;

		VectorMA (org, p->height, ru, point);
		VectorMA (point, p->width, rr, point);
		VectorCopy (point, verts[2].xyz);
		verts[2].st[0] = 1;
		verts[2].st[1] = 1;
		verts[2].modulate[0] = 111;
		verts[2].modulate[1] = 19;
		verts[2].modulate[2] = 9;
		verts[2].modulate[3] = 255 * alpha;

		VectorMA (org, p->height, ru, point);
		VectorMA (point, -p->width, rr, point);
		VectorCopy (point, verts[3].xyz);
		verts[3].st[0] = 1;
		verts[3].st[1] = 0;
		verts[3].modulate[0] = 111;
		verts[3].modulate[1] = 19;
		verts[3].modulate[2] = 9;
		verts[3].modulate[3] = 255 * alpha;

	}
	else if (p->type == P_FLAT_SCALEUP)
	{
		float width, height;
		float sinR, cosR;

		if (p->color == BLOODRED)
			VectorSet (color, 1, 1, 1);
		else
			VectorSet (color, 0.5, 0.5, 0.5);

		time = cg.time - p->time;
		time2 = p->endtime - p->time;
		ratio = time / time2;

		width = p->width + ( ratio * ( p->endwidth - p->width) );
		height = p->height + ( ratio * ( p->endheight - p->height) );

		if (width > p->endwidth)
			width = p->endwidth;

		if (height > p->endheight)
			height = p->endheight;

		sinR = height * sin(DEG2RAD(p->roll)) * sqrt(2);
		cosR = width * cos(DEG2RAD(p->roll)) * sqrt(2);

		VectorCopy (org, verts[0].xyz);
		verts[0].xyz[0] -= sinR;
		verts[0].xyz[1] -= cosR;
		verts[0].st[0] = 0;
		verts[0].st[1] = 0;
		verts[0].modulate[0] = 255 * color[0];
		verts[0].modulate[1] = 255 * color[1];
		verts[0].modulate[2] = 255 * color[2];
		verts[0].modulate[3] = 255;

		VectorCopy (org, verts[1].xyz);
		verts[1].xyz[0] -= cosR;
		verts[1].xyz[1] += sinR;
		verts[1].st[0] = 0;
		verts[1].st[1] = 1;
		verts[1].modulate[0] = 255 * color[0];
		verts[1].modulate[1] = 255 * color[1];
		verts[1].modulate[2] = 255 * color[2];
		verts[1].modulate[3] = 255;

		VectorCopy (org, verts[2].xyz);
		verts[2].xyz[0] += sinR;
		verts[2].xyz[1] += cosR;
		verts[2].st[0] = 1;
		verts[2].st[1] = 1;
		verts[2].modulate[0] = 255 * color[0];
		verts[2].modulate[1] = 255 * color[1];
		verts[2].modulate[2] = 255 * color[2];
		verts[2].modulate[3] = 255;

		VectorCopy (org, verts[3].xyz);
		verts[3].xyz[0] += cosR;
		verts[3].xyz[1] -= sinR;
		verts[3].st[0] = 1;
		verts[3].st[1] = 0;
		verts[3].modulate[0] = 255 * color[0];
		verts[3].modulate[1] = 255 * color[1];
		verts[3].modulate[2] = 255 * color[2];
		verts[3].modulate[3] = 255;
	}
	else if (p->type == P_FLAT)
	{

		VectorCopy (org, verts[0].xyz);
		verts[0].xyz[0] -= p->height;
		verts[0].xyz[1] -= p->width;
		verts[0].st[0] = 0;
		verts[0].st[1] = 0;
		verts[0].modulate[0] = 255;
		verts[0].modulate[1] = 255;
		verts[0].modulate[2] = 255;
		verts[0].modulate[3] = 255;

		VectorCopy (org, verts[1].xyz);
		verts[1].xyz[0] -= p->height;
		verts[1].xyz[1] += p->width;
		verts[1].st[0] = 0;
		verts[1].st[1] = 1;
		verts[1].modulate[0] = 255;
		verts[1].modulate[1] = 255;
		verts[1].modulate[2] = 255;
		verts[1].modulate[3] = 255;

		VectorCopy (org, verts[2].xyz);
		verts[2].xyz[0] += p->height;
		verts[2].xyz[1] += p->width;
		verts[2].st[0] = 1;
		verts[2].st[1] = 1;
		verts[2].modulate[0] = 255;
		verts[2].modulate[1] = 255;
		verts[2].modulate[2] = 255;
		verts[2].modulate[3] = 255;

		VectorCopy (org, verts[3].xyz);
		verts[3].xyz[0] += p->height;
		verts[3].xyz[1] -= p->width;
		verts[3].st[0] = 1;
		verts[3].st[1] = 0;
		verts[3].modulate[0] = 255;
		verts[3].modulate[1] = 255;
		verts[3].modulate[2] = 255;
		verts[3].modulate[3] = 255;

	}
	// Ridah
	else if (p->type == P_ANIM) {
		vec3_t	rr, ru;
		vec3_t	rotate_ang;
		int i, j;

		time = cg.time - p->time;
		time2 = p->endtime - p->time;
		ratio = time / time2;
		if (ratio >= 1.0f) {
			ratio = 0.9999f;
		}

		width = p->width + ( ratio * ( p->endwidth - p->width) );
		height = p->height + ( ratio * ( p->endheight - p->height) );

		// if we are "inside" this sprite, don't draw
		if (Distance( cg.snap->ps.origin, org ) < width/1.5) {
			return;
		}

		i = p->shaderAnim;
		j = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]);
		p->pshader = shaderAnims[i][j];

		if (p->roll) {
			vectoangles( cg.refdef.viewaxis[0], rotate_ang );
			rotate_ang[ROLL] += p->roll;
			AngleVectors ( rotate_ang, NULL, rr, ru);
		}

		if (p->roll) {
			VectorMA (org, -height, ru, point);
			VectorMA (point, -width, rr, point);
		} else {
			VectorMA (org, -height, pvup, point);
			VectorMA (point, -width, pvright, point);
		}
		VectorCopy (point, verts[0].xyz);
		verts[0].st[0] = 0;
		verts[0].st[1] = 0;
		verts[0].modulate[0] = 255;
		verts[0].modulate[1] = 255;
		verts[0].modulate[2] = 255;
		verts[0].modulate[3] = 255;

		if (p->roll) {
			VectorMA (point, 2*height, ru, point);
		} else {
			VectorMA (point, 2*height, pvup, point);
		}
		VectorCopy (point, verts[1].xyz);
		verts[1].st[0] = 0;
		verts[1].st[1] = 1;
		verts[1].modulate[0] = 255;
		verts[1].modulate[1] = 255;
		verts[1].modulate[2] = 255;
		verts[1].modulate[3] = 255;

		if (p->roll) {
			VectorMA (point, 2*width, rr, point);
		} else {
			VectorMA (point, 2*width, pvright, point);
		}
		VectorCopy (point, verts[2].xyz);
		verts[2].st[0] = 1;
		verts[2].st[1] = 1;
		verts[2].modulate[0] = 255;
		verts[2].modulate[1] = 255;
		verts[2].modulate[2] = 255;
		verts[2].modulate[3] = 255;

		if (p->roll) {
			VectorMA (point, -2*height, ru, point);
		} else {
			VectorMA (point, -2*height, pvup, point);
		}
		VectorCopy (point, verts[3].xyz);
		verts[3].st[0] = 1;
		verts[3].st[1] = 0;
		verts[3].modulate[0] = 255;
		verts[3].modulate[1] = 255;
		verts[3].modulate[2] = 255;
		verts[3].modulate[3] = 255;
	}
	// done.

	if (!p->pshader) {
// (SA) temp commented out for DM
//		CG_Printf ("CG_AddParticleToScene type %d p->pshader == ZERO\n", p->type);
		return;
	}

	if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY)
		trap_R_AddPolyToScene( p->pshader, 3, TRIverts );
	else
		trap_R_AddPolyToScene( p->pshader, 4, verts );

}