From ae17c0fde6af7b33c94182a44dbac575e6287b98 Mon Sep 17 00:00:00 2001 From: terencehill Date: Mon, 9 Mar 2020 16:30:05 +0100 Subject: [PATCH] Bot AI: evade dangers like trigger_hurt and lava by aligning to the ideal route if off-road (also pits are now counted as dangers). It improves movement control on dangerous paths, e.g. on mentalspace bots don't fall anymore after jumping from the central platform to the base. --- qcsrc/lib/vector.qh | 25 ++++++------- qcsrc/server/bot/default/havocbot/havocbot.qc | 36 ++++++++++++------- 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/qcsrc/lib/vector.qh b/qcsrc/lib/vector.qh index ca0e84f67..6f419954c 100644 --- a/qcsrc/lib/vector.qh +++ b/qcsrc/lib/vector.qh @@ -69,18 +69,6 @@ float vlen_minnorm2d(vector v) return min(max(v.x, -v.x), max(v.y, -v.y)); } -ERASEABLE -float dist_point_line(vector p, vector l0, vector ldir) -{ - ldir = normalize(ldir); - - // remove the component in line direction - p = p - (p * ldir) * ldir; - - // vlen of the remaining vector - return vlen(p); -} - /** requires that m2>m1 in all coordinates, and that m4>m3 */ ERASEABLE float boxesoverlap(vector m1, vector m2, vector m3, vector m4) { return m2_x >= m3_x && m1_x <= m4_x && m2_y >= m3_y && m1_y <= m4_y && m2_z >= m3_z && m1_z <= m4_z; } @@ -122,6 +110,19 @@ vector Rotate(vector v, float a) noref vector _yinvert; #define yinvert(v) (_yinvert = (v), _yinvert.y = 1 - _yinvert.y, _yinvert) +/// \param[in] p point +/// \param[in] l0 starting point of ldir +/// \param[in] ldir line +/// \return Vector starting from p perpendicular to ldir +ERASEABLE +vector point_line_vec(vector p, vector l0, vector ldir) +{ + ldir = normalize(ldir); + p = l0 - p; + // remove the component in line direction from p + return p - ((p * ldir) * ldir); +} + /** * @param dir the directional vector * @param norm the normalized normal diff --git a/qcsrc/server/bot/default/havocbot/havocbot.qc b/qcsrc/server/bot/default/havocbot/havocbot.qc index b1ce8a29c..493038fc3 100644 --- a/qcsrc/server/bot/default/havocbot/havocbot.qc +++ b/qcsrc/server/bot/default/havocbot/havocbot.qc @@ -875,7 +875,8 @@ void havocbot_movetogoal(entity this) dir = normalize(diff); flatdir = (diff.z == 0) ? dir : normalize(vec2(diff)); - vector evadedanger = '0 0 0'; + bool danger_detected = false; + vector do_break = '0 0 0'; //if (this.bot_dodgevector_time < time) { @@ -1084,7 +1085,6 @@ void havocbot_movetogoal(entity this) bool unreachable = false; s = CONTENT_SOLID; - bool danger_detected = false; if (trace_fraction == 1 && !this.jumppadcount && !waypoint_is_hardwiredlink(this.goalcurrent_prev, this.goalcurrent) && !(this.goalcurrent_prev && (this.goalcurrent_prev.wpflags & WAYPOINTFLAG_JUMP))) @@ -1098,6 +1098,8 @@ void havocbot_movetogoal(entity this) { if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY) danger_detected = true; + else if (trace_endpos.z < min(this.origin.z + this.mins.z, this.goalcurrent.origin.z) - 100) + danger_detected = true; else { s = pointcontents(trace_endpos + '0 0 1'); @@ -1125,12 +1127,6 @@ void havocbot_movetogoal(entity this) } } } - if (danger_detected && fabs(deviation.y) < 80 - && (fabs(deviation.y) > 5 || vdist(vec2(this.velocity), >, maxspeed * 1.5))) - { - evadedanger = normalize(this.velocity) * -1; - evadedanger.z = 0; - } dir = flatdir; makevectors(this.v_angle.y * '0 1 0'); @@ -1150,7 +1146,7 @@ void havocbot_movetogoal(entity this) // tracebox wouldn't work when bot is still on the ledge traceline(this.origin, this.origin - '0 0 200', true, this); if (this.origin.z - trace_endpos.z > 120) - evadedanger = normalize(this.velocity) * -1; + do_break = normalize(this.velocity) * -1; } if(unreachable) @@ -1165,7 +1161,6 @@ void havocbot_movetogoal(entity this) dodge = havocbot_dodge(this); if (dodge) dodge *= bound(0, 0.5 + (skill + this.bot_dodgeskill) * 0.1, 1); - evadedanger *= bound(1, 3 - (skill + this.bot_dodgeskill), 3); // Noobs fear dangers a lot and take more distance from them if (this.enemy) { traceline(this.origin, (this.enemy.absmin + this.enemy.absmax) * 0.5, true, NULL); @@ -1218,10 +1213,27 @@ void havocbot_movetogoal(entity this) bot_aimdir(this, dir, 0); } + vector evadedanger = '0 0 0'; if (!ladder_zdir) { dir *= dodge_enemy_factor; - dir = normalize(dir + dodge + evadedanger); + if (danger_detected && vdist(this.velocity, >, maxspeed * 0.8) && this.goalcurrent_prev + && this.goalcurrent.classname == "waypoint") + { + vector p = this.origin + this.velocity * 0.2; + vector evadedanger = point_line_vec(p, vec2(this.goalcurrent_prev.origin) + eZ * p.z, + vec2(destorg - this.goalcurrent_prev.origin)); + if (vdist(evadedanger, >, 20)) + { + if (vdist(evadedanger, >, 40)) + do_break = normalize(this.velocity) * -1; + evadedanger = normalize(evadedanger); + evadedanger *= bound(1, 3 - (skill + this.bot_dodgeskill), 3); // Noobs fear dangers a lot and take more distance from them + } + else + evadedanger = '0 0 0'; + } + dir = normalize(dir + dodge + do_break + evadedanger); } makevectors(this.v_angle); @@ -1237,7 +1249,7 @@ void havocbot_movetogoal(entity this) havocbot_keyboard_movement(this, destorg); // Bunnyhop! - if (!bunnyhop_forbidden && skill + this.bot_moveskill >= autocvar_bot_ai_bunnyhop_skilloffset) + if (!bunnyhop_forbidden && !evadedanger && !do_break && skill + this.bot_moveskill >= autocvar_bot_ai_bunnyhop_skilloffset) havocbot_bunnyhop(this, dir); if (dir * v_up >= autocvar_sv_jumpvelocity * 0.5 && IS_ONGROUND(this)) -- 2.39.2