//========================================================= // Revela la posición de los jugadores. //========================================================= void CDirector_Manager::Disclose() { CAI_BaseNPC *pNPC = NULL; do { // Buscamos a todos los hijos en el mapa. pNPC = (CAI_BaseNPC *)gEntList.FindEntityByName(pNPC, CHILD_NAME); // No existe o esta muerto. if ( !pNPC || !pNPC->IsAlive() ) continue; // Ya tiene a un jugador como enemigo. if ( pNPC->GetEnemy() && pNPC->GetEnemy()->IsPlayer() ) continue; // Seleccionamos al jugador más cercano. float flDistance = 0.0f; CIN_Player *pPlayer = UTIL_GetNearestInPlayer(pPlayer->GetAbsOrigin(), flDistance); if ( !pPlayer ) continue; // Le decimos que su nuevo enemigo es el jugador y le damos la ubicación de este. pNPC->SetEnemy(pPlayer); pNPC->UpdateEnemyMemory(pPlayer, pPlayer->GetAbsOrigin()); } while ( pNPC ); }
void CAI_Squad::SquadNewEnemy( CBaseEntity *pEnemy ) { if ( !pEnemy ) { DevMsg( "ERROR: SquadNewEnemy() - pEnemy is NULL!\n" ); return; } for (int i = 0; i < m_SquadMembers.Count(); i++) { CAI_BaseNPC *pMember = m_SquadMembers[i]; if (pMember) { // reset members who aren't activly engaged in fighting (only do this if the NPC's using the squad memory, or it'll fail) if ( !pMember->GetEnemy() || ( pMember->GetEnemy() != pEnemy && !pMember->HasCondition( COND_SEE_ENEMY) && gpGlobals->curtime - pMember->GetEnemyLastTimeSeen() > 3.0 ) ) { // give them a new enemy if( !hl2_episodic.GetBool() || pMember->IsValidEnemy(pEnemy) ) { pMember->SetEnemy( pEnemy ); } // pMember->SetLastAttackTime( 0 ); } } } }
//----------------------------------------------------------------------------- // Purpose: // Input : *pInflictor - // *pAttacker - // flDamage - // bitsDamageType - // Output : int //----------------------------------------------------------------------------- int CNPC_Bullseye::OnTakeDamage( const CTakeDamageInfo &info ) { SetNextThink( gpGlobals->curtime ); //If specified, we must be the enemy of the target if ( m_spawnflags & SF_BULLSEYE_ENEMYDAMAGEONLY ) { CAI_BaseNPC *pInstigator = info.GetAttacker()->MyNPCPointer(); if ( pInstigator == NULL ) return 0; if ( pInstigator->GetEnemy() != this ) return 0; } //If we're a pain proxy, send the damage through if ( m_hPainPartner != NULL ) { m_hPainPartner->TakeDamage( info ); //Fire all pain indicators but take no real damage CTakeDamageInfo subInfo = info; subInfo.SetDamage( 0 ); return BaseClass::OnTakeDamage( subInfo ); } return BaseClass::OnTakeDamage( info ); }
//----------------------------------------------------------------------------- // Purpose: Gets event from anim stream and throws the object // Input : // Output : //----------------------------------------------------------------------------- void CWeaponMolotov::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ) { switch( pEvent->event ) { case EVENT_WEAPON_THROW: { CAI_BaseNPC *pNPC = GetOwner()->MyNPCPointer(); if (!pNPC) { return; } CBaseEntity *pEnemy = pNPC->GetEnemy(); if (!pEnemy) { return; } Vector vec_target = pNPC->GetEnemyLKP(); // ----------------------------------------------------- // Get position of throw // ----------------------------------------------------- // If owner has a hand, set position to the hand bone position Vector launchPos; int iBIndex = pNPC->LookupBone("Bip01 R Hand"); if (iBIndex != -1) { Vector origin; QAngle angles; pNPC->GetBonePosition( iBIndex, launchPos, angles); } // Otherwise just set to in front of the owner else { Vector vFacingDir = pNPC->BodyDirection2D( ); vFacingDir = vFacingDir * 60.0; launchPos = pNPC->GetAbsOrigin()+vFacingDir; } //Vector vecVelocity = VecCheckToss( pNPC, launchPos, vec_target, 1.0 ); ThrowMolotov( launchPos, m_vecTossVelocity); // Drop the weapon and remove as no more ammo pNPC->Weapon_Drop( this ); UTIL_Remove( this ); } break; default: BaseClass::Operator_HandleAnimEvent( pEvent, pOperator ); break; } }
//----------------------------------------------------------------------------- // 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: Attempt to govern how many squad members can target any given entity // Input : *pCaller - Entity assessing the target // *pEnemy - Entity being assessed // Output : Returns true if potential enemy passes this filter stage //----------------------------------------------------------------------------- bool CFilterEnemy::PassesMobbedFilter( CBaseEntity *pCaller, CBaseEntity *pEnemy ) { // Must be a valid candidate CAI_BaseNPC *pNPC = pCaller->MyNPCPointer(); if ( pNPC == NULL || pNPC->GetSquad() == NULL ) return true; // Make sure we're checking for this if ( m_nMaxSquadmatesPerEnemy <= 0 ) return true; AISquadIter_t iter; int nNumMatchingSquadmates = 0; // Look through our squad members to see how many of them are already mobbing this entity for ( CAI_BaseNPC *pSquadMember = pNPC->GetSquad()->GetFirstMember( &iter ); pSquadMember != NULL; pSquadMember = pNPC->GetSquad()->GetNextMember( &iter ) ) { // Disregard ourself if ( pSquadMember == pNPC ) continue; // If the enemies match, count it if ( pSquadMember->GetEnemy() == pEnemy ) { nNumMatchingSquadmates++; // If we're at or passed the max we stop if ( nNumMatchingSquadmates >= m_nMaxSquadmatesPerEnemy ) { // We wanted to find more than allowed and we did if ( m_bNegated ) return true; // We wanted to be less but we're not return false; } } } // We wanted to find more than the allowed amount but we didn't if ( m_bNegated ) return false; return true; }
int CWeaponCrowbar::WeaponMeleeAttack1Condition( float flDot, float flDist ) { // Attempt to lead the target (needed because citizens can't hit manhacks with the crowbar!) CAI_BaseNPC *pNPC = GetOwner()->MyNPCPointer(); CBaseEntity *pEnemy = pNPC->GetEnemy(); if (!pEnemy) return COND_NONE; Vector vecVelocity; vecVelocity = pEnemy->GetSmoothedVelocity( ); // Project where the enemy will be in a little while float dt = sk_crowbar_lead_time.GetFloat(); dt += random->RandomFloat( -0.3f, 0.2f ); if ( dt < 0.0f ) dt = 0.0f; Vector vecExtrapolatedPos; VectorMA( pEnemy->WorldSpaceCenter(), dt, vecVelocity, vecExtrapolatedPos ); Vector vecDelta; VectorSubtract( vecExtrapolatedPos, pNPC->WorldSpaceCenter(), vecDelta ); if ( fabs( vecDelta.z ) > 70 ) { return COND_TOO_FAR_TO_ATTACK; } Vector vecForward = pNPC->BodyDirection2D( ); vecDelta.z = 0.0f; float flExtrapolatedDist = Vector2DNormalize( vecDelta.AsVector2D() ); if ((flDist > 64) && (flExtrapolatedDist > 64)) { return COND_TOO_FAR_TO_ATTACK; } float flExtrapolatedDot = DotProduct2D( vecDelta.AsVector2D(), vecForward.AsVector2D() ); if ((flDot < 0.7) && (flExtrapolatedDot < 0.7)) { return COND_NOT_FACING_ATTACK; } return COND_CAN_MELEE_ATTACK1; }
//----------------------------------------------------------------------------- // Purpose: // Input : *pAttacker - // flDamage - // &vecDir - // *ptr - // bitsDamageType - //----------------------------------------------------------------------------- void CNPC_Bullseye::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr ) { //If specified, we must be the enemy of the target if ( m_spawnflags & SF_BULLSEYE_ENEMYDAMAGEONLY ) { CAI_BaseNPC *pInstigator = info.GetAttacker()->MyNPCPointer(); if ( pInstigator == NULL ) return; if ( pInstigator->GetEnemy() != this ) return; } //We can bleed if we want to, we can leave decals behind... if ( ( m_spawnflags & SF_BULLSEYE_BLEED ) && ( m_takedamage == DAMAGE_NO ) ) { TraceBleed( info.GetDamage(), vecDir, ptr, info.GetDamageType() ); } BaseClass::TraceAttack( info, vecDir, ptr ); }
int CWeaponStunStick::WeaponMeleeAttack1Condition( float flDot, float flDist ) { // Attempt to lead the target (needed because citizens can't hit manhacks with the crowbar!) CAI_BaseNPC *pNPC = GetOwner()->MyNPCPointer(); CBaseEntity *pEnemy = pNPC->GetEnemy(); if (!pEnemy) return COND_NONE; Vector vecVelocity; AngularImpulse angVelocity; pEnemy->GetVelocity( &vecVelocity, &angVelocity ); // Project where the enemy will be in a little while, add some randomness so he doesn't always hit float dt = sk_crowbar_lead_time.GetFloat(); dt += random->RandomFloat( -0.3f, 0.2f ); if ( dt < 0.0f ) dt = 0.0f; Vector vecExtrapolatedPos; VectorMA( pEnemy->WorldSpaceCenter(), dt, vecVelocity, vecExtrapolatedPos ); Vector vecDelta; VectorSubtract( vecExtrapolatedPos, pNPC->WorldSpaceCenter(), vecDelta ); if ( fabs( vecDelta.z ) > 70 ) { return COND_TOO_FAR_TO_ATTACK; } Vector vecForward = pNPC->BodyDirection2D( ); vecDelta.z = 0.0f; float flExtrapolatedDot = DotProduct2D( vecDelta.AsVector2D(), vecForward.AsVector2D() ); if ((flDot < 0.7) && (flExtrapolatedDot < 0.7)) { return COND_NOT_FACING_ATTACK; } float flExtrapolatedDist = Vector2DNormalize( vecDelta.AsVector2D() ); if( pEnemy->IsPlayer() ) { //Vector vecDir = pEnemy->GetSmoothedVelocity(); //float flSpeed = VectorNormalize( vecDir ); // If player will be in front of me in one-half second, clock his arse. Vector vecProjectEnemy = pEnemy->GetAbsOrigin() + (pEnemy->GetAbsVelocity() * 0.35); Vector vecProjectMe = GetAbsOrigin(); if( (vecProjectMe - vecProjectEnemy).Length2D() <= 48.0f ) { return COND_CAN_MELEE_ATTACK1; } } /* if( metropolice_move_and_melee.GetBool() ) { if( pNPC->IsMoving() ) { flTargetDist *= 1.5f; } } */ float flTargetDist = 48.0f; if ((flDist > flTargetDist) && (flExtrapolatedDist > flTargetDist)) { return COND_TOO_FAR_TO_ATTACK; } return COND_CAN_MELEE_ATTACK1; }
//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CNPC_Monk::GatherConditions() { BaseClass::GatherConditions(); // Build my zombie danger index! m_iNumZombies = 0; m_iDangerousZombies = 0; AISightIter_t iter; CBaseEntity *pSightEnt; pSightEnt = GetSenses()->GetFirstSeenEntity( &iter ); while( pSightEnt ) { if( pSightEnt->Classify() == CLASS_ZOMBIE && pSightEnt->IsAlive() ) { // Is this zombie coming for me? CAI_BaseNPC *pZombie = dynamic_cast<CAI_BaseNPC*>(pSightEnt); if( pZombie && pZombie->GetEnemy() == this ) { m_iNumZombies++; // if this zombie is close enough to attack, add him to the zombie danger! float flDist; flDist = (pZombie->GetAbsOrigin() - GetAbsOrigin()).Length2DSqr(); if( flDist <= 128.0f * 128.0f ) { m_iDangerousZombies++; } } } pSightEnt = GetSenses()->GetNextSeenEntity( &iter ); } if( m_iDangerousZombies >= 3 || (GetEnemy() && GetHealth() < 25) ) { // I see many zombies, or I'm quite injured. SpeakIfAllowed( TLK_HELP_ME ); } // NOTE!!!!!! This code assumes grigori is using annabelle! ClearCondition(COND_LOW_PRIMARY_AMMO); if ( GetActiveWeapon() ) { if ( GetActiveWeapon()->UsesPrimaryAmmo() ) { if (!GetActiveWeapon()->HasPrimaryAmmo() ) { SetCondition(COND_NO_PRIMARY_AMMO); } else if ( m_NPCState != NPC_STATE_COMBAT && GetActiveWeapon()->UsesClipsForAmmo1() && GetActiveWeapon()->Clip1() < 2 ) { // Don't send a low ammo message unless we're not in combat. SetCondition(COND_LOW_PRIMARY_AMMO); } } } }
//----------------------------------------------------------------------------- // Purpose: // Input : flDot - // flDist - // Output : int //----------------------------------------------------------------------------- int CWeaponSMG1::WeaponRangeAttack2Condition( float flDot, float flDist ) { CAI_BaseNPC *npcOwner = GetOwner()->MyNPCPointer(); return COND_NONE; /* // -------------------------------------------------------- // Assume things haven't changed too much since last time // -------------------------------------------------------- if (gpGlobals->curtime < m_flNextGrenadeCheck ) return m_lastGrenadeCondition; */ // ----------------------- // If moving, don't check. // ----------------------- if ( npcOwner->IsMoving()) return COND_NONE; CBaseEntity *pEnemy = npcOwner->GetEnemy(); if (!pEnemy) return COND_NONE; Vector vecEnemyLKP = npcOwner->GetEnemyLKP(); if ( !( pEnemy->GetFlags() & FL_ONGROUND ) && pEnemy->GetWaterLevel() == 0 && vecEnemyLKP.z > (GetAbsOrigin().z + WorldAlignMaxs().z) ) { //!!!BUGBUG - we should make this check movetype and make sure it isn't FLY? Players who jump a lot are unlikely to // be grenaded. // don't throw grenades at anything that isn't on the ground! return COND_NONE; } // -------------------------------------- // Get target vector // -------------------------------------- Vector vecTarget; if (random->RandomInt(0,1)) { // magically know where they are vecTarget = pEnemy->WorldSpaceCenter(); } else { // toss it to where you last saw them vecTarget = vecEnemyLKP; } // vecTarget = m_vecEnemyLKP + (pEnemy->BodyTarget( GetLocalOrigin() ) - pEnemy->GetLocalOrigin()); // estimate position // vecTarget = vecTarget + pEnemy->m_vecVelocity * 2; if ( ( vecTarget - npcOwner->GetLocalOrigin() ).Length2D() <= COMBINE_MIN_GRENADE_CLEAR_DIST ) { // crap, I don't want to blow myself up m_flNextGrenadeCheck = gpGlobals->curtime + 1; // one full second. return (COND_NONE); } // --------------------------------------------------------------------- // Are any friendlies near the intended grenade impact area? // --------------------------------------------------------------------- CBaseEntity *pTarget = NULL; while ( ( pTarget = gEntList.FindEntityInSphere( pTarget, vecTarget, COMBINE_MIN_GRENADE_CLEAR_DIST ) ) != NULL ) { //Check to see if the default relationship is hatred, and if so intensify that if ( npcOwner->IRelationType( pTarget ) == D_LI ) { // crap, I might blow my own guy up. Don't throw a grenade and don't check again for a while. m_flNextGrenadeCheck = gpGlobals->curtime + 1; // one full second. return (COND_WEAPON_BLOCKED_BY_FRIEND); } } // --------------------------------------------------------------------- // Check that throw is legal and clear // --------------------------------------------------------------------- // FIXME: speed is based on difficulty... Vector vecToss = VecCheckThrow( this, npcOwner->GetLocalOrigin() + Vector(0,0,60), vecTarget, 600.0, 0.5 ); if ( vecToss != vec3_origin ) { m_vecTossVelocity = vecToss; // don't check again for a while. // JAY: HL1 keeps checking - test? //m_flNextGrenadeCheck = gpGlobals->curtime; m_flNextGrenadeCheck = gpGlobals->curtime + 0.3; // 1/3 second. return COND_CAN_RANGE_ATTACK2; } else { // don't check again for a while. m_flNextGrenadeCheck = gpGlobals->curtime + 1; // one full second. return COND_WEAPON_SIGHT_OCCLUDED; } }
//----------------------------------------------------------------------------- // 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; }
void CAI_MoveAndShootOverlay::RunShootWhileMove() { if ( m_flNextMoveShootTime == FLT_MAX ) return; CAI_BaseNPC *pOuter = GetOuter(); // keep enemy if dead but try to look for a new one if (!pOuter->GetEnemy() || !pOuter->GetEnemy()->IsAlive()) { CBaseEntity *pNewEnemy = pOuter->BestEnemy(); if( pNewEnemy != NULL ) { //New enemy! Clear the timers and set conditions. pOuter->SetCondition( COND_NEW_ENEMY ); pOuter->SetEnemy( pNewEnemy ); pOuter->SetState( NPC_STATE_COMBAT ); } else { pOuter->ClearAttackConditions(); } // SetEnemy( NULL ); } if ( GetEnemy() == NULL || !pOuter->GetNavigator()->IsGoalActive() ) return; bool bMoveAimAtEnemy = CanAimAtEnemy(); UpdateMoveShootActivity( bMoveAimAtEnemy ); if (bMoveAimAtEnemy) { Assert( pOuter->GetActiveWeapon() ); // This should have been caught at task start // time to fire? if ( pOuter->HasCondition( COND_CAN_RANGE_ATTACK1 ) && gpGlobals->curtime >= m_flNextMoveShootTime ) { if ( m_bMovingAndShooting || GetOuter()->OnBeginMoveAndShoot() ) { m_bMovingAndShooting = true; Activity activity = pOuter->TranslateActivity( ACT_GESTURE_RANGE_ATTACK1 ); Assert( activity != ACT_INVALID ); if (--m_nMoveShots > 0) { pOuter->SetLastAttackTime( gpGlobals->curtime ); pOuter->AddGesture( activity ); // FIXME: this seems a bit wacked pOuter->Weapon_SetActivity( pOuter->Weapon_TranslateActivity( ACT_RANGE_ATTACK1 ), 0 ); m_flNextMoveShootTime = gpGlobals->curtime + pOuter->GetActiveWeapon()->GetFireRate() - 0.1; } else { m_nMoveShots = random->RandomInt( m_minBurst, m_maxBurst ); m_flNextMoveShootTime = gpGlobals->curtime + random->RandomFloat( m_minPause, m_maxPause ); m_bMovingAndShooting = false; GetOuter()->OnEndMoveAndShoot(); } } } // try to keep facing towards the last known position of the enemy Vector vecEnemyLKP = pOuter->GetEnemyLKP(); pOuter->AddFacingTarget( pOuter->GetEnemy(), vecEnemyLKP, 1.0, 0.8 ); } else { if ( m_bMovingAndShooting ) { m_bMovingAndShooting = false; GetOuter()->OnEndMoveAndShoot(); } } }
void CAI_MoveAndShootOverlay::RunShootWhileMove() { if ( m_bNoShootWhileMove ) return; if ( gpGlobals->curtime < m_flSuspendUntilTime ) return; m_flSuspendUntilTime = MOVESHOOT_DO_NOT_SUSPEND; CAI_BaseNPC *pOuter = GetOuter(); // keep enemy if dead but try to look for a new one if (!pOuter->GetEnemy() || !pOuter->GetEnemy()->IsAlive()) { CBaseEntity *pNewEnemy = pOuter->BestEnemy(); if( pNewEnemy != NULL ) { //New enemy! Clear the timers and set conditions. pOuter->SetEnemy( pNewEnemy ); pOuter->SetState( NPC_STATE_COMBAT ); } else { pOuter->ClearAttackConditions(); } // SetEnemy( NULL ); } /*if( !pOuter->GetNavigator()->IsGoalActive() ) return;*/ if ( GetEnemy() == NULL ) { if ( pOuter->GetAlternateMoveShootTarget() ) { // Aim at this other thing if I can't aim at my enemy. pOuter->AddFacingTarget( pOuter->GetAlternateMoveShootTarget(), pOuter->GetAlternateMoveShootTarget()->GetAbsOrigin(), 1.0, 0.2 ); } return; } bool bMoveAimAtEnemy = CanAimAtEnemy(); UpdateMoveShootActivity( bMoveAimAtEnemy ); if ( !bMoveAimAtEnemy ) { EndShootWhileMove(); return; } Assert( HasAvailableRangeAttack() ); // This should have been caught at task start Activity activity; bool bIsReloading = false; if ( ( activity = pOuter->TranslateActivity( ACT_GESTURE_RELOAD ) ) != ACT_INVALID ) { bIsReloading = pOuter->IsPlayingGesture( activity ); } if ( !bIsReloading && HasAvailableRangeAttack() ) { // time to fire? if ( pOuter->HasCondition( COND_CAN_RANGE_ATTACK1, false ) ) { if ( pOuter->GetShotRegulator()->IsInRestInterval() ) { EndShootWhileMove(); } else if ( pOuter->GetShotRegulator()->ShouldShoot() ) { if ( m_bMovingAndShooting || pOuter->OnBeginMoveAndShoot() ) { m_bMovingAndShooting = true; pOuter->OnRangeAttack1(); activity = pOuter->TranslateActivity( ACT_GESTURE_RANGE_ATTACK1 ); Assert( activity != ACT_INVALID ); pOuter->RestartGesture( activity ); // FIXME: this seems a bit wacked pOuter->Weapon_SetActivity( pOuter->Weapon_TranslateActivity( ACT_RANGE_ATTACK1 ), 0 ); } } } } // try to keep facing towards the last known position of the enemy Vector vecEnemyLKP = pOuter->GetEnemyLKP(); pOuter->AddFacingTarget( pOuter->GetEnemy(), vecEnemyLKP, 1.0, 0.8 ); }