From: terencehill Date: Mon, 15 May 2017 16:12:22 +0000 (+0200) Subject: Improve automatic waypoint generation for jumppads with a slow horizontal speed;... X-Git-Tag: xonotic-v0.8.5~2378^2~159 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=af714c7aa2978049a30147cde6cf21198eab54cf;p=xonotic%2Fxonotic-data.pk3dir.git Improve automatic waypoint generation for jumppads with a slow horizontal speed; don't generate any waypoint for jumppads that can't be helped if destination wp would end up on the jumppad itself. Improve handling of jumppads during bot navigation especially for the new waypoints --- diff --git a/qcsrc/common/triggers/trigger/jumppads.qc b/qcsrc/common/triggers/trigger/jumppads.qc index d37f72788..c6c60ba7d 100644 --- a/qcsrc/common/triggers/trigger/jumppads.qc +++ b/qcsrc/common/triggers/trigger/jumppads.qc @@ -278,6 +278,29 @@ bool trigger_push_testorigin(entity e, entity targ, entity jp, vector org) tracetoss(e, e); if(trace_startsolid) return false; + + if(!jp.height) + { + // since tracetoss starting from jumppad's origin often fails when target + // is very close to real destination, start it directly from target's + // origin instead + e.velocity_z = 0; + setorigin(e, targ.origin + stepheightvec); + tracetoss(e, e); + if(trace_startsolid) + { + setorigin(e, targ.origin + stepheightvec / 2); + tracetoss(e, e); + if(trace_startsolid) + { + setorigin(e, targ.origin); + tracetoss(e, e); + if(trace_startsolid) + return false; + } + } + } + if(e.move_movetype == MOVETYPE_NONE) { tracebox(trace_endpos, e.mins, e.maxs, trace_endpos - eZ * 1500, true, jp); @@ -295,6 +318,9 @@ void trigger_push_findtarget(entity this) if (this.target) { int n = 0; +#ifdef SVQC + vector vel = '0 0 0'; +#endif for(entity t = NULL; (t = find(t, targetname, this.target)); ) { ++n; @@ -302,6 +328,7 @@ void trigger_push_findtarget(entity this) entity e = spawn(); setsize(e, PL_MIN_CONST, PL_MAX_CONST); e.velocity = trigger_push_calculatevelocity(org, t, this.height); + vel = e.velocity; vector best_target = '0 0 0'; vector best_org = '0 0 0'; vector best_vel = '0 0 0'; @@ -325,28 +352,41 @@ void trigger_push_findtarget(entity this) vector ofs = flatdir * 0.5 * min(fabs(this.absmax.x - this.absmin.x), fabs(this.absmax.y - this.absmin.y)); new_org = org + ofs; e.velocity = trigger_push_calculatevelocity(new_org, t, this.height); + vel = e.velocity; + if(vlen(vec2(e.velocity)) < autocvar_sv_maxspeed) + e.velocity = autocvar_sv_maxspeed * flatdir; if (trigger_push_testorigin(e, t, this, new_org) && (!valid_best_target || trace_endpos.z > best_target.z + 50)) { best_target = trace_endpos; best_org = new_org; - best_vel = e.velocity; + best_vel = vel; valid_best_target = true; } new_org = org - ofs; e.velocity = trigger_push_calculatevelocity(new_org, t, this.height); + vel = e.velocity; + if(vlen(vec2(e.velocity)) < autocvar_sv_maxspeed) + e.velocity = autocvar_sv_maxspeed * flatdir; if (trigger_push_testorigin(e, t, this, new_org) && (!valid_best_target || trace_endpos.z > best_target.z + 50)) { best_target = trace_endpos; best_org = new_org; - best_vel = e.velocity; + best_vel = vel; valid_best_target = true; } } + if (valid_best_target) { - float distxy = (vlen((best_target - eZ * best_target.z) - (best_org - eZ * best_org.z))); - float velxy = vlen(best_vel - eZ * best_vel.z); - waypoint_spawnforteleporter(this, best_target, distxy / velxy); + if (!(boxesoverlap(this.absmin, this.absmax + eZ * 50, best_target + PL_MIN_CONST, best_target + PL_MAX_CONST))) + { + float velxy = vlen(vec2(best_vel)); + float cost = vlen(vec2(t.origin - best_org)) / velxy; + if(velxy < autocvar_sv_maxspeed) + velxy = autocvar_sv_maxspeed; + cost += vlen(vec2(best_target - t.origin)) / velxy; + waypoint_spawnforteleporter(this, best_target, cost); + } } delete(e); #endif @@ -379,7 +419,8 @@ void trigger_push_findtarget(entity this) setsize(e, PL_MIN_CONST, PL_MAX_CONST); e.velocity = this.movedir; tracetoss(e, e); - waypoint_spawnforteleporter(this, trace_endpos, vlen(trace_endpos - org) / vlen(e.velocity)); + if (!(boxesoverlap(this.absmin, this.absmax + eZ * 50, trace_endpos + PL_MIN_CONST, trace_endpos + PL_MAX_CONST))) + waypoint_spawnforteleporter(this, trace_endpos, vlen(trace_endpos - org) / vlen(e.velocity)); delete(e); } diff --git a/qcsrc/server/bot/default/havocbot/havocbot.qc b/qcsrc/server/bot/default/havocbot/havocbot.qc index 7a2498ec3..c533071b0 100644 --- a/qcsrc/server/bot/default/havocbot/havocbot.qc +++ b/qcsrc/server/bot/default/havocbot/havocbot.qc @@ -413,9 +413,26 @@ void havocbot_bunnyhop(entity this, vector dir) #endif } -.entity goalcurrent_prev; -.float goalcurrent_distance; -.float goalcurrent_distance_time; +// return true when bot isn't getting closer to the current goal +bool havocbot_checkgoaldistance(entity this, vector gco) +{ + float curr_dist = vlen(this.origin - gco); + if(curr_dist > this.goalcurrent_distance) + { + if(!this.goalcurrent_distance_time) + this.goalcurrent_distance_time = time; + else if (time - this.goalcurrent_distance_time > 0.5) + return true; + } + else + { + // reduce it a little bit so it works even with very small approaches to the goal + this.goalcurrent_distance = max(20, curr_dist - 15); + this.goalcurrent_distance_time = 0; + } + return false; +} + void havocbot_movetogoal(entity this) { vector destorg; @@ -507,16 +524,20 @@ void havocbot_movetogoal(entity this) // Handling of jump pads if(this.jumppadcount) { - // If got stuck on the jump pad try to reach the farthest visible waypoint - // but with some randomness so it can try out different paths - if(this.aistatus & AI_STATUS_OUT_JUMPPAD) + if(this.goalcurrent.wpflags & WAYPOINTFLAG_TELEPORT) { - if(fabs(this.velocity.z)<50) + this.aistatus |= AI_STATUS_OUT_JUMPPAD; + navigation_poptouchedgoals(this); + return; + } + else if(this.aistatus & AI_STATUS_OUT_JUMPPAD) + { + // If got stuck on the jump pad try to reach the farthest visible waypoint + // but with some randomness so it can try out different paths + if(!this.goalcurrent) { entity newgoal = NULL; - if (vdist(this.origin - this.goalcurrent.origin, <, 150)) - this.aistatus &= ~AI_STATUS_OUT_JUMPPAD; - else IL_EACH(g_waypoints, vdist(it.origin - this.origin, <=, 1000), + IL_EACH(g_waypoints, vdist(it.origin - this.origin, <=, 1000), { if(it.wpflags & WAYPOINTFLAG_TELEPORT) if(it.origin.z < this.origin.z - 100 && vdist(vec2(it.origin - this.origin), <, 100)) @@ -543,11 +564,22 @@ void havocbot_movetogoal(entity this) } } else - return; + { + gco = (this.goalcurrent.absmin + this.goalcurrent.absmax) * 0.5; + if (this.origin.z > gco.z && vdist(vec2(this.velocity), <, autocvar_sv_maxspeed)) + this.aistatus &= ~AI_STATUS_OUT_JUMPPAD; + else if(havocbot_checkgoaldistance(this, gco)) + { + navigation_clearroute(this); + this.bot_strategytime = 0; + } + else + return; + } } else { - if(time - this.lastteleporttime > 0.3 && this.velocity.z > 0) + if(time - this.lastteleporttime > 0.2 && this.velocity.z > 0) { vector velxy = this.velocity; velxy_z = 0; if(vdist(velxy, <, autocvar_sv_maxspeed * 0.2)) @@ -792,33 +824,12 @@ void havocbot_movetogoal(entity this) } // if bot for some reason doesn't get close to the current goal find another one - if(!IS_PLAYER(this.goalcurrent) && !(this.goalcurrent.bot_pickup_respawning && this.goalcurrent_distance < 50)) + if(!this.jumppadcount && !IS_PLAYER(this.goalcurrent) && !(this.goalcurrent.bot_pickup_respawning && this.goalcurrent_distance < 50)) + if(havocbot_checkgoaldistance(this, gco)) { - float curr_dist = vlen(this.origin - this.goalcurrent.origin); - if(this.goalcurrent != this.goalcurrent_prev) - { - this.goalcurrent_prev = this.goalcurrent; - this.goalcurrent_distance = curr_dist; - this.goalcurrent_distance_time = 0; - } - else if(curr_dist > this.goalcurrent_distance) - { - if(!this.goalcurrent_distance_time) - this.goalcurrent_distance_time = time; - else if (time - this.goalcurrent_distance_time > 0.5) - { - this.goalcurrent_prev = NULL; - navigation_clearroute(this); - this.bot_strategytime = 0; - return; - } - } - else - { - // reduce it a little bit so it works even with very small approaches to the goal - this.goalcurrent_distance = max(20, curr_dist - 15); - this.goalcurrent_distance_time = 0; - } + navigation_clearroute(this); + this.bot_strategytime = 0; + return; } // Check for water/slime/lava and dangerous edges diff --git a/qcsrc/server/bot/default/navigation.qc b/qcsrc/server/bot/default/navigation.qc index 8633a9f87..76ac3389c 100644 --- a/qcsrc/server/bot/default/navigation.qc +++ b/qcsrc/server/bot/default/navigation.qc @@ -266,6 +266,9 @@ bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float m // completely empty the goal stack, used when deciding where to go void navigation_clearroute(entity this) { + this.goalcurrent_prev = this.goalcurrent; + this.goalcurrent_distance = 10000000; + this.goalcurrent_distance_time = 0; //print("bot ", etos(this), " clear\n"); this.goalentity = NULL; this.goalcurrent = NULL; @@ -310,6 +313,9 @@ void navigation_clearroute(entity this) // steps to the goal, and then recalculate the path. void navigation_pushroute(entity this, entity e) { + this.goalcurrent_prev = this.goalcurrent; + this.goalcurrent_distance = 10000000; + this.goalcurrent_distance_time = 0; //print("bot ", etos(this), " push ", etos(e), "\n"); if(this.goalstack31 == this.goalentity) this.goalentity = NULL; @@ -352,6 +358,9 @@ void navigation_pushroute(entity this, entity e) // (used when a spawnfunc_waypoint is reached) void navigation_poproute(entity this) { + this.goalcurrent_prev = this.goalcurrent; + this.goalcurrent_distance = 10000000; + this.goalcurrent_distance_time = 0; //print("bot ", etos(this), " pop\n"); if(this.goalcurrent == this.goalentity) this.goalentity = NULL; diff --git a/qcsrc/server/bot/default/navigation.qh b/qcsrc/server/bot/default/navigation.qh index 078f1ede7..ddb4bd3ef 100644 --- a/qcsrc/server/bot/default/navigation.qh +++ b/qcsrc/server/bot/default/navigation.qh @@ -24,6 +24,10 @@ entity navigation_bestgoal; .entity goalstack24, goalstack25, goalstack26, goalstack27; .entity goalstack28, goalstack29, goalstack30, goalstack31; +.entity goalcurrent_prev; +.float goalcurrent_distance; +.float goalcurrent_distance_time; + .entity nearestwaypoint; .float nearestwaypoint_dist; .float nearestwaypointtimeout;