Skip to content

Instantly share code, notes, and snippets.

@Kolesias123
Created November 18, 2014 12:39
Show Gist options
  • Save Kolesias123/9794faaa12c2a2e76c7c to your computer and use it in GitHub Desktop.
Save Kolesias123/9794faaa12c2a2e76c7c to your computer and use it in GitHub Desktop.
//==== InfoSmart 2014. http://creativecommons.org/licenses/by/2.5/mx/ ===========//
#include "cbase.h"
#include "bot.h"
#include "in_utils.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
float CBot::GetEndAimTime()
{
static const int iAngDiff = 40; // 30 degrees to make time difference in bot's aim.
static const int iEndAimSize = 180/iAngDiff + 1;
static const float aEndAimTime[LAST_AIM_SPEED][iEndAimSize] =
{
{ 0.50f, 0.70f, 0.90f, 1.10f, 1.30f }, // AIM_SPEED_VERYLOW
{ 0.50f, 0.60f, 0.70f, 0.80f, 0.90f }, // AIM_SPEED_LOW
{ 0.50f, 0.55f, 0.60f, 0.65f, 0.70f }, // AIM_SPEED_NORMAL
{ 0.40f, 0.45f, 0.50f, 0.55f, 0.60f }, // AIM_SPEED_FAST
{ 0.25f, 0.30f, 0.35f, 0.40f, 0.45f }, // AIM_SPEED_VERYFAST
};
int aimSpeed = AIM_SPEED_LOW;
// ¡Estamos en combate!
if ( Owner()->InCombat() )
aimSpeed = AIM_SPEED_NORMAL;
// Bajo ataque
if ( Owner()->IsUnderAttack() || GetEnemy() )
aimSpeed = AIM_SPEED_FAST;
QAngle angNeeded( m_lookAt );
Utils::GetAngleDifference( Owner()->GetLocalAngles(), angNeeded, angNeeded );
int iPitch = abs( (int)angNeeded.x );
int iYaw = abs( (int)angNeeded.y );
iPitch /= iAngDiff;
iYaw /= iAngDiff;
if ( iPitch < iYaw)
iPitch = iYaw; // iPitch = MAX2( iPitch, iYaw );
float aimTime = aEndAimTime[aimSpeed][iPitch];
return aimTime;
}
void CBot::GetAimCenter( CBaseEntity *pEntity, Vector &vecAim )
{
vecAim = pEntity->edict()->GetCollideable()->GetCollisionOrigin();
// TODO
if ( pEntity->MyCombatCharacterPointer() )
vecAim.z += HalfHumanHeight;
}
bool CBot::GetBodyPartPosition( CBaseAnimating *pEntity, BodyPart part, Vector &vecPosition )
{
if ( !pEntity )
return false;
// La ubicación del pie
if ( part == FEET )
{
vecPosition = pEntity->GetAbsOrigin();
vecPosition.z += 5.0f;
return true;
}
CStudioHdr *studioHdr = pEntity->GetModelPtr();
if ( !studioHdr )
return false;
mstudiohitboxset_t *set = studioHdr->pHitboxSet( pEntity->GetHitboxSet() );
if ( !set )
return false;
QAngle angles;
mstudiobbox_t *box;
// Obtenemos la información con los huesos de la entidad
BodyInfo_t pInfo = GetBodyInfo( pEntity );
int hitbox = pInfo.m_iHeadBone;
// Seleccionamos la ID del hueso solicitado
switch ( part )
{
case HEAD:
{
hitbox = pInfo.m_iHeadBone;
break;
}
case GUST:
{
hitbox = pInfo.m_iGust;
break;
}
case LEFT_ARM:
{
hitbox = pInfo.m_iLeftArm;
break;
}
case RIGHT_ARM:
{
hitbox = pInfo.m_iRightArm;
break;
}
case LEFT_FOOT:
{
hitbox = pInfo.m_iLeftFoot;
break;
}
case RIGHT_FOOT:
{
hitbox = pInfo.m_iRightFoot;
break;
}
}
// Obtenemos la posición del Hueso
box = set->pHitbox( hitbox );
pEntity->GetBonePosition( box->bone, vecPosition, angles );
vecPosition.z -= 5;
return true;
}
BodyInfo_t CBot::GetBodyInfo( CBaseEntity *pEntity )
{
BodyInfo_t pSurvivor;
pSurvivor.m_iHeadBone = 1;
pSurvivor.m_iGust = 2;
pSurvivor.m_iLeftArm = 4;
pSurvivor.m_iRightArm = 5;
pSurvivor.m_iLeftFoot = 6;
pSurvivor.m_iRightFoot = 7;
BodyInfo_t pInfected;
pInfected.m_iHeadBone = 10;
pInfected.m_iGust = 8;
pInfected.m_iLeftArm = 11;
pInfected.m_iRightArm = 14;
pInfected.m_iLeftFoot = 1;
pInfected.m_iRightFoot = 7;
return pInfected;
}
BodyPart CBot::GetBodyPartToAim( CBaseEntity *pEntity )
{
if ( !pEntity )
pEntity = GetEnemy();
CBaseAnimating *pAnimEntity = dynamic_cast<CBaseAnimating *>( pEntity );
// No es una entidad válida
if ( !pAnimEntity )
return FEET;
CBaseInWeapon *pWeapon = Owner()->GetActiveInWeapon();
// ¡No tiene arma!
if ( !pWeapon )
return FEET;
BodyPart part = FEET;
switch ( m_iSkill )
{
case BOT_SKILL_EASY:
part = (BodyPart)RandomInt(2,6); // LEFT_ARM > FEET
break;
case BOT_SKILL_NORMAL:
part = (BodyPart)RandomInt(1,6); // GUST > FEET
break;
case BOT_SKILL_HARD:
part = (BodyPart)RandomInt(0,5); // HEAD > RIGHT_FOOT
break;
case BOT_SKILL_ULTRA_HARD:
part = (BodyPart)RandomInt(0,1); // HEAD | GUST
break;
}
// Obtenemos la posición de la parte del cuerpo
Vector vecPosition;
GetBodyPartPosition( pAnimEntity, part, vecPosition );
// Esta parte no es visible
if ( !Owner()->FVisible(vecPosition) )
{
// Probamos con cada parte del cuerpo
for ( int i = 0; i < LAST_BODY_PART; ++i )
{
vecPosition.Invalidate();
GetBodyPartPosition( pAnimEntity, (BodyPart)i, vecPosition );
if ( Owner()->FVisible(vecPosition) )
return (BodyPart)i;
}
return FEET;
}
return part;
}
void CBot::LookAt( CBaseEntity *pEntity, ActionPriority priority )
{
if ( !pEntity )
priority = PRI_NONE;
else
{
// Ya estamos mirando a esta entidad
if ( pEntity == m_pLookAt.Get() )
return;
}
// Estamos mirando otra cosa con mayor prioridad
if ( m_iLookPriority > priority && pEntity )
return;
m_pLookAt = pEntity;
m_iLookPriority = priority;
}
void CBot::LookAt( const Vector &vecPosition, ActionPriority priority )
{
Vector vecDestination( vecPosition );
vecDestination -= Owner()->EarPosition();
// Transformamos Vector a QAngle
QAngle destination;
VectorAngles( vecDestination, destination );
// Apuntamos
LookAt( destination, priority );
}
void CBot::LookAt( const QAngle &lookAt, ActionPriority priority )
{
// Ya estamos mirando a este lugar
if ( m_lookAt == lookAt )
return;
// Estamos mirando otra cosa con mayor prioridad
if ( m_iLookPriority > priority )
return;
m_lookAt = lookAt;
m_pLookAt = NULL;
m_iLookPriority = priority;
// Necesitamos apuntar
SetNeedAim();
}
void CBot::UpdateEntityAim()
{
if ( !IsAimingEntity() )
return;
CBaseEntity *pEntity = GetAimingEntity();
// Transformamos la entidad a un "CBaseAnimating"
CBaseAnimating *pAnimating = dynamic_cast<CBaseAnimating *>( pEntity );
Vector vecPosition;
if ( pEntity == GetEnemy() && HasCondition(COND_BOT_LOST_ENEMY) )
{
if ( !GetLastEnemyPosition( vecPosition, pEntity ) )
{
LookAt( NULL );
return;
}
}
else if ( pAnimating )
{
GetBodyPartPosition( pAnimating, GetBodyPartToAim(pAnimating), vecPosition );
}
else
{
GetAimCenter( pEntity, vecPosition );
}
Vector vecDestination( vecPosition );
vecDestination -= Owner()->EarPosition();
// Transformamos Vector a QAngle
VectorAngles( vecDestination, m_lookAt );
// Necesitamos apuntar
SetNeedAim();
}
void CBot::UpdateAim()
{
// Estamos apuntando a una entidad
if ( IsAimingEntity() )
UpdateEntityAim();
// Estamos apuntando al lugar deseado
if ( m_lookAt == GetLastUserCommand()->viewangles )
return;
QAngle lookAt( m_lookAt );
// Es necesario simular el movimiento de mouse al apuntar
if ( m_bNeedAim )
{
// Obtenemos los frames que faltan para terminar de apuntar
float timeLeft = m_flEndAimTime - gpGlobals->curtime;
int framesLeft = (int)( 60.0f * timeLeft );
// Aún faltan frames, apuntamos poco a poco... (humanamente)
if ( framesLeft > 0 )
{
Utils::GetAngleDifference( m_nCmd.viewangles, lookAt, lookAt );
lookAt /= framesLeft;
m_nCmd.viewangles += lookAt;
}
else
{
// Hemos terminado de apuntar
m_bNeedAim = false;
}
}
Utils::DeNormalizeAngle( m_nCmd.viewangles.x );
Utils::DeNormalizeAngle( m_nCmd.viewangles.y );
}
void CBot::SetNeedAim()
{
if ( m_bNeedAim )
return;
m_bNeedAim = true;
m_flEndAimTime = gpGlobals->curtime + GetEndAimTime();
}
void CBot::UpdateLookAt()
{
// Miramos al enemigo
if ( GetEnemy() )
{
LookAt( GetEnemy() );
return;
}
// Miramos el destino
if ( HasGoal() )
{
LookAt( m_pNavPath.GetEndpoint() );
return;
}
if ( RandomInt(0,10) == 1 )
{
// Miramos a una ubicación al azar
float angleDelta = RandomInt( -180, 180 );
QAngle angle = Owner()->GetLocalAngles();
angle.x = RandomInt( -30, 30 );
angle.z = m_nCmd.viewangles.z;
angle.y = angleDelta;
LookAt( angle );
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment