/* ================ G_BounceItem ================ */ void G_BounceItem( gentity_t *ent, trace_t *trace ) { vec3_t velocity; float dot; int hitTime; // reflect the velocity on the trace plane hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction; EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity ); dot = DotProduct( velocity, trace->plane.normal ); VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta ); // cut the velocity to keep from bouncing forever VectorScale( ent->s.pos.trDelta, ent->physicsBounce, ent->s.pos.trDelta ); // check for stop if ( trace->plane.normal[2] > 0 && ent->s.pos.trDelta[2] < 40 ) { G_SetOrigin( ent, trace->endpos ); ent->s.groundEntityNum = trace->entityNum; return; } VectorAdd( ent->currentOrigin, trace->plane.normal, ent->currentOrigin); VectorCopy( ent->currentOrigin, ent->s.pos.trBase ); ent->s.pos.trTime = level.time; }
/* ================ CG_ReflectVelocity ================ */ void CG_ReflectVelocity( localEntity_t *le, trace_t *trace ) { vec3_t velocity; float dot; int hitTime; // reflect the velocity on the trace plane hitTime = cg.time - cg.frametime + cg.frametime * trace->fraction; EvaluateTrajectoryDelta( &le->pos, hitTime, velocity ); dot = DotProduct( velocity, trace->plane.normal ); VectorMA( velocity, -2*dot, trace->plane.normal, le->pos.trDelta ); VectorScale( le->pos.trDelta, le->bounceFactor, le->pos.trDelta ); VectorCopy( trace->endpos, le->pos.trBase ); le->pos.trTime = cg.time; // check for stop, making sure that even on low FPS systems it doesn't bobble if ( trace->allsolid || ( trace->plane.normal[2] > 0 && ( le->pos.trDelta[2] < 40 || le->pos.trDelta[2] < -cg.frametime * le->pos.trDelta[2] ) ) ) { le->pos.trType = TR_STATIONARY; } }
/* ================ G_BounceRollMissile ================ */ void G_BounceRollMissile( gentity_t *ent, trace_t *trace ) { vec3_t velocity, normal; float dot, speedXY, velocityZ, normalZ; int hitTime; // reflect the velocity on the trace plane hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction; EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity ); //Do horizontal //FIXME: Need to roll up, down slopes velocityZ = velocity[2]; velocity[2] = 0; speedXY = VectorLength( velocity );//friction VectorCopy( trace->plane.normal, normal ); normalZ = normal[2]; normal[2] = 0; dot = DotProduct( velocity, normal ); VectorMA( velocity, -2*dot, normal, ent->s.pos.trDelta ); //now do the z reflection //FIXME: Bobbles when it stops VectorSet( velocity, 0, 0, velocityZ ); VectorSet( normal, 0, 0, normalZ ); dot = DotProduct( velocity, normal )*-1; if ( dot > 10 ) { ent->s.pos.trDelta[2] = dot*0.3f;//not very bouncy } else { ent->s.pos.trDelta[2] = 0; } // check for stop if ( speedXY <= 0 ) { G_SetOrigin( ent, trace->endpos ); VectorCopy( ent->currentAngles, ent->s.apos.trBase ); VectorClear( ent->s.apos.trDelta ); ent->s.apos.trType = TR_STATIONARY; return; } //FIXME: rolling needs to match direction VectorCopy( ent->currentAngles, ent->s.apos.trBase ); VectorCopy( ent->s.pos.trDelta, ent->s.apos.trDelta ); //remember this spot VectorCopy( trace->endpos, ent->currentOrigin ); ent->s.pos.trTime = hitTime - 10; VectorCopy( ent->currentOrigin, ent->s.pos.trBase ); //VectorCopy( trace->plane.normal, ent->pos1 ); }
void FX_FlechetteProjectileThink( centity_t *cent, const struct weaponInfo_s *weapon ) { vec3_t forward; EvaluateTrajectoryDelta( ¢->gent->s.pos, cg.time, forward ); if ( VectorNormalize( forward ) == 0.0f ) { forward[2] = 1.0f; } theFxScheduler.PlayEffect( cgs.effects.flechetteShotEffect, cent->lerpOrigin, forward ); }
/* ================ G_BounceMissile ================ */ void G_BounceObject( gentity_t *ent, trace_t *trace ) { vec3_t velocity; float dot; int hitTime; // reflect the velocity on the trace plane hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction; EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity ); dot = DotProduct( velocity, trace->plane.normal ); float bounceFactor = 60/ent->mass; if ( bounceFactor > 1.0f ) { bounceFactor = 1.0f; } VectorMA( velocity, -2*dot*bounceFactor, trace->plane.normal, ent->s.pos.trDelta ); //FIXME: customized or material-based impact/bounce sounds if ( ent->s.eFlags & EF_BOUNCE_HALF ) { VectorScale( ent->s.pos.trDelta, 0.5, ent->s.pos.trDelta ); // check for stop if ( ((trace->plane.normal[2] > 0.7&&g_gravity->value>0) || (trace->plane.normal[2]<-0.7&&g_gravity->value<0)) && ((ent->s.pos.trDelta[2]<40&&g_gravity->value>0)||(ent->s.pos.trDelta[2]>-40&&g_gravity->value<0)) ) //this can happen even on very slightly sloped walls, so changed it from > 0 to > 0.7 { //G_SetOrigin( ent, trace->endpos ); //ent->nextthink = level.time + 500; ent->s.apos.trType = TR_STATIONARY; VectorCopy( ent->currentAngles, ent->s.apos.trBase ); VectorCopy( trace->endpos, ent->currentOrigin ); VectorCopy( trace->endpos, ent->s.pos.trBase ); ent->s.pos.trTime = level.time; return; } } // NEW--It would seem that we want to set our trBase to the trace endpos // and set the trTime to the actual time of impact.... // FIXME: Should we still consider adding the normal though?? VectorCopy( trace->endpos, ent->currentOrigin ); ent->s.pos.trTime = hitTime; VectorCopy( ent->currentOrigin, ent->s.pos.trBase ); VectorCopy( trace->plane.normal, ent->pos1 );//??? }
//------------------------------------------------------------------------- static void G_MissileStick( gentity_t *missile, gentity_t *other, trace_t *tr ) { if ( other->NPC || !Q_stricmp( other->classname, "misc_model_breakable" )) { // we bounce off of NPC's and misc model breakables because sticking to them requires too much effort vec3_t velocity; int hitTime = level.previousTime + ( level.time - level.previousTime ) * tr->fraction; EvaluateTrajectoryDelta( &missile->s.pos, hitTime, velocity ); float dot = DotProduct( velocity, tr->plane.normal ); G_SetOrigin( missile, tr->endpos ); VectorMA( velocity, -1.6f * dot, tr->plane.normal, missile->s.pos.trDelta ); VectorMA( missile->s.pos.trDelta, 10, tr->plane.normal, missile->s.pos.trDelta ); missile->s.pos.trTime = level.time - 10; // move a bit on the first frame // check for stop if ( tr->entityNum >= 0 && tr->entityNum < ENTITYNUM_WORLD && tr->plane.normal[2] > 0.7 && missile->s.pos.trDelta[2] < 40 ) //this can happen even on very slightly sloped walls, so changed it from > 0 to > 0.7 { missile->nextthink = level.time + 100; } else { // fall till we hit the ground missile->s.pos.trType = TR_GRAVITY; } return; // don't stick yet } if ( missile->e_TouchFunc != touchF_NULL ) { GEntity_TouchFunc( missile, other, tr ); } G_AddEvent( missile, EV_MISSILE_STICK, 0 ); if ( other->s.eType == ET_MOVER || other->e_DieFunc == dieF_funcBBrushDie || other->e_DieFunc == dieF_funcGlassDie) { // movers and breakable brushes need extra info...so sticky missiles can ride lifts and blow up when the thing they are attached to goes away. missile->s.groundEntityNum = tr->entityNum; } }
/* ================ G_BounceItem ================ */ void G_BounceItem( gentity_t *ent, trace_t *trace ) { vec3_t velocity; float dot; int hitTime; qboolean droppedSaber = qtrue; if ( ent->item && ent->item->giType == IT_WEAPON && ent->item->giTag == WP_SABER && (ent->flags&FL_DROPPED_ITEM) ) { droppedSaber = qtrue; } // reflect the velocity on the trace plane hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction; EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity ); dot = DotProduct( velocity, trace->plane.normal ); VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta ); // cut the velocity to keep from bouncing forever VectorScale( ent->s.pos.trDelta, ent->physicsBounce, ent->s.pos.trDelta ); if ( droppedSaber ) {//a dropped saber item //FIXME: use NPC_type (as saberType) to get proper bounce sound? WP_SaberFallSound( NULL, ent ); } // check for stop if ( trace->plane.normal[2] > 0 && ent->s.pos.trDelta[2] < 40 ) {//stop G_SetOrigin( ent, trace->endpos ); ent->s.groundEntityNum = trace->entityNum; if ( droppedSaber ) {//a dropped saber item //stop rotation VectorClear( ent->s.apos.trDelta ); ent->currentAngles[PITCH] = SABER_PITCH_HACK; ent->currentAngles[ROLL] = 0; if ( ent->NPC_type && ent->NPC_type[0] ) {//we have a valid saber for this saberInfo_t saber; if ( WP_SaberParseParms( ent->NPC_type, &saber ) ) { if ( (saber.saberFlags&SFL_BOLT_TO_WRIST) ) { ent->currentAngles[PITCH] = 0; } } } pitch_roll_for_slope( ent, trace->plane.normal, ent->currentAngles, qtrue ); G_SetAngles( ent, ent->currentAngles ); } return; } //bounce if ( droppedSaber ) {//a dropped saber item //change rotation VectorCopy( ent->currentAngles, ent->s.apos.trBase ); ent->s.apos.trType = TR_LINEAR; ent->s.apos.trTime = level.time; VectorSet( ent->s.apos.trDelta, Q_irand( -300, 300 ), Q_irand( -300, 300 ), Q_irand( -300, 300 ) ); } VectorAdd( ent->currentOrigin, trace->plane.normal, ent->currentOrigin); VectorCopy( ent->currentOrigin, ent->s.pos.trBase ); ent->s.pos.trTime = level.time; }
void G_MissileImpacted( gentity_t *ent, gentity_t *other, vec3_t impactPos, vec3_t normal, int hitLoc=HL_NONE ) { // impact damage if ( other->takedamage ) { // FIXME: wrong damage direction? if ( ent->damage ) { vec3_t velocity; EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity ); if ( VectorLength( velocity ) == 0 ) { velocity[2] = 1; // stepped on a grenade } int damage = ent->damage; if( other->client ) { class_t npc_class = other->client->NPC_class; // If we are a robot and we aren't currently doing the full body electricity... if ( npc_class == CLASS_SEEKER || npc_class == CLASS_PROBE || npc_class == CLASS_MOUSE || npc_class == CLASS_GONK || npc_class == CLASS_R2D2 || npc_class == CLASS_R5D2 || npc_class == CLASS_REMOTE || npc_class == CLASS_MARK1 || npc_class == CLASS_MARK2 || //npc_class == CLASS_PROTOCOL ||//no protocol, looks odd npc_class == CLASS_INTERROGATOR || npc_class == CLASS_ATST || npc_class == CLASS_SENTRY ) { // special droid only behaviors if ( other->client->ps.powerups[PW_SHOCKED] < level.time + 100 ) { // ... do the effect for a split second for some more feedback other->s.powerups |= ( 1 << PW_SHOCKED ); other->client->ps.powerups[PW_SHOCKED] = level.time + 450; } //FIXME: throw some sparks off droids,too } } G_Damage( other, ent, ent->owner, velocity, impactPos, damage, ent->dflags, ent->methodOfDeath, hitLoc); if ( ent->s.weapon == WP_DEMP2 ) {//a hit with demp2 decloaks saboteurs if ( other && other->client && other->client->NPC_class == CLASS_SABOTEUR ) {//FIXME: make this disabled cloak hold for some amount of time? Saboteur_Decloak( other, Q_irand( 3000, 10000 ) ); if ( ent->methodOfDeath == MOD_DEMP2_ALT ) {//direct hit with alt disabled cloak forever if ( other->NPC ) {//permanently disable the saboteur's cloak other->NPC->aiFlags &= ~NPCAI_SHIELDS; } } } } } } // is it cheaper in bandwidth to just remove this ent and create a new // one, rather than changing the missile into the explosion? //G_FreeEntity(ent); if ( (other->takedamage && other->client ) || (ent->s.weapon == WP_FLECHETTE && other->contents&CONTENTS_LIGHTSABER) ) { G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( normal ) ); ent->s.otherEntityNum = other->s.number; } else { G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( normal ) ); ent->s.otherEntityNum = other->s.number; } VectorCopy( normal, ent->pos1 ); if ( ent->owner )//&& ent->owner->s.number == 0 ) { //Add the event AddSoundEvent( ent->owner, ent->currentOrigin, 256, AEL_SUSPICIOUS, qfalse, qtrue ); AddSightEvent( ent->owner, ent->currentOrigin, 512, AEL_DISCOVERED, 75 ); } ent->freeAfterEvent = qtrue; // change over to a normal entity right at the point of impact ent->s.eType = ET_GENERAL; //SnapVectorTowards( trace->endpos, ent->s.pos.trBase ); // save net bandwidth VectorCopy( impactPos, ent->s.pos.trBase ); G_SetOrigin( ent, impactPos ); // splash damage (doesn't apply to person directly hit) if ( ent->splashDamage ) { G_RadiusDamage( impactPos, ent->owner, ent->splashDamage, ent->splashRadius, other, ent->splashMethodOfDeath ); } if ( ent->s.weapon == WP_NOGHRI_STICK ) { G_SpawnNoghriGasCloud( ent ); } gi.linkentity( ent ); }
/* ================ G_BounceMissile ================ */ void G_BounceMissile( gentity_t *ent, trace_t *trace ) { vec3_t velocity; float dot; int hitTime; // reflect the velocity on the trace plane hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction; EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity ); dot = DotProduct( velocity, trace->plane.normal ); VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta ); if ( ent->s.eFlags & EF_BOUNCE_SHRAPNEL ) { VectorScale( ent->s.pos.trDelta, 0.25f, ent->s.pos.trDelta ); ent->s.pos.trType = TR_GRAVITY; // check for stop if ( trace->plane.normal[2] > 0.7 && ent->s.pos.trDelta[2] < 40 ) //this can happen even on very slightly sloped walls, so changed it from > 0 to > 0.7 { G_SetOrigin( ent, trace->endpos ); ent->nextthink = level.time + 100; return; } } else if ( ent->s.eFlags & EF_BOUNCE_HALF ) { VectorScale( ent->s.pos.trDelta, 0.5, ent->s.pos.trDelta ); // check for stop if ( trace->plane.normal[2] > 0.7 && ent->s.pos.trDelta[2] < 40 ) //this can happen even on very slightly sloped walls, so changed it from > 0 to > 0.7 { if ( ent->s.weapon == WP_THERMAL ) {//roll when you "stop" ent->s.pos.trType = TR_INTERPOLATE; } else { G_SetOrigin( ent, trace->endpos ); ent->nextthink = level.time + 500; return; } } if ( ent->s.weapon == WP_THERMAL ) { ent->has_bounced = qtrue; } } #if 0 // OLD--this looks so wrong. It looked wrong in EF. It just must be wrong. VectorAdd( ent->currentOrigin, trace->plane.normal, ent->currentOrigin); ent->s.pos.trTime = level.time - 10; #else // NEW--It would seem that we want to set our trBase to the trace endpos // and set the trTime to the actual time of impact.... VectorAdd( trace->endpos, trace->plane.normal, ent->currentOrigin ); if ( hitTime >= level.time ) {//trace fraction must have been 1 ent->s.pos.trTime = level.time - 10; } else { ent->s.pos.trTime = hitTime - 10; // this is kinda dumb hacking, but it pushes the missile away from the impact plane a bit } #endif VectorCopy( ent->currentOrigin, ent->s.pos.trBase ); VectorCopy( trace->plane.normal, ent->pos1 ); if ( ent->s.weapon != WP_SABER && ent->s.weapon != WP_THERMAL && ent->e_clThinkFunc != clThinkF_CG_Limb && ent->e_ThinkFunc != thinkF_LimbThink ) {//not a saber, bouncing thermal or limb //now you can damage the guy you came from ent->owner = NULL; } }