]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/bot/default/waypoints.qc
Improve detection of item's nearest waypoint by using item's height in the tracewalk...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / bot / default / waypoints.qc
index 436220d698aff0fc108c0fd1d1c166af484c0c17..d56b0da44e58e914128f85a31971efaefc534fa6 100644 (file)
@@ -1,5 +1,7 @@
 #include "waypoints.qh"
 
+#include <server/defs.qh>
+#include <server/miscfunctions.qh>
 #include "cvars.qh"
 
 #include "bot.qh"
@@ -268,8 +270,13 @@ void waypoint_spawn_fromeditor(entity pl)
 
        LABEL(add_wp);
        e = waypoint_spawn(org, org, 0);
+       if(!e)
+       {
+               LOG_INFOF("Couldn't spawn waypoint at %v\n", org);
+               return;
+       }
        waypoint_schedulerelink(e);
-       bprint(strcat("Waypoint spawned at ", vtos(org), "\n"));
+       bprint(strcat("Waypoint spawned at ", vtos(e.origin), "\n"));
        if(sym)
        {
                org = waypoint_getSymmetricalOrigin(e.origin, ctf_flags);
@@ -444,9 +451,20 @@ float waypoint_getlinearcost(float dist)
                return dist / (autocvar_sv_maxspeed * 1.25);
        return dist / autocvar_sv_maxspeed;
 }
+float waypoint_getlinearcost_underwater(float dist)
+{
+       // NOTE: this value is hardcoded on the engine too, see SV_WaterMove
+       return dist / (autocvar_sv_maxspeed * 0.7);
+}
 
-float waypoint_gettravelcost(vector from, vector to)
+float waypoint_gettravelcost(vector from, vector to, entity from_ent, entity to_ent)
 {
+       bool submerged_from = navigation_check_submerged_state(from_ent, from);
+       bool submerged_to = navigation_check_submerged_state(to_ent, to);
+
+       if (submerged_from && submerged_to)
+               return waypoint_getlinearcost_underwater(vlen(to - from));
+
        float c = waypoint_getlinearcost(vlen(to - from));
 
        float height = from.z - to.z;
@@ -457,6 +475,9 @@ float waypoint_gettravelcost(vector from, vector to)
                if(height_cost > c)
                        c = height_cost;
        }
+
+       if (submerged_from || submerged_to)
+               return (c + waypoint_getlinearcost_underwater(vlen(to - from))) / 2;
        return c;
 }
 
@@ -466,19 +487,19 @@ float waypoint_getlinkcost(entity from, entity to)
        vector v2 = to.origin;
        if (from.wpisbox)
        {
-               vector m1 = to.absmin, m2 = to.absmax;
-               v1_x = bound(m1_x, v1_x, m2_x);
-               v1_y = bound(m1_y, v1_y, m2_y);
-               v1_z = bound(m1_z, v1_z, m2_z);
+               vector m1 = from.absmin, m2 = from.absmax;
+               v1.x = bound(m1.x, v2.x, m2.x);
+               v1.y = bound(m1.y, v2.y, m2.y);
+               v1.z = bound(m1.z, v2.z, m2.z);
        }
        if (to.wpisbox)
        {
-               vector m1 = from.absmin, m2 = from.absmax;
-               v2_x = bound(m1_x, v2_x, m2_x);
-               v2_y = bound(m1_y, v2_y, m2_y);
-               v2_z = bound(m1_z, v2_z, m2_z);
+               vector m1 = to.absmin, m2 = to.absmax;
+               v2.x = bound(m1.x, v1.x, m2.x);
+               v2.y = bound(m1.y, v1.y, m2.y);
+               v2.z = bound(m1.z, v1.z, m2.z);
        }
-       return waypoint_gettravelcost(v1, v2);
+       return waypoint_gettravelcost(v1, v2, from, to);
 }
 
 // add a new link to the spawnfunc_waypoint, replacing the furthest link it already has
@@ -538,8 +559,8 @@ void waypoint_addlink(entity from, entity to)
 // (SLOW!)
 void waypoint_think(entity this)
 {
-       vector sv, sv2, ev, ev2, dv;
-       float sv2_height, ev2_height;
+       vector sv = '0 0 0', sv2 = '0 0 0', ev = '0 0 0', ev2 = '0 0 0', dv;
+       float sv2_height = 0, ev2_height = 0;
 
        bot_calculate_stepheightvec();
 
@@ -680,8 +701,27 @@ bool waypoint_load_links()
                return false;
        }
 
+       bool parse_comments = true;
+       float ver = 0;
+
        while ((s = fgets(file)))
        {
+               if(parse_comments)
+               {
+                       if(substring(s, 0, 2) == "//")
+                       {
+                               if(substring(s, 2, 8) == "VERSION ")
+                                       ver = stof(substring(s, 10, -1));
+                               continue;
+                       }
+                       else
+                       {
+                               if(ver < WAYPOINT_VERSION)
+                                       return false;
+                               parse_comments = false;
+                       }
+               }
+
                tokens = tokenizebyseparator(s, "*");
 
                if (tokens!=2)
@@ -840,6 +880,8 @@ void waypoint_load_or_remove_links_hardwired(bool removal_mode)
                waypoint_addlink(wp_from, wp_to);
                wp_from.wphardwired = true;
                wp_to.wphardwired = true;
+               waypoint_setupmodel(wp_from);
+               waypoint_setupmodel(wp_to);
        }
 
        fclose(file);
