Cube bot, main think function:
Code:
void CBot::Think()
{
if (intermission)
return;
// Bot is dead?
if (m_pMyEnt->state == CS_DEAD)
{
if(lastmillis-m_pMyEnt->lastaction<1200)
{
m_pMyEnt->move = 0;
moveplayer(m_pMyEnt, 1, false);
}
else if (!m_arena)
Spawn();
return;
}
CheckItems();
CheckQuad(curtime);
// Basic AI
if (!BotManager.IdleBots())
{
// Default bots will run forward
m_pMyEnt->move = 1;
// Default bots won't strafe
m_pMyEnt->strafe = 0;
if (!BotManager.BotsShoot() && m_pMyEnt->enemy)
m_pMyEnt->enemy = NULL;
// Find enemy
if (BotManager.BotsShoot() && FindEnemy())
{
// Shoot at enemy
ShootEnemy();
}
// Navigate
HomeThroughMap();
}
else
m_pMyEnt->move = 0;
// Aim to ideal yaw and pitch
AimToIdeal();
// Store current location, to see if the bot is stuck
m_vPrevOrigin = m_pMyEnt->o;
// Move the bot
moveplayer(m_pMyEnt, 1, false);
// Update bot info on all clients
SendBotInfo();
}
My favourite template

(esf & cube bot)
Code:
template <class C> class TMultiChoice
{
struct SMultiChoice
{
int MinVal;
int MaxVal;
C Choice;
SMultiChoice(void) : MinVal(0), MaxVal(0){};
};
int TotalVal;
TLinkedList<SMultiChoice*> *pChoiceList;
public:
TMultiChoice(void) : TotalVal(0) // Constructor
{
pChoiceList = new TLinkedList<SMultiChoice*>;
};
~TMultiChoice(void) // Destructor
{
while(pChoiceList->Empty() == false)
{
SMultiChoice *pEntry = pChoiceList->Pop();
if (pEntry)
delete pEntry;
else
break;
}
delete pChoiceList;
pChoiceList = NULL;
}
void Insert(C Choice, short Percent = 50)
{
if (Percent == 0)
return;
SMultiChoice *pChoiceEntry = new SMultiChoice;
pChoiceEntry->MinVal = TotalVal;
pChoiceEntry->MaxVal = TotalVal + Percent;
pChoiceEntry->Choice = Choice;
pChoiceList->AddNode(pChoiceEntry);
TotalVal += Percent;
};
bool FindSelection(SMultiChoice *MS, int Choice)
{
if ((Choice >= MS->MinVal) && (Choice < MS->MaxVal))
{
return true;
}
return false;
}
void ClearChoices(void)
{
TotalVal = 0;
while(pChoiceList->Empty() == false)
delete pChoiceList->Pop();
}
bool GetSelection(C &Var)
{
int Choice = RandomLong(0, (TotalVal - 1));
TLinkedList<SMultiChoice*>::node_s *pNode = pChoiceList->GetFirst();
while(pNode)
{
if ((Choice >= pNode->Entry->MinVal) && (Choice < pNode->Entry->MaxVal))
{
Var = pNode->Entry->Choice;
return true;
}
pNode = pNode->next;
}
return false;
}
};
Used if there are things to select, like weapons, where each choice has a different score. For example:
Code:
TMultiChoice WeaponChoices;
WeaponChoices.Insert(GUN_FIST, 20);
WeaponChoices.Insert(GUN_RIFLE, 50); // Higher chance for rifle
Here something new in the cube bot: used when bots have an enemy and still want an item(ammo etc). They will strafe to it but keep aiming(and shooting) at their enemy.
Code:
vec v = { m_pTargetEnt->x, m_pTargetEnt->y,
S(m_pTargetEnt->x, m_pTargetEnt->y)->floor+m_pMyEnt->eyeheight };
vec v2, forward, right, up, cross;
float flDot;
AnglesToVectors(GetViewAngles(), forward, right, up);
v2 = v;
vsub(v2, m_pMyEnt->o);
v2.z = 0.0f; // Make 2D
v2 = Normalize(v2);
forward.z = 0; // Make 2D
flDot = dotprod(v2 , forward);
cross = CrossProduct(v2, forward);
bool IsLeft = (cross.z < -0.1f);
bool IsRight = (cross.z > 0.1f);
bool IsBehind = (flDot < 0.1f);
bool IsInFront = (flDot > 0.1f);
particle_trail(1, 500, m_pMyEnt->o, v);
EDirection eMoveDir = FORWARD;
if (IsInFront && !IsLeft && !IsRight) // ent is straight forward
{
eMoveDir = FORWARD;
m_pMyEnt->move = m_iMoveDir = 1; // move forward
m_pMyEnt->strafe = m_iStrafeDir = 0; // Don't strafe
}
else if (IsBehind && !IsLeft && !IsRight) // Ent is straight behind bot
{
eMoveDir = BACKWARD;
m_pMyEnt->move = m_iMoveDir = -1; // Move backward
m_pMyEnt->strafe = m_iStrafeDir = 0; // Don't strafe
}
else if (!IsBehind && !IsInFront && IsLeft) // Ent is straight left
{
eMoveDir = LEFT;
m_pMyEnt->move = m_iMoveDir = 0; // don't move back or forward
m_pMyEnt->strafe = m_iStrafeDir = -1; // Strafe left
}
else if (!IsBehind && !IsInFront && IsRight) // Ent is straight right
{
eMoveDir = RIGHT;
m_pMyEnt->move = m_iMoveDir = 0; // don't move back or forward
m_pMyEnt->strafe = m_iStrafeDir = 1; // Strafe right
}
else if (IsInFront && IsLeft) // Ent is forward-left
{
eMoveDir = FORWARD_LEFT;
m_pMyEnt->move = m_iMoveDir = 1; // Move forward
m_pMyEnt->strafe = m_iStrafeDir = -1; // Strafe left
}
else if (IsInFront && IsRight) // Ent is forward-right
{
eMoveDir = FORWARD_RIGHT;
m_pMyEnt->move = m_iMoveDir = 1; // Move forward
m_pMyEnt->strafe = m_iStrafeDir = 1; // Strafe right
}
else if (IsBehind && IsLeft) // ent is backward-left
{
eMoveDir = BACKWARD_LEFT;
m_pMyEnt->move = m_iMoveDir = -1; // Move backward
m_pMyEnt->strafe = m_iStrafeDir = -1; // Strafe left
}
else if (IsBehind && IsRight) // ent is backward-right
{
eMoveDir = BACKWARD_RIGHT;
m_pMyEnt->move = m_iMoveDir = -1; // Move backward
m_pMyEnt->strafe = m_iStrafeDir = 1; // Strafe right
}
m_iCombatNavTime = lastmillis + RandomLong(125, 250);
// Check if bot needs to jump
vec from = m_pMyEnt->o;
from.z -= 1.0f;
if (!IsVisible(from, eMoveDir, 3.0f, false))
m_pMyEnt->jumpnext = true;
Aiming in cube bot(maths obviously not by me

)
Code:
void CBot::AimToVec(const vec &o)
{
m_pMyEnt->targetpitch = atan2(o.z-m_pMyEnt->o.z, GetDistance(o))*180/PI;
m_pMyEnt->targetyaw = -(float)atan2(o.x - m_pMyEnt->o.x, o.y -
m_pMyEnt->o.y)/PI*180+180;
}
Handy for rocketlaunchers:
Code:
// Prediction:
// - pos: Current position
// - vel: Current velocity
// - Time: In seconds, predict how far it is after Time seconds
vec PredictPos(vec pos, vec vel, float Time)
{
float flVelLength = sqrt(vel.x*vel.x + vel.y*vel.y + vel.z*vel.z);
if (flVelLength <= 1.0)
return pos; // don't bother with low velocities...
float speed = flVelLength * Time;
float flTemp = 1/flVelLength;
vec vecNormalize;
vecNormalize.x = vel.x * flTemp;
vecNormalize.y = vel.y * flTemp;
vecNormalize.z = vel.z * flTemp;
vec v_src = pos;
vmul(vecNormalize, speed);
vec v_end = v_src;
vadd(v_end, vecNormalize);
return v_end;
}
A* Function, was pretty happy when it was done:
Code:
// return true when done calculating
bool CBot::AStar()
{
if (!m_pCurrentGoalWaypoint || !m_pCurrentWaypoint)
{
m_bCalculatingAStarPath = false;
return true;
}
// Ideas by PMB :
// * Make locals static to speed up a bit
// * MaxCycles per frame and make it fps dependent
static int iMaxCycles;
static int iCurrentCycles;
static float newg;
static waypoint_s *n, *n2;
static TLinkedList<waypoint_s *>::node_s *pPath = NULL;
iMaxCycles = 10 * BotManager.m_iFrameTime;
iCurrentCycles = 0;
if (!m_bCalculatingAStarPath)
{
m_pCurrentWaypoint->g = 0.0f;
m_pCurrentWaypoint->f = m_pCurrentWaypoint->g + GetDistance(m_pCurrentGoalWaypoint->v_origin);
m_pCurrentWaypoint->pParent = NULL;
m_AStarOpenList.Clear();
m_AStarClosedList.DeleteAllNodes();
m_AStarOpenList.AddEntry(m_pCurrentWaypoint, m_pCurrentWaypoint->f);
m_AStarNodeList.DeleteAllNodes();
}
while(!m_AStarOpenList.Empty())
{
if (iCurrentCycles >= iMaxCycles)
{
m_bCalculatingAStarPath = true;
return false;
}
n = m_AStarOpenList.Pop();
// Done with calculating
if (n == m_pCurrentGoalWaypoint)
{
while(n)
{
m_AStarNodeList.PushNode(n);
n = n->pParent;
}
m_AStarOpenList.Clear();
m_AStarClosedList.DeleteAllNodes();
m_bCalculatingAStarPath = false;
return true;
}
pPath = n->ConnectedWPs.GetFirst();
while(pPath)
{
n2 = pPath->Entry;
newg = AStarCost(n, n2);
if ((n2->g <= newg) &&
((m_AStarClosedList.IsInList(n2) || m_AStarOpenList.IsInList(n2, n2->f))))
{
pPath = pPath->next;
continue;
}
n2->pParent = n;
n2->g = newg;
n2->f = n2->g + GetDistance(n2->v_origin, m_pCurrentGoalWaypoint->v_origin);
m_AStarClosedList.DeleteEntry(n2);
if (!m_AStarOpenList.IsInList(n2, n2->f))
{
m_AStarOpenList.AddEntry(n2, n2->f);
}
pPath = pPath->next;
}
m_AStarClosedList.PushNode(n);
iCurrentCycles++;
}
// Failed making path
conoutf("Path failed");
m_AStarOpenList.Clear();
m_AStarClosedList.DeleteAllNodes();
m_bCalculatingAStarPath = false;
return true;
}
And I saw this from a n00b somewhere at a forum
Code:
int blah=0;
blah++;
blah++;
blah++;
blah++;
As usual most code is inspired by PMB, he has some nice ideas *hugs*