quake4-sdk/source/game/ai/AI_Debug.cpp
2007-06-15 00:00:00 +00:00

330 lines
14 KiB
C++

/*
================
AI_Debug.cpp
================
*/
#include "../../idlib/precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
#include "AI_Manager.h"
#include "AI_Util.h"
const char *aiMoveCommandString[ NUM_MOVE_COMMANDS ] = {
"MOVE_NONE",
"MOVE_FACE_ENEMY",
"MOVE_FACE_ENTITY",
"MOVE_TO_ENEMY",
"MOVE_TO_ENTITY",
"MOVE_TO_ATTACK",
"MOVE_TO_HELPER",
"MOVE_TO_TETHER",
"MOVE_TO_COVER",
"MOVE_TO_HIDE",
"MOVE_TO_POSITION",
"MOVE_OUT_OF_RANGE",
"MOVE_SLIDE_TO_POSITION",
"MOVE_WANDER"
};
const char* aiMoveStatusString[ NUM_MOVE_STATUS ] = {
"MOVE_STATUS_DONE",
"MOVE_STATUS_MOVING",
"MOVE_STATUS_WAITING",
"MOVE_STATUS_DEST_NOT_FOUND",
"MOVE_STATUS_DEST_UNREACHABLE",
"MOVE_STATUS_BLOCKED_BY_WALL",
"MOVE_STATUS_BLOCKED_BY_OBJECT",
"MOVE_STATUS_BLOCKED_BY_ENEMY",
"MOVE_STATUS_BLOCKED_BY_MONSTER",
"MOVE_STATUS_BLOCKED_BY_PLAYER",
"MOVE_STATUS_DISABLED"
};
const char* aiMoveDirectionString [ MOVEDIR_MAX ] = {
"MOVEDIR_FORWARD",
"MOVEDIR_BACKWARD",
"MOVEDIR_LEFT",
"MOVEDIR_RIGHT"
};
const char* aiTacticalString [ AITACTICAL_MAX ] = {
"AITACTICAL_NONE",
"AITACTICAL_MELEE",
"AITACTICAL_MOVE_FOLLOW",
"AITACTICAL_MOVE_TETHER",
"AITACTICAL_MOVE_PLAYERPUSH",
"AITACTICAL_COVER",
"AITACTICAL_COVER_FLANK",
"AITACTICAL_COVER_ADVANCE",
"AITACTICAL_COVER_RETREAT",
"AITACTICAL_COVER_AMBUSH",
"AITACTICAL_RANGED",
"AITACTICAL_TURRET",
"AITACTICAL_HIDE",
"AITACTICAL_PASSIVE",
};
const char* aiFocusString [ AIFOCUS_MAX ] = {
"AIFOCUS_NONE",
"AIFOCUS_LEADER",
"AIFOCUS_TARGET",
"AIFOCUS_TALK",
"AIFOCUS_PLAYER",
"AIFOCUS_ENEMY",
"AIFOCUS_COVER",
"AIFOCUS_COVERLOOK",
"AIFOCUS_HELPER",
"AIFOCUS_TETHER",
};
const char* aiActionStatusString [ rvAIAction::STATUS_MAX ] = {
"Unused",
"OK",
"Disabled",
"Failed: timer",
"Failed: external timer",
"Failed: within min range",
"Failed: out of max range",
"Failed: random chance",
"Failed: bad animation",
"Failed: condition",
"Failed: no enemy",
};
/*
=====================
idAI::GetDebugInfo
=====================
*/
void idAI::GetDebugInfo ( debugInfoProc_t proc, void* userData ) {
// Base class first
idActor::GetDebugInfo ( proc, userData );
proc ( "idAI", "aifl.damage", aifl.damage ? "true" : "false", userData );
proc ( "idAI", "aifl.undying", aifl.undying ? "true" : "false", userData );
proc ( "idAI", "aifl.pain", aifl.pain ? "true" : "false", userData );
proc ( "idAI", "aifl.dead", aifl.dead ? "true" : "false", userData );
proc ( "idAI", "aifl.activated", aifl.activated ? "true" : "false", userData );
proc ( "idAI", "aifl.jump", aifl.jump ? "true" : "false", userData );
proc ( "idAI", "aifl.hitEnemy", aifl.hitEnemy ? "true" : "false", userData );
proc ( "idAI", "aifl.pushed", aifl.pushed ? "true" : "false", userData );
proc ( "idAI", "aifl.lookAtPlayer", aifl.lookAtPlayer ? "true" : "false", userData );
proc ( "idAI", "aifl.disableAttacks", aifl.disableAttacks ? "true" : "false", userData );
proc ( "idAI", "aifl.simpleThink", aifl.simpleThink ? "true" : "false", userData );
proc ( "idAI", "aifl.action", aifl.action ? "true" : "false", userData );
proc ( "idAI", "aifl.scripted", aifl.scripted? "true" : "false", userData );
proc ( "idAI", "leader", leader.GetEntity() ? leader.GetEntity()->GetName() : "<none>", userData );
proc ( "idAI", "move.followRangeMin", va("%g",move.followRange[0]), userData );
proc ( "idAI", "move.followRangeMax", va("%g",move.followRange[1]), userData );
proc ( "idAI", "combat.fl.aware", combat.fl.aware ? "true" : "false", userData );
proc ( "idAI", "combat.fl.ignoreEnemies", combat.fl.ignoreEnemies ? "true" : "false", userData );
proc ( "idAI", "enemy", enemy.ent ? enemy.ent->GetName() : "<none>", userData );
proc ( "idAI", "enemy.fl.inFov", enemy.fl.inFov ? "true" : "false", userData );
proc ( "idAI", "enemy.fl.visible", enemy.fl.visible ? "true" : "false", userData );
proc ( "idAI", "combat.fl.seenEnemyDirectly",combat.fl.seenEnemyDirectly ? "true" : "false", userData );
proc ( "idAI", "enemy.lastVisibleTime", va("%d",enemy.lastVisibleTime), userData );
proc ( "idAI", "combat.maxLostVisTime", va("%d",combat.maxLostVisTime), userData );
proc ( "idAI", "enemy.range", va("%g",enemy.range), userData );
proc ( "idAI", "enemy.ranged2d", va("%g",enemy.range2d), userData );
proc ( "idAI", "lastAttackTime", va("%d",lastAttackTime), userData );
proc ( "idAI", "move.fl.done", move.fl.done ? "true" : "false", userData );
proc ( "idAI", "move.fl.disabled", move.fl.disabled ? "true" : "false", userData );
proc ( "idAI", "move.fl.onGround", move.fl.onGround ? "true" : "false", userData );
proc ( "idAI", "move.fl.blocked", move.fl.blocked ? "true" : "false", userData );
proc ( "idAI", "move.fl.obstacleInPath", move.fl.obstacleInPath ? "true" : "false", userData );
proc ( "idAI", "move.fl.goalUnreachable", move.fl.goalUnreachable ? "true" : "false", userData );
proc ( "idAI", "move.fl.moving", move.fl.moving ? "true" : "false", userData );
proc ( "idAI", "move.command", aiMoveCommandString[move.moveCommand], userData );
proc ( "idAI", "move.status", aiMoveStatusString[move.moveStatus], userData );
proc ( "idAI", "move.fl.allowDirectional", move.fl.allowDirectional ? "true" : "false", userData );
proc ( "idAI", "move.direction_ideal", aiMoveDirectionString[move.idealDirection ], userData );
proc ( "idAI", "move.direction_current", aiMoveDirectionString[move.currentDirection ], userData );
proc ( "idAI", "move.yaw_ideal", va("%d",(int)move.ideal_yaw), userData );
proc ( "idAI", "move.yaw_current", va("%d",(int)move.current_yaw), userData );
proc ( "idAI", "move.fly_roll", va("%g", move.fly_roll ), userData );
proc ( "idAI", "move.fly_pitch", va("%g", move.fly_pitch ), userData );
proc ( "idAI", "tether", tether!=NULL?tether->GetName():"<none>", userData );
proc ( "idAI", "IsTethered()", IsTethered()?"true":"false", userData );
proc ( "idAI", "lookTarget", lookTarget.GetEntity() ? lookTarget.GetEntity()->GetName() : "<none>", userData );
proc ( "idAI", "talkTarget", talkTarget.GetEntity() ? talkTarget.GetEntity()->GetName() : "<none>", userData );
proc ( "idAI", "focusType", aiFocusString[focusType], userData );
proc ( "idAI", "look.yaw", va("%g", lookAng.yaw ), userData );
proc ( "idAI", "look.pitch", va("%g", lookAng.pitch ), userData );
proc ( "idAI", "combat.attackRangeMin", va("%g",combat.attackRange[0]), userData );
proc ( "idAI", "combat.attackRangeMax", va("%g",combat.attackRange[1]), userData );
proc ( "idAI", "combat.tacticalCurrent", aiTacticalString[combat.tacticalCurrent], userData );
proc ( "idAI", "action_rangedAttack", aiActionStatusString[actionRangedAttack.status], userData );
proc ( "idAI", "action_meleeAttack", aiActionStatusString[actionMeleeAttack.status], userData );
proc ( "idAI", "action_leapAttack", aiActionStatusString[actionLeapAttack.status], userData );
proc ( "idAI", "action_jumpBack", aiActionStatusString[actionJumpBack.status], userData );
proc ( "idAI", "action_evadeLeft", aiActionStatusString[actionEvadeLeft.status], userData );
proc ( "idAI", "action_evadeRight", aiActionStatusString[actionEvadeRight.status], userData );
proc ( "idAI", "npc_name", spawnArgs.FindKey("npc_name")?common->GetLocalizedString(spawnArgs.GetString( "npc_name", "<none>")):"<none>", userData );
}
/*
=====================
idAI::DrawRoute
=====================
*/
void idAI::DrawRoute( void ) const {
if ( aas && move.toAreaNum && move.moveCommand != MOVE_NONE && move.moveCommand != MOVE_WANDER && move.moveCommand != MOVE_FACE_ENEMY && move.moveCommand != MOVE_FACE_ENTITY ) {
if ( move.moveType == MOVETYPE_FLY ) {
aas->ShowFlyPath( physicsObj.GetOrigin(), move.toAreaNum, move.moveDest );
} else {
aas->ShowWalkPath( physicsObj.GetOrigin(), move.toAreaNum, move.moveDest );
}
}
}
/*
=====================
idAI::DrawTactical
Draw the debug tactical information
=====================
*/
void idAI::DrawTactical ( void ) {
if ( !DebugFilter(ai_debugTactical) ) {
return;
}
// Colors For Lines In This File
//-------------------------------
// Majenta = Move Dest
// Green / Red = Enemy (On Player Side, On Enemy Side)
// Pink = Tether Radius
// Grey = FOV
// Colors From AAST Draw Debug Info
//----------------------------------
// Blue = Reserved Feature
// Orange = Near Feature
// Yellow = Look Feature
// Get Origin
//------------
idVec3 origin = GetPhysics()->GetOrigin();
origin += (GetPhysics()->GetGravityNormal() * 5.0f);
// Draw FOV (Must be close to player and on enemy team)
//------------------------------------------------------
if (team && DistanceTo(gameLocal.GetLocalPlayer())<500.0f) {
if (!combat.fl.aware) {
gameRenderWorld->DebugFOV(colorLtGrey, origin, viewAxis[0], fovDot, 300.0f, fovCloseDot, fovCloseRange, 0.3f, 10);
} else if (!combat.fl.seenEnemyDirectly) {
gameRenderWorld->DebugFOV(colorMdGrey, origin, viewAxis[0], fovDot, 300.0f, -1.0f, combat.awareRange, 0.3f, 10);
} else {
float alpha = (1.0f - ((float)(gameLocal.GetTime() - enemy.lastVisibleTime) / (float)combat.maxLostVisTime)) * 0.35f;
gameRenderWorld->DebugFOV(colorDkGrey, origin, viewAxis[0], fovDot, 300.0f, -1.0f, combat.awareRange, Max(alpha, 0.1f), 10);
}
}
// Move Over Head
//----------------
origin -= GetPhysics()->GetGravityNormal() * (GetPhysics()->GetBounds()[ 1 ].z - GetPhysics()->GetBounds()[ 0 ].z);
// Draw Enemy Related Info
//-------------------------
if ( enemy.ent ) {
// Draw Lost Time
origin -= (GetPhysics()->GetGravityNormal() * 5.0f);
if ( enemy.lastVisibleTime && (gameLocal.GetTime() - enemy.lastVisibleTime) > combat.maxLostVisTime ) {
gameRenderWorld->DrawText ( va("losttime: %d", (gameLocal.GetTime() - enemy.lastVisibleTime)), origin, 0.12f, colorRed, gameLocal.GetLocalPlayer()->viewAxis );
} else if ( enemy.lastVisibleTime && (gameLocal.GetTime() - enemy.lastVisibleTime) > ( combat.maxLostVisTime/2 ) ) {
gameRenderWorld->DrawText ( va("losttime: %d", (gameLocal.GetTime() - enemy.lastVisibleTime)), origin, 0.12f, colorYellow, gameLocal.GetLocalPlayer()->viewAxis );
} else if ( enemy.lastVisibleTime ) {
gameRenderWorld->DrawText ( va("losttime: %d", (gameLocal.GetTime() - enemy.lastVisibleTime)), origin, 0.12f, colorGreen, gameLocal.GetLocalPlayer()->viewAxis );
}
// Enemy Chest position for enemy lines
idVec3 enemyEyePosition;
idVec3 offset;
if ( enemy.ent->IsType ( idActor::GetClassType() ) ){
enemyEyePosition = static_cast<idActor*>(enemy.ent.GetEntity())->GetEyePosition ( );
} else {
enemyEyePosition = enemy.ent->GetPhysics()->GetOrigin();
}
offset = idVec3(0,0,team*2.0f);
gameRenderWorld->DebugLine ( aiTeamColor[team], GetEyePosition() + offset, enemy.lastVisibleFromEyePosition + offset, 4.0f );
if ( enemyEyePosition != enemy.lastVisibleEyePosition ) {
gameRenderWorld->DebugLine ( aiTeamColor[team], enemy.lastVisibleFromEyePosition + offset, enemy.lastVisibleEyePosition + offset, 4.0f );
gameRenderWorld->DebugArrow ( aiTeamColor[team], enemy.lastVisibleEyePosition + offset, enemyEyePosition + offset, 4.0f );
} else {
gameRenderWorld->DebugArrow ( aiTeamColor[team], enemy.lastVisibleFromEyePosition + offset, enemyEyePosition + offset, 4.0f );
}
}
// Ivalid Cover Timer
//--------------------
if ( IsBehindCover() && combat.coverValidTime && combat.coverValidTime < gameLocal.time) {
origin -= (GetPhysics()->GetGravityNormal() * 5.0f);
gameRenderWorld->DrawText ( va("invalid cover time: %d", (gameLocal.GetTime() - combat.coverValidTime)), origin, 0.12f, colorRed, gameLocal.GetLocalPlayer()->viewAxis );
}
// Vis Crouch
gameRenderWorld->DebugArrow ( colorBrown,
GetPhysics()->GetOrigin ( ) - GetPhysics()->GetGravityNormal() * combat.visCrouchHeight,
GetPhysics()->GetOrigin ( ) - GetPhysics()->GetGravityNormal() * combat.visCrouchHeight + viewAxis[0] * 16.0f, 10.0f );
// Vis Stand
gameRenderWorld->DebugArrow ( colorBrown,
GetPhysics()->GetOrigin ( ) - GetPhysics()->GetGravityNormal() * combat.visStandHeight,
GetPhysics()->GetOrigin ( ) - GetPhysics()->GetGravityNormal() * combat.visStandHeight + viewAxis[0] * 16.0f, 10.0f );
// Aggression
if ( combat.aggressiveScale != 1.0f ) {
origin -= (GetPhysics()->GetGravityNormal() * 5.0f);
gameRenderWorld->DrawText ( va("aggressive: %g", combat.aggressiveScale), origin, 0.12f, colorYellow, gameLocal.GetLocalPlayer()->viewAxis );
}
// Draw anim prefix
//-----------------------
if ( animPrefix.Length ( ) ) {
origin -= (GetPhysics()->GetGravityNormal() * 5.0f);
gameRenderWorld->DrawText ( va("anim: %s", animPrefix.c_str()), origin, 0.12f, colorCyan, gameLocal.GetLocalPlayer()->viewAxis );
}
// Draw focus type
//-----------------------
if ( focusType != AIFOCUS_NONE ) {
origin -= (GetPhysics()->GetGravityNormal() * 5.0f);
gameRenderWorld->DrawText ( aiFocusString[focusType], origin, 0.12f, colorCyan, gameLocal.GetLocalPlayer()->viewAxis );
}
// Draw Tactical Current
//-----------------------
origin -= (GetPhysics()->GetGravityNormal() * 5.0f);
gameRenderWorld->DrawText ( aiTacticalString[combat.tacticalCurrent], origin, 0.12f, colorYellow, gameLocal.GetLocalPlayer()->viewAxis );
// Draw My Name
//--------------
origin -= (GetPhysics()->GetGravityNormal() * 5.0f);
gameRenderWorld->DrawText(name, origin, 0.12f, colorWhite, gameLocal.GetLocalPlayer()->viewAxis);
// Draw the tethered radius
if ( IsTethered ( ) ) {
tether->DebugDraw ( );
}
// Draw Move Destination
if ( !move.fl.done ) {
gameRenderWorld->DebugArrow ( colorMagenta, GetPhysics()->GetOrigin(), move.moveDest, 5 );
}
}