Skip to content

Commit 0fcf764

Browse files
committed
Added more safety checks
Fix multiple bot issues and harden null/overflow handling: - bot.cpp: Correct caltrop classname check to match deployed entity, add jump + strafing avoidance (skill-gated) to prevent bots landing on caltrop clusters. Zero-initialize c_class and return early for unknown class ids to avoid issuing empty commands. - bot_combat.cpp: Guard reads from pDelay with null checks to avoid dereferencing a null pointer when computing firing delays. - dll.cpp: Hoist and combine euser1 null checks to avoid dereferencing null pointers during camera traces and vector setup. Fix RoleStatus index typo (set team 2 instead of 3). Replace patterns of snprintf into a temp buffer followed by strcpy with direct snprintf into curr->ifs to prevent unnecessary copying and potential buffer issues. Overall these changes fix crashes, a logic bug, and improve bot avoidance behavior around caltrops.
1 parent 87e3ac8 commit 0fcf764

3 files changed

Lines changed: 45 additions & 33 deletions

File tree

bot.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2703,10 +2703,30 @@ static void BotGrenadeAvoidance(bot_t* pBot) {
27032703
}
27042704
}
27052705
}
2706-
else if (std::strncmp("tf_weapon_caltrop", classname, 29) == 0 && pBot->bot_skill < 3) {
2706+
// Deployed caltrops use the entity name "tf_weapon_caltropgrenade".
2707+
// The old check looked for "tf_weapon_caltrop" with a 29-byte strncmp,
2708+
// which only matches the exact 17-char string and therefore never
2709+
// triggered against the real grenade entity (PVS-style dead branch).
2710+
// Now match both the prefix and broaden the skill gate so that
2711+
// average-skill bots also try to avoid the speed penalty by sidestepping
2712+
// around or jumping over the cluster. [APG]RoboCop[CL]
2713+
else if (std::strncmp("tf_weapon_caltrop", classname, 17) == 0) {
27072714
entity_origin = pent->v.origin;
2708-
if (FInViewCone(entity_origin, pBot->pEdict) && FVisible(entity_origin, pBot->pEdict))
2715+
if (FInViewCone(entity_origin, pBot->pEdict) && FVisible(entity_origin, pBot->pEdict)) {
2716+
// jump over the immediate cluster
27092717
pBot->pEdict->v.button |= IN_JUMP;
2718+
2719+
// also strafe sideways so the bot doesn't land in the same pile.
2720+
// Skill 1-3 (better bots) sidestep; skill 4-5 just jumps.
2721+
if (pBot->bot_skill <= 3) {
2722+
UTIL_MakeVectors(pBot->pEdict->v.v_angle);
2723+
const Vector toCaltrop = entity_origin - pBot->pEdict->v.origin;
2724+
const float dotR = DotProduct(toCaltrop, gpGlobals->v_right);
2725+
// strafe away from the caltrop along the right vector
2726+
pBot->f_side_speed = (dotR > 0.0f) ? -pBot->f_max_speed : pBot->f_max_speed;
2727+
pBot->strafe_mod = STRAFE_MOD_NORMAL;
2728+
}
2729+
}
27102730
}
27112731
}
27122732

