]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge remote-tracking branch 'origin/divVerent/waypointeditor-auto'
authorRudolf Polzer <divverent@alientrap.org>
Mon, 9 Jan 2012 20:19:08 +0000 (21:19 +0100)
committerRudolf Polzer <divverent@alientrap.org>
Mon, 9 Jan 2012 20:19:08 +0000 (21:19 +0100)
defaultXonotic.cfg
qcsrc/server/autocvars.qh
qcsrc/server/bot/bot.qc
qcsrc/server/bot/navigation.qc
qcsrc/server/bot/waypoints.qc
qcsrc/server/bot/waypoints.qh

index eadb6a16f51097906d657456407d986441892087..d255f8e338ac656bbe6cae29ed39e2fe38c2dcf1 100644 (file)
@@ -438,6 +438,7 @@ set bot_ai_aimskill_order_filter_5th 0.5 "Movement prediction filter. Used rarel
 
 // waypoint editor enable
 set g_waypointeditor 0
+set g_waypointeditor_auto 0 "Automatically create waypoints for bots while playing"
 set bot_ignore_bots 0  "When set, bots don't shoot at other bots"
 set bot_join_empty 0   "When set, bots also play if no player has joined the server"
 set bot_vs_human 0     "Bots and humans play in different teams when set. positive values to make an all-bot blue team, set to negative values to make an all-bot red team, the absolute value is the ratio bots vs humans (1 for equal count). Changes will be correctly applied only from the next game"
index 6f5ea2b297c332b430d38805966e6dd714ec241f..538d65307f1c3647d7c3264ae9c1e070ca99f42f 100644 (file)
@@ -1024,6 +1024,7 @@ float autocvar_g_turrets_unit_walker_turn_strafe;
 float autocvar_g_turrets_unit_walker_turn_swim;
 float autocvar_g_use_ammunition;
 float autocvar_g_waypointeditor;
+float autocvar_g_waypointeditor_auto;
 float autocvar_g_waypoints_for_items;
 float autocvar_g_weapon_charge_colormod_blue_full;
 float autocvar_g_weapon_charge_colormod_blue_half;
index 1658d7fac4f3c6de0c1313c7780258492b273914..039e21daed025bf588322272997456ed3f2fb240 100644 (file)
@@ -633,7 +633,7 @@ void bot_serverframe()
                        localcmd("quit\n");
        }
 
-       if (currentbots > 0 || autocvar_g_waypointeditor)
+       if (currentbots > 0 || autocvar_g_waypointeditor || autocvar_g_waypointeditor_auto)
        if (botframe_spawnedwaypoints)
        {
                if(botframe_cachedwaypointlinks)
@@ -685,6 +685,9 @@ void bot_serverframe()
        if (autocvar_g_waypointeditor)
                botframe_showwaypointlinks();
 
+       if (autocvar_g_waypointeditor_auto)
+               botframe_autowaypoints();
+
        if(time > bot_cvar_nextthink)
        {
                if(currentbots>0)
index 6aa6ea2a17f8a32b4f22df6d5c702df0ee591bd6..3387fdfef8fdcc1b4e5711cb9d3c165c979782b2 100644 (file)
@@ -332,12 +332,37 @@ void navigation_poproute()
        self.goalstack31 = world;
 }
 
+float navigation_waypoint_will_link(vector v, vector org, entity ent, float walkfromwp, float bestdist)
+{
+       float dist;
+       dist = vlen(v - org);
+       if (bestdist > dist)
+       {
+               traceline(v, org, TRUE, ent);
+               if (trace_fraction == 1)
+               {
+                       if (walkfromwp)
+                       {
+                               if (tracewalk(ent, v, PL_MIN, PL_MAX, org, bot_navigation_movemode))
+                                       return TRUE;
+                       }
+                       else
+                       {
+                               if (tracewalk(ent, org, PL_MIN, PL_MAX, v, bot_navigation_movemode))
+                                       return TRUE;
+                       }
+               }
+       }
+       return FALSE;
+}
+
 // find the spawnfunc_waypoint near a dynamic goal such as a dropped weapon
-entity navigation_findnearestwaypoint(entity ent, float walkfromwp)
+entity navigation_findnearestwaypoint_withdist(entity ent, float walkfromwp, float bestdist)
 {
        entity waylist, w, best;
-       float dist, bestdist;
+       float dist;
        vector v, org, pm1, pm2;
+
        pm1 = ent.origin + ent.mins;
        pm2 = ent.origin + ent.maxs;
        waylist = findchain(classname, "waypoint");
@@ -362,7 +387,6 @@ entity navigation_findnearestwaypoint(entity ent, float walkfromwp)
                te_plasmaburn(org);
 
        best = world;
-       bestdist = 1050;
 
        // box check failed, try walk
        w = waylist;
@@ -382,36 +406,20 @@ entity navigation_findnearestwaypoint(entity ent, float walkfromwp)
                        }
                        else
                                v = w.origin;
-                       dist = vlen(v - org);
-                       if (bestdist > dist)
+                       if(navigation_waypoint_will_link(v, org, ent, walkfromwp, bestdist))
                        {
-                               traceline(v, org, TRUE, ent);
-                               if (trace_fraction == 1)
-                               {
-                                       if (walkfromwp)
-                                       {
-                                               //print("^1can I reach ", vtos(org), " from ", vtos(v), "?\n");
-                                               if (tracewalk(ent, v, PL_MIN, PL_MAX, org, bot_navigation_movemode))
-                                               {
-                                                       bestdist = dist;
-                                                       best = w;
-                                               }
-                                       }
-                                       else
-                                       {
-                                               if (tracewalk(ent, org, PL_MIN, PL_MAX, v, bot_navigation_movemode))
-                                               {
-                                                       bestdist = dist;
-                                                       best = w;
-                                               }
-                                       }
-                               }
+                               bestdist = vlen(v - org);
+                               best = w;
                        }
                }
                w = w.chain;
        }
        return best;
 }
