/* ================ idBotAI::Buffalo_Air_To_Ground_Movement Ground Specific attack case for the buffalo ================ */ bool idBotAI::Buffalo_Air_To_Ground_Movement() { float desiredRange = 4500.0f; const clientInfo_t& enemyPlayerInfo = botWorld->clientInfo[ enemy ]; idVec3 distToTarget = enemyPlayerInfo.origin - botVehicleInfo->origin; distToTarget.z = 0.0f; if ( distToTarget.LengthSqr() > 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; } combatMoveTime = botWorld->gameLocalInfo.time + 500; Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, NULLMOVETYPE ); Bot_LookAtLocation( botAAS.path.viewGoal, SMOOTH_TURN ); return true; } if ( InFrontOfVehicle( botVehicleInfo->entNum, enemyPlayerInfo.origin ) && combatMoveTime < botWorld->gameLocalInfo.time ) { if ( botVehicleInfo->xyspeed < 100.0f ) { Bot_LookAtEntity( enemy, SMOOTH_TURN ); botUcmd->botCmds.topHat = true; } Bot_CheckVehicleAttack(); //mal: always see if we can get a shot off. } Bot_MoveToGoal( vec3_zero, vec3_zero, NULLMOVEFLAG, FULL_STOP ); return true; }
/* ================ idBotAI::Vehicle_Chase_Movement ================ */ bool idBotAI::Vehicle_Chase_Movement() { if ( enemyInfo.enemyDist > 900.0f ) { 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 ( botVehicleInfo->type == HOG && Bot_VehicleCanRamClient( enemy ) ) { VEHICLE_COMBAT_MOVEMENT_STATE = NULL; return true; } if ( enemyInfo.enemyDist < 700.0f ) { VEHICLE_COMBAT_MOVEMENT_STATE = NULL; } return true; }
/* ================ idBotAI::Vehicle_Ram_Attack_Movement ================ */ bool idBotAI::Vehicle_Ram_Attack_Movement() { proxyInfo_t enemyVehicleInfo; idBox enemyBox; if ( enemyInfo.enemyDist < 700.0f && botVehicleInfo->forwardSpeed < 100.0f && botVehicleInfo->type != HOG ) { //mal: somethings holding us up, we can't ram at this speed/dist! VEHICLE_COMBAT_MOVEMENT_STATE = NULL; return false; } if ( !Bot_VehicleCanRamClient( enemy ) ) { VEHICLE_COMBAT_MOVEMENT_STATE = NULL; return false; } if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { GetVehicleInfo( botWorld->clientInfo[ enemy ].proxyInfo.entNum, enemyVehicleInfo ); enemyBox = idBox( enemyVehicleInfo.bbox, enemyVehicleInfo.origin, enemyVehicleInfo.axis ); } else { enemyBox = idBox( botWorld->clientInfo[ enemy ].localBounds, botWorld->clientInfo[ enemy ].origin, botWorld->clientInfo[ enemy ].bodyAxis ); } if ( !InFrontOfVehicle( botVehicleInfo->entNum, enemyBox.GetCenter(), false ) ) { VEHICLE_COMBAT_MOVEMENT_STATE = NULL; return false; } Bot_MoveToGoal( enemyBox.GetCenter(), vec3_zero, SPRINT_ATTACK, NULLMOVETYPE ); //mal: Prepare for ramming speed! Ram them until they're dead, or we are.... Bot_LookAtLocation( enemyBox.GetCenter(), SMOOTH_TURN ); return true; }
/* ================ idBotAI::COMBAT_Vehicle_ChaseEnemy ================ */ bool idBotAI::COMBAT_Vehicle_ChaseEnemy() { if ( enemyInfo.enemyVisible ) { VEHICLE_COMBAT_AI_SUB_NODE = &idBotAI::Enter_COMBAT_Vehicle_AttackEnemy; return false; } if ( chaseEnemyTime < botWorld->gameLocalInfo.time ) { Bot_ResetEnemy(); return false; } Bot_SetupVehicleMove( vec3_zero, enemy, ACTION_NULL ); if ( MoveIsInvalid() ) { Bot_ResetEnemy(); return false; } Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, NULLMOVETYPE ); Bot_LookAtEntity( enemy, SMOOTH_TURN ); return true; }
/* =============== idBotAI::BotAI_CheckThinkState Should the bot think this frame? =============== */ bool idBotAI::BotAI_CheckThinkState() { if ( botWorld->gameLocalInfo.botsPaused ) { return false; } if ( botWorld->gameLocalInfo.botsSleep ) { return false; } if ( botInfo->team == NOTEAM || botInfo->classType == NOCLASS ) { if ( botThreadData.AllowDebugData() ) { // assert( false ); } return false; } if ( botThreadData.AllowDebugData() ) { if ( bot_skipThinkClient.GetInteger() == botNum ) { botUcmd->botCmds.godMode = true; return false; } if ( bot_godMode.GetInteger() == botNum ) { botUcmd->botCmds.godMode = true; } } if ( botInfo->isTeleporting ) { return false; } if ( botAAS.aas == NULL ) { if ( botThreadData.random.RandomInt( 100 ) > 98 ) { botUcmd->botCmds.hasNoGoals = true; //mal: pass a warning to the player to let them know we have no goals } return false; } if ( !botInfo->hasGroundContact && botInfo->invulnerableEndTime > botWorld->gameLocalInfo.time ) { return false; } //mal: dont start thinking until we've actually touched the ground after spawning in. if ( botInfo->justSpawned ) { UpdateBotsInformation( botInfo->classType, botInfo->team, false ); return false; //mal: dont think til we have some team/class stuff to think about! } if ( botWorld->gameLocalInfo.debugBotWeapons ) { botUcmd->botCmds.lookDown = true; botUcmd->idealWeaponSlot = GUN; botUcmd->botCmds.attack = true; if ( !botInfo->weapInfo.primaryWeapHasAmmo && !botInfo->weapInfo.sideArmHasAmmo && !botInfo->justSpawned ) { botUcmd->botCmds.suicide = true; } Bot_MoveToGoal( botInfo->origin + idVec3( 5.0f, 5.0f, 0.0f ), vec3_zero, RUN, ( botThreadData.random.RandomInt( 100 ) > 80 ) ? RANDOM_JUMP : NULLMOVETYPE ); return false; } if ( botInfo->resetState > 0 ) { ResetBotsAI( ( botInfo->resetState == MINOR_RESET_EVENT ) ? false : true ); return false; } return true; }
/* ================ idBotAI::CheckBotStuckState ================ */ void idBotAI::CheckBotStuckState() { if ( !botInfo->hasGroundContact && botInfo->invulnerableEndTime > botWorld->gameLocalInfo.time ) { framesStuck = 0; framesFlipped = 0; vehicleFramesStuck = 0; overallFramesStuck = 0; return; //mal: if we're spawning in, dont count a lack of a valid AAS area against us } if ( stuckRandomMoveTime > botWorld->gameLocalInfo.time ) { BotAI_ResetUcmd(); Bot_MoveToGoal( vec3_zero, vec3_zero, SPRINT, RANDOM_DIR_JUMP ); return; } if ( !botAAS.triedToMoveThisFrame ) { botAAS.blockedByObstacleCounterOnFoot = 0; } if ( botInfo->areaNum == 0 ) { noAASCounter++; if ( noAASCounter >= 100 ) { if ( botVehicleInfo == NULL ) { botUcmd->botCmds.suicide = true; noAASCounter = 0; } else { Bot_ExitVehicle(); } } return; } else { noAASCounter = 0; } if ( moveErrorCounter.moveErrorTime < botWorld->gameLocalInfo.time ) { moveErrorCounter.moveErrorTime = botWorld->gameLocalInfo.time + 5000; if ( moveErrorCounter.moveErrorCount >= MAX_MOVE_ERRORS ) { moveErrorCounter.moveErrorCount = 0; botUcmd->botCmds.suicide = true; } else { moveErrorCounter.moveErrorCount = 0; } } if ( botVehicleInfo == NULL ) { idVec3 vec = botInfo->origin - botInfo->oldOrigin; if ( vec.LengthSqr() < Square( 10.0f ) && botInfo->isTryingToMove ) { framesStuck++; // if ( framesStuck > MAX_FRAMES_BLOCKED_BY_OBSTACLE_ON_FOOT ) { // botAAS.blockedByObstacleCounterOnFoot = MAX_FRAMES_BLOCKED_BY_OBSTACLE_ON_FOOT + 1; // framesStuck = 0; // stuckRandomMoveTime = botWorld->gameLocalInfo.time + 500; // overallFramesStuck++; // } if ( framesStuck >= 300 ) { stuckRandomMoveTime = botWorld->gameLocalInfo.time + 500; framesStuck = 0; overallFramesStuck++; } if ( overallFramesStuck > 6 && botWorld->gameLocalInfo.botsCanSuicide ) { botUcmd->botCmds.suicide = true; } return; } } framesStuck = 0; overallFramesStuck = 0; if ( botVehicleInfo != NULL ) { if ( botVehicleInfo->isFlipped ) { framesFlipped++; if ( framesFlipped >= 100 ) { //mal: give us time to recover, just in case we can. Bot_ExitVehicle( false); } return; } if ( botVehicleInfo->isCareening && botVehicleInfo->isAirborneVehicle ) { //mal: out NOW! This thing is lost! Bot_ExitVehicle(); } if ( botVehicleInfo->inWater && !( botVehicleInfo->flags & WATER ) ) { Bot_ExitVehicle( false ); } } framesFlipped = 0; /* if ( botVehicleInfo != NULL ) { //mal: this sucks. idVec3 vec = botInfo->origin - botInfo->oldOrigin; vec.z = 0.0f; if ( vec.LengthSqr() < Square( 10.0f ) && botInfo->isTryingToMove ) { vehicleFramesStuck++; if ( vehicleFramesStuck >= 300 ) { vehicleReverseTime = botWorld->gameLocalInfo.time + 900; botUcmd->specialMoveType = REVERSEMOVE; vehicleFramesStuck = 0; } } else { vehicleFramesStuck = 0; } } */ }
/* ================ idBotAI::ResetUcmd Clears out the Bot's user cmd structure at the start of every frame, so that we can build a fresh one each bot think. ================ */ void idBotAI::BotAI_ResetUcmd () { Bot_MoveToGoal( vec3_zero, vec3_zero, NULLMOVEFLAG, NULLMOVETYPE ); //mal: clear out the move state at first! // botUcmd->viewType = VIEW_ORIGIN; botUcmd->turnType = SMOOTH_TURN; botUcmd->viewEntityNum = -1; botUcmd->actionEntityNum = -1; botUcmd->actionEntitySpawnID = -1; botUcmd->botCmds.ackJustSpawned = false; botUcmd->botCmds.ackReset = false; botUcmd->botCmds.activate = false; botUcmd->botCmds.ackSeatChange = false; botUcmd->botCmds.activateHeld = false; botUcmd->botCmds.altAttackOff = false; botUcmd->botCmds.honkHorn = false; botUcmd->botCmds.isBlocked = false; botUcmd->botCmds.launchDecoys = false; botUcmd->botCmds.launchDecoysNow = false; botUcmd->botCmds.altAttackOn = false; botUcmd->botCmds.godMode = false; botUcmd->botCmds.attack = false; botUcmd->botCmds.reload = false; botUcmd->botCmds.enterVehicle = false; botUcmd->botCmds.exitVehicle = false; botUcmd->botCmds.zoom = false; botUcmd->botCmds.lookDown = false; botUcmd->botCmds.lookUp = false; botUcmd->botCmds.constantFire = false; botUcmd->botCmds.throwNade = false; botUcmd->botCmds.hasNoGoals = false; botUcmd->botCmds.switchVehicleWeap = false; botUcmd->botCmds.dropDisguise = false; botUcmd->botCmds.shoveClient = false; botUcmd->botCmds.droppingSupplyCrate = false; botUcmd->botCmds.destroySupplyCrate = false; botUcmd->botCmds.hasMedicInFOV = false; botUcmd->botCmds.becomeDriver = false; botUcmd->botCmds.becomeGunner = false; botUcmd->botCmds.enterSiegeMode = false; botUcmd->botCmds.exitSiegeMode = false; botUcmd->desiredChat = NULL_CHAT; botUcmd->desiredChatForced = false; botUcmd->botCmds.useTankAim = false; botUcmd->botCmds.altFire = false; botUcmd->deployInfo.deployableType = NULL_DEPLOYABLE; botUcmd->deployInfo.location.Zero(); botUcmd->deployInfo.actionNumber = ACTION_NULL; botUcmd->ackKillForClient = -1; botUcmd->ackRepairForClient = -1; isStrafeJumping = false; ignoreWeapChange = false; botAAS.triedToMoveThisFrame = false; weaponLocked = false; botUcmd->botCmds.launchPacks = false; botUcmd->botCmds.switchAwayFromSniperRifle = false; botUcmd->botCmds.topHat = false; botUcmd->tkReviveTime = 0; botUcmd->decayObstacleSpawnID = -1; botUcmd->botCmds.actorBriefedPlayer = false; botUcmd->botCmds.actorSurrenderStatus = false; botUcmd->botCmds.actorIsBriefingPlayer = false; botUcmd->botCmds.actorHasEnteredActorNode = false; botUcmd->specialMoveType = NULLMOVETYPE; }
/* ================ idBotAI::COMBAT_Vehicle_EvadeEnemy ================ */ bool idBotAI::COMBAT_Vehicle_EvadeEnemy() { bool bailOut = false; idVec3 vec; if ( !ClientIsValid( enemy, -1 ) ) { Bot_ResetEnemy(); return false; } if ( botVehicleInfo->type == MCP ) { assert( actionNum > -1 ); if ( Bot_CheckActionIsValid( actionNum ) ) { vec = botThreadData.botActions[ actionNum ]->GetActionOrigin() - botVehicleInfo->origin; if ( vec.LengthSqr() > Square( MCP_PARKED_DIST ) ) { Bot_SetupVehicleMove( vec3_zero, -1, actionNum ); if ( MoveIsInvalid() ) { //mal: this should NEVER happen - but if it does, the bot is better off leaving. Bot_ExitVehicleAINode( true ); Bot_ExitVehicle( false ); assert( false ); return false; } Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, NULLMOVETYPE ); } else { Bot_ExitVehicleAINode( true ); //mal: reached our goal, so just leave, and let the MCP deploy! Bot_ExitVehicle( false ); return false; } } } else { if ( AIStack.stackActionNum != ACTION_NULL ) { float evadeDist = 1200.0f; vec = botThreadData.botActions[ AIStack.stackActionNum ]->origin - botInfo->origin; if ( botVehicleInfo->type > ICARUS ) { evadeDist = 550.0f; bailOut = true; vec.z = 0.0f; } if ( vec.LengthSqr() > Square( evadeDist ) ) { Bot_SetupVehicleMove( vec3_zero, -1, AIStack.stackActionNum ); bailOut = false; if ( MoveIsInvalid() ) { VEHICLE_COMBAT_AI_SUB_NODE = &idBotAI::Enter_COMBAT_Vehicle_AttackEnemy; //mal: if theres a problem getting to our target, just fight our enemy normally. return false; } Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, NULLMOVETYPE ); } if ( vec.LengthSqr() < Square( 800.0f ) && botVehicleInfo->type != MCP ) { //mal: get to the outpost if MCP, even to the bitter end! VEHICLE_COMBAT_AI_SUB_NODE = &idBotAI::Enter_COMBAT_Vehicle_AttackEnemy; //mal: we're right at our target, so just fight our enemy normally. return false; } } else { // assert( false ); VEHICLE_COMBAT_AI_SUB_NODE = &idBotAI::Enter_COMBAT_Vehicle_AttackEnemy; return false; } } if ( bailOut ) { Bot_ExitVehicle(); return false; } Bot_PickBestVehicleWeapon(); if ( !enemyInfo.enemyVisible && enemyInfo.enemyLastVisTime + 500 < botWorld->gameLocalInfo.time ) { UpdateNonVisEnemyInfo(); if ( BotLeftEnemysSight() ) { vec = bot_LS_Enemy_Pos; } else { vec = enemyInfo.enemy_LS_Pos; } Bot_LookAtLocation( vec, AIM_TURN ); } else { if ( botVehicleInfo->type > ICARUS ) { vec = botWorld->clientInfo[ enemy ].origin - botVehicleInfo->origin; vec[ 2 ] = 0.0f; if ( vec.LengthSqr() > Square( 2500.0f ) && InFrontOfVehicle( botVehicleInfo->entNum, botWorld->clientInfo[ enemy ].origin ) && botVehicleInfo->type != BUFFALO ) { Bot_LookAtEntity( enemy, AIM_TURN ); Bot_CheckVehicleAttack(); } else { Bot_LookAtLocation( botAAS.path.viewGoal, SMOOTH_TURN ); if ( botVehicleInfo->type != BUFFALO ) { Bot_CheckVehicleAttack(); } } } else { Bot_LookAtEntity( enemy, AIM_TURN ); Bot_CheckVehicleAttack(); } } return true; }
/* ================ 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; }
/* ================ idBotAI::Vehicle_Air_To_Air_Movement Air to Air 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_Air_Movement() { bool overRideLook = false; bool enemyInFront; bool botInFrontOfEnemy; float desiredRange; float tooCloseDist; float dist; proxyInfo_t enemyVehicleInfo; idVec3 enemyOrg; idVec3 vec; if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE ) { Bot_ResetEnemy(); return false; } GetVehicleInfo( botWorld->clientInfo[ enemy ].proxyInfo.entNum, enemyVehicleInfo ); enemyOrg = enemyVehicleInfo.origin; vec = enemyOrg - botVehicleInfo->origin; vec.z = 0.0f; dist = vec.LengthSqr(); float tempDist = vec.LengthFast(); 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!1 Panic and run for it. Bot_IgnoreEnemy( enemy, 3000 ); Bot_ResetEnemy(); return false; } if ( botVehicleInfo->type == ANANSI ) { desiredRange = 5000.0f; tooCloseDist = 2500.0f; if ( Bot_CheckEnemyHasLockOn( enemy ) && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY && botWorld->gameLocalInfo.botSkill != BOT_SKILL_DEMO ) { //mal: they need a bit of an edge botUcmd->botCmds.launchDecoysNow = true; } if ( dist < Square( tooCloseDist ) && combatMoveTime < botWorld->gameLocalInfo.time && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { combatMoveDir = BACK; combatMoveTime = botWorld->gameLocalInfo.time + 5000; botUcmd->botCmds.launchDecoys = true; //mal: we're exposing our flank, so fire some decoys to cover our move. } if ( combatMoveTime > botWorld->gameLocalInfo.time ) { if ( !InAirVehicleGunSights( enemyVehicleInfo.entNum, botInfo->origin ) ) { //mal: he can't see us anymore, so attack! combatMoveTime = 0; overRideLook = true; } } if ( combatMoveTime > 0 ) { vec = enemyOrg; vec += ( -desiredRange * enemyVehicleInfo.axis[ 0 ] ); 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; return true; } Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, NULLMOVETYPE ); Bot_LookAtLocation( botAAS.path.viewGoal, SMOOTH_TURN ); return true; } } else { //must be in a hornet desiredRange = 2500.0f; //mal: was 1500 tooCloseDist = 0.0f; if ( dist < Square( desiredRange ) && combatMoveTime < botWorld->gameLocalInfo.time && botWorld->gameLocalInfo.botSkill > BOT_SKILL_EASY ) { int n = botThreadData.random.RandomInt( 3 ); //mal: we're too close, so manuever around our enemy and fire. low skill bots need not apply. if ( n == 0 ) { combatMoveDir = BACK; } else if ( n == 1 ) { combatMoveDir = RIGHT; } else { combatMoveDir = LEFT; } combatMoveTime = botWorld->gameLocalInfo.time + 5000; botUcmd->botCmds.launchDecoys = true; //mal: we're exposing our flank, so fire some decoys to cover our move. } if ( combatMoveTime > botWorld->gameLocalInfo.time ) { if ( !InAirVehicleGunSights( enemyVehicleInfo.entNum, botInfo->origin ) ) { //mal: he can't see us anymore, so attack! combatMoveTime = 0; overRideLook = true; } } if ( combatMoveTime > 0 ) { vec = enemyOrg; if ( combatMoveDir == BACK ) { vec += ( -desiredRange * botInfo->viewAxis[ 0 ] ); //mal: this seems wrong, but it works SO well. } else if ( combatMoveDir == RIGHT ) { vec += ( desiredRange * ( botInfo->viewAxis[ 1 ] * -1 ) ); } else if ( combatMoveDir == LEFT ) { vec += ( -desiredRange * ( botInfo->viewAxis[ 1 ] * -1 ) ); } 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; return true; } Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, NULLMOVETYPE ); Bot_LookAtLocation( botAAS.path.viewGoal, SMOOTH_TURN ); return true; } } enemyInFront = InFrontOfVehicle( botVehicleInfo->entNum, enemyOrg ); botInFrontOfEnemy = InFrontOfVehicle( enemyVehicleInfo.entNum, botInfo->origin ); 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; } //mal: if we're just moving into range of the target, we'll try to get a lock. If not ( or in danger ) we'll gun it. Fighter pilot mantra: speed is life. Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, ( botInFrontOfEnemy && enemyInFront && dist > Square( 6000.0f ) && botVehicleInfo->forwardSpeed > 1500.0f && !botInfo->enemyHasLockon ) ? AIR_COAST : NULLMOVETYPE ); if ( enemyInFront || 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; } Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, ( botAAS.obstacleNum == -1 ) ? AIR_BRAKE : NULLMOVETYPE ); Bot_LookAtEntity( enemy, SMOOTH_TURN ); } return true; }
/* ================ idBotAI::Vehicle_Random_Movement ================ */ bool idBotAI::Vehicle_Random_Movement() { float tooCloseDist = 750.0f; idVec3 vec; if ( combatMoveFailedCount >= 10 ) { VEHICLE_COMBAT_MOVEMENT_STATE = NULL; //mal: this just isn't working out, try something else. return false; } if ( combatDangerExists ) { Bot_SetupVehicleQuickMove( botInfo->origin, false ); //mal: just path to itself, if its in an obstacle, it will freak and avoid it. if ( MoveIsInvalid() ) { VEHICLE_COMBAT_MOVEMENT_STATE = NULL; return false; } vec = botAAS.path.moveGoal - botInfo->origin; if ( vec.LengthSqr() > Square( 25.0f ) ) { Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, SPRINT, NULLMOVETYPE ); } return true; } if ( combatMoveDir == NULL_DIR || combatMoveTime < botWorld->gameLocalInfo.time ) { if ( botThreadData.random.RandomInt( 100 ) > 50 ) { if ( botThreadData.random.RandomInt( 100 ) > 50 ) { combatMoveDir = RIGHT; } else { combatMoveDir = LEFT; } } else { if ( botThreadData.random.RandomInt( 100 ) > 50 ) { combatMoveDir = FORWARD; } else { combatMoveDir = BACK; } } if ( Bot_VehicleCanMove( combatMoveDir, 300.0f, true ) ) { combatMoveTime = botWorld->gameLocalInfo.time + 7000; } else { combatMoveFailedCount++; } return true; } if ( enemyInfo.enemyDist < tooCloseDist ) { if ( enemyInfo.enemyInfont ) { if ( Bot_VehicleCanMove( BACK, 100.0f, true )) { Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, NULLMOVETYPE ); } else { VEHICLE_COMBAT_MOVEMENT_STATE = NULL; } } else { if ( Bot_VehicleCanMove( FORWARD, 100.0f, true )) { Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, NULLMOVETYPE ); } else { VEHICLE_COMBAT_MOVEMENT_STATE = NULL; } } return true; } if ( Bot_VehicleCanMove( combatMoveDir, 300.0f, true ) ) { Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, NULLMOVETYPE ); } else { combatMoveDir = NULL_DIR; combatMoveFailedCount++; } return true; }
/* ================ idBotAI::Vehicle_Stand_Ground_Movement ================ */ bool idBotAI::Vehicle_Stand_Ground_Movement() { // int result; bool enemyHasVehicle = false; float tooCloseDist = 750.0f; proxyInfo_t enemyVehicleInfo; idVec3 vec; if ( combatMoveFailedCount >= 10 ) { VEHICLE_COMBAT_MOVEMENT_STATE = NULL; return false; } if ( botWorld->clientInfo[ enemy ].proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) { GetVehicleInfo( botWorld->clientInfo[ enemy ].proxyInfo.entNum, enemyVehicleInfo ); enemyHasVehicle = true; } if ( combatDangerExists ) { Bot_SetupVehicleQuickMove( botInfo->origin, false ); //mal: just path to itself, if its in an obstacle, it will freak and avoid it. if ( MoveIsInvalid() ) { VEHICLE_COMBAT_MOVEMENT_STATE = NULL; return false; } vec = botAAS.path.moveGoal - botInfo->origin; if ( vec.LengthSqr() > Square( 25.0f ) ) { Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, SPRINT, NULLMOVETYPE ); } return true; } if ( botVehicleInfo->type == TROJAN && botVehicleInfo->driverEntNum == botNum ) { if ( !InFrontOfVehicle( botVehicleInfo->entNum, botWorld->clientInfo[ enemy ].origin ) ) { Bot_SetupVehicleMove( vec3_zero, enemy, ACTION_NULL ); if ( MoveIsInvalid() ) { VEHICLE_COMBAT_MOVEMENT_STATE = NULL; return false; } Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, NULLMOVETYPE ); return true; } } /* if ( ( !botInfo->proxyInfo.weaponIsReady && botInfo->proxyInfo.weapon == TANK_GUN ) || combatMoveTime < botWorld->gameLocalInfo.time && !vehicleInfo.inSiegeMode ) { if ( combatMoveDir == NULL_DIR ) { result = botThreadData.random.RandomInt( 4 ); if ( result == 0 ) { combatMoveDir = FORWARD; } else if ( result == 1 ) { combatMoveDir = BACK; } else if ( result == 2 ) { combatMoveDir = RIGHT; } else { combatMoveDir = LEFT; } combatMoveTime = botWorld->gameLocalInfo.time + 2000; } if ( Bot_CanMove( combatMoveDir, 300.0f, true ) ) { Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, NULLMOVETYPE ); } else { combatMoveDir = NULL_DIR; combatMoveFailedCount++; } return true; } */ if ( enemyInfo.enemyDist < tooCloseDist ) { if ( botVehicleInfo->type == GOLIATH ) { const clientInfo_t& enemyPlayer = botWorld->clientInfo[ enemy ]; botUcmd->botCmds.exitSiegeMode = true; if ( enemyPlayer.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE ) { Bot_MoveToGoal( vec3_zero, vec3_zero, NULLMOVEFLAG, TAUNT_MOVE ); return true; } } if ( enemyInfo.enemyInfont ) { if ( Bot_VehicleCanMove( BACK, 100.0f, true )) { Bot_MoveToGoal( botCanMoveGoal, vec3_zero, REVERSE, NULLMOVETYPE ); } else if ( Bot_VehicleCanMove( RIGHT, 100.0f, true ) ) { Bot_MoveToGoal( botCanMoveGoal, vec3_zero, REVERSE, NULLMOVETYPE ); } else if ( Bot_VehicleCanMove( LEFT, 100.0f, true ) ) { Bot_MoveToGoal( botCanMoveGoal, vec3_zero, REVERSE, NULLMOVETYPE ); } else { combatMoveFailedCount++; } } else { if ( Bot_VehicleCanMove( FORWARD, 100.0f, true )) { Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, NULLMOVETYPE ); } else if ( Bot_VehicleCanMove( RIGHT, 100.0f, true ) ) { Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, NULLMOVETYPE ); } else if ( Bot_VehicleCanMove( LEFT, 100.0f, true ) ) { Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, NULLMOVETYPE ); } else { combatMoveFailedCount++; } } return true; } if ( botVehicleInfo->type == GOLIATH && !botVehicleInfo->inSiegeMode ) { idVec3 enemyOrg = botWorld->clientInfo[ enemy ].origin; trace_t trace; botThreadData.clip->TracePointExt( CLIP_DEBUG_PARMS trace, botVehicleInfo->origin, enemyOrg, BOT_VISIBILITY_TRACE_MASK, GetGameEntity( botNum ), GetGameEntity( botVehicleInfo->entNum ) ); if ( enemyInfo.enemyDist > 1200.0f && trace.fraction == 1.0f ) { botUcmd->botCmds.enterSiegeMode = true; } } else if ( botVehicleInfo->type == DESECRATOR ) { if ( enemyHasVehicle && enemyVehicleInfo.type != TITAN ) { if ( enemyInfo.enemyDist > 1500.0f ) { botUcmd->botCmds.enterSiegeMode = true; } } /* else { if ( combatMoveTime < botWorld->gameLocalInfo.time ) { //mal_NOTE: this just caused more problems then its worth. if ( combatMoveDir == NULL_DIR ) { if ( botThreadData.random.RandomInt( 100 ) > 50 ) { combatMoveDir = RIGHT; } else { combatMoveDir = LEFT; } } else { if ( combatMoveDir == RIGHT ) { combatMoveDir = LEFT; } else { combatMoveDir = RIGHT; } } combatMoveTime = botWorld->gameLocalInfo.time + 5000; } if ( combatMoveDir == RIGHT ) { Bot_MoveToGoal( vec3_zero, vec3_zero, NULLMOVEFLAG, LEAN_RIGHT ); } else { Bot_MoveToGoal( vec3_zero, vec3_zero, NULLMOVEFLAG, LEAN_LEFT ); } return true; } */ } Bot_MoveToGoal( vec3_zero, vec3_zero, NULLMOVEFLAG, FULL_STOP ); //mal: hit the brakes! return true; }