/* ================ idBotAI::Bot_VehicleFindEnemy We'll sort thru the clients, and ignore certain clients if we're too busy to be buggered (carrying obj, planting/hacking, etc) or they're not valid enemies (in disguise, hidden by smoke, etc). ================ */ bool idBotAI::Bot_VehicleFindEnemy() { bool hasAttackedMate; bool hasAttackedCriticalMate; bool hasObj; bool isDefusingOurBomb; bool inFront; bool botGotShotRecently; bool botIsBigShot; bool audible; bool isVisible; bool isFacingUs; bool isFiringWeapon; bool isNearOurObj; bool isAttackingDeployable = false; bool inAttackAirCraft = false; int i; int entClientNum = -1; float dist; float botSightDist; float tempSightDist; float entDist = idMath::INFINITY; proxyInfo_t enemyVehicleInfo; enemyVehicleInfo.entNum = 0; idVec3 vec; numVisEnemies = 0; vehicleEnemyWasInheritedFromFootCombat = false; botSightDist = Square( ENEMY_VEHICLE_SIGHT_DIST ); //mal_FIXME: break this out into a script cmd! /* if ( botSightDist > Square( 8000.0f ) ) { botSightDist = Square( 8000.0f ); } else if ( botSightDist < Square( 3000.0f ) ) { botSightDist = Square( 3000.0f ); } */ //mal: some debugging stuff.... if ( botWorld->gameLocalInfo.botIgnoreEnemies == 1 ) { return false; } else if ( botWorld->gameLocalInfo.botIgnoreEnemies == 2 ) { if ( botInfo->team == GDF ) { return false; } } else if ( botWorld->gameLocalInfo.botIgnoreEnemies == 3 ) { if ( botInfo->team == STROGG ) { return false; } } if ( botVehicleInfo->type != BUFFALO && Bot_VehicleIsUnderAVTAttack() != -1 && ( ( botVehicleInfo->flags & ARMOR ) || botVehicleInfo->type > ICARUS ) ) { return false; } if ( botVehicleInfo->type > ICARUS ) { botSightDist = Square( 6000.0f ); } if ( botVehicleInfo->type == BUFFALO ) { botSightDist = Square( 3500.0f ); } if ( botVehicleInfo->type == GOLIATH || botVehicleInfo->type == DESECRATOR ) { //mal: these 2 are really limited botSightDist = Square( PLASMA_CANNON_RANGE - 1000.0f ); } if ( botVehicleInfo->type == HUSKY ) { //mal: we're no match for anybody! return false; } #ifdef _XENON if ( botVehicleInfo->type == MCP && botVehicleInfo->driverEntNum == botNum ) { return false; } if ( botVehicleInfo->type == PLATYPUS && botVehicleInfo->driverEntNum == botNum ) { return false; } #endif if ( botVehicleInfo->type > ICARUS && Client_IsCriticalForCurrentObj( botNum, -1.0f ) ) { return false; } botIsBigShot = Client_IsCriticalForCurrentObj( botNum, 3500.0f ); if ( aiState == VLTG && vLTGType == V_DESTROY_DEPLOYABLE ) { deployableInfo_t deployable; if ( GetDeployableInfo( false, vLTGTarget, deployable ) ) { if ( deployable.type == APT || deployable.type == AVT || deployable.type == AIT ) { //mal: these are the priorities isAttackingDeployable = true; } } } for ( i = 0; i < MAX_CLIENTS; i++ ) { if ( !ClientIsValid( i, -1 ) ) { continue; //mal: no valid client in this client slot! } if ( i == botNum ) { continue; //mal: dont try to fight ourselves! } if ( EnemyIsIgnored( i ) ) { continue; //mal: dont try to fight someone we've flagged to ignore for whatever reason! } if ( !Bot_VehicleCanAttackEnemy( i ) ) { //mal: check if the bot has access to a weapon in the vehicle, that can hit this client. continue; } const clientInfo_t& playerInfo = botWorld->clientInfo[ i ]; if ( playerInfo.isNoTarget ) { continue; } //mal: dont target clients that have notarget set - this is useful for debugging, etc. bool enemyIsBigShot = Client_IsCriticalForCurrentObj( i, 2500.0f ); if ( playerInfo.inLimbo ) { continue; } if ( playerInfo.invulnerableEndTime > botWorld->gameLocalInfo.time ) { continue; //mal: ignore revived/just spawned in clients - get the ppl around them! } if ( playerInfo.isActor ) { continue; } if ( playerInfo.health <= 0 ) { continue; } if ( playerInfo.team == botInfo->team ) { continue; } if ( botVehicleInfo->type == MCP && botVehicleInfo->driverEntNum == botNum ) { if ( !InFrontOfVehicle( botInfo->proxyInfo.entNum, playerInfo.origin ) ) { continue; } } if ( botWorld->gameLocalInfo.botSkill == BOT_SKILL_DEMO && botVehicleInfo->type > ICARUS && !playerInfo.isBot ) { //mal: don't attack human players in training mode when we're in flyers. continue; } hasAttackedCriticalMate = ClientHasAttackedTeammate( i, true, 3000 ); hasAttackedMate = ClientHasAttackedTeammate( i, false, 3000 ); hasObj = ClientHasObj( i ); isDefusingOurBomb = ClientIsDefusingOurTeamCharge( i ); inFront = ( botInfo->proxyInfo.weapon == PERSONAL_WEAPON ) ? InFrontOfClient( botNum, playerInfo.origin) : InFrontOfVehicle( botInfo->proxyInfo.entNum, playerInfo.origin ); isFacingUs = ( playerInfo.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE ) ? InFrontOfClient( i, botInfo->origin ) : InFrontOfVehicle( playerInfo.proxyInfo.entNum, botInfo->origin ); botGotShotRecently = ( botInfo->lastAttackerTime + 3000 < botWorld->gameLocalInfo.time ) ? false : true; isFiringWeapon = playerInfo.weapInfo.isFiringWeap; isNearOurObj = ( LocationDistFromCurrentObj( botInfo->team, playerInfo.origin ) < 2500.0f ) ? true : false; bool isCriticalEnemy = Client_IsCriticalForCurrentObj( i, 2500.0f ); if ( playerInfo.proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { GetVehicleInfo( playerInfo.proxyInfo.entNum, enemyVehicleInfo ); } if ( isAttackingDeployable ) { if ( botInfo->team == botWorld->botGoalInfo.attackingTeam ) { if ( playerInfo.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE ) { if ( playerInfo.weapInfo.weapon != ROCKET && !isDefusingOurBomb ) { continue; } } else { if ( !( enemyVehicleInfo.flags & ARMOR ) && enemyVehicleInfo.type != ANANSI && enemyVehicleInfo.type != HORNET ) { continue; } } } else { if ( !isDefusingOurBomb && playerInfo.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE && !hasObj && playerInfo.weapInfo.weapon != ROCKET && ( !isCriticalEnemy || !isNearOurObj ) ) { continue; } } } if ( botIsBigShot && !isFacingUs && ( !botGotShotRecently || botInfo->lastAttacker != i ) && !isFiringWeapon && !hasObj && !isNearOurObj ) { continue; } //mal: if we're trying to do an important obj, dont get into a fight with everyone. vec = playerInfo.origin - botInfo->origin; if ( botVehicleInfo->isAirborneVehicle ) { vec.z = 0.0f; } dist = vec.LengthSqr(); if ( botIsBigShot && !inFront && dist > Square( 2500.0f ) && ( !botGotShotRecently || botInfo->lastAttacker != i ) && botVehicleInfo->driverEntNum == botNum ) { continue; } if ( playerInfo.proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { //mal: pick the driver of a vehicle as the target, NOT passengers, unless there is no driver - then kill whoever. if ( enemyVehicleInfo.type == ANANSI || enemyVehicleInfo.type == HORNET ) { inAttackAirCraft = true; } if ( botIsBigShot && enemyVehicleInfo.type <= ICARUS ) { continue; } if ( enemyVehicleInfo.type == BUFFALO && botVehicleInfo->flags & ARMOR && playerInfo.isBot ) { continue; } if ( enemyVehicleInfo.type == MCP && enemyVehicleInfo.isImmobilized && enemyVehicleInfo.driverEntNum == i ) { continue; } if ( botVehicleInfo->type == ANANSI && enemyVehicleInfo.type == ICARUS ) { //mal: this is funny to watch, but is a waste of time. :-) continue; } if ( isAttackingDeployable ) { if ( botVehicleInfo->isAirborneVehicle && ( enemyVehicleInfo.type <= ICARUS || enemyVehicleInfo.type == BUFFALO ) ) { //mal: if attacking from the air, only worry about air vehicles. continue; } } if ( enemyVehicleInfo.driverEntNum != i && enemyVehicleInfo.driverEntNum != -1 ) { continue; } if ( inAttackAirCraft && enemyVehicleInfo.xyspeed > 500.0f && dist > Square( TANK_MINIGUN_RANGE ) && botVehicleInfo->flags & ARMOR ) { //mal: tanks won't attack fast moving aircraft that are too far away for their MGs continue; } if ( botVehicleInfo->type == BADGER ) { if ( botInfo->proxyInfo.weapon == NULL_VEHICLE_WEAPON && enemyVehicleInfo.flags & ARMOR || enemyVehicleInfo.inWater || ( enemyVehicleInfo.isAirborneVehicle && dist > Square( 3000.0f ) || enemyVehicleInfo.type == HOG ) ) { continue; } } if ( botVehicleInfo->inWater && botInfo->proxyInfo.weapon == NULL_VEHICLE_WEAPON ) { continue; } if ( botVehicleInfo->type != ANANSI && botVehicleInfo->type != HORNET ) { if ( enemyVehicleInfo.xyspeed > 600.0f && dist > Square( 1900.0f ) && !InFrontOfVehicle( enemyVehicleInfo.entNum, botInfo->origin ) && !ClientHasObj( i ) && !enemyIsBigShot ) { //mal: if they're in a mad dash away from us, forget about them! continue; } } } if ( botVehicleInfo->type == BUFFALO && !inAttackAirCraft ) { //mal_TODO: need to make the buffalo a more effective fighting platform! continue; } tempSightDist = botSightDist; if ( !ClientHasObj( i ) && !enemyIsBigShot && playerInfo.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE && !playerInfo.isCamper && playerInfo.killsSinceSpawn < KILLING_SPREE && botVehicleInfo->driverEntNum == botNum && !isDefusingOurBomb ) { //mal: vehicles will prefer to fight other vehicles, not some guy on foot a mile away.... tempSightDist = Square( 3500.0f ); } if ( inAttackAirCraft && ( botVehicleInfo->type == ANANSI || botVehicleInfo->type == HORNET ) && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { tempSightDist = Square( AIRCRAFT_ATTACK_DIST ); } if ( dist > tempSightDist ) { continue; } if ( playerInfo.isDisguised ) { //mal: when in a vehicle, bots are much less likely to notice or worry about coverts if ( botThreadData.GetBotSkill() == BOT_SKILL_EASY ) { continue; } else { if ( ( playerInfo.disguisedClient != botNum && !hasAttackedMate ) || dist > Square( 2500.0f ) ) { continue; } } } if ( !ClientHasObj( i ) ) { audible = ClientIsAudibleToVehicle( i ); //mal: if we can hear you, we'll skip the FOV test in the vis check below } else { audible = true; dist = Square( 500.0f ); //mal: if you've got the docs, your our priority target, unless someone else is right on top of us! } isVisible = ClientIsVisibleToBot( i, !audible, false ); if ( !isVisible && !ClientHasObj( i ) ) { continue; } if ( botWorld->gameLocalInfo.botSkill != BOT_SKILL_DEMO || botWorld->botGoalInfo.gameIsOnFinalObjective || botWorld->botGoalInfo.attackingTeam == botInfo->team ) { if ( isDefusingOurBomb ) { dist = Square( 100.0f ); } if ( hasAttackedCriticalMate && inFront && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { dist = Square( 600.0f ); //mal: will give higher priority to someone attacking a critical mate, if we can see it happening. } if ( botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { if ( Client_IsCriticalForCurrentObj( i, 6000.0f ) ) { dist = Square( 700.0f ); //mal: if your a critical client, we're more likely to kill you. } } if ( botWorld->botGoalInfo.mapHasMCPGoal ) { if ( playerInfo.proxyInfo.entNum == botWorld->botGoalInfo.botGoal_MCP_VehicleNum ) { dist = 400.0f; } } //mal: if your in MCP, you get higher priority then a normal enemy. Especially when we're in a vehicle! if ( botVehicleInfo->type > ICARUS && botVehicleInfo->type != BUFFALO && ( playerInfo.isCamper || playerInfo.killsSinceSpawn >= KILLING_SPREE ) && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY && !playerInfo.isBot ) { dist = Square( 600.0f ); } //mal: target trouble making humans! } else { if ( !playerInfo.isBot || playerInfo.isActor ) { dist += Square( TRAINING_MODE_RANGE_ADDITION ); } } numVisEnemies++; if ( dist < entDist ) { entClientNum = i; entDist = dist; } } if ( entClientNum != -1 ) { enemy = entClientNum; enemySpawnID = botWorld->clientInfo[ entClientNum ].spawnID; enemyInfo.enemy_FS_Pos = botWorld->clientInfo[ entClientNum ].origin; enemyInfo.enemy_LS_Pos = enemyInfo.enemy_FS_Pos; bot_FS_Enemy_Pos = botInfo->origin; bot_LS_Enemy_Pos = bot_FS_Enemy_Pos; enemyInfo.enemyLastVisTime = botWorld->gameLocalInfo.time; enemyAcquireTime = botWorld->gameLocalInfo.time; Bot_SetAttackTimeDelay( inFront ); //mal: this sets a delay on how long the bot should take to see enemy, based on bot's state. VEHICLE_COMBAT_AI_SUB_NODE = NULL; //mal: reset the bot's combat AI node COMBAT_MOVEMENT_STATE = NULL; return true; } return false; }
/* ================ idBotAI::Vehicle_Air_To_Ground_Movement Ground Specific attack case. Special case: Air vehicles can't attack one way, while move in another. So they need to have their attack/move unified. This is a bit of a hack, but theres no time to do anything else. :-( ================ */ bool idBotAI::Vehicle_Air_To_Ground_Movement() { bool overRideLook = false; bool inVehicle = false; float desiredRange = 5800.0f; float tooCloseRange = 2700.0f; float enemySpeed = 0.0f; float dist; proxyInfo_t enemyVehicleInfo; idVec3 enemyOrg; idVec3 vec; if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { GetVehicleInfo( botWorld->clientInfo[ enemy ].proxyInfo.entNum, enemyVehicleInfo ); enemyOrg = enemyVehicleInfo.origin; inVehicle = true; } else { enemyOrg = botWorld->clientInfo[ enemy ].origin; } enemySpeed = botWorld->clientInfo[ enemy ].xySpeed; vec = enemyOrg - botVehicleInfo->origin; vec[ 2 ] = 0.0f; dist = vec.LengthSqr(); Bot_CheckVehicleAttack(); //mal: always see if we can get a shot off. if ( botInfo->enemyHasLockon && dist < Square( 6000.0f ) && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { //mal: OH NOES! Panic and run for it. Bot_IgnoreEnemy( enemy, 3000 ); Bot_ResetEnemy(); return false; } //mal: we're too close, so manuever around our enemy and fire. if ( dist < Square( tooCloseRange ) && combatMoveTime < botWorld->gameLocalInfo.time && enemySpeed < SPRINTING_SPEED ) { //mal: if they're moving fast, just let them move into our crosshairs.. int actionNumber = ACTION_NULL; if ( botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { actionNumber = Bot_FindNearbySafeActionToMoveToward( botInfo->origin, ( desiredRange ) ); } if ( actionNumber != -1 ) { combatMoveActionGoal = actionNumber; combatMoveTime = botWorld->gameLocalInfo.time + 10000; combatMoveTooCloseRange = ( inVehicle ) ? 5000.0f : tooCloseRange + 1000.0f; } else { int n = botThreadData.random.RandomInt( 3 ); if ( n == 0 ) { combatMoveDir = BACK; } else if ( n == 1 ) { combatMoveDir = RIGHT; } else { combatMoveDir = LEFT; } combatMoveTime = botWorld->gameLocalInfo.time + 5000; combatMoveTooCloseRange = tooCloseRange; } } if ( combatMoveTime > botWorld->gameLocalInfo.time ) { if ( dist > Square( combatMoveTooCloseRange ) ) { //mal: we're far enough away to get a shot - attack. combatMoveTime = 0; combatMoveActionGoal = ACTION_NULL; overRideLook = true; } } if ( combatMoveTime > botWorld->gameLocalInfo.time ) { if ( combatMoveActionGoal != ACTION_NULL ) { Bot_SetupVehicleMove( vec3_zero, -1, combatMoveActionGoal ); } else { vec = enemyOrg; if ( combatMoveDir == BACK ) { vec += ( -tooCloseRange * botWorld->clientInfo[ enemy ].viewAxis[ 0 ] ); } else if ( combatMoveDir == RIGHT ) { vec += ( tooCloseRange * ( botWorld->clientInfo[ enemy ].viewAxis[ 1 ] * -1 ) ); } else if ( combatMoveDir == LEFT ) { vec += ( -tooCloseRange * ( botWorld->clientInfo[ enemy ].viewAxis[ 1 ] * -1 ) ); } vec.z = botVehicleInfo->origin.z; if ( !botThreadData.Nav_IsDirectPath( AAS_VEHICLE, botInfo->team, botInfo->areaNumVehicle, botInfo->aasVehicleOrigin, vec ) ) { combatMoveTime = 0; return true; } Bot_SetupVehicleMove( vec, -1, ACTION_NULL ); } if ( MoveIsInvalid() ) { combatMoveTime = 0; combatMoveActionGoal = ACTION_NULL; return true; } Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, NULLMOVETYPE ); Bot_LookAtLocation( botAAS.path.viewGoal, SMOOTH_TURN ); return true; } if ( dist > Square( desiredRange ) ) { Bot_SetupVehicleMove( vec3_zero, enemy, ACTION_NULL ); if ( MoveIsInvalid() ) { Bot_IgnoreEnemy( enemy, ENEMY_IGNORE_TIME ); //mal: no valid path to this client for some reason - ignore him for a while Bot_ResetEnemy(); return false; } Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, NULLMOVETYPE ); if ( InFrontOfVehicle( botVehicleInfo->entNum, enemyOrg ) || overRideLook ) { Bot_LookAtEntity( enemy, SMOOTH_TURN ); } else { Bot_LookAtLocation( botAAS.path.viewGoal, SMOOTH_TURN ); } } else { Bot_SetupVehicleMove( vec3_zero, enemy, ACTION_NULL ); //mal: still want to take into account obstacles, so do a move check. if ( MoveIsInvalid() ) { Bot_IgnoreEnemy( enemy, ENEMY_IGNORE_TIME ); //mal: no valid path to this client for some reason - ignore him for a while Bot_ResetEnemy(); return false; } botMoveTypes_t defaultMoveType = AIR_BRAKE; if ( botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY && Bot_VehicleIsUnderAVTAttack() != -1 || Bot_CheckIfEnemyHasUsInTheirSightsWhenInAirVehicle() || Bot_CheckEnemyHasLockOn( -1, true ) || combatKeepMovingTime > botWorld->gameLocalInfo.time ) { //mal: do a bombing run if someone is shooting at us! defaultMoveType = NULLMOVETYPE; if ( combatKeepMovingTime < botWorld->gameLocalInfo.time ) { combatKeepMovingTime = botWorld->gameLocalInfo.time + FLYER_AVOID_DANGER_TIME; } } Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, ( botAAS.obstacleNum == -1 ) ? defaultMoveType : NULLMOVETYPE ); Bot_LookAtEntity( enemy, SMOOTH_TURN ); } return true; }