bot_turntovalidforward.c
#ifdef ROBOCLIENT
class BotTurnToValidForward extends BotStateBase
{
private int m_AngleCheck = 5; //5 degree incremental checks
private float m_TurnRate = 2;
private bool m_FoundDirection = false;
private vector m_ValidDirection = vector.Zero;
private float m_TurnDirection = 1;
private float m_MinAngle = 500;
void BotTurnToValidForward(Bot bot = NULL, BotStateBase parent = NULL)
{
}
override void OnEntry (BotEventBase e)
{
super.OnEntry(e);
m_ValidDirection = m_Owner.GetDirection();
m_FoundDirection = false;
m_MinAngle = 500;
m_TurnRate = 2;
#ifdef INPUT_OVERRIDE
g_Game.GetPlayer().GetInputInterface().SyncedRemoveOverride_ID(UAAimLeft);
g_Game.GetPlayer().GetInputInterface().SyncedRemoveOverride_ID(UAAimRight);
#endif
}
override void OnExit (BotEventBase e)
{
super.OnExit(e);
#ifdef INPUT_OVERRIDE
g_Game.GetPlayer().GetInputInterface().SyncedRemoveOverride_ID(UAAimLeft);
g_Game.GetPlayer().GetInputInterface().SyncedRemoveOverride_ID(UAAimRight);
#endif
}
BotEventBase GetNextEvent()
{
if (m_Bot.m_Target && m_Bot.m_Target.IsAlive())
return m_Bot.__Atkd__;
else
return m_Bot.__VaFw__;
}
override void OnUpdate (float dt)
{
if (!m_FoundDirection)
{
vector m_OwnerPosition = m_Owner.GetPosition();
vector m_WaterPositionCheck = m_OwnerPosition + m_Owner.GetDirection() * 3;
if (GetGame().SurfaceIsSea(m_WaterPositionCheck[0], m_WaterPositionCheck[2]))
{
m_TurnDirection = 1;
m_ValidDirection = -m_Owner.GetDirection();
m_FoundDirection = true;
}
else
{
const vector raycastHeight = "0 0.75 0"; //raycast from a higher point than the feet
const float startPosOffset = 0.1; //offset for some issues with vaulting
const float raycastDist = 0.8;
const float raycastSphereRadius = 0.3;
vector startPos = m_OwnerPosition + raycastHeight + startPosOffset * m_Owner.GetDirection();
vector endPos = m_OwnerPosition + raycastHeight + raycastDist * m_Owner.GetDirection();
vector hitPosition, hitNormal;
float hitFraction;
Object hitObject = null;
PhxInteractionLayers collisionMask = PhxInteractionLayers.DEFAULT | PhxInteractionLayers.BUILDING | PhxInteractionLayers.CHARACTER | PhxInteractionLayers.DOOR | PhxInteractionLayers.DYNAMICITEM | PhxInteractionLayers.FENCE | PhxInteractionLayers.WORLDBOUNDS | PhxInteractionLayers.VEHICLE | PhxInteractionLayers.WATERLAYER;
int leftStreak = 0;
int rightStreak = 0;
int rotationsAvailable = (360 / m_AngleCheck) / 2 + 1;
float lastResortTurnDirection = 0;
vector lastResortDirection = vector.Zero;
for (int i = 1; i < rotationsAvailable; i++)
{
vector newLeftDirection = vector.RotateAroundZeroDeg(m_Owner.GetDirection(), vector.Up, -m_AngleCheck * i);
vector newRightDirection = vector.RotateAroundZeroDeg(m_Owner.GetDirection(), vector.Up, m_AngleCheck * i);
vector leftEndPos = startPos + newLeftDirection * 3;
vector rightEndPos = startPos + newRightDirection * 3;
//looking for 2 consecutive valid raycast checks
bool resLeft = DayZPhysics.SphereCastBullet(startPos, leftEndPos, raycastSphereRadius, collisionMask, m_Owner, hitObject, hitPosition, hitNormal, hitFraction);
if (!resLeft)
{
leftStreak++;
lastResortTurnDirection = -1;
lastResortDirection = newLeftDirection;
if (leftStreak == 2)
{
m_ValidDirection = vector.RotateAroundZeroDeg(m_Owner.GetDirection(), vector.Up, -(m_AngleCheck * (i - 1) + m_AngleCheck / 2));
m_TurnDirection = -1;
m_FoundDirection = true;
break;
}
}
else
leftStreak = 0;
bool resRight = DayZPhysics.SphereCastBullet(startPos, rightEndPos, raycastSphereRadius, collisionMask, m_Owner, hitObject, hitPosition, hitNormal, hitFraction);
if (!resRight)
{
rightStreak++;
lastResortTurnDirection = 1;
lastResortDirection = newRightDirection;
if (rightStreak == 2)
{
m_ValidDirection = vector.RotateAroundZeroDeg(m_Owner.GetDirection(), vector.Up, m_AngleCheck * (i - 1) + m_AngleCheck / 2);
m_TurnDirection = 1;
m_FoundDirection = true;
break;
}
}
else
rightStreak = 0;
if (!m_FoundDirection)
{
m_TurnDirection = lastResortTurnDirection;
m_ValidDirection = lastResortDirection;
m_FoundDirection = true;
}
}
}
}
if (!m_FoundDirection)
{
m_Bot.ProcessEvent(GetNextEvent());
return;
}
float prod = m_Owner.GetDirection().Length() * m_ValidDirection.Length();
if (prod == 0)
{
m_Bot.ProcessEvent(GetNextEvent());
return;
}
float dot = vector.Dot(m_Owner.GetDirection(), m_ValidDirection);
float angle = Math.Acos(dot / prod);
angle = Math.RAD2DEG * angle;
if (angle < 3 || angle > m_MinAngle + 0.5)
{
m_Bot.ProcessEvent(GetNextEvent());
return;
}
m_MinAngle = Math.Min(angle, m_MinAngle);
float slowDown = 1;
if (angle < 30)
slowDown = angle / 30;
slowDown = Math.Clamp(slowDown, 0.2, 1);
int inputID = UAAimLeft;
if (m_TurnDirection > 0)
inputID = UAAimRight;
#ifdef INPUT_OVERRIDE
g_Game.GetPlayer().GetInputInterface().SyncedOverride_ID(inputID, m_TurnDirection * m_TurnRate * slowDown, OverrideInputType.HOLD, false);
#endif
super.OnUpdate(dt);
}
}
#endif