@@ -3314,7 +3334,8 @@ static void BotPickNewClass(bot_t* pBot) {
33143334
return;
33153335

33163336
// name the class the bot wishes to use and change to it
3317-
char c_class[16];
3337+
// (zero-initialised so an unhandled new_class can't pass garbage to FakeClientCommand)
3338+
char c_class[16] = {0};
33183339
switch (new_class) {
33193340
case 1:
33203341
std::strcpy(c_class, "scout");
@@ -3344,7 +3365,7 @@ static void BotPickNewClass(bot_t* pBot) {
33443365
std::strcpy(c_class, "engineer");
33453366
break;
33463367
default:
3347-
break;
3368+
return; // unknown class id - don't issue an empty change-class command
33483369
}
33493370
pBot->bot_class = new_class;
33503371
FakeClientCommand(pBot->pEdict, c_class, nullptr, nullptr);

bot_combat.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,9 +1672,10 @@ bool BotFireWeapon(const Vector &v_enemy, bot_t *pBot, const int weapon_choice)
16721672
while (pSelect[select_index].iId && pSelect[select_index].iId != iId)
16731673
select_index++;
16741674

1675+
// All three reads now guarded against null pDelay - [APG]RoboCop[CL]
16751676
const float base_delay = pDelay != nullptr ? pDelay[select_index].primary_base_delay : 0.0f;
1676-
const float min_delay = pDelay[select_index].primary_min_delay[pBot->bot_skill];
1677-
const float max_delay = pDelay[select_index].primary_max_delay[pBot->bot_skill];
1677+
const float min_delay = pDelay != nullptr ? pDelay[select_index].primary_min_delay[pBot->bot_skill] : 0.0f;
1678+
const float max_delay = pDelay != nullptr ? pDelay[select_index].primary_max_delay[pBot->bot_skill] : 0.0f;
16781679

16791680
pBot->f_shoot_time = pBot->f_think_time + base_delay + random_float(min_delay, max_delay);
16801681
return true;

dll.cpp

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -936,11 +936,13 @@ int DispatchSpawn(edict_t* pent) {
936936
}
937937

938938
void DispatchThink(edict_t* pent) {
939-
if (FStrEq(STRING(pent->v.classname), "entity_botcam")) {
939+
// hoist the euser1 null check to the top so the trace and
940+
// MakeVectors below it never deref a null pointer - [APG]RoboCop[CL]
941+
if (FStrEq(STRING(pent->v.classname), "entity_botcam") && pent->v.euser1 != nullptr && !FNullEnt(pent->v.euser1)) {
940942
TraceResult tr;
941943
int off_f = 16;
942944
UTIL_MakeVectors(pent->v.euser1->v.v_angle);
943-
if (pent->v.euser1 != nullptr && !FNullEnt(pent->v.euser1) && pent->v.owner != nullptr && !FNullEnt(pent->v.owner)) {
945+
if (pent->v.owner != nullptr && !FNullEnt(pent->v.owner)) {
944946
bot_t* pBot = UTIL_GetBotPointer(pent->v.euser1);
945947

946948
UTIL_TraceLine(pent->v.euser1->v.origin + pent->v.euser1->v.view_ofs + gpGlobals->v_forward * static_cast<float>(off_f), pent->v.euser1->v.origin + pent->v.euser1->v.view_ofs + gpGlobals->v_forward * 4000, ignore_monsters, pent->v.euser1, &tr);
@@ -3239,7 +3241,7 @@ void StartFrame() { // v7 last frame timing
32393241
for (int j = 0; j < 12; j++) {
32403242
i1++;
32413243
buf = buf + 1;
3242-
RoleStatus[3] = 90;
3244+
RoleStatus[2] = 90; // was RoleStatus[3] - typo, green is team 2 - [APG]RoboCop[CL]
32433245
} // move to end
32443246
} // defend
32453247
else if (std::strncmp(buf, "blue_defend", 11) == 0) {
@@ -4396,8 +4398,7 @@ void StartFrame() { // v7 last frame timing
43964398
curr->yellow_av[i2] = -1;
43974399
curr->green_av[i2] = -1;
43984400
}
4399-
snprintf(msg, sizeof(msg), "b_p_%d", pnt);
4400-
std::strcpy(curr->ifs, msg);
4401+
snprintf(curr->ifs, sizeof(curr->ifs), "b_p_%d", pnt);
44014402
}
44024403
else if (std::strncmp(buf, "if_red_point", 12) == 0) {
44034404
// this can only be in a section
@@ -4429,8 +4430,7 @@ void StartFrame() { // v7 last frame timing
44294430
curr->yellow_av[i2] = -1;
44304431
curr->green_av[i2] = -1;
44314432
}
4432-
snprintf(msg, sizeof(msg), "r_p_%d", pnt);
4433-
std::strcpy(curr->ifs, msg);
4433+
snprintf(curr->ifs, sizeof(curr->ifs), "r_p_%d", pnt);
44344434
}
44354435
else if (std::strncmp(buf, "if_green_point", 14) == 0) {
44364436
// this can only be in a section
@@ -4462,8 +4462,7 @@ void StartFrame() { // v7 last frame timing
44624462
curr->yellow_av[i2] = -1;
44634463
curr->green_av[i2] = -1;
44644464
}
4465-
snprintf(msg, sizeof(msg), "g_p_%d", pnt);
4466-
std::strcpy(curr->ifs, msg);
4465+
snprintf(curr->ifs, sizeof(curr->ifs), "g_p_%d", pnt);
44674466
}
44684467
else if (std::strncmp(buf, "if_yellow_point", 15) == 0) {
44694468
// this can only be in a section
@@ -4495,8 +4494,7 @@ void StartFrame() { // v7 last frame timing
44954494
curr->yellow_av[i2] = -1;
44964495
curr->green_av[i2] = -1;
44974496
}
4498-
snprintf(msg, sizeof(msg), "y_p_%d", pnt);
4499-
std::strcpy(curr->ifs, msg);
4497+
snprintf(curr->ifs, sizeof(curr->ifs), "y_p_%d", pnt);
45004498
} // is point<n> NOT availabe?
45014499
else if (std::strncmp(buf, "ifn_blue_point", 14) == 0) {
45024500
// this can only be in a section
@@ -4529,8 +4527,7 @@ void StartFrame() { // v7 last frame timing
45294527
curr->yellow_av[i2] = -1;
45304528
curr->green_av[i2] = -1;
45314529
}
4532-
snprintf(msg, sizeof(msg), "b_pn_%d", pnt);
4533-
std::strcpy(curr->ifs, msg);
4530+
snprintf(curr->ifs, sizeof(curr->ifs), "b_pn_%d", pnt);
45344531
}
45354532
else if (std::strncmp(buf, "ifn_red_point", 13) == 0) {
45364533
// this can only be in a section
@@ -4562,8 +4559,7 @@ void StartFrame() { // v7 last frame timing
45624559
curr->yellow_av[i2] = -1;
45634560
curr->green_av[i2] = -1;
45644561
}
4565-
snprintf(msg, sizeof(msg), "r_pn_%d", pnt);
4566-
std::strcpy(curr->ifs, msg);
4562+
snprintf(curr->ifs, sizeof(curr->ifs), "r_pn_%d", pnt);
45674563
}
45684564
else if (std::strncmp(buf, "ifn_green_point", 15) == 0) {
45694565
// this can only be in a section
@@ -4595,8 +4591,7 @@ void StartFrame() { // v7 last frame timing
45954591
curr->yellow_av[i2] = -1;
45964592
curr->green_av[i2] = -1;
45974593
}
4598-
snprintf(msg, sizeof(msg), "g_pn_%d", pnt);
4599-
std::strcpy(curr->ifs, msg);
4594+
snprintf(curr->ifs, sizeof(curr->ifs), "g_pn_%d", pnt);
46004595
}
46014596
else if (std::strncmp(buf, "ifn_yellow_point", 16) == 0) {
46024597
// this can only be in a section
@@ -4628,8 +4623,7 @@ void StartFrame() { // v7 last frame timing
46284623
curr->yellow_av[i2] = -1;
46294624
curr->green_av[i2] = -1;
46304625
}
4631-
snprintf(msg, sizeof(msg), "y_pn_%d", pnt);
4632-
std::strcpy(curr->ifs, msg);
4626+
snprintf(curr->ifs, sizeof(curr->ifs), "y_pn_%d", pnt);
46334627
}
46344628
// multipoint ifs
46354629
else if (std::strncmp(buf, "if_blue_mpoint", 14) == 0) {
@@ -4667,8 +4661,7 @@ void StartFrame() { // v7 last frame timing
46674661
curr->green_av[i2] = -1;
46684662
}
46694663
pnts[8] = '\0';
4670-
snprintf(msg, sizeof(msg), "b_mp_%s", pnts);
4671-
std::strcpy(curr->ifs, msg);
4664+
snprintf(curr->ifs, sizeof(curr->ifs), "b_mp_%s", pnts);
46724665
}
46734666
else if (std::strncmp(buf, "if_red_mpoint", 13) == 0) {
46744667
// this can only be in a section
@@ -4705,8 +4698,7 @@ void StartFrame() { // v7 last frame timing
47054698
curr->green_av[i2] = -1;
47064699
}
47074700
pnts[8] = '\0';
4708-
snprintf(msg, sizeof(msg), "r_mp_%s", pnts);
4709-
std::strcpy(curr->ifs, msg);
4701+
snprintf(curr->ifs, sizeof(curr->ifs), "r_mp_%s", pnts);
47104702
}
47114703
else if (std::strncmp(buf, "if_green_mpoint", 15) == 0) {
47124704
// this can only be in a section
@@ -4743,8 +4735,7 @@ void StartFrame() { // v7 last frame timing
47434735
curr->green_av[i2] = -1;
47444736
}
47454737
pnts[8] = '\0';
4746-
snprintf(msg, sizeof(msg), "g_mp_%s", pnts);
4747-
std::strcpy(curr->ifs, msg);
4738+
snprintf(curr->ifs, sizeof(curr->ifs), "g_mp_%s", pnts);
47484739
}
47494740
else if (std::strncmp(buf, "if_yellow_mpoint", 16) == 0) {
47504741
// this can only be in a section
@@ -4781,8 +4772,7 @@ void StartFrame() { // v7 last frame timing
47814772
curr->green_av[i2] = -1;
47824773
}
47834774
pnts[8] = '\0';
4784-
snprintf(msg, sizeof(msg), "y_mp_%s", pnts);
4785-
std::strcpy(curr->ifs, msg);
4775+
snprintf(curr->ifs, sizeof(curr->ifs), "y_mp_%s", pnts);
47864776
} // end of multipoint ifs
47874777
else if (buffer[i1] != '/' && buffer[i1] != '{' && buffer[i1] != '}' && buffer[i1] != ' ' && buffer[i1] != '\n' && random_shit_error == false) {
47884778
random_shit_error = true;

0 commit comments

Comments
 (0)