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->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->currentOrigin, oldOrg ); // get current position EvaluateTrajectory( &ent->s.pos, level.time, origin ); //Get current angles? EvaluateTrajectory( &ent->s.apos, level.time, ent->currentAngles ); if ( VectorCompare( ent->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 gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, origin, ent->owner ? ent->owner->s.number : ent->s.number, ent->clipmask ); if ( !tr.startsolid && !tr.allsolid && tr.fraction ) { VectorCopy( tr.endpos, ent->currentOrigin ); gi.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->currentAngles, ent->s.apos.trBase ); ent->s.apos.trType = TR_LINEAR; ent->s.apos.trDelta[1] = Q_flrand( -300, 300 ); ent->s.apos.trDelta[0] = Q_flrand( -10, 10 ); ent->s.apos.trDelta[2] = Q_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->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->currentOrigin, oldOrg ) ) {//moved and impacted if ( (traceEnt && traceEnt->takedamage) ) {//hurt someone vec3_t fxDir; VectorNormalize2( ent->s.pos.trDelta, fxDir ); VectorScale( fxDir, -1, fxDir ); G_PlayEffect( G_EffectIndex( "melee/kick_impact" ), tr.endpos, fxDir ); //G_Sound( ent, G_SoundIndex( va( "sound/weapons/melee/punch%d", Q_irand( 1, 4 ) ) ) ); } else { G_PlayEffect( G_EffectIndex( "melee/kick_impact_silent" ), tr.endpos, tr.plane.normal ); } if ( ent->mass > 100 ) { G_Sound( ent, G_SoundIndex( "sound/movers/objects/objectHitHeavy.wav" ) ); } else { G_Sound( ent, G_SoundIndex( "sound/movers/objects/objectHit.wav" ) ); } } DoImpact( ent, traceEnt, !(tr.surfaceFlags&SURF_NODAMAGE), &tr ); } 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->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->currentAngles[0] = 0;//FIXME: match to slope //ent->currentAngles[2] = 0;//FIXME: match to slope VectorCopy( ent->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->currentAngles[0] = 0;//FIXME: match to slope //ent->currentAngles[2] = 0;//FIXME: match to slope VectorCopy( ent->currentAngles, ent->s.apos.trBase ); } //call touch func GEntity_TouchFunc( ent, &g_entities[tr.entityNum], &tr ); }
//------------------------------------ void Seeker_MaintainHeight( void ) { float dif; // Update our angles regardless NPC_UpdateAngles( qtrue, qtrue ); // If we have an enemy, we should try to hover at or a little below enemy eye level if ( NPC->enemy ) { if (TIMER_Done( NPC, "heightChange" )) { float difFactor; TIMER_Set( NPC,"heightChange",Q_irand( 1000, 3000 )); // Find the height difference //[CoOp] //changed to use same function call as SP. dif = (NPC->enemy->r.currentOrigin[2] + Q_flrand( NPC->enemy->r.maxs[2]/2, NPC->enemy->r.maxs[2]+8 )) - NPC->r.currentOrigin[2]; //dif = (NPC->enemy->r.currentOrigin[2] + flrand( NPC->enemy->r.maxs[2]/2, NPC->enemy->r.maxs[2]+8 )) - NPC->r.currentOrigin[2]; //[/CoOp] difFactor = 1.0f; if ( NPC->client->NPC_class == CLASS_BOBAFETT ) { if ( TIMER_Done( NPC, "flameTime" ) ) { difFactor = 10.0f; } } // cap to prevent dramatic height shifts if ( fabs( dif ) > 2*difFactor ) { if ( fabs( dif ) > 24*difFactor ) { dif = ( dif < 0 ? -24*difFactor : 24*difFactor ); } NPC->client->ps.velocity[2] = (NPC->client->ps.velocity[2]+dif)/2; } if ( NPC->client->NPC_class == CLASS_BOBAFETT ) { //[CoOp] //changed to use same function call as SP. NPC->client->ps.velocity[2] *= Q_flrand( 0.85f, 3.0f ); //NPC->client->ps.velocity[2] *= flrand( 0.85f, 3.0f ); //[/CoOp] } } } else { gentity_t *goal = NULL; if ( NPCInfo->goalEntity ) // Is there a goal? { goal = NPCInfo->goalEntity; } else { goal = NPCInfo->lastGoalEntity; } if ( goal ) { dif = goal->r.currentOrigin[2] - NPC->r.currentOrigin[2]; if ( fabs( dif ) > 24 ) { ucmd.upmove = ( ucmd.upmove < 0 ? -4 : 4 ); } else { if ( NPC->client->ps.velocity[2] ) { NPC->client->ps.velocity[2] *= VELOCITY_DECAY; if ( fabs( NPC->client->ps.velocity[2] ) < 2 ) { NPC->client->ps.velocity[2] = 0; } } } } } // Apply friction if ( NPC->client->ps.velocity[0] ) { NPC->client->ps.velocity[0] *= VELOCITY_DECAY; if ( fabs( NPC->client->ps.velocity[0] ) < 1 ) { NPC->client->ps.velocity[0] = 0; } } if ( NPC->client->ps.velocity[1] ) { NPC->client->ps.velocity[1] *= VELOCITY_DECAY; if ( fabs( NPC->client->ps.velocity[1] ) < 1 ) { NPC->client->ps.velocity[1] = 0; } } }
static void WP_FireConcussionAlt( gentity_t *ent ) {//a rail-gun-like beam int damage = weaponData[WP_CONCUSSION].altDamage, skip, traces = DISRUPTOR_ALT_TRACES; //int velocity = weaponData[WP_CONCUSSION].altVelocity; qboolean render_impact = qtrue; vec3_t start, end; vec3_t muzzle2, spot, dir; trace_t tr; gentity_t *traceEnt, *tent; float dist, shotDist, shotRange = 8192; qboolean hitDodged = qfalse; if (ent->s.number >= MAX_CLIENTS) { vec3_t angles; vectoangles(forwardVec, angles); angles[PITCH] += ( Q_flrand(-1.0f, 1.0f) * (CONC_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f));//was 0.5f angles[YAW] += ( Q_flrand(-1.0f, 1.0f) * (CONC_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f));//was 0.5f AngleVectors(angles, forwardVec, vrightVec, up); } //Shove us backwards for half a second VectorMA( ent->client->ps.velocity, -200, forwardVec, ent->client->ps.velocity ); ent->client->ps.groundEntityNum = ENTITYNUM_NONE; if ( (ent->client->ps.pm_flags&PMF_DUCKED) ) {//hunkered down ent->client->ps.pm_time = 100; } else { ent->client->ps.pm_time = 250; } ent->client->ps.pm_flags |= PMF_TIME_KNOCKBACK|PMF_TIME_NOFRICTION; //FIXME: only if on ground? So no "rocket jump"? Or: (see next FIXME) //FIXME: instead, set a forced ucmd backmove instead of this sliding VectorCopy( muzzle, muzzle2 ); // making a backup copy // The trace start will originate at the eye so we can ensure that it hits the crosshair. if ( ent->NPC ) { switch ( g_spskill->integer ) { case 0: damage = CONC_ALT_NPC_DAMAGE_EASY; break; case 1: damage = CONC_ALT_NPC_DAMAGE_MEDIUM; break; case 2: default: damage = CONC_ALT_NPC_DAMAGE_HARD; break; } damage *= weaponData[WP_CONCUSSION].npcAltDmgMult; } VectorCopy( muzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin ); skip = ent->s.number; // if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time ) // { // // in overcharge mode, so doing double damage // damage *= 2; // } //Make it a little easier to hit guys at long range vec3_t shot_mins, shot_maxs; VectorSet( shot_mins, -1, -1, -1 ); VectorSet( shot_maxs, 1, 1, 1 ); for ( int i = 0; i < traces; i++ ) { VectorMA( start, shotRange, forwardVec, end ); //NOTE: if you want to be able to hit guys in emplaced guns, use "G2_COLLIDE, 10" instead of "G2_RETURNONHIT, 0" //alternately, if you end up hitting an emplaced_gun that has a sitter, just redo this one trace with the "G2_COLLIDE, 10" to see if we it the sitter //gi.trace( &tr, start, NULL, NULL, end, skip, MASK_SHOT, G2_COLLIDE, 10 );//G2_RETURNONHIT, 0 ); gi.trace( &tr, start, shot_mins, shot_maxs, end, skip, MASK_SHOT, G2_COLLIDE, 10 );//G2_RETURNONHIT, 0 ); if ( tr.surfaceFlags & SURF_NOIMPACT ) { render_impact = qfalse; } if ( tr.entityNum == ent->s.number ) { // should never happen, but basically we don't want to consider a hit to ourselves? // Get ready for an attempt to trace through another person VectorCopy( tr.endpos, muzzle2 ); VectorCopy( tr.endpos, start ); skip = tr.entityNum; #ifdef _DEBUG gi.Printf( "BAD! Concussion gun shot somehow traced back and hit the owner!\n" ); #endif continue; } // always render a shot beam, doing this the old way because I don't much feel like overriding the effect. //NOTE: let's just draw one beam at the end //tent = G_TempEntity( tr.endpos, EV_CONC_ALT_SHOT ); //tent->svFlags |= SVF_BROADCAST; //VectorCopy( muzzle2, tent->s.origin2 ); if ( tr.fraction >= 1.0f ) { // draw the beam but don't do anything else break; } traceEnt = &g_entities[tr.entityNum]; if ( traceEnt //&& traceEnt->NPC && (traceEnt->s.weapon == WP_SABER || (traceEnt->client && (traceEnt->client->NPC_class == CLASS_BOBAFETT || traceEnt->client->NPC_class == CLASS_MANDA || traceEnt->client->NPC_class == CLASS_COMMANDO||traceEnt->client->NPC_class == CLASS_REBORN)))) {//FIXME: need a more reliable way to know we hit a jedi? hitDodged = Jedi_DodgeEvasion( traceEnt, ent, &tr, HL_NONE ); //acts like we didn't even hit him } if ( !hitDodged ) { if ( render_impact ) { if (( tr.entityNum < ENTITYNUM_WORLD && traceEnt->takedamage ) || !Q_stricmp( traceEnt->classname, "misc_model_breakable" ) || traceEnt->s.eType == ET_MOVER ) { // Create a simple impact type mark that doesn't last long in the world G_PlayEffect( G_EffectIndex( "concussion/alt_hit" ), tr.endpos, tr.plane.normal ); if ( traceEnt->client && LogAccuracyHit( traceEnt, ent )) {//NOTE: hitting multiple ents can still get you over 100% accuracy ent->client->ps.persistant[PERS_ACCURACY_HITS]++; } int hitLoc = G_GetHitLocFromTrace( &tr, MOD_CONC_ALT ); qboolean noKnockBack = (qboolean)((traceEnt->flags&FL_NO_KNOCKBACK) != 0);//will be set if they die, I want to know if it was on *before* they died if ( traceEnt && traceEnt->client && traceEnt->client->NPC_class == CLASS_GALAKMECH ) {//hehe G_Damage( traceEnt, ent, ent, forwardVec, tr.endpos, 10, DAMAGE_NO_KNOCKBACK|DAMAGE_NO_HIT_LOC, MOD_CONC_ALT, hitLoc ); break; } G_Damage( traceEnt, ent, ent, forwardVec, tr.endpos, damage, DAMAGE_NO_KNOCKBACK|DAMAGE_NO_HIT_LOC, MOD_CONC_ALT, hitLoc ); //do knockback and knockdown manually if ( traceEnt->client ) {//only if we hit a client vec3_t pushDir; VectorCopy( forwardVec, pushDir ); if ( pushDir[2] < 0.2f ) { pushDir[2] = 0.2f; }//hmm, re-normalize? nah... //if ( traceEnt->NPC || Q_irand(0,g_spskill->integer+1) ) { if ( !noKnockBack ) {//knock-backable G_Throw( traceEnt, pushDir, 200 ); if ( traceEnt->client->NPC_class == CLASS_ROCKETTROOPER ) { traceEnt->client->ps.pm_time = Q_irand( 1500, 3000 ); } } if ( traceEnt->health > 0 ) {//alive if ( G_HasKnockdownAnims( traceEnt ) ) {//knock-downable G_Knockdown( traceEnt, ent, pushDir, 400, qtrue ); } } } } if ( traceEnt->s.eType == ET_MOVER ) {//stop the traces on any mover break; } } else { // we only make this mark on things that can't break or move tent = G_TempEntity( tr.endpos, EV_CONC_ALT_MISS ); tent->svFlags |= SVF_BROADCAST; VectorCopy( tr.plane.normal, tent->pos1 ); break; // hit solid, but doesn't take damage, so stop the shot...we _could_ allow it to shoot through walls, might be cool? } } else // not rendering impact, must be a skybox or other similar thing? { break; // don't try anymore traces } } // Get ready for an attempt to trace through another person VectorCopy( tr.endpos, muzzle2 ); VectorCopy( tr.endpos, start ); skip = tr.entityNum; hitDodged = qfalse; } //just draw one beam all the way to the end tent = G_TempEntity( tr.endpos, EV_CONC_ALT_SHOT ); tent->svFlags |= SVF_BROADCAST; VectorCopy( muzzle, tent->s.origin2 ); // now go along the trail and make sight events VectorSubtract( tr.endpos, muzzle, dir ); shotDist = VectorNormalize( dir ); //FIXME: if shoot *really* close to someone, the alert could be way out of their FOV for ( dist = 0; dist < shotDist; dist += 64 ) { //FIXME: on a really long shot, this could make a LOT of alerts in one frame... VectorMA( muzzle, dist, dir, spot ); AddSightEvent( ent, spot, 256, AEL_DISCOVERED, 50 ); //FIXME: creates *way* too many effects, make it one effect somehow? G_PlayEffect( G_EffectIndex( "concussion/alt_ring" ), spot, forwardVec ); } //FIXME: spawn a temp ent that continuously spawns sight alerts here? And 1 sound alert to draw their attention? VectorMA( start, shotDist-4, forwardVec, spot ); AddSightEvent( ent, spot, 256, AEL_DISCOVERED, 50 ); G_PlayEffect( G_EffectIndex( "concussion/altmuzzle_flash" ), muzzle, forwardVec ); }
void Pilot_Update(void) { mActivePilotCount = 0; mRegistered.clear(); for (int i=0; i<ENTITYNUM_WORLD; i++) { if (g_entities[i].inuse && g_entities[i].client && g_entities[i].NPC && g_entities[i].NPC->greetEnt && g_entities[i].NPC->greetEnt->owner==(&g_entities[i]) ) { mActivePilotCount++; } if ( g_entities[i].inuse && g_entities[i].client && g_entities[i].m_pVehicle && !g_entities[i].owner && g_entities[i].health>0 && g_entities[i].m_pVehicle->m_pVehicleInfo->type==VH_SPEEDER && !mRegistered.full()) { mRegistered.push_back(&g_entities[i]); } } if (player && player->inuse && TIMER_Done(player, "FlybySoundArchitectureDebounce")) { TIMER_Set(player, "FlybySoundArchitectureDebounce", 300); Vehicle_t* pVeh = G_IsRidingVehicle(player); if (pVeh && (pVeh->m_pVehicleInfo->soundFlyBy || pVeh->m_pVehicleInfo->soundFlyBy2) && //fabsf(pVeh->m_pParentEntity->currentAngles[2])<15.0f && VectorLength(pVeh->m_pParentEntity->client->ps.velocity)>500.0f) { vec3_t projectedPosition; vec3_t projectedDirection; vec3_t projectedRight; vec3_t anglesNoRoll; VectorCopy(pVeh->m_pParentEntity->currentAngles, anglesNoRoll); anglesNoRoll[2] = 0; AngleVectors(anglesNoRoll, projectedDirection, projectedRight, 0); VectorMA(player->currentOrigin, 1.2f, pVeh->m_pParentEntity->client->ps.velocity, projectedPosition); VectorMA(projectedPosition, Q_flrand(-200.0f, 200.0f), projectedRight, projectedPosition); gi.trace(&mPilotViewTrace, player->currentOrigin, 0, 0, projectedPosition, player->s.number, MASK_SHOT, (EG2_Collision)0, 0); if ((mPilotViewTrace.allsolid==qfalse) && (mPilotViewTrace.startsolid==qfalse) && (mPilotViewTrace.fraction<0.99f) && (mPilotViewTrace.plane.normal[2]<0.5f) && (DotProduct(projectedDirection, mPilotViewTrace.plane.normal)<-0.5f) ) { // CG_DrawEdge(player->currentOrigin, mPilotViewTrace.endpos, EDGE_IMPACT_POSSIBLE); TIMER_Set(player, "FlybySoundArchitectureDebounce", Q_irand(1000, 2000)); int soundFlyBy = pVeh->m_pVehicleInfo->soundFlyBy; if (pVeh->m_pVehicleInfo->soundFlyBy2 && (!soundFlyBy || !Q_irand(0,1))) { soundFlyBy = pVeh->m_pVehicleInfo->soundFlyBy2; } G_SoundAtSpot(mPilotViewTrace.endpos, soundFlyBy, qtrue); } else { // CG_DrawEdge(player->currentOrigin, mPilotViewTrace.endpos, EDGE_IMPACT_SAFE); } } } }
static void WP_FireConcussion( gentity_t *ent ) {//a fast rocket-like projectile vec3_t start; int damage = weaponData[WP_CONCUSSION].damage; float vel = weaponData[WP_CONCUSSION].velocity; if (ent->s.number >= MAX_CLIENTS) { vec3_t angles; vectoangles(forwardVec, angles); angles[PITCH] += ( Q_flrand(-1.0f, 1.0f) * (CONC_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f));//was 0.5f angles[YAW] += ( Q_flrand(-1.0f, 1.0f) * (CONC_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f));//was 0.5f AngleVectors(angles, forwardVec, vrightVec, up); } //hold us still for a bit ent->client->ps.pm_time = 300; ent->client->ps.pm_flags |= PMF_TIME_KNOCKBACK; //add viewkick if ( ent->s.number < MAX_CLIENTS//player only && !cg.renderingThirdPerson )//gives an advantage to being in 3rd person, but would look silly otherwise {//kick the view back cg.kick_angles[PITCH] = Q_flrand( -10, -15 ); cg.kick_time = level.time; } VectorCopy( muzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall gentity_t *missile = CreateMissile( start, forwardVec, vel, 10000, ent, qfalse ); missile->classname = "conc_proj"; missile->s.weapon = WP_CONCUSSION; missile->mass = 10; // Do the damages if ( ent->s.number != 0 ) { if ( g_spskill->integer == 0 ) { damage = CONC_NPC_DAMAGE_EASY; } else if ( g_spskill->integer == 1 ) { damage = CONC_NPC_DAMAGE_NORMAL; } else { damage = CONC_NPC_DAMAGE_HARD; } damage *= weaponData[WP_BLASTER].npcDmgMult; } // Make it easier to hit things VectorSet( missile->maxs, ROCKET_SIZE, ROCKET_SIZE, ROCKET_SIZE ); VectorScale( missile->maxs, -1, missile->mins ); missile->damage = damage; missile->dflags = DAMAGE_EXTRA_KNOCKBACK; missile->methodOfDeath = MOD_CONC; missile->splashMethodOfDeath = MOD_CONC; missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER; missile->splashDamage = weaponData[WP_CONCUSSION].splashDamage; missile->splashRadius = weaponData[WP_CONCUSSION].splashRadius; // we don't want it to ever bounce missile->bounceCount = 0; }