Esempio n. 1
0
void Bot::EnableAutoAlert(const AiAlertSpot &alertSpot, AlertCallback callback, void *receiver)
{
    // First check duplicate ids. Fail on error since callers of this method are internal.
    for (unsigned i = 0; i < alertSpots.size(); ++i)
    {
        if (alertSpots[i].id == alertSpot.id)
            FailWith("Duplicated alert spot (id=%d)\n", alertSpot.id);
    }

    if (alertSpots.size() == alertSpots.capacity())
        FailWith("Can't add an alert spot (id=%d)\n: too many spots", alertSpot.id);

    alertSpots.emplace_back(AlertSpot(alertSpot, callback, receiver));
}
Esempio n. 2
0
int Ai::CheckTravelTimeMillis( const Vec3& from, const Vec3 &to, bool allowUnreachable ) {

	// We try to use the same checks the TacticalSpotsRegistry performs to find spots.
	// If a spot is not reachable, it is an bug,
	// because a reachability must have been checked by the spots registry first in a few preceeding calls.

	int fromAreaNum;
	constexpr float squareDistanceError = WorldState::OriginVar::MAX_ROUNDING_SQUARE_DISTANCE_ERROR;
	if( ( from - self->s.origin ).SquaredLength() < squareDistanceError ) {
		fromAreaNum = aasWorld->FindAreaNum( self );
	} else {
		fromAreaNum = aasWorld->FindAreaNum( from );
	}

	if( !fromAreaNum ) {
		if( allowUnreachable ) {
			return 0;
		}

		FailWith( "CheckTravelTimeMillis(): Can't find `from` AAS area" );
	}

	const int toAreaNum = aasWorld->FindAreaNum( to.Data() );
	if( !toAreaNum ) {
		if( allowUnreachable ) {
			return 0;
		}

		FailWith( "CheckTravelTimeMillis(): Can't find `to` AAS area" );
	}

	for( int flags: { self->ai->aiRef->PreferredTravelFlags(), self->ai->aiRef->AllowedTravelFlags() } ) {
		if( int aasTravelTime = routeCache->TravelTimeToGoalArea( fromAreaNum, toAreaNum, flags ) ) {
			return 10U * aasTravelTime;
		}
	}

	if( allowUnreachable ) {
		return 0;
	}

	FailWith( "CheckTravelTimeMillis(): Can't find travel time %d->%d\n", fromAreaNum, toAreaNum );
}
Esempio n. 3
0
void Bot::DisableAutoAlert(int id)
{
    for (unsigned i = 0; i < alertSpots.size(); ++i)
    {
        if (alertSpots[i].id == id)
        {
            alertSpots.erase(alertSpots.begin() + i);
            return;
        }
    }

    FailWith("Can't find alert spot by id %d\n", id);
}
Esempio n. 4
0
bool Bot::MayKeepRunningInCombat() const
{
    if (!HasEnemy())
        FailWith("MayKeepRunningInCombat(): there is no enemy");

    Vec3 enemyToBotDir = Vec3(self->s.origin) - EnemyOrigin();
    bool enemyMayHit = true;
    if (IsEnemyAStaticSpot())
    {
        enemyMayHit = false;
    }
    else if (EnemyFireDelay() > 300)
    {
        enemyMayHit = false;
    }
    else
    {
        Vec3 enemyLookDir = EnemyLookDir();
        float squaredDistance = enemyToBotDir.SquaredLength();
        if (squaredDistance > 1)
        {
            float distance = 1.0f / Q_RSqrt(squaredDistance);
            enemyToBotDir *= 1.0f / distance;
            // Compute a cosine of angle between enemy look dir and enemy to bot dir
            float cosPhi = enemyLookDir.Dot(enemyToBotDir);
            // Be aware of RL splash on this range
            if (distance < 150.0f)
                enemyMayHit = cosPhi > 0.3;
            else if (cosPhi <= 0.3)
                enemyMayHit = false;
            else
            {
                float cotPhi = Q_RSqrt((1.0f / (cosPhi * cosPhi)) - 1);
                float sideMiss = distance / cotPhi;
                // Use hitbox height plus a bit as a worst case
                float hitboxLargestSectionSide = 8.0f + playerbox_stand_maxs[2] - playerbox_stand_mins[2];
                enemyMayHit = sideMiss < hitboxLargestSectionSide;
            }
        }
    }

    if (enemyMayHit)
        return false;

    vec3_t botLookDir;
    AngleVectors(self->s.angles, botLookDir, nullptr, nullptr);
    // Check whether the bot may hit while running
    return ((-enemyToBotDir).Dot(botLookDir) > 0.99);
}