//----------------------------------------------------------------------------- // Purpose: Check the weapon LOS for an owner at an arbitrary position // If bSetConditions is true, LOS related conditions will also be set //----------------------------------------------------------------------------- bool CASW_Weapon::WeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions ) { bool bHasLOS = BaseClass::WeaponLOSCondition(ownerPos, targetPos, bSetConditions); // if the weapon has LOS, then do another wider trace to check we don't hit any friendlies // this is to stop the AI marines shooting way too close to other marines, which stops the player thinking about positioning so much if (bHasLOS && GetOwner() && asw_weapon_safety_hull.GetFloat() > 0) { CAI_BaseNPC* npcOwner = GetOwner()->MyNPCPointer(); Vector vecRelativeShootPosition; VectorSubtract( npcOwner->Weapon_ShootPosition(), npcOwner->GetAbsOrigin(), vecRelativeShootPosition ); // Find its relative shoot position Vector barrelPos = ownerPos + vecRelativeShootPosition; CASWWeaponLOSFilter traceFilter( GetOwner(), npcOwner->GetEnemy(), COLLISION_GROUP_BREAKABLE_GLASS ); // Use the custom LOS trace filter trace_t tr; UTIL_TraceHull( barrelPos, targetPos, Vector(-asw_weapon_safety_hull.GetFloat(), -asw_weapon_safety_hull.GetFloat(), -asw_weapon_safety_hull.GetFloat()), Vector(asw_weapon_safety_hull.GetFloat(), asw_weapon_safety_hull.GetFloat(), asw_weapon_safety_hull.GetFloat()), MASK_SHOT, &traceFilter, &tr ); if ( tr.fraction == 1.0 || tr.m_pEnt == npcOwner->GetEnemy() ) return true; // if a friendly is in the way, then we report failure CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( tr.m_pEnt ); if ( pBCC ) { if ( npcOwner->IRelationType( pBCC ) == D_HT ) return true; if ( bSetConditions ) { npcOwner->SetCondition( COND_WEAPON_BLOCKED_BY_FRIEND ); } return false; } } return bHasLOS; }
//----------------------------------------------------------------------------- // Purpose: Check the weapon LOS for an owner at an arbitrary position // If bSetConditions is true, LOS related conditions will also be set //----------------------------------------------------------------------------- bool CBaseCombatWeapon::WeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions ) { // -------------------- // Check for occlusion // -------------------- CAI_BaseNPC* npcOwner = m_hOwner.Get()->MyNPCPointer(); // Find its relative shoot position Vector vecRelativeShootPosition; VectorSubtract( npcOwner->Weapon_ShootPosition(), npcOwner->GetAbsOrigin(), vecRelativeShootPosition ); Vector barrelPos = ownerPos + vecRelativeShootPosition; // Use the custom LOS trace filter CWeaponLOSFilter traceFilter( m_hOwner.Get(), npcOwner->GetEnemy(), COLLISION_GROUP_BREAKABLE_GLASS ); trace_t tr; UTIL_TraceLine( barrelPos, targetPos, MASK_SHOT, &traceFilter, &tr ); // See if we completed the trace without interruption if ( tr.fraction == 1.0 ) { if ( ai_debug_shoot_positions.GetBool() ) { NDebugOverlay::Line( barrelPos, targetPos, 0, 255, 0, false, 1.0 ); } return true; } CBaseEntity *pHitEnt = tr.m_pEnt; CBasePlayer *pEnemyPlayer = ToBasePlayer( npcOwner->GetEnemy() ); // is player in a vehicle? if so, verify vehicle is target and return if so (so npc shoots at vehicle) if ( pEnemyPlayer && pEnemyPlayer->IsInAVehicle() ) { // Ok, player in vehicle, check if vehicle is target we're looking at, fire if it is // Also, check to see if the owner of the entity is the vehicle, in which case it's valid too. // This catches vehicles that use bone followers. CBaseEntity *pVehicle = pEnemyPlayer->GetVehicle()->GetVehicleEnt(); if ( pHitEnt == pVehicle || pHitEnt->GetOwnerEntity() == pVehicle ) return true; } // Hitting our enemy is a success case if ( pHitEnt == npcOwner->GetEnemy() ) { if ( ai_debug_shoot_positions.GetBool() ) { NDebugOverlay::Line( barrelPos, targetPos, 0, 255, 0, false, 1.0 ); } return true; } // If a vehicle is blocking the view, grab its driver and use that as the combat character CBaseCombatCharacter *pBCC; IServerVehicle *pVehicle = pHitEnt->GetServerVehicle(); if ( pVehicle ) { pBCC = pVehicle->GetPassenger( ); } else { pBCC = ToBaseCombatCharacter( pHitEnt ); } if ( pBCC ) { if ( npcOwner->IRelationType( pBCC ) == D_HT ) return true; if ( bSetConditions ) { npcOwner->SetCondition( COND_WEAPON_BLOCKED_BY_FRIEND ); } } else if ( bSetConditions ) { npcOwner->SetCondition( COND_WEAPON_SIGHT_OCCLUDED ); npcOwner->SetEnemyOccluder( pHitEnt ); if( ai_debug_shoot_positions.GetBool() ) { NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 0, 0, false, 1.0 ); } } return false; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CWeaponAR2::FireNPCSecondaryAttack( CBaseCombatCharacter *pOperator, bool bUseWeaponAngles ) { WeaponSound( WPN_DOUBLE ); if ( !GetOwner() ) return; CAI_BaseNPC *pNPC = GetOwner()->MyNPCPointer(); if ( !pNPC ) return; // Fire! Vector vecSrc; Vector vecAiming; if ( bUseWeaponAngles ) { QAngle angShootDir; GetAttachment( LookupAttachment( "muzzle" ), vecSrc, angShootDir ); AngleVectors( angShootDir, &vecAiming ); } else { vecSrc = pNPC->Weapon_ShootPosition( ); Vector vecTarget; CNPC_Combine *pSoldier = dynamic_cast<CNPC_Combine *>( pNPC ); if ( pSoldier ) { // In the distant misty past, elite soldiers tried to use bank shots. // Therefore, we must ask them specifically what direction they are shooting. vecTarget = pSoldier->GetAltFireTarget(); } else { // All other users of the AR2 alt-fire shoot directly at their enemy. if ( !pNPC->GetEnemy() ) return; vecTarget = pNPC->GetEnemy()->BodyTarget( vecSrc ); } vecAiming = vecTarget - vecSrc; VectorNormalize( vecAiming ); } Vector impactPoint = vecSrc + ( vecAiming * MAX_TRACE_LENGTH ); float flAmmoRatio = 1.0f; float flDuration = RemapValClamped( flAmmoRatio, 0.0f, 1.0f, 0.5f, sk_weapon_ar2_alt_fire_duration.GetFloat() ); float flRadius = RemapValClamped( flAmmoRatio, 0.0f, 1.0f, 4.0f, sk_weapon_ar2_alt_fire_radius.GetFloat() ); // Fire the bullets Vector vecVelocity = vecAiming * 1000.0f; // Fire the combine ball CreateCombineBall( vecSrc, vecVelocity, flRadius, sk_weapon_ar2_alt_fire_mass.GetFloat(), flDuration, pNPC ); }
//----------------------------------------------------------------------------- // Purpose: Override to check throw // Input : // Output : //----------------------------------------------------------------------------- int CWeaponMolotov::WeaponRangeAttack1Condition( float flDot, float flDist ) { // If things haven't changed too much since last time // just return that previously calculated value if (gpGlobals->curtime < m_fNextThrowCheck ) { return m_iThrowBits; } if ( flDist < m_fMinRange1) { m_iThrowBits = COND_TOO_CLOSE_TO_ATTACK; } else if (flDist > m_fMaxRange1) { m_iThrowBits = COND_TOO_FAR_TO_ATTACK; } else if (flDot < 0.5) { m_iThrowBits = COND_NOT_FACING_ATTACK; } // If moving, can't throw. else if ( m_flGroundSpeed != 0 ) { m_iThrowBits = COND_NONE; } else { // Ok we should check again as some time has passed // This function is only used by NPC's so we can cast to a Base Monster CAI_BaseNPC *pNPC = GetOwner()->MyNPCPointer(); CBaseEntity *pEnemy = pNPC->GetEnemy(); if (!pEnemy) { m_iThrowBits = COND_NONE; } // Get Enemy Position Vector vecTarget; pEnemy->CollisionProp()->NormalizedToWorldSpace( Vector( 0.5f, 0.5f, 0.0f ), &vecTarget ); // Get Toss Vector Vector throwStart = pNPC->Weapon_ShootPosition(); Vector vecToss; CBaseEntity* pBlocker = NULL; float throwDist = (throwStart - vecTarget).Length(); float fGravity = sv_gravity.GetFloat(); float throwLimit = pNPC->ThrowLimit(throwStart, vecTarget, fGravity, 35, WorldAlignMins(), WorldAlignMaxs(), pEnemy, &vecToss, &pBlocker); // If I can make the throw (or most of the throw) if (!throwLimit || (throwLimit != throwDist && throwLimit > 0.8*throwDist)) { m_vecTossVelocity = vecToss; m_iThrowBits = COND_CAN_RANGE_ATTACK1; } else { m_iThrowBits = COND_NONE; } } // don't check again for a while. m_fNextThrowCheck = gpGlobals->curtime + 0.33; // 1/3 second. return m_iThrowBits; }