/* ** RB_SurfaceRailRinges */ static void RB_SurfaceRailRings( void ) { refEntity_t *e; int numSegs; int len; vec3_t vec; vec3_t right, up; vec3_t start, end; e = &backEnd.currentEntity->e; VectorCopy( e->oldorigin, start ); VectorCopy( e->origin, end ); // compute variables VectorSubtract( end, start, vec ); len = VectorNormalize( vec ); MakeNormalVectors( vec, right, up ); numSegs = ( len ) / r_railSegmentLength->value; if ( numSegs <= 0 ) { numSegs = 1; } VectorScale( vec, r_railSegmentLength->value, vec ); DoRailDiscs( numSegs, start, vec, right, up ); }
/* ============== CG_SurfaceRailRings ============== */ void CG_SurfaceRailRings( const refEntity_t *originEnt ) { refEntity_t re; int numSegs; int len; vec3_t vec; vec3_t right, up; vec3_t start, end; re = *originEnt; VectorCopy( re.oldorigin, start ); VectorCopy( re.origin, end ); // compute variables VectorSubtract( end, start, vec ); len = VectorNormalize( vec ); MakeNormalVectors( vec, right, up ); numSegs = ( len ) / cg_railSegmentLength.value; if ( numSegs <= 0 ) { numSegs = 1; } VectorScale( vec, cg_railSegmentLength.value, vec ); CG_DoRailDiscs( re.customShader, re.shaderRGBA, numSegs, start, vec, right, up ); }
/* =============== CL_ParticleSmokeEffect - like the steam effect, but unaffected by gravity =============== */ void CL_ParticleSmokeEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude) { int i, j; cparticle_t *p; float d; vec3_t r, u; MakeNormalVectors (dir, r, u); for (i=0 ; i<count ; i++) { p = CL_AllocParticle(); if (!p) return; p->time = cl.time; p->color = color + (rand()&7); for (j=0 ; j<3 ; j++) { p->org[j] = org[j] + magnitude*0.1*crand(); // p->vel[j] = dir[j]*magnitude; } VectorScale (dir, magnitude, p->vel); d = crand()*magnitude/3; VectorMA (p->vel, d, r, p->vel); d = crand()*magnitude/3; VectorMA (p->vel, d, u, p->vel); p->accel[0] = p->accel[1] = p->accel[2] = 0; p->alpha = 1.0; p->alphavel = -1.0 / (0.5 + frand()*0.3); } }
// Puffs with velocity along direction, with some randomness thrown in void CLQ2_ParticleSteamEffect( vec3_t org, vec3_t dir, int color, int count, int magnitude ) { vec3_t r, u; MakeNormalVectors( dir, r, u ); for ( int i = 0; i < count; i++ ) { cparticle_t* p = CL_AllocParticle(); if ( !p ) { return; } p->type = pt_q2static; p->color = color + ( rand() & 7 ); for ( int j = 0; j < 3; j++ ) { p->org[ j ] = org[ j ] + magnitude * 0.1 * crand(); } VectorScale( dir, magnitude, p->vel ); float d = crand() * magnitude / 3; VectorMA( p->vel, d, r, p->vel ); d = crand() * magnitude / 3; VectorMA( p->vel, d, u, p->vel ); p->accel[ 0 ] = p->accel[ 1 ] = 0; p->accel[ 2 ] = -PARTICLE_GRAVITY / 2; p->alpha = 1.0; p->alphavel = -1.0 / ( 0.5 + frand() * 0.3 ); } }
void CLQ2_DebugTrail( vec3_t start, vec3_t end ) { vec3_t move; VectorCopy( start, move ); vec3_t vec; VectorSubtract( end, start, vec ); float len = VectorNormalize( vec ); vec3_t right, up; MakeNormalVectors( vec, right, up ); float dec = 3; VectorScale( vec, dec, vec ); VectorCopy( start, move ); while ( len > 0 ) { len -= dec; cparticle_t* p = CL_AllocParticle(); if ( !p ) { return; } p->type = pt_q2static; VectorClear( p->accel ); VectorClear( p->vel ); p->alpha = 1.0; p->alphavel = -0.1; p->color = 0x74 + ( rand() & 7 ); VectorCopy( move, p->org ); VectorAdd( move, vec, move ); } }
void R_RailTrail (vec3_t start, vec3_t end) { vec3_t move; vec3_t vec; float len; int j; particle_t *p; float dec; vec3_t right, up; int i; float d, c, s; vec3_t dir; byte clr = 40; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); MakeNormalVectors (vec, right, up); for (i=0 ; i<len ; i++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->die = cl.time + 2.0; p->start_time = cl.time; // Manoel Kasimier VectorClear (p->vel); d = i * 0.1; c = cos(d); s = sin(d); VectorScale (right, c, dir); VectorMA (dir, s, up, dir); p->type = pt_staticfadeadd; p->alpha = 1.0; // p->alphavel = -1.0 / (1+frand()*0.2); p->alphavel = -1.0; p->color = clr + (rand()&7); for (j=0 ; j<3 ; j++) { p->org[j] = move[j] + dir[j]*3; p->vel[j] = dir[j]*6; } VectorAdd (move, vec, move); } dec = 0.75; VectorScale (vec, dec, vec); VectorCopy (start, move); }
/* ====== CL_DebugTrail ====== */ void CL_DebugTrail (vec3_t start, vec3_t end) { vec3_t move; vec3_t vec; float len; // int j; cparticle_t *p; float dec; vec3_t right, up; // int i; // float d, c, s; // vec3_t dir; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); MakeNormalVectors (vec, right, up); // VectorScale(vec, RT2_SKIP, vec); // dec = 1.0; // dec = 0.75; dec = 3; VectorScale (vec, dec, vec); VectorCopy (start, move); while (len > 0) { len -= dec; if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; VectorClear (p->accel); VectorClear (p->vel); p->alpha = 1.0; p->alphavel = -0.1; // p->alphavel = 0; p->color = 0x74 + (rand()&7); VectorCopy (move, p->org); /* for (j=0 ; j<3 ; j++) { p->org[j] = move[j] + crand()*2; p->vel[j] = crand()*3; p->accel[j] = 0; } */ VectorAdd (move, vec, move); } }
void CG_PlayEffect( const char *fxName, vec3_t origin, const vec3_t fwd ) { vec3_t temp, axis[3]; // Assume angles, we'll do a cross product to finish up VectorCopy( fwd, axis[0] ); MakeNormalVectors( fwd, axis[1], temp ); CrossProduct( axis[0], axis[1], axis[2] ); //call FX scheduler directly theFxScheduler.PlayEffect( fxName, origin, axis, -1, -1, false ); }
/*============== CG_AuraStart ==============*/ void CG_AuraStart( centity_t *player){ int clientNum, tier; auraState_t *state; auraConfig_t *config; vec3_t groundPoint; trace_t trace; // Get the aura system corresponding to the player clientNum = player->currentState.clientNum; if(clientNum < 0 || clientNum >= MAX_CLIENTS){ CG_Error( "Bad clientNum on player entity"); return; } state = &auraStates[ clientNum ]; tier = cgs.clientinfo[clientNum].tierCurrent; config = &(state->configurations[tier]); // If the aura is already active, don't continue activating it again. if(state->isActive){ return; } // Initialize the system state->isActive = qtrue; state->lightAmt = config->lightMin; // create a small camerashake CG_AddEarthquake( player->lerpOrigin, 1000, 1, 0, 1, 200); // We don't want smoke jets if this is a boost aura instead of a charge aura. if(!(player->currentState.powerups &(1 << PW_BOOST))){ // Check if we're on, or near ground level VectorCopy( player->lerpOrigin, groundPoint); groundPoint[2] -= 48; CG_Trace( &trace, player->lerpOrigin, NULL, NULL, groundPoint, player->currentState.number, CONTENTS_SOLID); if(trace.allsolid || trace.startsolid){ trace.fraction = 1.0f; } if(trace.fraction < 1.0f){ vec3_t tempAxis[3]; // Place the explosion just a bit off the surface VectorNormalize2(trace.plane.normal, groundPoint); VectorMA( trace.endpos, 5, groundPoint, groundPoint); VectorNormalize2( trace.plane.normal, tempAxis[0]); MakeNormalVectors( tempAxis[0], tempAxis[1], tempAxis[2]); PSys_SpawnCachedSystem( "AuraSmokeBurst", groundPoint, tempAxis, NULL, NULL, qfalse, qfalse); } } }
// Play an effect at the origin of the specified entity //---------------------------- void G_PlayEffect( int fxID, int entNum, vec3_t fwd ) { gentity_t *tent; vec3_t temp; tent = G_TempEntity( g_entities[entNum].currentOrigin, EV_PLAY_EFFECT ); tent->s.eventParm = fxID; tent->s.otherEntityNum = entNum; VectorSet( tent->maxs, FX_ENT_RADIUS, FX_ENT_RADIUS, FX_ENT_RADIUS ); VectorScale( tent->maxs, -1, tent->mins ); VectorCopy( fwd, tent->pos3 ); // Assume angles, we'll do a cross product on the other end to finish up MakeNormalVectors( fwd, tent->pos4, temp ); }
void CL_ParticleSteamEffect2 (cl_sustain_t *self) //vec3_t org, vec3_t dir, int color, int count, int magnitude) { int i, j; cparticle_t *p; float d; vec3_t r, u; vec3_t dir; // vectoangles2 (dir, angle_dir); // AngleVectors (angle_dir, f, r, u); VectorCopy (self->dir, dir); MakeNormalVectors (dir, r, u); for (i=0 ; i<self->count ; i++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; #ifndef QMAX p->color = self->color + (rand()&7); #endif for (j=0 ; j<3 ; j++) { p->org[j] = self->org[j] + self->magnitude*0.1*crand(); // p->vel[j] = dir[j]*magnitude; } VectorScale (dir, self->magnitude, p->vel); d = crand()*self->magnitude/3; VectorMA (p->vel, d, r, p->vel); d = crand()*self->magnitude/3; VectorMA (p->vel, d, u, p->vel); p->accel[0] = p->accel[1] = 0; p->accel[2] = -PARTICLE_GRAVITY/2; p->alpha = 1.0; p->alphavel = -1.0 / (0.5 + frand()*0.3); } self->nextthink += self->thinkinterval; }
//----------------------------- void G_PlayEffect( int fxID, const vec3_t origin, const vec3_t fwd ) { gentity_t *tent; vec3_t temp; tent = G_TempEntity( origin, EV_PLAY_EFFECT ); tent->s.eventParm = fxID; VectorSet( tent->maxs, FX_ENT_RADIUS, FX_ENT_RADIUS, FX_ENT_RADIUS ); VectorScale( tent->maxs, -1, tent->mins ); VectorCopy( fwd, tent->pos3 ); // Assume angles, we'll do a cross product on the other end to finish up MakeNormalVectors( fwd, tent->pos4, temp ); gi.linkentity( tent ); }
// Play an effect at a position on an entity. // Mostly for G_MissileBounceEffect so we can play an effect on the bouncee. //----------------------------- void G_PlayEffect( int fxID, int clientNum, vec3_t origin, vec3_t fwd ) { gentity_t *tent; vec3_t temp; tent = G_TempEntity( origin, EV_PLAY_EFFECT ); tent->s.eventParm = fxID; if ( clientNum != -1 ) { tent->s.saberActive = 1; tent->s.otherEntityNum = clientNum; } VectorSet( tent->maxs, FX_ENT_RADIUS, FX_ENT_RADIUS, FX_ENT_RADIUS ); VectorScale( tent->maxs, -1, tent->mins ); VectorCopy( fwd, tent->s.angles ); // Assume angles, we'll do a cross product on the other end to finish up MakeNormalVectors( fwd, tent->s.angles2, temp ); }
/* =============== CL_ParticleSteamEffect Puffs with velocity along direction, with some randomness thrown in =============== */ void CL_ParticleSteamEffect (vec3_t org, vec3_t dir, int color, int count, int magnitude) { int i, j; cparticle_t *p; float d; vec3_t r, u; // vectoangles2 (dir, angle_dir); // AngleVectors (angle_dir, f, r, u); MakeNormalVectors (dir, r, u); for (i=0 ; i<count ; i++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; p->color = color + (rand()&7); for (j=0 ; j<3 ; j++) { p->org[j] = org[j] + magnitude*0.1*crand(); // p->vel[j] = dir[j]*magnitude; } VectorScale (dir, magnitude, p->vel); d = crand()*magnitude/3; VectorMA (p->vel, d, r, p->vel); d = crand()*magnitude/3; VectorMA (p->vel, d, u, p->vel); p->accel[0] = p->accel[1] = 0; p->accel[2] = -PARTICLE_GRAVITY/2; p->alpha = 1.0; p->alphavel = -1.0 / (0.5 + frand()*0.3); } }
//---------------------------------------------------------- void fx_runner_think( gentity_t *ent ) { vec3_t temp; EvaluateTrajectory( &ent->s.pos, level.time, ent->currentOrigin ); EvaluateTrajectory( &ent->s.apos, level.time, ent->currentAngles ); // call the effect with the desired position and orientation G_AddEvent( ent, EV_PLAY_EFFECT, ent->fxID ); // Assume angles, we'll do a cross product on the other end to finish up AngleVectors( ent->currentAngles, ent->pos3, NULL, NULL ); MakeNormalVectors( ent->pos3, ent->pos4, temp ); // there IS a reason this is done...it's so that it doesn't break every effect in the game... ent->nextthink = level.time + ent->delay + random() * ent->random; if ( ent->spawnflags & 4 ) // damage { G_RadiusDamage( ent->currentOrigin, ent, ent->splashDamage, ent->splashRadius, ent, MOD_UNKNOWN ); } if ( ent->target2 ) { // let our target know that we have spawned an effect G_UseTargets2( ent, ent, ent->target2 ); } if ( !(ent->spawnflags & 2 ) && !ent->s.loopSound ) // NOT ONESHOT...this is an assy thing to do { if ( VALIDSTRING( ent->soundSet ) == true ) { ent->s.loopSound = CAS_GetBModelSound( ent->soundSet, BMS_MID ); if ( ent->s.loopSound < 0 ) { ent->s.loopSound = 0; } } } }
/* ====== CL_DebugTrail ====== */ void CL_DebugTrail (const vec3_t start, const vec3_t end) { vec3_t move, vec; float len; cparticle_t *p; float dec = 3; vec3_t right, up; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); MakeNormalVectors (vec, right, up); VectorScale (vec, dec, vec); VectorCopy (start, move); while (len > 0) { len -= dec; if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; VectorClear (p->accel); VectorClear (p->vel); p->alpha = 1.0f; p->alphavel = -0.1f; p->color = 0x74 + (rand()&7); VectorCopy (move, p->org); VectorAdd (move, vec, move); } }
/* =============== CL_ParticleSteamEffect Puffs with velocity along direction, with some randomness thrown in =============== */ void CL_ParticleSteamEffect (const vec3_t org, const vec3_t dir, int color, int count, int magnitude) { int i; cparticle_t *p; float d; vec3_t r, u; // VecToAngles(dir, angle_dir); // AngleVectors (angle_dir, f, r, u); MakeNormalVectors (dir, r, u); for (i=0 ; i<count ; i++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; p->color = color + (rand()&7); p->org[0] = org[0] + magnitude*0.1f*crand(); p->org[1] = org[1] + magnitude*0.1f*crand(); p->org[2] = org[2] + magnitude*0.1f*crand(); VectorScale (dir, magnitude, p->vel); d = crand()*magnitude*0.3333333333f; VectorMA (p->vel, d, r, p->vel); d = crand()*magnitude*0.3333333333f; VectorMA (p->vel, d, u, p->vel); p->accel[0] = p->accel[1] = 0; p->accel[2] = -PARTICLE_GRAVITY*0.5f; p->alpha = 1.0f; p->alphavel = -1.0f / (0.5f + frand()*0.3f); } }
void CL_ParticleSteamEffect2 (cl_sustain_t *self) { int i; cparticle_t *p; float d; vec3_t r, u, dir; VectorCopy (self->dir, dir); MakeNormalVectors (dir, r, u); for (i=0 ; i<self->count ; i++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; p->color = self->color + (rand()&7); p->org[0] = self->org[0] + self->magnitude*0.1f*crand(); p->org[1] = self->org[1] + self->magnitude*0.1f*crand(); p->org[2] = self->org[2] + self->magnitude*0.1f*crand(); VectorScale (dir, self->magnitude, p->vel); d = crand()*self->magnitude*0.3333333333f; VectorMA (p->vel, d, r, p->vel); d = crand()*self->magnitude*0.3333333333f; VectorMA (p->vel, d, u, p->vel); p->accel[0] = p->accel[1] = 0; p->accel[2] = -PARTICLE_GRAVITY*0.5f; p->alpha = 1.0f; p->alphavel = -1.0f / (0.5f + frand()*0.3f); } self->nextthink += self->thinkinterval; }
void FXQuad::Draw( void ) { polyVert_t verts[NUM_QUADVERTS]; vec3_t vr, vu; vec3_t axis[3]; float scale; int i; scale = m_scale * 0.5f; MakeNormalVectors( m_normal, vr, vu ); VectorCopy( m_normal, axis[0] ); VectorCopy( vr, axis[1] ); VectorCopy( vu, axis[2] ); RotateAroundDirection( axis, m_roll ); //Construct the quad for ( i = 0; i < NUM_QUADVERTS; i++ ) { VectorMA( m_origin, quad_template[i][0] * ( scale ), axis[1], verts[i].xyz ); VectorMA( verts[i].xyz, quad_template[i][1] * ( scale ), axis[2], verts[i].xyz ); verts[i].modulate[0] = m_RGB[0] * 255; verts[i].modulate[1] = m_RGB[1] * 255; verts[i].modulate[2] = m_RGB[2] * 255; if ( m_flags & FXF_USE_ALPHA_CHAN ) verts[i].modulate[3] = (byte)(m_alpha * 255); else verts[i].modulate[3] = 255; verts[i].st[0] = quad_st_template[i][0]; verts[i].st[1] = quad_st_template[i][1]; } cgi_R_AddPolyToScene( m_shader, NUM_QUADVERTS, verts ); }
/* ================== CM_Trace ================== */ static void CM_Trace(trace_t *results, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, clipHandle_t model, const vec3_t origin, int brushmask, int capsule, sphere_t *sphere) { int i; traceWork_t tw; vec3_t offset; cmodel_t *cmod; qboolean positionTest; cmod = CM_ClipHandleToModel(model); cm.checkcount++; // for multi-check avoidance c_traces++; // for statistics, may be zeroed // fill in a default trace memset(&tw, 0, sizeof(tw)); tw.trace.fraction = 1.0f; // assume it goes the entire distance until shown otherwise VectorCopy(origin, tw.modelOrigin); if (!cm.numNodes) { *results = tw.trace; return; // map not loaded, shouldn't happen } // allow NULL to be passed in for 0,0,0 if (!mins) { mins = vec3_origin; } if (!maxs) { maxs = vec3_origin; } // set basic parms tw.contents = brushmask; // adjust so that mins and maxs are always symetric, which // avoids some complications with plane expanding of rotated // bmodels for (i = 0 ; i < 3 ; i++) { offset[i] = (mins[i] + maxs[i]) * 0.5; tw.size[0][i] = mins[i] - offset[i]; tw.size[1][i] = maxs[i] - offset[i]; tw.start[i] = start[i] + offset[i]; tw.end[i] = end[i] + offset[i]; } // if a sphere is already specified if (sphere) { tw.sphere = *sphere; } else { tw.sphere.use = capsule; tw.sphere.radius = (tw.size[1][0] > tw.size[1][2]) ? tw.size[1][2] : tw.size[1][0]; tw.sphere.halfheight = tw.size[1][2]; VectorSet(tw.sphere.offset, 0, 0, tw.size[1][2] - tw.sphere.radius); } positionTest = (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]); tw.maxOffset = tw.size[1][0] + tw.size[1][1] + tw.size[1][2]; // tw.offsets[signbits] = vector to apropriate corner from origin tw.offsets[0][0] = tw.size[0][0]; tw.offsets[0][1] = tw.size[0][1]; tw.offsets[0][2] = tw.size[0][2]; tw.offsets[1][0] = tw.size[1][0]; tw.offsets[1][1] = tw.size[0][1]; tw.offsets[1][2] = tw.size[0][2]; tw.offsets[2][0] = tw.size[0][0]; tw.offsets[2][1] = tw.size[1][1]; tw.offsets[2][2] = tw.size[0][2]; tw.offsets[3][0] = tw.size[1][0]; tw.offsets[3][1] = tw.size[1][1]; tw.offsets[3][2] = tw.size[0][2]; tw.offsets[4][0] = tw.size[0][0]; tw.offsets[4][1] = tw.size[0][1]; tw.offsets[4][2] = tw.size[1][2]; tw.offsets[5][0] = tw.size[1][0]; tw.offsets[5][1] = tw.size[0][1]; tw.offsets[5][2] = tw.size[1][2]; tw.offsets[6][0] = tw.size[0][0]; tw.offsets[6][1] = tw.size[1][1]; tw.offsets[6][2] = tw.size[1][2]; tw.offsets[7][0] = tw.size[1][0]; tw.offsets[7][1] = tw.size[1][1]; tw.offsets[7][2] = tw.size[1][2]; // check for point special case if (tw.size[0][0] == 0.0f && tw.size[0][1] == 0.0f && tw.size[0][2] == 0.0f) { tw.isPoint = qtrue; VectorClear(tw.extents); } else { tw.isPoint = qfalse; tw.extents[0] = tw.size[1][0]; tw.extents[1] = tw.size[1][1]; tw.extents[2] = tw.size[1][2]; } if (positionTest) { CM_CalcTraceBounds(&tw, qfalse); } else { vec3_t dir; VectorSubtract(tw.end, tw.start, dir); VectorCopy(dir, tw.dir); VectorNormalize(dir); MakeNormalVectors(dir, tw.tracePlane1.normal, tw.tracePlane2.normal); tw.tracePlane1.dist = DotProduct(tw.tracePlane1.normal, tw.start); tw.tracePlane2.dist = DotProduct(tw.tracePlane2.normal, tw.start); if (tw.isPoint) { tw.traceDist1 = tw.traceDist2 = 1.0f; } else { float dist; tw.traceDist1 = tw.traceDist2 = 0.0f; for (i = 0; i < 8; i++) { dist = Q_fabs(DotProduct(tw.tracePlane1.normal, tw.offsets[i]) - tw.tracePlane1.dist); if (dist > tw.traceDist1) { tw.traceDist1 = dist; } dist = Q_fabs(DotProduct(tw.tracePlane2.normal, tw.offsets[i]) - tw.tracePlane2.dist); if (dist > tw.traceDist2) { tw.traceDist2 = dist; } } // expand for epsilon tw.traceDist1 += 1.0f; tw.traceDist2 += 1.0f; } CM_CalcTraceBounds(&tw, qtrue); } // check for position test special case if (positionTest) { if (model) { #ifdef ALWAYS_BBOX_VS_BBOX if (model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) { tw.sphere.use = qfalse; CM_TestInLeaf(&tw, &cmod->leaf); } else #elif defined(ALWAYS_CAPSULE_VS_CAPSULE) if (model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) { CM_TestCapsuleInCapsule(&tw, model); } else #else // this is dead code when ALWAYS_BBOX_VS_BBOX or ALWAYS_CAPSULE_VS_CAPSULE are active if (model == CAPSULE_MODEL_HANDLE) { if (tw.sphere.use) { CM_TestCapsuleInCapsule(&tw, model); } else { CM_TestBoundingBoxInCapsule(&tw, model); } } else #endif { CM_TestInLeaf(&tw, &cmod->leaf); } } else { CM_PositionTest(&tw); } } else { // general sweeping through world if (model) { #ifdef ALWAYS_BBOX_VS_BBOX if (model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) { tw.sphere.use = qfalse; CM_TraceThroughLeaf(&tw, &cmod->leaf); } else #elif defined(ALWAYS_CAPSULE_VS_CAPSULE) if (model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) { CM_TraceCapsuleThroughCapsule(&tw, model); } else #else // this is dead code when ALWAYS_BBOX_VS_BBOX or ALWAYS_CAPSULE_VS_CAPSULE are active if (model == CAPSULE_MODEL_HANDLE) { if (tw.sphere.use) { CM_TraceCapsuleThroughCapsule(&tw, model); } else { CM_TraceBoundingBoxThroughCapsule(&tw, model); } } else #endif { CM_TraceThroughLeaf(&tw, &cmod->leaf); } } else { CM_TraceThroughTree(&tw, 0, 0, 1, tw.start, tw.end); } } // generate endpos from the original, unmodified start/end if (tw.trace.fraction == 1) { VectorCopy(end, tw.trace.endpos); } else { for (i = 0 ; i < 3 ; i++) { tw.trace.endpos[i] = start[i] + tw.trace.fraction * (end[i] - start[i]); } } *results = tw.trace; }
/* ==================== AddEdge ==================== */ int AddEdge( vec3_t v1, vec3_t v2, qboolean createNonAxial ) { int i; edgeLine_t *e; float d; vec3_t dir; VectorSubtract( v2, v1, dir ); d = VectorNormalize( dir, dir ); if ( d < 0.1 ) { // if we added a 0 length vector, it would make degenerate planes c_degenerateEdges++; return -1; } if ( !createNonAxial ) { if ( fabs( dir[0] + dir[1] + dir[2] ) != 1.0 ) { if ( numOriginalEdges == MAX_ORIGINAL_EDGES ) { Error( "MAX_ORIGINAL_EDGES" ); } originalEdges[ numOriginalEdges ].dv[0] = (bspDrawVert_t *)v1; originalEdges[ numOriginalEdges ].dv[1] = (bspDrawVert_t *)v2; originalEdges[ numOriginalEdges ].length = d; numOriginalEdges++; return -1; } } for ( i = 0 ; i < numEdgeLines ; i++ ) { e = &edgeLines[i]; d = DotProduct( v1, e->normal1 ) - e->dist1; if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) { continue; } d = DotProduct( v1, e->normal2 ) - e->dist2; if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) { continue; } d = DotProduct( v2, e->normal1 ) - e->dist1; if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) { continue; } d = DotProduct( v2, e->normal2 ) - e->dist2; if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) { continue; } // this is the edge InsertPointOnEdge( v1, e ); InsertPointOnEdge( v2, e ); return i; } // create a new edge if ( numEdgeLines >= MAX_EDGE_LINES ) { Error( "MAX_EDGE_LINES" ); } e = &edgeLines[ numEdgeLines ]; numEdgeLines++; e->chain.next = e->chain.prev = &e->chain; VectorCopy( v1, e->origin ); VectorCopy( dir, e->dir ); MakeNormalVectors( e->dir, e->normal1, e->normal2 ); e->dist1 = DotProduct( e->origin, e->normal1 ); e->dist2 = DotProduct( e->origin, e->normal2 ); InsertPointOnEdge( v1, e ); InsertPointOnEdge( v2, e ); return numEdgeLines - 1; }
/* ==================== AddEdge ==================== */ int AddEdge( vec3_t v1, vec3_t v2, qboolean createNonAxial ) { int i; edgeLine_t *e; float d; vec3_t dir; VectorSubtract( v2, v1, dir ); d = VectorNormalize( dir, dir ); if ( d < 0.1 ) { // if we added a 0 length vector, it would make degenerate planes c_degenerateEdges++; return -1; } if ( !createNonAxial ) { if ( fabs( dir[0] + dir[1] + dir[2] ) != 1.0 ) { AUTOEXPAND_BY_REALLOC( originalEdges, numOriginalEdges, allocatedOriginalEdges, 1024 ); originalEdges[ numOriginalEdges ].dv[0] = (bspDrawVert_t *)v1; originalEdges[ numOriginalEdges ].dv[1] = (bspDrawVert_t *)v2; originalEdges[ numOriginalEdges ].length = d; numOriginalEdges++; return -1; } } for ( i = 0 ; i < numEdgeLines ; i++ ) { e = &edgeLines[i]; d = DotProduct( v1, e->normal1 ) - e->dist1; if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) { continue; } d = DotProduct( v1, e->normal2 ) - e->dist2; if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) { continue; } d = DotProduct( v2, e->normal1 ) - e->dist1; if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) { continue; } d = DotProduct( v2, e->normal2 ) - e->dist2; if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) { continue; } // this is the edge InsertPointOnEdge( v1, e ); InsertPointOnEdge( v2, e ); return i; } // create a new edge AUTOEXPAND_BY_REALLOC( edgeLines, numEdgeLines, allocatedEdgeLines, 1024 ); e = &edgeLines[ numEdgeLines ]; numEdgeLines++; e->chain = safe_malloc( sizeof( edgePoint_t ) ); e->chain->next = e->chain->prev = e->chain; VectorCopy( v1, e->origin ); VectorCopy( dir, e->dir ); MakeNormalVectors( e->dir, e->normal1, e->normal2 ); e->dist1 = DotProduct( e->origin, e->normal1 ); e->dist2 = DotProduct( e->origin, e->normal2 ); InsertPointOnEdge( v1, e ); InsertPointOnEdge( v2, e ); return numEdgeLines - 1; }
void QClipMap46::Trace( q3trace_t* results, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, clipHandle_t model, const vec3_t origin, int brushmask, int capsule, sphere_t* sphere ) { int i; traceWork_t tw; vec3_t offset; cmodel_t* cmod; cmod = ClipHandleToModel( model ); checkcount++; // for multi-check avoidance c_traces++; // for statistics, may be zeroed // fill in a default trace Com_Memset( &tw, 0, sizeof ( tw ) ); tw.trace.fraction = 1; // assume it goes the entire distance until shown otherwise VectorCopy( origin, tw.modelOrigin ); if ( !numNodes ) { *results = tw.trace; return; // map not loaded, shouldn't happen } // allow NULL to be passed in for 0,0,0 if ( !mins ) { mins = oldvec3_origin; } if ( !maxs ) { maxs = oldvec3_origin; } // set basic parms tw.contents = brushmask; // adjust so that mins and maxs are always symetric, which // avoids some complications with plane expanding of rotated // bmodels for ( i = 0; i < 3; i++ ) { offset[ i ] = ( mins[ i ] + maxs[ i ] ) * 0.5; tw.size[ 0 ][ i ] = mins[ i ] - offset[ i ]; tw.size[ 1 ][ i ] = maxs[ i ] - offset[ i ]; tw.start[ i ] = start[ i ] + offset[ i ]; tw.end[ i ] = end[ i ] + offset[ i ]; } // if a sphere is already specified if ( sphere ) { tw.sphere = *sphere; } else { tw.sphere.use = capsule; tw.sphere.radius = ( tw.size[ 1 ][ 0 ] > tw.size[ 1 ][ 2 ] ) ? tw.size[ 1 ][ 2 ] : tw.size[ 1 ][ 0 ]; tw.sphere.halfheight = tw.size[ 1 ][ 2 ]; VectorSet( tw.sphere.offset, 0, 0, tw.size[ 1 ][ 2 ] - tw.sphere.radius ); } bool positionTest = start[ 0 ] == end[ 0 ] && start[ 1 ] == end[ 1 ] && start[ 2 ] == end[ 2 ]; tw.maxOffset = tw.size[ 1 ][ 0 ] + tw.size[ 1 ][ 1 ] + tw.size[ 1 ][ 2 ]; // tw.offsets[signbits] = vector to apropriate corner from origin tw.offsets[ 0 ][ 0 ] = tw.size[ 0 ][ 0 ]; tw.offsets[ 0 ][ 1 ] = tw.size[ 0 ][ 1 ]; tw.offsets[ 0 ][ 2 ] = tw.size[ 0 ][ 2 ]; tw.offsets[ 1 ][ 0 ] = tw.size[ 1 ][ 0 ]; tw.offsets[ 1 ][ 1 ] = tw.size[ 0 ][ 1 ]; tw.offsets[ 1 ][ 2 ] = tw.size[ 0 ][ 2 ]; tw.offsets[ 2 ][ 0 ] = tw.size[ 0 ][ 0 ]; tw.offsets[ 2 ][ 1 ] = tw.size[ 1 ][ 1 ]; tw.offsets[ 2 ][ 2 ] = tw.size[ 0 ][ 2 ]; tw.offsets[ 3 ][ 0 ] = tw.size[ 1 ][ 0 ]; tw.offsets[ 3 ][ 1 ] = tw.size[ 1 ][ 1 ]; tw.offsets[ 3 ][ 2 ] = tw.size[ 0 ][ 2 ]; tw.offsets[ 4 ][ 0 ] = tw.size[ 0 ][ 0 ]; tw.offsets[ 4 ][ 1 ] = tw.size[ 0 ][ 1 ]; tw.offsets[ 4 ][ 2 ] = tw.size[ 1 ][ 2 ]; tw.offsets[ 5 ][ 0 ] = tw.size[ 1 ][ 0 ]; tw.offsets[ 5 ][ 1 ] = tw.size[ 0 ][ 1 ]; tw.offsets[ 5 ][ 2 ] = tw.size[ 1 ][ 2 ]; tw.offsets[ 6 ][ 0 ] = tw.size[ 0 ][ 0 ]; tw.offsets[ 6 ][ 1 ] = tw.size[ 1 ][ 1 ]; tw.offsets[ 6 ][ 2 ] = tw.size[ 1 ][ 2 ]; tw.offsets[ 7 ][ 0 ] = tw.size[ 1 ][ 0 ]; tw.offsets[ 7 ][ 1 ] = tw.size[ 1 ][ 1 ]; tw.offsets[ 7 ][ 2 ] = tw.size[ 1 ][ 2 ]; // // check for point special case // if ( tw.size[ 0 ][ 0 ] == 0 && tw.size[ 0 ][ 1 ] == 0 && tw.size[ 0 ][ 2 ] == 0 ) { tw.isPoint = true; VectorClear( tw.extents ); } else { tw.isPoint = false; tw.extents[ 0 ] = tw.size[ 1 ][ 0 ]; tw.extents[ 1 ] = tw.size[ 1 ][ 1 ]; tw.extents[ 2 ] = tw.size[ 1 ][ 2 ]; } if ( GGameType & GAME_ET ) { if ( positionTest ) { CalcTraceBounds( &tw, false ); } else { vec3_t dir; VectorSubtract( tw.end, tw.start, dir ); VectorCopy( dir, tw.dir ); VectorNormalize( dir ); MakeNormalVectors( dir, tw.tracePlane1.normal, tw.tracePlane2.normal ); tw.tracePlane1.dist = DotProduct( tw.tracePlane1.normal, tw.start ); tw.tracePlane2.dist = DotProduct( tw.tracePlane2.normal, tw.start ); if ( tw.isPoint ) { tw.traceDist1 = tw.traceDist2 = 1.0f; } else { tw.traceDist1 = tw.traceDist2 = 0.0f; for ( i = 0; i < 8; i++ ) { float dist = idMath::Fabs( DotProduct( tw.tracePlane1.normal, tw.offsets[ i ] ) - tw.tracePlane1.dist ); if ( dist > tw.traceDist1 ) { tw.traceDist1 = dist; } dist = idMath::Fabs( DotProduct( tw.tracePlane2.normal, tw.offsets[ i ] ) - tw.tracePlane2.dist ); if ( dist > tw.traceDist2 ) { tw.traceDist2 = dist; } } // expand for epsilon tw.traceDist1 += 1.0f; tw.traceDist2 += 1.0f; } CalcTraceBounds( &tw, true ); } } else { // // calculate bounds // if ( tw.sphere.use ) { for ( i = 0; i < 3; i++ ) { if ( tw.start[ i ] < tw.end[ i ] ) { tw.bounds[ 0 ][ i ] = tw.start[ i ] - idMath::Fabs( tw.sphere.offset[ i ] ) - tw.sphere.radius; tw.bounds[ 1 ][ i ] = tw.end[ i ] + idMath::Fabs( tw.sphere.offset[ i ] ) + tw.sphere.radius; } else { tw.bounds[ 0 ][ i ] = tw.end[ i ] - idMath::Fabs( tw.sphere.offset[ i ] ) - tw.sphere.radius; tw.bounds[ 1 ][ i ] = tw.start[ i ] + idMath::Fabs( tw.sphere.offset[ i ] ) + tw.sphere.radius; } } } else { for ( i = 0; i < 3; i++ ) { if ( tw.start[ i ] < tw.end[ i ] ) { tw.bounds[ 0 ][ i ] = tw.start[ i ] + tw.size[ 0 ][ i ]; tw.bounds[ 1 ][ i ] = tw.end[ i ] + tw.size[ 1 ][ i ]; } else { tw.bounds[ 0 ][ i ] = tw.end[ i ] + tw.size[ 0 ][ i ]; tw.bounds[ 1 ][ i ] = tw.start[ i ] + tw.size[ 1 ][ i ]; } } } } // // check for position test special case // if ( positionTest ) { if ( model ) { if ( GGameType & ( GAME_WolfSP | GAME_ET ) ) { // Always box vs. box. if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE ) { tw.sphere.use = false; } TestInLeaf( &tw, &cmod->leaf ); } else { #ifdef ALWAYS_BBOX_VS_BBOX // bk010201 - FIXME - compile time flag? if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE ) { tw.sphere.use = false; TestInLeaf( &tw, &cmod->leaf ); } else #elif defined( ALWAYS_CAPSULE_VS_CAPSULE ) if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE ) { TestCapsuleInCapsule( &tw, model ); } else #endif if ( model == CAPSULE_MODEL_HANDLE ) { if ( tw.sphere.use ) { TestCapsuleInCapsule( &tw, model ); } else { TestBoundingBoxInCapsule( &tw, model ); } } else { TestInLeaf( &tw, &cmod->leaf ); } } } else { PositionTest( &tw ); } } else { // // general sweeping through world // if ( model ) { if ( GGameType & ( GAME_WolfSP | GAME_ET ) ) { // Always box vs. box. if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE ) { tw.sphere.use = false; } TraceThroughLeaf( &tw, &cmod->leaf ); } else { #ifdef ALWAYS_BBOX_VS_BBOX if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE ) { tw.sphere.use = false; TraceThroughLeaf( &tw, &cmod->leaf ); } else #elif defined( ALWAYS_CAPSULE_VS_CAPSULE ) if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE ) { TraceCapsuleThroughCapsule( &tw, model ); } else #endif if ( model == CAPSULE_MODEL_HANDLE ) { if ( tw.sphere.use ) { TraceCapsuleThroughCapsule( &tw, model ); } else { TraceBoundingBoxThroughCapsule( &tw, model ); } } else { TraceThroughLeaf( &tw, &cmod->leaf ); } } } else { TraceThroughTree( &tw, 0, 0, 1, tw.start, tw.end ); } } // generate endpos from the original, unmodified start/end if ( tw.trace.fraction == 1 ) { VectorCopy( end, tw.trace.endpos ); } else { for ( i = 0; i < 3; i++ ) { tw.trace.endpos[ i ] = start[ i ] + tw.trace.fraction * ( end[ i ] - start[ i ] ); } } // If allsolid is set (was entirely inside something solid), the plane is not valid. // If fraction == 1.0, we never hit anything, and thus the plane is not valid. // Otherwise, the normal on the plane should have unit length assert( tw.trace.allsolid || tw.trace.fraction == 1.0 || VectorLengthSquared( tw.trace.plane.normal ) > 0.9999 ); *results = tw.trace; }
/* =============== CL_RailTrail =============== */ void CL_RailTrail (const vec3_t start, const vec3_t end) { vec3_t move, vec, right, up, dir; float len, dec, c, s; cparticle_t *p; int i; byte clr = 0x74; cdlight_t *dl; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); // add a light at the dest dl = CL_AllocDlight(0); VectorCopy(end, dl->origin); dl->radius = 100; dl->die = cl.time + 200; VectorSet(dl->color, 0.3, 0.5, 1.0); MakeNormalVectors (vec, right, up); for (i=0 ; i<len ; i++) { if(i % 3 == 0){ VectorAdd(move, vec, move); continue; } if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; VectorClear (p->accel); Q_sincos(i * 0.1f, &s, &c); VectorScale (right, c, dir); VectorMA (dir, s, up, dir); p->alpha = 1.0f; p->alphavel = -1.0f / (1.0f+frand()*0.2f); p->color = clr + (rand()&7); p->org[0] = move[0] + dir[0]*3; p->org[1] = move[1] + dir[1]*3; p->org[2] = move[2] + dir[2]*3; p->vel[0] = dir[0]*6; p->vel[1] = dir[1]*6; p->vel[2] = dir[2]*6; VectorAdd (move, vec, move); } dec = 2.0f; VectorScale (vec, dec, vec); VectorCopy (start, move); while (len > 0) { len -= dec; if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; VectorClear (p->accel); p->alpha = 1.0f; p->alphavel = -1.0f / (0.6f+frand()*0.2f); p->color = 0x0 + (rand()&15); p->org[0] = move[0] + crand()*3; p->org[1] = move[1] + crand()*3; p->org[2] = move[2] + crand()*3; p->vel[0] = crand()*3; p->vel[1] = crand()*3; p->vel[2] = crand()*3; VectorAdd (move, vec, move); } }
//--------------------------------------------------------- void FireWeapon( gentity_t *ent, qboolean alt_fire ) //--------------------------------------------------------- { float alert = 256; Vehicle_t *pVeh = NULL; // track shots taken for accuracy tracking. ent->client->ps.persistant[PERS_ACCURACY_SHOTS]++; // If this is a vehicle, fire it's weapon and we're done. if ( ent && ent->client && ent->client->NPC_class == CLASS_VEHICLE ) { FireVehicleWeapon( ent, alt_fire ); return; } // set aiming directions if ( ent->s.weapon == WP_DISRUPTOR && alt_fire ) { if ( ent->NPC ) { //snipers must use the angles they actually did their shot trace with AngleVectors( ent->lastAngles, forwardVec, vrightVec, up ); } } else if ( ent->s.weapon == WP_ATST_SIDE || ent->s.weapon == WP_ATST_MAIN ) { vec3_t delta1, enemy_org1, muzzle1; vec3_t angleToEnemy1; VectorCopy( ent->client->renderInfo.muzzlePoint, muzzle1 ); if ( !ent->s.number ) {//player driving an AT-ST //SIGH... because we can't anticipate alt-fire, must calc muzzle here and now mdxaBone_t boltMatrix; int bolt; if ( ent->client->ps.weapon == WP_ATST_MAIN ) {//FIXME: alt_fire should fire both barrels, but slower? if ( ent->alt_fire ) { bolt = ent->handRBolt; } else { bolt = ent->handLBolt; } } else {// ATST SIDE weapons if ( ent->alt_fire ) { if ( gi.G2API_GetSurfaceRenderStatus( &ent->ghoul2[ent->playerModel], "head_light_blaster_cann" ) ) {//don't have it! return; } bolt = ent->genericBolt2; } else { if ( gi.G2API_GetSurfaceRenderStatus( &ent->ghoul2[ent->playerModel], "head_concussion_charger" ) ) {//don't have it! return; } bolt = ent->genericBolt1; } } vec3_t yawOnlyAngles = {0, ent->currentAngles[YAW], 0}; if ( ent->currentAngles[YAW] != ent->client->ps.legsYaw ) { yawOnlyAngles[YAW] = ent->client->ps.legsYaw; } gi.G2API_GetBoltMatrix( ent->ghoul2, ent->playerModel, bolt, &boltMatrix, yawOnlyAngles, ent->currentOrigin, (cg.time?cg.time:level.time), NULL, ent->s.modelScale ); // work the matrix axis stuff into the original axis and origins used. gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, ent->client->renderInfo.muzzlePoint ); gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_Y, ent->client->renderInfo.muzzleDir ); ent->client->renderInfo.mPCalcTime = level.time; AngleVectors( ent->client->ps.viewangles, forwardVec, vrightVec, up ); //CalcMuzzlePoint( ent, forwardVec, vrightVec, up, muzzle, 0 ); } else if ( !ent->enemy ) {//an NPC with no enemy to auto-aim at VectorCopy( ent->client->renderInfo.muzzleDir, forwardVec ); } else {//NPC, auto-aim at enemy CalcEntitySpot( ent->enemy, SPOT_HEAD, enemy_org1 ); VectorSubtract (enemy_org1, muzzle1, delta1); vectoangles ( delta1, angleToEnemy1 ); AngleVectors (angleToEnemy1, forwardVec, vrightVec, up); } } else if ( ent->s.weapon == WP_BOT_LASER && ent->enemy ) { vec3_t delta1, enemy_org1, muzzle1; vec3_t angleToEnemy1; CalcEntitySpot( ent->enemy, SPOT_HEAD, enemy_org1 ); CalcEntitySpot( ent, SPOT_WEAPON, muzzle1 ); VectorSubtract (enemy_org1, muzzle1, delta1); vectoangles ( delta1, angleToEnemy1 ); AngleVectors (angleToEnemy1, forwardVec, vrightVec, up); } else { if ( (pVeh = G_IsRidingVehicle( ent )) != NULL) //riding a vehicle {//use our muzzleDir, can't use viewangles or vehicle m_vOrientation because we may be animated to shoot left or right... if ((ent->s.eFlags&EF_NODRAW))//we're inside it { vec3_t aimAngles; VectorCopy( ent->client->renderInfo.muzzleDir, forwardVec ); vectoangles( forwardVec, aimAngles ); //we're only keeping the yaw aimAngles[PITCH] = ent->client->ps.viewangles[PITCH]; aimAngles[ROLL] = 0; AngleVectors( aimAngles, forwardVec, vrightVec, up ); } else { vec3_t actorRight; vec3_t actorFwd; VectorCopy( ent->client->renderInfo.muzzlePoint, muzzle ); AngleVectors(ent->currentAngles, actorFwd, actorRight, 0); // Aiming Left //------------- if (ent->client->ps.torsoAnim==BOTH_VT_ATL_G || ent->client->ps.torsoAnim==BOTH_VS_ATL_G) { VectorScale(actorRight, -1.0f, forwardVec); } // Aiming Right //-------------- else if (ent->client->ps.torsoAnim==BOTH_VT_ATR_G || ent->client->ps.torsoAnim==BOTH_VS_ATR_G) { VectorCopy(actorRight, forwardVec); } // Aiming Forward //---------------- else { VectorCopy(actorFwd, forwardVec); } // If We Have An Enemy, Fudge The Aim To Hit The Enemy if (ent->enemy) { vec3_t toEnemy; VectorSubtract(ent->enemy->currentOrigin, ent->currentOrigin, toEnemy); VectorNormalize(toEnemy); if (DotProduct(toEnemy, forwardVec)>0.75f && ((ent->s.number==0 && !Q_irand(0,2)) || // the player has a 1 in 3 chance (ent->s.number!=0 && !Q_irand(0,5)))) // other guys have a 1 in 6 chance { VectorCopy(toEnemy, forwardVec); } else { forwardVec[0] += Q_flrand(-0.1f, 0.1f); forwardVec[1] += Q_flrand(-0.1f, 0.1f); forwardVec[2] += Q_flrand(-0.1f, 0.1f); } } } } else { AngleVectors( ent->client->ps.viewangles, forwardVec, vrightVec, up ); } } ent->alt_fire = alt_fire; if (!pVeh) { if (ent->NPC && (ent->NPC->scriptFlags&SCF_FIRE_WEAPON_NO_ANIM)) { VectorCopy( ent->client->renderInfo.muzzlePoint, muzzle ); VectorCopy( ent->client->renderInfo.muzzleDir, forwardVec ); MakeNormalVectors(forwardVec, vrightVec, up); } else { CalcMuzzlePoint ( ent, forwardVec, vrightVec, up, muzzle , 0); } } // fire the specific weapon switch( ent->s.weapon ) { // Player weapons //----------------- case WP_SABER: return; break; case WP_BRYAR_PISTOL: case WP_BLASTER_PISTOL: WP_FireBryarPistol( ent, alt_fire ); break; case WP_BLASTER: WP_FireBlaster( ent, alt_fire ); break; case WP_TUSKEN_RIFLE: if ( alt_fire ) { WP_FireTuskenRifle( ent ); } else { WP_Melee( ent ); } break; case WP_DISRUPTOR: alert = 50; // if you want it to alert enemies, remove this WP_FireDisruptor( ent, alt_fire ); break; case WP_BOWCASTER: WP_FireBowcaster( ent, alt_fire ); break; case WP_REPEATER: WP_FireRepeater( ent, alt_fire ); break; case WP_DEMP2: WP_FireDEMP2( ent, alt_fire ); break; case WP_FLECHETTE: WP_FireFlechette( ent, alt_fire ); break; case WP_ROCKET_LAUNCHER: WP_FireRocket( ent, alt_fire ); break; case WP_CONCUSSION: WP_Concussion( ent, alt_fire ); break; case WP_THERMAL: WP_FireThermalDetonator( ent, alt_fire ); break; case WP_TRIP_MINE: alert = 0; // if you want it to alert enemies, remove this WP_PlaceLaserTrap( ent, alt_fire ); break; case WP_DET_PACK: alert = 0; // if you want it to alert enemies, remove this WP_FireDetPack( ent, alt_fire ); break; case WP_BOT_LASER: WP_BotLaser( ent ); break; case WP_EMPLACED_GUN: // doesn't care about whether it's alt-fire or not. We can do an alt-fire if needed WP_EmplacedFire( ent ); break; case WP_MELEE: alert = 0; // if you want it to alert enemies, remove this if ( !alt_fire || !g_debugMelee->integer ) { WP_Melee( ent ); } break; case WP_ATST_MAIN: WP_ATSTMainFire( ent ); break; case WP_ATST_SIDE: // TEMP if ( alt_fire ) { // WP_FireRocket( ent, qfalse ); WP_ATSTSideAltFire(ent); } else { // FIXME! /* if ( ent->s.number == 0 && ent->client->NPC_class == CLASS_VEHICLE && vehicleData[((CVehicleNPC *)ent->NPC)->m_iVehicleTypeID].type == VH_FIGHTER ) { WP_ATSTMainFire( ent ); } else*/ { WP_ATSTSideFire(ent); } } break; case WP_TIE_FIGHTER: // TEMP WP_EmplacedFire( ent ); break; case WP_RAPID_FIRE_CONC: // TEMP if ( alt_fire ) { WP_FireRepeater( ent, alt_fire ); } else { WP_EmplacedFire( ent ); } break; case WP_STUN_BATON: WP_FireStunBaton( ent, alt_fire ); break; // case WP_BLASTER_PISTOL: case WP_JAWA: WP_FireBryarPistol( ent, qfalse ); // never an alt-fire? break; case WP_SCEPTER: WP_FireScepter( ent, alt_fire ); break; case WP_NOGHRI_STICK: if ( !alt_fire ) { WP_FireNoghriStick( ent ); } //else does melee attack/damage/func break; case WP_TUSKEN_STAFF: default: return; break; } if ( !ent->s.number ) { if ( ent->s.weapon == WP_FLECHETTE || (ent->s.weapon == WP_BOWCASTER && !alt_fire) ) {//these can fire multiple shots, count them individually within the firing functions } else if ( W_AccuracyLoggableWeapon( ent->s.weapon, alt_fire, MOD_UNKNOWN ) ) { ent->client->sess.missionStats.shotsFired++; } } // We should probably just use this as a default behavior, in special cases, just set alert to false. if ( ent->s.number == 0 && alert > 0 ) { if ( ent->client->ps.groundEntityNum == ENTITYNUM_WORLD//FIXME: check for sand contents type? && ent->s.weapon != WP_STUN_BATON && ent->s.weapon != WP_MELEE && ent->s.weapon != WP_TUSKEN_STAFF && ent->s.weapon != WP_THERMAL && ent->s.weapon != WP_TRIP_MINE && ent->s.weapon != WP_DET_PACK ) {//the vibration of the shot carries through your feet into the ground AddSoundEvent( ent, muzzle, alert, AEL_DISCOVERED, qfalse, qtrue ); } else {//an in-air alert AddSoundEvent( ent, muzzle, alert, AEL_DISCOVERED ); } AddSightEvent( ent, muzzle, alert*2, AEL_DISCOVERED, 20 ); } }
static void objectVec3_MakeNormalVectors( asvec3_t *r, asvec3_t *u, asvec3_t *self ) { MakeNormalVectors( self->v, r->v, u->v ); }
void FXCylinder::Draw( void ) { polyVert_t lower_points[NUM_CYLINDER_SEGMENTS], upper_points[NUM_CYLINDER_SEGMENTS], verts[4]; vec3_t vr, vu, vu2, midpoint, origin2; float detail, length; int i; int segments; // allow for overriding the LOD mechanism, not recommended, but hey, flexibility is often cool... if ( m_flags & FXF_NO_LOD ) { segments = NUM_CYLINDER_SEGMENTS; } else { //Work out the detail level of this cylinder VectorMA( m_origin, m_height * 0.5, m_normal, midpoint ); VectorSubtract( midpoint, cg.refdef.vieworg, midpoint ); length = VectorLengthSquared( midpoint ); detail = 1 - (length / (1024.0*1024.0) ); // FIXME: the bias doesn't really work all that great //Cylinder bias is simply implemented as a multiplier segments = NUM_CYLINDER_SEGMENTS * detail * m_bias; // 3 is the absolute minimum, but the pop between 3, 4 and 5 is too noticeable if ( segments < 7 ) { segments = 7; } if ( segments > NUM_CYLINDER_SEGMENTS ) { segments = NUM_CYLINDER_SEGMENTS; } } //Get the direction vector MakeNormalVectors( m_normal, vr, vu ); VectorScale( vu, m_scale2 * 0.5, vu2 ); VectorScale( vu, m_scale * 0.5, vu ); VectorMA( m_origin, m_height, m_normal, origin2 ); // Calculate the step around the cylinder detail = 360.0 / (float)segments; for ( i = 0; i < segments ; i++ ) { //Upper ring RotatePointAroundVector( upper_points[i].xyz, m_normal, vu, detail * i ); VectorAdd( upper_points[i].xyz, m_origin, upper_points[i].xyz ); //Lower ring RotatePointAroundVector( lower_points[i].xyz, m_normal, vu2, detail * i ); VectorAdd( lower_points[i].xyz, origin2, lower_points[i].xyz ); } // Calculate the texture coords so the texture can wrap around the whole cylinder if ( m_flags & FXF_WRAP ) { if ( m_flags & FXF_STRETCH ) detail = 1.0f / (float)segments; else detail = m_stScale / (float)segments; } for ( i = 0; i < segments ; i++ ) { int nextSegment = ( i + 1 == segments ) ? 0 : i + 1; if ( m_flags & FXF_WRAP ) { verts[0].st[0] = detail * i; verts[1].st[0] = detail * i; verts[2].st[0] = detail * ( i + 1 ); verts[3].st[0] = detail * ( i + 1 ); } else { verts[0].st[0] = 0.0f; verts[1].st[0] = 0.0f; verts[2].st[0] = m_stScale; verts[3].st[0] = m_stScale; } if( m_flags & FXF_STRETCH ) { verts[0].st[1] = m_stScale; verts[1].st[1] = 0.0f; verts[2].st[1] = 0.0f; verts[3].st[1] = m_stScale; } else { verts[0].st[1] = 1.0f; verts[1].st[1] = 0.0f; verts[2].st[1] = 0.0f; verts[3].st[1] = 1.0f; } VectorCopy( upper_points[i].xyz, verts[0].xyz ); verts[0].modulate[0] = m_RGB[0] * 255; verts[0].modulate[1] = m_RGB[1] * 255; verts[0].modulate[2] = m_RGB[2] * 255; VectorCopy( lower_points[i].xyz, verts[1].xyz ); verts[1].modulate[0] = m_RGB[0] * 255; verts[1].modulate[1] = m_RGB[1] * 255; verts[1].modulate[2] = m_RGB[2] * 255; VectorCopy( lower_points[nextSegment].xyz, verts[2].xyz ); verts[2].modulate[0] = m_RGB[0] * 255; verts[2].modulate[1] = m_RGB[1] * 255; verts[2].modulate[2] = m_RGB[2] * 255; VectorCopy( upper_points[nextSegment].xyz, verts[3].xyz ); verts[3].modulate[0] = m_RGB[0] * 255; verts[3].modulate[1] = m_RGB[1] * 255; verts[3].modulate[2] = m_RGB[2] * 255; if ( m_flags & FXF_USE_ALPHA_CHAN ) { verts[0].modulate[3] = verts[1].modulate[3] = verts[2].modulate[3] = verts[3].modulate[3] = (byte)(m_alpha * 255); } else { verts[0].modulate[3] = verts[1].modulate[3] = verts[2].modulate[3] = verts[3].modulate[3] = 255; } cgi_R_AddPolyToScene( m_shader, 4, verts ); } }
/* =============== CL_RailTrail =============== */ void CL_RailTrail (vec3_t start, vec3_t end) { vec3_t move; vec3_t vec; float len; int j; cparticle_t *p; float dec; vec3_t right, up; int i; float d, c, s; vec3_t dir; byte clr = 0x74; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); MakeNormalVectors (vec, right, up); for (i = 0; i < len; i++) { if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; VectorClear (p->accel); d = i * 0.1; Q_sincos (d, &s, &c); VectorScale (right, c, dir); VectorMA (dir, s, up, dir); p->alpha = 1.0; p->alphavel = -1.0 / (1 + frand () * 0.2); p->color = clr + (rand () & 7); for (j = 0; j < 3; j++) { p->org[j] = move[j] + dir[j] * 3; p->vel[j] = dir[j] * 6; } VectorAdd (move, vec, move); p->bounceFactor = 0.1f; p->ignoreGrav = true; } dec = 0.75; VectorScale (vec, dec, vec); VectorCopy (start, move); while (len > 0) { len -= dec; if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; VectorClear (p->accel); p->alpha = 1.0; p->alphavel = -1.0 / (0.6 + frand () * 0.2); p->color = 0x0 + rand () & 15; for (j = 0; j < 3; j++) { p->org[j] = move[j] + crand () * 3; p->vel[j] = crand () * 3; p->accel[j] = 0; } VectorAdd (move, vec, move); p->bounceFactor = 0.1f; p->ignoreGrav = true; } }
void CLQ2_RailTrail( vec3_t start, vec3_t end ) { byte clr = 0x74; vec3_t move; VectorCopy( start, move ); vec3_t vec; VectorSubtract( end, start, vec ); float len = VectorNormalize( vec ); vec3_t right, up; MakeNormalVectors( vec, right, up ); for ( int i = 0; i < len; i++ ) { cparticle_t* p = CL_AllocParticle(); if ( !p ) { return; } p->type = pt_q2static; VectorClear( p->accel ); float d = i * 0.1; float c = cos( d ); float s = sin( d ); vec3_t dir; VectorScale( right, c, dir ); VectorMA( dir, s, up, dir ); p->alpha = 1.0; p->alphavel = -1.0 / ( 1 + frand() * 0.2 ); p->color = clr + ( rand() & 7 ); for ( int j = 0; j < 3; j++ ) { p->org[ j ] = move[ j ] + dir[ j ] * 3; p->vel[ j ] = dir[ j ] * 6; } VectorAdd( move, vec, move ); } float dec = 0.75; VectorScale( vec, dec, vec ); VectorCopy( start, move ); 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 = -1.0 / ( 0.6 + frand() * 0.2 ); p->color = rand() & 15; for ( int j = 0; j < 3; j++ ) { p->org[ j ] = move[ j ] + crand() * 3; p->vel[ j ] = crand() * 3; p->accel[ j ] = 0; } VectorAdd( move, vec, move ); } }
/* ====== CL_DebugTrail ====== */ void CL_DebugTrail (vec3_t start, vec3_t end) { vec3_t move; vec3_t vec; float len; #ifndef QMAX cparticle_t *p; #endif float dec; vec3_t right, up; VectorCopy (start, move); VectorSubtract (end, start, vec); len = VectorNormalize (vec); MakeNormalVectors (vec, right, up); // VectorScale(vec, RT2_SKIP, vec); // dec = 1.0; // dec = 0.75; dec = 3; VectorScale (vec, dec, vec); VectorCopy (start, move); while (len > 0) { len -= dec; #ifdef QMAX setupParticle ( 0, 0, 0, move[0], move[1], move[2], 0, 0, 0, 0, 0, 0, 50, 50, 255, 0, 0, 0, 1, -0.75, 7.5, 0, particle_generic, 0, NULL,0); #else if (!free_particles) return; p = free_particles; free_particles = p->next; p->next = active_particles; active_particles = p; p->time = cl.time; VectorClear (p->accel); VectorClear (p->vel); p->alpha = 1.0; p->alphavel = -0.1; // p->alphavel = 0; p->color = 0x74 + (rand()&7); VectorCopy (move, p->org); /* for (j=0 ; j<3 ; j++) { p->org[j] = move[j] + crand()*2; p->vel[j] = crand()*3; p->accel[j] = 0; } */ #endif VectorAdd (move, vec, move); } }