/* Copyright (C) 1997-2001 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // cg_lents.c -- client side temporary entities #include "cg_local.h" #define MAX_BEAMS 32 #define MAX_LOCAL_ENTITIES 512 #define MAX_BEAMENTS 32 #define NUM_BEAM_SEGS 6 //splitmodels debrisbounce[start] static vec3_t debris_maxs = { 4, 4, 8 }; static vec3_t debris_mins = { -4, -4, 0 }; //[end] typedef enum { LE_FREE, LE_NO_FADE, LE_RGB_FADE, LE_ALPHA_FADE, LE_SCALE_ALPHA_FADE, LE_LASER } letype_t; typedef struct lentity_s { struct lentity_s *prev, *next; letype_t type; entity_t ent; vec4_t color; float start; float light; vec3_t lightcolor; vec3_t velocity; vec3_t accel; //splitmodels[start] int bounce; //is activator and bounceability value at once (debrisbounce) //[end] int frames; } lentity_t; typedef struct { int entity; int dest_entity; struct model_s *model; unsigned int endtime; vec3_t offset; vec3_t start, end; //wsw : jal (so electrotrail model isn't rotated) qboolean random_rotation; float model_length; // wsw : jal : custom shaders struct shader_s *shader; } beam_t; typedef struct { vec3_t verts[NUM_BEAM_SEGS][4]; vec2_t stcoords[NUM_BEAM_SEGS][4]; byte_vec4_t colors[NUM_BEAM_SEGS][4]; } cg_beament_t; lentity_t cg_localents[MAX_LOCAL_ENTITIES]; lentity_t cg_localents_headnode, *cg_free_lents; beam_t cg_beams[MAX_BEAMS]; cg_beament_t cg_beamEnts[MAX_BEAMENTS]; int cg_numBeamEnts; //================= //CG_ClearLocalEntities //================= void CG_ClearLocalEntities( void ) { int i; memset( cg_beams, 0, sizeof( cg_beams ) ); memset( cg_localents, 0, sizeof( cg_localents ) ); // link local entities cg_free_lents = cg_localents; cg_localents_headnode.prev = &cg_localents_headnode; cg_localents_headnode.next = &cg_localents_headnode; for( i = 0; i < MAX_LOCAL_ENTITIES - 1; i++ ) cg_localents[i].next = &cg_localents[i+1]; } //================= //CG_AllocLocalEntity //================= lentity_t *CG_AllocLocalEntity( int type, float r, float g, float b, float a ) { lentity_t *le; if ( cg_free_lents ) { // take a free decal if possible le = cg_free_lents; cg_free_lents = le->next; } else { // grab the oldest one otherwise le = cg_localents_headnode.prev; le->prev->next = le->next; le->next->prev = le->prev; } memset( le, 0, sizeof (*le) ); le->type = type; le->start = cg.time; le->color[0] = r; le->color[1] = g; le->color[2] = b; le->color[3] = a; switch( le->type ) { case LE_NO_FADE: break; case LE_RGB_FADE: le->ent.color[3] = ( qbyte )( 255 * a ); break; case LE_SCALE_ALPHA_FADE: case LE_ALPHA_FADE: le->ent.color[0] = ( qbyte )( 255 * r ); le->ent.color[1] = ( qbyte )( 255 * g ); le->ent.color[2] = ( qbyte )( 255 * b ); break; default: break; } // put the decal at the start of the list le->prev = &cg_localents_headnode; le->next = cg_localents_headnode.next; le->next->prev = le; le->prev->next = le; return le; } //================= //CG_FreeLocalEntity //================= static void CG_FreeLocalEntity( lentity_t *le ) { // remove from linked active list le->prev->next = le->next; le->next->prev = le->prev; // insert into linked free list le->next = cg_free_lents; cg_free_lents = le; } //================= //CG_AllocModel //================= lentity_t *CG_AllocModel( letype_t type, const vec3_t origin, const vec3_t angles, int frames, float r, float g, float b, float a, float light, float lr, float lg, float lb, struct model_s *model, struct shader_s *shader ) { lentity_t *le; le = CG_AllocLocalEntity( type, r, g, b, a ); le->frames = frames; le->light = light; le->lightcolor[0] = lr; le->lightcolor[1] = lg; le->lightcolor[2] = lb; le->ent.rtype = RT_MODEL; le->ent.flags = RF_NOSHADOW; le->ent.model = model; le->ent.customShader = shader; le->ent.shaderTime = cg.time * 0.001f; le->ent.scale = 1.0f; AnglesToAxis( angles, le->ent.axis ); VectorCopy( origin, le->ent.origin ); return le; } //================= //CG_AllocSprite //================= lentity_t *CG_AllocSprite( letype_t type, vec3_t origin, float radius, int frames, float r, float g, float b, float a, float light, float lr, float lg, float lb, struct shader_s *shader ) { lentity_t *le; le = CG_AllocLocalEntity( type, r, g, b, a ); le->frames = frames; le->light = light; le->lightcolor[0] = lr; le->lightcolor[1] = lg; le->lightcolor[2] = lb; le->ent.rtype = RT_SPRITE; le->ent.flags = RF_NOSHADOW; le->ent.radius = radius; le->ent.customShader = shader; le->ent.shaderTime = cg.time * 0.001f; le->ent.scale = 1.0f; Matrix_Identity( le->ent.axis ); VectorCopy( origin, le->ent.origin ); return le; } //================= //CG_AllocLaser //================= lentity_t *CG_AllocLaser( vec3_t start, vec3_t end, float radius, int frames, float r, float g, float b, float a, struct shader_s *shader ) { lentity_t *le; le = CG_AllocLocalEntity( LE_LASER, 1, 1, 1, 1 ); le->frames = frames; le->ent.radius = radius; le->ent.customShader = shader; le->ent.skinnum = COLOR_RGBA( (int)(r * 255), (int)(g * 255), (int)(b * 255), (int)(a * 255) ); VectorCopy( start, le->ent.origin ); VectorCopy( end, le->ent.oldorigin ); return le; } //================= //CG_AddLaser //================= void CG_AddLaser( vec3_t start, vec3_t end, float radius, int colors, struct shader_s *shader ) { int i; vec3_t perpvec; vec3_t direction, normalized_direction; vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS]; vec3_t oldorigin, origin; poly_t poly; cg_beament_t *beamEnt; if( cg_numBeamEnts >= MAX_BEAMENTS ) return; VectorCopy( start, origin ); VectorCopy( end, oldorigin ); VectorSubtract( oldorigin, origin, direction ); if( VectorNormalize2( direction, normalized_direction ) == 0 ) return; PerpendicularVector( perpvec, normalized_direction ); VectorScale( perpvec, radius, perpvec ); for( i = 0; i < NUM_BEAM_SEGS; i++ ) { RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i ); VectorAdd( start_points[i], origin, start_points[i] ); VectorAdd( start_points[i], direction, end_points[i] ); } beamEnt = &cg_beamEnts[cg_numBeamEnts++]; memset( &poly, 0, sizeof(poly) ); poly.numverts = 4; poly.shader = shader; for( i = 0; i < NUM_BEAM_SEGS; i++ ) { poly.colors = beamEnt->colors[i]; poly.stcoords = beamEnt->stcoords[i]; poly.verts = beamEnt->verts[i]; VectorCopy( start_points[i], poly.verts[0] ); poly.stcoords[0][0] = 0; poly.stcoords[0][1] = 0; *(int *)poly.colors[0] = colors; VectorCopy( end_points[i], poly.verts[1] ); poly.stcoords[1][0] = 0; poly.stcoords[1][1] = 1; *(int *)poly.colors[1] = colors; VectorCopy( end_points[(i+1)%NUM_BEAM_SEGS], poly.verts[2] ); poly.stcoords[2][0] = 1; poly.stcoords[2][1] = 1; *(int *)poly.colors[2] = colors; VectorCopy( start_points[(i+1)%NUM_BEAM_SEGS], poly.verts[3] ); poly.stcoords[3][0] = 1; poly.stcoords[3][1] = 0; *(int *)poly.colors[3] = colors; trap_R_AddPolyToScene( &poly ); } } //================= //CG_AdjustImpactToWall // // Helper for impacts positioning. Checks if inside solid and tries to move the origin out //================= void CG_AdjustImpactToWall( vec3_t pos, vec3_t dir ) { /* trace_t trace; vec3_t end; if( !(CG_PointContents( pos ) & CONTENTS_SOLID) ) { CG_Printf( "Start VOID\n" ); VectorMA( pos, -16, dir, end ); //start from void to solid CG_Trace( &trace, pos, vec3_origin, vec3_origin, end, cgs.playerNum, CONTENTS_SOLID ); if( trace.fraction < 1.0f ) { CG_Printf( "Adjusted\n" ); VectorCopy( trace.endpos, pos ); VectorCopy( trace.plane.normal, dir ); } else CG_Printf( "Failed to adjust\n" ); return; } CG_Printf( "Start SOLID\n" ); // find void and trace to solid then //VectorNormalizeFast(dir); VectorMA( pos, 16, dir, end ); if( !(CG_PointContents( end ) & CONTENTS_SOLID) ) { CG_Trace( &trace, end, vec3_origin, vec3_origin, pos, cgs.playerNum, CONTENTS_SOLID ); if( trace.fraction < 1.0f ) { CG_Printf( "Adjusted\n" ); VectorCopy( trace.endpos, pos ); VectorCopy( trace.plane.normal, dir ); } else CG_Printf( "Failed to adjust\n" ); } */ } //================= //CG_ElectroEffect //================= void CG_ElectroIonsTrail( vec3_t start, vec3_t end ); void CG_ElectroTrail2( vec3_t start, vec3_t end ) { CG_ElectroPolyBeam( start, end ); CG_ElectroIonsTrail( start, end ); } //================= //CG_BulletExplosion_QF (backup) //================= void CG_BulletExplosion_QF( vec3_t origin, vec3_t dir ) { vec3_t v; lentity_t *le; le = CG_AllocModel( LE_NO_FADE, origin, vec3_origin, 6, 1, 1, 1, 1, 0, 0, 0, 0, CG_MediaModel( cgs.media.modBulletExplode ), NULL /*CG_MediaShader( cgs.media.shaderBulletExplosion )*/ ); //wsw le->ent.scale = 8.0f; if( !dir || VectorCompare( dir, vec3_origin ) ) { Matrix_Identity( le->ent.axis ); return; } VectorMA( le->ent.origin, -8, dir, le->ent.origin ); VectorCopy( dir, le->ent.axis[0] ); PerpendicularVector( v, le->ent.axis[0] ); RotatePointAroundVector( le->ent.axis[1], le->ent.axis[0], v, rand() % 360 ); CrossProduct( le->ent.axis[0], le->ent.axis[1], le->ent.axis[2] ); } //================= //CG_ImpactSmokePuff //================= void CG_ImpactSmokePuff( vec3_t origin, vec3_t dir, float radius, float alpha, int time, int speed ) { #define SMOKEPUFF_MAXVIEWDIST 700 lentity_t *le; struct shader_s *shader = CG_MediaShader( cgs.media.shaderSmokePuff ); if( CG_PointContents(origin) & MASK_WATER ) { return; } if( DistanceFast( origin, cg.refdef.vieworg ) * cg.view_fracDistFOV > SMOKEPUFF_MAXVIEWDIST ) return; if( !VectorLength(dir) ) { VectorCopy( cg.v_forward, dir ); VectorInverse( dir ); } VectorNormalize( dir ); //offset the origin by half of the radius VectorMA( origin, radius*0.5f, dir, origin ); le = CG_AllocSprite( LE_SCALE_ALPHA_FADE, origin, radius + crandom(), time, 1, 1, 1, alpha, 0, 0, 0, 0, shader ); le->ent.rotation = rand () % 360; VectorScale( dir, speed, le->velocity ); } //================= //CG_BulletExplosion //================= void CG_BulletExplosion( vec3_t pos, vec3_t dir ) { lentity_t *le; vec3_t angles; vec3_t end; trace_t trace; //find what are we hitting VectorMA( pos, -1.0, dir, end ); CG_Trace( &trace, pos, vec3_origin, vec3_origin, end, cgs.playerNum+1, MASK_SHOT ); if( trace.fraction == 1.0 ) return; VecToAngles( dir, angles ); if( trace.surfFlags & SURF_FLESH || (trace.ent > 0 && cg_entities[trace.ent].current.type == ET_PLAYER) ) { 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; } else if( trace.surfFlags & SURF_DUST ) { // throw particles on dust CG_ImpactSmokePuff( trace.endpos, trace.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( trace.endpos, trace.plane.normal, 2, 0.6f, 6, 8 ); if( !(trace.surfFlags & SURF_NOMARKS) ) CG_SpawnDecal ( pos, dir, random()*360, 8, 1, 1, 1, 1, 10, 1, qfalse, CG_MediaShader (cgs.media.shaderBulletMark) ); } } //================= //CG_AddBeam //================= void CG_AddBeam( int ent, vec3_t start, vec3_t end, vec3_t offset, struct model_s *model, struct shader_s *shader ) { int i; beam_t *b; if( !model ) return; // override any beam with the same entity for( i = 0, b = cg_beams; i < MAX_BEAMS; i++, b++ ) { if( b->entity != ent ) continue; b->entity = ent; b->model = model; b->shader = shader; b->endtime = cg.time + 100; VectorCopy( start, b->start ); VectorCopy( end, b->end ); VectorCopy( offset, b->offset ); return; } // find a free beam for( i = 0, b = cg_beams; i < MAX_BEAMS; i++, b++ ) { if( b->model || b->endtime >= cg.time ) continue; b->entity = ent; b->model = model; b->shader = shader; b->endtime = cg.time + 100; VectorCopy( start, b->start ); VectorCopy( end, b->end ); VectorCopy( offset, b->offset ); return; } } //================= //CG_AddLightning //================= void CG_AddLightning( int srcEnt, int destEnt, vec3_t start, vec3_t end, struct model_s *model ) { int i; beam_t *b; if( !model ) return; // override any beam with the same source AND destination entities for( i = 0, b = cg_beams; i < MAX_BEAMS; i++, b++ ) { if( b->entity != srcEnt || b->dest_entity != destEnt ) continue; b->entity = srcEnt; b->dest_entity = destEnt; b->model = model; b->endtime = cg.time + (4 * cg.frameTime); VectorCopy( start, b->start ); VectorCopy( end, b->end ); VectorClear( b->offset ); return; } // find a free beam for( i = 0, b = cg_beams; i < MAX_BEAMS; i++, b++ ) { if( b->model || b->endtime >= cg.time ) continue; b->entity = srcEnt; b->dest_entity = destEnt; b->model = model; b->endtime = cg.time + (8 * cg.frameTime); VectorCopy( start, b->start ); VectorCopy( end, b->end ); VectorClear( b->offset ); return; } } //=============== //CG_BubbleTrail //=============== void CG_BubbleTrail( vec3_t start, vec3_t end, int dist ) { int i; float len; vec3_t move, vec; lentity_t *le; struct shader_s *shader; VectorCopy( start, move ); VectorSubtract( end, start, vec ); len = VectorNormalize( vec ); if( !len ) return; VectorScale( vec, dist, vec ); shader = CG_MediaShader( cgs.media.shaderWaterBubble ); for( i = 0; i < len; i += dist ) { le = CG_AllocSprite( LE_ALPHA_FADE, move, 3, 10, 1, 1, 1, 1, 0, 0, 0, 0, shader ); VectorSet( le->velocity, crandom()*5, crandom()*5, crandom()*5 + 6 ); VectorAdd( move, vec, move ); } } //=============== //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, 1, 0, CG_MediaModel(cgs.media.modPlasmaExplosion), NULL ); //le->ent.scale = 3.0f; le->ent.scale = radius/model_radius; //trap_S_StartSound ( pos, 0, 0, CG_MediaSfx (cgs.media.sfxPlasmaStrongHit), cg_volume_effects->value, ATTN_NORM, 0 ); } else { le = CG_AllocModel( LE_ALPHA_FADE, pos, angles, 4, 1, 1, 1, 1, 80, 0, 1, 0, CG_MediaModel(cgs.media.modPlasmaExplosion), NULL ); le->ent.scale = radius/model_radius; //trap_S_StartSound ( pos, 0, 0, CG_MediaSfx (cgs.media.sfxPlasmaWeakHit), cg_volume_effects->value, ATTN_NORM, 0 ); } le->ent.rotation = rand () % 360; CG_SpawnDecal ( pos, dir, random()*360, 8, 1, 1, 1, 1, 10, 1, qfalse, CG_MediaShader (cgs.media.shaderPlasmaMark) ); } //=============== //CG_BoltExplosionMode //=============== void CG_BoltExplosionMode( vec3_t pos, vec3_t dir, int fire_mode ) { lentity_t *le; vec3_t angles; CG_AdjustImpactToWall( pos, dir ); 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, 1, 1, 1, //white dlight CG_MediaModel(cgs.media.modBladeWallHit), cgs.shaderWhite ); le->ent.rotation = rand () % 360; if( fire_mode == FIRE_MODE_STRONG ) { le->ent.scale = 1.5f; // add white energy particles on the impact CG_ImpactPufParticles( pos, dir, 8, 1.25f, 1, 1, 1, 1, trap_R_RegisterPic("additiveParticleShine") ); } else { le->ent.scale = 1.0f; CG_ImpactPufParticles( pos, dir, 8, 1.0f, 1, 1, 1, 1, NULL ); } //FIXME: need a proper shader CG_SpawnDecal( pos, dir, random()*360, 8, 1, 1, 1, 1, 10, 1, qfalse, CG_MediaShader (cgs.media.shaderBulletMark) ); } //=============== //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; if( cg_explosionsAlpha->value < 0.1f ) trap_Cvar_SetValue( "cg_explosionsAlpha", 0.1f ); 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, 64, 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, 32, 1, 1, 1, 1, 10, 1, qfalse, CG_MediaShader(cgs.media.shaderExplosionMark) ); } // animmap shader of the explosion VectorMA( pos, radius*0.25f, dir, origin ); le = CG_AllocSprite( LE_ALPHA_FADE, origin, radius * 0.5f, 8, 1, 1, 1, cg_explosionsAlpha->value, radius*4, 1, 0.80f, 0, // yellow dlight CG_MediaShader(cgs.media.shaderRocketExplosion) ); VectorScale( dir, crandom()*6, vec ); VectorSet( le->velocity, -vec[0] * 5 + crandom()*5, -vec[1] * 5 + crandom()*5, -vec[2] * 5 + crandom()*5 + 4 ); le->ent.rotation = rand () % 360; if( cg_explosionsRingAlpha->value ) { // explosion ring sprite VectorMA( pos, radius*0.5f, dir, origin ); le = CG_AllocSprite( LE_ALPHA_FADE, origin, radius, 3, 1, 1, 1, cg_explosionsRingAlpha->value, 0, 0, 0, 0, // no dlight CG_MediaShader(cgs.media.shaderRocketExplosionRing) ); le->ent.rotation = rand () % 360; } //jalfixme: add sound at water? } //=============== //CG_BladeImpact //=============== void CG_BladeImpact( vec3_t pos, vec3_t dir ) { lentity_t *le; vec3_t angles; vec3_t end; trace_t trace; //find what are we hitting VectorMA( pos, -1.0, dir, end ); CG_Trace( &trace, pos, vec3_origin, vec3_origin, end, cgs.playerNum+1, MASK_SHOT ); if( trace.fraction == 1.0 ) return; VecToAngles( dir, angles ); if( trace.surfFlags & SURF_FLESH || (trace.ent > 0 && cg_entities[trace.ent].current.type == ET_PLAYER) ) { 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_StartSound ( pos, 0, CHAN_AUTO, CG_MediaSfx (cgs.media.sfxBladeFleshHit[(int)(random()*3)]), cg_volume_effects->value, ATTN_NORM, 0 ); } else if( trace.surfFlags & SURF_DUST ) { // throw particles on dust if( trace.surfFlags & SURF_DUST ) CG_ParticleEffect( trace.endpos, trace.plane.normal, 0.30f, 0.30f, 0.25f, 30 ); //fixme? would need a dust sound trap_S_StartSound ( pos, 0, CHAN_AUTO, CG_MediaSfx (cgs.media.sfxBladeWallHit[(int)(random()*2)]), cg_volume_effects->value, ATTN_NORM, 0 ); } 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_StartSound ( pos, 0, CHAN_AUTO, CG_MediaSfx (cgs.media.sfxBladeWallHit[(int)(random()*2)]), cg_volume_effects->value, ATTN_NORM, 0 ); if( !(trace.surfFlags & SURF_NOMARKS) ) CG_SpawnDecal ( pos, dir, random()*360, 8, 1, 1, 1, 1, 10, 1, qfalse, CG_MediaShader (cgs.media.shaderBulletMark) ); } } //=============== //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; CG_AdjustImpactToWall( pos, dir ); 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) ); } //=============== //CG_NewGrenadeTrail //=============== void CG_NewGrenadeTrail( centity_t *cent ) { lentity_t *le; float len; vec3_t vec; int contents; int trailTime; float radius = 4, alpha = cg_grenadeTrailAlpha->value; struct shader_s *shader = CG_MediaShader( cgs.media.shaderGrenadeTrailSmokePuff ); if( !cg_grenadeTrail->integer ) return; // didn't move VectorSubtract( cent->ent.origin, cent->trailOrigin, vec ); len = VectorNormalize( vec ); if( !len ) return; // density is found by quantity per second trailTime = (int)(1000.0f / cg_grenadeTrail->value ); if( trailTime < 1 ) trailTime = 1; // we don't add more than one sprite each frame. If frame // ratio is too slow, people will prefer having less sprites on screen if( cent->localEffects[LOCALEFFECT_TRAIL_LAST_DROP] + trailTime < cg.time ) { cent->localEffects[LOCALEFFECT_TRAIL_LAST_DROP] = cg.time; contents = ( CG_PointContents( cent->trailOrigin ) & CG_PointContents( cent->ent.origin ) ); if( contents & MASK_WATER ) { shader = CG_MediaShader( cgs.media.shaderWaterBubble ); radius = 3 + crandom(); alpha = 1.0f; } clamp( alpha, 0.0f, 1.0f ); le = CG_AllocSprite( LE_SCALE_ALPHA_FADE, cent->trailOrigin, radius, 10, 1.0f, 1.0f, 1.0f, alpha, 0, 0, 0, 0, shader ); VectorSet( le->velocity, -vec[0] * 5 + crandom()*5, -vec[1] * 5 + crandom()*5, -vec[2] * 5 + crandom()*5 + 3 ); le->ent.rotation = rand () % 360; } } //=============== //CG_NewRocketTrail //=============== void CG_NewRocketTrail( centity_t *cent ) { lentity_t *le; float len; vec3_t vec; int contents; int trailTime; float radius = 4, alpha = cg_rocketTrailAlpha->value; struct shader_s *shader = CG_MediaShader( cgs.media.shaderSmokePuff ); if( !cg_rocketTrail->integer ) return; // didn't move VectorSubtract( cent->ent.origin, cent->trailOrigin, vec ); len = VectorNormalize( vec ); if( !len ) return; // density is found by quantity per second trailTime = (int)(1000.0f / cg_rocketTrail->value ); if( trailTime < 1 ) trailTime = 1; // we don't add more than one sprite each frame. If frame // ratio is too slow, people will prefer having less sprites on screen if( cent->localEffects[LOCALEFFECT_TRAIL_LAST_DROP] + trailTime < cg.time ) { cent->localEffects[LOCALEFFECT_TRAIL_LAST_DROP] = cg.time; contents = ( CG_PointContents( cent->trailOrigin ) & CG_PointContents( cent->ent.origin ) ); if( contents & MASK_WATER ) { shader = CG_MediaShader( cgs.media.shaderWaterBubble ); radius = 3 + crandom(); alpha = 1.0f; } clamp( alpha, 0.0f, 1.0f ); le = CG_AllocSprite( LE_SCALE_ALPHA_FADE, cent->trailOrigin, radius, 10, 1.0f, 1.0f, 1.0f, alpha, 0, 0, 0, 0, shader ); VectorSet( le->velocity, -vec[0] * 5 + crandom()*5, -vec[1] * 5 + crandom()*5, -vec[2] * 5 + crandom()*5 + 3 ); le->ent.rotation = rand () % 360; } } //=============== //CG_NewElectroBeamPuff //=============== void CG_NewElectroBeamPuff( centity_t *cent, vec3_t origin, vec3_t dir ) { float len; vec3_t vec; int trailTime; if( !cg_particles->integer ) return; // didn't move VectorSubtract( cent->ent.origin, cent->trailOrigin, vec ); len = VectorNormalize( vec ); if( !len ) return; // density is found by quantity per second trailTime = (int)(1000.0f / 20.0f ); if( trailTime < 1 ) trailTime = 1; // we don't add more than one sprite each frame. If frame // ratio is too slow, people will prefer having less sprites on screen if( cent->localEffects[LOCALEFFECT_TRAIL_LAST_DROP] + trailTime < cg.time ) { cent->localEffects[LOCALEFFECT_TRAIL_LAST_DROP] = cg.time; CG_ImpactSmokePuff( origin, dir, 3, 1.0f, 8, 12 ); } } //=============== //CG_NewBloodTrail //=============== void CG_NewBloodTrail( centity_t *cent ) { lentity_t *le; float len; vec3_t vec; int contents; int trailTime; float radius = 2.5f, alpha = cg_bloodTrailAlpha->value; struct shader_s *shader = CG_MediaShader( cgs.media.shaderBloodTrailPuff ); if( !cg_showBloodTrail->integer) return; if(!cg_bloodTrail->integer) return; // didn't move VectorSubtract( cent->ent.origin, cent->trailOrigin, vec ); len = VectorNormalize( vec ); if( !len ) return; // density is found by quantity per second trailTime = (int)(1000.0f / cg_bloodTrail->value ); if( trailTime < 1 ) trailTime = 1; // we don't add more than one sprite each frame. If frame // ratio is too slow, people will prefer having less sprites on screen if( cent->localEffects[LOCALEFFECT_TRAIL_LAST_DROP] + trailTime < cg.time ) { cent->localEffects[LOCALEFFECT_TRAIL_LAST_DROP] = cg.time; contents = ( CG_PointContents( cent->trailOrigin ) & CG_PointContents( cent->ent.origin ) ); if( contents & MASK_WATER ) { shader = CG_MediaShader( cgs.media.shaderBloodTrailLiquidPuff ); radius = 4 + crandom(); alpha = 0.5f * cg_bloodTrailAlpha->value; } clamp( alpha, 0.0f, 1.0f ); le = CG_AllocSprite( LE_SCALE_ALPHA_FADE, cent->trailOrigin, radius, 8, 1.0f, 1.0f, 1.0f, alpha, 0, 0, 0, 0, shader ); VectorSet( le->velocity, -vec[0] * 5 + crandom()*5, -vec[1] * 5 + crandom()*5, -vec[2] * 5 + crandom()*5 + 3 ); le->ent.rotation = rand () % 360; } } //=============== //CG_BloodDamageEffect //=============== void CG_BloodDamageEffect( vec3_t origin, vec3_t dir, int damage ) { lentity_t *le; int count, i; float radius = 3.0f, alpha = cg_bloodTrailAlpha->value; int time = 8; struct shader_s *shader = CG_MediaShader( cgs.media.shaderBloodImpactPuff ); if( !cg_showBloodTrail->integer) return; if( !cg_bloodTrail->integer ) return; count = (int)(damage * 0.25f); clamp( count, 1, 10 ); if( CG_PointContents(origin) & MASK_WATER ) { shader = CG_MediaShader( cgs.media.shaderBloodTrailLiquidPuff ); radius += (1 + crandom()); alpha = 0.5f * cg_bloodTrailAlpha->value; } if( !VectorLength(dir) ) { VectorCopy( cg.v_forward, dir ); VectorInverse( dir ); } VectorNormalize( dir ); for( i = 0; i < count; i++ ) { le = CG_AllocSprite( LE_SCALE_ALPHA_FADE, origin, radius + crandom(), time, 1, 1, 1, alpha, 0, 0, 0, 0, shader ); le->ent.rotation = rand () % 360; // randomize dir VectorSet( le->velocity, -dir[0] * 5 + crandom()*5, -dir[1] * 5 + crandom()*5, -dir[2] * 5 + crandom()*5 + 3 ); VectorMA( dir, min(6, count), le->velocity, le->velocity ); } } //=============== //CG_PModel_SpawnTeleportEffect //=============== void CG_PModel_SpawnTeleportEffect( centity_t *cent ) { // the thing is, we must have a built skeleton, so we // can run all bones and spawn a polygon at their origin int i, j; bonepose_t *bonepose; cgs_skeleton_t *skel; orientation_t orient, ref; float radius = 5; lentity_t *le; vec3_t vec, teleportOrigin; skel = CG_SkeletonForModel( cent->ent.model ); if( !skel || !cent->ent.boneposes ) return; for( j = LOCALEFFECT_EV_PLAYER_TELEPORT_IN; j <= LOCALEFFECT_EV_PLAYER_TELEPORT_OUT; j++ ) { if( cent->localEffects[j] ) { cent->localEffects[j] = 0; if( j == LOCALEFFECT_EV_PLAYER_TELEPORT_OUT ) VectorCopy( cent->teleportedFrom, teleportOrigin ); else VectorCopy( cent->ent.origin, teleportOrigin ); for( i = 0; i < skel->numBones; i++ ) { bonepose = cent->ent.boneposes + i; Quat_Matrix( bonepose->quat, orient.axis ); orient.origin[0] = bonepose->origin[0]; orient.origin[1] = bonepose->origin[1]; orient.origin[2] = bonepose->origin[2]; VectorCopy( vec3_origin, ref.origin ); Matrix_Copy( axis_identity, ref.axis ); CG_MoveToTag( ref.origin, ref.axis, teleportOrigin, cent->ent.axis, orient.origin, orient.axis ); VectorSet( vec, 0.1f, 0.1f, 0.1f ); // spawn a sprite at each bone le = CG_AllocSprite( LE_SCALE_ALPHA_FADE, ref.origin, radius, 15 + crandom()*5, 1, 1, 1, 0.5f, 0, 0, 0, 0, CG_MediaShader( cgs.media.shaderTeleporterSmokePuff ) ); VectorSet( le->velocity, -vec[0] * 5 + crandom()*5, -vec[1] * 5 + crandom()*5, -vec[2] * 5 + crandom()*5 + 3 ); le->ent.rotation = rand () % 360; CG_ParticleEffect( ref.origin, ref.axis[2], 0.9f, 0.9f, 0.9f, 2 ); } } } } //=============== //CG_GrenadeExplosionMode //=============== //wsw void CG_GrenadeExplosionMode( vec3_t pos, vec3_t dir, int fire_mode, float radius ) { lentity_t *le; vec3_t angles; vec3_t decaldir; //float model_radius = GRENADE_EXPLOSION_MODEL_RADIUS; vec3_t origin,vec; if( cg_explosionsAlpha->value < 0.1f ) trap_Cvar_SetValue( "cg_explosionsAlpha", 0.1f ); /* if( !dir ) { angles[0] = random()*360; angles[1] = random()*360; angles[2] = 0; AngleVectors(angles, NULL, NULL, decaldir); } else {*/ 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 ) { /* le = CG_AllocModel( LE_ALPHA_FADE, pos, angles, 5, 1.0f, 1.0f, 1.0f, 0.6f, //jal: suposed to be white transparent 250, 1.0f, 1.0f, 0.0f, //jal: supposed to be yellow dlight CG_MediaModel(cgs.media.modGrenadeExplosion), NULL ); //le->ent.scale = 4.0f; le->ent.scale = radius / model_radius; //trap_S_StartSound ( pos, 0, 0, CG_MediaSfx (cgs.media.sfxGrenadeStrongExplosion), cg_volume_effects->value, ATTN_NORM, 0 ); */ CG_SpawnDecal( pos, decaldir, random()*360, 64, 1, 1, 1, 1, 10, 1, qfalse, CG_MediaShader( cgs.media.shaderExplosionMark ) ); } else { /* le = CG_AllocModel( LE_ALPHA_FADE, pos, angles, 3, 1.0, 1.0, 1.0, 1.0, //jal: suposed to be white opaque 100, 1.0, 1.0, 0, //jal: supposed to be yellow dlight CG_MediaModel(cgs.media.modGrenadeExplosion), NULL ); //le->ent.scale = 2.0f; le->ent.scale = radius / model_radius; //trap_S_StartSound ( pos, 0, 0, CG_MediaSfx (cgs.media.sfxGrenadeWeakExplosion), cg_volume_effects->value, ATTN_NORM, 0 ); */ CG_SpawnDecal( pos, decaldir, random()*360, 32, 1, 1, 1, 1, 10, 1, qfalse, CG_MediaShader( cgs.media.shaderExplosionMark ) ); } //le->ent.rotation = rand () % 360; // animmap shader of the explosion VectorMA( pos, radius*0.25f, dir, origin ); le = CG_AllocSprite( LE_ALPHA_FADE, origin, radius * 0.5f, 8, 1, 1, 1, cg_explosionsAlpha->value, radius*4, 1, 0.80f, 0, // yellow dlight CG_MediaShader(cgs.media.shaderRocketExplosion) ); VectorScale( dir, crandom()*6, vec ); VectorSet( le->velocity, -vec[0] * 5 + crandom()*5, -vec[1] * 5 + crandom()*5, -vec[2] * 5 + crandom()*5 + 4 ); le->ent.rotation = rand () % 360; // explosion ring sprite if( cg_explosionsRingAlpha->value ) { VectorMA( pos, radius*0.5f, dir, origin ); le = CG_AllocSprite( LE_ALPHA_FADE, origin, radius, 3, 1, 1, 1, cg_explosionsRingAlpha->value, 0, 0, 0, 0, // no dlight CG_MediaShader(cgs.media.shaderRocketExplosionRing) ); le->ent.rotation = rand () % 360; } } //================= //CG_FlagFlareTrail //================= void CG_FlagTrail( vec3_t origin, vec3_t start, vec3_t end, float r, float g, float b ) { lentity_t *le; float len, mass = 20; vec3_t dir; VectorSubtract( end, start, dir ); len = VectorNormalize( dir ); if( !len ) return; le = CG_AllocSprite( LE_SCALE_ALPHA_FADE, origin, 8, 50 + 50*random(), r, g, b, 0.7f, 0, 0, 0, 0, CG_MediaShader( cgs.media.shaderTeleporterSmokePuff ) ); VectorSet( le->velocity, -dir[0] * 5 + crandom()*5, -dir[1] * 5 + crandom()*5, -dir[2] * 5 + crandom()*5 + 3 ); le->ent.rotation = rand () % 360; //friction and gravity VectorSet( le->accel, -0.2f, -0.2f, -9.8f * mass); le->bounce = 20; } //=============== //CG_Explosion1 //=============== void CG_Explosion1( vec3_t pos ) { CG_RocketExplosionMode( pos, vec3_origin, FIRE_MODE_STRONG, 120 ); } //=============== //CG_Explosion2 //=============== void CG_Explosion2( vec3_t pos ) { CG_GrenadeExplosionMode( pos, vec3_origin, FIRE_MODE_STRONG, 120 ); } //=============== //CG_TeleportEffect //=============== void CG_TeleportEffect( vec3_t org ) { lentity_t *le; le = CG_AllocModel( LE_RGB_FADE, org, vec3_origin, 5, 1, 1, 1, 1, 0, 0, 0, 0, CG_MediaModel( cgs.media.modTeleportEffect ), CG_MediaShader( cgs.media.shaderTeleportEffect ) ); le->ent.origin[2] -= 24; } //=============== //CG_GreenLaser //=============== void CG_GreenLaser( vec3_t start, vec3_t end ) { lentity_t *le; le = CG_AllocLaser( start, end, 2.0f, 2.0f, 0.0f, 0.85f, 0.0f, 0.3f, CG_MediaShader( cgs.media.shaderLaser ) ); } //================= //CG_SmallPileOfGibs - SPLITMODELS (debrisbounce) // velocity can be NULL //================= void CG_SmallPileOfGibs( vec3_t origin, int count, vec3_t velocity ) { lentity_t *le; int i; float mass = 60; vec3_t angles; if( !cg_gibs->integer ) return; for( i = 0; i < count; i++ ) { le = CG_AllocModel( LE_NO_FADE, origin, vec3_origin, 200 + 200*random(), 1, 1, 1, 1, 0, 0, 0, 0, CG_MediaModel( cgs.media.modMeatyGibs[(int)(random()*(MAX_MEATY_GIBS-1))] ), NULL ); //random rotation and scale variations VectorSet( angles, crandom()*360, crandom()*360, crandom()*360 ); AnglesToAxis ( angles, le->ent.axis ); le->ent.scale = 1.0 - (crandom()*0.25); le->ent.flags = RF_FULLBRIGHT; //jalfixme: needs to fix ligthing if( velocity ) { //velocity brought by game + random variations le->velocity[0] = velocity[0] + crandom()*75; le->velocity[1] = velocity[1] + crandom()*75; le->velocity[2] = velocity[2] + crandom()*75; } else { vec3_t dir; float v; //pure random dir & velocity VectorSet( dir, crandom()*0.5, crandom()*0.5, random() ); v = 100 + random() * 100; VectorSet( le->velocity, dir[0]*v, dir[1]*v, dir[2]*v ); } //friction and gravity VectorSet( le->accel, -0.2f, -0.2f, -9.8f * mass); le->bounce = 35; } } //================= //CG_EjectBrass - SPLITMODELS //eject brass-debris //================= void CG_EjectBrass( vec3_t origin, int count, struct model_s *model ) { lentity_t *le; int i; float mass = 40; vec3_t angles; vec3_t dir; float v; if(!cg_ejectBrass->integer) return; for( i = 0; i < count; i++ ) { le = CG_AllocModel( LE_NO_FADE, origin, vec3_origin, 50 + 50*random(), 1, 1, 1, 1, 0, 0, 0, 0, model, NULL ); //random rotation VectorSet( angles, crandom()*360, crandom()*360, crandom()*360 ); AnglesToAxis ( angles, le->ent.axis ); //pure random dir & velocity VectorSet( dir, crandom()*0.25, crandom()*0.25, random() ); v = 100 + random() * 25; VectorSet( le->velocity, dir[0]*v, dir[1]*v, dir[2]*v ); //friction and gravity VectorSet( le->accel, -0.2f, -0.2f, -9.8f * mass); le->bounce = 60; } } //================= //CG_AddBeams //================= void CG_AddBeams( void ) { int i; beam_t *b; vec3_t dist, org, angles, angles2; float d; entity_t ent; float len, steps; float model_length; // update beams for( i = 0, b = cg_beams; i < MAX_BEAMS; i++, b++ ) { if( !b->model || b->endtime < cg.time ) continue; // if coming from the player, update the start position //if( b->entity == cgs.playerNum + 1 ) { // entity 0 is the world // VectorCopy( cg.refdef.vieworg, b->start ); // b->start[2] -= 22; // adjust for view height //} VectorAdd( b->start, b->offset, org ); // calculate pitch and yaw VectorSubtract( b->end, org, dist ); VecToAngles( dist, angles2 ); // add new entities for the beams d = VectorNormalize( dist ); memset( &ent, 0, sizeof(ent) ); ent.scale = 1.0f; ent.color[0] = ent.color[1] = ent.color[2] = ent.color[3] = 255; if( b->model == CG_MediaModel( cgs.media.modLightning ) ) { model_length = 35.0; d -= 20.0; // correction so it doesn't end in middle of tesla } else { //wsw : jal : custom model leghts if( b->model_length ) model_length = b->model_length; else model_length = 30.0; } steps = ceil( d / model_length); len = (d - model_length) / (steps - 1); // PMM - special case for lightning model .. if the real length is shorter than the model, // flip it around & draw it from the end to the start. This prevents the model from going // through the tesla mine (instead it goes through the target) if( (b->model == CG_MediaModel( cgs.media.modLightning )) && (d <= model_length) ) { VectorCopy( b->end, ent.origin ); VectorCopy( b->end, ent.lightingOrigin ); VectorCopy( b->end, ent.oldorigin ); // offset to push beam outside of tesla model // (negative because dist is from end to start for this beam) ent.rtype = RT_MODEL; ent.model = b->model; ent.flags = RF_FULLBRIGHT|RF_NOSHADOW; angles[0] = angles2[0]; angles[1] = angles2[1]; angles[2] = rand()%360; AnglesToAxis( angles, ent.axis ); CG_AddEntityToScene( &ent ); // skelmod return; } ent.rtype = RT_MODEL; ent.flags = RF_NOSHADOW; ent.model = b->model; ent.customShader = b->shader; // wsw : jal : allow custom shaders while( d > 0 ) { VectorCopy( org, ent.origin ); VectorCopy( org, ent.lightingOrigin ); VectorCopy( org, ent.oldorigin ); if( b->model == CG_MediaModel( cgs.media.modLightning ) ) { angles[0] = -angles2[0]; angles[1] = angles2[1] + 180.0; angles[2] = rand()%360; } else { //wsw : jal (add rotation angle) if( b->random_rotation ) { angles[0] = angles2[0]; angles[1] = angles2[1]; angles[2] = rand()%360; } else { angles[0] = angles2[0]; angles[1] = angles2[1]; angles[2] = angles2[2]; } } AnglesToAxis( angles, ent.axis ); CG_AddEntityToScene( &ent ); // skelmod VectorMA( org, len, dist, org ); d -= model_length; } } } //================= //CG_AddLocalEntities //================= void CG_AddLocalEntities( void ) { int f; lentity_t *le, *next, *hnode; entity_t *ent; float scale, frac, fade, time; float backlerp; 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 ); f = max( 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; } else { scale = 1.0f; fade = 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_AddLaser( ent->origin, ent->oldorigin, ent->radius, ent->skinnum, ent->customShader ); continue; } switch( le->type ) { case LE_NO_FADE: break; case LE_RGB_FADE: ent->color[0] = ( qbyte )( fade * le->color[0] ); ent->color[1] = ( qbyte )( fade * le->color[1] ); ent->color[2] = ( qbyte )( fade * le->color[2] ); break; case LE_SCALE_ALPHA_FADE: ent->scale = 1.0f + 1.0f / scale; ent->scale = min( ent->scale, 5.0f ); case LE_ALPHA_FADE: ent->color[3] = ( qbyte )( fade * le->color[3] ); break; default: break; } ent->backlerp = backlerp; //splitmodels debrisbounce[start] 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 ); 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); } } else VectorScale( le->velocity, le->bounce * time, le->velocity ); } else { VectorCopy( ent->origin, ent->oldorigin ); VectorCopy( next_origin, ent->origin ); } } else { VectorCopy( ent->origin, ent->oldorigin ); VectorMA( ent->origin, time, le->velocity, ent->origin ); } //[end] VectorCopy( ent->origin, ent->lightingOrigin ); VectorMA( le->velocity, time, le->accel, le->velocity ); CG_AddEntityToScene( ent ); // skelmod } } // ======================================================= // Unused code below // ======================================================= #ifdef THIS_IS_DISABLED //=============== //CG_BlasterExplosion //=============== void CG_BlasterExplosion( vec3_t pos, vec3_t dir ) { CG_BlasterParticles( pos, dir ); trap_S_StartSound( pos, 0, 0, CG_MediaSfx( cgs.media.sfxLashit ), cg_volume_effects->value, ATTN_NORM, 0 ); CG_SpawnDecal( pos, dir, random()*360, 16, 1, 0.8, 0, 1, 8, 2, qtrue, CG_MediaShader( cgs.media.shaderEnergyMark ) ); } //=============== //CG_BFGExplosion //=============== void CG_BFGExplosion( vec3_t pos ) { lentity_t *le; le = CG_AllocModel( LE_NO_FADE, pos, vec3_origin, 4, 1, 1, 1, 1, 350, 0, 1.0, 0, CG_MediaModel( cgs.media.modBfgExplo ), NULL ); } //=============== //CG_BFGBigExplosion //=============== void CG_BFGBigExplosion( vec3_t pos ) { lentity_t *le; le = CG_AllocModel( LE_NO_FADE, pos, vec3_origin, 6, 1, 1, 1, 1, 700, 0, 1.0, 0, CG_MediaModel( cgs.media.modBfgBigExplo ), NULL ); CG_BFGExplosionParticles( pos ); } #endif