/* * W_Plasma_Backtrace */ void W_Plasma_Backtrace( edict_t *ent, const vec3_t start ) { trace_t tr; vec3_t oldorigin; vec3_t mins = { -2, -2, -2 }, maxs = { 2, 2, 2 }; if( GS_RaceGametype() ) return; VectorCopy( ent->s.origin, oldorigin ); VectorCopy( start, ent->s.origin ); do { G_Trace4D( &tr, ent->s.origin, mins, maxs, oldorigin, ent, ( CONTENTS_BODY|CONTENTS_CORPSE ), ent->timeDelta ); VectorCopy( tr.endpos, ent->s.origin ); if( tr.ent == -1 ) break; if( tr.allsolid || tr.startsolid ) W_Touch_Plasma( ent, &game.edicts[tr.ent], NULL, 0 ); else if( tr.fraction != 1.0 ) W_Touch_Plasma( ent, &game.edicts[tr.ent], &tr.plane, tr.surfFlags ); else break; } while( ent->r.inuse && ent->s.type == ET_PLASMA && !VectorCompare( ent->s.origin, oldorigin ) ); if( ent->r.inuse && ent->s.type == ET_PLASMA ) VectorCopy( oldorigin, ent->s.origin ); }
/* * G_GS_Trace - Used only for gameshared linking */ static void G_GS_Trace( trace_t *tr, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int ignore, int contentmask, int timeDelta ) { edict_t *passent = NULL; if( ignore >= 0 && ignore < MAX_EDICTS ) passent = &game.edicts[ignore]; G_Trace4D( tr, start, mins, maxs, end, passent, contentmask, timeDelta ); }
/* * G_ProjectileDistancePrestep */ static void G_ProjectileDistancePrestep( edict_t *projectile, float distance ) { float speed; vec3_t dir, dest; int mask, i; trace_t trace; #ifdef PLASMAHACK vec3_t plasma_hack_start; #endif if( projectile->movetype != MOVETYPE_TOSS && projectile->movetype != MOVETYPE_LINEARPROJECTILE && projectile->movetype != MOVETYPE_BOUNCE && projectile->movetype != MOVETYPE_BOUNCEGRENADE ) return; if( !distance ) return; if( ( speed = VectorNormalize2( projectile->velocity, dir ) ) == 0.0f ) return; mask = ( projectile->r.clipmask ) ? projectile->r.clipmask : MASK_SHOT; // race trick should come set up inside clipmask if( projectile->movetype == MOVETYPE_LINEARPROJECTILE ) VectorCopy( projectile->s.origin2, projectile->s.origin ); #ifdef PLASMAHACK VectorCopy( projectile->s.origin, plasma_hack_start ); #endif VectorMA( projectile->s.origin, distance, dir, dest ); G_Trace4D( &trace, projectile->s.origin, projectile->r.mins, projectile->r.maxs, dest, projectile->r.owner, mask, projectile->timeDelta ); for( i = 0; i < 3; i++ ) projectile->s.origin[i] = projectile->s.origin2[i] = projectile->olds.origin[i] = projectile->olds.origin2[i] = trace.endpos[i]; GClip_LinkEntity( projectile ); SV_Impact( projectile, &trace ); // set initial water state if( !projectile->r.inuse ) return; projectile->waterlevel = ( G_PointContents4D( projectile->s.origin, projectile->timeDelta ) & MASK_WATER ) ? qtrue : qfalse; // ffs : hack for the plasmagun #ifdef PLASMAHACK if( projectile->s.type == ET_PLASMA ) if (trap_Cvar_Get( "rs_plasma_hack", "1", CVAR_ARCHIVE )->integer==1)//racesow W_Plasma_Backtrace( projectile, plasma_hack_start ); #endif }
/* * SV_TestEntityPosition * */ static edict_t *SV_TestEntityPosition( edict_t *ent ) { trace_t trace; int mask; if( ent->r.clipmask ) { mask = ent->r.clipmask; } else { mask = MASK_SOLID; } G_Trace4D( &trace, ent->s.origin, ent->r.mins, ent->r.maxs, ent->s.origin, ent, mask, ent->timeDelta ); if( trace.startsolid ) { return game.edicts; } return NULL; }
/* * SV_PushEntity * * Does not change the entities velocity at all */ static trace_t SV_PushEntity( edict_t *ent, vec3_t push ) { trace_t trace; vec3_t start; vec3_t end; int mask; VectorCopy( ent->s.origin, start ); VectorAdd( start, push, end ); retry: if( ent->r.clipmask ) { mask = ent->r.clipmask; } else { mask = MASK_SOLID; } G_Trace4D( &trace, start, ent->r.mins, ent->r.maxs, end, ent, mask, ent->timeDelta ); if( ent->movetype == MOVETYPE_PUSH || !trace.startsolid ) { VectorCopy( trace.endpos, ent->s.origin ); } GClip_LinkEntity( ent ); if( trace.fraction < 1.0 ) { SV_Impact( ent, &trace ); // if the pushed entity went away and the pusher is still there if( !game.edicts[trace.ent].r.inuse && ent->movetype == MOVETYPE_PUSH && ent->r.inuse ) { // move the pusher back and try again VectorCopy( start, ent->s.origin ); GClip_LinkEntity( ent ); goto retry; } } if( ent->r.inuse ) { GClip_TouchTriggers( ent ); } return trace; }
/* * W_Fire_Blade */ void W_Fire_Blade( edict_t *self, int range, vec3_t start, vec3_t angles, float damage, int knockback, int stun, int mod, int timeDelta ) { edict_t *event, *other = NULL; vec3_t end; trace_t trace; int mask = MASK_SHOT; vec3_t dir; int dmgflags = 0; if( GS_Instagib() ) damage = 9999; AngleVectors( angles, dir, NULL, NULL ); VectorMA( start, range, dir, end ); if( GS_RaceGametype() ) mask = MASK_SOLID; G_Trace4D( &trace, start, NULL, NULL, end, self, MASK_SHOT, timeDelta ); if( trace.ent == -1 ) //didn't touch anything return; // find out what touched other = &game.edicts[trace.ent]; if( !other->takedamage ) // it was the world { // wall impact VectorMA( trace.endpos, -0.02, dir, end ); event = G_SpawnEvent( EV_BLADE_IMPACT, 0, end ); event->s.ownerNum = ENTNUM( self ); VectorScale( trace.plane.normal, 1024, event->s.origin2 ); event->r.svflags = SVF_TRANSMITORIGIN2; return; } // it was a player G_Damage( other, self, self, dir, dir, other->s.origin, damage, knockback, stun, dmgflags, mod ); }
/* * W_Fire_Lead * the seed is important to be as pointer for cgame prediction accuracy */ static void W_Fire_Lead( edict_t *self, vec3_t start, vec3_t aimdir, vec3_t axis[3], int damage, int knockback, int stun, int hspread, int vspread, int *seed, int dflags, int mod, int timeDelta ) { trace_t tr; vec3_t dir; vec3_t end; float r; float u; vec3_t water_start; int content_mask = MASK_SHOT | MASK_WATER; G_Trace4D( &tr, self->s.origin, NULL, NULL, start, self, MASK_SHOT, timeDelta ); if( !( tr.fraction < 1.0 ) ) { #if 1 // circle double alpha = M_PI * Q_crandom( seed ); // [-PI ..+PI] double s = fabs( Q_crandom( seed ) ); // [0..1] r = s * cos( alpha ) * hspread; u = s * sin( alpha ) * vspread; #else // square r = Q_crandom( seed ) * hspread; u = Q_crandom( seed ) * vspread; #endif VectorMA( start, 8192, axis[0], end ); VectorMA( end, r, axis[1], end ); VectorMA( end, u, axis[2], end ); if( G_PointContents4D( start, timeDelta ) & MASK_WATER ) { VectorCopy( start, water_start ); content_mask &= ~MASK_WATER; } G_Trace4D( &tr, start, NULL, NULL, end, self, content_mask, timeDelta ); // see if we hit water if( tr.contents & MASK_WATER ) { VectorCopy( tr.endpos, water_start ); if( !VectorCompare( start, tr.endpos ) ) { vec3_t forward, right, up; // change bullet's course when it enters water VectorSubtract( end, start, dir ); VecToAngles( dir, dir ); AngleVectors( dir, forward, right, up ); #if 1 // circle alpha = M_PI *Q_crandom( seed ); // [-PI ..+PI] s = fabs( Q_crandom( seed ) ); // [0..1] r = s *cos( alpha )*hspread*1.5; u = s *sin( alpha )*vspread*1.5; #else r = Q_crandom( seed ) * hspread * 2; u = Q_crandom( seed ) * vspread * 2; #endif VectorMA( water_start, 8192, forward, end ); VectorMA( end, r, right, end ); VectorMA( end, u, up, end ); } // re-trace ignoring water this time G_Trace4D( &tr, water_start, NULL, NULL, end, self, MASK_SHOT, timeDelta ); } } // send gun puff / flash if( tr.fraction < 1.0 && tr.ent != -1 ) { if( game.edicts[tr.ent].takedamage ) { G_Damage( &game.edicts[tr.ent], self, self, aimdir, aimdir, tr.endpos, tr.plane.normal, damage, knockback, stun, dflags, mod ); } else { if( !( tr.surfFlags & SURF_NOIMPACT ) ) { } } } }
/* * * - We will consider direct impacts as splash when the player is on the ground and the hit very close to the ground */ int G_Projectile_HitStyle( edict_t *projectile, edict_t *target ) { trace_t trace; vec3_t end; qboolean atGround = qfalse; edict_t *attacker; #define AIRHIT_MINHEIGHT 64 // don't hurt owner for the first second if( target == projectile->r.owner && target != world ) { if( !g_projectile_touch_owner->integer || ( g_projectile_touch_owner->integer && projectile->timeStamp + 1000 > level.time ) ) return PROJECTILE_TOUCH_NOT; } if( !target->takedamage || ISBRUSHMODEL( target->s.modelindex ) ) return PROJECTILE_TOUCH_DIRECTHIT; if( target->waterlevel > 1 ) return PROJECTILE_TOUCH_DIRECTHIT; // water hits are direct but don't count for awards attacker = ( projectile->r.owner && projectile->r.owner->r.client ) ? projectile->r.owner : NULL; // see if the target is at ground or a less than a step of height if( target->groundentity ) atGround = qtrue; else { VectorCopy( target->s.origin, end ); end[2] -= STEPSIZE; G_Trace4D( &trace, target->s.origin, target->r.mins, target->r.maxs, end, target, MASK_DEADSOLID, 0 ); if( ( trace.ent != -1 || trace.startsolid ) && ISWALKABLEPLANE( &trace.plane ) ) atGround = qtrue; } if( atGround ) { // when the player is at ground we will consider a direct hit only when // the hit is 16 units above the feet if( projectile->s.origin[2] <= 16 + target->s.origin[2] + target->r.mins[2] ) return PROJECTILE_TOUCH_DIRECTSPLASH; } else { // it's direct hit, but let's see if it's airhit VectorCopy( target->s.origin, end ); end[2] -= AIRHIT_MINHEIGHT; G_Trace4D( &trace, target->s.origin, target->r.mins, target->r.maxs, end, target, MASK_DEADSOLID, 0 ); if( ( trace.ent != -1 || trace.startsolid ) && ISWALKABLEPLANE( &trace.plane ) ) { // add directhit and airhit to awards counter if( attacker && !GS_IsTeamDamage( &attacker->s, &target->s ) && G_ModToAmmo( projectile->style ) != AMMO_NONE ) { projectile->r.owner->r.client->level.stats.accuracy_hits_direct[G_ModToAmmo( projectile->style )-AMMO_GUNBLADE]++; teamlist[projectile->r.owner->s.team].stats.accuracy_hits_direct[G_ModToAmmo( projectile->style )-AMMO_GUNBLADE]++; projectile->r.owner->r.client->level.stats.accuracy_hits_air[G_ModToAmmo( projectile->style )-AMMO_GUNBLADE]++; teamlist[projectile->r.owner->s.team].stats.accuracy_hits_air[G_ModToAmmo( projectile->style )-AMMO_GUNBLADE]++; } return PROJECTILE_TOUCH_DIRECTAIRHIT; } } // add directhit to awards counter if( attacker && !GS_IsTeamDamage( &attacker->s, &target->s ) && G_ModToAmmo( projectile->style ) != AMMO_NONE ) { projectile->r.owner->r.client->level.stats.accuracy_hits_direct[G_ModToAmmo( projectile->style )-AMMO_GUNBLADE]++; teamlist[projectile->r.owner->s.team].stats.accuracy_hits_direct[G_ModToAmmo( projectile->style )-AMMO_GUNBLADE]++; } return PROJECTILE_TOUCH_DIRECTHIT; #undef AIRHIT_MINHEIGHT }
/* * W_Fire_Instagun_Strong */ void W_Fire_Instagun( edict_t *self, vec3_t start, vec3_t angles, float damage, int knockback, int stun, int radius, int range, int mod, int timeDelta ) { vec3_t from, end, dir; trace_t tr; edict_t *ignore, *event; int mask; qboolean missed = qtrue; int dmgflags = 0; if( GS_Instagib() ) damage = 9999; AngleVectors( angles, dir, NULL, NULL ); VectorMA( start, range, dir, end ); VectorCopy( start, from ); ignore = self; mask = MASK_SHOT; if( GS_RaceGametype() ) mask = MASK_SOLID; tr.ent = -1; while( ignore ) { G_Trace4D( &tr, from, NULL, NULL, end, ignore, mask, timeDelta ); VectorCopy( tr.endpos, from ); ignore = NULL; if( tr.ent == -1 ) break; // some entity was touched if( tr.ent == world->s.number || game.edicts[tr.ent].movetype == MOVETYPE_NONE || game.edicts[tr.ent].movetype == MOVETYPE_PUSH ) { if( g_instajump->integer && self && self->r.client ) { // create a temporary inflictor entity edict_t *inflictor; inflictor = G_Spawn(); inflictor->s.solid = SOLID_NOT; inflictor->timeDelta = 0; VectorCopy( tr.endpos, inflictor->s.origin ); inflictor->s.ownerNum = ENTNUM( self ); inflictor->projectileInfo.maxDamage = 0; inflictor->projectileInfo.minDamage = 0; inflictor->projectileInfo.maxKnockback = knockback; inflictor->projectileInfo.minKnockback = 1; inflictor->projectileInfo.stun = 0; inflictor->projectileInfo.radius = radius; G_RadiusDamage( inflictor, self, &tr.plane, NULL, mod ); G_FreeEdict( inflictor ); } break; } // allow trail to go through SOLID_BBOX entities (players, gibs, etc) if( !ISBRUSHMODEL( game.edicts[tr.ent].s.modelindex ) ) ignore = &game.edicts[tr.ent]; if( ( &game.edicts[tr.ent] != self ) && ( game.edicts[tr.ent].takedamage ) ) { G_Damage( &game.edicts[tr.ent], self, self, dir, dir, tr.endpos, damage, knockback, stun, dmgflags, mod ); // spawn a impact event on each damaged ent event = G_SpawnEvent( EV_INSTA_EXPLOSION, DirToByte( tr.plane.normal ), tr.endpos ); event->s.firemode = FIRE_MODE_STRONG; if( game.edicts[tr.ent].r.client ) missed = qfalse; } } if( missed && self->r.client ) G_AwardPlayerMissedElectrobolt( self, mod ); // send the weapon fire effect event = G_SpawnEvent( EV_INSTATRAIL, ENTNUM( self ), start ); event->r.svflags = SVF_TRANSMITORIGIN2; VectorScale( dir, 1024, event->s.origin2 ); }
void W_Fire_Electrobolt_FullInstant( edict_t *self, vec3_t start, vec3_t angles, float maxdamage, float mindamage, int maxknockback, int minknockback, int stun, int range, int minDamageRange, int mod, int timeDelta ) { vec3_t from, end, dir; trace_t tr; edict_t *ignore, *event, *hit, *damaged; int mask; qboolean missed = qtrue; int dmgflags = 0; #define FULL_DAMAGE_RANGE g_projectile_prestep->value if( GS_Instagib() ) maxdamage = mindamage = 9999; AngleVectors( angles, dir, NULL, NULL ); VectorMA( start, range, dir, end ); VectorCopy( start, from ); ignore = self; hit = damaged = NULL; mask = MASK_SHOT; if( GS_RaceGametype() ) mask = MASK_SOLID; clamp_high( mindamage, maxdamage ); clamp_high( minknockback, maxknockback ); clamp_high( minDamageRange, range ); if( minDamageRange <= FULL_DAMAGE_RANGE ) minDamageRange = FULL_DAMAGE_RANGE + 1; if( range <= FULL_DAMAGE_RANGE + 1 ) range = FULL_DAMAGE_RANGE + 1; tr.ent = -1; while( ignore ) { G_Trace4D( &tr, from, NULL, NULL, end, ignore, mask, timeDelta ); VectorCopy( tr.endpos, from ); ignore = NULL; if( tr.ent == -1 ) break; // some entity was touched hit = &game.edicts[tr.ent]; if( hit == world ) // stop dead if hit the world break; if( hit->movetype == MOVETYPE_NONE || hit->movetype == MOVETYPE_PUSH ) break; // allow trail to go through BBOX entities (players, gibs, etc) if( !ISBRUSHMODEL( hit->s.modelindex ) ) ignore = hit; if( ( hit != self ) && ( hit->takedamage ) ) { float frac, damage, knockback, dist; dist = DistanceFast( tr.endpos, start ); if( dist <= FULL_DAMAGE_RANGE ) frac = 0.0f; else { frac = ( dist - FULL_DAMAGE_RANGE ) / (float)( minDamageRange - FULL_DAMAGE_RANGE ); clamp( frac, 0.0f, 1.0f ); } damage = maxdamage - ( ( maxdamage - mindamage ) * frac ); knockback = maxknockback - ( ( maxknockback - minknockback ) * frac ); //G_Printf( "mindamagerange %i frac %.1f damage %i\n", minDamageRange, 1.0f - frac, (int)damage ); G_Damage( hit, self, self, dir, dir, tr.endpos, damage, knockback, stun, dmgflags, mod ); // spawn a impact event on each damaged ent event = G_SpawnEvent( EV_BOLT_EXPLOSION, DirToByte( tr.plane.normal ), tr.endpos ); event->s.firemode = FIRE_MODE_STRONG; if( hit->r.client ) missed = qfalse; damaged = hit; } } if( missed && self->r.client ) G_AwardPlayerMissedElectrobolt( self, mod ); // send the weapon fire effect event = G_SpawnEvent( EV_ELECTROTRAIL, ENTNUM( self ), start ); event->r.svflags = SVF_TRANSMITORIGIN2; VectorScale( dir, 1024, event->s.origin2 ); event->s.firemode = FIRE_MODE_STRONG; #undef FULL_DAMAGE_RANGE }
/* * W_Fire_Electrobolt_Combined */ void W_Fire_Electrobolt_Combined( edict_t *self, vec3_t start, vec3_t angles, float maxdamage, float mindamage, float maxknockback, float minknockback, int stun, int range, int mod, int timeDelta ) { vec3_t from, end, dir; trace_t tr; edict_t *ignore, *event, *hit, *damaged; int mask; qboolean missed = qtrue; int dmgflags = 0; int fireMode; #ifdef ELECTROBOLT_TEST fireMode = FIRE_MODE_WEAK; #else fireMode = FIRE_MODE_STRONG; #endif if( GS_Instagib() ) maxdamage = mindamage = 9999; AngleVectors( angles, dir, NULL, NULL ); VectorMA( start, range, dir, end ); VectorCopy( start, from ); ignore = self; hit = damaged = NULL; mask = MASK_SHOT; if( GS_RaceGametype() ) mask = MASK_SOLID; clamp_high( mindamage, maxdamage ); clamp_high( minknockback, maxknockback ); tr.ent = -1; while( ignore ) { G_Trace4D( &tr, from, NULL, NULL, end, ignore, mask, timeDelta ); VectorCopy( tr.endpos, from ); ignore = NULL; if( tr.ent == -1 ) break; // some entity was touched hit = &game.edicts[tr.ent]; if( hit == world ) // stop dead if hit the world break; if( hit->movetype == MOVETYPE_NONE || hit->movetype == MOVETYPE_PUSH ) break; // allow trail to go through BBOX entities (players, gibs, etc) if( !ISBRUSHMODEL( hit->s.modelindex ) ) ignore = hit; if( ( hit != self ) && ( hit->takedamage ) ) { float frac, damage, knockback; frac = DistanceFast( tr.endpos, start ) / (float)range; clamp( frac, 0.0f, 1.0f ); damage = maxdamage - ( ( maxdamage - mindamage ) * frac ); knockback = maxknockback - ( ( maxknockback - minknockback ) * frac ); G_Damage( hit, self, self, dir, dir, tr.endpos, damage, knockback, stun, dmgflags, mod ); // spawn a impact event on each damaged ent event = G_SpawnEvent( EV_BOLT_EXPLOSION, DirToByte( tr.plane.normal ), tr.endpos ); event->s.firemode = fireMode; if( hit->r.client ) missed = qfalse; damaged = hit; } } if( missed && self->r.client ) G_AwardPlayerMissedElectrobolt( self, mod ); // send the weapon fire effect event = G_SpawnEvent( EV_ELECTROTRAIL, ENTNUM( self ), start ); event->r.svflags = SVF_TRANSMITORIGIN2; VectorScale( dir, 1024, event->s.origin2 ); event->s.firemode = fireMode; if( !GS_Instagib() && tr.ent == -1 ) // didn't touch anything, not even a wall { edict_t *bolt; gs_weapon_definition_t *weapondef = GS_GetWeaponDef( self->s.weapon ); // fire a weak EB from the end position bolt = W_Fire_Electrobolt_Weak( self, end, angles, weapondef->firedef_weak.speed, mindamage, minknockback, minknockback, stun, weapondef->firedef_weak.timeout, mod, timeDelta ); bolt->enemy = damaged; } }
/* * SV_Physics_Toss * * Toss, bounce, and fly movement. When onground, do nothing. * * FIXME: This function needs a serious rewrite */ static void SV_Physics_Toss( edict_t *ent ) { trace_t trace; vec3_t move; float backoff; edict_t *slave; bool wasinwater; bool isinwater; vec3_t old_origin; float oldSpeed; // if not a team captain, so movement will be handled elsewhere if( ent->flags & FL_TEAMSLAVE ) { return; } // refresh the ground entity if( ent->movetype == MOVETYPE_BOUNCE || ent->movetype == MOVETYPE_BOUNCEGRENADE ) { if( ent->velocity[2] > 0.1f ) { ent->groundentity = NULL; } } if( ent->groundentity && ent->groundentity != world && !ent->groundentity->r.inuse ) { ent->groundentity = NULL; } oldSpeed = VectorLength( ent->velocity ); if( ent->groundentity ) { if( !oldSpeed ) { return; } if( ent->movetype == MOVETYPE_TOSS ) { if( ent->velocity[2] >= 8 ) { ent->groundentity = NULL; } else { VectorClear( ent->velocity ); VectorClear( ent->avelocity ); G_CallStop( ent ); return; } } } VectorCopy( ent->s.origin, old_origin ); if( ent->accel != 0 ) { if( ent->accel < 0 && VectorLength( ent->velocity ) < 50 ) { VectorClear( ent->velocity ); } else { vec3_t acceldir; VectorNormalize2( ent->velocity, acceldir ); VectorScale( acceldir, ent->accel * FRAMETIME, acceldir ); VectorAdd( ent->velocity, acceldir, ent->velocity ); } } SV_CheckVelocity( ent ); // add gravity if( ent->movetype != MOVETYPE_FLY && !ent->groundentity ) { SV_AddGravity( ent ); } // move angles VectorMA( ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles ); // move origin VectorScale( ent->velocity, FRAMETIME, move ); trace = SV_PushEntity( ent, move ); if( !ent->r.inuse ) { return; } if( trace.fraction < 1.0f ) { if( ent->movetype == MOVETYPE_BOUNCE ) { backoff = 1.5; } else if( ent->movetype == MOVETYPE_BOUNCEGRENADE ) { backoff = 1.5; } else { backoff = 1; } GS_ClipVelocity( ent->velocity, trace.plane.normal, ent->velocity, backoff ); // stop if on ground if( ent->movetype == MOVETYPE_BOUNCE || ent->movetype == MOVETYPE_BOUNCEGRENADE ) { // stop dead on allsolid // LA: hopefully will fix grenades bouncing down slopes // method taken from Darkplaces sourcecode if( trace.allsolid || ( ISWALKABLEPLANE( &trace.plane ) && fabs( DotProduct( trace.plane.normal, ent->velocity ) ) < 40 ) ) { ent->groundentity = &game.edicts[trace.ent]; ent->groundentity_linkcount = ent->groundentity->linkcount; VectorClear( ent->velocity ); VectorClear( ent->avelocity ); G_CallStop( ent ); } } else { // in movetype_toss things stop dead when touching ground #if 0 G_CheckGround( ent ); if( ent->groundentity ) { #else // walkable or trapped inside solid brush if( trace.allsolid || ISWALKABLEPLANE( &trace.plane ) ) { ent->groundentity = trace.ent < 0 ? world : &game.edicts[trace.ent]; ent->groundentity_linkcount = ent->groundentity->linkcount; #endif VectorClear( ent->velocity ); VectorClear( ent->avelocity ); G_CallStop( ent ); } } } // check for water transition wasinwater = ( ent->watertype & MASK_WATER ) ? true : false; ent->watertype = G_PointContents( ent->s.origin ); isinwater = ent->watertype & MASK_WATER ? true : false; // never allow items in CONTENTS_NODROP if( ent->item && ( ent->watertype & CONTENTS_NODROP ) ) { G_FreeEdict( ent ); return; } if( isinwater ) { ent->waterlevel = 1; } else { ent->waterlevel = 0; } if( !wasinwater && isinwater ) { G_PositionedSound( old_origin, CHAN_AUTO, trap_SoundIndex( S_HIT_WATER ), ATTN_IDLE ); } else if( wasinwater && !isinwater ) { G_PositionedSound( ent->s.origin, CHAN_AUTO, trap_SoundIndex( S_HIT_WATER ), ATTN_IDLE ); } // move teamslaves for( slave = ent->teamchain; slave; slave = slave->teamchain ) { VectorCopy( ent->s.origin, slave->s.origin ); GClip_LinkEntity( slave ); } } //============================================================================ void SV_Physics_LinearProjectile( edict_t *ent ) { vec3_t start, end; int mask; float startFlyTime, endFlyTime; trace_t trace; int old_waterLevel; // if not a team captain movement will be handled elsewhere if( ent->flags & FL_TEAMSLAVE ) { return; } old_waterLevel = ent->waterlevel; mask = ( ent->r.clipmask ) ? ent->r.clipmask : MASK_SOLID; // find it's current position given the starting timeStamp startFlyTime = (float)( max( game.prevServerTime - ent->s.linearMovementTimeStamp, 0 ) ) * 0.001f; endFlyTime = (float)( game.serverTime - ent->s.linearMovementTimeStamp ) * 0.001f; VectorMA( ent->s.linearMovementBegin, startFlyTime, ent->s.linearMovementVelocity, start ); VectorMA( ent->s.linearMovementBegin, endFlyTime, ent->s.linearMovementVelocity, end ); G_Trace4D( &trace, start, ent->r.mins, ent->r.maxs, end, ent, mask, ent->timeDelta ); VectorCopy( trace.endpos, ent->s.origin ); GClip_LinkEntity( ent ); SV_Impact( ent, &trace ); if( !ent->r.inuse ) { // the projectile may be freed if touched something return; } // update some data required for the transmission //VectorCopy( ent->velocity, ent->s.linearMovementVelocity ); GClip_TouchTriggers( ent ); ent->groundentity = NULL; // projectiles never have ground entity ent->waterlevel = ( G_PointContents4D( ent->s.origin, ent->timeDelta ) & MASK_WATER ) ? true : false; if( !old_waterLevel && ent->waterlevel ) { G_PositionedSound( start, CHAN_AUTO, trap_SoundIndex( S_HIT_WATER ), ATTN_IDLE ); } else if( old_waterLevel && !ent->waterlevel ) { G_PositionedSound( ent->s.origin, CHAN_AUTO, trap_SoundIndex( S_HIT_WATER ), ATTN_IDLE ); } }
int SV_FlyMove( edict_t *ent, float time, int mask ) { edict_t *hit; int bumpcount, numbumps; vec3_t dir; float d; int numplanes; vec3_t planes[MAX_CLIP_PLANES]; vec3_t primal_velocity, original_velocity, new_velocity; int i, j; trace_t trace; vec3_t end; float time_left; int blocked; numbumps = 4; blocked = 0; VectorCopy( ent->velocity, original_velocity ); VectorCopy( ent->velocity, primal_velocity ); numplanes = 0; time_left = time; ent->groundentity = NULL; for( bumpcount = 0; bumpcount < numbumps; bumpcount++ ) { for( i = 0; i < 3; i++ ) end[i] = ent->s.origin[i] + time_left * ent->velocity[i]; G_Trace4D( &trace, ent->s.origin, ent->r.mins, ent->r.maxs, end, ent, mask, ent->timeDelta ); if( trace.allsolid ) { // entity is trapped in another solid VectorClear( ent->velocity ); return 3; } if( trace.fraction > 0 ) { // actually covered some distance VectorCopy( trace.endpos, ent->s.origin ); VectorCopy( ent->velocity, original_velocity ); numplanes = 0; } if( trace.fraction == 1 ) { break; // moved the entire distance } hit = &game.edicts[trace.ent]; if( ISWALKABLEPLANE( &trace.plane ) ) { blocked |= 1; // floor if( hit->s.solid == SOLID_BMODEL ) { ent->groundentity = hit; ent->groundentity_linkcount = hit->linkcount; } } if( !trace.plane.normal[2] ) { blocked |= 2; // step } // // run the impact function // SV_Impact( ent, &trace ); if( !ent->r.inuse ) { break; // removed by the impact function } time_left -= time_left * trace.fraction; // cliped to another plane if( numplanes >= MAX_CLIP_PLANES ) { // this shouldn't really happen VectorClear( ent->velocity ); return 3; } VectorCopy( trace.plane.normal, planes[numplanes] ); numplanes++; // // modify original_velocity so it parallels all of the clip planes // for( i = 0; i < numplanes; i++ ) { GS_ClipVelocity( original_velocity, planes[i], new_velocity, 1 ); for( j = 0; j < numplanes; j++ ) if( j != i ) { if( DotProduct( new_velocity, planes[j] ) < 0 ) { break; // not ok } } if( j == numplanes ) { break; } } if( i != numplanes ) { // go along this plane VectorCopy( new_velocity, ent->velocity ); } else { // go along the crease if( numplanes != 2 ) { VectorClear( ent->velocity ); return 7; } CrossProduct( planes[0], planes[1], dir ); VectorNormalize( dir ); d = DotProduct( dir, ent->velocity ); VectorScale( dir, d, ent->velocity ); } // // if original velocity is against the original velocity, stop dead // to avoid tiny occilations in sloping corners // if( DotProduct( ent->velocity, primal_velocity ) <= 0 ) { VectorClear( ent->velocity ); return blocked; } } return blocked; }
/* * G_CanSplashDamage */ static qboolean G_CanSplashDamage( edict_t *targ, edict_t *inflictor, cplane_t *plane ) { vec3_t dest, origin; trace_t trace; int solidmask = MASK_SOLID; if( !targ ) return qfalse; if( !plane ) { VectorCopy( inflictor->s.origin, origin ); } else { // up by 9 units to account for stairs VectorMA( inflictor->s.origin, 9, plane->normal, origin ); } // bmodels need special checking because their origin is 0,0,0 if( targ->movetype == MOVETYPE_PUSH ) { // NOT FOR PLAYERS only for entities that can push the players VectorAdd( targ->r.absmin, targ->r.absmax, dest ); VectorScale( dest, 0.5, dest ); G_Trace4D( &trace, origin, vec3_origin, vec3_origin, dest, inflictor, solidmask, inflictor->timeDelta ); if( trace.fraction == 1.0 || trace.ent == ENTNUM( targ ) ) return qtrue; return qfalse; } // This is for players G_Trace4D( &trace, origin, vec3_origin, vec3_origin, targ->s.origin, inflictor, solidmask, inflictor->timeDelta ); if( trace.fraction == 1.0 || trace.ent == ENTNUM( targ ) ) return qtrue; VectorCopy( targ->s.origin, dest ); dest[0] += 15.0; dest[1] += 15.0; G_Trace4D( &trace, origin, vec3_origin, vec3_origin, dest, inflictor, solidmask, inflictor->timeDelta ); if( trace.fraction == 1.0 || trace.ent == ENTNUM( targ ) ) return qtrue; VectorCopy( targ->s.origin, dest ); dest[0] += 15.0; dest[1] -= 15.0; G_Trace4D( &trace, origin, vec3_origin, vec3_origin, dest, inflictor, solidmask, inflictor->timeDelta ); if( trace.fraction == 1.0 || trace.ent == ENTNUM( targ ) ) return qtrue; VectorCopy( targ->s.origin, dest ); dest[0] -= 15.0; dest[1] += 15.0; G_Trace4D( &trace, origin, vec3_origin, vec3_origin, dest, inflictor, solidmask, inflictor->timeDelta ); if( trace.fraction == 1.0 || trace.ent == ENTNUM( targ ) ) return qtrue; VectorCopy( targ->s.origin, dest ); dest[0] -= 15.0; dest[1] -= 15.0; G_Trace4D( &trace, origin, vec3_origin, vec3_origin, dest, inflictor, solidmask, inflictor->timeDelta ); if( trace.fraction == 1.0 || trace.ent == ENTNUM( targ ) ) return qtrue; /* VectorCopy( targ->s.origin, dest ); origin[2] += 9; G_Trace4D( &trace, origin, vec3_origin, vec3_origin, targ->s.origin, inflictor, solidmask, inflictor->timeDelta ); if( trace.fraction == 1.0 || trace.ent == ENTNUM( targ ) ) return qtrue; */ return qfalse; }