void G_RollMissile( gentity_t *ent ) { int bumpcount, numbumps; vec3_t dir; float d; int numplanes; vec3_t planes[MAX_CLIP_PLANES]; vec3_t primal_velocity; vec3_t clipVelocity; int i, j, k; trace_t trace; vec3_t end; float time_left; float into; vec3_t endVelocity; vec3_t endClipVelocity; pml_t objPML; float bounceAmt = BUMPCLIP; gentity_t *hitEnt = NULL; memset( &objPML, 0, sizeof( objPML ) ); G_GroundTrace( ent, &objPML ); objPML.frametime = (level.time - level.previousTime)*0.001; numbumps = 4; VectorCopy ( ent->s.pos.trDelta, primal_velocity ); VectorCopy( ent->s.pos.trDelta, endVelocity ); endVelocity[2] -= g_gravity->value * objPML.frametime; ent->s.pos.trDelta[2] = ( ent->s.pos.trDelta[2] + endVelocity[2] ) * 0.5; primal_velocity[2] = endVelocity[2]; if ( objPML.groundPlane ) {//FIXME: never happens! // slide along the ground plane G_ClipVelocity( ent->s.pos.trDelta, objPML.groundTrace.plane.normal, ent->s.pos.trDelta, BUMPCLIP ); VectorScale( ent->s.pos.trDelta, 0.9f, ent->s.pos.trDelta ); } time_left = objPML.frametime; // never turn against the ground plane if ( objPML.groundPlane ) { numplanes = 1; VectorCopy( objPML.groundTrace.plane.normal, planes[0] ); } else { numplanes = 0; } // never turn against original velocity /* VectorNormalize2( ent->s.pos.trDelta, planes[numplanes] ); numplanes++; */ for ( bumpcount = 0; bumpcount < numbumps; bumpcount++ ) { // calculate position we are trying to move to VectorMA( ent->currentOrigin, time_left, ent->s.pos.trDelta, end ); // see if we can make it there gi.trace ( &trace, ent->currentOrigin, ent->mins, ent->maxs, end, ent->s.number, ent->clipmask, G2_RETURNONHIT, 10 ); //TEMP HACK: //had to move this up above the trace.allsolid check now that for some reason ghoul2 impacts tell me I'm allsolid?! //this needs to be fixed, really if ( trace.entityNum < ENTITYNUM_WORLD ) {//hit another ent hitEnt = &g_entities[trace.entityNum]; if ( hitEnt && (hitEnt->takedamage || (hitEnt->contents&CONTENTS_LIGHTSABER) ) ) { G_MissileImpact( ent, &trace ); if ( ent->s.eType == ET_GENERAL ) {//exploded return; } } } if ( trace.allsolid ) { // entity is completely trapped in another solid //FIXME: this happens a lot now when we hit a G2 ent... WTF? ent->s.pos.trDelta[2] = 0; // don't build up falling damage, but allow sideways acceleration return;// qtrue; } if ( trace.fraction > 0 ) { // actually covered some distance VectorCopy( trace.endpos, ent->currentOrigin ); } if ( trace.fraction == 1 ) { break; // moved the entire distance } //pm->ps->pm_flags |= PMF_BUMPED; // save entity for contact //PM_AddTouchEnt( trace.entityNum ); //Hit it /* if ( PM_ClientImpact( trace.entityNum, qtrue ) ) { continue; } */ time_left -= time_left * trace.fraction; if ( numplanes >= MAX_CLIP_PLANES ) { // this shouldn't really happen VectorClear( ent->s.pos.trDelta ); return;// qtrue; } // // if this is the same plane we hit before, nudge velocity // out along it, which fixes some epsilon issues with // non-axial planes // for ( i = 0 ; i < numplanes ; i++ ) { if ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) { VectorAdd( trace.plane.normal, ent->s.pos.trDelta, ent->s.pos.trDelta ); break; } } if ( i < numplanes ) { continue; } VectorCopy( trace.plane.normal, planes[numplanes] ); numplanes++; // // modify velocity so it parallels all of the clip planes // if ( &g_entities[trace.entityNum] != NULL && g_entities[trace.entityNum].client ) {//hit a person, bounce off much less bounceAmt = OVERCLIP; } else { bounceAmt = BUMPCLIP; } // find a plane that it enters for ( i = 0 ; i < numplanes ; i++ ) { into = DotProduct( ent->s.pos.trDelta, planes[i] ); if ( into >= 0.1 ) { continue; // move doesn't interact with the plane } // see how hard we are hitting things if ( -into > pml.impactSpeed ) { pml.impactSpeed = -into; } // slide along the plane G_ClipVelocity( ent->s.pos.trDelta, planes[i], clipVelocity, bounceAmt ); // slide along the plane G_ClipVelocity( endVelocity, planes[i], endClipVelocity, bounceAmt ); // see if there is a second plane that the new move enters for ( j = 0 ; j < numplanes ; j++ ) { if ( j == i ) { continue; } if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) { continue; // move doesn't interact with the plane } // try clipping the move to the plane G_ClipVelocity( clipVelocity, planes[j], clipVelocity, bounceAmt ); G_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, bounceAmt ); // see if it goes back into the first clip plane if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) { continue; } // slide the original velocity along the crease CrossProduct (planes[i], planes[j], dir); VectorNormalize( dir ); d = DotProduct( dir, ent->s.pos.trDelta ); VectorScale( dir, d, clipVelocity ); CrossProduct (planes[i], planes[j], dir); VectorNormalize( dir ); d = DotProduct( dir, endVelocity ); VectorScale( dir, d, endClipVelocity ); // see if there is a third plane the the new move enters for ( k = 0 ; k < numplanes ; k++ ) { if ( k == i || k == j ) { continue; } if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) { continue; // move doesn't interact with the plane } // stop dead at a triple plane interaction VectorClear( ent->s.pos.trDelta ); return;// qtrue; } } // if we have fixed all interactions, try another move VectorCopy( clipVelocity, ent->s.pos.trDelta ); VectorCopy( endClipVelocity, endVelocity ); break; } VectorScale( endVelocity, 0.975f, endVelocity ); } VectorCopy( endVelocity, ent->s.pos.trDelta ); // don't change velocity if in a timer (FIXME: is this correct?) /* if ( pm->ps->pm_time ) { VectorCopy( primal_velocity, ent->s.pos.trDelta ); } */ return;// ( bumpcount != 0 ); }
/* * @brief Toss, bounce, and fly movement. When on ground, do nothing. */ static void G_Physics_Toss(g_edict_t *ent) { vec3_t org, move; // regular thinking G_RunThink(ent); // if not a team captain, movement will be handled elsewhere if (ent->locals.flags & FL_TEAM_SLAVE) return; // check for the ground entity going away if (ent->locals.ground_entity) { if (!ent->locals.ground_entity->in_use) ent->locals.ground_entity = NULL; else if (ent->locals.velocity[2] > ent->locals.ground_entity->locals.velocity[2] + 0.1) ent->locals.ground_entity = NULL; else return; } // if on ground, or intentionally floating, return without moving if (ent->locals.ground_entity || (ent->locals.item && (ent->locals.spawn_flags & 4))) return; // enforce max velocity values G_ClampVelocity(ent); // move angles VectorMA(ent->s.angles, gi.frame_seconds, ent->locals.avelocity, ent->s.angles); // move origin VectorCopy(ent->s.origin, org); VectorScale(ent->locals.velocity, gi.frame_seconds, move); // push through the world, interacting with triggers and other ents c_trace_t trace = G_PushEntity(ent, move); if (!ent->in_use) return; if (trace.fraction < 1.0) { // move was blocked // if it was a floor, we might bounce or come to rest vec_t *vel = ent->locals.velocity; if (G_ClipVelocity(vel, trace.plane.normal, vel, 1.3) & 1) { VectorSubtract(ent->s.origin, org, move); // if we're approaching a stop, clear our velocity and set ground if (VectorLength(move) < STOP_EPSILON) { VectorClear(ent->locals.velocity); ent->locals.ground_entity = trace.ent; ent->locals.ground_entity_link_count = trace.ent->link_count; } else { // bounce and slide along the floor vec_t bounce, speed = VectorLength(ent->locals.velocity); bounce = sqrt(speed); if (ent->locals.velocity[2] < bounce) ent->locals.velocity[2] = bounce; } } // all impacts reduce velocity and angular velocity VectorScale(ent->locals.velocity, 0.9, ent->locals.velocity); VectorScale(ent->locals.avelocity, 0.9, ent->locals.avelocity); } // check for water transition const _Bool was_in_water = (ent->locals.water_type & MASK_WATER); ent->locals.water_type = gi.PointContents(ent->s.origin); const _Bool is_in_water = ent->locals.water_type & MASK_WATER; if (is_in_water) ent->locals.water_level = 1; else ent->locals.water_level = 0; // add gravity if (ent->locals.move_type == MOVE_TYPE_FLY) G_AddFlying(ent); else G_AddGravity(ent); if (!was_in_water && is_in_water) { gi.PositionedSound(ent->s.origin, g_game.edicts, gi.SoundIndex("world/water_in"), ATTEN_NORM); VectorScale(ent->locals.velocity, 0.66, ent->locals.velocity); } else if (was_in_water && !is_in_water) gi.PositionedSound(ent->s.origin, g_game.edicts, gi.SoundIndex("world/water_out"), ATTEN_NORM); // move team slaves g_edict_t *slave = ent->locals.team_chain; while (slave) { VectorCopy(ent->s.origin, slave->s.origin); gi.LinkEdict(slave); slave = slave->locals.team_chain; } }