Bot waypoints: implement crouch waypoints, spawn them with "wpeditor spawn crouch...
authorterencehill <piuntn@gmail.com>
Mon, 15 Jul 2019 13:35:00 +0000 (15:35 +0200)
committerterencehill <piuntn@gmail.com>
Mon, 15 Jul 2019 13:35:00 +0000 (15:35 +0200)
qcsrc/common/constants.qh
qcsrc/server/bot/api.qh
qcsrc/server/bot/default/havocbot/havocbot.qc
qcsrc/server/bot/default/waypoints.qc
qcsrc/server/bot/default/waypoints.qh
qcsrc/server/bot/null/bot_null.qc
qcsrc/server/command/cmd.qc

index 15c1366..a7e7da5 100644 (file)
@@ -50,6 +50,8 @@ const int SERVERFLAG_PLAYERSTATS = 4;
 // a bit more constant
 const vector PL_MAX_CONST = '16 16 45';
 const vector PL_MIN_CONST = '-16 -16 -24';
+const vector PL_CROUCH_MAX_CONST = '16 16 25';
+const vector PL_CROUCH_MIN_CONST = '-16 -16 -24';
 
 // gametype vote flags
 const int GTV_FORBIDDEN = 0; // Cannot be voted
index 4d9c5d7..75062e6 100644 (file)
@@ -15,6 +15,7 @@ const int WAYPOINTFLAG_DEAD_END = BIT(16);  // Useless WP detection temporary fl
 const int WAYPOINTFLAG_LADDER = BIT(15);
 const int WAYPOINTFLAG_JUMP = BIT(14);
 const int WAYPOINTFLAG_CUSTOM_JP = BIT(13);  // jumppad with different destination waypoint (changed in the editor)
+const int WAYPOINTFLAG_CROUCH = BIT(12);
 
 entity kh_worldkeylist;
 .entity kh_worldkeynext;
@@ -122,7 +123,7 @@ void waypoint_spawnforitem(entity e);
 void waypoint_spawnforitem_force(entity e, vector org);
 void waypoint_spawnforteleporter(entity e, vector destination, float timetaken, entity tracetest_ent);
 void waypoint_spawnforteleporter_wz(entity e, entity tracetest_ent);
-void waypoint_spawn_fromeditor(entity pl, bool at_crosshair, bool is_jump_wp);
+void waypoint_spawn_fromeditor(entity pl, bool at_crosshair, bool is_jump_wp, bool is_crouch_wp);
 entity waypoint_spawn(vector m1, vector m2, float f);
 void waypoint_unreachable(entity pl);
 
index e9b9cdf..700ef1e 100644 (file)
@@ -288,7 +288,7 @@ void havocbot_bunnyhop(entity this, vector dir)
                return;
        }
 
