//------------------------------------------------------------------------------ // Purpose : // Input : // Output : //------------------------------------------------------------------------------ Vector CAI_BaseFlyingBot::VelocityToAvoidObstacles(float flInterval) { // -------------------------------- // Avoid banging into stuff // -------------------------------- trace_t tr; Vector vTravelDir = m_vCurrentVelocity*flInterval; Vector endPos = GetAbsOrigin() + vTravelDir; AI_TraceEntity( this, GetAbsOrigin(), endPos, GetAITraceMask()|CONTENTS_WATER, &tr ); if (tr.fraction != 1.0) { // Bounce off in normal Vector vBounce = tr.plane.normal * 0.5 * m_vCurrentVelocity.Length(); return (vBounce); } // -------------------------------- // Try to remain above the ground. // -------------------------------- float flMinGroundDist = MinGroundDist(); AI_TraceLine(GetAbsOrigin(), GetAbsOrigin() + Vector(0, 0, -flMinGroundDist), GetAITraceMask_BrushOnly()|CONTENTS_WATER, this, COLLISION_GROUP_NONE, &tr); if (tr.fraction < 1) { // Clamp veloctiy if (tr.fraction < 0.1) { tr.fraction = 0.1; } return Vector(0, 0, 50/tr.fraction); } return vec3_origin; }
//----------------------------------------------------------------------------- // Purpose: Input handler that makes the crow fly away. //----------------------------------------------------------------------------- void CNPC_Crow::InputFlyAway( inputdata_t &inputdata ) { string_t sTarget = MAKE_STRING( inputdata.value.String() ); if ( sTarget != NULL_STRING )// this npc has a target { CBaseEntity *pEnt = gEntList.FindEntityByName( NULL, sTarget ); if ( pEnt ) { trace_t tr; AI_TraceLine ( EyePosition(), pEnt->GetAbsOrigin(), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction != 1.0f ) return; // Find the npc's initial target entity, stash it SetGoalEnt( pEnt ); } } else SetGoalEnt( NULL ); SetCondition( COND_CROW_FORCED_FLY ); SetCondition( COND_PROVOKED ); }
//------------------------------------------------------------------------------ // Computes the spotlight endpoint //------------------------------------------------------------------------------ void CAI_Spotlight::ComputeEndpoint( const Vector &vecStartPoint, Vector *pEndPoint ) { // Create the endpoint trace_t tr; AI_TraceLine( vecStartPoint, vecStartPoint + m_vSpotlightDir * 2 * m_flSpotlightMaxLength, MASK_OPAQUE, GetOuter(), COLLISION_GROUP_NONE, &tr ); *pEndPoint = tr.endpos; }
int CASW_Parasite::RangeAttack1Conditions( float flDot, float flDist ) { if ( gpGlobals->curtime < m_flNextAttack ) return 0; if ( ( GetFlags() & FL_ONGROUND ) == false ) return 0; // This code stops lots of headcrabs swarming you and blocking you // whilst jumping up and down in your face over and over. It forces // them to back up a bit. If this causes problems, consider using it // for the fast headcrabs only, rather than just removing it.(sjb) if ( flDist < ASW_PARASITE_MIN_JUMP_DIST ) return COND_TOO_CLOSE_TO_ATTACK; if ( flDist > ASW_PARASITE_MAX_JUMP_DIST ) return COND_TOO_FAR_TO_ATTACK; // Make sure the way is clear! CBaseEntity *pEnemy = GetEnemy(); if( pEnemy ) { bool bEnemyIsBullseye = ( dynamic_cast<CNPC_Bullseye *>(pEnemy) != NULL ); trace_t tr; AI_TraceLine( EyePosition(), pEnemy->EyePosition(), MASK_SOLID, this, COLLISION_GROUP_NONE, &tr ); if ( tr.m_pEnt != GetEnemy() ) { if ( !bEnemyIsBullseye || tr.m_pEnt != NULL ) return COND_NONE; } if( GetEnemy()->EyePosition().z - 36.0f > GetAbsOrigin().z ) { // Only run this test if trying to jump at a player who is higher up than me, else this // code will always prevent a headcrab from jumping down at an enemy, and sometimes prevent it // jumping just slightly up at an enemy. Vector vStartHullTrace = GetAbsOrigin(); vStartHullTrace.z += 1.0; Vector vEndHullTrace = GetEnemy()->EyePosition() - GetAbsOrigin(); vEndHullTrace.NormalizeInPlace(); vEndHullTrace *= 8.0; vEndHullTrace += GetAbsOrigin(); AI_TraceHull( vStartHullTrace, vEndHullTrace,GetHullMins(), GetHullMaxs(), MASK_NPCSOLID, this, GetCollisionGroup(), &tr ); if ( tr.m_pEnt != NULL && tr.m_pEnt != GetEnemy() ) { return COND_TOO_CLOSE_TO_ATTACK; } } } return COND_CAN_RANGE_ATTACK1; }
void C_ASW_Sentry_Top::AdjustRadiusBeamEdges( const Vector &vecStart, const Vector &vecDir, int iControlPoint ) { CTraceFilterSkipTwoEntities traceFilter( this, GetSentryBase(), COLLISION_GROUP_DEBRIS ); trace_t tr; AI_TraceLine( vecStart, vecStart + vecDir * 500.0f, MASK_SHOT, &traceFilter, &tr ); m_hRadiusDisplay->SetControlPoint( iControlPoint, tr.endpos ); }
//---------------------------------------------------------------------------------- // Purpose: Returns z value of floor below given point (up to fMaxDrop inches below) // Input : // Output : //---------------------------------------------------------------------------------- float GetFloorZ(const Vector &origin, float fMaxDrop) { // trace to the ground, then pop up 8 units and place node there to make it // easier for them to connect (think stairs, chairs, and bumps in the floor). // After the routing is done, push them back down. // trace_t tr; AI_TraceLine ( origin, origin - Vector ( 0, 0, fMaxDrop ), MASK_NPCSOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr ); // This trace is ONLY used if we hit an entity flagged with FL_WORLDBRUSH trace_t trEnt; AI_TraceLine ( origin, origin - Vector ( 0, 0, fMaxDrop ), MASK_NPCSOLID, NULL, COLLISION_GROUP_NONE, &trEnt ); // Did we hit something closer than the floor? if ( trEnt.fraction < tr.fraction ) { // If it was a world brush entity, copy the node location if ( trEnt.m_pEnt ) { CBaseEntity *e = trEnt.m_pEnt; if ( e && ( e->GetFlags() & FL_WORLDBRUSH ) ) { tr.endpos = trEnt.endpos; } } } return tr.endpos.z; }
void CNPC_Stalker::UpdateAttackBeam( void ) { CBaseEntity *pEnemy = GetEnemy(); // If not burning at a target if (pEnemy) { if (gpGlobals->curtime > m_fBeamEndTime) { TaskComplete(); } else { Vector enemyLKP = GetEnemyLKP(); m_vLaserTargetPos = enemyLKP + pEnemy->GetViewOffset(); // Face my enemy GetMotor()->SetIdealYawToTargetAndUpdate( enemyLKP ); // --------------------------------------------- // Get beam end point // --------------------------------------------- Vector vecSrc = LaserStartPosition(GetAbsOrigin()); Vector targetDir = m_vLaserTargetPos - vecSrc; VectorNormalize(targetDir); // -------------------------------------------------------- // If beam position and laser dir are way off, end attack // -------------------------------------------------------- if ( DotProduct(targetDir,m_vLaserDir) < 0.5 ) { TaskComplete(); return; } trace_t tr; AI_TraceLine( vecSrc, vecSrc + m_vLaserDir * MAX_STALKER_FIRE_RANGE, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr); // --------------------------------------------- // If beam not long enough, stop attacking // --------------------------------------------- if (tr.fraction == 1.0) { TaskComplete(); return; } CSoundEnt::InsertSound(SOUND_DANGER, tr.endpos, 60, 0.025, this); } } else { TaskFail(FAIL_NO_ENEMY); } }
//========================================================= // FVisible - returns true if a line can be traced from // the caller's eyes to the target vector //========================================================= bool CNPC_Bullsquid::FVisible ( Vector vecOrigin ) { trace_t tr; Vector vecLookerOrigin; vecLookerOrigin = EyePosition();//look through the caller's 'eyes' AI_TraceLine(vecLookerOrigin, vecOrigin, MASK_OPAQUE, this/*pentIgnore*/, COLLISION_GROUP_NONE, &tr); if ( tr.fraction != 1.0 ) return false; // Line of sight is not established else return true;// line of sight is valid. }
//------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ bool CNPC_EnemyFinder::FVisible( CBaseEntity *pTarget, int traceMask, CBaseEntity **ppBlocker ) { float flTargetDist = GetAbsOrigin().DistTo( pTarget->GetAbsOrigin() ); if ( flTargetDist < m_flMinSearchDist) return false; if ( m_flMaxSearchDist && flTargetDist > m_flMaxSearchDist) return false; if ( !FBitSet( m_spawnflags, SF_ENEMY_FINDER_CHECK_VIS) ) return true; if ( !HasSpawnFlags(SF_ENEMY_FINDER_APC_VIS) ) { bool bIsVisible = BaseClass::FVisible( pTarget, traceMask, ppBlocker ); if ( bIsVisible && pTarget == m_PlayerFreePass.GetPassTarget() ) bIsVisible = m_PlayerFreePass.ShouldAllowFVisible( bIsVisible ); return bIsVisible; } // Make sure I can see the target from my position trace_t tr; // Trace from launch position to target position. // Use position above actual barral based on vertical launch speed Vector vStartPos = GetAbsOrigin(); Vector vEndPos = pTarget->EyePosition(); CBaseEntity *pVehicle = NULL; if ( pTarget->IsPlayer() ) { CBasePlayer *pPlayer = assert_cast<CBasePlayer*>(pTarget); pVehicle = pPlayer->GetVehicleEntity(); } CTraceFilterSkipTwoEntities traceFilter( pTarget, pVehicle, COLLISION_GROUP_NONE ); AI_TraceLine( vStartPos, vEndPos, MASK_SHOT, &traceFilter, &tr ); if ( ppBlocker ) { *ppBlocker = tr.m_pEnt; } return (tr.fraction == 1.0); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CDarknessLightSourcesSystem::AreThereLightSourcesWithinRadius( CBaseEntity *pLooker, float flRadius ) { float flRadiusSqr = (flRadius * flRadius); for ( int i = m_LightSources.Count() - 1; i >= 0; i-- ) { // Removed? if ( m_LightSources[i].hEntity == NULL || m_LightSources[i].hEntity->IsMarkedForDeletion() ) { m_LightSources.FastRemove( i ); continue; } CBaseEntity *pLightSource = m_LightSources[i].hEntity; // Close enough to a light source? float flDistanceSqr = (pLooker->WorldSpaceCenter() - pLightSource->GetAbsOrigin()).LengthSqr(); if ( flDistanceSqr < flRadiusSqr ) { trace_t tr; AI_TraceLine( pLooker->EyePosition(), pLightSource->GetAbsOrigin(), MASK_SOLID_BRUSHONLY, pLooker, COLLISION_GROUP_NONE, &tr ); if ( g_debug_darkness.GetBool() ) { if (tr.fraction != 1.0) { NDebugOverlay::Line( pLooker->WorldSpaceCenter(), tr.endpos, 255,0,0,true, 0.1); } else { NDebugOverlay::Line( pLooker->WorldSpaceCenter(), tr.endpos, 0,255,0,true, 0.1); NDebugOverlay::Line( pLightSource->GetAbsOrigin(), tr.endpos, 255,0,0,true, 0.1); } } if ( tr.fraction == 1.0 ) return true; } } return false; }
//--------------------------------------------------------- //--------------------------------------------------------- bool CNPC_Roller::IsBlocked( const Vector &vecCheck ) { trace_t tr; return false; #if 0 NDebugOverlay::Line( GetLocalOrigin(), GetLocalOrigin() + vecCheck, 255,255,0, true, 0.1 ); Vector vecRight; Vector vecForward; AngleVectors( GetLocalAngles(), &vecForward, &vecRight, NULL ); NDebugOverlay::Line( GetLocalOrigin() + vecRight * 32, GetLocalOrigin() + vecRight * -32, 0,255,0, true, 0.1 ); #endif ROLLER_DEBUG AI_TraceLine( GetAbsOrigin(), GetAbsOrigin() + vecCheck, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); return ( tr.fraction != 1.0 ); }
//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CNPC_GroundTurret::ProjectBeam( const Vector &vecStart, const Vector &vecDir, int width, int brightness, float duration ) { CBeam *pBeam; pBeam = CBeam::BeamCreate( GROUNDTURRET_BEAM_SPRITE, width ); if ( !pBeam ) return; trace_t tr; AI_TraceLine( vecStart, vecStart + vecDir * m_flSensingDist, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); pBeam->SetStartPos( tr.endpos ); pBeam->SetEndPos( tr.startpos ); pBeam->SetWidth( width ); pBeam->SetEndWidth( 0.1 ); pBeam->SetFadeLength( 16 ); pBeam->SetBrightness( brightness ); pBeam->SetColor( 0, 145+random->RandomInt( -16, 16 ), 255 ); pBeam->RelinkBeam(); pBeam->LiveForTime( duration ); }
//------------------------------------------------------------------------------ // Purpose : Override base implimentation to let decals pass through // me onto the surface beneath // Input : // Output : //------------------------------------------------------------------------------ void CNPC_Bullseye::DecalTrace( trace_t *pOldTrace, char const *decalName ) { int index = decalsystem->GetDecalIndexForName( decalName ); if ( index < 0 ) return; // Get direction of original trace Vector vTraceDir = pOldTrace->endpos - pOldTrace->startpos; VectorNormalize(vTraceDir); // Create a new trace that passes through me Vector vStartTrace = pOldTrace->endpos - (1.0 * vTraceDir); Vector vEndTrace = pOldTrace->endpos + (MAX_TRACE_LENGTH * vTraceDir); trace_t pNewTrace; AI_TraceLine(vStartTrace, vEndTrace, MASK_SHOT, this, COLLISION_GROUP_NONE, &pNewTrace); CBroadcastRecipientFilter filter; te->Decal( filter, 0.0, &pNewTrace.endpos, &pNewTrace.startpos, ENTINDEX( pNewTrace.m_pEnt ), pNewTrace.hitbox, index ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CNPC_Bullseye::ImpactTrace( trace_t *pTrace, int iDamageType, char *pCustomImpactName ) { // Get direction of original trace Vector vTraceDir = pTrace->endpos - pTrace->startpos; VectorNormalize(vTraceDir); // Create a new trace that passes through me Vector vStartTrace = pTrace->endpos - (1.0 * vTraceDir); Vector vEndTrace = pTrace->endpos + (MAX_TRACE_LENGTH * vTraceDir); trace_t pNewTrace; AI_TraceLine(vStartTrace, vEndTrace, MASK_SHOT, this, COLLISION_GROUP_NONE, &pNewTrace); CBaseEntity *pEntity = pNewTrace.m_pEnt; // Only do this for BSP model entities if ( ( pEntity ) && ( pEntity->IsBSPModel() == false ) ) return; BaseClass::ImpactTrace( pTrace, iDamageType, pCustomImpactName ); }
//----------------------------------------------------------------------------- // Purpose: Override so can handle LOS to m_pScriptedTarget // Input : // Output : //----------------------------------------------------------------------------- bool CNPC_Stalker::InnateWeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions ) { // -------------------- // Check for occlusion // -------------------- // Base class version assumes innate weapon position is at eye level Vector barrelPos = LaserStartPosition(ownerPos); trace_t tr; AI_TraceLine( barrelPos, targetPos, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr); if ( tr.fraction == 1.0 ) { return true; } CBaseEntity *pBE = tr.m_pEnt; CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( pBE ); if ( pBE == GetEnemy() ) { return true; } else if (pBCC) { if (IRelationType( pBCC ) == D_HT) { return true; } else if (bSetConditions) { SetCondition(COND_WEAPON_BLOCKED_BY_FRIEND); } } else if (bSetConditions) { SetCondition(COND_WEAPON_SIGHT_OCCLUDED); SetEnemyOccluder(pBE); } return false; }
// Эффект пыли для шагов крематора (аналогично шагам страйдера или охотника, но в меньших масштабах void CNPC_Cremator::FootstepEffect( const Vector &origin ) { trace_t tr; AI_TraceLine( origin, origin - Vector(0,0,0), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr ); float yaw = random->RandomInt(0,0); for ( int i = 0; i < 2; i++ ) { if ( UTIL_PointContents( tr.endpos + Vector( 0, 0, 1 ) ) & MASK_WATER ) { float flWaterZ = UTIL_FindWaterSurface( tr.endpos, tr.endpos.z, tr.endpos.z + 100.0f ); CEffectData data; data.m_fFlags = 0; data.m_vOrigin = tr.endpos; data.m_vOrigin.z = flWaterZ; data.m_vNormal = Vector( 0, 0, 1 ); data.m_flScale = random->RandomFloat( 10.0, 14.0 ); // Если крематор идет по неглубокой воде, образуются всплески. DispatchEffect( "watersplash", data ); } else { Vector dir = UTIL_YawToVector( yaw + i*180 ) * 10; VectorNormalize( dir ); dir.z = 0.25; VectorNormalize( dir ); g_pEffects->Dust( tr.endpos, dir, 12, 50 ); /*g_pEffects->FootprintDecal( tr.endpos, dir, 12, 50 ); virtual void FootprintDecal( IRecipientFilter& filer, float delay, const Vector *origin, const Vector* right, int entity, int index, unsigned char materialType ) = 0; virtual void Dust( IRecipientFilter& filer, float delay, const Vector &pos, const Vector &dir, float size, float speed ) = 0;*/ } } }
void CASW_Alien_Jumper::CreateDust( bool placeDecal ) { trace_t tr; AI_TraceLine( GetAbsOrigin()+Vector(0,0,1), GetAbsOrigin()-Vector(0,0,64), MASK_SOLID_BRUSHONLY | CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP, this, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction < 1.0f ) { surfacedata_t *pdata = physprops->GetSurfaceData( tr.surface.surfaceProps ); if ( ( pdata->game.material == CHAR_TEX_CONCRETE ) || ( pdata->game.material == CHAR_TEX_DIRT ) || ( pdata->game.material == CHAR_TEX_SAND ) ) { UTIL_CreateAntlionDust( tr.endpos + Vector(0,0,24), GetAbsAngles() ); if ( placeDecal ) { UTIL_DecalTrace( &tr, "Antlion.Unburrow" ); } } } }
void CAI_RappelBehavior::SetDescentSpeed() { // Trace to the floor and see how close we're getting. Slow down if we're close. // STOP if there's an NPC under us. trace_t tr; AI_TraceLine( GetOuter()->GetAbsOrigin(), GetOuter()->GetAbsOrigin() - Vector( 0, 0, 8192 ), MASK_SHOT, GetOuter(), COLLISION_GROUP_NONE, &tr ); float flDist = fabs( GetOuter()->GetAbsOrigin().z - tr.endpos.z ); float speed = RAPPEL_MAX_SPEED; if( flDist <= RAPPEL_DECEL_DIST ) { float factor; factor = flDist / RAPPEL_DECEL_DIST; speed = MAX( RAPPEL_MIN_SPEED, speed * factor ); } Vector vecNewVelocity = vec3_origin; vecNewVelocity.z = -speed; GetOuter()->SetAbsVelocity( vecNewVelocity ); }
//------------------------------------------------------------------------------ // Purpose : Override base class to check range and visibility //------------------------------------------------------------------------------ bool CNPC_Launcher::IsValidEnemy( CBaseEntity *pTarget ) { // --------------------------------- // Check range // --------------------------------- float flTargetDist = (GetAbsOrigin() - pTarget->GetAbsOrigin()).Length(); if (flTargetDist < m_flMinAttackDist) { return false; } if (flTargetDist > m_flMaxAttackDist) { return false; } if (!FBitSet (m_spawnflags, SF_LAUNCHER_CHECK_LOS)) { return true; } // ------------------------------------------------------ // Make sure I can see the target from above my position // ------------------------------------------------------ trace_t tr; // Trace from launch position to target position. // Use position above actual barral based on vertical launch speed Vector vStartPos = GetAbsOrigin() + Vector(0,0,0.2*m_flLaunchSpeed); Vector vEndPos = pTarget->GetAbsOrigin(); AI_TraceLine( vStartPos, vEndPos, MASK_SHOT, pTarget, COLLISION_GROUP_NONE, &tr ); if (tr.fraction == 1.0) { return true; } return false; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CUnitBase::FireBullets( const FireBulletsInfo_t &info ) { VPROF_BUDGET( "CUnitBase::FireBullets", VPROF_BUDGETGROUP_UNITS ); static int tracerCount; trace_t tr; CAmmoDef* pAmmoDef = GetAmmoDef(); int nDamageType = pAmmoDef->DamageType(info.m_iAmmoType); //int nAmmoFlags = pAmmoDef->Flags(info.m_iAmmoType); int iNumShots; float flActualDamage; // the default attacker is ourselves CBaseEntity *pAttacker = info.m_pAttacker ? info.m_pAttacker : this; ClearMultiDamage(); g_MultiDamage.SetDamageType( nDamageType | DMG_NEVERGIB ); Vector vecDir; Vector vecEnd; // Adjust spread to accuracy Vector vecSpread( info.m_vecSpread ); //vecSpread.x = sin( ( (asin( info.m_vecSpread.x ) * 2.0f) * m_fAccuracy ) / 2.0f ); //vecSpread.y = sin( ( (asin( info.m_vecSpread.y ) * 2.0f) * m_fAccuracy ) / 2.0f ); //vecSpread.z = sin( ( (asin( info.m_vecSpread.z ) * 2.0f) * m_fAccuracy ) / 2.0f ); // Skip multiple entities when tracing CWarsBulletsFilter traceFilter( this, COLLISION_GROUP_NONE ); traceFilter.SetPassEntity( this ); // Standard pass entity for THIS so that it can be easily removed from the list after passing through a portal traceFilter.AddEntityToIgnore( info.m_pAdditionalIgnoreEnt ); CShotManipulator Manipulator( info.m_vecDirShooting ); iNumShots = info.m_iShots; flActualDamage = info.m_flDamage; if ( flActualDamage == 0.0 ) { flActualDamage = g_pGameRules->GetAmmoDamage( pAttacker, tr.m_pEnt, info.m_iAmmoType ); } flActualDamage *= m_fAccuracy; // Pretty much a damage modifier for (int iShot = 0; iShot < iNumShots; iShot++) { //vecDir = info.m_vecDirShooting; vecDir = Manipulator.ApplySpread( vecSpread ); vecEnd = info.m_vecSrc + vecDir * info.m_flDistance; AI_TraceLine(info.m_vecSrc, vecEnd, MASK_SHOT, &traceFilter, &tr); if( unit_debugfirebullets.GetBool() ) { #ifdef CLIENT_DLL NDebugOverlay::Line(info.m_vecSrc, vecEnd, 255, 0, 0, 255, 0.1f); NDebugOverlay::Line(info.m_vecSrc, tr.endpos, 0, 255, 0, 255, 0.1f); #else NDebugOverlay::Line(info.m_vecSrc, vecEnd, 255, 255, 0, 255, 0.1f); NDebugOverlay::Line(info.m_vecSrc, tr.endpos, 0, 255, 255, 255, 0.1f); #endif // CLIENT_DLL } // Make sure given a valid bullet type if (info.m_iAmmoType == -1) { DevMsg("ERROR: Undefined ammo type!\n"); return; } Vector vecTracerDest = tr.endpos; // do damage, paint decals if (tr.fraction != 1.0) { CTakeDamageInfo dmgInfo( pAttacker, pAttacker, flActualDamage, nDamageType ); CalculateBulletDamageForce( &dmgInfo, info.m_iAmmoType, vecDir, tr.endpos ); dmgInfo.ScaleDamageForce( info.m_flDamageForceScale ); dmgInfo.SetAmmoType( info.m_iAmmoType ); (dynamic_cast<CBaseEntity *>(tr.m_pEnt))->DispatchTraceAttack( dmgInfo, vecDir, &tr ); // Effects only, FireBullets should be called on the client. // Dispatching on the server generates far too many events/data! #ifdef CLIENT_DLL DoImpactEffect( tr, nDamageType ); Vector vecTracerSrc = vec3_origin; ComputeTracerStartPosition( info.m_vecSrc, &vecTracerSrc ); trace_t Tracer; Tracer = tr; Tracer.endpos = vecTracerDest; MakeTracer( vecTracerSrc, Tracer, pAmmoDef->TracerType(info.m_iAmmoType) ); #endif // CLIENT_DLL } } #ifdef GAME_DLL ApplyMultiDamage(); #endif // GAME_DLL }
void CNPC_Stalker::StartAttackBeam( void ) { if ( m_fBeamEndTime > gpGlobals->curtime || m_fBeamRechargeTime > gpGlobals->curtime ) { // UNDONE: Debug this and fix!?!?! m_fBeamRechargeTime = gpGlobals->curtime; } // --------------------------------------------- // If I don't have a beam yet, create one // --------------------------------------------- // UNDONE: Why would I ever have a beam already?!?!?! if (!m_pBeam) { Vector vecSrc = LaserStartPosition(GetAbsOrigin()); trace_t tr; AI_TraceLine ( vecSrc, vecSrc + m_vLaserDir * MAX_STALKER_FIRE_RANGE, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr); if ( tr.fraction >= 1.0 ) { // too far TaskComplete(); return; } m_pBeam = CBeam::BeamCreate( "sprites/laser.vmt", 2.0 ); m_pBeam->PointEntInit( tr.endpos, this ); m_pBeam->SetEndAttachment( STALKER_LASER_ATTACHMENT ); m_pBeam->SetBrightness( 255 ); m_pBeam->SetNoise( 0 ); switch (m_eBeamPower) { case STALKER_BEAM_LOW: m_pBeam->SetColor( 255, 0, 0 ); m_pLightGlow = CSprite::SpriteCreate( "sprites/redglow1.vmt", GetAbsOrigin(), FALSE ); break; case STALKER_BEAM_MED: m_pBeam->SetColor( 255, 50, 0 ); m_pLightGlow = CSprite::SpriteCreate( "sprites/orangeglow1.vmt", GetAbsOrigin(), FALSE ); break; case STALKER_BEAM_HIGH: m_pBeam->SetColor( 255, 150, 0 ); m_pLightGlow = CSprite::SpriteCreate( "sprites/yellowglow1.vmt", GetAbsOrigin(), FALSE ); break; } // ---------------------------- // Light myself in a red glow // ---------------------------- m_pLightGlow->SetTransparency( kRenderGlow, 255, 200, 200, 0, kRenderFxNoDissipation ); m_pLightGlow->SetAttachment( this, 1 ); m_pLightGlow->SetBrightness( 255 ); m_pLightGlow->SetScale( 0.65 ); #if 0 CBaseEntity *pEnemy = GetEnemy(); // -------------------------------------------------------- // Play start up sound - client should always hear this! // -------------------------------------------------------- if (pEnemy != NULL && (pEnemy->IsPlayer()) ) { EmitAmbientSound( 0, pEnemy->GetAbsOrigin(), "NPC_Stalker.AmbientLaserStart" ); } else { EmitAmbientSound( 0, GetAbsOrigin(), "NPC_Stalker.AmbientLaserStart" ); } #endif } SetThink( &CNPC_Stalker::StalkerThink ); m_flNextNPCThink = GetNextThink(); SetNextThink( gpGlobals->curtime + g_StalkerBeamThinkTime ); m_fBeamEndTime = gpGlobals->curtime + STALKER_LASER_DURATION; }
//------------------------------------------------------------------------------ // Purpose : Draw attack beam and do damage / decals // Input : // Output : //------------------------------------------------------------------------------ void CNPC_Stalker::DrawAttackBeam(void) { if (!m_pBeam) return; // --------------------------------------------- // Get beam end point // --------------------------------------------- Vector vecSrc = LaserStartPosition(GetAbsOrigin()); trace_t tr; AI_TraceLine( vecSrc, vecSrc + m_vLaserDir * MAX_STALKER_FIRE_RANGE, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr); CalcBeamPosition(); bool bInWater = (UTIL_PointContents ( tr.endpos, MASK_WATER ) & MASK_WATER)?true:false; // --------------------------------------------- // Update the beam position // --------------------------------------------- m_pBeam->SetStartPos( tr.endpos ); m_pBeam->RelinkBeam(); Vector vAttachPos; GetAttachment(STALKER_LASER_ATTACHMENT,vAttachPos); Vector vecAimDir = tr.endpos - vAttachPos; VectorNormalize( vecAimDir ); SetAim( vecAimDir ); // -------------------------------------------- // Play burn sounds // -------------------------------------------- CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( tr.m_pEnt ); if (pBCC) { if (gpGlobals->curtime > m_fNextDamageTime) { ClearMultiDamage(); float damage = 0.0; switch (m_eBeamPower) { case STALKER_BEAM_LOW: damage = 1; break; case STALKER_BEAM_MED: damage = 3; break; case STALKER_BEAM_HIGH: damage = 10; break; } CTakeDamageInfo info( this, this, damage, DMG_SHOCK ); CalculateMeleeDamageForce( &info, m_vLaserDir, tr.endpos ); pBCC->DispatchTraceAttack( info, m_vLaserDir, &tr ); ApplyMultiDamage(); m_fNextDamageTime = gpGlobals->curtime + 0.1; } if (pBCC->Classify()!=CLASS_BULLSEYE) { if (!m_bPlayingHitFlesh) { CPASAttenuationFilter filter( m_pBeam,"NPC_Stalker.BurnFlesh" ); filter.MakeReliable(); EmitSound( filter, m_pBeam->entindex(),"NPC_Stalker.BurnFlesh" ); m_bPlayingHitFlesh = true; } if (m_bPlayingHitWall) { StopSound( m_pBeam->entindex(), "NPC_Stalker.BurnWall" ); m_bPlayingHitWall = false; } tr.endpos.z -= 24.0f; if (!bInWater) { DoSmokeEffect(tr.endpos + tr.plane.normal * 8); } } } if (!pBCC || pBCC->Classify()==CLASS_BULLSEYE) { if (!m_bPlayingHitWall) { CPASAttenuationFilter filter( m_pBeam, "NPC_Stalker.BurnWall" ); filter.MakeReliable(); EmitSound( filter, m_pBeam->entindex(), "NPC_Stalker.BurnWall" ); m_bPlayingHitWall = true; } if (m_bPlayingHitFlesh) { StopSound(m_pBeam->entindex(), "NPC_Stalker.BurnFlesh" ); m_bPlayingHitFlesh = false; } UTIL_DecalTrace( &tr, "RedGlowFade"); UTIL_DecalTrace( &tr, "FadingScorch" ); tr.endpos.z -= 24.0f; if (!bInWater) { DoSmokeEffect(tr.endpos + tr.plane.normal * 8); } } if (bInWater) { UTIL_Bubbles(tr.endpos-Vector(3,3,3),tr.endpos+Vector(3,3,3),10); } /* CBroadcastRecipientFilter filter; TE_DynamicLight( filter, 0.0, EyePosition(), 255, 0, 0, 5, 0.2, 0 ); */ }
//----------------------------------------------------------------------------- // Purpose: Return true if pTestHint passes the criteria specified in hintCriteria //----------------------------------------------------------------------------- bool CAI_Hint::HintMatchesCriteria( CAI_BaseNPC *pNPC, const CHintCriteria &hintCriteria, const Vector &position, float *flNearestDistance, bool bIgnoreLock, bool bIgnoreHintType ) { // Cannot be locked if ( !bIgnoreLock && IsLocked() ) { REPORTFAILURE( "Node is locked." ); return false; } if ( !bIgnoreHintType && !hintCriteria.MatchesHintType( HintType() ) ) { return false; } if ( GetMinState() > NPC_STATE_IDLE || GetMaxState() < NPC_STATE_COMBAT ) { if ( pNPC && ( pNPC->GetState() < GetMinState() || pNPC->GetState() > GetMaxState() ) ) { REPORTFAILURE( "NPC not in correct state." ); return false; } } // See if we're filtering by group name if ( hintCriteria.GetGroup() != NULL_STRING ) { AssertIsValidString( GetGroup() ); AssertIsValidString( hintCriteria.GetGroup() ); if ( GetGroup() == NULL_STRING || GetGroup() != hintCriteria.GetGroup() ) { Assert(GetGroup() == NULL_STRING || strcmp( STRING(GetGroup()), STRING(hintCriteria.GetGroup())) != 0 ); REPORTFAILURE( "Doesn't match NPC hint group." ); return false; } } // If we're watching for include zones, test it if ( ( hintCriteria.HasIncludeZones() ) && ( hintCriteria.InIncludedZone( GetAbsOrigin() ) == false ) ) { REPORTFAILURE( "Not inside include zones." ); return false; } // If we're watching for exclude zones, test it if ( ( hintCriteria.HasExcludeZones() ) && ( hintCriteria.InExcludedZone( GetAbsOrigin() ) ) ) { REPORTFAILURE( "Inside exclude zones." ); return false; } // See if the class handles this hint type if ( ( pNPC != NULL ) && ( pNPC->FValidateHintType( this ) == false ) ) { REPORTFAILURE( "NPC doesn't know how to handle that type." ); return false; } if ( hintCriteria.HasFlag(bits_HINT_NPC_IN_NODE_FOV) ) { if ( pNPC == NULL ) { AssertMsg(0,"Hint node attempted to verify NPC in node FOV without NPC!\n"); } else { if( !IsInNodeFOV(pNPC) ) { REPORTFAILURE( "NPC Not in hint's FOV" ); return false; } } } if ( hintCriteria.HasFlag( bits_HINT_NODE_IN_AIMCONE ) ) { if ( pNPC == NULL ) { AssertMsg( 0, "Hint node attempted to find node in aimcone without specifying NPC!\n" ); } else { if( !pNPC->FInAimCone( GetAbsOrigin() ) ) { REPORTFAILURE( "Hint isn't in NPC's aimcone" ); return false; } } } if ( hintCriteria.HasFlag( bits_HINT_NODE_IN_VIEWCONE ) ) { if ( pNPC == NULL ) { AssertMsg( 0, "Hint node attempted to find node in viewcone without specifying NPC!\n" ); } else { if( !pNPC->FInViewCone( this ) ) { REPORTFAILURE( "Hint isn't in NPC's viewcone" ); return false; } } } { AI_PROFILE_SCOPE( HINT_FVisible ); // See if we're requesting a visible node if ( hintCriteria.HasFlag( bits_HINT_NODE_VISIBLE ) ) { if ( pNPC == NULL ) { //NOTENOTE: If you're hitting this, you've asked for a visible node without specifing an NPC! AssertMsg( 0, "Hint node attempted to find visible node without specifying NPC!\n" ); } else { if( m_NodeData.nNodeID == NO_NODE ) { // This is just an info_hint, not a node. if( !pNPC->FVisible( this ) ) { REPORTFAILURE( "Hint isn't visible to NPC." ); return false; } } else { // This hint associated with a node. trace_t tr; Vector vHintPos; GetPosition(pNPC,&vHintPos); AI_TraceLine ( pNPC->EyePosition(), vHintPos + pNPC->GetViewOffset(), MASK_NPCSOLID_BRUSHONLY, pNPC, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction != 1.0f ) { REPORTFAILURE( "Node isn't visible to NPC." ); return false; } } } } } // Check for clear if requested if ( hintCriteria.HasFlag( bits_HINT_NODE_CLEAR ) ) { if ( pNPC == NULL ) { //NOTENOTE: If you're hitting this, you've asked for a clear node without specifing an NPC! AssertMsg( 0, "Hint node attempted to find clear node without specifying NPC!\n" ); } else { trace_t tr; // Can my bounding box fit there? AI_TraceHull ( GetAbsOrigin(), GetAbsOrigin(), pNPC->WorldAlignMins(), pNPC->WorldAlignMaxs(), MASK_SOLID, pNPC, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction != 1.0 ) { REPORTFAILURE( "Node isn't clear." ); return false; } } } // See if this is our next, closest node if ( hintCriteria.HasFlag( bits_HINT_NODE_NEAREST ) ) { Assert( flNearestDistance ); // Calculate our distance float distance = (GetAbsOrigin() - position).Length(); // Must be closer than the current best if ( distance > *flNearestDistance ) { REPORTFAILURE( "Not the nearest node." ); return false; } // Remember the distance *flNearestDistance = distance; } // Must either be visible or not if requested if ( hintCriteria.HasFlag( bits_HINT_NODE_NOT_VISIBLE_TO_PLAYER|bits_HINT_NODE_VISIBLE_TO_PLAYER ) ) { bool bWasSeen = false; // Test all potential seers for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { CBasePlayer *pPlayer = UTIL_PlayerByIndex(i); if ( pPlayer ) { // Only spawn if the player's looking away from me Vector vLookDir = pPlayer->EyeDirection3D(); Vector vTargetDir = GetAbsOrigin() - pPlayer->EyePosition(); VectorNormalize(vTargetDir); float fDotPr = DotProduct(vLookDir,vTargetDir); if ( fDotPr > 0 ) { trace_t tr; UTIL_TraceLine( pPlayer->EyePosition(), GetAbsOrigin(), MASK_SOLID_BRUSHONLY, pPlayer, COLLISION_GROUP_NONE, &tr); if ( tr.fraction == 1.0 ) { if ( hintCriteria.HasFlag( bits_HINT_NODE_NOT_VISIBLE_TO_PLAYER ) ) { REPORTFAILURE( "Node is visible to player." ); return false; } bWasSeen = true; } } } } if ( !bWasSeen && hintCriteria.HasFlag( bits_HINT_NODE_VISIBLE_TO_PLAYER ) ) { REPORTFAILURE( "Node isn't visible to player." ); return false; } } return true; }
void CASW_Queen_Divers::ASWTraceBleed( float flDamage, const Vector &vecDir, trace_t *ptr, int bitsDamageType ) { if ((BloodColor() == DONT_BLEED) || (BloodColor() == BLOOD_COLOR_MECH)) { return; } if (flDamage == 0) return; if (! (bitsDamageType & (DMG_CRUSH | DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB | DMG_AIRBOAT))) return; // make blood decal on the wall! trace_t Bloodtr; Vector vecTraceDir; float flNoise; int cCount; int i; #ifdef GAME_DLL if ( !IsAlive() ) { // dealing with a dead npc. if ( GetMaxHealth() <= 0 ) { // no blood decal for a npc that has already decalled its limit. return; } else { m_iMaxHealth -= 1; } } #endif if (flDamage < 10) { flNoise = 0.1; cCount = 1; } else if (flDamage < 25) { flNoise = 0.2; cCount = 2; } else { flNoise = 0.3; cCount = 4; } float flTraceDist = (bitsDamageType & DMG_AIRBOAT) ? 384 : 172; for ( i = 0 ; i < cCount ; i++ ) { vecTraceDir = vecDir * -1;// trace in the opposite direction the shot came from (the direction the shot is going) vecTraceDir.x += random->RandomFloat( -flNoise, flNoise ); vecTraceDir.y += random->RandomFloat( -flNoise, flNoise ); vecTraceDir.z += random->RandomFloat( -flNoise, flNoise ); // Don't bleed on grates. Vector vecEndPos = ptr->endpos; AI_TraceLine( vecEndPos, vecEndPos + vecTraceDir * -flTraceDist, MASK_SOLID_BRUSHONLY & ~CONTENTS_GRATE, this, COLLISION_GROUP_NONE, &Bloodtr); if ( Bloodtr.fraction != 1.0 ) { UTIL_BloodDecalTrace( &Bloodtr, BloodColor() ); } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CDarknessLightSourcesSystem::IsEntityVisibleToTarget( CBaseEntity *pLooker, CBaseEntity *pTarget ) { if ( pTarget->IsEffectActive( EF_BRIGHTLIGHT ) || pTarget->IsEffectActive( EF_DIMLIGHT ) ) return true; bool bDebug = g_debug_darkness.GetBool(); if ( bDebug && pLooker ) { bDebug = (pLooker->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT) != 0; } trace_t tr; // Loop through all the light sources. Do it backwards, so we can remove dead ones. for ( int i = m_LightSources.Count() - 1; i >= 0; i-- ) { // Removed? if ( m_LightSources[i].hEntity == NULL || m_LightSources[i].hEntity->IsMarkedForDeletion() ) { m_LightSources.FastRemove( i ); continue; } CInfoDarknessLightSource *pLightSource = m_LightSources[i].hEntity; // Close enough to a light source? float flDistanceSqr = (pTarget->WorldSpaceCenter() - pLightSource->GetAbsOrigin()).LengthSqr(); if ( flDistanceSqr < m_LightSources[i].flLightRadiusSqr ) { if ( pLightSource->ShouldIgnoreLOS() ) { if ( bDebug ) { NDebugOverlay::Line( pTarget->WorldSpaceCenter(), pLightSource->GetAbsOrigin(), 0,255,0,true, 0.1); } return true; } // Check LOS from the light to the target CTraceFilterSkipTwoEntities filter( pTarget, pLooker, COLLISION_GROUP_NONE ); AI_TraceLine( pTarget->WorldSpaceCenter(), pLightSource->GetAbsOrigin(), MASK_OPAQUE, &filter, &tr ); if ( tr.fraction == 1.0 ) { if ( bDebug ) { NDebugOverlay::Line( tr.startpos, tr.endpos, 0,255,0,true, 0.1); } return true; } if ( bDebug ) { NDebugOverlay::Line( tr.startpos, tr.endpos, 255,0,0,true, 0.1); NDebugOverlay::Line( tr.endpos, pLightSource->GetAbsOrigin(), 128,0,0,true, 0.1); } // If the target is within the radius of the light, don't do sillhouette checks continue; } if ( !pLooker ) continue; // Between a light source and the looker? Vector vecLookerToLight = (pLightSource->GetAbsOrigin() - pLooker->WorldSpaceCenter()); Vector vecLookerToTarget = (pTarget->WorldSpaceCenter() - pLooker->WorldSpaceCenter()); float flDistToSource = VectorNormalize( vecLookerToLight ); float flDistToTarget = VectorNormalize( vecLookerToTarget ); float flDot = DotProduct( vecLookerToLight, vecLookerToTarget ); if ( flDot > 0 ) { // Make sure the target is in front of the lightsource if ( flDistToTarget < flDistToSource ) { if ( bDebug ) { NDebugOverlay::Line( pLooker->WorldSpaceCenter(), pLooker->WorldSpaceCenter() + (vecLookerToLight * 128), 255,255,255,true, 0.1); NDebugOverlay::Line( pLooker->WorldSpaceCenter(), pLooker->WorldSpaceCenter() + (vecLookerToTarget * 128), 255,0,0,true, 0.1); } // Now, we need to find out if the light source is obscured by anything. // To do this, we want to calculate the point of intersection between the light source // sphere and the line from the looker through the target. float flASqr = (flDistToSource * flDistToSource); float flB = -2 * flDistToSource * flDot; float flCSqr = m_LightSources[i].flLightRadiusSqr; float flDesc = (flB * flB) - (4 * (flASqr - flCSqr)); if ( flDesc >= 0 ) { float flLength = (-flB - sqrt(flDesc)) / 2; Vector vecSpherePoint = pLooker->WorldSpaceCenter() + (vecLookerToTarget * flLength); // We've got the point of intersection. See if we can see it. CTraceFilterSkipTwoEntities filter( pTarget, pLooker, COLLISION_GROUP_NONE ); AI_TraceLine( pLooker->EyePosition(), vecSpherePoint, MASK_SOLID_BRUSHONLY, &filter, &tr ); if ( bDebug ) { if (tr.fraction != 1.0) { NDebugOverlay::Line( pLooker->WorldSpaceCenter(), vecSpherePoint, 255,0,0,true, 0.1); } else { NDebugOverlay::Line( pLooker->WorldSpaceCenter(), vecSpherePoint, 0,255,0,true, 0.1); NDebugOverlay::Line( pLightSource->GetAbsOrigin(), vecSpherePoint, 255,0,0,true, 0.1); } } if ( tr.fraction == 1.0 ) return true; } } } } return false; }
//----------------------------------------------------------------------------- // Purpose: // Input : pTask - //----------------------------------------------------------------------------- void CNPC_Crow::RunTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_CROW_TAKEOFF: { if ( GetNavigator()->IsGoalActive() ) { GetMotor()->SetIdealYawToTargetAndUpdate( GetAbsOrigin() + GetNavigator()->GetCurWaypointPos(), AI_KEEP_YAW_SPEED ); } else TaskFail( FAIL_NO_ROUTE ); if ( IsActivityFinished() ) { TaskComplete(); SetIdealActivity( ACT_FLY ); m_bSoar = false; m_flSoarTime = gpGlobals->curtime + random->RandomFloat( 2, 5 ); } break; } case TASK_CROW_HOP: { if ( IsActivityFinished() ) { TaskComplete(); SetIdealActivity( ACT_IDLE ); } if ( ( GetAbsOrigin().z < m_flHopStartZ ) && ( !( GetFlags() & FL_ONGROUND ) ) ) { // // We've hopped off of something! See if we're going to fall very far. // trace_t tr; AI_TraceLine( GetAbsOrigin(), GetAbsOrigin() + Vector( 0, 0, -32 ), MASK_SOLID, this, HL2COLLISION_GROUP_CROW, &tr ); if ( tr.fraction == 1.0f ) { // // We're falling! Better fly away. SelectSchedule will check ONGROUND and do the right thing. // TaskComplete(); } else { // // We'll be okay. Don't check again unless what we're hopping onto moves // out from under us. // m_flHopStartZ = GetAbsOrigin().z - ( 32 * tr.fraction ); } } break; } // // Face the direction we are flying. // case TASK_CROW_FLY: { GetMotor()->SetIdealYawToTargetAndUpdate( GetAbsOrigin() + GetAbsVelocity(), AI_KEEP_YAW_SPEED ); break; } case TASK_CROW_FALL_TO_GROUND: { if ( GetFlags() & FL_ONGROUND ) { SetFlyingState( FlyState_Walking ); TaskComplete(); } break; } case TASK_CROW_WAIT_FOR_BARNACLE_KILL: { if ( m_flNextFlinchTime < gpGlobals->curtime ) { m_flNextFlinchTime = gpGlobals->curtime + random->RandomFloat( 0.5f, 2.0f ); // dvs: TODO: squirm // dvs: TODO: spawn feathers EmitSound( "NPC_Crow.Squawk" ); } break; } default: { CAI_BaseNPC::RunTask( pTask ); } } }
void CNPC_Roller::Unstick( void ) { CBaseEntity *pList[ 16 ]; IPhysicsObject *pPhysObj; int i; Vector vecDirToEnemy; Vector vecDirToObject; m_flWaitFinished = gpGlobals->curtime; int count = UTIL_EntitiesInBox( pList, 16, GetAbsOrigin() - vecDelta, GetAbsOrigin() + vecDelta, 0 ); m_vecUnstickDirection = vec3_origin; for( i = 0 ; i < count ; i++ ) { pPhysObj = pList[ i ]->VPhysicsGetObject(); if( !pPhysObj || pList[ i ]->m_iClassname == m_iClassname ) { // Only consider physics objects. Exclude rollers. continue; } if( pPhysObj->GetMass() <= ROLLER_MAX_PUSH_MASS ) { // Try to bash this physics object. trace_t tr; AI_TraceLine( GetAbsOrigin(), pList[ i ]->GetAbsOrigin(), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); if( tr.fraction == 1.0 || tr.m_pEnt == pList[ i ] ) { // Roll towards this item if the trace hits nothing, or // the trace hits the object. Vector vecBashDir; vecBashDir = pList[ i ]->GetAbsOrigin() - GetAbsOrigin(); VectorNormalize( vecBashDir ); vecBashDir.z = 0.0; //NDebugOverlay::Line( GetAbsOrigin(), pList[ i ]->GetAbsOrigin(), 0,255,0, true, 2 ); m_vecUnstickDirection = vecBashDir * 80; return; } } } // No physics objects. Just pick a direction with some clearance and go there. #define ROLLER_UNSTICK_DIST 80 Vector vecDirections[ 4 ] = { Vector( 0, ROLLER_UNSTICK_DIST, 0 ), Vector( ROLLER_UNSTICK_DIST, 0, 0 ), Vector( 0, -ROLLER_UNSTICK_DIST, 0 ), Vector( -ROLLER_UNSTICK_DIST, 0, 0 ) }; trace_t tr; for( i = 0 ; i < 4 ; i++ ) { AI_TraceLine( GetAbsOrigin(), GetAbsOrigin() + vecDirections[ i ], MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); if( tr.fraction == 1.0 ) { m_vecUnstickDirection = vecDirections[ i ]; //NDebugOverlay::Line( GetLocalOrigin(), GetLocalOrigin() + m_vecUnstickDirection, 255,255,0, true, 2 ); // Roll in this direction for a couple of seconds. Msg( "unsticking!\n" ); return; } } }
//------------------------------------------------------------------------------ // Purpose : // Input : // Output : //------------------------------------------------------------------------------ void CNPC_MissileDefense::FireCannons( void ) { // ---------------------------------------------- // Make sure I have an enemy // ---------------------------------------------- if (GetEnemy() == NULL) { return; } // ---------------------------------------------- // Make sure I have ammo // ---------------------------------------------- if( m_iAmmoLoaded < 1 ) { return; } // ---------------------------------------------- // Make sure gun it pointing in right direction // ---------------------------------------------- Vector vGunDir; GetGunAim( &vGunDir ); Vector vTargetPos; EnemyShootPosition(GetEnemy(),&vTargetPos); Vector vTargetDir = vTargetPos - GetAbsOrigin(); VectorNormalize( vTargetDir ); float fDotPr = DotProduct( vGunDir, vTargetDir ); if (fDotPr < 0.95) { return; } // ---------------------------------------------- // Check line of sight // ---------------------------------------------- trace_t tr; AI_TraceLine( GetEnemy()->EyePosition(), GetAbsOrigin(), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr); if (tr.fraction < 1.0) { return; } Vector vecRight; Vector vecDir; Vector vecCenter; AngleVectors( GetLocalAngles(), NULL, &vecRight, NULL ); vecCenter = WorldSpaceCenter(); if( GetEnemy() == NULL ) { return; } bool fSound = false; if( random->RandomInt( 0, 3 ) == 0 ) { fSound = true; } EmitSound( "NPC_MissileDefense.Attack" ); Vector vecGun; QAngle vecAng; GetAttachment( MD_AP_LGUN, vecGun, vecAng ); Vector vecTarget; EnemyShootPosition(GetEnemy(),&vecTarget); vecDir = vecTarget - vecCenter; VectorNormalize(vecDir); vecDir.x += random->RandomFloat( -NOISE, NOISE ); vecDir.y += random->RandomFloat( -NOISE, NOISE ); Vector vecStart = vecGun + vecDir * 110; Vector vecEnd = vecGun + vecDir * 4096; UTIL_Tracer( vecStart, vecEnd, 0, TRACER_DONT_USE_ATTACHMENT, 3000 + random->RandomFloat( 0, 2000 ), fSound ); vecDir = vecTarget - vecCenter; VectorNormalize(vecDir); vecDir.x += random->RandomFloat( -NOISE, NOISE ); vecDir.y += random->RandomFloat( -NOISE, NOISE ); vecDir.z += random->RandomFloat( -NOISE, NOISE ); GetAttachment( MD_AP_RGUN, vecGun, vecAng ); vecStart = vecGun + vecDir * 110; vecEnd = vecGun + vecDir * 4096; UTIL_Tracer( vecStart, vecEnd, 0, TRACER_DONT_USE_ATTACHMENT, 3000 + random->RandomFloat( 0, 2000 ) ); m_iAmmoLoaded -= 2; if( m_iAmmoLoaded < 1 ) { // Incite a reload. EmitSound( "NPC_MissileDefense.Reload" ); m_flReloadedTime = gpGlobals->curtime + 0.3; return; } // Do damage to the missile based on distance. // if < 1, make damage 0. float flDist = (GetEnemy()->GetLocalOrigin() - vecGun).Length(); float flDamage; flDamage = 4000 - flDist; flDamage /= 1000.0; if( flDamage > 0 ) { if( flDist <= 1500 ) { flDamage *= 2; } CTakeDamageInfo info( this, this, flDamage, DMG_MISSILEDEFENSE ); CalculateBulletDamageForce( &info, GetAmmoDef()->Index("SMG1"), vecDir, GetEnemy()->GetAbsOrigin() ); GetEnemy()->TakeDamage( info ); } }
//----------------------------------------------------------------------------- // Purpose: // Input : &Steer - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CNPC_Ichthyosaur::SteerAvoidObstacles(Vector &Steer, const Vector &Velocity, const Vector &Forward, const Vector &Right, const Vector &Up) { trace_t tr; bool collided = false; Vector dir = Velocity; float speed = VectorNormalize( dir ); //Look ahead one second and avoid whatever is in our way. AI_TraceHull( GetAbsOrigin(), GetAbsOrigin() + (dir*speed), GetHullMins(), GetHullMaxs(), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr ); Vector forward; GetVectors( &forward, NULL, NULL ); //If we're hitting our enemy, just continue on if ( ( GetEnemy() != NULL ) && ( tr.m_pEnt == GetEnemy() ) ) return false; if ( tr.fraction < 1.0f ) { CBaseEntity *pBlocker = tr.m_pEnt; if ( ( pBlocker != NULL ) && ( pBlocker->MyNPCPointer() != NULL ) ) { DevMsg( 2, "Avoiding an NPC\n" ); Vector HitOffset = tr.endpos - GetAbsOrigin(); Vector SteerUp = CrossProduct( HitOffset, Velocity ); Steer = CrossProduct( SteerUp, Velocity ); VectorNormalize( Steer ); /*Vector probeDir = tr.endpos - GetAbsOrigin(); Vector normalToProbeAndWallNormal = probeDir.Cross( tr.plane.normal ); Steer = normalToProbeAndWallNormal.Cross( probeDir ); VectorNormalize( Steer );*/ if ( tr.fraction > 0 ) { Steer = (Steer * Velocity.Length()) / tr.fraction; //NDebugOverlay::Line( GetLocalOrigin(), GetLocalOrigin()+Steer, 255, 0, 0, false, 0.1f ); } else { Steer = (Steer * 1000 * Velocity.Length()); //NDebugOverlay::Line( GetLocalOrigin(), GetLocalOrigin()+Steer, 255, 0, 0, false, 0.1f ); } } else { if ( ( pBlocker != NULL ) && ( pBlocker == GetEnemy() ) ) { DevMsg( "Avoided collision\n" ); return false; } DevMsg( 2, "Avoiding the world\n" ); Vector steeringVector = tr.plane.normal; if ( tr.fraction == 0.0f ) return false; Steer = steeringVector * ( Velocity.Length() / tr.fraction ); //NDebugOverlay::Line( GetLocalOrigin(), GetLocalOrigin()+Steer, 255, 0, 0, false, 0.1f ); } //return true; collided = true; } //Try to remain 8 feet above the ground. AI_TraceLine( GetAbsOrigin(), GetAbsOrigin() + Vector(0, 0, -ICH_HEIGHT_PREFERENCE), MASK_NPCSOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction < 1.0f ) { Steer += Vector( 0, 0, m_vecAccelerationMax.z / tr.fraction ); collided = true; } //Stay under the surface if ( m_bIgnoreSurface == false ) { float waterLevel = ( UTIL_WaterLevel( GetAbsOrigin(), GetAbsOrigin().z, GetAbsOrigin().z+ICH_DEPTH_PREFERENCE ) - GetAbsOrigin().z ) / ICH_DEPTH_PREFERENCE; if ( waterLevel < 1.0f ) { Steer += -Vector( 0, 0, m_vecAccelerationMax.z / waterLevel ); collided = true; } } return collided; }
void CNPC_Portal_GroundTurret::Shoot() { FireBulletsInfo_t info; Vector vecSrc = EyePosition(); Vector vecDir; GetVectors( &vecDir, NULL, NULL ); for( int i = 0 ; i < 1 ; i++ ) { info.m_vecSrc = vecSrc; if( i > 0 || !GetEnemy()->IsPlayer() ) { // Subsequent shots or shots at non-players random GetVectors( &info.m_vecDirShooting, NULL, NULL ); info.m_vecSpread = m_vecSpread; } else { // First shot is at the enemy. info.m_vecDirShooting = GetActualShootTrajectory( vecSrc ); info.m_vecSpread = VECTOR_CONE_PRECALCULATED; } info.m_iTracerFreq = 1; info.m_iShots = 1; info.m_pAttacker = this; info.m_flDistance = MAX_COORD_RANGE; info.m_iAmmoType = m_iAmmoType; FireBullets( info ); trace_t tr; CTraceFilterSkipTwoEntities traceFilter( this, info.m_pAdditionalIgnoreEnt, COLLISION_GROUP_NONE ); Vector vecEnd = info.m_vecSrc + vecDir * info.m_flDistance; AI_TraceLine( info.m_vecSrc, vecEnd, MASK_SHOT, &traceFilter, &tr ); if ( tr.m_pEnt && !tr.m_pEnt->IsPlayer() && ( vecDir * info.m_flDistance * tr.fraction ).Length() < 16.0f ) { CTakeDamageInfo damageInfo; damageInfo.SetAttacker( this ); damageInfo.SetDamageType( DMG_BULLET ); damageInfo.SetDamage( 20.0f ); TakeDamage( damageInfo ); EmitSound( "NPC_FloorTurret.DryFire" ); } } // Do the AR2 muzzle flash CEffectData data; data.m_nEntIndex = entindex(); data.m_nAttachmentIndex = LookupAttachment( "eyes" ); data.m_flScale = 1.0f; data.m_fFlags = MUZZLEFLASH_COMBINE; DispatchEffect( "MuzzleFlash", data ); EmitSound( "NPC_FloorTurret.ShotSounds" ); m_flTimeNextShoot = gpGlobals->curtime + 0.09; }