void CG_FragmentBounceMark( localEntity_t *le, trace_t *trace ) { #if 0 if ( le->leMarkType == LEMT_BLOOD ) CG_ImpactMark( media.gfx.world.bloodMark, trace->endpos, trace->plane.normal, random()*360, 1,1,1,1, qtrue, radius, qfalse ); else if ( le->leMarkType == LEMT_BURN ) CG_ImpactMark( media.gfx.world.burnMark, trace->endpos, trace->plane.normal, random()*360, 1,1,1,1, qtrue, radius, qfalse ); #endif // don't allow a fragment to make multiple marks, or they // pile up while settling le->leMarkType = LEMT_NONE; }
/* ======================================================================================================================================= CG_FragmentBounceMark ======================================================================================================================================= */ void CG_FragmentBounceMark(localEntity_t *le, trace_t *trace) { int markRadius; if (le->leMarkType == LEMT_BLOOD) { markRadius = 16 + (rand()&31); CG_ImpactMark(cgs.media.bloodMarkShader, trace->endpos, trace->plane.normal, random() * 360, 1, 1, 1, 1, qtrue, markRadius, qfalse); } else if (le->leMarkType == LEMT_BURN) { markRadius = 8 + (rand()&15); CG_ImpactMark(cgs.media.burnMarkShader, trace->endpos, trace->plane.normal, random() * 360, 1, 1, 1, 1, qtrue, markRadius, qfalse); } // don't allow a fragment to make multiple marks, or they pile up while settling le->leMarkType = LEMT_NONE; }
void FX_RegenBeam( vec3_t origin, vec3_t dir, int clientNum, qboolean alt_fire ) { trace_t tr; vec3_t end; VectorMA( origin, REGEN_BEAM_LENGTH, dir, end ); CG_Trace( &tr, origin, NULL, NULL, end, clientNum, CONTENTS_SOLID ); trap_R_AddLightToScene( origin, 30, 235.0f / 255, 74.0f / 255, 102.0f / 255 ); if ( tr.fraction != 1.0f ) { float radius; if ( alt_fire ) radius = flrandom(1.5f, 3.0f) * (1.0 - (tr.fraction*0.3)); else radius = flrandom(0.5f, 1.5f) * (1.0 - (tr.fraction*0.3)); if ( !radius ) return; CG_ImpactMark( cgs.media.regenDecal, tr.endpos, tr.plane.normal, 0, 1, 1, 1, 0.2*(1.0-tr.fraction), qfalse, radius, qtrue ); trap_R_AddLightToScene( origin, radius*5, 235.0f / 255, 74.0f / 255, 102.0f / 255 ); } }
/* ================ CG_FragmentBounceMark ================ */ void CG_FragmentBounceMark( localEntity_t *le, trace_t *trace ) { int radius; vec4_t projection, color; if ( le->leMarkType == LEMT_BLOOD ) { static int lastBloodMark; // don't drop too many blood marks if ( !( lastBloodMark > cg.time || lastBloodMark > cg.time - 100 ) ) { radius = 16 + ( rand() & 31 ); //% CG_ImpactMark( cgs.media.bloodDotShaders[rand()%5], trace->endpos, trace->plane.normal, random()*360, //% 1,1,1,1, qtrue, radius, qfalse, cg_bloodTime.integer * 1000 ); #if 0 VectorSubtract( vec3_origin, trace->plane.normal, projection ); projection[ 3 ] = radius * 2.0f; VectorMA( trace->endpos, -8.0f, projection, markOrigin ); CG_ImpactMark( cgs.media.bloodDotShaders[ rand() % 5 ], markOrigin, projection, radius, random() * 360.0f, 1.0f, 1.0f, 1.0f, 1.0f, cg_bloodTime.integer * 1000 ); #else VectorSet( projection, 0, 0, -1 ); projection[ 3 ] = radius; Vector4Set( color, 1.0f, 1.0f, 1.0f, 1.0f ); trap_R_ProjectDecal( cgs.media.bloodDotShaders[ rand() % 5 ], 1, ( vec3_t * ) trace->endpos, projection, color, cg_bloodTime.integer * 1000, ( cg_bloodTime.integer * 1000 ) >> 4 ); #endif lastBloodMark = cg.time; } }
void FX_GrenadeShrapnelExplode( vec3_t origin, vec3_t norm ) { localEntity_t *le; FXTrail *fx; vec3_t direction, org; //Orient the explosions to face the camera VectorSubtract( cg.refdef.vieworg, origin, direction ); VectorNormalize( direction ); VectorMA( origin, 12, direction, org ); // Add an explosion and tag a light to it le = CG_MakeExplosion( org, direction, cgs.media.explosionModel, 6, cgs.media.surfaceExplosionShader, 700, qfalse, 1.2f + (random()*0.3f) ); le->light = 150; le->refEntity.renderfx |= RF_NOSHADOW; VectorSet( le->lightColor, 1.0f, 0.6f, 0.6f ); for ( int i = 0; i < 6; i++) { fx = FX_AddTrail( origin, NULL, NULL, 16.0f, -15.0f, 1.5, -1.5, 1.0f, 1.0f, 0.2f, 1000.0f, cgs.media.orangeTrailShader, rand() & FXF_BOUNCE ); if ( fx == NULL ) return; FXE_Spray( norm, 500, 175, 0.8f, 512, (FXPrimitive *) fx ); } cgi_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeAltExplodeSnd ); CG_ImpactMark( cgs.media.compressionMarkShader, origin, norm, random()*360, 1,1,1,1.0, qfalse, random() * 16 + 48, qfalse ); CG_ExplosionEffects( origin, 2.0, 350 ); }
void FX_ProtonAltMiss( vec3_t origin, vec3_t normal ) { vec3_t new_org; vec3_t velocity; float scale, dscale; int i; // Smoke puffs for ( i = 0; i < 8; i++ ) { scale = random() * 12.0f + 4.0f; dscale = random() * 12.0f + 8.0f; VectorMA( origin, random() * 8.0f, normal, new_org ); velocity[0] = normal[0] * crandom() * 24.0f; velocity[1] = normal[1] * crandom() * 24.0f; velocity[2] = normal[2] * ( random() * 24.0f + 8.0f ) + 8.0f; // move mostly up FX_AddSprite( new_org, velocity, NULL, scale, dscale, random() * 0.5f + 0.5f, 0.0f, random() * 45.0f, 0.0f, 800 + random() * 300.0f, cgs.media.steamShader ); } // Scorch mark CG_ImpactMark( cgs.media.bulletmarksShader, origin, normal, random()*360, 1,1,1,1, qfalse, 6, qfalse ); // FX_ProtonHit( origin ); CG_ExplosionEffects( origin, 1.0f, 150 ); }
/* ================== CG_Creep ================== */ static void CG_Creep( centity_t *cent ) { int msec; float size, frac; trace_t tr; vec3_t temp, origin; int scaleUpTime = BG_Buildable( cent->currentState.modelindex )->buildTime; int time; // int creepSize; time = cent->currentState.time; //should the creep be growing or receding? if( time >= 0 ) { msec = cg.time - time; if( msec >= 0 && msec < scaleUpTime ) frac = (float)msec / scaleUpTime; else frac = 1.0f; } else if( time < 0 ) { msec = cg.time + time; if( msec >= 0 && msec < CREEP_SCALEDOWN_TIME ) frac = 1.0f - ( (float)msec / CREEP_SCALEDOWN_TIME ); else frac = 0.0f; } VectorCopy( cent->currentState.origin2, temp ); VectorScale( temp, -CREEP_DISTANCE, temp ); VectorAdd( temp, cent->lerpOrigin, temp ); CG_Trace( &tr, cent->lerpOrigin, NULL, NULL, temp, cent->currentState.number, MASK_PLAYERSOLID ); VectorCopy( tr.endpos, origin ); // size = CREEP_SIZE * frac; size = BG_Buildable( cent->currentState.modelindex )->creepSize * frac; if( size > 0.0f && tr.fraction < 1.0f ) CG_ImpactMark( cgs.media.creepShader, //qhandle_t markShader origin, //const vec3_t origin cent->currentState.origin2, //const vec3_t dir 0.0f, //float orientation 1.0f, //red 1.0f, //green 1.0f, //blue 1.0f, //float alpha qtrue, //qboolean alphaFade size, //float radius qtrue);//qboolean temporary }
// LEILEI void CG_GoreMark( localEntity_t *le, trace_t *trace ) { int radius; if ( le->leMarkType == LEMT_BURN ) { radius = 6 + (rand()&16); CG_ImpactMark( cgs.media.lbldShader2, trace->endpos, trace->plane.normal, random()*360, 1,1,1,1, qtrue, radius, qfalse ); } le->leMarkType = LEMT_NONE; }
//TiM - Beam FX for the Neutrino Probe weapon void FX_ProbeBeam( vec3_t origin, vec3_t dir, int clientNum, qboolean alt_fire ) { trace_t tr; refEntity_t beam; vec3_t end; float scale; memset( &beam, 0, sizeof( beam ) ); if ( alt_fire ) scale = flrandom(7.0f, 12.0f); else scale = Q_fabs( 12.0f * sin( cg.time * 0.1f ) ); VectorMA( origin, PROBE_BEAM_LENGTH, dir, end ); CG_Trace( &tr, origin, NULL, NULL, end, clientNum, CONTENTS_SOLID ); trap_R_AddLightToScene( origin, 20, 114.0f / 255, 164.0f / 255, 1.0f ); VectorCopy( origin, beam.origin); VectorCopy( tr.endpos, beam.oldorigin ); beam.reType = RT_LINE; beam.customShader = cgs.media.probeBeam; beam.shaderRGBA[0] = 0xff; beam.shaderRGBA[1] = 0xff; beam.shaderRGBA[2] = 0xff; beam.shaderRGBA[3] = 0xff; AxisClear( beam.axis ); beam.data.line.width = scale*0.1; beam.data.line.width2 = scale; beam.data.line.stscale = 1.0; trap_R_AddRefEntityToScene( &beam ); if ( tr.fraction != 1.0f ) { float radius; if ( alt_fire ) radius = flrandom(1.5f, 3.0f) * (1.0 - (tr.fraction*0.3)); else radius = flrandom(0.5f, 1.5f) * (1.0 - (tr.fraction*0.3)); if ( !radius ) return; CG_ImpactMark( cgs.media.probeDecal, tr.endpos, tr.plane.normal, 0, 1, 1, 1, 0.2*(1.0-tr.fraction), qfalse, radius, qtrue ); trap_R_AddLightToScene( origin, radius*5, 114.0f / 255, 164.0f / 255, 1.0f ); } }
/* ================ CG_FragmentBounceMark ================ */ void CG_FragmentBounceMark(localEntity_t * le, trace_t * trace) { int radius, r = 0; qhandle_t h; if(le->leMarkType == LEMT_BLOOD) { radius = 16 + (rand() & 31); r = rand() & 3; if(r == 0) { h = cgs.media.bloodMarkShader; } else if(r == 1) { h = cgs.media.bloodMark2Shader; } else { h = cgs.media.bloodMark3Shader; } CG_ImpactMark(h, trace->endpos, trace->plane.normal, random() * 360, 1, 1, 1, 1, qtrue, radius, qfalse); } else if(le->leMarkType == LEMT_BURN) { radius = 8 + (rand() & 15); CG_ImpactMark(cgs.media.burnMarkShader, trace->endpos, trace->plane.normal, random() * 360, 1, 1, 1, 1, qtrue, radius, qfalse); } // don't allow a fragment to make multiple marks, or they // pile up while settling le->leMarkType = LEMT_NONE; }
/* ================== CG_Creep ================== */ static void CG_Creep( centity_t *cent ) { int msec; float size, frac; trace_t tr; vec3_t temp, origin; int scaleUpTime = BG_FindBuildTimeForBuildable( cent->currentState.modelindex ); int time; time = cent->currentState.time; //should the creep be growing or receding? if( time >= 0 ) { msec = cg.time - time; if( msec >= 0 && msec < scaleUpTime ) frac = (float)msec / scaleUpTime; else frac = 1.0f; } else if( time < 0 ) { msec = cg.time + time; if( msec >= 0 && msec < CREEP_SCALEDOWN_TIME ) frac = 1.0f - ( (float)msec / CREEP_SCALEDOWN_TIME ); else frac = 0.0f; } VectorCopy( cent->currentState.origin2, temp ); VectorScale( temp, -4096, temp ); VectorAdd( temp, cent->lerpOrigin, temp ); CG_Trace( &tr, cent->lerpOrigin, NULL, NULL, temp, cent->currentState.number, MASK_PLAYERSOLID ); VectorCopy( tr.endpos, origin ); size = CREEP_SIZE * frac; if( size > 0.0f ) CG_ImpactMark( cgs.media.creepShader, origin, cent->currentState.origin2, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, qfalse, size, qtrue ); }
/* ================ CG_FragmentBounceMark ================ */ void CG_FragmentBounceMark( localEntity_t *le, trace_t *trace ) { int radius; if ( le->leMarkType == LEMT_BLOOD ) { static int lastBloodMark; // don't drop too many blood marks if (!(lastBloodMark > cg.time || lastBloodMark > cg.time-100)) { radius = 16 + (rand()&31); CG_ImpactMark( cgs.media.bloodDotShaders[rand()%5], trace->endpos, trace->plane.normal, random()*360, 1,1,1,1, qtrue, radius, qfalse, cg_bloodTime.integer * 1000 ); lastBloodMark = cg.time; } } // don't allow a fragment to make multiple marks, or they // pile up while settling le->leMarkType = LEMT_NONE; }
/* ================ CG_ProjectedSpotLight ================ */ void CG_ProjectedSpotLight( vec3_t start, vec3_t dir ) { vec3_t end, proj; trace_t tr; float alpha, radius; VectorMA( start, 1000, dir, end ); CG_Trace( &tr, start, NULL, NULL, end, -1, CONTENTS_SOLID ); if ( tr.fraction == 1.0 ) { return; } // alpha = ( 1.0 - tr.fraction ); if ( alpha > 1.0 ) { alpha = 1.0; } // radius = 32 + 64 * tr.fraction; VectorNegate( dir, proj ); CG_ImpactMark( cgs.media.spotLightShader, tr.endpos, proj, 0, alpha, alpha, alpha, 1.0, qfalse, radius, qtrue, -2 ); }
void FX_GrenadeExplode( vec3_t origin, vec3_t normal ) { localEntity_t *le; FXTrail *fx; vec3_t direction, org; VectorSet( direction, 0,0,1 ); // Add an explosion and tag a light to it le = CG_MakeExplosion( origin, direction, cgs.media.nukeModel, 5, NULL, 250, qfalse, 25.0f, LEF_FADE_RGB ); le->light = 150; le->refEntity.renderfx |= RF_NOSHADOW; VectorSet( le->lightColor, 1.0f, 0.6f, 0.2f ); // Ground ring FX_AddQuad( origin, normal, NULL, NULL, 5, 330, 1.0, 0.0, random() * 360, 0, 0, 300, cgs.media.bigShockShader ); // Flare VectorMA( origin, 12, direction, org ); FX_AddSprite( org, NULL, NULL, 160.0, -540.0, 1.0, 0.0, 0.0, 0.0, 200, cgs.media.sunnyFlareShader ); for ( int i = 0; i < 12; i++) { fx = FX_AddTrail( origin, NULL, NULL, 24.0f + random() * 12, -40.0f, 0.5 + random() * 2, -3.0, 1.0f, 1.0f, 0.5f, 1000.0f, cgs.media.orangeTrailShader, rand() & FXF_BOUNCE ); if ( fx == NULL ) return; FXE_Spray( normal, 470, 325, 0.5f, 700, (FXPrimitive *) fx ); } cgi_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeExplodeSnd ); // Smoke and impact CG_ImpactMark( cgs.media.compressionMarkShader, origin, normal, random()*360, 1,1,1,1.0, qfalse, random() * 16 + 48, qfalse ); CG_ExplosionEffects( origin, 3.0f, 400 ); }
void FX_GrenadeExplode( vec3_t origin, vec3_t normal ) { localEntity_t *le; qhandle_t null = 0; vec3_t direction, org, vel; int i; VectorSet( direction, 0,0,1 ); // Add an explosion and tag a light to it le = CG_MakeExplosion2( origin, direction, cgs.media.nukeModel, 5, null, 250, qfalse, 25.0f, LEF_FADE_RGB); le->light = 150; le->refEntity.renderfx |= RF_NOSHADOW; VectorSet( le->lightColor, 1.0f, 0.6f, 0.2f ); // Ground ring FX_AddQuad( origin, normal, 5, 100, 1.0, 0.0, random() * 360, 300, cgs.media.bigShockShader ); // Flare VectorMA( origin, 12, direction, org ); FX_AddSprite( org, NULL, qfalse, 160.0, -160.0, 1.0, 0.0, 0.0, 0.0, 200, cgs.media.sunnyFlareShader );//, FXF_NON_LINEAR_FADE ); for (i = 0; i < 12; i++) { float width, length; FXE_Spray( normal, 470, 325, 0.5f, vel); length = 24.0 + random() * 12; width = 0.5 + random() * 2; FX_AddTrail( origin, vel, qtrue, length, -length, width, -width, 1.0f, 1.0f, 0.5f, 1000.0f, cgs.media.orangeTrailShader); } trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeExplodeSound ); // Smoke and impact // FX_AddSpawner( origin, normal, NULL, NULL, 100, 25.0f, 2000.0f, (void *) CG_SmokeSpawn, NULL, 1024 ); CG_ImpactMark( cgs.media.compressionMarkShader, origin, normal, random()*360, 1,1,1,1.0, qfalse, random() * 16 + 48, qfalse ); }
//----------------------------------- //By: RedTechie - Imported/Modifyed from SP //----------------------------------- void FX_GrenadeShrapnelExplode( vec3_t origin, vec3_t norm ) { localEntity_t *le; //FXTrail *fx; vec3_t direction, org, vel; int i; CG_InitLensFlare( origin, 350, 350, colorTable[CT_DKRED1], 1.2, 2.0, 1600, 200, colorTable[CT_DKRED1], 1600, 200, 800, 20, qtrue, 0, 0, qfalse, qtrue, qfalse, 1.0, cg.time, 90, 0, 300); //Orient the explosions to face the camera VectorSubtract( cg.refdef.vieworg, origin, direction ); VectorNormalize( direction ); VectorMA( origin, 12, direction, org ); // Add an explosion and tag a light to it le = CG_MakeExplosion2( org, direction, cgs.media.explosionModel, 6, cgs.media.surfaceExplosionShader, 700, qfalse, 1.2f + (random()*0.5f),LEF_FADE_RGB ); //RPG-X: RedTechie - Scale use to be 1.2f + (random()*0.3f) le->light = 150; le->refEntity.renderfx |= RF_NOSHADOW; VectorSet( le->lightColor, 1.0f, 0.6f, 0.6f ); VectorMA( org, 8, norm, direction ); VectorSet(vel, 0, 0, 8); //Some smoke FX_AddSprite( direction, vel, qfalse, 20.0f + random()*50.0f,//1.2f + (random()*0.5f),//60.0f - random()*60.0f 16.0f, 100.0f,//1.0f 100.0f,//0.0f random()*45.0f, -12.0f, 8000.0f, cgs.media.steamShader ); for ( i = 0; i < 6; i++) { float width, length; FXE_Spray( norm, 500, 175, 0.8f, vel);//, (FXPrimitive *) fx length = 24.0 + random() * 12; width = 0.5 + random() * 2; FX_AddTrail( origin, vel, qtrue, length, -length, width, -width, 1.0f, 1.0f, 0.5f, 2500.0f, cgs.media.orangeTrailShader);//RPG-X: RedTechie - Killtime use to be 1000.0f /*FX_AddTrail( origin, NULL, NULL, 16.0f, -15.0f, 1.5, -1.5, 1.0f, 1.0f, 0.2f, 1000.0f, cgs.media.orangeTrailShader, rand() & FXF_BOUNCE ); */ /*if ( fx == NULL ) return;*/ } trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeAltExplodeSnd ); CG_ImpactMark( cgs.media.compressionMarkShader, origin, norm, random()*360, 1,1,1,1.0, qfalse, random() * 16 + 48, qfalse ); CG_ExplosionEffects( origin, 2.0, 350 ); }
void CG_GibPlayer(centity_t *cent, vec3_t playerOrigin, vec3_t gdir) { int i, count = 0, tagIndex, gibIndex; vec3_t origin, velocity, dir; trace_t trace; qboolean foundtag; clientInfo_t *ci; int clientNum; bg_character_t *character; vec4_t projection, color; // Rafael // BloodCloud qboolean newjunction[MAXJUNCTIONS]; vec3_t junctionOrigin[MAXJUNCTIONS]; int junction; int j; vec3_t axis[3], angles; char *JunctiongibTags[] = { // leg tag "tag_footright", "tag_footleft", "tag_legright", "tag_legleft", // torsotags "tag_armright", "tag_armleft", "tag_torso", "tag_chest" }; char *ConnectTags[] = { // legs tags "tag_legright", "tag_legleft", "tag_torso", "tag_torso", // torso tags "tag_chest", "tag_chest", "tag_chest", "tag_torso", }; char *gibTags[] = { // tags in the legs "tag_footright", "tag_footleft", "tag_legright", "tag_legleft", "tag_torso", // tags in the torso "tag_chest", "tag_armright", "tag_armleft", "tag_head", NULL }; if (cg_blood.integer) { // Rafael for (i = 0; i < MAXJUNCTIONS; i++) newjunction[i] = qfalse; clientNum = cent->currentState.clientNum; if (clientNum < 0 || clientNum >= MAX_CLIENTS) { CG_Error("Bad clientNum on player entity"); } ci = &cgs.clientinfo[clientNum]; character = CG_CharacterForClientinfo(ci, cent); // Ridah, fetch the various positions of the tag_gib*'s // and spawn the gibs from the correct places (especially the head) for (gibIndex = 0, count = 0, foundtag = qtrue; foundtag && gibIndex < MAX_GIB_MODELS && gibTags[gibIndex]; gibIndex++) { refEntity_t *re = 0; foundtag = qfalse; if (!character->gibModels[gibIndex]) { continue; } re = ¢->pe.bodyRefEnt; for (tagIndex = 0; (tagIndex = CG_GetOriginForTag(cent, re, gibTags[gibIndex], tagIndex, origin, axis)) >= 0; count++, tagIndex++) { foundtag = qtrue; VectorSubtract(origin, re->origin, dir); VectorNormalize(dir); // spawn a gib velocity[0] = dir[0] * (0.5 + random()) * GIB_VELOCITY * 0.3; velocity[1] = dir[1] * (0.5 + random()) * GIB_VELOCITY * 0.3; velocity[2] = GIB_JUMP + dir[2] * (0.5 + random()) * GIB_VELOCITY * 0.5; VectorMA(velocity, GIB_VELOCITY, gdir, velocity); AxisToAngles(axis, angles); CG_LaunchGib(cent, origin, angles, velocity, character->gibModels[gibIndex], 1.0, 0); for (junction = 0; junction < MAXJUNCTIONS; junction++) { if (!Q_stricmp(gibTags[gibIndex], JunctiongibTags[junction])) { VectorCopy(origin, junctionOrigin[junction]); newjunction[junction] = qtrue; } } } } for (i = 0; i < MAXJUNCTIONS; i++) { if (newjunction[i] == qtrue) { for (j = 0; j < MAXJUNCTIONS; j++) { if (!Q_stricmp(JunctiongibTags[j], ConnectTags[i])) { if (newjunction[j] == qtrue) { // spawn a blood cloud somewhere on the vec from VectorSubtract(junctionOrigin[i], junctionOrigin[j], dir); CG_ParticleBloodCloud(cent, junctionOrigin[i], dir); } } } } } // Ridah, spawn a bunch of blood dots around the place #define GIB_BLOOD_DOTS 3 for (i = 0, count = 0; i < GIB_BLOOD_DOTS * 2; i++) { // TTimo: unused //static vec3_t mins = {-10,-10,-10}; //static vec3_t maxs = { 10, 10, 10}; if (i > 0) { velocity[0] = ((i % 2) * 2 - 1) * (40 + 40 * random()); velocity[1] = (((i / 2) % 2) * 2 - 1) * (40 + 40 * random()); velocity[2] = (((i < GIB_BLOOD_DOTS) * 2) - 1) * 40; } else { VectorClear(velocity); velocity[2] = -64; } VectorAdd(playerOrigin, velocity, origin); CG_Trace(&trace, playerOrigin, NULL, NULL, origin, -1, CONTENTS_SOLID); if (trace.fraction < 1.0) { //% BG_GetMarkDir( velocity, trace.plane.normal, velocity ); //% CG_ImpactMark( cgs.media.bloodDotShaders[rand()%5], trace.endpos, velocity, random()*360, //% 1,1,1,1, qtrue, 30, qfalse, cg_bloodTime.integer * 1000 ); #if 0 BG_GetMarkDir(velocity, trace.plane.normal, projection); VectorSubtract(vec3_origin, projection, projection); projection[3] = 64; VectorMA(trace.endpos, -8.0f, projection, markOrigin); CG_ImpactMark(cgs.media.bloodDotShaders[rand() % 5], markOrigin, projection, 30.0f, random() * 360.0f, 1.0f, 1.0f, 1.0f, 1.0f, cg_bloodTime.integer * 1000); #else VectorSet(projection, 0, 0, -1); projection[3] = 30.0f; Vector4Set(color, 1.0f, 1.0f, 1.0f, 1.0f); trap_R_ProjectDecal(cgs.media.bloodDotShaders[rand() % 5], 1, (vec3_t *) trace.endpos, projection, color, cg_bloodTime.integer * 1000, (cg_bloodTime.integer * 1000) >> 4); #endif if (count++ > GIB_BLOOD_DOTS) { break; } } } }
void CG_FragmentBounceMark( localEntity_t *le, trace_t *trace ) { if ( le->leMarkType == LEMT_BLOOD ) CG_ImpactMark( cgs.media.bloodMarkShader, &trace->endpos, &trace->plane.normal, random()*360, 1, 1, 1, 1, qtrue, 16.0f+flrand( 0, 31 ), qfalse ); else if ( le->leMarkType == LEMT_BURN ) CG_ImpactMark( cgs.media.burnMarkShader, &trace->endpos, &trace->plane.normal, random()*360, 1, 1, 1, 1, qtrue, 8.0f+flrand( 0, 15 ), qfalse ); le->leMarkType = LEMT_NONE; // don't allow a fragment to make multiple marks, or they pile up while settling }
void FX_PhaserFire( vec3_t startpos, vec3_t endpos, vec3_t normal, qboolean spark, qboolean impact, qboolean empty ) { refEntity_t beam; sfxHandle_t sfx; float size; vec3_t velocity; int sparks; vec3_t rgb = { 1,0.9,0.6}, rgb2={1,0.3,0}; //vec3_t rgb3 = { 1.0, 1.0, 1.0 }; sfx = 0; // Draw beam first. memset( &beam, 0, sizeof( beam ) ); VectorCopy( startpos, beam.origin); VectorCopy( endpos, beam.oldorigin ); beam.reType = RT_LINE; if (empty) { beam.customShader = cgs.media.phaserEmptyShader; } else { beam.customShader = cgs.media.phaserShader; } AxisClear( beam.axis ); beam.shaderRGBA[0] = 0xff; beam.shaderRGBA[1] = 0xff; beam.shaderRGBA[2] = 0xff; beam.shaderRGBA[3] = 0xff; if (empty) { beam.data.line.width = 1.0f + ( crandom() * 0.6f ); } else { beam.data.line.width = 2.0f + ( crandom() * 0.6f ); } beam.data.line.stscale = 5.0; trap_R_AddRefEntityToScene( &beam ); // Now draw the hit graphic // no explosion at LG impact, it is added with the beam if ( sfx ) { Com_Printf("playing %s\n", "phaser sound"); trap_S_StartSound( endpos, ENTITYNUM_WORLD, CHAN_AUTO, sfx ); } // // impact mark // if (impact) { if (!empty) { // normal. CG_ImpactMark( cgs.media.scavMarkShader, endpos, normal, random()*360, 1,1,1,0.2, qfalse, random() + 1, qfalse ); //VectorCopy( endpos, phaserFlare.worldCoord ); /*CG_InitLensFlare( endpos, 80, 80, rgb, 1.2, 1.5, 1600, 200, colorTable[CT_BLACK], 1600, 200, 80, 5, qfalse, 5, 40, qfalse, qfalse, qfalse, 1.0, 1.0, 200.0, 200.0, 200.0 );*/ //CG_InitLensFlare( endpos, // 30, 30, // rgb, 1.2, 2.0, 1600, 200, // colorTable[CT_BLACK], 1600, 200, 410, 15, qfalse, // 0, 0, qfalse, qtrue, // qfalse, 1.0, cg.time, 0, 0, 50); //TiM : Add your basic cheesy 'seen-way-too-much-in-movies-these-days' anamorphic lens streak :) //CG_DrawLensFlare( &phaserFlare ); //FX_AddSprite( endpos, NULL, qfalse, random() * 1.25 + 5.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 50.0, cgs.media.blueParticleStreakShader ); //1.5f //FX_AddQuad2( endpos, normal, random() * 1.25 + 8.0f, 0.0f, 1.0f, 1.0f, rgb3, rgb3, 270, 50.0, cgs.media.blueParticleStreakShader ); //eh... looked bad :P FX_AddQuad2( endpos, normal, random() * 1.25 + 1.5f, 0.0f, 1.0f, 0.0f, rgb, rgb2, rand() % 360, 500 + random() * 200, cgs.media.sunnyFlareShader ); } else { // Wuss hit when empty. FX_AddQuad2( endpos, normal, random() * .75 + 1.0f, 0.0f, 0.5f, 0.0f, rgb, rgb2, rand() % 360, 300 + random() * 200, cgs.media.sunnyFlareShader ); } } // "Fun" sparks... Not when empty. if ( spark && !empty) { sparks = (rand() & 1) + 1; for(;sparks>0;sparks--) { size = 0.2f + (random() * 0.4); FXE_Spray( normal, 200, 75, 0.8f, velocity); if (rand() & LEF_USE_COLLISION) { // This spark bounces. FX_AddTrail( endpos, velocity, qtrue, 5.0f, -15.0f, size, -size, 1.0f, 0.5f, 0.4f, 500.0f, cgs.media.sparkShader); } else { FX_AddTrail( endpos, velocity, qtrue, 5.0f, -15.0f, size, -size, 1.0f, 0.5f, 0.0, 500.0f, cgs.media.sparkShader); } } } }
void FX_PhaserAltFire( vec3_t start, vec3_t end, vec3_t normal, qboolean spark, qboolean impact, qboolean empty ) { float scale = flrandom(13.0f, 17.0f), scale2 = flrandom(2.0f, 6.0f); vec3_t vel, diff, end2; int i = 0, sparks = 0; refEntity_t beam; vec3_t rgb = { 1,0.6,0.5}, rgb2={1,0.3,0}; float len; int color; VectorSubtract(end, start, diff); len = VectorNormalize(diff); color = 0xff * flrandom(0.75, 1.0); if (empty) { // More faint and shaky line. scale *= flrandom(0.25,0.75); } if (len > PHASER_ALT_CONE_LEN) { // Draw beam in two parts... // Draw main beam first. VectorMA(start, PHASER_ALT_CONE_LEN, diff, end2); // Draw starting cone memset( &beam, 0, sizeof( beam ) ); VectorCopy( start, beam.origin); VectorCopy( end2, beam.oldorigin ); beam.reType = RT_LINE2; if (empty) { beam.customShader = cgs.media.phaserAltEmptyShader; } else { beam.customShader = cgs.media.phaserAltShader; } AxisClear( beam.axis ); beam.shaderRGBA[0] = 0xff; beam.shaderRGBA[1] = 0xff*0.3; beam.shaderRGBA[2] = 0; beam.shaderRGBA[3] = 0xff; beam.data.line.width = scale*0.1; beam.data.line.width2 = scale; beam.data.line.stscale = 1.0; trap_R_AddRefEntityToScene( &beam ); // Draw big thick normal beam for the rest. memset( &beam, 0, sizeof( beam ) ); VectorCopy( end2, beam.oldorigin); VectorCopy( end, beam.origin ); beam.reType = RT_LINE; if (empty) { beam.customShader = cgs.media.phaserAltEmptyShader; } else { beam.customShader = cgs.media.phaserAltShader; } AxisClear( beam.axis ); beam.shaderRGBA[0] = 0xff; beam.shaderRGBA[1] = 0xff*0.3; beam.shaderRGBA[2] = 0; beam.shaderRGBA[3] = 0xff; beam.data.line.width = scale; beam.data.line.stscale = 1.0; trap_R_AddRefEntityToScene( &beam ); // Draw beam core, all one bit. memset( &beam, 0, sizeof( beam ) ); VectorCopy( start, beam.origin); VectorCopy( end, beam.oldorigin ); beam.reType = RT_LINE2; beam.customShader = cgs.media.phaserShader; AxisClear( beam.axis ); beam.shaderRGBA[0] = color*0.75f; beam.shaderRGBA[1] = 0xff*0.5f; beam.shaderRGBA[2] = 0xff*0.5f; beam.shaderRGBA[3] = 0xff; beam.data.line.width = scale2*0.2; beam.data.line.width2 = scale2; beam.data.line.stscale = 1.0; trap_R_AddRefEntityToScene( &beam ); } else { // Draw beam in two parts... // Draw beam first. memset( &beam, 0, sizeof( beam ) ); VectorCopy( start, beam.origin); VectorCopy( end, beam.oldorigin ); beam.reType = RT_LINE2; beam.customShader = cgs.media.phaserAltShader; AxisClear( beam.axis ); beam.shaderRGBA[0] = 0xff; beam.shaderRGBA[1] = 0xff*0.3; beam.shaderRGBA[2] = 0; beam.shaderRGBA[3] = 0xff; beam.data.line.width = scale*0.1; beam.data.line.width2 = scale; beam.data.line.stscale = 1.0; trap_R_AddRefEntityToScene( &beam ); // just one beam is never enough memset( &beam, 0, sizeof( beam ) ); VectorCopy( start, beam.origin); VectorCopy( end, beam.oldorigin ); beam.reType = RT_LINE2; beam.customShader = cgs.media.phaserShader; AxisClear( beam.axis ); beam.shaderRGBA[0] = color*0.75f; beam.shaderRGBA[1] = 0xff*0.5f; beam.shaderRGBA[2] = 0xff*0.5f; beam.shaderRGBA[3] = 0xff; beam.data.line.width = scale2*0.2; beam.data.line.width2 = scale2; beam.data.line.stscale = 1.0; trap_R_AddRefEntityToScene( &beam ); } // Phaser beam // FX_AddLine( start, end, 1.0f, scale, 0.0f, 0.9f, 0.9f, 2, cgs.media.phaserShader ); // FX_AddLine( start, end, 1.0f, scale * 0.5f, 0.0f, 0.8f, 0.8f, 2, cgs.media.phaserShader ); // Per frame impact mark FX_AddQuad( end, normal, random() * 1.5 + 1.75f, 0.0f, 1.0f, 0.0f, 0.0f, 1, cgs.media.sparkShader ); FX_AddQuad( end, normal, random() * 5 + 2.75f, 0.0f, 1.0f, 0.0f, 0.0f, 1, cgs.media.yellowParticleShader ); // Multi frame impacts--never do this when it hits a player because it will just look stupid if ( impact ) { FX_AddQuad2( end, normal, random() * 2.0 + 5.0f, 2.5f, 0.6f, 0.0f, rgb, rgb2, 0.0f, 500 + random() * 200, cgs.media.sunnyFlareShader ); CG_ImpactMark( cgs.media.scavMarkShader, end, normal, random()*360, 1,1,1,0.1, qfalse, random() + 6.0, qfalse ); } // "Fun" sparks if ( spark ) { // kef -- fixme. dunno what the deal is with this velocity vector VectorClear(vel); sparks = (rand() & 3) + 1; // Set random starting pos... end2[0] = flrandom(-1.0, 1.0) + end[0]; end2[1] = flrandom(-1.0, 1.0) + end[1]; end2[2] = flrandom(-1.0, 1.0) + end[2]; for( i = 0; i < sparks; i++ ) { scale = 0.5f + (random() * 0.5); FXE_Spray( normal, 200, 75, 0.8f, /*1024*/vel); FX_AddTrail2( end2, vel, qfalse, 8.0f, -8.0f, scale, -scale, 0.5f, 0.0f, rgb, rgb2, 0.4f, 500.0f, cgs.media.sparkShader ); } VectorMA(end, -8, diff, end2); // Add a hit sprite over everything... memset( &beam, 0, sizeof( beam ) ); VectorCopy( end2, beam.origin); beam.reType = RT_SPRITE; beam.customShader = cgs.media.sunnyFlareShader; AxisClear( beam.axis ); beam.shaderRGBA[0] = 0xff*1.0f; beam.shaderRGBA[1] = 0xff*0.9f; beam.shaderRGBA[2] = 0xff*0.8f; beam.shaderRGBA[3] = 0xff; beam.data.sprite.radius = random()*2.0 + 9.0; trap_R_AddRefEntityToScene( &beam ); } }
void CG_Spotlight( centity_t *cent, float *color, vec3_t realstart, vec3_t lightDir, int segs, float range, int startWidth, float coneAngle, int flags ) { int i, j; vec3_t start, traceEnd, proj; vec3_t right, up; vec3_t v1, v2; vec3_t startvec, endvec; // the vectors to rotate around lightDir to create the circles vec3_t conevec; vec3_t start_points[MAX_SPOT_SEGS], end_points[MAX_SPOT_SEGS]; vec3_t coreright; polyVert_t verts[MAX_SPOT_SEGS * 4]; // x4 for 4 verts per poly polyVert_t plugVerts[MAX_SPOT_SEGS]; vec3_t endCenter; polyVert_t coreverts[4]; trace_t tr; float alpha; float radius = 0.0; // TTimo might be used uninitialized float coreEndRadius; qboolean capStart = qtrue; float hitDist; // the actual distance of the trace impact (0 is no hit) float beamLen; // actual distance of the drawn beam float endAlpha = 0.0; vec4_t colorNorm; // normalized color vector refEntity_t ent; vec3_t angles; VectorCopy( realstart, start ); // normalize color colorNorm[3] = 0; // store normalize multiplier in alpha index for ( i = 0; i < 3; i++ ) { if ( color[i] > colorNorm[3] ) { colorNorm[3] = color[i]; // find largest color value in RGB } } if ( colorNorm[3] != 1 ) { // it needs to be boosted VectorMA( color, 1.0 / colorNorm[3], color, colorNorm ); // FIXME: div by 0 } else { VectorCopy( color, colorNorm ); } colorNorm[3] = color[3]; if ( flags & SL_NOSTARTCAP ) { capStart = qfalse; } if ( startWidth == 0 ) { // cone, not cylinder capStart = qfalse; } if ( flags & SL_LOCKTRACETORANGE ) { VectorMA( start, range, lightDir, traceEnd ); // trace out to 'range' } else { VectorMA( start, MAX_SPOT_RANGE, lightDir, traceEnd ); // trace all the way out to max dist } // first trace to see if anything is hit if ( flags & SL_NOTRACE ) { tr.fraction = 1.0; // force no hit } else { if ( flags & SL_TRACEWORLDONLY ) { CG_Trace( &tr, start, NULL, NULL, traceEnd, -1, CONTENTS_SOLID ); } else { CG_Trace( &tr, start, NULL, NULL, traceEnd, -1, MASK_SHOT ); } // CG_Trace( &tr, start, NULL, NULL, traceEnd, -1, MASK_ALL &~(CONTENTS_MONSTERCLIP|CONTENTS_AREAPORTAL|CONTENTS_CLUSTERPORTAL)); } if ( tr.fraction < 1.0 ) { hitDist = beamLen = MAX_SPOT_RANGE * tr.fraction; if ( beamLen > range ) { beamLen = range; } } else { hitDist = 0; beamLen = range; } if ( flags & SL_LOCKUV ) { if ( beamLen < range ) { endAlpha = 255.0f * ( color[3] - ( color[3] * beamLen / range ) ); } } if ( segs >= MAX_SPOT_SEGS ) { segs = MAX_SPOT_SEGS - 1; } // TODO: adjust segs based on r_lodbias // TODO: move much of this to renderer // model at base if ( cent->currentState.modelindex ) { memset( &ent, 0, sizeof( ent ) ); ent.frame = 0; ent.oldframe = 0; ent.backlerp = 0; VectorCopy( cent->lerpOrigin, ent.origin ); VectorCopy( cent->lerpOrigin, ent.oldorigin ); ent.hModel = cgs.gameModels[cent->currentState.modelindex]; // AnglesToAxis( cent->lerpAngles, ent.axis ); vectoangles( lightDir, angles ); AnglesToAxis( angles, ent.axis ); trap_R_AddRefEntityToScene( &ent ); memcpy( ¢->refEnt, &ent, sizeof( refEntity_t ) ); // push start out a bit so the beam fits to the front of the base model VectorMA( start, 14, lightDir, start ); } //// BEAM PerpendicularVector( up, lightDir ); CrossProduct( lightDir, up, right ); // find first vert of the start VectorScale( right, startWidth, startvec ); // find the first vert of the end RotatePointAroundVector( conevec, up, lightDir, -coneAngle ); VectorMA( startvec, beamLen, conevec, endvec ); // this applies the offset of the start diameter before finding the end points VectorScale( lightDir, beamLen, endCenter ); VectorSubtract( endCenter, endvec, coreverts[3].xyz ); // get a vector of the radius out at the end for the core to use coreEndRadius = VectorLength( coreverts[3].xyz ); #define CORESCALE 0.6f // // generate the flat beam 'core' // if ( !( flags & SL_NOCORE ) ) { VectorSubtract( start, cg.refdef.vieworg, v1 ); VectorNormalize( v1 ); VectorSubtract( traceEnd, cg.refdef.vieworg, v2 ); VectorNormalize( v2 ); CrossProduct( v1, v2, coreright ); VectorNormalize( coreright ); memset( &coreverts[0], 0, 4 * sizeof( polyVert_t ) ); VectorMA( start, startWidth * 0.5f, coreright, coreverts[0].xyz ); VectorMA( start, -startWidth * 0.5f, coreright, coreverts[1].xyz ); VectorMA( endCenter, -coreEndRadius * CORESCALE, coreright, coreverts[2].xyz ); VectorAdd( start, coreverts[2].xyz, coreverts[2].xyz ); VectorMA( endCenter, coreEndRadius * CORESCALE, coreright, coreverts[3].xyz ); VectorAdd( start, coreverts[3].xyz, coreverts[3].xyz ); for ( i = 0; i < 4; i++ ) { coreverts[i].modulate[0] = color[0] * 200.0f; coreverts[i].modulate[1] = color[1] * 200.0f; coreverts[i].modulate[2] = color[2] * 200.0f; coreverts[i].modulate[3] = color[3] * 200.0f; if ( i > 1 ) { coreverts[i].modulate[3] = 0; } } trap_R_AddPolyToScene( cgs.media.spotLightBeamShader, 4, &coreverts[0] ); } // // generate the beam cylinder // for ( i = 0; i <= segs; i++ ) { RotatePointAroundVector( start_points[i], lightDir, startvec, ( 360.0f / (float)segs ) * i ); VectorAdd( start_points[i], start, start_points[i] ); RotatePointAroundVector( end_points[i], lightDir, endvec, ( 360.0f / (float)segs ) * i ); VectorAdd( end_points[i], start, end_points[i] ); } for ( i = 0; i < segs; i++ ) { j = ( i * 4 ); VectorCopy( start_points[i], verts[( i * 4 )].xyz ); verts[j].st[0] = 0; verts[j].st[1] = 1; verts[j].modulate[0] = color[0] * 255.0f; verts[j].modulate[1] = color[1] * 255.0f; verts[j].modulate[2] = color[2] * 255.0f; verts[j].modulate[3] = color[3] * 255.0f; j++; VectorCopy( end_points[i], verts[j].xyz ); verts[j].st[0] = 0; verts[j].st[1] = 0; verts[j].modulate[0] = color[0] * 255.0f; verts[j].modulate[1] = color[1] * 255.0f; verts[j].modulate[2] = color[2] * 255.0f; verts[j].modulate[3] = endAlpha; j++; VectorCopy( end_points[i + 1], verts[j].xyz ); verts[j].st[0] = 1; verts[j].st[1] = 0; verts[j].modulate[0] = color[0] * 255.0f; verts[j].modulate[1] = color[1] * 255.0f; verts[j].modulate[2] = color[2] * 255.0f; verts[j].modulate[3] = endAlpha; j++; VectorCopy( start_points[i + 1], verts[j].xyz ); verts[j].st[0] = 1; verts[j].st[1] = 1; verts[j].modulate[0] = color[0] * 255.0f; verts[j].modulate[1] = color[1] * 255.0f; verts[j].modulate[2] = color[2] * 255.0f; verts[j].modulate[3] = color[3] * 255.0f; if ( capStart ) { VectorCopy( start_points[i], plugVerts[i].xyz ); plugVerts[i].st[0] = 0; plugVerts[i].st[1] = 0; plugVerts[i].modulate[0] = color[0] * 255.0f; plugVerts[i].modulate[1] = color[1] * 255.0f; plugVerts[i].modulate[2] = color[2] * 255.0f; plugVerts[i].modulate[3] = color[3] * 255.0f; } } trap_R_AddPolysToScene( cgs.media.spotLightBeamShader, 4, &verts[0], segs ); // plug up the start circle if ( capStart ) { trap_R_AddPolyToScene( cgs.media.spotLightBeamShader, segs, &plugVerts[0] ); } // show the endpoint if ( !( flags & SL_NOIMPACT ) ) { if ( hitDist ) { VectorMA( startvec, hitDist, conevec, endvec ); alpha = 0.3f; radius = coreEndRadius * ( hitDist / beamLen ); VectorNegate( lightDir, proj ); CG_ImpactMark( cgs.media.spotLightShader, tr.endpos, proj, 0, colorNorm[0], colorNorm[1], colorNorm[2], alpha, qfalse, radius, qtrue, -1 ); } } // add d light at end if ( !( flags & SL_NODLIGHT ) ) { vec3_t dlightLoc; // VectorMA(tr.endpos, -60, lightDir, dlightLoc); // back away from the hit // trap_R_AddLightToScene(dlightLoc, 200, colorNorm[0], colorNorm[1], colorNorm[2], 0); // ,REF_JUNIOR_DLIGHT); VectorMA( tr.endpos, 0, lightDir, dlightLoc ); // back away from the hit // trap_R_AddLightToScene(dlightLoc, radius*2, colorNorm[0], colorNorm[1], colorNorm[2], 0); // ,REF_JUNIOR_DLIGHT); trap_R_AddLightToScene( dlightLoc, radius * 2, 0.3, 0.3, 0.3, 0 ); // ,REF_JUNIOR_DLIGHT); } // draw flare at source if ( !( flags & SL_NOFLARE ) ) { qboolean lightInEyes = qfalse; vec3_t camloc, dirtolight; float dot, deg, dist; float flarescale = 0.0; // TTimo: might be used uninitialized // get camera position and direction to lightsource VectorCopy( cg.snap->ps.origin, camloc ); camloc[2] += cg.snap->ps.viewheight; VectorSubtract( start, camloc, dirtolight ); dist = VectorNormalize( dirtolight ); // first use dot to determine if it's facing the camera dot = DotProduct( lightDir, dirtolight ); // it's facing the camera, find out how closely and trace to see if the source can be seen deg = RAD2DEG( M_PI - acos( dot ) ); if ( deg <= 35 ) { // start flare a bit before the camera gets inside the cylinder lightInEyes = qtrue; flarescale = 1 - ( deg / 35 ); } if ( lightInEyes ) { // the dot check succeeded, now do a trace CG_Trace( &tr, start, NULL, NULL, camloc, -1, MASK_ALL & ~( CONTENTS_MONSTERCLIP | CONTENTS_AREAPORTAL | CONTENTS_CLUSTERPORTAL ) ); if ( tr.fraction != 1 ) { lightInEyes = qfalse; } } if ( lightInEyes ) { float coronasize = flarescale; if ( dist < 512 ) { // make even bigger if you're close enough coronasize *= ( 512.0f / dist ); } trap_R_AddCoronaToScene( start, colorNorm[0], colorNorm[1], colorNorm[2], coronasize, cent->currentState.number, qtrue ); } else { // even though it's off, still need to add it, but turned off so it can fade in/out properly trap_R_AddCoronaToScene( start, colorNorm[0], colorNorm[1], colorNorm[2], 0, cent->currentState.number, qfalse ); } } }
//------------------------------------------------ void FX_ParasiteAcidHitWall( vec3_t origin, vec3_t dir ) //------------------------------------------------ { FXTrail *particle; float detail; vec3_t rgb={0.2f,0.8f,0.0f}; int i; // Spawn some smoke from the acid burn for ( i = 0; i < 4; i ++ ) { CG_Smoke( origin, dir, random() * 4.0f + 8.0f, random() * 16.0f + 2.0f, cgs.media.steamShader ); } FX_AddQuad( origin, dir, NULL, NULL, 4.0, 6.0, 0.5, 0.0, rgb, rgb, 0.0, 0.0, 0.0, 550, cgs.media.waterDropShader ); // Leave a melted spot CG_ImpactMark( cgs.media.bulletmarksShader, origin, dir, random()*360, 1,1,1,0.2f, qfalse, random() * 3.0f + 8.0, qfalse ); //Sound cgi_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cg_weapons[WP_PARASITE].missileHitSound ); // See if it's worth doing a splash detail = FX_DetailLevel( origin, 16, 400 ); if (detail == 0) return; // splash the acid for ( i = 0; i < 10; i++ ) { particle = FX_AddTrail( origin, NULL, NULL, 3.0f, -1.0f, 2.0, -1.0, 0.3f, 0.1f, rgb, rgb, 0.4f, 500.0f, cgs.media.waterDropShader, rand() & FXF_BOUNCE ); if ( particle != NULL ) { FXE_Spray( dir, 80, 100, 0.95f, 512, (FXPrimitive *) particle ); } } // Make a real splash vec3_t org; FXSprite *fx; vec3_t moveDir; vec3_t accel = { 0, 0, -400 }; for ( i = 0; i < 6; i++ ) { VectorSet( org, origin[0] + crandom() * 2.5f, origin[1] + crandom() * 2.5f, origin[2] + crandom() * 2.5f ); for ( int j = 0; j < 3; j++ ) { moveDir[j] = crandom() * 55.0; } moveDir[2] += 120.0f; VectorSet( rgb, random() * 0.3f + 0.2f, random() * 0.4f + 0.5f, random() * 0.2f + 0.05f ); fx = FX_AddSprite( org, moveDir, accel, 2.0f + ( random() * 1.0f ), -2.0f, 1.0f, 1.0f, rgb, rgb, 0, 0.0f, 400 + random() * 700, cgs.media.spooShader ); if ( fx == NULL ) return; fx->SetRoll( 0 ); } }
void FX_DisruptorWeaponHitWall( vec3_t origin, vec3_t dir, int size ) { vec3_t vel, /*accel,*/ hitpos, direction, org; //int i, t; weaponInfo_t *weaponInfo = &cg_weapons[WP_10]; CG_InitLensFlare( origin, 375, 375, colorTable[CT_GREEN], 1.2, 2.0, 1600, 200, colorTable[CT_GREEN], 1600, 200, 800, 20, qtrue, 0, 0, qfalse, qtrue, qfalse, 1.0, cg.time, 0, 0, 200); // Generate "crawling" electricity // eh, don't it doesn't look that great. FX_DisruptorDischarge( origin, dir, NUM_DISCHARGES, DISCHARGE_DIST, DISCHARGE_SIDE_DIST ); VectorMA(origin, size, dir, hitpos); // Set an oriented residual glow effect FX_AddQuad( hitpos, dir, size * size * 15.0f, -150.0f, 1.0f, 0.0f, 0, 300, cgs.media.greenParticleShader ); CG_ImpactMark( cgs.media.scavMarkShader, origin, dir, random()*360, 1,1,1,0.6, qfalse, size * 12 + 1, qfalse ); FX_AddSprite( hitpos, NULL, qfalse, size * size * 15.0f, -150.0f, 1.0f, 0.0f, 360*random(), 0, 400, cgs.media.greenParticleShader ); /* FX_AddSprite( hitpos, NULL, qfalse, size * size * 15.0f, -150.0f, 1.0f, 0.0f, 360*random(), 0, 400, cgs.media.greenParticleStreakShader ); */ FX_AddSprite( hitpos, NULL, qfalse, size * size * 25.0f, -150.0f, 1.0f, 0.0f, 0.0f, 0, 400, cgs.media.greenParticleStreakShader ); VectorSubtract( cg.refdef.vieworg, origin, direction ); VectorNormalize( direction ); VectorMA( origin, 12, direction, org ); VectorMA( org, 8, dir, direction ); VectorSet(vel, 0, 0, 32 ); //8 FX_AddSprite( origin, vel, qfalse, random() * 4 + 2, 12, 0.6 + random() * 0.4, 0.0, random() * 180, 0.0, random() * 200 + 1200, //300 cgs.media.steamShader ); //FX_AddSprite( // Only play the impact sound and throw off the purple particles when it's the main projectile /* if ( size < 3 ) return; for ( i = 0; i < 4; i++ ) { for ( t = 0; t < 3; t++ ) vel[t] = ( dir[t] + crandom() * 0.9 ) * ( random() * 100 + 250 ); VectorScale( vel, -2.2, accel ); FX_AddSprite( hitpos, vel, qfalse, random() * 8 + 8, 0, 1.0, 0.0, 0.0, 0.0, 200, cgs.media.purpleParticleShader ); }*/ trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, weaponInfo->mainHitSound ); }
/* ------------------------- FX_fxfunc_Explosion ------------------------- */ void FX_fxfunc_Explosion( vec3_t start, vec3_t origin, vec3_t normal ) { localEntity_t *le; vec3_t dir; vec3_t velocity; // vec3_t end; // trace_t trace; float scale; int i, j, numSparks; //weaponInfo_t *weaponInfo = &cg_weapons[WP_6]; //float scale, dscale; // int s; // vec3_t new_org; //Sparks numSparks = 20 + (random() * 4.0f);//4 for ( i = 0; i < numSparks; i++ ) { scale = 0.25f + (random() * 1.0f); //Randomize the direction for (j = 0; j < 3; j ++ ) { dir[j] = normal[j] + (0.75 * crandom()); } VectorNormalize(dir); //set the speed VectorScale( dir, 200 + (50 * crandom()), velocity); le = FX_AddTrail( origin, velocity, qtrue, 4.0f, -4.0f, scale, -scale, 1.0f, 1.0f, 0.5f, 1000.0f, cgs.media.sparkShader); } VectorMA( origin, 8, normal, dir ); VectorSet(velocity, 0, 0, 8); // Smoke puffs FX_AddSprite( dir, velocity, qfalse, 20.0f + random()*60.0f,//2.2f + ( crandom() * 0.9f),//60.0f - random()*60.0f 16.0f, 100.0f,//1.0f 100.0f,//0.0f random()*45.0f, -12.0f, 8000.0f, cgs.media.steamShader ); //Orient the explosions to face the camera VectorSubtract( cg.refdef.vieworg, origin, dir ); VectorNormalize( dir ); le = CG_MakeExplosion2( origin, dir, cgs.media.explosionModel, 5, cgs.media.electricalExplosionSlowShader, 475, qfalse, 2.2f + ( crandom() * 0.9f), LEF_NONE);//RPG-X: RedTechie - Scale use to be - 1.2f + ( crandom() * 0.3f) le->light = 150; le->refEntity.renderfx |= RF_NOSHADOW; VectorSet( le->lightColor, 0.8f, 0.8f, 1.0f ); CG_ImpactMark( cgs.media.compressionMarkShader, origin, normal, random()*360, 1,1,1,1.0, qfalse, random() * 16 + 48, qfalse ); //CG_ImpactMark( cgs.media.compressionMarkShader, origin, normal, random()*360, 1,1,1,1, qfalse, 12, qfalse ); //Shake the camera CG_ExplosionEffects( origin, 2, 400 ); // nice explosion sound at the point of impact trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeAltExplodeSnd ); //trap_S_StartSound(origin, ENTITYNUM_WORLD, CHAN_AUTO, weaponInfo->mainHitSound); }
static void CG_RainParticleRender(cg_atmosphericParticle_t * particle) { // Draw a raindrop vec3_t forward, right; polyVert_t verts[4]; vec2_t line; float len, frac; vec3_t start, finish; if (!particle->active) return; VectorCopy(particle->pos, start); len = particle->height; if (start[2] <= particle->minz) { // Stop rain going through surfaces. len = particle->height - particle->minz + start[2]; frac = start[2]; VectorMA(start, len - particle->height, particle->deltaNormalized, start); if (!cg_lowEffects.integer) { frac = (ATMOSPHERIC_CUTHEIGHT - particle->minz + frac) / (float) ATMOSPHERIC_CUTHEIGHT; // Splash effects on different surfaces if (particle->contents & (CONTENTS_WATER | CONTENTS_SLIME)) { // Water splash if (cg_atmFx.effectwatershader && frac > 0 && frac < 1) CG_EffectMark(cg_atmFx.effectwatershader, start, particle->surfacenormal, frac * 0.5, 8 - frac * 8); } else if (!(particle->contents & CONTENTS_LAVA) && !(particle-> surface & (SURF_NODAMAGE | SURF_NOIMPACT | SURF_NOMARKS | SURF_SKY))) { // Solid splash if (cg_atmFx.effectlandshader && frac > 0 && frac < 1) CG_ImpactMark(cg_atmFx.effectlandshader, start, particle->surfacenormal, 0, 1, 1, 1, frac * 0.5, qfalse, 3 - frac * 2, qtrue); } } } if (len <= 0) return; VectorCopy(particle->deltaNormalized, forward); VectorMA(start, -len, forward, finish); line[0] = DotProduct(forward, cg.refdef.viewaxis[1]); line[1] = DotProduct(forward, cg.refdef.viewaxis[2]); VectorScale(cg.refdef.viewaxis[1], line[1], right); VectorMA(right, -line[0], cg.refdef.viewaxis[2], right); VectorNormalize(right); VectorMA(finish, particle->weight, right, verts[0].xyz); verts[0].st[0] = 1; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = 0; VectorMA(finish, -particle->weight, right, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 0; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = 0; VectorMA(start, -particle->weight, right, verts[2].xyz); verts[2].st[0] = 0; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = 127; VectorMA(start, particle->weight, right, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 1; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = 127; trap_R_AddPolyToScene(*particle->effectshader, 4, verts); }
/* ================= CG_MissileHitWall Caused by an EV_MISSILE_MISS event, or directly by local bullet tracing ================= */ void CG_MissileHitWall( weapon_t weaponNum, weaponMode_t weaponMode, int clientNum, vec3_t origin, vec3_t dir, impactSound_t soundType ) { qhandle_t mark = 0; qhandle_t ps = 0; int c; float radius = 1.0f; weaponInfo_t *weapon = &cg_weapons[ weaponNum ]; if( weaponMode <= WPM_NONE || weaponMode >= WPM_NUM_WEAPONMODES ) weaponMode = WPM_PRIMARY; mark = weapon->wim[ weaponMode ].impactMark; radius = weapon->wim[ weaponMode ].impactMarkSize; ps = weapon->wim[ weaponMode ].impactParticleSystem; if( soundType == IMPACTSOUND_FLESH ) { //flesh sound for( c = 0; c < 4; c++ ) { if( !weapon->wim[ weaponMode ].impactFleshSound[ c ] ) break; } if( c > 0 ) { c = rand( ) % c; if( weapon->wim[ weaponMode ].impactFleshSound[ c ] ) trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, weapon->wim[ weaponMode ].impactFleshSound[ c ] ); } } else { //normal sound for( c = 0; c < 4; c++ ) { if( !weapon->wim[ weaponMode ].impactSound[ c ] ) break; } if( c > 0 ) { c = rand( ) % c; if( weapon->wim[ weaponMode ].impactSound[ c ] ) trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, weapon->wim[ weaponMode ].impactSound[ c ] ); } } //create impact particle system if( ps ) { particleSystem_t *partSystem = CG_SpawnNewParticleSystem( ps ); if( CG_IsParticleSystemValid( &partSystem ) ) { CG_SetAttachmentPoint( &partSystem->attachment, origin ); CG_SetParticleSystemNormal( partSystem, dir ); CG_AttachToPoint( &partSystem->attachment ); } } // // impact mark // if( radius > 0.0f ) CG_ImpactMark( mark, origin, dir, random( ) * 360, 1, 1, 1, 1, qfalse, radius, qfalse ); }