From 9a86b33a632e9f8a957267ada102a0e2e6047c09 Mon Sep 17 00:00:00 2001 From: terencehill Date: Mon, 15 Jul 2019 15:35:00 +0200 Subject: [PATCH] Bot waypoints: implement crouch waypoints, spawn them with "wpeditor spawn crouch". They can be connected from/to normal waypoints only if close enough --- qcsrc/common/constants.qh | 2 + qcsrc/server/bot/api.qh | 3 +- qcsrc/server/bot/default/havocbot/havocbot.qc | 19 ++++++- qcsrc/server/bot/default/waypoints.qc | 55 +++++++++++++++---- qcsrc/server/bot/default/waypoints.qh | 2 +- qcsrc/server/bot/null/bot_null.qc | 2 +- qcsrc/server/command/cmd.qc | 2 +- 7 files changed, 69 insertions(+), 16 deletions(-) diff --git a/qcsrc/common/constants.qh b/qcsrc/common/constants.qh index 15c1366ea1..a7e7da546e 100644 --- a/qcsrc/common/constants.qh +++ b/qcsrc/common/constants.qh @@ -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 diff --git a/qcsrc/server/bot/api.qh b/qcsrc/server/bot/api.qh index 4d9c5d706e..75062e6ace 100644 --- a/qcsrc/server/bot/api.qh +++ b/qcsrc/server/bot/api.qh @@ -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); diff --git a/qcsrc/server/bot/default/havocbot/havocbot.qc b/qcsrc/server/bot/default/havocbot/havocbot.qc index e9b9cdf41e..700ef1eeb6 100644 --- a/qcsrc/server/bot/default/havocbot/havocbot.qc +++ b/qcsrc/server/bot/default/havocbot/havocbot.qc @@ -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) diff --git a/qcsrc/server/bot/default/waypoints.qc b/qcsrc/server/bot/default/waypoints.qc index 6a9dfc9256..488e538b8a 100644 --- a/qcsrc/server/bot/default/waypoints.qc +++ b/qcsrc/server/bot/default/waypoints.qc @@ -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; diff --git a/qcsrc/server/bot/default/waypoints.qh b/qcsrc/server/bot/default/waypoints.qh index cf4f4c182e..3676ca5f4e 100644 --- a/qcsrc/server/bot/default/waypoints.qh +++ b/qcsrc/server/bot/default/waypoints.qh @@ -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); diff --git a/qcsrc/server/bot/null/bot_null.qc b/qcsrc/server/bot/null/bot_null.qc index e0c9fd8129..f3b362e871 100644 --- a/qcsrc/server/bot/null/bot_null.qc +++ b/qcsrc/server/bot/null/bot_null.qc @@ -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 diff --git a/qcsrc/server/command/cmd.qc b/qcsrc/server/command/cmd.qc index 96389c30d7..d79a290174 100644 --- a/qcsrc/server/command/cmd.qc +++ b/qcsrc/server/command/cmd.qc @@ -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") -- 2.39.2