Ejemplo n.º 1
0
/*
================
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;
}
Ejemplo n.º 2
0
/*
================
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;
}
Ejemplo n.º 3
0
/*
================
idBotAI::COMBAT_Vehicle_AttackEnemy
================
*/
bool idBotAI::COMBAT_Vehicle_AttackEnemy() {

    bool keepEnemy = true;

    if ( !enemyInfo.enemyVisible && enemyInfo.enemyLastVisTime + 5000 < botWorld->gameLocalInfo.time ) {
        if ( !Bot_ShouldVehicleChaseHiddenEnemy() ) {
            Bot_ResetEnemy();
            return false;
        }

        Bot_PickVehicleChaseType();
        return false;
    }

    Bot_PickBestVehicleWeapon();

    if ( vehicleUpdateTime < botWorld->gameLocalInfo.time ) {
        if ( VEHICLE_COMBAT_MOVEMENT_STATE == NULL ) {
            keepEnemy = Bot_FindBestVehicleCombatMovement();
        }
    }

    if ( !keepEnemy ) { //mal: make sure enemy is reachable by our current move state/abilities/limitations. If not, we have to forget them.
        Bot_IgnoreEnemy( enemy, 3000 ); //mal: perhaps in 3 seconds, we will have moved to a better position for a kill...
        Bot_ResetEnemy();
        return false;
    }

    if ( VEHICLE_COMBAT_MOVEMENT_STATE != NULL ) {
        CallFuncPtr( VEHICLE_COMBAT_MOVEMENT_STATE );
    }

    if ( ClientIsValid( enemy, enemySpawnID ) && enemyInfo.enemyVisible ) {
        if ( botVehicleInfo->type <= ICARUS || botInfo->proxyInfo.weapon == MINIGUN ) {
            Bot_LookAtEntity( enemy, AIM_TURN ); //mal: aim at the enemy - but let the game side code handle it.
            Bot_CheckVehicleAttack();
        }
    }

    return false;
}
Ejemplo n.º 4
0
/*
================
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;
}
Ejemplo n.º 5
0
/*
================
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;
}
Ejemplo n.º 6
0
/*
================
idBotAI::Bot_FindBestVehicleCombatMovement

Finds the best combat movement for the bot while in a vehicle.
================
*/
bool idBotAI::Bot_FindBestVehicleCombatMovement() {
	bool vehicleCanRamClient; //mal: sounds a bit... dirty, doesn't it?
	bool vehicleGunnerSeatOpen;
	bool hasAttackedCriticalMate = false;
	bool enemyReachable = false;
	bool enemyHasVehicle = false;
	proxyInfo_t enemyVehicleInfo;

	const clientInfo_t& enemyPlayerInfo = botWorld->clientInfo[ enemy ];

	if ( enemyPlayerInfo.proxyInfo.entNum != CLIENT_HAS_NO_VEHICLE ) {
		GetVehicleInfo( enemyPlayerInfo.proxyInfo.entNum, enemyVehicleInfo );
		enemyHasVehicle = true;
	}

	combatMoveFailedCount = 0;
	combatMoveTime = -1;

	if ( botInfo->proxyInfo.weapon == NULL_VEHICLE_WEAPON && botVehicleInfo->driverEntNum != botNum ) {
		return false;
	} //mal: this shouldn't really ever happen, but may if the bot is moving between positions in a vehicle. Or if a human entered/exited a vehicle at just the right/wrong time.

	if ( ( botInfo->proxyInfo.weapon == MINIGUN || botInfo->proxyInfo.weapon == LAW || botInfo->proxyInfo.weapon == PERSONAL_WEAPON ) && botVehicleInfo->driverEntNum != botNum ) {
		VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_NULL_Movement; //mal: just sit there, and shoot the enemy.
		return true;
	}

	if ( botVehicleInfo->type > ICARUS ) {
		VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Air_Movement;
		return true;
	}

	//mal: this more often then not causes issues
/*
	if ( enemyHasVehicle ) {
		if ( enemyVehicleInfo.type == HOG && enemyInfo.enemyDist < 3000.0f && botVehicleInfo->driverEntNum == botNum ) { //mal: never stand around if a hog has us in his sights.
			VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Random_Movement;
			return true;
		}
	}
*/

	vehicleGunnerSeatOpen = VehicleHasGunnerSeatOpen( botInfo->proxyInfo.entNum );

	if ( enemyPlayerInfo.lastAttackClient > - 1 && enemyPlayerInfo.lastAttackClient < MAX_CLIENTS ) {
		if ( botWorld->clientInfo[ enemyPlayerInfo.lastAttackClient ].team == botInfo->team && enemyPlayerInfo.lastAttackClientTime + 3000 > botWorld->gameLocalInfo.time ) {
			if ( Client_IsCriticalForCurrentObj( enemyPlayerInfo.lastAttackClient, 2000.0f ) || ClientHasObj( enemyPlayerInfo.lastAttackClient ) ) {
				hasAttackedCriticalMate = true;
			}
		}
	}

	Bot_SetupVehicleMove( vec3_zero, enemy, ACTION_NULL );

    if ( botAAS.hasPath && botAAS.path.travelTime < Bot_ApproxTravelTimeToLocation( botInfo->origin, enemyPlayerInfo.origin, true ) * TRAVEL_TIME_MULTIPLY ) {
		enemyReachable = true;
	}

	if ( botInfo->proxyInfo.weapon == NULL_VEHICLE_WEAPON && botVehicleInfo->driverEntNum == botNum ) {

		vehicleCanRamClient = Bot_VehicleCanRamClient( enemy );

		if ( botVehicleInfo->type == HOG ) {
			if ( vehicleCanRamClient && InFrontOfVehicle( botVehicleInfo->entNum, enemyPlayerInfo.origin, true ) ) {
				VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Ram_Attack_Movement; //mal: ram them! Thats our only weapon.
				return true;
			}

			if ( enemyReachable && enemyHasVehicle ) {
				if ( enemyVehicleInfo.type != HUSKY ) {
					VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Chase_Movement; //mal: move in for a closer kill, THEN ram them.
					return true;
				}
			}
		}

		if ( botVehicleInfo->type == BADGER && enemyInfo.enemyDist < 1500.0f && vehicleCanRamClient && enemyPlayerInfo.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE && botVehicleInfo->driverEntNum == botNum ) {
			VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Ram_Attack_Movement; //mal: 10 points! Fun for the whole family.
			return true;
		}

		if ( !vehicleGunnerSeatOpen ) {
			if ( enemyInfo.enemyDist < 2500.0f ) {
				VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Stand_Ground_Movement; //mal: just sit there, let our gunner get a chance to kill the enemy.
			} else {
				if ( enemyReachable || enemyInfo.enemyDist > 1500.0f ) {
                    VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Chase_Movement; //mal: move in for a closer kill.
				} else {
					VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Stand_Ground_Movement; //mal: just sit there, let our gunner get a chance to kill the enemy.
				}
			}

			return true;
		} else {
			if ( enemyPlayerInfo.proxyInfo.entNum == CLIENT_HAS_NO_VEHICLE ) {
				if ( enemyInfo.enemyDist < 6000.0f && ( vehicleCanRamClient || hasAttackedCriticalMate ) ) { //mal: if an important mate is under attack, we'll fight to the end, even if its just to draw the enemies fire.
					VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Ram_Attack_Movement; //mal: ram them! Thats our only weapon.
					return true;
				}
			} else {
				Bot_IgnoreEnemy( enemy, 15000 );
				return false;
			} //mal: if all else fails, we have no choice but to ignore this enemy.
		}
	}

	if ( ( botInfo->proxyInfo.weapon == MINIGUN || botInfo->proxyInfo.weapon == LAW || botInfo->proxyInfo.weapon == PERSONAL_WEAPON ) && botVehicleInfo->driverEntNum != botNum ) {
		VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_NULL_Movement; //mal: just sit there, and shoot the enemy.
		return true;
	}

	if ( ( botInfo->proxyInfo.weapon == MINIGUN || botInfo->proxyInfo.weapon == LAW || botInfo->proxyInfo.weapon == PERSONAL_WEAPON ) && botVehicleInfo->driverEntNum == botNum ) {

		if ( botThreadData.random.RandomInt( 100 ) > 50 && enemyInfo.enemyDist < 1500.0f ) {
   			VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Stand_Ground_Movement; 
		} else {
			VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Chase_Movement; //mal: move around a bit to make ourselves harder to hit.
		}
		return true;
	}

	if ( botVehicleInfo->type == GOLIATH && botVehicleInfo->driverEntNum == botNum ) {
		VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Stand_Ground_Movement;
		return true;
	}

	if ( botInfo->proxyInfo.weapon == TANK_GUN && botVehicleInfo->driverEntNum == botNum ) {
		if ( !enemyReachable && enemyInfo.enemyDist < 3000.0f ) { //mal: dont do chase movement of our enemy, if we cant reach him.
           VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Stand_Ground_Movement; 
		} else {
			if ( enemyAcquireTime + 10000 < botWorld->gameLocalInfo.time && botInfo->lastAttackClientTime + 10000 < botWorld->gameLocalInfo.time ) {
				proxyInfo_t enemyVehicleInfo;
				GetVehicleInfo( enemyPlayerInfo.proxyInfo.entNum, enemyVehicleInfo );

				if ( enemyVehicleInfo.entNum != 0 && enemyVehicleInfo.type >= ICARUS ) { //mal: dont chase air vehicles around - this looks retarded.
					VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Stand_Ground_Movement;
				} else {
					VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Chase_Movement; //mal: haven't had much success hitting our enemy - so chase him for a better shot.
				}
			} else {
//				if ( botThreadData.random.RandomInt( 100 ) > 40 ) {
					VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Stand_Ground_Movement;
//				} else {
//					VEHICLE_COMBAT_MOVEMENT_STATE = &idBotAI::Enter_Vehicle_Chase_Movement;  //mal: move around a bit to make ourselves harder to hit.
//				}
			}
		}

		return true;
	}


	//mal_TODO: add support for air vehicles too......

	botThreadData.Warning( "Can't find a move that suits bot %i and his vehicle!", botNum );

	return false;
}