// leave this line at the top for all g_xxxx.cpp files... #include "g_local.h" extern void G_MoverTouchPushTriggers( gentity_t *ent, vec3_t oldOrg ); void G_StopObjectMoving( gentity_t *object ); /* ==================================================================== void pitch_roll_for_slope (edict_t *forwhom, vec3_t *slope) MG This will adjust the pitch and roll of a monster to match a given slope - if a non-'0 0 0' slope is passed, it will use that value, otherwise it will use the ground underneath the monster. If it doesn't find a surface, it does nothinh\g and returns. ==================================================================== */ void pitch_roll_for_slope( gentity_t *forwhom, vec3_t pass_slope ) { vec3_t slope; vec3_t nvf, ovf, ovr, startspot, endspot, new_angles = { 0, 0, 0 }; float pitch, mod, dot; float oldmins2; //if we don't have a slope, get one if( !pass_slope || VectorCompare( vec3_origin, pass_slope ) ) { trace_t trace; VectorCopy( forwhom->r.currentOrigin, startspot ); startspot[2] += forwhom->r.mins[2] + 4; VectorCopy( startspot, endspot ); endspot[2] -= 300; trap_Trace( &trace, forwhom->r.currentOrigin, vec3_origin, vec3_origin, endspot, forwhom->s.number, MASK_SOLID ); // if(trace_fraction>0.05&&forwhom.movetype==MOVETYPE_STEP) // forwhom.flags(-)FL_ONGROUND; if ( trace.fraction >= 1.0 ) return; if( !( &trace.plane ) ) return; if ( VectorCompare( vec3_origin, trace.plane.normal ) ) return; VectorCopy( trace.plane.normal, slope ); } else { VectorCopy( pass_slope, slope ); } AngleVectors( forwhom->r.currentAngles, ovf, ovr, NULL ); vectoangles( slope, new_angles ); pitch = new_angles[PITCH] + 90; new_angles[ROLL] = new_angles[PITCH] = 0; AngleVectors( new_angles, nvf, NULL, NULL ); mod = DotProduct( nvf, ovr ); if ( mod<0 ) mod = -1; else mod = 1; dot = DotProduct( nvf, ovf ); if ( forwhom->client ) { forwhom->client->ps.viewangles[PITCH] = dot * pitch; forwhom->client->ps.viewangles[ROLL] = ((1-Q_fabs(dot)) * pitch * mod); oldmins2 = forwhom->r.mins[2]; forwhom->r.mins[2] = -24 + 12 * fabs(forwhom->client->ps.viewangles[PITCH])/180.0f; //FIXME: if it gets bigger, move up if ( oldmins2 > forwhom->r.mins[2] ) {//our mins is now lower, need to move up //FIXME: trace? forwhom->client->ps.origin[2] += (oldmins2 - forwhom->r.mins[2]); forwhom->r.currentOrigin[2] = forwhom->client->ps.origin[2]; trap_LinkEntity( forwhom ); } } else { forwhom->r.currentAngles[PITCH] = dot * pitch; forwhom->r.currentAngles[ROLL] = ((1-Q_fabs(dot)) * pitch * mod); } } /* ================ G_BounceObject ================ */ void G_BounceObject( gentity_t *ent, trace_t *trace ) { vec3_t velocity; float dot, bounceFactor; int hitTime; // reflect the velocity on the trace plane hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction; BG_EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity ); dot = DotProduct( velocity, trace->plane.normal ); // bounceFactor = 60/ent->mass; // NOTENOTE Mass is not yet implemented bounceFactor = 1.0f; 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->r.currentAngles, ent->s.apos.trBase ); VectorCopy( trace->endpos, ent->r.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->r.currentOrigin ); ent->s.pos.trTime = hitTime; VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase ); VectorCopy( trace->plane.normal, ent->pos1 );//??? } /* ================ G_RunObject TODO: When transition to 0 grav, push away from surface you were resting on TODO: When free-floating in air, apply some friction to your trDelta (based on mass?) ================ */ extern void DoImpact( gentity_t *self, gentity_t *other, qboolean damageSelf ); extern void pitch_roll_for_slope( gentity_t *forwhom, vec3_t pass_slope ); void G_RunObject( gentity_t *ent ) { vec3_t origin, oldOrg; trace_t tr; gentity_t *traceEnt = NULL; //FIXME: floaters need to stop floating up after a while, even if gravity stays negative? if ( ent->s.pos.trType == TR_STATIONARY )//g_gravity.value <= 0 && { ent->s.pos.trType = TR_GRAVITY; VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase ); ent->s.pos.trTime = level.previousTime;//?necc? if ( !g_gravity.value ) { ent->s.pos.trDelta[2] += 100; } } ent->nextthink = level.time + FRAMETIME; VectorCopy( ent->r.currentOrigin, oldOrg ); // get current position BG_EvaluateTrajectory( &ent->s.pos, level.time, origin ); //Get current angles? BG_EvaluateTrajectory( &ent->s.apos, level.time, ent->r.currentAngles ); if ( VectorCompare( ent->r.currentOrigin, origin ) ) {//error - didn't move at all! return; } // trace a line from the previous position to the current position, // ignoring interactions with the missile owner trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, ent->parent ? ent->parent->s.number : ent->s.number, ent->clipmask ); if ( !tr.startsolid && !tr.allsolid && tr.fraction ) { VectorCopy( tr.endpos, ent->r.currentOrigin ); trap_LinkEntity( ent ); } else //if ( tr.startsolid ) { tr.fraction = 0; } G_MoverTouchPushTriggers( ent, oldOrg ); /* if ( !(ent->s.eFlags & EF_TELEPORT_BIT) && !(ent->svFlags & SVF_NO_TELEPORT) ) { G_MoverTouchTeleportTriggers( ent, oldOrg ); if ( ent->s.eFlags & EF_TELEPORT_BIT ) {//was teleported return; } } else { ent->s.eFlags &= ~EF_TELEPORT_BIT; } */ if ( tr.fraction == 1 ) { if ( g_gravity.value <= 0 ) { if ( ent->s.apos.trType == TR_STATIONARY ) { VectorCopy( ent->r.currentAngles, ent->s.apos.trBase ); ent->s.apos.trType = TR_LINEAR; ent->s.apos.trDelta[1] = flrand( -300, 300 ); ent->s.apos.trDelta[0] = flrand( -10, 10 ); ent->s.apos.trDelta[2] = flrand( -10, 10 ); ent->s.apos.trTime = level.time; } } //friction in zero-G if ( !g_gravity.value ) { float friction = 0.975f; //friction -= ent->mass/1000.0f; if ( friction < 0.1 ) { friction = 0.1f; } VectorScale( ent->s.pos.trDelta, friction, ent->s.pos.trDelta ); VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase ); ent->s.pos.trTime = level.time; } return; } //hit something //Do impact damage traceEnt = &g_entities[tr.entityNum]; if ( tr.fraction || (traceEnt && traceEnt->takedamage) ) { if ( !VectorCompare( ent->r.currentOrigin, oldOrg ) ) {//moved and impacted if ( (traceEnt && traceEnt->takedamage) ) {//hurt someone // G_Sound( ent, G_SoundIndex( "sound/movers/objects/objectHurt.wav" ) ); } // G_Sound( ent, G_SoundIndex( "sound/movers/objects/objectHit.wav" ) ); } DoImpact( ent, traceEnt, qtrue ); } if ( !ent || (ent->takedamage&&ent->health <= 0) ) {//been destroyed by impact //chunks? // G_Sound( ent, G_SoundIndex( "sound/movers/objects/objectBreak.wav" ) ); return; } //do impact physics if ( ent->s.pos.trType == TR_GRAVITY )//tr.fraction < 1.0 && {//FIXME: only do this if no trDelta if ( g_gravity.value <= 0 || tr.plane.normal[2] < 0.7 ) { if ( ent->s.eFlags&(EF_BOUNCE|EF_BOUNCE_HALF) ) { if ( tr.fraction <= 0.0f ) { VectorCopy( tr.endpos, ent->r.currentOrigin ); VectorCopy( tr.endpos, ent->s.pos.trBase ); VectorClear( ent->s.pos.trDelta ); ent->s.pos.trTime = level.time; } else { G_BounceObject( ent, &tr ); } } else {//slide down? //FIXME: slide off the slope } } else { ent->s.apos.trType = TR_STATIONARY; pitch_roll_for_slope( ent, tr.plane.normal ); //ent->r.currentAngles[0] = 0;//FIXME: match to slope //ent->r.currentAngles[2] = 0;//FIXME: match to slope VectorCopy( ent->r.currentAngles, ent->s.apos.trBase ); //okay, we hit the floor, might as well stop or prediction will //make us go through the floor! //FIXME: this means we can't fall if something is pulled out from under us... G_StopObjectMoving( ent ); } } else { ent->s.apos.trType = TR_STATIONARY; pitch_roll_for_slope( ent, tr.plane.normal ); //ent->r.currentAngles[0] = 0;//FIXME: match to slope //ent->r.currentAngles[2] = 0;//FIXME: match to slope VectorCopy( ent->r.currentAngles, ent->s.apos.trBase ); } //call touch func ent->touch( ent, &g_entities[tr.entityNum], &tr ); } void G_StopObjectMoving( gentity_t *object ) { object->s.pos.trType = TR_STATIONARY; VectorCopy( object->r.currentOrigin, object->s.origin ); VectorCopy( object->r.currentOrigin, object->s.pos.trBase ); VectorClear( object->s.pos.trDelta ); /* //Stop spinning VectorClear( self->s.apos.trDelta ); vectoangles(trace->plane.normal, self->s.angles); VectorCopy(self->s.angles, self->r.currentAngles ); VectorCopy(self->s.angles, self->s.apos.trBase); */ } void G_StartObjectMoving( gentity_t *object, vec3_t dir, float speed, trType_t trType ) { VectorNormalize (dir); //object->s.eType = ET_GENERAL; object->s.pos.trType = trType; VectorCopy( object->r.currentOrigin, object->s.pos.trBase ); VectorScale(dir, speed, object->s.pos.trDelta ); object->s.pos.trTime = level.time; /* //FIXME: incorporate spin? vectoangles(dir, object->s.angles); VectorCopy(object->s.angles, object->s.apos.trBase); VectorSet(object->s.apos.trDelta, 300, 0, 0 ); object->s.apos.trTime = level.time; */ //FIXME: make these objects go through G_RunObject automatically, like missiles do if ( object->think == NULL ) { object->nextthink = level.time + FRAMETIME; object->think = G_RunObject; } else {//You're responsible for calling RunObject } }