void CG_Dash( entity_state_t *state ) { lentity_t *le; vec3_t pos, dvect, angle = { 0, 0, 0 }; if( !(cg_cartoonEffects->integer & 4) ) return; // KoFFiE: Calculate angle based on relative position of the previous origin state of the player entity VectorSubtract( state->origin, cg_entities[state->number].prev.origin, dvect ); // ugly inline define -> Ignore when difference between 2 positions was less than this value. #define IGNORE_DASH 6.0 if( ( dvect[0] > -IGNORE_DASH ) && ( dvect[0] < IGNORE_DASH ) && ( dvect[1] > -IGNORE_DASH ) && ( dvect[1] < IGNORE_DASH ) ) return; VecToAngles( dvect, angle ); VectorCopy( state->origin, pos ); angle[1] += 270; // Adjust angle pos[2] -= 24; // Adjust the position to ground height if( CG_PointContents( pos ) & MASK_WATER ) return; // no smoke under water :) le = CG_AllocModel( LE_DASH_SCALE, pos, angle, 7, //5 1.0, 1.0, 1.0, 1.0, 0, 0, 0, 0, CG_MediaModel( cgs.media.modDash ), NULL ); le->ent.scale = 0.01f; le->ent.axis[2][2] *= 2.0f; }
/* * CG_BoltExplosionMode */ void CG_BoltExplosionMode( const vec3_t pos, const vec3_t dir, int fire_mode, int surfFlags ) { lentity_t *le; vec3_t angles; if( !CG_SpawnDecal( pos, dir, random()*360, 12, 1, 1, 1, 1, 10, 1, true, CG_MediaShader( cgs.media.shaderElectroboltMark ) ) ) { if( surfFlags & (SURF_SKY|SURF_NOMARKS|SURF_NOIMPACT) ) { return; } } VecToAngles( dir, angles ); le = CG_AllocModel( LE_INVERSESCALE_ALPHA_FADE, pos, angles, 6, // 6 is time 1, 1, 1, 1, //full white no inducted alpha 250, 0.75, 0.75, 0.75, //white dlight CG_MediaModel( cgs.media.modElectroBoltWallHit ), NULL ); le->ent.rotation = rand() % 360; le->ent.scale = ( fire_mode == FIRE_MODE_STRONG ) ? 1.5f : 1.0f; // add white energy particles on the impact CG_ImpactPuffParticles( pos, dir, 15, 0.75f, 1, 1, 1, 1, NULL ); trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxElectroboltHit ), pos, CHAN_AUTO, cg_volume_effects->value, ATTN_STATIC ); }
static asvec3_t objectVec3_VecToAngles( asvec3_t *self ) { asvec3_t angles; VecToAngles( self->v, angles.v ); return angles; }
/* * CG_PlasmaExplosion */ void CG_PlasmaExplosion( vec3_t pos, vec3_t dir, int fire_mode, float radius ) { lentity_t *le; vec3_t angles; float model_radius = PLASMA_EXPLOSION_MODEL_RADIUS; VecToAngles( dir, angles ); if( fire_mode == FIRE_MODE_STRONG ) { le = CG_AllocModel( LE_ALPHA_FADE, pos, angles, 4, 1, 1, 1, 1, 150, 0, 0.75, 0, CG_MediaModel( cgs.media.modPlasmaExplosion ), NULL ); le->ent.scale = radius/model_radius; } else { le = CG_AllocModel( LE_ALPHA_FADE, pos, angles, 4, 1, 1, 1, 1, 80, 0, 0.75, 0, CG_MediaModel( cgs.media.modPlasmaExplosion ), NULL ); le->ent.scale = radius/model_radius; } le->ent.rotation = rand() % 360; CG_SpawnDecal( pos, dir, 90, 16, 1, 1, 1, 1, 4, 1, qtrue, CG_MediaShader( cgs.media.shaderPlasmaMark ) ); }
/* * CG_InstaExplosionMode */ void CG_InstaExplosionMode( vec3_t pos, vec3_t dir, int fire_mode ) { lentity_t *le; vec3_t angles; VecToAngles( dir, angles ); le = CG_AllocModel( LE_ALPHA_FADE, pos, angles, 6, // 6 is time 1, 1, 1, 1, //full white no inducted alpha 250, 0.65, 0.65, 0.65, //white dlight CG_MediaModel( cgs.media.modInstagunWallHit ), NULL ); le->ent.rotation = rand() % 360; if( fire_mode == FIRE_MODE_STRONG ) { le->ent.scale = 1.5f; // add white energy particles on the impact CG_ImpactPuffParticles( pos, dir, 12, 1.25f, 1, 1, 1, 1, CG_MediaShader( cgs.media.shaderAdditiveParticleShine ) ); } else { le->ent.scale = 1.0f; CG_ImpactPuffParticles( pos, dir, 12, 1.0f, 1, 1, 1, 1, NULL ); } CG_SpawnDecal( pos, dir, random()*360, 8, 1, 1, 1, 1, 10, 1, qtrue, CG_MediaShader( cgs.media.shaderInstagunMark ) ); }
void GS_TraceCurveLaserBeam( trace_t *trace, vec3_t origin, vec3_t angles, vec3_t blendPoint, int ignore, int timeDelta, void ( *impact )( trace_t *tr, vec3_t dir ) ) { float frac, subdivisions = CURVELASERBEAM_SUBDIVISIONS; float range = (float)GS_GetWeaponDef( WEAP_LASERGUN )->firedef_weak.timeout; vec3_t from, dir, end; int passthrough = ignore; int i, j; vec3_t tmpangles, blendAngles; assert( trace ); VectorCopy( origin, from ); VectorSubtract( blendPoint, origin, dir ); VecToAngles( dir, blendAngles ); for( i = 1; i <= (int)subdivisions; i++ ) { frac = ( ( range/subdivisions )*(float)i ) / (float)range; for( j = 0; j < 3; j++ ) tmpangles[j] = LerpAngle( angles[j], blendAngles[j], frac ); AngleVectors( tmpangles, dir, NULL, NULL ); VectorMA( origin, range * frac, dir, end ); GS_TraceLaserBeam( trace, from, tmpangles, DistanceFast( from, end ), passthrough, timeDelta, impact ); if( trace->fraction != 1.0f ) break; passthrough = trace->ent; VectorCopy( end, from ); } }
/* * CG_GunBladeBlastImpact */ void CG_GunBladeBlastImpact( vec3_t pos, vec3_t dir, float radius ) { lentity_t *le; lentity_t *le_explo; vec3_t angles; float model_radius = GUNBLADEBLAST_EXPLOSION_MODEL_RADIUS; VecToAngles( dir, angles ); le = CG_AllocModel( LE_ALPHA_FADE, pos, angles, 2, //3 frames 1, 1, 1, 1, //full white no inducted alpha 0, 0, 0, 0, //dlight CG_MediaModel( cgs.media.modBladeWallHit ), //"models/weapon_hits/gunblade/hit_blast.md3" NULL ); le->ent.rotation = rand() % 360; le->ent.scale = 1.0f; // this is the small bullet impact le_explo = CG_AllocModel( LE_ALPHA_FADE, pos, angles, 2 + ( radius/16.1f ), 1, 1, 1, 1, //full white no inducted alpha 0, 0, 0, 0, //dlight CG_MediaModel( cgs.media.modBladeWallExplo ), NULL ); le_explo->ent.rotation = rand() % 360; le_explo->ent.scale = radius/model_radius; CG_SpawnDecal( pos, dir, random()*360, 3+( radius*0.5f ), 1, 1, 1, 1, 10, 1, qfalse, CG_MediaShader( cgs.media.shaderExplosionMark ) ); }
/** * @note Think function */ static void LET_Projectile (le_t* le) { if (cl.time >= le->endTime) { vec3_t impact; VectorCopy(le->origin, impact); CL_ParticleFree(le->ptl); /* don't run the think function again */ le->inuse = false; if (Q_strvalid(le->ref1)) { VectorCopy(le->ptl->s, impact); le->ptl = CL_ParticleSpawn(le->ref1, 0, impact, bytedirs[le->angle]); VecToAngles(bytedirs[le->state], le->ptl->angles); } if (Q_strvalid(le->ref2)) { S_LoadAndPlaySample(le->ref2, impact, le->fd->impactAttenuation, SND_VOLUME_WEAPONS); } if (le->ref3) { /* Spawn blood particles (if defined) if actor(-body) was hit. Even if actor is dead. */ /** @todo Special particles for stun attack (mind you that there is * electrical and gas/chemical stunning)? */ if (le->fd->obj->dmgtype != csi.damStunGas) LE_ActorBodyHit(le->ref3, impact, le->angle); CL_ActorPlaySound(le->ref3, SND_HURT); } } else if (CL_OutsideMap(le->ptl->s, UNIT_SIZE * 10)) { le->endTime = cl.time; CL_ParticleFree(le->ptl); /* don't run the think function again */ le->inuse = false; } }
/* * CG_DemoCam_LookAt */ bool CG_DemoCam_LookAt( int trackEnt, vec3_t vieworg, vec3_t viewangles ) { centity_t *cent; vec3_t dir; vec3_t origin; struct cmodel_s *cmodel; int i; if( trackEnt < 1 || trackEnt >= MAX_EDICTS ) { return false; } cent = &cg_entities[trackEnt]; if( cent->serverFrame != cg.frame.serverFrame ) { return false; } // seems to be valid. Find the angles to look at this entity VectorLerp( cent->prev.origin, cg.lerpfrac, cent->current.origin, origin ); // if having a bounding box, look to its center if( ( cmodel = CG_CModelForEntity( trackEnt ) ) != NULL ) { vec3_t mins, maxs; trap_CM_InlineModelBounds( cmodel, mins, maxs ); for( i = 0; i < 3; i++ ) origin[i] += ( mins[i] + maxs[i] ); } VectorSubtract( origin, vieworg, dir ); VectorNormalize( dir ); VecToAngles( dir, viewangles ); return true; }
Vec3 Ai::GetNewViewAngles( const vec3_t oldAngles, const Vec3 &desiredDirection, unsigned frameTime, float angularSpeedMultiplier ) const { // Based on turret script code // For those trying to learn working with angles // Vec3.x is the PITCH angle (up and down rotation) // Vec3.y is the YAW angle (left and right rotation) // Vec3.z is the ROLL angle (left and right inclination) vec3_t newAngles, desiredAngles; VecToAngles( desiredDirection.Data(), desiredAngles ); // Normalize180 all angles so they can be compared for( int i = 0; i < 3; ++i ) { newAngles[i] = AngleNormalize180( oldAngles[i] ); desiredAngles[i] = AngleNormalize180( desiredAngles[i] ); } // Rotate the entity angles to the desired angles if( !VectorCompare( newAngles, desiredAngles ) ) { for( auto angleNum: { YAW, PITCH } ) { newAngles[angleNum] = GetChangedAngle( newAngles[angleNum], desiredAngles[angleNum], frameTime, angularSpeedMultiplier, angleNum ); } } return Vec3( newAngles ); }
/* * G_LocalSpread */ static void G_LocalSpread( vec3_t angles, int spread, int seed ) { float r, u; vec3_t axis[3], dir; double alpha; double s; if( spread <= 0 ) return; seed &= 255; alpha = M_PI * Q_crandom( &seed ); // [-PI ..+PI] s = fabs( Q_crandom( &seed ) ); // [0..1] r = s * cos( alpha ) * spread; u = s * sin( alpha ) * spread; AngleVectors( angles, axis[0], axis[1], axis[2] ); VectorMA( vec3_origin, 8192, axis[0], dir ); VectorMA( dir, r, axis[1], dir ); VectorMA( dir, u, axis[2], dir ); VecToAngles( dir, angles ); }
/* * CG_BladeImpact */ void CG_BladeImpact( const vec3_t pos, const vec3_t dir ) { lentity_t *le; vec3_t angles; vec3_t end; vec3_t local_pos, local_dir; trace_t trace; //find what are we hitting VectorCopy( pos, local_pos ); VectorNormalize2( dir, local_dir ); VectorMA( pos, -1.0, local_dir, end ); CG_Trace( &trace, local_pos, vec3_origin, vec3_origin, end, cg.view.POVent, MASK_SHOT ); if( trace.fraction == 1.0 ) return; VecToAngles( local_dir, angles ); if( trace.surfFlags & SURF_FLESH || ( trace.ent > 0 && cg_entities[trace.ent].current.type == ET_PLAYER ) || ( trace.ent > 0 && cg_entities[trace.ent].current.type == ET_CORPSE ) ) { le = CG_AllocModel( LE_ALPHA_FADE, pos, angles, 3, //3 frames for weak 1, 1, 1, 1, //full white no inducted alpha 0, 0, 0, 0, //dlight CG_MediaModel( cgs.media.modBladeWallHit ), NULL ); le->ent.rotation = rand() % 360; le->ent.scale = 1.0f; trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxBladeFleshHit[(int)( random()*3 )] ), pos, CHAN_AUTO, cg_volume_effects->value, ATTN_NORM ); } else if( trace.surfFlags & SURF_DUST ) { // throw particles on dust CG_ParticleEffect( trace.endpos, trace.plane.normal, 0.30f, 0.30f, 0.25f, 30 ); //fixme? would need a dust sound trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxBladeWallHit[(int)( random()*2 )] ), pos, CHAN_AUTO, cg_volume_effects->value, ATTN_NORM ); } else { le = CG_AllocModel( LE_ALPHA_FADE, pos, angles, 3, //3 frames for weak 1, 1, 1, 1, //full white no inducted alpha 0, 0, 0, 0, //dlight CG_MediaModel( cgs.media.modBladeWallHit ), NULL ); le->ent.rotation = rand() % 360; le->ent.scale = 1.0f; CG_ParticleEffect( trace.endpos, trace.plane.normal, 0.30f, 0.30f, 0.25f, 15 ); trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxBladeWallHit[(int)( random()*2 )] ), pos, CHAN_AUTO, cg_volume_effects->value, ATTN_NORM ); if( !( trace.surfFlags & SURF_NOMARKS ) ) CG_SpawnDecal( pos, dir, random()*10, 8, 1, 1, 1, 1, 10, 1, false, CG_MediaShader( cgs.media.shaderBladeMark ) ); } }
/* * SelectSpawnPoint * * Chooses a player start, deathmatch start, etc */ void SelectSpawnPoint( edict_t *ent, edict_t **spawnpoint, vec3_t origin, vec3_t angles ) { edict_t *spot = NULL; if( GS_MatchState() >= MATCH_STATE_POSTMATCH ) { spot = G_SelectIntermissionSpawnPoint(); } else { if( game.asEngine != NULL ) spot = GT_asCallSelectSpawnPoint( ent ); if( !spot ) spot = SelectDeathmatchSpawnPoint( ent ); } // find a single player start spot if( !spot ) { spot = G_Find( spot, FOFS( classname ), "info_player_start" ); if( !spot ) { spot = G_Find( spot, FOFS( classname ), "team_CTF_alphaspawn" ); if( !spot ) spot = G_Find( spot, FOFS( classname ), "team_CTF_betaspawn" ); if( !spot ) spot = world; } } *spawnpoint = spot; VectorCopy( spot->s.origin, origin ); VectorCopy( spot->s.angles, angles ); if( !Q_stricmp( spot->classname, "info_player_intermission" ) ) { // if it has a target, look towards it if( spot->target ) { vec3_t dir; edict_t *target; target = G_PickTarget( spot->target ); if( target ) { VectorSubtract( target->s.origin, origin, dir ); VecToAngles( dir, angles ); } } } // SPAWN TELEFRAGGING PROTECTION. if( ent->r.solid == SOLID_YES && ( level.gametype.spawnpointRadius > ( playerbox_stand_maxs[0] - playerbox_stand_mins[0] ) ) ) G_OffsetSpawnPoint( origin, playerbox_stand_mins, playerbox_stand_maxs, level.gametype.spawnpointRadius, !( spot->spawnflags & 1 ) ? true : false ); }
/* * W_Fire_LinearProjectile - Spawn a generic linear projectile without a model, touch func, sound nor mod */ static edict_t *W_Fire_LinearProjectile( edict_t *self, vec3_t start, vec3_t dir, int speed, float damage, int minKnockback, int maxKnockback, int stun, int minDamage, int radius, int timeout, int timeDelta ) { edict_t *projectile; vec3_t angles; projectile = G_Spawn(); VectorCopy( start, projectile->s.origin ); VectorCopy( start, projectile->olds.origin ); VecToAngles( dir, angles ); VectorCopy( angles, projectile->s.angles ); VectorScale( dir, speed, projectile->velocity ); projectile->movetype = MOVETYPE_LINEARPROJECTILE; projectile->r.solid = SOLID_YES; projectile->r.clipmask = ( !GS_RaceGametype() ) ? MASK_SHOT : MASK_SOLID; projectile->r.svflags = SVF_PROJECTILE; // enable me when drawing exception is added to cgame VectorClear( projectile->r.mins ); VectorClear( projectile->r.maxs ); projectile->s.modelindex = 0; projectile->r.owner = self; projectile->s.ownerNum = ENTNUM( self ); projectile->touch = W_Touch_Projectile; //generic one. Should be replaced after calling this func projectile->nextThink = level.time + timeout; projectile->think = G_FreeEdict; projectile->classname = NULL; // should be replaced after calling this func. projectile->style = 0; projectile->s.sound = 0; projectile->timeStamp = level.time; projectile->timeDelta = timeDelta; projectile->projectileInfo.minDamage = min( minDamage, damage ); projectile->projectileInfo.maxDamage = damage; projectile->projectileInfo.minKnockback = min( minKnockback, maxKnockback ); projectile->projectileInfo.maxKnockback = maxKnockback; projectile->projectileInfo.stun = stun; projectile->projectileInfo.radius = radius; GClip_LinkEntity( projectile ); // update some data required for the transmission projectile->s.linearMovement = true; VectorCopy( projectile->s.origin, projectile->s.linearMovementBegin ); VectorCopy( projectile->velocity, projectile->s.linearMovementVelocity ); projectile->s.linearMovementTimeStamp = game.serverTime; projectile->s.team = self->s.team; projectile->s.modelindex2 = ( abs( timeDelta ) > 255 ) ? 255 : (unsigned int)abs( timeDelta ); return projectile; }
/* * W_Fire_TossProjectile - Spawn a generic projectile without a model, touch func, sound nor mod */ static edict_t *W_Fire_TossProjectile( edict_t *self, vec3_t start, vec3_t dir, int speed, float damage, int minKnockback, int maxKnockback, int stun, int minDamage, int radius, int timeout, int timeDelta ) { edict_t *projectile; vec3_t angles; projectile = G_Spawn(); VectorCopy( start, projectile->s.origin ); VectorCopy( start, projectile->olds.origin ); VecToAngles( dir, angles ); VectorCopy( angles, projectile->s.angles ); VectorScale( dir, speed, projectile->velocity ); projectile->movetype = MOVETYPE_BOUNCEGRENADE; // make missile fly through players in race if( GS_RaceGametype() ) { projectile->r.clipmask = MASK_SOLID; } else { projectile->r.clipmask = MASK_SHOT; } projectile->r.solid = SOLID_YES; projectile->r.svflags = SVF_PROJECTILE; VectorClear( projectile->r.mins ); VectorClear( projectile->r.maxs ); //projectile->s.modelindex = trap_ModelIndex ("models/objects/projectile/plasmagun/proj_plasmagun2.md3"); projectile->s.modelindex = 0; projectile->r.owner = self; projectile->touch = W_Touch_Projectile; //generic one. Should be replaced after calling this func projectile->nextThink = level.time + timeout; projectile->think = G_FreeEdict; projectile->classname = NULL; // should be replaced after calling this func. projectile->style = 0; projectile->s.sound = 0; projectile->timeStamp = level.time; projectile->timeDelta = timeDelta; projectile->s.team = self->s.team; projectile->projectileInfo.minDamage = min( minDamage, damage ); projectile->projectileInfo.maxDamage = damage; projectile->projectileInfo.minKnockback = min( minKnockback, maxKnockback ); projectile->projectileInfo.maxKnockback = maxKnockback; projectile->projectileInfo.stun = stun; projectile->projectileInfo.radius = radius; GClip_LinkEntity( projectile ); return projectile; }
void SP_misc_particles_finish( edict_t *ent ) { // if it has a target, look towards it if( ent->target ) { vec3_t dir; edict_t *target = G_PickTarget( ent->target ); if( target ) { VectorSubtract( target->s.origin, ent->s.origin, dir ); VecToAngles( dir, ent->s.angles ); } } ent->think = NULL; }
/* =============== CL_TrackerTrail =============== */ void CL_TrackerTrail (const vec3_t start, const vec3_t end, int particleColor) { vec3_t move, vec; vec3_t forward,right,up,angle_dir; float len, dist; cparticle_t *p; int dec = 3; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); VectorCopy(vec, forward); VecToAngles(forward, angle_dir); AngleVectors(angle_dir, forward, right, up); VectorScale (vec, dec, vec); // FIXME: this is a really silly way to have a loop while (len > 0) { len -= dec; if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; VectorClear (p->accel); p->time = cl.time; p->alpha = 1.0f; p->alphavel = -2.0f; p->color = particleColor; dist = 8 * (float)cos(DotProduct(move, forward)); VectorMA(move, dist, up, p->org); p->vel[0] = p->vel[1] = 0; p->vel[2] = 5; VectorAdd (move, vec, move); } }
void CLQ2_TrackerTrail( vec3_t start, vec3_t end, int particleColour ) { vec3_t move; VectorCopy( start, move ); vec3_t vec; VectorSubtract( end, start, vec ); float len = VectorNormalize( vec ); vec3_t forward; VectorCopy( vec, forward ); vec3_t angle_dir; VecToAngles( forward, angle_dir ); vec3_t right, up; AngleVectors( angle_dir, forward, right, up ); int dec = 3; VectorScale( vec, 3, vec ); // FIXME: this is a really silly way to have a loop while ( len > 0 ) { len -= dec; cparticle_t* p = CL_AllocParticle(); if ( !p ) { return; } p->type = pt_q2static; VectorClear( p->accel ); p->alpha = 1.0; p->alphavel = -2.0; p->color = particleColour; float dist = DotProduct( move, forward ); VectorMA( move, 8 * cos( dist ), up, p->org ); for ( int j = 0; j < 3; j++ ) { p->vel[ j ] = 0; p->accel[ j ] = 0; } p->vel[ 2 ] = 5; VectorAdd( move, vec, move ); } }
/* * CG_FireBullet */ static void CG_FireBullet( int self, vec3_t start, vec3_t forward, int count, int spread, int seed, void ( *impact )(trace_t *tr /*, int impactnum*/) ) { int i; trace_t tr; vec3_t dir, axis[3]; qboolean takedamage; // calculate normal vectors VecToAngles( forward, dir ); AngleVectors( dir, axis[0], axis[1], axis[2] ); for( i = 0; i < count; i++ ) { CG_FireLead( self, start, axis, spread, spread, &seed, &tr ); takedamage = tr.ent && ( cg_entities[tr.ent].current.effects & EF_TAKEDAMAGE ); if( tr.fraction < 1.0f && !takedamage && !( tr.surfFlags & SURF_NOIMPACT ) ) impact( &tr ); } }
/* * CG_LasertGunImpact */ void CG_LaserGunImpact( const vec3_t pos, const vec3_t dir, float radius, const vec3_t laser_dir, const vec4_t color ) { entity_t ent; vec3_t ndir; vec3_t angles; memset( &ent, 0, sizeof( ent ) ); VectorCopy( pos, ent.origin ); VectorMA( ent.origin, 2, dir, ent.origin ); ent.renderfx = RF_FULLBRIGHT|RF_NOSHADOW; ent.scale = 1.45f; Vector4Set( ent.shaderRGBA, color[0] * 255, color[1] * 255, color[2] * 255, color[3] * 255 ); ent.model = CG_MediaModel( cgs.media.modLasergunWallExplo ); VectorNegate( laser_dir, ndir ); VecToAngles( ndir, angles ); angles[2] = anglemod( -360.0f * cg.time * 0.001f ); AnglesToAxis( angles, ent.axis ); trap_R_AddEntityToScene( &ent ); }
/* * CG_InstaExplosionMode */ void CG_InstaExplosionMode( const vec3_t pos, const vec3_t dir, int fire_mode, int surfFlags, int owner ) { int team = -1; vec4_t tcolor = { 0.65f, 0.0f, 0.26f, 1.0f }; lentity_t *le; vec3_t angles; if( cg_teamColoredInstaBeams->integer && owner && ( owner < gs.maxclients + 1 ) ) team = cg_entities[owner].current.team; if( ( team == TEAM_ALPHA ) || ( team == TEAM_BETA ) ) { CG_TeamColor( team, tcolor ); tcolor[0] *= 0.65f; tcolor[1] *= 0.65f; tcolor[2] *= 0.65f; } if( !CG_SpawnDecal( pos, dir, random()*360, 12, tcolor[0], tcolor[1], tcolor[2], 1.0f, 10, 1, true, CG_MediaShader( cgs.media.shaderInstagunMark ) ) ) { if( surfFlags & (SURF_SKY|SURF_NOMARKS|SURF_NOIMPACT) ) { return; } } VecToAngles( dir, angles ); le = CG_AllocModel( LE_ALPHA_FADE, pos, angles, 6, // 6 is time tcolor[0], tcolor[1], tcolor[2], 1, 250, 0.65, 0.65, 0.65, //white dlight CG_MediaModel( cgs.media.modInstagunWallHit ), NULL ); le->ent.rotation = rand() % 360; le->ent.scale = ( fire_mode == FIRE_MODE_STRONG ) ? 1.5f : 1.0f; // add white energy particles on the impact CG_ImpactPuffParticles( pos, dir, 15, 0.75f, 1, 1, 1, 1, NULL ); trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxElectroboltHit ), pos, CHAN_AUTO, cg_volume_effects->value, ATTN_STATIC ); }
void CG_AddShadeBoxes( void ) { // ok, what we have to do here is finding the light direction of each of the shadeboxes origins int i; cgshadebox_t *sb; vec3_t lightdir, end, sborigin; trace_t trace; if( !cg_shadows->integer ) return; for( i = 0, sb = cg_shadeBoxes; i < cg_numShadeBoxes; i++, sb++ ) { VectorClear( lightdir ); trap_R_LightForOrigin( sb->origin, lightdir, NULL, NULL, RadiusFromBounds( sb->mins, sb->maxs ) ); // move the point we will project close to the bottom of the bbox (so shadow doesn't dance much to the sides) VectorSet( sborigin, sb->origin[0], sb->origin[1], sb->origin[2] + sb->mins[2] + 8 ); VectorMA( sborigin, -SHADOW_PROJECTION_DISTANCE, lightdir, end ); //CG_DrawTestLine( sb->origin, end ); // lightdir testline CG_Trace( &trace, sborigin, vec3_origin, vec3_origin, end, sb->entNum, MASK_OPAQUE ); if( trace.fraction < 1.0f ) { // we have a shadow float blobradius; float alpha, maxalpha = 0.95f; vec3_t shangles; VecToAngles( lightdir, shangles ); blobradius = SHADOW_MIN_SIZE + trace.fraction * ( SHADOW_MAX_SIZE-SHADOW_MIN_SIZE ); alpha = ( 1.0f - trace.fraction ) * maxalpha; CG_AddBlobShadow( trace.endpos, trace.plane.normal, shangles[YAW], blobradius, 1, 1, 1, alpha, sb ); } } // clean up the polygons list from old frames cg_numShadeBoxes = 0; }
/* * CG_GenericExplosion */ void CG_GenericExplosion( vec3_t pos, vec3_t dir, int fire_mode, float radius ) { lentity_t *le; vec3_t angles; vec3_t decaldir; vec3_t origin, vec; float expvelocity = 8.0f; VectorCopy( dir, decaldir ); VecToAngles( dir, angles ); //if( CG_PointContents( pos ) & MASK_WATER ) //jalfixme: (shouldn't we do the water sound variation?) if( fire_mode == FIRE_MODE_STRONG ) CG_SpawnDecal( pos, decaldir, random()*360, radius * 0.5, 1, 1, 1, 1, 10, 1, qfalse, CG_MediaShader( cgs.media.shaderExplosionMark ) ); else CG_SpawnDecal( pos, decaldir, random()*360, radius * 0.25, 1, 1, 1, 1, 10, 1, qfalse, CG_MediaShader( cgs.media.shaderExplosionMark ) ); // animmap shader of the explosion VectorMA( pos, radius*0.15f, dir, origin ); le = CG_AllocSprite( LE_ALPHA_FADE, origin, radius * 0.5f, 8, 1, 1, 1, 1, radius*4, 0.75f, 0.533f, 0, // yellow dlight CG_MediaShader( cgs.media.shaderRocketExplosion ) ); VectorSet( vec, crandom()*expvelocity, crandom()*expvelocity, crandom()*expvelocity ); VectorScale( dir, expvelocity, le->velocity ); VectorAdd( le->velocity, vec, le->velocity ); le->ent.rotation = rand() % 360; // use the rocket explosion sounds if( fire_mode == FIRE_MODE_STRONG ) trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxRocketLauncherStrongHit ), pos, CHAN_AUTO, cg_volume_effects->value, ATTN_DISTANT ); else trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxRocketLauncherWeakHit ), pos, CHAN_AUTO, cg_volume_effects->value, ATTN_DISTANT ); }
/* * CG_SpawnPolyBeam * Spawns a polygon from start to end points length and given width. * shaderlenght makes reference to size of the texture it will draw, so it can be tiled. */ static cpoly_t *CG_SpawnPolyBeam( const vec3_t start, const vec3_t end, const vec4_t color, int width, unsigned int dietime, unsigned int fadetime, struct shader_s *shader, int shaderlength, int tag ) { cpoly_t *cgpoly; poly_t *poly; vec3_t angles, dir; int i; float xmin, ymin, xmax, ymax; float stx = 1.0f, sty = 1.0f; // find out beam polygon sizes VectorSubtract( end, start, dir ); VecToAngles( dir, angles ); xmin = 0; xmax = VectorNormalize( dir ); ymin = -( width*0.5 ); ymax = width*0.5; if( shaderlength && xmax > shaderlength ) stx = xmax / (float)shaderlength; if( xmax - xmin < ymax - ymin ) { // do not render polybeams which have width longer than their length return NULL; } cgpoly = CG_SpawnPolygon( 1.0, 1.0, 1.0, 1.0, dietime ? dietime : cgs.snapFrameTime, fadetime, shader, tag ); VectorCopy( angles, cgpoly->angles ); VectorCopy( start, cgpoly->origin ); if( color ) Vector4Copy( color, cgpoly->color ); // create the polygon inside the cgpolygon poly = cgpoly->poly; poly->shader = cgpoly->shader; poly->numverts = 0; // Vic: I think it's safe to assume there should be no fog applied to beams... poly->fognum = 0; // A Vector4Set( poly->verts[poly->numverts], xmin, 0, ymin, 1 ); poly->stcoords[poly->numverts][0] = 0; poly->stcoords[poly->numverts][1] = 0; poly->colors[poly->numverts][0] = ( uint8_t )( cgpoly->color[0] * 255 ); poly->colors[poly->numverts][1] = ( uint8_t )( cgpoly->color[1] * 255 ); poly->colors[poly->numverts][2] = ( uint8_t )( cgpoly->color[2] * 255 ); poly->colors[poly->numverts][3] = ( uint8_t )( cgpoly->color[3] * 255 ); poly->numverts++; // B Vector4Set( poly->verts[poly->numverts], xmin, 0, ymax, 1 ); poly->stcoords[poly->numverts][0] = 0; poly->stcoords[poly->numverts][1] = sty; poly->colors[poly->numverts][0] = ( uint8_t )( cgpoly->color[0] * 255 ); poly->colors[poly->numverts][1] = ( uint8_t )( cgpoly->color[1] * 255 ); poly->colors[poly->numverts][2] = ( uint8_t )( cgpoly->color[2] * 255 ); poly->colors[poly->numverts][3] = ( uint8_t )( cgpoly->color[3] * 255 ); poly->numverts++; // C Vector4Set( poly->verts[poly->numverts], xmax, 0, ymax, 1 ); poly->stcoords[poly->numverts][0] = stx; poly->stcoords[poly->numverts][1] = sty; poly->colors[poly->numverts][0] = ( uint8_t )( cgpoly->color[0] * 255 ); poly->colors[poly->numverts][1] = ( uint8_t )( cgpoly->color[1] * 255 ); poly->colors[poly->numverts][2] = ( uint8_t )( cgpoly->color[2] * 255 ); poly->colors[poly->numverts][3] = ( uint8_t )( cgpoly->color[3] * 255 ); poly->numverts++; // D Vector4Set( poly->verts[poly->numverts], xmax, 0, ymin, 1 ); poly->stcoords[poly->numverts][0] = stx; poly->stcoords[poly->numverts][1] = 0; poly->colors[poly->numverts][0] = ( uint8_t )( cgpoly->color[0] * 255 ); poly->colors[poly->numverts][1] = ( uint8_t )( cgpoly->color[1] * 255 ); poly->colors[poly->numverts][2] = ( uint8_t )( cgpoly->color[2] * 255 ); poly->colors[poly->numverts][3] = ( uint8_t )( cgpoly->color[3] * 255 ); poly->numverts++; // the verts data is stored inside cgpoly, cause it can be moved later for( i = 0; i < poly->numverts; i++ ) Vector4Copy( poly->verts[i], cgpoly->verts[i] ); return cgpoly; }
/* * CG_Democam_CalcView */ static int CG_Democam_CalcView( void ) { int i, viewType; float lerpfrac; vec3_t v; viewType = VIEWDEF_PLAYERVIEW; VectorClear( cam_velocity ); if( currentcam ) { if( !nextcam ) { lerpfrac = 0; } else { lerpfrac = (float)( demo_time - currentcam->timeStamp ) / (float)( nextcam->timeStamp - currentcam->timeStamp ); } switch( currentcam->type ) { case DEMOCAM_FIRSTPERSON: VectorCopy( cg.view.origin, cam_origin ); VectorCopy( cg.view.angles, cam_angles ); VectorCopy( cg.view.velocity, cam_velocity ); cam_fov = cg.view.fov_y; break; case DEMOCAM_THIRDPERSON: VectorCopy( cg.view.origin, cam_origin ); VectorCopy( cg.view.angles, cam_angles ); VectorCopy( cg.view.velocity, cam_velocity ); cam_fov = cg.view.fov_y; cam_3dPerson = true; break; case DEMOCAM_POSITIONAL: viewType = VIEWDEF_DEMOCAM; cam_POVent = 0; VectorCopy( currentcam->origin, cam_origin ); if( !CG_DemoCam_LookAt( currentcam->trackEnt, cam_origin, cam_angles ) ) { VectorCopy( currentcam->angles, cam_angles ); } cam_fov = currentcam->fov; break; case DEMOCAM_PATH_LINEAR: viewType = VIEWDEF_DEMOCAM; cam_POVent = 0; VectorCopy( cam_origin, v ); if( !nextcam || nextcam->type == DEMOCAM_FIRSTPERSON || nextcam->type == DEMOCAM_THIRDPERSON ) { CG_Printf( "Warning: CG_DemoCam: path_linear cam without a valid next cam\n" ); VectorCopy( currentcam->origin, cam_origin ); if( !CG_DemoCam_LookAt( currentcam->trackEnt, cam_origin, cam_angles ) ) { VectorCopy( currentcam->angles, cam_angles ); } cam_fov = currentcam->fov; } else { VectorLerp( currentcam->origin, lerpfrac, nextcam->origin, cam_origin ); if( !CG_DemoCam_LookAt( currentcam->trackEnt, cam_origin, cam_angles ) ) { for( i = 0; i < 3; i++ ) cam_angles[i] = LerpAngle( currentcam->angles[i], nextcam->angles[i], lerpfrac ); } cam_fov = (float)currentcam->fov + (float)( nextcam->fov - currentcam->fov ) * lerpfrac; } // set velocity VectorSubtract( cam_origin, v, cam_velocity ); VectorScale( cam_velocity, 1.0f / (float)cg.frameTime, cam_velocity ); break; case DEMOCAM_PATH_SPLINE: viewType = VIEWDEF_DEMOCAM; cam_POVent = 0; clamp( lerpfrac, 0, 1 ); VectorCopy( cam_origin, v ); if( !nextcam || nextcam->type == DEMOCAM_FIRSTPERSON || nextcam->type == DEMOCAM_THIRDPERSON ) { CG_Printf( "Warning: CG_DemoCam: path_spline cam without a valid next cam\n" ); VectorCopy( currentcam->origin, cam_origin ); if( !CG_DemoCam_LookAt( currentcam->trackEnt, cam_origin, cam_angles ) ) { VectorCopy( currentcam->angles, cam_angles ); } cam_fov = currentcam->fov; } else { // valid spline path #define VectorHermiteInterp( a, at, b, bt, c, v ) ( ( v )[0] = ( 2 * pow( c, 3 ) - 3 * pow( c, 2 ) + 1 ) * a[0] + ( pow( c, 3 ) - 2 * pow( c, 2 ) + c ) * 2 * at[0] + ( -2 * pow( c, 3 ) + 3 * pow( c, 2 ) ) * b[0] + ( pow( c, 3 ) - pow( c, 2 ) ) * 2 * bt[0], ( v )[1] = ( 2 * pow( c, 3 ) - 3 * pow( c, 2 ) + 1 ) * a[1] + ( pow( c, 3 ) - 2 * pow( c, 2 ) + c ) * 2 * at[1] + ( -2 * pow( c, 3 ) + 3 * pow( c, 2 ) ) * b[1] + ( pow( c, 3 ) - pow( c, 2 ) ) * 2 * bt[1], ( v )[2] = ( 2 * pow( c, 3 ) - 3 * pow( c, 2 ) + 1 ) * a[2] + ( pow( c, 3 ) - 2 * pow( c, 2 ) + c ) * 2 * at[2] + ( -2 * pow( c, 3 ) + 3 * pow( c, 2 ) ) * b[2] + ( pow( c, 3 ) - pow( c, 2 ) ) * 2 * bt[2] ) float lerpspline, A, B, C, n1, n2, n3; cg_democam_t *previouscam = NULL; cg_democam_t *secondnextcam = NULL; if( nextcam ) { secondnextcam = CG_Democam_FindNext( nextcam->timeStamp ); } if( currentcam->timeStamp > 0 ) { previouscam = CG_Democam_FindCurrent( currentcam->timeStamp - 1 ); } if( !previouscam && nextcam && !secondnextcam ) { lerpfrac = (float)( demo_time - currentcam->timeStamp ) / (float)( nextcam->timeStamp - currentcam->timeStamp ); lerpspline = lerpfrac; } else if( !previouscam && nextcam && secondnextcam ) { n1 = nextcam->timeStamp - currentcam->timeStamp; n2 = secondnextcam->timeStamp - nextcam->timeStamp; A = n1 * ( n1 - n2 ) / ( pow( n1, 2 ) + n1 * n2 - n1 - n2 ); B = ( 2 * n1 * n2 - n1 - n2 ) / ( pow( n1, 2 ) + n1 * n2 - n1 - n2 ); lerpfrac = (float)( demo_time - currentcam->timeStamp ) / (float)( nextcam->timeStamp - currentcam->timeStamp ); lerpspline = A * pow( lerpfrac, 2 ) + B * lerpfrac; } else if( previouscam && nextcam && !secondnextcam ) { n2 = currentcam->timeStamp - previouscam->timeStamp; n3 = nextcam->timeStamp - currentcam->timeStamp; A = n3 * ( n2 - n3 ) / ( -n2 - n3 + n2 * n3 + pow( n3, 2 ) ); B = -1 / ( -n2 - n3 + n2 * n3 + pow( n3, 2 ) ) * ( n2 + n3 - 2 * pow( n3, 2 ) ); lerpfrac = (float)( demo_time - currentcam->timeStamp ) / (float)( nextcam->timeStamp - currentcam->timeStamp ); lerpspline = A * pow( lerpfrac, 2 ) + B * lerpfrac; } else if( previouscam && nextcam && secondnextcam ) { n1 = currentcam->timeStamp - previouscam->timeStamp; n2 = nextcam->timeStamp - currentcam->timeStamp; n3 = secondnextcam->timeStamp - nextcam->timeStamp; A = -2 * pow( n2, 2 ) * ( -pow( n2, 2 ) + n1 * n3 ) / ( 2 * n2 * n3 + pow( n2, 3 ) * n3 - 3 * pow( n2, 2 ) * n1 + n1 * pow( n2, 3 ) + 2 * n1 * n2 - 3 * pow( n2, 2 ) * n3 - 3 * pow( n2, 3 ) + 2 * pow( n2, 2 ) + pow( n2, 4 ) + n1 * pow( n2, 2 ) * n3 - 3 * n1 * n2 * n3 + 2 * n1 * n3 ); B = pow( n2, 2 ) * ( -2 * n1 - 3 * pow( n2, 2 ) - n2 * n3 + 2 * n3 + 3 * n1 * n3 + n1 * n2 ) / ( 2 * n2 * n3 + pow( n2, 3 ) * n3 - 3 * pow( n2, 2 ) * n1 + n1 * pow( n2, 3 ) + 2 * n1 * n2 - 3 * pow( n2, 2 ) * n3 - 3 * pow( n2, 3 ) + 2 * pow( n2, 2 ) + pow( n2, 4 ) + n1 * pow( n2, 2 ) * n3 - 3 * n1 * n2 * n3 + 2 * n1 * n3 ); C = -( pow( n2, 2 ) * n1 - 2 * n1 * n2 + 3 * n1 * n2 * n3 - 2 * n1 * n3 - 2 * pow( n2, 4 ) + 3 * pow( n2, 3 ) - 2 * pow( n2, 3 ) * n3 + 5 * pow( n2, 2 ) * n3 - 2 * pow( n2, 2 ) - 2 * n2 * n3 ) / ( 2 * n2 * n3 + pow( n2, 3 ) * n3 - 3 * pow( n2, 2 ) * n1 + n1 * pow( n2, 3 ) + 2 * n1 * n2 - 3 * pow( n2, 2 ) * n3 - 3 * pow( n2, 3 ) + 2 * pow( n2, 2 ) + pow( n2, 4 ) + n1 * pow( n2, 2 ) * n3 - 3 * n1 * n2 * n3 + 2 * n1 * n3 ); lerpfrac = (float)( demo_time - currentcam->timeStamp ) / (float)( nextcam->timeStamp - currentcam->timeStamp ); lerpspline = A * pow( lerpfrac, 3 ) + B * pow( lerpfrac, 2 ) + C * lerpfrac; } else { lerpfrac = 0; lerpspline = 0; } VectorHermiteInterp( currentcam->origin, currentcam->tangent, nextcam->origin, nextcam->tangent, lerpspline, cam_origin ); if( !CG_DemoCam_LookAt( currentcam->trackEnt, cam_origin, cam_angles ) ) { VectorHermiteInterp( currentcam->angles, currentcam->angles_tangent, nextcam->angles, nextcam->angles_tangent, lerpspline, cam_angles ); } cam_fov = (float)currentcam->fov + (float)( nextcam->fov - currentcam->fov ) * lerpfrac; #undef VectorHermiteInterp } // set velocity VectorSubtract( cam_origin, v, cam_velocity ); VectorScale( cam_velocity, 1.0f / (float)cg.frameTime, cam_velocity ); break; case DEMOCAM_ORBITAL: viewType = VIEWDEF_DEMOCAM; cam_POVent = 0; cam_fov = currentcam->fov; VectorCopy( cam_origin, v ); if( !currentcam->trackEnt || currentcam->trackEnt >= MAX_EDICTS ) { CG_Printf( "Warning: CG_DemoCam: orbital cam needs a track entity set\n" ); VectorCopy( currentcam->origin, cam_origin ); VectorClear( cam_angles ); VectorClear( cam_velocity ); } else { vec3_t center, forward; struct cmodel_s *cmodel; const float ft = (float)cg.frameTime * 0.001f; // find the trackEnt origin VectorLerp( cg_entities[currentcam->trackEnt].prev.origin, cg.lerpfrac, cg_entities[currentcam->trackEnt].current.origin, center ); // if having a bounding box, look to its center if( ( cmodel = CG_CModelForEntity( currentcam->trackEnt ) ) != NULL ) { vec3_t mins, maxs; trap_CM_InlineModelBounds( cmodel, mins, maxs ); for( i = 0; i < 3; i++ ) center[i] += ( mins[i] + maxs[i] ); } if( !cam_orbital_radius ) { // cam is just started, find distance from cam to trackEnt and keep it as radius VectorSubtract( currentcam->origin, center, forward ); cam_orbital_radius = VectorNormalize( forward ); VecToAngles( forward, cam_orbital_angles ); } for( i = 0; i < 3; i++ ) { cam_orbital_angles[i] += currentcam->angles[i] * ft; cam_orbital_angles[i] = AngleNormalize360( cam_orbital_angles[i] ); } AngleVectors( cam_orbital_angles, forward, NULL, NULL ); VectorMA( center, cam_orbital_radius, forward, cam_origin ); // lookat VectorInverse( forward ); VecToAngles( forward, cam_angles ); } // set velocity VectorSubtract( cam_origin, v, cam_velocity ); VectorScale( cam_velocity, 1.0f / ( cg.frameTime * 1000.0f ), cam_velocity ); break; default: break; } if( currentcam->type != DEMOCAM_ORBITAL ) { VectorClear( cam_orbital_angles ); cam_orbital_radius = 0; } } return viewType; }
/* * CG_RocketExplosionMode */ void CG_RocketExplosionMode( vec3_t pos, vec3_t dir, int fire_mode, float radius ) { lentity_t *le; vec3_t angles, vec; vec3_t origin; float expvelocity = 8.0f; VecToAngles( dir, angles ); if( fire_mode == FIRE_MODE_STRONG ) { //trap_S_StartSound ( pos, 0, 0, CG_MediaSfx (cgs.media.sfxRocketLauncherStrongHit), cg_volume_effects->value, ATTN_NORM, 0 ); CG_SpawnDecal( pos, dir, random()*360, radius * 0.5, 1, 1, 1, 1, 10, 1, qfalse, CG_MediaShader( cgs.media.shaderExplosionMark ) ); } else { //trap_S_StartSound ( pos, 0, 0, CG_MediaSfx (cgs.media.sfxRocketLauncherWeakHit), cg_volume_effects->value, ATTN_NORM, 0 ); CG_SpawnDecal( pos, dir, random()*360, radius * 0.25, 1, 1, 1, 1, 10, 1, qfalse, CG_MediaShader( cgs.media.shaderExplosionMark ) ); } // animmap shader of the explosion VectorMA( pos, radius*0.12f, dir, origin ); le = CG_AllocSprite( LE_ALPHA_FADE, origin, radius * 0.5f, 8, 1, 1, 1, 1, radius*4, 0.75f, 0.533f, 0, // yellow dlight CG_MediaShader( cgs.media.shaderRocketExplosion ) ); VectorSet( vec, crandom()*expvelocity, crandom()*expvelocity, crandom()*expvelocity ); VectorScale( dir, expvelocity, le->velocity ); VectorAdd( le->velocity, vec, le->velocity ); le->ent.rotation = rand() % 360; if( cg_explosionsRing->integer ) { // explosion ring sprite VectorMA( pos, radius*0.20f, dir, origin ); le = CG_AllocSprite( LE_ALPHA_FADE, origin, radius, 3, 1, 1, 1, 1, 0, 0, 0, 0, // no dlight CG_MediaShader( cgs.media.shaderRocketExplosionRing ) ); le->ent.rotation = rand() % 360; } if( cg_explosionsDust->integer == 1 ) { // dust ring parallel to the contact surface CG_ExplosionsDust(pos, dir, radius); } // Explosion particles CG_ParticleExplosionEffect( pos, dir, 1, 0.5, 0, 32 ); if( fire_mode == FIRE_MODE_STRONG ) trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxRocketLauncherStrongHit ), pos, CHAN_AUTO, cg_volume_effects->value, ATTN_DISTANT ); else trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxRocketLauncherWeakHit ), pos, CHAN_AUTO, cg_volume_effects->value, ATTN_DISTANT ); //jalfixme: add sound at water? }
/* * CG_BulletExplosion */ void CG_BulletExplosion( vec3_t pos, vec_t *dir, trace_t *trace ) { lentity_t *le; vec3_t angles; vec3_t local_dir, end; trace_t local_trace, *tr; assert( dir || trace ); if( dir ) { // find what are we hitting tr = &local_trace; VectorMA( pos, -1.0, dir, end ); CG_Trace( tr, pos, vec3_origin, vec3_origin, end, cg.view.POVent, MASK_SHOT ); if( tr->fraction == 1.0 ) return; } else { tr = trace; dir = local_dir; VectorCopy( tr->plane.normal, dir ); } VecToAngles( dir, angles ); if( tr->surfFlags & SURF_FLESH || ( tr->ent > 0 && cg_entities[tr->ent].current.type == ET_PLAYER ) || ( tr->ent > 0 && cg_entities[tr->ent].current.type == ET_CORPSE ) ) { le = CG_AllocModel( LE_ALPHA_FADE, pos, angles, 3, //3 frames for weak 1, 0, 0, 1, //full white no inducted alpha 0, 0, 0, 0, //dlight CG_MediaModel( cgs.media.modBulletExplode ), NULL ); le->ent.rotation = rand() % 360; le->ent.scale = 1.0f; if( ISVIEWERENTITY( tr->ent ) ) le->ent.renderfx |= RF_VIEWERMODEL; } else if( tr->surfFlags & SURF_DUST ) { // throw particles on dust CG_ImpactSmokePuff( tr->endpos, tr->plane.normal, 4, 0.6f, 6, 8 ); } else { le = CG_AllocModel( LE_ALPHA_FADE, pos, angles, 3, //3 frames for weak 1, 1, 1, 1, //full white no inducted alpha 0, 0, 0, 0, //dlight CG_MediaModel( cgs.media.modBulletExplode ), NULL ); le->ent.rotation = rand() % 360; le->ent.scale = 1.0f; CG_ImpactSmokePuff( tr->endpos, tr->plane.normal, 2, 0.6f, 6, 8 ); if( !( tr->surfFlags & SURF_NOMARKS ) ) CG_SpawnDecal( pos, dir, random()*360, 8, 1, 1, 1, 1, 10, 1, qfalse, CG_MediaShader( cgs.media.shaderBulletMark ) ); } }
/* * CG_GrenadeExplosionMode */ void CG_GrenadeExplosionMode( vec3_t pos, vec3_t dir, int fire_mode, float radius ) { lentity_t *le; vec3_t angles; vec3_t decaldir; vec3_t origin, vec; float expvelocity = 8.0f; VectorCopy( dir, decaldir ); VecToAngles( dir, angles ); //if( CG_PointContents( pos ) & MASK_WATER ) //jalfixme: (shouldn't we do the water sound variation?) if( fire_mode == FIRE_MODE_STRONG ) { CG_SpawnDecal( pos, decaldir, random()*360, radius * 0.5, 1, 1, 1, 1, 10, 1, qfalse, CG_MediaShader( cgs.media.shaderExplosionMark ) ); } else { CG_SpawnDecal( pos, decaldir, random()*360, radius * 0.25, 1, 1, 1, 1, 10, 1, qfalse, CG_MediaShader( cgs.media.shaderExplosionMark ) ); } // animmap shader of the explosion VectorMA( pos, radius*0.15f, dir, origin ); le = CG_AllocSprite( LE_ALPHA_FADE, origin, radius * 0.5f, 8, 1, 1, 1, 1, radius*4, 0.75f, 0.533f, 0, // yellow dlight CG_MediaShader( cgs.media.shaderRocketExplosion ) ); VectorSet( vec, crandom()*expvelocity, crandom()*expvelocity, crandom()*expvelocity ); VectorScale( dir, expvelocity, le->velocity ); VectorAdd( le->velocity, vec, le->velocity ); le->ent.rotation = rand() % 360; // explosion ring sprite if( cg_explosionsRing->integer ) { VectorMA( pos, radius*0.25f, dir, origin ); le = CG_AllocSprite( LE_ALPHA_FADE, origin, radius, 3, 1, 1, 1, 1, 0, 0, 0, 0, // no dlight CG_MediaShader( cgs.media.shaderRocketExplosionRing ) ); le->ent.rotation = rand() % 360; } if( cg_explosionsDust->integer == 1 ) { // dust ring parallel to the contact surface CG_ExplosionsDust(pos, dir, radius); } // Explosion particles CG_ParticleExplosionEffect( pos, dir, 1, 0.5, 0, 32 ); if( fire_mode == FIRE_MODE_STRONG ) trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxGrenadeStrongExplosion ), pos, CHAN_AUTO, cg_volume_effects->value, ATTN_DISTANT ); else trap_S_StartFixedSound( CG_MediaSfx( cgs.media.sfxGrenadeWeakExplosion ), pos, CHAN_AUTO, cg_volume_effects->value, ATTN_DISTANT ); }
/* * W_Fire_Lead * the seed is important to be as pointer for cgame prediction accuracy */ static void W_Fire_Lead( edict_t *self, vec3_t start, vec3_t aimdir, vec3_t axis[3], int damage, int knockback, int stun, int hspread, int vspread, int *seed, int dflags, int mod, int timeDelta ) { trace_t tr; vec3_t dir; vec3_t end; float r; float u; vec3_t water_start; int content_mask = MASK_SHOT | MASK_WATER; G_Trace4D( &tr, self->s.origin, NULL, NULL, start, self, MASK_SHOT, timeDelta ); if( !( tr.fraction < 1.0 ) ) { #if 1 // circle double alpha = M_PI * Q_crandom( seed ); // [-PI ..+PI] double s = fabs( Q_crandom( seed ) ); // [0..1] r = s * cos( alpha ) * hspread; u = s * sin( alpha ) * vspread; #else // square r = Q_crandom( seed ) * hspread; u = Q_crandom( seed ) * vspread; #endif VectorMA( start, 8192, axis[0], end ); VectorMA( end, r, axis[1], end ); VectorMA( end, u, axis[2], end ); if( G_PointContents4D( start, timeDelta ) & MASK_WATER ) { VectorCopy( start, water_start ); content_mask &= ~MASK_WATER; } G_Trace4D( &tr, start, NULL, NULL, end, self, content_mask, timeDelta ); // see if we hit water if( tr.contents & MASK_WATER ) { VectorCopy( tr.endpos, water_start ); if( !VectorCompare( start, tr.endpos ) ) { vec3_t forward, right, up; // change bullet's course when it enters water VectorSubtract( end, start, dir ); VecToAngles( dir, dir ); AngleVectors( dir, forward, right, up ); #if 1 // circle alpha = M_PI *Q_crandom( seed ); // [-PI ..+PI] s = fabs( Q_crandom( seed ) ); // [0..1] r = s *cos( alpha )*hspread*1.5; u = s *sin( alpha )*vspread*1.5; #else r = Q_crandom( seed ) * hspread * 2; u = Q_crandom( seed ) * vspread * 2; #endif VectorMA( water_start, 8192, forward, end ); VectorMA( end, r, right, end ); VectorMA( end, u, up, end ); } // re-trace ignoring water this time G_Trace4D( &tr, water_start, NULL, NULL, end, self, MASK_SHOT, timeDelta ); } } // send gun puff / flash if( tr.fraction < 1.0 && tr.ent != -1 ) { if( game.edicts[tr.ent].takedamage ) { G_Damage( &game.edicts[tr.ent], self, self, aimdir, aimdir, tr.endpos, tr.plane.normal, damage, knockback, stun, dflags, mod ); } else { if( !( tr.surfFlags & SURF_NOIMPACT ) ) { } } } }
/* * CG_AddLocalEntities */ void CG_AddLocalEntities( void ) { #define FADEINFRAMES 2 int f; lentity_t *le, *next, *hnode; entity_t *ent; float scale, frac, fade, time, scaleIn, fadeIn; float backlerp; vec3_t angles; time = cg.frameTime; backlerp = 1.0f - cg.lerpfrac; hnode = &cg_localents_headnode; for( le = hnode->next; le != hnode; le = next ) { next = le->next; frac = ( cg.time - le->start ) * 0.01f; f = ( int )floor( frac ); clamp_low( f, 0 ); // it's time to DIE if( f >= le->frames - 1 ) { le->type = LE_FREE; CG_FreeLocalEntity( le ); continue; } if( le->frames > 1 ) { scale = 1.0f - frac / ( le->frames - 1 ); scale = bound( 0.0f, scale, 1.0f ); fade = scale * 255.0f; // quick fade in, if time enough if( le->frames > FADEINFRAMES * 2 ) { scaleIn = frac / (float)FADEINFRAMES; clamp( scaleIn, 0.0f, 1.0f ); fadeIn = scaleIn * 255.0f; } else fadeIn = 255.0f; } else { scale = 1.0f; fade = 255.0f; fadeIn = 255.0f; } ent = &le->ent; if( le->light && scale ) CG_AddLightToScene( ent->origin, le->light * scale, le->lightcolor[0], le->lightcolor[1], le->lightcolor[2], NULL ); if( le->type == LE_LASER ) { CG_QuickPolyBeam( ent->origin, ent->origin2, ent->radius, ent->customShader ); // wsw : jalfixme: missing the color (comes inside ent->skinnum) continue; } if( le->type == LE_DASH_SCALE ) { if( f < 1 ) ent->scale = 0.2 * frac; else { VecToAngles( ent->axis[1], angles ); ent->axis[1][1] += 0.005f *sin( DEG2RAD ( angles[YAW] ) ); //length ent->axis[1][0] += 0.005f *cos( DEG2RAD ( angles[YAW] ) ); //length ent->axis[0][1] += 0.008f *cos( DEG2RAD ( angles[YAW] ) ); //width ent->axis[0][0] -= 0.008f *sin( DEG2RAD ( angles[YAW] ) ); //width ent->axis[2][2] -= 0.052f; //height if( ent->axis[2][2] <= 0 ) { le->type = LE_FREE; CG_FreeLocalEntity( le ); } } } if( le->type == LE_DASH_SCALE_2 ) { if( f < 1 ) ent->scale = 0.25 * frac; else { VecToAngles( ent->axis[1], angles ); ent->axis[1][1] += 0.005f *sin( DEG2RAD ( angles[YAW] ) ); //length ent->axis[1][0] += 0.005f *cos( DEG2RAD ( angles[YAW] ) ); //length ent->axis[0][1] += 0.008f *cos( DEG2RAD ( angles[YAW] ) ); //width ent->axis[0][0] -= 0.008f *sin( DEG2RAD ( angles[YAW] ) ); //width ent->axis[2][2] -= 0.018f; //height ent->origin[1] -= 0.6f *sin( DEG2RAD ( angles[YAW] ) ); //velocity ent->origin[0] -= 0.6f *cos( DEG2RAD ( angles[YAW] ) ); //velocity if( ent->axis[2][2] <= 0 ) { le->type = LE_FREE; CG_FreeLocalEntity( le ); } } } if( le->type == LE_PUFF_SCALE ) { if( frac < 1 ) ent->scale = 7.0f*frac; else ent->scale = 7.0f - 4.0f*( frac-1 ); if( ent->scale < 0 ) { le->type = LE_FREE; CG_FreeLocalEntity( le ); } } if( le->type == LE_PUFF_SCALE_2 ) { if( le->frames - f < 4 ) ent->scale = 1.0f - 1.0f * ( frac - abs( 4-le->frames ) )/4; } if( le->type == LE_PUFF_SHRINK ) { if( frac < 3 ) ent->scale = 1.0f - 0.2f * frac/4; else { ent->scale = 0.8 - 0.8*( frac-3 )/3; VectorScale( le->velocity, 0.85f, le->velocity ); } } if( le->type == LE_EXPLOSION_TRACER ) { if( cg.time - ent->rotation > 10.0f ) { ent->rotation = cg.time; if( ent->radius - 16*frac > 4 ) CG_Explosion_Puff( ent->origin, ent->radius-16*frac, le->frames - f ); } } switch( le->type ) { case LE_NO_FADE: break; case LE_RGB_FADE: fade = min( fade, fadeIn ); ent->shaderRGBA[0] = ( qbyte )( fade * le->color[0] ); ent->shaderRGBA[1] = ( qbyte )( fade * le->color[1] ); ent->shaderRGBA[2] = ( qbyte )( fade * le->color[2] ); break; case LE_SCALE_ALPHA_FADE: fade = min( fade, fadeIn ); ent->scale = 1.0f + 1.0f / scale; ent->scale = min( ent->scale, 5.0f ); ent->shaderRGBA[3] = ( qbyte )( fade * le->color[3] ); break; case LE_INVERSESCALE_ALPHA_FADE: fade = min( fade, fadeIn ); ent->scale = scale + 0.1f; clamp( ent->scale, 0.1f, 1.0f ); ent->shaderRGBA[3] = ( qbyte )( fade * le->color[3] ); break; case LE_ALPHA_FADE: fade = min( fade, fadeIn ); ent->shaderRGBA[3] = ( qbyte )( fade * le->color[3] ); break; default: break; } ent->backlerp = backlerp; if( le->bounce ) { trace_t trace; vec3_t next_origin; VectorMA( ent->origin, time, le->velocity, next_origin ); CG_Trace( &trace, ent->origin, debris_mins, debris_maxs, next_origin, 0, MASK_SOLID ); // remove the particle when going out of the map if( ( trace.contents & CONTENTS_NODROP ) || ( trace.surfFlags & SURF_SKY ) ) { le->frames = 0; } else if( trace.fraction != 1.0 ) // found solid { float dot; vec3_t vel; float xzyspeed; // Reflect velocity VectorSubtract( next_origin, ent->origin, vel ); dot = -2 *DotProduct( vel, trace.plane.normal ); VectorMA( vel, dot, trace.plane.normal, le->velocity ); //put new origin in the impact point, but move it out a bit along the normal VectorMA( trace.endpos, 1, trace.plane.normal, ent->origin ); //the entity has not speed enough. Stop checks xzyspeed = sqrt( le->velocity[0]*le->velocity[0] + le->velocity[1]*le->velocity[1] + le->velocity[2]*le->velocity[2] ); if( xzyspeed * time < 1.0f ) { trace_t traceground; vec3_t ground_origin; //see if we have ground VectorCopy( ent->origin, ground_origin ); ground_origin[2] += ( debris_mins[2] - 4 ); CG_Trace( &traceground, ent->origin, debris_mins, debris_maxs, ground_origin, 0, MASK_SOLID ); if( traceground.fraction != 1.0 ) { le->bounce = qfalse; VectorClear( le->velocity ); VectorClear( le->accel ); if( le->type == LE_EXPLOSION_TRACER ) { // blx le->type = LE_FREE; CG_FreeLocalEntity( le ); } } } else VectorScale( le->velocity, le->bounce * time, le->velocity ); } else { VectorCopy( ent->origin, ent->origin2 ); VectorCopy( next_origin, ent->origin ); } } else { VectorCopy( ent->origin, ent->origin2 ); VectorMA( ent->origin, time, le->velocity, ent->origin ); } VectorCopy( ent->origin, ent->lightingOrigin ); VectorMA( le->velocity, time, le->accel, le->velocity ); CG_AddEntityToScene( ent ); } }