]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/bot/default/waypoints.qc
Merge branch 'master' into 'master'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / bot / default / waypoints.qc
index ef75d7aa2f8e344f3ea10572506de246f1cc8724..9de3779870e7c732a9193357cdaba18ecd6af1b8 100644 (file)
@@ -12,6 +12,7 @@
 #include "../../antilag.qh"
 
 #include <common/constants.qh>
+#include <common/debug.qh>
 #include <common/net_linked.qh>
 #include <common/physics/player.qh>
 
@@ -30,7 +31,7 @@ void waypoint_unreachable(entity pl)
        entity e2 = navigation_findnearestwaypoint(pl, false);
        if(!e2)
        {
-               LOG_INFOF("Can't find any waypoint nearby\n");
+               LOG_INFO("Can't find any waypoint nearby\n");
                return;
        }
 
@@ -128,6 +129,108 @@ void waypoint_unreachable(entity pl)
        if (j) LOG_INFOF("%d items have no nearest waypoint and cannot be walked to (marked with blue light)\n", j);
 }
 
+void waypoint_getSymmetricalAxis_cmd(entity caller, bool save, int arg_idx)
+{
+       vector v1 = stov(argv(arg_idx++));
+       vector v2 = stov(argv(arg_idx++));
+       vector mid = (v1 + v2) / 2;
+
+       float diffy = (v2.y - v1.y);
+       float diffx = (v2.x - v1.x);
+       if (v1.y == v2.y)
+               diffy = 0.000001;
+       if (v1.x == v2.x)
+               diffx = 0.000001;
+       float m = - diffx / diffy;
+       float q = - m * mid.x + mid.y;
+       if (fabs(m) <= 0.000001) m = 0;
+       if (fabs(q) <= 0.000001) q = 0;
+
+       string axis_str =  strcat(ftos(m), " ", ftos(q));
+       if (save)
+               cvar_set("g_waypointeditor_symmetrical_axis", axis_str);
+       axis_str = strcat("\"", axis_str, "\"");
+       sprint(caller, strcat("Axis of symmetry based on input points: ", axis_str, "\n"));
+       if (save)
+               sprint(caller, sprintf(" ^3saved to %s\n", "g_waypointeditor_symmetrical_axis"));
+       if (save)
+       {
+               cvar_set("g_waypointeditor_symmetrical", "-2");
+               sprint(caller, strcat("g_waypointeditor_symmetrical", " has been set to ",
+                       cvar_string("g_waypointeditor_symmetrical"), "\n"));
+       }
+}
+
+void waypoint_getSymmetricalOrigin_cmd(entity caller, bool save, int arg_idx)
+{
+       vector org = '0 0 0';
+       int ctf_flags = 0;
+       for (int i = 0; i < 6; i++)
+       {
+               if (argv(arg_idx + i) != "")
+                       ctf_flags++;
+       }
+       if (ctf_flags < 2)
+       {
+               ctf_flags = 0;
+               org = vec2(havocbot_middlepoint);
+               if (argv(arg_idx) != "")
+                       sprint(caller, "WARNING: Ignoring single input point\n");
+               if (havocbot_middlepoint_radius == 0)
+               {
+                       sprint(caller, "Origin of symmetry can't be automatically determined\n");
+                       return;
+               }
+       }
+       else
+       {
+               vector v1, v2, v3, v4, v5, v6;
+               for (int i = 1; i <= ctf_flags; i++)
+               {
+                       if (i == 1) { v1 = stov(argv(arg_idx++)); org = v1 / ctf_flags; }
+                       else if (i == 2) { v2 = stov(argv(arg_idx++)); org += v2 / ctf_flags; }
+                       else if (i == 3) { v3 = stov(argv(arg_idx++)); org += v3 / ctf_flags; }
+                       else if (i == 4) { v4 = stov(argv(arg_idx++)); org += v4 / ctf_flags; }
+                       else if (i == 5) { v5 = stov(argv(arg_idx++)); org += v5 / ctf_flags; }
+                       else if (i == 6) { v6 = stov(argv(arg_idx++)); org += v6 / ctf_flags; }
+               }
+       }
+
+       if (fabs(org.x) <= 0.000001) org.x = 0;
+       if (fabs(org.y) <= 0.000001) org.y = 0;
+       string org_str = strcat(ftos(org.x), " ", ftos(org.y));
+       if (save)
+       {
+               cvar_set("g_waypointeditor_symmetrical_origin", org_str);
+               cvar_set("g_waypointeditor_symmetrical_order", ftos(ctf_flags));
+       }
+       org_str = strcat("\"", org_str, "\"");
+
+       if (ctf_flags < 2)
+               sprint(caller, strcat("Origin of symmetry based on flag positions: ", org_str, "\n"));
+       else
+               sprint(caller, strcat("Origin of symmetry based on input points: ", org_str, "\n"));
+       if (save)
+               sprint(caller, sprintf(" ^3saved to %s\n", "g_waypointeditor_symmetrical_origin"));
+
+       if (ctf_flags < 2)
+               sprint(caller, "Order of symmetry: 0 (autodetected)\n");
+       else
+               sprint(caller, strcat("Order of symmetry: ", ftos(ctf_flags), "\n"));
+       if (save)
+               sprint(caller, sprintf(" ^3saved to %s\n", "g_waypointeditor_symmetrical_order"));
+
+       if (save)
+       {
+               if (ctf_flags < 2)
+                       cvar_set("g_waypointeditor_symmetrical", "0");
+               else
+                       cvar_set("g_waypointeditor_symmetrical", "-1");
+               sprint(caller, strcat("g_waypointeditor_symmetrical", " has been set to ",
+                       cvar_string("g_waypointeditor_symmetrical"), "\n"));
+       }
+}
+
 vector waypoint_getSymmetricalPoint(vector org, int ctf_flags)
 {
        vector new_org = org;
@@ -193,7 +296,7 @@ entity waypoint_spawn(vector m1, vector m2, float f)
        // spawn only one destination waypoint for teleports teleporting player to the exact same spot
        // otherwise links loaded from file would be applied only to the first destination
        // waypoint since link format doesn't specify waypoint entities but just positions
-       if((f & WAYPOINTFLAG_GENERATED) && !(f & WAYPOINTFLAG_NORELINK) && m1 == m2)
+       if((f & WAYPOINTFLAG_GENERATED) && !(f & (WAYPOINTFLAG_NORELINK | WAYPOINTFLAG_PERSONAL)) && m1 == m2)
        {
                IL_EACH(g_waypoints, boxesoverlap(m1, m2, it.absmin, it.absmax),
                {
@@ -363,16 +466,16 @@ void waypoint_removelink(entity from, entity to)
        switch (waypoint_getlinknum(from, to))
        {
                // fallthrough all the way
-               case 00: from.wp00 = from.wp01; from.wp00mincost = from.wp01mincost;
-               case 01: from.wp01 = from.wp02; from.wp01mincost = from.wp02mincost;
-               case 02: from.wp02 = from.wp03; from.wp02mincost = from.wp03mincost;
-               case 03: from.wp03 = from.wp04; from.wp03mincost = from.wp04mincost;
-               case 04: from.wp04 = from.wp05; from.wp04mincost = from.wp05mincost;
-               case 05: from.wp05 = from.wp06; from.wp05mincost = from.wp06mincost;
-               case 06: from.wp06 = from.wp07; from.wp06mincost = from.wp07mincost;
-               case 07: from.wp07 = from.wp08; from.wp07mincost = from.wp08mincost;
-               case 08: from.wp08 = from.wp09; from.wp08mincost = from.wp09mincost;
-               case 09: from.wp09 = from.wp10; from.wp09mincost = from.wp10mincost;
+               case  0: from.wp00 = from.wp01; from.wp00mincost = from.wp01mincost;
+               case  1: from.wp01 = from.wp02; from.wp01mincost = from.wp02mincost;
+               case  2: from.wp02 = from.wp03; from.wp02mincost = from.wp03mincost;
+               case  3: from.wp03 = from.wp04; from.wp03mincost = from.wp04mincost;
+               case  4: from.wp04 = from.wp05; from.wp04mincost = from.wp05mincost;
+               case  5: from.wp05 = from.wp06; from.wp05mincost = from.wp06mincost;
+               case  6: from.wp06 = from.wp07; from.wp06mincost = from.wp07mincost;
+               case  7: from.wp07 = from.wp08; from.wp07mincost = from.wp08mincost;
+               case  8: from.wp08 = from.wp09; from.wp08mincost = from.wp09mincost;
+               case  9: from.wp09 = from.wp10; from.wp09mincost = from.wp10mincost;
                case 10: from.wp10 = from.wp11; from.wp10mincost = from.wp11mincost;
                case 11: from.wp11 = from.wp12; from.wp11mincost = from.wp12mincost;
                case 12: from.wp12 = from.wp13; from.wp12mincost = from.wp13mincost;
@@ -403,9 +506,9 @@ void waypoint_removelink(entity from, entity to)
 
 int waypoint_getlinknum(entity from, entity to)
 {
-       if (from.wp00 == to) return 00; if (from.wp01 == to) return 01; if (from.wp02 == to) return 02; if (from.wp03 == to) return 03;
-       if (from.wp04 == to) return 04; if (from.wp05 == to) return 05; if (from.wp06 == to) return 06; if (from.wp07 == to) return 07;
-       if (from.wp08 == to) return 08; if (from.wp09 == to) return 09; if (from.wp10 == to) return 10; if (from.wp11 == to) return 11;
+       if (from.wp00 == to) return  0; if (from.wp01 == to) return  1; if (from.wp02 == to) return  2; if (from.wp03 == to) return  3;
+       if (from.wp04 == to) return  4; if (from.wp05 == to) return  5; if (from.wp06 == to) return  6; if (from.wp07 == to) return  7;
+       if (from.wp08 == to) return  8; if (from.wp09 == to) return  9; if (from.wp10 == to) return 10; if (from.wp11 == to) return 11;
        if (from.wp12 == to) return 12; if (from.wp13 == to) return 13; if (from.wp14 == to) return 14; if (from.wp15 == to) return 15;
        if (from.wp16 == to) return 16; if (from.wp17 == to) return 17; if (from.wp18 == to) return 18; if (from.wp19 == to) return 19;
        if (from.wp20 == to) return 20; if (from.wp21 == to) return 21; if (from.wp22 == to) return 22; if (from.wp23 == to) return 23;
@@ -1235,11 +1338,12 @@ float waypoint_loadall()
 
 vector waypoint_fixorigin_down_dir(vector position, entity tracetest_ent, vector down_dir)
 {
-       tracebox(position + '0 0 1', PL_MIN_CONST, PL_MAX_CONST, position + down_dir * 3000, MOVE_NOMONSTERS, tracetest_ent);
+       vector endpos = position + down_dir * 3000;
+       tracebox(position + '0 0 1', PL_MIN_CONST, PL_MAX_CONST, endpos, MOVE_NOMONSTERS, tracetest_ent);
        if(trace_startsolid)
-               tracebox(position + '0 0 1' * (1 - PL_MIN_CONST.z / 2), PL_MIN_CONST, PL_MAX_CONST, position + down_dir * 3000, MOVE_NOMONSTERS, tracetest_ent);
+               tracebox(position + '0 0 1' * (1 - PL_MIN_CONST.z / 2), PL_MIN_CONST, PL_MAX_CONST, endpos, MOVE_NOMONSTERS, tracetest_ent);
        if(trace_startsolid)
-               tracebox(position + '0 0 1' * (1 - PL_MIN_CONST.z), PL_MIN_CONST, PL_MAX_CONST, position + down_dir * 3000, MOVE_NOMONSTERS, tracetest_ent);
+               tracebox(position + '0 0 1' * (1 - PL_MIN_CONST.z), PL_MIN_CONST, PL_MAX_CONST, endpos, MOVE_NOMONSTERS, tracetest_ent);
        if(trace_fraction < 1)
                position = trace_endpos;
        return position;
@@ -1297,22 +1401,42 @@ void waypoint_spawnforteleporter_boxes(entity e, int teleport_flag, vector org1,
        e.nearestwaypointtimeout = -1;
 }
 
-void waypoint_spawnforteleporter_wz(entity e, vector src, vector destination, float timetaken, vector down_dir_src, vector down_dir_dest, entity tracetest_ent)
+void waypoint_spawnforteleporter_wz(entity e, entity tracetest_ent)
 {
-       // warpzones with oblique warp plane rely on down_dir to snap waypoints
-       // to the ground without leaving the warp plane
-       // warpzones with horizontal warp plane (down_dir.x == -1) generate
-       // destination waypoint snapped to the ground (leaving warpzone), source
-       // waypoint in the center of the warp plane
-
-       // snap to the ground only if source warpzone isn't horizontal
-       if(down_dir_src.x != -1)
+       float src_angle = e.warpzone_angles.x;
+       while (src_angle < -180) src_angle += 360;
+       while (src_angle > 180) src_angle -= 360;
+
+       float dest_angle = e.enemy.warpzone_angles.x;
+       while (dest_angle < -180) dest_angle += 360;
+       while (dest_angle > 180) dest_angle -= 360;
+
+       // no waypoints for warpzones pointing upwards, they can't be used by the bots
+       if (src_angle == -90 || dest_angle == -90)
+               return;
+
+       makevectors(e.warpzone_angles);
+       vector src = (e.absmin + e.absmax) * 0.5;
+       src += ((e.warpzone_origin - src) * v_forward) * v_forward + 16 * v_right;
+       vector down_dir_src = -v_up;
+
+       makevectors(e.enemy.warpzone_angles);
+       vector dest = (e.enemy.absmin + e.enemy.absmax) * 0.5;
+       dest += ((e.enemy.warpzone_origin - dest) * v_forward) * v_forward - 16 * v_right;
+       vector down_dir_dest = -v_up;
+
+       int extra_flag = 0;
+       // don't snap to the ground waypoints for source warpzones pointing downwards
+       if (src_angle != 90)
+       {
                src = waypoint_fixorigin_down_dir(src, tracetest_ent, down_dir_src);
-       if(down_dir_dest.x == -1) // horizontal
-               down_dir_dest = '0 0 -1'; // change to vertical
-       destination = waypoint_fixorigin_down_dir(destination, tracetest_ent, down_dir_dest);
+               dest = waypoint_fixorigin_down_dir(dest, tracetest_ent, down_dir_dest);
+               // oblique warpzones need a jump otherwise bots gets stuck
+               if (src_angle != 0)
+                       extra_flag = WAYPOINTFLAG_JUMP;
+       }
 
-       waypoint_spawnforteleporter_boxes(e, WAYPOINTFLAG_TELEPORT, src, src, destination, destination, timetaken);
+       waypoint_spawnforteleporter_boxes(e, WAYPOINTFLAG_TELEPORT | extra_flag, src, src, dest, dest, 0);
 }
 
 void waypoint_spawnforteleporter(entity e, vector destination, float timetaken, entity tracetest_ent)
@@ -1380,6 +1504,25 @@ void waypoint_showlinks_from(entity wp, int display_type)
        waypoint_showlink(wp.wp15, wp, display_type); waypoint_showlink(wp.wp31, wp, display_type);
 }
 
+void crosshair_trace_waypoints(entity pl)
+{
+       IL_EACH(g_waypoints, true, {
+               it.solid = SOLID_BSP;
+               if (!it.wpisbox)
+                       setsize(it, '-16 -16 -16', '16 16 16');
+       });
+
+       crosshair_trace(pl);
+
+       IL_EACH(g_waypoints, true, {
+               it.solid = SOLID_TRIGGER;
+               if (!it.wpisbox)
+                       setsize(it, '0 0 0', '0 0 0');
+       });
+       if (trace_ent.classname != "waypoint")
+               trace_ent = NULL;
+}
+
 void botframe_showwaypointlinks()
 {
        if (time < botframe_waypointeditorlightningtime)
@@ -1388,10 +1531,18 @@ void botframe_showwaypointlinks()
        FOREACH_CLIENT(IS_PLAYER(it) && !it.isbot,
        {
                int display_type = 0;
-               entity head = navigation_findnearestwaypoint(it, false);
+               if (wasfreed(it.wp_aimed))
+                       it.wp_aimed = NULL;
+               if (wasfreed(it.wp_locked))
+                       it.wp_locked = NULL;
+               if (PHYS_INPUT_BUTTON_USE(it))
+                       it.wp_locked = it.wp_aimed;
+               entity head = it.wp_locked;
+               if (!head)
+                       head = navigation_findnearestwaypoint(it, false);
                it.nearestwaypoint = head; // mainly useful for debug
                it.nearestwaypointtimeout = time + 2; // while I'm at it...
-               if (IS_ONGROUND(it) || it.waterlevel > WATERLEVEL_NONE)
+               if (IS_ONGROUND(it) || it.waterlevel > WATERLEVEL_NONE || it.wp_locked)
                        display_type = 1; // default
                else if(head && (head.wphardwired))
                        display_type = 2; // only hardwired
@@ -1410,6 +1561,29 @@ void botframe_showwaypointlinks()
                                        waypoint_showlinks_from(head, display_type);
                        }
                }
+               string str;
+               entity wp = NULL;
+               if (vdist(vec2(it.velocity), <, autocvar_sv_maxspeed * 1.1))
+               {
+                       crosshair_trace_waypoints(it);
+                       if (trace_ent)
+                       {
+                               wp = trace_ent;
+                               if (wp != it.wp_aimed)
+                               {
+                                       str = sprintf("\necho ^2WP info^7: entity: %d, flags: %d, origin: '%s'\n", etof(wp), wp.wpflags, vtos(wp.origin));
+                                       if (wp.wpisbox)
+                                               str = strcat(str, sprintf("echo \" absmin: '%s', absmax: '%s'\"\n", vtos(wp.absmin), vtos(wp.absmax)));
+                                       stuffcmd(it, str);
+                                       str = sprintf("entity: %d\nflags: %d\norigin: \'%s\'", etof(wp), wp.wpflags, vtos(wp.origin));
+                                       if (wp.wpisbox)
+                                               str = strcat(str, sprintf(" \nabsmin: '%s'\nabsmax: '%s'", vtos(wp.absmin), vtos(wp.absmax)));
+                                       debug_text_3d(wp.origin, str, 0, 7, '0 0 0');
+                               }
+                       }
+               }
+               if (it.wp_aimed != wp)
+                       it.wp_aimed = wp;
        });
 }