]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Improve automatic waypoint generation for jumppads with a slow horizontal speed;...
authorterencehill <piuntn@gmail.com>
Mon, 15 May 2017 16:12:22 +0000 (18:12 +0200)
committerterencehill <piuntn@gmail.com>
Mon, 15 May 2017 20:47:09 +0000 (22:47 +0200)
qcsrc/common/triggers/trigger/jumppads.qc
qcsrc/server/bot/default/havocbot/havocbot.qc
qcsrc/server/bot/default/navigation.qc
qcsrc/server/bot/default/navigation.qh

index d37f72788d6c005c37ef2b2d4b4984b4c92fb2ea..c6c60ba7d330557bd95366bec5f3872b0149d1b4 100644 (file)
@@ -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);
        }
 
index 7a2498ec39fc6fd6e0156194dace59b0c7fd9ed0..c533071b029871e9b4c1436b6a0f406061cd005e 100644 (file)
@@ -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
index 8633a9f879a2e7ff46a0d3dff7a8e79a4e7c02d5..76ac3389cdac1e72961e48b23c64bc3ebb27d63b 100644 (file)
@@ -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;
index 078f1ede7308306022a0cf341370e2cdf46f79db..ddb4bd3ef8995ba9908ad0fbb7e6d8cb2c6db9dd 100644 (file)
@@ -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;