etqw-sdk/source/game/botai/BotAI_Actions.cpp
2008-05-29 00:00:00 +00:00

383 lines
9.7 KiB
C++

// Copyright (C) 2007 Id Software, Inc.
//
#include "../precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
#include "BotThreadData.h"
#include "BotAI_Main.h"
idBotActions::idBotActions() {
actionBBox.Clear();
posture = WALK;
actionState = ACTION_STATE_NORMAL;
radius = 70.0f;
groupID = 0;
routeID = -1; //dont use a route by default.
activeForever = false;
baseHumanObj = humanObj = ACTION_NULL;
baseStroggObj = stroggObj = ACTION_NULL;
active = false;
actionTimeInSeconds = 0;
areaNum = 0;
areaNumVehicle = 0;
disguiseSafe = true;
noHack = false;
name = "";
targetAction = "";
requiresVehicleType = false;
origin.Zero();
blindFire = false;
priority = true;
teamOwner = NOTEAM;
weapType = NULL_WEAP;
baseActionType = BASE_ACTION;
actionVehicleFlags = -1; //mal: by default, no vehicle used.
spawnControllerEntityNum = -1;
actionActivateTime = 0;
memset( actionTargets, 0, sizeof( actionTargets ) );
//mal_TODO: add more variables here to clear as create them.
}
/*
================
idBotActions::EntityOriginIsInsideActionBBox
================
*/
bool idBotActions::EntityOriginIsInsideActionBBox( const idVec3& entOrg ) {
idBox actionBounds = actionBBox;
actionBounds.ExpandSelf( ACTION_BBOX_EXPAND_BIG ); //mal: be a bit forgiving when doing this bounds check.
if ( actionBounds.ContainsPoint( entOrg ) ) {
return true;
}
return false;
}
/*
================
idBotActions::EntityIsInsideActionBBox
Is the entity inside the bbox of the action?
================
*/
bool idBotActions::EntityIsInsideActionBBox( int entNum, const dangerTypes_t entityType, bool expandBox ) const {
int i, j;
idBox entBounds;
idBox actionBounds = actionBBox;
if ( expandBox ) {
actionBounds.ExpandSelf( ACTION_BBOX_EXPAND_BIG ); //mal: be a bit forgiving when doing this bounds check.
}
if ( entityType == PLANTED_CHARGE ) {
for( i = 0; i < MAX_CLIENT_CHARGES; i++ ) {
const plantedChargeInfo_t& charge = botThreadData.GetBotWorldState()->chargeInfo[ i ];
if ( charge.entNum != entNum ) {
continue;
}
if ( actionBounds.ContainsPoint( charge.origin ) ) {
return true;
}
}
} else if ( entityType == PLANTED_LANDMINE ) {
for( i = 0; i < MAX_CLIENTS; i++ ) {
for( j = 0; j < MAX_MINES; j++ ) {
if ( botThreadData.GetGameWorldState()->clientInfo[ i ].weapInfo.landMines[ j ].entNum != entNum ) {
continue;
}
if ( actionBounds.ContainsPoint( botThreadData.GetBotWorldState()->clientInfo[ i ].weapInfo.landMines[ j ].origin ) ) {
return true;
}
}
}
} else if ( entityType == INGAME_PLAYER ) {
entBounds = idBox( botThreadData.GetBotWorldState()->clientInfo[ entNum ].localBounds, botThreadData.GetBotWorldState()->clientInfo[ entNum ].origin, botThreadData.GetBotWorldState()->clientInfo[ entNum ].bodyAxis );
entBounds.ExpandSelf( 16.0f ); //mal: make it a bit flexible.
if ( actionBounds.IntersectsBox( entBounds ) ) {
return true;
}
} //mal_TODO: keep adding more entity types here!
return false;
}
/*
================
idBotActions::ArmedChargesInsideActionBBox
Is there any armed charges currently inside this action's bbox?
================
*/
bool idBotActions::ArmedChargesInsideActionBBox( int ignoreEnt ) const {
idBox actionBox = actionBBox;
actionBox.ExpandSelf( ACTION_BBOX_EXPAND_BIG );
for( int i = 0; i < MAX_CLIENT_CHARGES; i++ ) {
const plantedChargeInfo_t& bombInfo = botThreadData.GetBotWorldState()->chargeInfo[ i ];
if ( bombInfo.entNum == 0 ) {
continue;
}
if ( bombInfo.entNum == ignoreEnt ) {
continue;
}
if ( bombInfo.state != BOMB_ARMED ) {
continue;
}
idBox bombBox = idBox( bombInfo.bbox );
if ( actionBox.IntersectsBox( bombBox ) ) {
return true;
}
}
return false;
}
/*
================
idBotActions::ArmedMinesInsideActionBBox
Is there any armed mines currently inside this action's bbox?
================
*/
bool idBotActions::ArmedMinesInsideActionBBox() const {
for( int j = 0; j < MAX_CLIENTS; j++ ) {
for( int i = 0; i < MAX_MINES; i++ ) {
if ( botThreadData.GetBotWorldState()->clientInfo[ j ].weapInfo.landMines[ i ].entNum == 0 ) {
continue;
}
plantedMineInfo_t mine = botThreadData.GetBotWorldState()->clientInfo[ j ].weapInfo.landMines[ i ];
if ( mine.state != BOMB_ARMED ) {
continue;
}
idBox mineBox = idBox( mine.bbox );
idBox actionBox = actionBBox;
actionBox.ExpandSelf( ACTION_BBOX_EXPAND_BIG );
if ( botThreadData.AllowDebugData() ) {
gameRenderWorld->DebugBox( colorGreen, mineBox, 1024 );
gameRenderWorld->DebugBox( colorRed, actionBox, 1024 );
}
if ( actionBox.IntersectsBox( mineBox ) ) {
return true;
}
}
}
return false;
}
/*
================
idBotActions::FindBBoxCenterLinePoint
Find a point to look in the actions bbox, staying in the bounds of the box.
================
*/
void idBotActions::FindBBoxCenterLinePoint( idVec3& point ) const {
int index = Max3Index( actionBBox.GetExtents()[ 0 ], actionBBox.GetExtents()[ 1 ], actionBBox.GetExtents()[ 2 ] );
float extents = actionBBox.GetExtents()[ index ];
if ( extents > 64.0f ) {
extents -= 16.0f;
} else {
extents *= 0.80f;
}
idVec3 dir = actionBBox.GetAxis()[ index ] * extents;
idVec3 start = actionBBox.GetCenter() + dir;
idVec3 end = actionBBox.GetCenter() - dir;
ProjectPointOntoLine( start, end, point );
/*
idBounds bounds = actionBBox;
idVec3 v = bounds[1] - bounds[0];
int i = MaxIndex( v[0], v[1] );
idVec3 start = bounds.GetCenter();
idVec3 end = bounds.GetCenter();
start[i] = bounds[0][i] + 16.0f; //mal: move in from the start/end points just a bit, incase the bbox is right at the edge of a wall.
end[i] = bounds[1][i] - 16.0f;
*/
//mal_DEBUG
if ( botThreadData.AllowDebugData() ) {
gameRenderWorld->DebugLine( colorGreen, start, end, 1024 );
}
}
/*
================
idBotActions::ProjectPointOntoLine
================
*/
void idBotActions::ProjectPointOntoLine( const idVec3 &start, const idVec3 &end, idVec3 &point ) const {
idVec3 v1 = end - start;
float l = v1.Normalize();
idVec3 v2 = point - start;
float d = ( v1 * v2 );
if ( d < 0.0f ) {
point = start;
} else if ( d > l ) {
point = end;
}
point = start + d * v1;
}
/*
================
idBotActions::FindRandomPointInBBox
Find a random point in a action's bbox, along the center axis, for the bot to move toward.
================
*/
void idBotActions::FindRandomPointInBBox( idVec3 &point, int ignoreClientNum, const playerTeamTypes_t team ) const {
int index = Max3Index( actionBBox.GetExtents()[ 0 ], actionBBox.GetExtents()[ 1 ], actionBBox.GetExtents()[ 2 ] );
float extents = actionBBox.GetExtents()[ index ];
if ( extents > 64.0f ) {
extents -= 16.0f;
} else {
extents *= 0.80f;
}
idVec3 dir = actionBBox.GetAxis()[ index ] * extents;
idVec3 start = actionBBox.GetCenter() + dir;
idVec3 end = actionBBox.GetCenter() - dir;
point = actionBBox.GetCenter();
point = start + botThreadData.random.RandomFloat() * ( end - start );
int j = 0;
int i;
while( j < 10 ) {
for( i = 0; i < MAX_CLIENTS; i++ ) {
if ( i == ignoreClientNum ) { //mal: dont scan the calling client.
continue;
}
const clientInfo_t& player = botThreadData.GetBotWorldState()->clientInfo[ i ];
if ( player.inGame == false || player.team == NOTEAM || player.team != team || player.health <= 0 ) {
continue;
}
idVec3 vec = player.origin - point;
vec.z = 0.0f;
float z = vec.z;
if ( idMath::Fabs( z ) > 128.0f ) {
continue;
}
if ( vec.LengthSqr() > Square( SAFE_PLAYER_BODY_WIDTH ) ) {
continue;
}
j++;
point = actionBBox.GetCenter();
point = start + botThreadData.random.RandomFloat() * ( end - start );
break;
}
if ( i >= 32 ) {
break;
}
}
if ( botThreadData.AllowDebugData() ) {
end = point;
end[ 2 ] += 64;
gameRenderWorld->DebugLine( colorRed, point, end, 1024 );
}
}
/*
================
idBotActions::CheckTeamMemberIsInsideAction
================
*/
bool idBotActions::CheckTeamMemberIsInsideAction( int ignoreClientNum, const playerTeamTypes_t team, const playerClassTypes_t classType, bool needsBombCharge ) const {
bool hasMate = false;
for( int i = 0; i < MAX_CLIENTS; i++ ) {
if ( i == ignoreClientNum ) {
continue;
}
const clientInfo_t& player = botThreadData.GetBotWorldState()->clientInfo[ i ];
if ( player.inGame == false || player.team == NOTEAM || player.team != team || player.health <= 0 || player.classType != classType ) {
continue;
}
idBox playerBox = idBox( player.localBounds, player.origin, player.bodyAxis );
playerBox.ExpandSelf( 16.0f );
if ( !actionBBox.IntersectsBox( playerBox ) ) {
continue;
}
if ( needsBombCharge ) {
if ( player.bombChargeUsed > 0 ) {
continue;
}
}
hasMate = true;
break;
}
return hasMate;
}
/*
================
idBotActions::GetActionVehicleFlags
only allow the Icarus to be used if the action is inside a valid vehicle AAS area.
================
*/
int idBotActions::GetActionVehicleFlags( const playerTeamTypes_t team ) const {
if ( actionVehicleFlags == 0 && areaNumVehicle == 0 && team == STROGG ) {
return ALL_VEHICLES_BUT_ICARUS;
}
if ( actionVehicleFlags == 1 && areaNumVehicle == 0 && team == STROGG ) {
return NO_VEHICLE;
}
if ( actionVehicleFlags != -1 && areaNumVehicle == 0 && ( actionVehicleFlags & PERSONAL ) && team == STROGG ) {
int newFlags = actionVehicleFlags;
newFlags &= ~PERSONAL;
return newFlags;
}
return actionVehicleFlags;
}