2
// C++ Implementation: bot
6
// Contains code of the base bot class
8
// Author: Rick <rickhelmus@gmail.com>
16
vector<botent *> bots;
18
extern int triggertime;
19
extern itemstat itemstats[];
20
extern ENetHost *clienthost;
22
const vec g_vecZero(0, 0, 0);
28
// Delete all waypoints
33
while (m_WaypointList[i][j].Empty() == false)
34
delete m_WaypointList[i][j].Pop();
41
// Init all bot variabeles
42
spawnplayer(m_pMyEnt);
44
m_pMyEnt->targetyaw = m_pMyEnt->targetpitch = 0.0f;
45
m_pMyEnt->enemy = NULL;
46
m_pMyEnt->maxspeed = 22.0f;
47
m_pMyEnt->pBot = this;
49
m_eCurrentBotState = STATE_NORMAL;
50
m_iShootDelay = m_iChangeWeaponDelay = 0;
52
m_vPrevOrigin = g_vecZero;
53
m_iStuckCheckDelay = lastmillis + 250;
56
m_iStrafeTime = m_iStrafeCheckDelay = 0;
57
m_iMoveDir = DIR_NONE;
62
m_iEnemySearchDelay = 0;
64
m_bCombatJump = false;
65
m_iCombatJumpDelay = 0;
66
m_bShootAtFeet = (RandomLong(1, 100) <= m_pBotSkill->sShootAtFeetWithRLPercent);
68
m_vHuntLocation = m_vPrevHuntLocation = g_vecZero;
70
m_fPrevHuntDist = 0.0f;
71
m_iHuntLastTurnLessTime = m_iHuntPlayerUpdateTime = m_iHuntPauseTime = 0;
72
m_iLookAroundDelay = m_iLookAroundTime = m_iLookAroundUpdateTime = 0;
73
m_fLookAroundYaw = 0.0f;
78
while(!m_UnreachableEnts.Empty()) delete m_UnreachableEnts.Pop();
79
m_iCheckTeleporterDelay = m_iCheckJumppadsDelay = 0;
80
m_iCheckEntsDelay = 0;
81
m_iCheckTriggersDelay = 0;
82
m_iLookForWaypointTime = 0;
85
m_fYawToTurn = m_fPitchToTurn = 0.0f;
87
m_vGoal = m_vWaterGoal = g_vecZero;
98
if (m_pMyEnt->state == CS_DEAD)
100
if(lastmillis-m_pMyEnt->lastaction<1200)
103
moveplayer(m_pMyEnt, 1, true);
105
else if (!m_arena && lastmillis-m_pMyEnt->lastaction>5000)
114
TLinkedList<unreachable_ent_s*>::node_s *p = m_UnreachableEnts.GetFirst(), *tmp;
117
if ((lastmillis - p->Entry->time) > 3500)
122
m_UnreachableEnts.DeleteNode(tmp);
128
if (!BotManager.IdleBots())
137
// Aim to ideal yaw and pitch
140
// Store current location, to see if the bot is stuck
141
m_vPrevOrigin = m_pMyEnt->o;
143
// Don't check for stuck if the bot doesn't want to move
144
if (!m_pMyEnt->move && !m_pMyEnt->strafe)
145
m_iStuckCheckDelay = max(m_iStuckCheckDelay, lastmillis+100.0f);
148
moveplayer(m_pMyEnt, 1, true);
150
// Update bot info on all clients
154
void CBot::AimToVec(const vec &o)
156
m_pMyEnt->targetpitch = atan2(o.z-m_pMyEnt->o.z, GetDistance(o))*180/PI;
157
m_pMyEnt->targetyaw = -(float)atan2(o.x - m_pMyEnt->o.x, o.y -
158
m_pMyEnt->o.y)/PI*180+180;
161
void CBot::AimToIdeal()
163
if (m_iAimDelay > lastmillis)
166
float MaxXSpeed = RandomFloat(m_pBotSkill->flMinAimXSpeed,
167
m_pBotSkill->flMaxAimXSpeed);
168
float MaxYSpeed = RandomFloat(m_pBotSkill->flMinAimYSpeed,
169
m_pBotSkill->flMaxAimYSpeed);
170
float XOffset = RandomFloat(m_pBotSkill->flMinAimXOffset,
171
m_pBotSkill->flMaxAimXOffset);
172
float YOffset = RandomFloat(m_pBotSkill->flMinAimYOffset,
173
m_pBotSkill->flMaxAimYOffset);
174
float RealXOffset, RealYOffset;
175
float AimXSpeed = MaxXSpeed, AimYSpeed = MaxYSpeed;
176
float XDiff = fabs(m_pMyEnt->targetpitch - m_pMyEnt->pitch);
177
float YDiff = fabs(m_pMyEnt->targetyaw - m_pMyEnt->yaw);
179
// How higher the diff, how higher the offsets and aim speed
183
if (RandomLong(0, 1))
184
RealXOffset = XDiff * (XOffset / 100.0f);
186
RealXOffset = -(XDiff * (XOffset / 100.0f));
193
if (RandomLong(0, 1))
194
RealYOffset = YDiff * (YOffset / 100.0f);
196
RealYOffset = -(YDiff * (YOffset / 100.0f));
203
AimXSpeed = (AimXSpeed * (XDiff / 80.0f)) + (AimXSpeed * 0.25f);
208
AimYSpeed = (AimYSpeed * (YDiff / 70.0f)) + (AimYSpeed * 0.25f);
212
m_fPitchToTurn = fabs((m_pMyEnt->targetpitch + RealXOffset) - m_pMyEnt->pitch);
213
m_fYawToTurn = fabs((m_pMyEnt->targetyaw + RealYOffset) - m_pMyEnt->yaw);
215
float flIdealPitch = ChangeAngle(AimXSpeed, m_pMyEnt->targetpitch + RealXOffset, m_pMyEnt->pitch);
216
float flIdealYaw = ChangeAngle(AimYSpeed, m_pMyEnt->targetyaw + RealYOffset, m_pMyEnt->yaw);
218
// m_pMyEnt->pitch = WrapXAngle(m_pMyEnt->targetpitch); // Uncomment for instant aiming
219
// m_pMyEnt->yaw = WrapYZAngle(m_pMyEnt->targetyaw);
221
m_pMyEnt->pitch = WrapXAngle(flIdealPitch);
222
m_pMyEnt->yaw = WrapYZAngle(flIdealYaw);
225
// Function code by Botman
226
float CBot::ChangeAngle(float speed, float ideal, float current)
228
float current_180; // current +/- 180 degrees
231
// find the difference in the current and ideal angle
232
diff = fabs(current - ideal);
234
// speed that we can turn during this frame...
235
speed = speed * (float(BotManager.m_iFrameTime)/1000.0f);
237
// check if difference is less than the max degrees per turn
239
speed = diff; // just need to turn a little bit (less than max)
241
// check if the bot is already facing the idealpitch direction...
245
if ((current >= 180) && (ideal >= 180))
252
else if ((current >= 180) && (ideal < 180))
254
current_180 = current - 180;
256
if (current_180 > ideal)
261
else if ((current < 180) && (ideal >= 180))
263
current_180 = current + 180;
265
if (current_180 > ideal)
270
else // (current < 180) && (ideal < 180)
282
void CBot::SendBotInfo()
284
if(lastmillis-m_iLastBotUpdate<40) return; // don't update faster than 25fps
285
m_iLastBotUpdate = lastmillis;
288
float CBot::GetDistance(const vec &o)
290
return o.dist(m_pMyEnt->o);
293
float CBot::GetDistance(const vec &v1, const vec &v2)
298
float CBot::GetDistance(entity *e)
300
vec v(e->x, e->y, e->z);
301
return v.dist(m_pMyEnt->o);
304
bool CBot::SelectGun(int Gun)
306
if(m_pMyEnt->weaponsel->reloading) return false;
307
if (m_pMyEnt->gunselect != Gun) playsound(S_GUNCHANGE, m_pMyEnt);
308
m_pMyEnt->gunselect = Gun;
312
bool CBot::IsVisible(entity *e, bool CheckPlayers)
314
vec v(e->x, e->y, e->z);
315
return ::IsVisible(m_pMyEnt->o, v, (CheckPlayers) ? m_pMyEnt : NULL);
318
bool CBot::IsVisible(vec o, int Dir, float flDist, bool CheckPlayers, float *pEndDist)
320
static vec angles, end, forward, right, up;
321
static traceresult_s tr;
324
angles = GetViewAngles();
328
angles.x = WrapXAngle(angles.x + 45.0f);
330
angles.x = WrapXAngle(angles.x - 45.0f);
332
if ((Dir & FORWARD) || (Dir & BACKWARD))
335
angles.y = WrapYZAngle(angles.y + 180.0f);
340
angles.y = WrapYZAngle(angles.y - 45.0f);
342
angles.y = WrapYZAngle(angles.y + 45.0f);
344
else if (Dir & RIGHT)
347
angles.y = WrapYZAngle(angles.y + 45.0f);
349
angles.y = WrapYZAngle(angles.y - 45.0f);
353
angles.y = WrapYZAngle(angles.y - 90.0f);
354
else if (Dir & RIGHT)
355
angles.y = WrapYZAngle(angles.y + 90.0f);
357
angles.x = WrapXAngle(angles.x + 90.0f);
359
angles.x = WrapXAngle(angles.x - 90.0f);
361
AnglesToVectors(angles, forward, right, up);
366
TraceLine(o, end, m_pMyEnt, CheckPlayers, &tr);
369
*pEndDist = GetDistance(o, tr.end);
374
void CBot::SetMoveDir(int iMoveDir, bool add)
376
if (iMoveDir & FORWARD)
378
else if (m_iMoveDir & BACKWARD)
384
m_pMyEnt->strafe = 1;
385
else if (m_iMoveDir & RIGHT)
386
m_pMyEnt->strafe = -1;
388
m_pMyEnt->strafe = 0;
391
m_pMyEnt->jumpnext = true;
394
// Used when switching to another task/state
395
void CBot::ResetCurrentTask()
397
switch (m_eCurrentBotState)
400
m_pMyEnt->enemy = NULL;
402
m_iCombatNavTime = m_iMoveDir = 0;
403
m_bCombatJump = false;
411
m_iSPMoveTime = m_iMoveDir = 0;
416
m_iStrafeTime = m_iMoveDir = 0;