@@ -848,9 +890,6 @@ void waypoint_load_or_remove_links_hardwired(bool removal_mode)
                LOG_TRACE("loaded ", ftos(c), " waypoint links from maps/", mapname, ".waypoints.hardwired");
 }
 
-void waypoint_load_links_hardwired() { waypoint_load_or_remove_links_hardwired(false); }
-void waypoint_remove_links_hardwired() { waypoint_load_or_remove_links_hardwired(true); }
-
 entity waypoint_get_link(entity w, float i)
 {
        switch(i)
@@ -905,6 +944,8 @@ void waypoint_save_links()
                return;
        }
 
+       fputs(file, strcat("//", "VERSION ", ftos_decimals(WAYPOINT_VERSION, 2), "\n"));
+
        int c = 0;
        IL_EACH(g_waypoints, true,
        {
@@ -941,6 +982,12 @@ void waypoint_saveall()
                return;
        }
 
+       // add 3 comments to not break compatibility with older Xonotic versions
+       // (they are read as a waypoint with origin '0 0 0' and flag 0 though)
+       fputs(file, strcat("//", "VERSION ", ftos_decimals(WAYPOINT_VERSION, 2), "\n"));
+       fputs(file, strcat("//", "\n"));
+       fputs(file, strcat("//", "\n"));
+
        int c = 0;
        IL_EACH(g_waypoints, true,
        {
@@ -974,49 +1021,66 @@ float waypoint_loadall()
        filename = strcat("maps/", mapname);
        filename = strcat(filename, ".waypoints");
        file = fopen(filename, FILE_READ);
-       if (file >= 0)
+
+       bool parse_comments = true;
+       float ver = 0;
+
+       if (file < 0)
        {
-               while ((s = fgets(file)))
+               LOG_TRACE("waypoint load from ", filename, " failed");
+               return 0;
+       }
+
+       while ((s = fgets(file)))
+       {
+               if(parse_comments)
                {
-                       m1 = stov(s);
-                       s = fgets(file);
-                       if (!s)
-                               break;
-                       m2 = stov(s);
-                       s = fgets(file);
-                       if (!s)
-                               break;
-                       fl = stof(s);
-                       waypoint_spawn(m1, m2, fl);
-                       if (m1 == m2)
-                               cwp = cwp + 1;
+                       if(substring(s, 0, 2) == "//")
+                       {
+                               if(substring(s, 2, 8) == "VERSION ")
+                                       ver = stof(substring(s, 10, -1));
+                               continue;
+                       }
                        else
-                               cwb = cwb + 1;
+                       {
+                               if(floor(ver) < floor(WAYPOINT_VERSION))
+                                       LOG_TRACE("waypoints for this map are outdated");
+                               parse_comments = false;
+                       }
                }
-               fclose(file);
-               LOG_TRACE("loaded ", ftos(cwp), " waypoints and ", ftos(cwb), " wayboxes from maps/", mapname, ".waypoints");
-       }
-       else
-       {
-               LOG_TRACE("waypoint load from ", filename, " failed");
+               m1 = stov(s);
+               s = fgets(file);
+               if (!s)
+                       break;
+               m2 = stov(s);
+               s = fgets(file);
+               if (!s)
+                       break;
+               fl = stof(s);
+               waypoint_spawn(m1, m2, fl);
+               if (m1 == m2)
+                       cwp = cwp + 1;
+               else
+                       cwb = cwb + 1;
        }
+       fclose(file);
+       LOG_TRACE("loaded ", ftos(cwp), " waypoints and ", ftos(cwb), " wayboxes from maps/", mapname, ".waypoints");
+
        return cwp + cwb;
 }
 
-vector waypoint_fixorigin(vector position)
+vector waypoint_fixorigin(vector position, entity tracetest_ent)
 {
-       tracebox(position + '0 0 1' * (1 - PL_MIN_CONST.z), PL_MIN_CONST, PL_MAX_CONST, position + '0 0 -512', MOVE_NOMONSTERS, NULL);
+       tracebox(position + '0 0 1' * (1 - PL_MIN_CONST.z), PL_MIN_CONST, PL_MAX_CONST, position + '0 0 -512', MOVE_NOMONSTERS, tracetest_ent);
        if(trace_fraction < 1)
                position = trace_endpos;
-       //traceline(position, position + '0 0 -512', MOVE_NOMONSTERS, NULL);
-       //print("position is ", ftos(trace_endpos_z - position_z), " above solid\n");
        return position;
 }
 
 void waypoint_spawnforitem_force(entity e, vector org)
 {
        // Fix the waypoint altitude if necessary
-       org = waypoint_fixorigin(org);
+       org = waypoint_fixorigin(org, NULL);
 
        // don't spawn an item spawnfunc_waypoint if it already exists
        IL_EACH(g_waypoints, true,
@@ -1065,16 +1129,16 @@ void waypoint_spawnforteleporter_boxes(entity e, int teleport_flag, vector org1,
        e.nearestwaypointtimeout = -1;
 }
 
-void waypoint_spawnforteleporter_v(entity e, vector org, vector destination, float timetaken)
+void waypoint_spawnforteleporter_wz(entity e, vector org, vector destination, float timetaken, entity tracetest_ent)
 {
-       org = waypoint_fixorigin(org);
-       destination = waypoint_fixorigin(destination);
+       org = waypoint_fixorigin(org, tracetest_ent);
+       destination = waypoint_fixorigin(destination, tracetest_ent);
        waypoint_spawnforteleporter_boxes(e, WAYPOINTFLAG_TELEPORT, org, org, destination, destination, timetaken);
 }
 
-void waypoint_spawnforteleporter(entity e, vector destination, float timetaken)
+void waypoint_spawnforteleporter(entity e, vector destination, float timetaken, entity tracetest_ent)
 {
-       destination = waypoint_fixorigin(destination);
+       destination = waypoint_fixorigin(destination, tracetest_ent);
        waypoint_spawnforteleporter_boxes(e, WAYPOINTFLAG_TELEPORT, e.absmin - PL_MAX_CONST + '1 1 1', e.absmax - PL_MIN_CONST + '-1 -1 -1', destination, destination, timetaken);
 }
 
@@ -1085,7 +1149,7 @@ entity waypoint_spawnpersonal(entity this, vector position)
        // drop the waypoint to a proper location:
        //   first move it up by a player height
        //   then move it down to hit the floor with player bbox size
-       position = waypoint_fixorigin(position);
+       position = waypoint_fixorigin(position, this);
 
        w = waypoint_spawn(position, position, WAYPOINTFLAG_GENERATED | WAYPOINTFLAG_PERSONAL);
        w.nearestwaypoint = NULL;
@@ -1214,7 +1278,7 @@ float botframe_autowaypoints_fix_from(entity p, float walkfromwp, entity wp, .en
 
                // if wp -> porg, then OK
                float maxdist;
-               if(navigation_waypoint_will_link(wp.origin, porg, p, wp.origin, 0, walkfromwp, 1050))
+               if(navigation_waypoint_will_link(wp.origin, porg, p, porg, 0, wp.origin, 0, walkfromwp, 1050))
                {
                        // we may find a better one
                        maxdist = vlen(wp.origin - porg);
@@ -1230,8 +1294,8 @@ float botframe_autowaypoints_fix_from(entity p, float walkfromwp, entity wp, .en
                {
                        float d = vlen(wp.origin - it.origin) + vlen(it.origin - porg);
                        if(d < bestdist)
-                       if(navigation_waypoint_will_link(wp.origin, it.origin, p, wp.origin, 0, walkfromwp, 1050))
-                       if(navigation_waypoint_will_link(it.origin, porg, p, it.origin, 0, walkfromwp, 1050))
+                       if(navigation_waypoint_will_link(wp.origin, it.origin, p, it.origin, 0, wp.origin, 0, walkfromwp, 1050))
+                       if(navigation_waypoint_will_link(it.origin, porg, p, porg, 0, it.origin, 0, walkfromwp, 1050))
                        {
                                bestdist = d;
                                p.(fld) = it;
@@ -1285,7 +1349,7 @@ float botframe_autowaypoints_fix_from(entity p, float walkfromwp, entity wp, .en
 
                if(wp)
                {
-                       if(!navigation_waypoint_will_link(wp.origin, o, p, wp.origin, 0, walkfromwp, 1050))
+                       if(!navigation_waypoint_will_link(wp.origin, o, p, o, 0, wp.origin, 0, walkfromwp, 1050))
                        {
                                // we cannot walk from wp.origin to o
                                // get closer to tmax
@@ -1311,7 +1375,7 @@ float botframe_autowaypoints_fix_from(entity p, float walkfromwp, entity wp, .en
                // 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, o, 0, walkfromwp, 1050))
+               if(navigation_waypoint_will_link(o, porg, p, porg, 0, o, 0, walkfromwp, 1050))
                        break;
 
                // o is no good, we need to get closer to the player
@@ -1422,12 +1486,12 @@ LABEL(next)
 
 void botframe_autowaypoints()
 {
-       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && !IS_DEAD(it), LAMBDA(
+       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && !IS_DEAD(it), {
                // going back is broken, so only fix waypoints to walk TO the player
                //botframe_autowaypoints_fix(p, false, botframe_autowaypoints_lastwp0);
                botframe_autowaypoints_fix(it, true, botframe_autowaypoints_lastwp1);
                //te_explosion(p.botframe_autowaypoints_lastwp0.origin);
-       ));
+       });
 
        if (autocvar_g_waypointeditor_auto >= 2) {
                botframe_deleteuselesswaypoints();