-       if(this.waterlevel > WATERLEVEL_WETFEET)
+       if(this.waterlevel > WATERLEVEL_WETFEET || this.maxs.z == PL_CROUCH_MAX_CONST.z)
        {
                this.aistatus &= ~AI_STATUS_RUNNING;
                return;
@@ -479,6 +479,11 @@ void havocbot_movetogoal(entity this)
        CS(this).movement = '0 0 0';
        maxspeed = autocvar_sv_maxspeed;
 
+       if (this.goalcurrent.wpflags & WAYPOINTFLAG_CROUCH)
+               PHYS_INPUT_BUTTON_CROUCH(this) = true;
+       else
+               PHYS_INPUT_BUTTON_CROUCH(this) = false;
+
        PHYS_INPUT_BUTTON_JETPACK(this) = false;
        // Jetpack navigation
        if(this.navigation_jetpack_goal)
@@ -1055,7 +1060,17 @@ void havocbot_movetogoal(entity this)
                        LABEL(jumpobstacle_check);
                        dir = flatdir = normalize(actual_destorg - this.origin);
 
-                       if (turning || fabs(deviation.y) < 50) // don't even try to jump if deviation is too high
+                       bool jump_forbidden = false;
+                       if (!turning && fabs(deviation.y) > 50)
+                               jump_forbidden = true;
+                       else if (this.maxs.z == PL_CROUCH_MAX_CONST.z)
+                       {
+                               tracebox(this.origin, PL_MIN_CONST, PL_MAX_CONST, this.origin, false, this);
+                               if (trace_startsolid)
+                                       jump_forbidden = true;
+                       }
+
+                       if (!jump_forbidden)
                        {
                                tracebox(this.origin, this.mins, this.maxs, actual_destorg, false, this);
                                if (trace_fraction < 1 && trace_plane_normal.z < 0.7)
index 6a9dfc9..488e538 100644 (file)
@@ -345,11 +345,13 @@ void waypoint_setupmodel(entity wp)
                setsize(wp, m1, m2);
                wp.effects = EF_LOWPRECISION;
                if (wp.wpflags & WAYPOINTFLAG_ITEM)
-                       wp.colormod = '1 0 0';
+                       wp.colormod = '1 0 0'; // red
                else if (wp.wpflags & WAYPOINTFLAG_GENERATED)
-                       wp.colormod = '1 1 0';
+                       wp.colormod = '1 1 0'; // yellow
                else if (wp.wpflags & WAYPOINTFLAG_NORELINK)
                        wp.colormod = '1 0.5 0'; // orange
+               else if (wp.wpflags & WAYPOINTFLAG_CROUCH)
+                       wp.colormod = '0 1 1'; // cyan
                else if (waypoint_has_hardwiredlinks(wp))
                        wp.colormod = '0.5 0 1'; // purple
                else
@@ -404,7 +406,10 @@ entity waypoint_spawn(vector m1, vector m2, float f)
 
        if(!w.wpisbox)
        {
-               setsize(w, PL_MIN_CONST - '1 1 0', PL_MAX_CONST + '1 1 0');
+               if (f & WAYPOINTFLAG_CROUCH)
+                       setsize(w, PL_CROUCH_MIN_CONST - '1 1 0', PL_CROUCH_MAX_CONST + '1 1 0');
+               else
+                       setsize(w, PL_MIN_CONST - '1 1 0', PL_MAX_CONST + '1 1 0');
                if(!move_out_of_solid(w))
                {
                        if(!(f & WAYPOINTFLAG_GENERATED))
@@ -481,7 +486,7 @@ void waypoint_start_hardwiredlink(entity pl)
                start_wp_is_hardwired = false;
 }
 
-void waypoint_spawn_fromeditor(entity pl, bool at_crosshair, bool is_jump_wp)
+void waypoint_spawn_fromeditor(entity pl, bool at_crosshair, bool is_jump_wp, bool is_crouch_wp)
 {
        if (WAYPOINT_VERSION < waypoint_version_loaded)
        {
@@ -572,7 +577,7 @@ void waypoint_spawn_fromeditor(entity pl, bool at_crosshair, bool is_jump_wp)
                        pl.wp_locked = e;
        }
        else
-               e = waypoint_spawn(org, org, 0);
+               e = waypoint_spawn(org, org, (is_crouch_wp) ? WAYPOINTFLAG_CROUCH : 0);
        if(!e)
        {
                LOG_INFOF("Couldn't spawn waypoint at %v\n", org);
@@ -618,7 +623,7 @@ void waypoint_spawn_fromeditor(entity pl, bool at_crosshair, bool is_jump_wp)
                                        LOG_INFO("Error: hardwired links can be created only between 2 existing (and unconnected) waypoints.\n");
                                        waypoint_remove(e);
                                        waypoint_clear_start_wp(pl, true);
-                                       waypoint_spawn_fromeditor(pl, at_crosshair, is_jump_wp);
+                                       waypoint_spawn_fromeditor(pl, at_crosshair, is_jump_wp, is_crouch_wp);
                                        return;
                                }
                                if (start_wp == e)
@@ -889,12 +894,18 @@ float waypoint_getlinearcost(float dist)
                return dist / (autocvar_sv_maxspeed * 1.25);
        return dist / autocvar_sv_maxspeed;
 }
+
 float waypoint_getlinearcost_underwater(float dist)
 {
        // NOTE: underwater speed factor is hardcoded in the engine too, see SV_WaterMove
        return dist / (autocvar_sv_maxspeed * 0.7);
 }
 
+float waypoint_getlinearcost_crouched(float dist)
+{
+       return dist / (autocvar_sv_maxspeed * 0.5);
+}
+
 float waypoint_gettravelcost(vector from, vector to, entity from_ent, entity to_ent)
 {
        bool submerged_from = navigation_check_submerged_state(from_ent, from);
@@ -903,12 +914,15 @@ float waypoint_gettravelcost(vector from, vector to, entity from_ent, entity to_
        if (submerged_from && submerged_to)
                return waypoint_getlinearcost_underwater(vlen(to - from));
 
+       if (from_ent.wpflags & WAYPOINTFLAG_CROUCH && to_ent.wpflags & WAYPOINTFLAG_CROUCH)
+               return waypoint_getlinearcost_crouched(vlen(to - from));
+
        float c = waypoint_getlinearcost(vlen(to - from));
 
        float height = from.z - to.z;
        if(height > jumpheight_vec.z && autocvar_sv_gravity > 0)
        {
-               float height_cost;
+               float height_cost; // fall cost
                if (boolean(from_ent.wpflags & WAYPOINTFLAG_JUMP))
                        height_cost = jumpheight_time + sqrt((height + jumpheight_vec.z) / (autocvar_sv_gravity / 2));
                else
@@ -918,8 +932,14 @@ float waypoint_gettravelcost(vector from, vector to, entity from_ent, entity to_
                        c = height_cost;
        }
 
+       // consider half path underwater
        if (submerged_from || submerged_to)
                return (c + waypoint_getlinearcost_underwater(vlen(to - from))) / 2;
+
+       // consider half path crouched
+       if (from_ent.wpflags & WAYPOINTFLAG_CROUCH || to_ent.wpflags & WAYPOINTFLAG_CROUCH)
+               return (c + waypoint_getlinearcost_crouched(vlen(to - from))) / 2;
+
        return c;
 }
 
@@ -1040,7 +1060,22 @@ void waypoint_think(entity this)
 
                        dv = ev - sv;
                        dv.z = 0;
-                       if(vdist(dv, >=, 1050)) // max search distance in XY
+                       int maxdist = 1050;
+                       vector m1 = PL_MIN_CONST;
+                       vector m2 = PL_MAX_CONST;
+
+                       if (this.wpflags & WAYPOINTFLAG_CROUCH || it.wpflags & WAYPOINTFLAG_CROUCH)
+                       {
+                               m1 = PL_CROUCH_MIN_CONST;
+                               m2 = PL_CROUCH_MAX_CONST;
+                               // links from crouch wp to normal wp (and viceversa) are very short to avoid creating many links
+                               // that would be wasted due to rough travel cost calculation (the longer link is, the higher cost is)
+                               // links from crouch wp to crouch wp can be as long as normal links
+                               if (!(this.wpflags & WAYPOINTFLAG_CROUCH && it.wpflags & WAYPOINTFLAG_CROUCH))
+                                       maxdist = 100;
+                       }
+
+                       if (vdist(dv, >=, maxdist)) // max search distance in XY
                        {
                                ++relink_lengthculled;
                                continue;
@@ -1054,7 +1089,7 @@ void waypoint_think(entity this)
                                relink_walkculled += 0.5;
                        else
                        {
-                               if (tracewalk(this, sv, PL_MIN_CONST, PL_MAX_CONST, ev2, ev2_height, MOVE_NOMONSTERS))
+                               if (tracewalk(this, sv, m1, m2, ev2, ev2_height, MOVE_NOMONSTERS))
                                        waypoint_addlink(this, it);
                                else
                                        relink_walkculled += 0.5;
@@ -1064,7 +1099,7 @@ void waypoint_think(entity this)
                                relink_walkculled += 0.5;
                        else
                        {
-                               if (tracewalk(this, ev, PL_MIN_CONST, PL_MAX_CONST, sv2, sv2_height, MOVE_NOMONSTERS))
+                               if (tracewalk(this, ev, m1, m2, sv2, sv2_height, MOVE_NOMONSTERS))
                                        waypoint_addlink(it, this);
                                else
                                        relink_walkculled += 0.5;
index cf4f4c1..3676ca5 100644 (file)
@@ -84,7 +84,7 @@ float waypoint_loadall();
 bool waypoint_load_links();
 void waypoint_load_hardwiredlinks();
 
-void waypoint_spawn_fromeditor(entity pl, bool at_crosshair, bool is_jump_wp);
+void waypoint_spawn_fromeditor(entity pl, bool at_crosshair, bool is_jump_wp, bool is_crouch_wp);
 entity waypoint_spawn(vector m1, vector m2, float f);
 entity waypoint_spawnpersonal(entity this, vector position);
 
index e0c9fd8..f3b362e 100644 (file)
@@ -39,6 +39,6 @@ void waypoint_spawnforitem(entity e) { }
 void waypoint_spawnforitem_force(entity e, vector org) { }
 void waypoint_spawnforteleporter(entity e, vector destination, float timetaken, entity tracetest_ent) { }
 void waypoint_spawnforteleporter_wz(entity e, entity tracetest_ent) { }
-void waypoint_spawn_fromeditor(entity pl, bool at_crosshair, bool is_jump_wp) { }
+void waypoint_spawn_fromeditor(entity pl, bool at_crosshair, bool is_jump_wp, bool is_crouch_wp) { }
 entity waypoint_spawn(vector m1, vector m2, float f) { return NULL; }
 #endif
index 96389c3..d79a290 100644 (file)
@@ -187,7 +187,7 @@ void ClientCommand_wpeditor(entity caller, int request, int argc)
                                        if (!IS_PLAYER(caller))
                                                sprint(caller, "ERROR: this command works only if you are player\n");
                                        else
-                                               waypoint_spawn_fromeditor(caller, (argv(2) == "crosshair"), (argv(2) == "jump"));
+                                               waypoint_spawn_fromeditor(caller, (argv(2) == "crosshair"), (argv(2) == "jump"), (argv(2) == "crouch"));
                                        return;
                                }
                                else if (argv(1) == "remove")