etqw-sdk/source/game/botai/BotAI_MoveNet.cpp

961 lines
23 KiB
C++

// Copyright (C) 2007 Id Software, Inc.
//
#include "../precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
#include "BotThreadData.h"
#include "BotAI_Main.h"
/*
================
idBotAI::Enter_Run_And_Gun_Movement
================
*/
bool idBotAI::Enter_Run_And_Gun_Movement() {
COMBAT_MOVEMENT_STATE = &idBotAI::Run_And_Gun_Movement;
combatMoveType = RUN_N_GUN_ATTACK;
lastMoveNode = "Run And Gun";
return true;
}
/*
================
idBotAI::Run_And_Gun_Movement
================
*/
bool idBotAI::Run_And_Gun_Movement() { //mal: like the name says, just a basic, run to the enemy and shoot him movement, occasionally jumping.
float chaseDist = ( botInfo->weapInfo.weapon == ROCKET ) ? 500.0f : 300.0f;
float tooCloseDist = ( botInfo->weapInfo.weapon == ROCKET ) ? 450.0f : 125.0f;
if ( botWorld->gameLocalInfo.botSkill != BOT_SKILL_DEMO ) {
if ( botInfo->weapInfo.isReloading ) { //mal: what should the bot do while they're reloading their gun.
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
if ( botInfo->weapInfo.weapon == SNIPERRIFLE ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
if ( botInfo->weapInfo.weapon == KNIFE ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
}
if ( enemyInfo.enemyDist > 1200.0f ) {
Bot_SetupMove( 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, ( botThreadData.random.RandomInt( 100 ) > 80 ) ? RANDOM_JUMP : NULLMOVETYPE );
} else if ( enemyInfo.enemyDist > chaseDist ) {
if ( combatMoveTime < botWorld->gameLocalInfo.time ) {
if ( botThreadData.random.RandomInt( 100 ) > 90 && botInfo->weapInfo.isReloading != true ) {
if ( Bot_CanProne( enemy ) && botWorld->gameLocalInfo.botSkill != BOT_SKILL_DEMO ) {
combatMoveFlag = PRONE;
} else {
combatMoveFlag = RUN;
}
} else {
combatMoveFlag = RUN;
}
combatMoveTime = botWorld->gameLocalInfo.time + 7000;
}
if ( combatMoveFlag == PRONE ) {
Bot_MoveToGoal( vec3_zero, vec3_zero, PRONE, NULLMOVETYPE );
} else {
Bot_SetupMove( 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, ( botThreadData.random.RandomInt( 100 ) > 80 ) ? RANDOM_JUMP : NULLMOVETYPE );
}
} else {
if ( combatMoveFlag != PRONE ) {
if ( enemyInfo.enemyDist < tooCloseDist ) {
if ( Bot_CanMove( BACK, 100.0f, true )) {
Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, NULLMOVETYPE );
} else {
COMBAT_MOVEMENT_STATE = NULL;
}
}
}
}
return true;
}
/*
================
idBotAI::Enter_Crazy_Jump_Attack_Movement
================
*/
bool idBotAI::Enter_Crazy_Jump_Attack_Movement() {
COMBAT_MOVEMENT_STATE = &idBotAI::Crazy_Jump_Attack_Movement;
combatMoveType = CRAZY_JUMP_ATTACK;
lastMoveNode = "Crazy Jump Attack";
return true;
}
/*
================
idBotAI::Crazy_Jump_Attack_Movement
================
*/
bool idBotAI::Crazy_Jump_Attack_Movement() {
float chaseDist = ( botInfo->weapInfo.weapon == ROCKET ) ? 900.0f : 500.0f;
float tooCloseDist = ( botInfo->weapInfo.weapon == ROCKET ) ? 450.0f : 300.0f;
if ( combatMoveFailedCount > 10 ) { //mal: move failed too many times, get out of here!
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
if ( botInfo->weapInfo.weapon == KNIFE ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
if ( enemyInfo.enemyDist < tooCloseDist ) {
if ( Bot_CanMove( BACK, 150.0f, true )) {
Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, RANDOM_JUMP );
} else if ( Bot_CanMove( RIGHT, 150.0f, true )) {
Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, RANDOM_JUMP );
} else if ( Bot_CanMove( LEFT, 150.0f, true )) {
Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, RANDOM_JUMP );
} else {
combatMoveFailedCount++;
}
} else {
if ( combatMoveTime < botWorld->gameLocalInfo.time ) {
if ( combatMoveTime == -1 || combatMoveTime != 1 ) {
if ( botThreadData.random.RandomInt( 100 ) > 50 ) {
combatMoveDir = RIGHT;
} else {
combatMoveDir = LEFT;
}
} else {
if ( combatMoveDir == LEFT ) {
combatMoveDir = RIGHT;
} else {
combatMoveDir = LEFT;
}
}
combatMoveTime = botWorld->gameLocalInfo.time + 1700;
}
if ( enemyInfo.enemyDist > chaseDist ) {
if ( Bot_CanMove( combatMoveDir, 150.0f, true )) {
Bot_SetupMove( 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, ( combatMoveDir == RIGHT ) ? RANDOM_JUMP_RIGHT : RANDOM_JUMP_LEFT );
}
} else {
combatMoveTime = 1; //mal: move failed, try another!
combatMoveFailedCount++;
}
}
return true;
}
/*
================
idBotAI::Enter_Knife_Attack_Movement
================
*/
bool idBotAI::Enter_Knife_Attack_Movement() {
COMBAT_MOVEMENT_STATE = &idBotAI::Knife_Attack_Movement;
combatMoveType = KNIFE_ATTACK;
lastMoveNode = "Knife Attack";
return true;
}
/*
================
idBotAI::Knife_Attack_Movement
================
*/
bool idBotAI::Knife_Attack_Movement() {
if ( botInfo->weapInfo.weapon != KNIFE && !botWorld->gameLocalInfo.inWarmup ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
if ( enemyInfo.enemyDist > 150.0f && enemyInfo.enemyFacingBot != false ) {
if ( combatMoveTime < botWorld->gameLocalInfo.time ) {
if ( combatMoveTime == -1 || combatMoveTime != 1 ) {
if ( botThreadData.random.RandomInt( 100 ) > 50 ) {
combatMoveDir = RIGHT;
} else {
combatMoveDir = LEFT;
}
} else {
if ( combatMoveDir == LEFT ) {
combatMoveDir = RIGHT;
} else {
combatMoveDir = LEFT;
}
}
combatMoveTime = botWorld->gameLocalInfo.time + 500;
}
if ( Bot_CanMove( combatMoveDir, 50.0f, true )) {
Bot_SetupMove( 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, SPRINT, ( combatMoveDir == RIGHT ) ? RANDOM_JUMP_RIGHT : RANDOM_JUMP_LEFT );
} else {
combatMoveTime = 1; //mal: mark the move as having failed, so we know to try a diff dir next frame.
combatMoveFailedCount++;
}
return true;
}
//mal: hes close, or we're behind him, so just run up and stab the bastid!
if ( enemyInfo.enemyDist > 65.0f ) {
Bot_SetupMove( 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_MoveAlongPath( SPRINT );
}
return true;
}
/*
================
idBotAI::Enter_Prone_Attack_Movement
================
*/
bool idBotAI::Enter_Prone_Attack_Movement() {
COMBAT_MOVEMENT_STATE = &idBotAI::Prone_Attack_Movement;
combatMoveType = PRONE_ATTACK;
combatMoveFailedCount = 0;
lastMoveNode = "Prone Attack";
return true;
}
/*
================
idBotAI::Prone_Attack_Movement
================
*/
bool idBotAI::Prone_Attack_Movement() {
idVec3 vec;
if ( botInfo->weapInfo.weapon != SNIPERRIFLE ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
if ( !Bot_CanProne( enemy ) ) {
combatMoveFailedCount++;
if ( combatMoveFailedCount > MAX_MOVE_FAILED_COUNT ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
} else {
combatMoveFailedCount = 0;
}
Bot_MoveToGoal( vec3_zero, vec3_zero, PRONE, NULLMOVETYPE );
if ( combatDangerExists ) {
Bot_SetupQuickMove( botInfo->origin, false ); //mal: just path to itself, if its in an obstacle, it will freak and avoid it.
if ( MoveIsInvalid() ) {
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 ( enemyInfo.enemyDist < 300.0f ) {
if ( Bot_CanMove( BACK, 50.0f, true )) {
Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, NULLMOVETYPE );
} else {
COMBAT_MOVEMENT_STATE = NULL;
}
return false;
}
return true;
}
/*
================
idBotAI::Enter_Crouch_Attack_Movement
================
*/
bool idBotAI::Enter_Crouch_Attack_Movement() {
COMBAT_MOVEMENT_STATE = &idBotAI::Crouch_Attack_Movement;
combatMoveType = CROUCH_ATTACK;
combatMoveFailedCount = 0;
lastMoveNode = "Crouch Attack";
return true;
}
/*
================
idBotAI::Crouch_Attack_Movement
================
*/
bool idBotAI::Crouch_Attack_Movement() {
int result;
idVec3 vec;
if ( botInfo->weapInfo.weapon == KNIFE ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
if ( !Bot_CanCrouch( enemy ) ) {
combatMoveFailedCount++;
if ( combatMoveFailedCount > MAX_MOVE_FAILED_COUNT ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
} else {
combatMoveFailedCount = 0;
}
if ( botInfo->lastAttacker == enemy && botInfo->lastAttackerTime + 5000 > botWorld->gameLocalInfo.time && enemyInfo.enemyDist < 1500.0f && botInfo->weapInfo.weapon != SNIPERRIFLE ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
if ( combatDangerExists ) {
Bot_SetupQuickMove( botInfo->origin, false ); //mal: just path to itself, if its in an obstacle, it will freak and avoid it.
if ( MoveIsInvalid() ) {
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 ( botInfo->weapInfo.weapon == SNIPERRIFLE ) {
combatMoveDir = NULL_DIR;
}
if ( botInfo->weapInfo.isReloading && combatMoveTime < botWorld->gameLocalInfo.time && botInfo->weapInfo.weapon != SNIPERRIFLE ) { //mal: what should the bot do while they're reloading their gun.
if ( botThreadData.random.RandomInt( 100 ) > 50 ) {
combatMoveDir = LEFT;
} else {
combatMoveDir = RIGHT;
}
combatMoveTime = botWorld->gameLocalInfo.time + 5000;
}
if ( enemyInfo.enemyDist < 300.0f ) {
if ( Bot_CanMove( BACK, 50.0f, true )) {
Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, NULLMOVETYPE );
} else {
COMBAT_MOVEMENT_STATE = NULL;
}
return false;
}
if ( combatMoveTime < botWorld->gameLocalInfo.time && botInfo->weapInfo.weapon != SNIPERRIFLE ) {
result = botThreadData.random.RandomInt( 3 );
if ( result == 0 ) {
combatMoveDir = RIGHT;
} else if ( result == 1 ) {
combatMoveDir = LEFT;
} else {
combatMoveDir = BACK; //mal: basically, do nothing, just crouch there.
}
combatMoveTime = botWorld->gameLocalInfo.time + 3000;
}
if ( combatMoveDir != NULL_DIR ) {
if ( combatMoveDir == BACK ) {
Bot_MoveToGoal( vec3_zero, vec3_zero, CROUCH, NULLMOVETYPE );
} else {
if ( Bot_CanMove( combatMoveDir, 100.0f, true ) ) {
Bot_MoveToGoal( botCanMoveGoal, vec3_zero, CROUCH, ( combatMoveDir == RIGHT ) ? STRAFE_RIGHT : STRAFE_LEFT );
} else {
COMBAT_MOVEMENT_STATE = NULL;
}
}
}
return true;
}
/*
================
idBotAI::Enter_Circle_Strafe_Attack_Movement
================
*/
bool idBotAI::Enter_Circle_Strafe_Attack_Movement() {
COMBAT_MOVEMENT_STATE = &idBotAI::Circle_Strafe_Attack_Movement;
combatMoveType = CIRCLE_STRAFE_ATTACK;
lastMoveNode = "Circle Strafe";
return true;
}
/*
================
idBotAI::Circle_Strafe_Attack_Movement
================
*/
bool idBotAI::Circle_Strafe_Attack_Movement() {
if ( enemyInfo.enemyDist > 700.0f ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
if ( botInfo->weapInfo.weapon == KNIFE ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
if ( enemyInfo.enemyHeight < -150 && enemyInfo.enemyDist > 700 ) { //mal: if we have the height advantage - stop moving!
Bot_MoveToGoal( vec3_zero, vec3_zero, NULLMOVEFLAG, NULLMOVETYPE );
return true;
}
if ( combatMoveTime < botWorld->gameLocalInfo.time ) {
if ( botThreadData.random.RandomInt( 100 ) > 50 ) {
combatMoveDir = RIGHT;
} else {
combatMoveDir = LEFT;
}
combatMoveTime = botWorld->gameLocalInfo.time + 15000;
}
if ( Bot_CanMove( combatMoveDir, 100.0f, true )) {
Bot_MoveToGoal( vec3_zero, vec3_zero, RUN, ( combatMoveDir == RIGHT ) ? STRAFE_RIGHT : STRAFE_LEFT );
} else {
COMBAT_MOVEMENT_STATE = NULL;
}
return true;
}
/*
================
idBotAI::Enter_Side_Strafe_Attack_Movement
================
*/
bool idBotAI::Enter_Side_Strafe_Attack_Movement() {
COMBAT_MOVEMENT_STATE = &idBotAI::Side_Strafe_Attack_Movement;
combatMoveType = SIDE_STRAFE_ATTACK;
lastMoveNode = "Side Strafe";
return true;
}
/*
================
idBotAI::Side_Strafe_Attack_Movement
================
*/
bool idBotAI::Side_Strafe_Attack_Movement() {
float tooCloseDist = ( botInfo->weapInfo.weapon == ROCKET ) ? 450.0f : 300.0f;
if ( botInfo->weapInfo.weapon == KNIFE ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
if ( enemyInfo.enemyDist < tooCloseDist ) {
if ( Bot_CanMove( BACK, 100.0f, true )) {
Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, NULLMOVETYPE );
} else {
COMBAT_MOVEMENT_STATE = NULL;
}
return false;
}
if ( combatMoveTime < botWorld->gameLocalInfo.time && combatMoveTime != -1 ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
if ( combatMoveTime < botWorld->gameLocalInfo.time ) {
if ( botThreadData.random.RandomInt( 100 ) > 50 ) {
combatMoveDir = RIGHT;
} else {
combatMoveDir = LEFT;
}
combatMoveTime = botWorld->gameLocalInfo.time + 5000;
}
botMoveTypes_t botMove;
if ( botThreadData.random.RandomInt( 100 ) > 60 ) {
botMove = ( combatMoveDir == RIGHT ) ? RANDOM_JUMP_RIGHT : RANDOM_JUMP_LEFT;
} else {
botMove = ( combatMoveDir == RIGHT ) ? STRAFE_RIGHT : STRAFE_LEFT;
}
if ( Bot_CanMove( combatMoveDir, 50.0f, true )) {
Bot_MoveToGoal( vec3_zero, vec3_zero, RUN, botMove );
} else {
combatMoveTime = 1; //mal: move failed - leave here. Side strafing is a one time deal...
}
return true;
}
/*
================
idBotAI::Enter_Hal_Strafe_Attack_Movement
================
*/
bool idBotAI::Enter_Hal_Strafe_Attack_Movement() {
COMBAT_MOVEMENT_STATE = &idBotAI::Hal_Strafe_Attak_Movement;
combatMoveType = HAL_STRAFE_ATTACK;
lastMoveNode = "Hal Strafe";
return true;
}
/*
================
idBotAI::Hal_Strafe_Attak_Movement
================
*/
bool idBotAI::Hal_Strafe_Attak_Movement() {
float chaseDist = ( botInfo->weapInfo.weapon == ROCKET ) ? 2500.0f : 1500.0f;
float tooCloseDist = ( botInfo->weapInfo.weapon == ROCKET ) ? 450.0f : 300.0f;
if ( botInfo->weapInfo.weapon == KNIFE ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
if ( enemyInfo.enemyDist < tooCloseDist ) {
if ( Bot_CanMove( BACK, 100.0f, true )) {
Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, NULLMOVETYPE );
} else {
COMBAT_MOVEMENT_STATE = NULL;
}
return false;
}
if ( enemyInfo.enemyDist > chaseDist ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
if ( combatMoveTime < botWorld->gameLocalInfo.time ) {
if ( combatMoveDir != RIGHT && combatMoveDir != LEFT ) {
if ( botThreadData.random.RandomInt( 100 ) > 50 ) {
combatMoveDir = RIGHT;
} else {
combatMoveDir = LEFT;
}
} else {
if ( combatMoveDir == RIGHT ) {
combatMoveDir = LEFT;
} else {
combatMoveDir = RIGHT;
}
}
combatMoveTime = botWorld->gameLocalInfo.time + 700;
}
if ( Bot_CanMove( combatMoveDir, 150.0f, true )) {
Bot_MoveToGoal( vec3_zero, vec3_zero, RUN, ( combatMoveDir == RIGHT ) ? STRAFE_RIGHT : STRAFE_LEFT );
} else {
COMBAT_MOVEMENT_STATE = NULL;
}
return true;
}
/*
================
idBotAI::Enter_Stand_Ground_Attack_Movement
================
*/
bool idBotAI::Enter_Stand_Ground_Attack_Movement() {
COMBAT_MOVEMENT_STATE = &idBotAI::Stand_Ground_Attack_Movement;
combatMoveType = STAND_GROUND_ATTACK;
lastMoveNode = "Stand Ground";
return true;
}
/*
================
idBotAI::Stand_Ground_Attack_Movement
================
*/
bool idBotAI::Stand_Ground_Attack_Movement() {
float tooCloseDist = ( botInfo->weapInfo.weapon == ROCKET ) ? 450.0f : 300.0f;
idVec3 vec;
if ( botWorld->gameLocalInfo.botSkill != BOT_SKILL_DEMO ) {
if ( botInfo->weapInfo.weapon == KNIFE ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
}
if ( combatDangerExists && botWorld->gameLocalInfo.botSkill != BOT_SKILL_DEMO ) {
Bot_SetupQuickMove( botInfo->origin, false ); //mal: just path to itself, if its in an obstacle, it will freak and avoid it.
if ( MoveIsInvalid() ) {
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 ( botInfo->weapInfo.isReloading && botThreadData.GetBotSkill() > BOT_SKILL_EASY && botInfo->weapInfo.weapon != SNIPERRIFLE && botWorld->gameLocalInfo.botSkill != BOT_SKILL_DEMO ) { //mal: what should the bot do while they're reloading their gun.
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
if ( enemyInfo.enemyDist < tooCloseDist ) {
if ( Bot_CanMove( BACK, 100.0f, true )) {
Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, NULLMOVETYPE );
} else {
COMBAT_MOVEMENT_STATE = NULL;
}
return false;
}
return true;
}
/*
================
idBotAI::Enter_Grenade_Attack_Movement
================
*/
bool idBotAI::Enter_Grenade_Attack_Movement() {
COMBAT_MOVEMENT_STATE = &idBotAI::Grenade_Attack_Movement;
combatMoveType = GRENADE_ATTACK;
lastMoveNode = "Grenade Attack";
return true;
}
/*
================
idBotAI::Grenade_Attack_Movement
================
*/
bool idBotAI::Grenade_Attack_Movement() {
float chaseDist = GRENADE_THROW_MAXDIST;
float tooCloseDist = GRENADE_THROW_MINDIST;
if ( combatMoveFailedCount > 10 ) { //mal: move failed too many times, get out of here!
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
if ( botInfo->weapInfo.weapon != NADE ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
if ( enemyInfo.enemyDist < tooCloseDist ) {
if ( Bot_CanMove( BACK, 150.0f, true )) {
Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, RANDOM_JUMP );
} else if ( Bot_CanMove( RIGHT, 150.0f, true )) {
Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, RANDOM_JUMP );
} else if ( Bot_CanMove( LEFT, 150.0f, true )) {
Bot_MoveToGoal( botCanMoveGoal, vec3_zero, RUN, RANDOM_JUMP );
} else {
combatMoveFailedCount++;
}
} else {
if ( combatMoveTime < botWorld->gameLocalInfo.time ) {
if ( combatMoveTime == -1 || combatMoveTime != 1 ) {
if ( botThreadData.random.RandomInt( 100 ) > 50 ) {
combatMoveDir = RIGHT;
} else {
combatMoveDir = LEFT;
}
} else {
if ( combatMoveDir == LEFT ) {
combatMoveDir = RIGHT;
} else {
combatMoveDir = LEFT;
}
}
combatMoveTime = botWorld->gameLocalInfo.time + 1700;
}
if ( enemyInfo.enemyDist > chaseDist ) {
if ( Bot_CanMove( combatMoveDir, 150.0f, true ) ) {
Bot_SetupMove( 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, ( combatMoveDir == RIGHT ) ? RANDOM_JUMP_RIGHT : RANDOM_JUMP_LEFT );
} else {
combatMoveTime = 1; //mal: move failed, try another!
combatMoveFailedCount++;
}
} else {
Bot_MoveToGoal( vec3_zero, vec3_zero, RUN, ( combatMoveDir == RIGHT ) ? RANDOM_JUMP_RIGHT : RANDOM_JUMP_LEFT );
}
}
return true;
}
/*
================
idBotAI::Enter_Avoid_Danger_Movement
================
*/
bool idBotAI::Enter_Avoid_Danger_Movement() {
COMBAT_MOVEMENT_STATE = &idBotAI::Avoid_Danger_Movement;
combatMoveType = AVOID_DANGER_ATTACK;
lastMoveNode = "Avoid Danger";
combatMoveTime = botWorld->gameLocalInfo.time + 4000;
return true;
}
/*
================
idBotAI::Avoid_Danger_Movement
================
*/
bool idBotAI::Avoid_Danger_Movement() {
Bot_SetupQuickMove( botInfo->origin, false ); //mal: just path to itself, if its in an obstacle, it will freak and avoid it.
if ( MoveIsInvalid() ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
if ( combatMoveTime < botWorld->gameLocalInfo.time ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, NULLMOVETYPE );
return true;
}
/*
================
idBotAI::Enter_Null_Move_Attack
================
*/
bool idBotAI::Enter_Null_Move_Attack() {
COMBAT_MOVEMENT_STATE = &idBotAI::Null_Move_Attack;
combatMoveType = NULL_MOVE_ATTACK;
lastMoveNode = "Null Move";
return true;
}
/*
================
idBotAI::Null_Move_Attack
This was one of the harder, most complex functions ever written, but somehow.... I managed. :-P
================
*/
bool idBotAI::Null_Move_Attack() {
return true;
}
/*
================
idBotAI::Enter_MoveTo_Shield_Attack_Movement
================
*/
bool idBotAI::Enter_MoveTo_Shield_Attack_Movement() {
COMBAT_MOVEMENT_STATE = &idBotAI::MoveTo_Shield_Attack_Movement;
combatMoveType = MOVETO_SHIELD_ATTACK;
lastMoveNode = "MoveTo Shield";
return true;
}
/*
================
idBotAI::MoveTo_Shield_Attack_Movement
================
*/
bool idBotAI::MoveTo_Shield_Attack_Movement() {
if ( !botInfo->weapInfo.isReloading && botInfo->weapInfo.isReady ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
idVec3 shieldOrg;
float shieldDistSqr = Bot_DistSqrToClosestForceShield( shieldOrg );
if ( shieldDistSqr == -1.0f || shieldDistSqr > Square( SHIELD_CONSIDER_RANGE * 2.0f ) ) { //mal: make sure the shield didn't die, or that theres not another close one nearby...
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
if ( shieldDistSqr > Square( 45.0f ) ) {
Bot_SetupMove( shieldOrg, -1, ACTION_NULL );
if ( MoveIsInvalid() ) {
COMBAT_MOVEMENT_STATE = NULL;
return false;
}
Bot_MoveToGoal( botAAS.path.moveGoal, vec3_zero, RUN, NULLMOVETYPE );
}
return true;
}