+entity navigation_findnearestwaypoint(entity ent, float walkfromwp)
+{
+       return navigation_findnearestwaypoint_withdist(ent, walkfromwp, 1050);
+}
 
 // finds the waypoints near the bot initiating a navigation query
 float navigation_markroutes_nearestwaypoints(entity waylist, float maxdist)
index e2bcc5bd628e341000f7273cd9d7dee80da44167..4db72e407da5676ad73a15eab5a3c170a1aafd67 100644 (file)
@@ -877,3 +877,205 @@ void botframe_showwaypointlinks()
                player = find(player, classname, "player");
        }
 }
+
+float botframe_autowaypoints_fixdown(vector v)
+{
+       tracebox(v, PL_MIN, PL_MAX, v + '0 0 -64', MOVE_NOMONSTERS, world);
+       if(trace_fraction >= 1)
+               return 0;
+       return 1;
+}
+
+float botframe_autowaypoints_createwp(vector v, entity p, .entity fld)
+{
+       entity w;
+
+       w = find(world, classname, "waypoint");
+       while (w)
+       {
+               // if a matching spawnfunc_waypoint already exists, don't add a duplicate
+               if (boxesoverlap(v - '32 32 32', v + '32 32 32', w.absmin, w.absmax))
+               //if (boxesoverlap(v - '4 4 4', v + '4 4 4', w.absmin, w.absmax))
+                       return 0;
+               w = find(w, classname, "waypoint");
+       }
+
+       waypoint_schedulerelink(p.fld = waypoint_spawn(v, v, 0));
+       return 1;
+}
+
+// return value:
+//    1 = WP created
+//    0 = no action needed
+//   -1 = temp fail, try from world too
+//   -2 = permanent fail, do not retry
+float botframe_autowaypoints_fix_from(entity p, float walkfromwp, entity wp, .entity fld)
+{
+       // make it possible to go from p to wp, if we can
+       // if wp is world, nearest is chosen
+
+       entity w;
+       vector porg;
+       float t, tmin, tmax;
+       vector o;
+       vector save;
+
+       if(!botframe_autowaypoints_fixdown(p.origin))
+               return -2;
+       porg = trace_endpos;
+
+       if(wp)
+       {
+               // if any WP w fulfills wp -> w -> porg, then switch from wp to w
+
+               // if wp -> porg, then OK
+               float maxdist;
+               if(navigation_waypoint_will_link(wp.origin, porg, p, walkfromwp, 1050))
+               {
+                       // we may find a better one
+                       maxdist = vlen(wp.origin - porg);
+               }
+               else
+               {
+                       // accept any "good"
+                       maxdist = 2100;
+               }
+
+               float bestdist;
+               bestdist = maxdist;
+               w = find(world, classname, "waypoint");
+               while (w)
+               {
+                       if(w != wp && !(w.wpflags & WAYPOINTFLAG_NORELINK))
+                       {
+                               float d;
+                               d = vlen(wp.origin - w.origin) + vlen(w.origin - porg);
+                               if(d < bestdist)
+                                       if(navigation_waypoint_will_link(wp.origin, w.origin, p, walkfromwp, 1050))
+                                               if(navigation_waypoint_will_link(w.origin, porg, p, walkfromwp, 1050))
+                                               {
+                                                       bestdist = d;
+                                                       p.fld = w;
+                                               }
+                       }
+                       w = find(w, classname, "waypoint");
+               }
+               if(bestdist < maxdist)
+               {
+                       print("update chain to new nearest WP ", etos(p.fld), "\n");
+                       return 0;
+               }
+
+               if(bestdist < 2100)
+               {
+                       // we know maxdist < 2100
+                       // so wp -> porg is still valid
+                       // all is good
+                       p.fld = wp;
+                       return 0;
+               }
+
+               // otherwise, no existing WP can fix our issues
+       }
+       else
+       {
+               save = p.origin;
+               setorigin(p, porg);
+               w = navigation_findnearestwaypoint(p, walkfromwp);
+               setorigin(p, save);
+               if(w)
+               {
+                       p.fld = w;
+                       return 0;
+               }
+       }
+
+       tmin = 0;
+       tmax = 1;
+       for(;;)
+       {
+               if(tmax - tmin < 0.001)
+               {
+                       // did not get a good candidate
+                       return -1;
+               }
+
+               t = (tmin + tmax) * 0.5;
+               o = antilag_takebackorigin(p, time - t);
+               if(!botframe_autowaypoints_fixdown(o))
+                       return -1;
+               o = trace_endpos;
+
+               if(wp)
+               {
+                       if(!navigation_waypoint_will_link(wp.origin, o, p, walkfromwp, 1050))
+                       {
+                               // we cannot walk from wp.origin to o
+                               // get closer to tmax
+                               tmin = t;
+                               continue;
+                       }
+               }
+               else
+               {
+                       save = p.origin;
+                       setorigin(p, o);
+                       w = navigation_findnearestwaypoint(p, walkfromwp);
+                       setorigin(p, save);
+                       if(!w)
+                       {
+                               // we cannot walk from any WP to o
+                               // get closer to tmax
+                               tmin = t;
+                               continue;
+                       }
+               }
+
+               // if we get here, o is valid regarding waypoints
+               // check if o is connected right to the player
+               // we break if it succeeds, as that means o is a good waypoint location
+               if(navigation_waypoint_will_link(o, porg, p, walkfromwp, 1050))
+                       break;
+
+               // o is no good, we need to get closer to the player
+               tmax = t;
+       }
+
+       print("spawning a waypoint for connecting to ", etos(wp), "\n");
+       botframe_autowaypoints_createwp(o, p, fld);
+       return 1;
+}
+
+// automatically create missing waypoints
+.entity botframe_autowaypoints_lastwp0, botframe_autowaypoints_lastwp1;
+void botframe_autowaypoints_fix(entity p, float walkfromwp, .entity fld)
+{
+       float r;
+       r = botframe_autowaypoints_fix_from(p, walkfromwp, p.fld, fld);
+       if(r != -1)
+               return;
+       r = botframe_autowaypoints_fix_from(p, walkfromwp, world, fld);
+       if(r != -1)
+               return;
+
+       print("emergency: got no good nearby WP to build a link from, starting a new chain\n");
+       if(!botframe_autowaypoints_fixdown(p.origin))
+               return; // shouldn't happen, caught above
+       botframe_autowaypoints_createwp(trace_endpos, p, fld);
+}
+
+void botframe_autowaypoints()
+{
+       entity p;
+       entity wp0, wp1;
+       FOR_EACH_REALPLAYER(p)
+       {
+               if(p.deadflag)
+                       continue;
+               // going back is broken, so only fix waypoints to walk TO the player
+               //botframe_autowaypoints_fix(p, FALSE, botframe_autowaypoints_lastwp0);
+               botframe_autowaypoints_fix(p, TRUE, botframe_autowaypoints_lastwp1);
+               //te_explosion(p.botframe_autowaypoints_lastwp0.origin);
+       }
+}
+
index 1bb800fd054ac5382b1a92491c2c6bf86ee0bc4e..fb7beea0fcaf74cfa73e4aa9deeded549cad3270 100644 (file)
@@ -57,3 +57,5 @@ entity waypoint_spawn(vector m1, vector m2, float f);
 entity waypoint_spawnpersonal(vector position);
 
 vector waypoint_fixorigin(vector position);
+
+void botframe_autowaypoints();