X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fbot%2Fdefault%2Fwaypoints.qc;h=c3b67a378fef08ac1a7823ceeb7064f049ef86a3;hb=042089583dd3eae6bbe1cbdf85bd694d5bd1bb0c;hp=f801052931068723de996146058a160e8cbf936b;hpb=5921f17b0750d3666917008465afaf1b05d2088e;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/bot/default/waypoints.qc b/qcsrc/server/bot/default/waypoints.qc index f80105293..c3b67a378 100644 --- a/qcsrc/server/bot/default/waypoints.qc +++ b/qcsrc/server/bot/default/waypoints.qc @@ -1,5 +1,7 @@ #include "waypoints.qh" +#include +#include #include "cvars.qh" #include "bot.qh" @@ -168,6 +170,8 @@ void waypoint_setupmodel(entity wp) wp.colormod = '1 0 0'; else if (wp.wpflags & WAYPOINTFLAG_GENERATED) wp.colormod = '1 1 0'; + else if (wp.wphardwired) + wp.colormod = '0.5 0 1'; else wp.colormod = '1 1 1'; } @@ -182,9 +186,8 @@ entity waypoint_spawn(vector m1, vector m2, float f) { if(!(f & WAYPOINTFLAG_PERSONAL)) { - vector em1 = m1; - vector em2 = m2; - if (m1 == m2) + vector em1 = m1, em2 = m2; + if (!(f & WAYPOINTFLAG_GENERATED) && m1 == m2) { em1 = m1 - '8 8 8'; em2 = m2 + '8 8 8'; @@ -220,7 +223,7 @@ entity waypoint_spawn(vector m1, vector m2, float f) { if(autocvar_developer) { - LOG_INFO("A generated waypoint is stuck in solid at ", vtos(w.origin), "\n"); + LOG_INFO("A generated waypoint is stuck in solid at ", vtos(w.origin)); backtrace("Waypoint stuck"); } } @@ -267,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); @@ -443,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; @@ -456,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; } @@ -465,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 @@ -537,15 +559,14 @@ void waypoint_addlink(entity from, entity to) // (SLOW!) void waypoint_think(entity this) { - vector sv, sm1, sm2, ev, em1, em2, dv; + 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(); bot_navigation_movemode = ((autocvar_bot_navigation_ignoreplayers) ? MOVE_NOMONSTERS : MOVE_NORMAL); //dprint("waypoint_think wpisbox = ", ftos(this.wpisbox), "\n"); - sm1 = this.origin + this.mins; - sm2 = this.origin + this.maxs; IL_EACH(g_waypoints, this != it, { if (boxesoverlap(this.absmin, this.absmax, it.absmin, it.absmax)) @@ -561,16 +582,10 @@ void waypoint_think(entity this) ++relink_pvsculled; continue; } - sv = it.origin; - sv.x = bound(sm1_x, sv.x, sm2_x); - sv.y = bound(sm1_y, sv.y, sm2_y); - sv.z = bound(sm1_z, sv.z, sm2_z); - ev = this.origin; - em1 = it.origin + it.mins; - em2 = it.origin + it.maxs; - ev.x = bound(em1_x, ev.x, em2_x); - ev.y = bound(em1_y, ev.y, em2_y); - ev.z = bound(em1_z, ev.z, em2_z); + + SET_TRACEWALK_DESTCOORDS_2(this, it.origin, sv, sv2, sv2_height); + SET_TRACEWALK_DESTCOORDS_2(it, this.origin, ev, ev2, ev2_height); + dv = ev - sv; dv.z = 0; if(vdist(dv, >=, 1050)) // max search distance in XY @@ -578,39 +593,16 @@ void waypoint_think(entity this) ++relink_lengthculled; continue; } - float sv_deviation = 0; - float ev_deviation = 0; + navigation_testtracewalk = 0; - if (!this.wpisbox) - { - tracebox(sv - PL_MIN_CONST.z * '0 0 1', PL_MIN_CONST, PL_MAX_CONST, sv, false, this); - if (!trace_startsolid) - { - //dprint("sv deviation", vtos(trace_endpos - sv), "\n"); - sv_deviation = trace_endpos.z + 1 - sv.z; - sv = trace_endpos + '0 0 1'; - } - } - if (!it.wpisbox) - { - tracebox(ev - PL_MIN_CONST.z * '0 0 1', PL_MIN_CONST, PL_MAX_CONST, ev, false, it); - if (!trace_startsolid) - { - //dprint("ev deviation", vtos(trace_endpos - ev), "\n"); - ev_deviation = trace_endpos.z + 1 - ev.z; - ev = trace_endpos + '0 0 1'; - } - } + //traceline(this.origin, it.origin, false, NULL); //if (trace_fraction == 1) if (this.wpisbox) relink_walkculled += 0.5; else { - vector dest = ev; - dest.z = em1.z + ev_deviation; - float dest_height = em2.z - em1.z; - if(tracewalk(this, sv, PL_MIN_CONST, PL_MAX_CONST, dest, dest_height, MOVE_NOMONSTERS)) + if (tracewalk(this, sv, PL_MIN_CONST, PL_MAX_CONST, ev2, ev2_height, MOVE_NOMONSTERS)) waypoint_addlink(this, it); else relink_walkculled += 0.5; @@ -620,10 +612,7 @@ void waypoint_think(entity this) relink_walkculled += 0.5; else { - vector dest = sv; - dest.z = sm1.z + sv_deviation; - float dest_height = sm2.z - sm1.z; - if(tracewalk(it, ev, PL_MIN_CONST, PL_MAX_CONST, dest, dest_height, MOVE_NOMONSTERS)) + if (tracewalk(it, ev, PL_MIN_CONST, PL_MAX_CONST, sv2, sv2_height, MOVE_NOMONSTERS)) waypoint_addlink(it, this); else relink_walkculled += 0.5; @@ -712,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, 17) == "WAYPOINT_VERSION ") + ver = stof(substring(s, 19, -1)); + continue; + } + else + { + if(ver < WAYPOINT_VERSION) + return false; + parse_comments = false; + } + } + tokens = tokenizebyseparator(s, "*"); if (tokens!=2) @@ -836,7 +844,7 @@ void waypoint_load_or_remove_links_hardwired(bool removal_mode) if(!found) { if(!removal_mode) - LOG_INFO(strcat("NOTICE: Can not find waypoint at ", vtos(wp_from_pos), ". Path skipped\n")); + LOG_INFO("NOTICE: Can not find waypoint at ", vtos(wp_from_pos), ". Path skipped"); continue; } } @@ -858,7 +866,7 @@ void waypoint_load_or_remove_links_hardwired(bool removal_mode) if(!found) { if(!removal_mode) - LOG_INFO(strcat("NOTICE: Can not find waypoint at ", vtos(wp_to_pos), ". Path skipped\n")); + LOG_INFO("NOTICE: Can not find waypoint at ", vtos(wp_to_pos), ". Path skipped"); continue; } @@ -872,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); @@ -880,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) @@ -933,10 +940,12 @@ void waypoint_save_links() int file = fopen(filename, FILE_WRITE); if (file < 0) { - LOG_INFOF("waypoint link save to %s failed\n", filename); + LOG_INFOF("waypoint link save to %s failed", filename); return; } + fputs(file, strcat("//", "WAYPOINT_VERSION ", ftos_decimals(WAYPOINT_VERSION, 2), "\n")); + int c = 0; IL_EACH(g_waypoints, true, { @@ -954,7 +963,7 @@ void waypoint_save_links() fclose(file); botframe_cachedwaypointlinks = true; - LOG_INFOF("saved %d waypoint links to maps/%s.waypoints.cache\n", c, mapname); + LOG_INFOF("saved %d waypoint links to maps/%s.waypoints.cache", c, mapname); waypoint_load_links_hardwired(); } @@ -969,10 +978,16 @@ void waypoint_saveall() waypoint_save_links(); // save anyway? botframe_loadedforcedlinks = false; - LOG_INFOF("waypoint links: save to %s failed\n", filename); + LOG_INFOF("waypoint links: save to %s failed", filename); 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("//", "WAYPOINT_VERSION ", ftos_decimals(WAYPOINT_VERSION, 2), "\n")); + fputs(file, strcat("//", "\n")); + fputs(file, strcat("//", "\n")); + int c = 0; IL_EACH(g_waypoints, true, { @@ -992,7 +1007,7 @@ void waypoint_saveall() waypoint_save_links(); botframe_loadedforcedlinks = false; - LOG_INFOF("saved %d waypoints to maps/%s.waypoints\n", c, mapname); + LOG_INFOF("saved %d waypoints to maps/%s.waypoints", c, mapname); } // load waypoints from file @@ -1006,49 +1021,73 @@ 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, 17) == "WAYPOINT_VERSION ") + ver = stof(substring(s, 19, -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) +#define waypoint_fixorigin(position, tracetest_ent) \ + waypoint_fixorigin_down_dir(position, tracetest_ent, '0 0 -1') + +vector waypoint_fixorigin_down_dir(vector position, entity tracetest_ent, vector down_dir) { - 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', PL_MIN_CONST, PL_MAX_CONST, position + down_dir * 3000, 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); + 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); 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, @@ -1097,17 +1136,25 @@ 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, vector down_dir, entity tracetest_ent) { - org = waypoint_fixorigin(org); - destination = waypoint_fixorigin(destination); + // 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 + if(down_dir.x != -1) + org = waypoint_fixorigin_down_dir(org, tracetest_ent, down_dir); + if(down_dir.x == -1) + down_dir = '0 0 -1'; + destination = waypoint_fixorigin_down_dir(destination, tracetest_ent, down_dir); 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); - waypoint_spawnforteleporter_boxes(e, WAYPOINTFLAG_TELEPORT, e.absmin, e.absmax, destination, destination, timetaken); + 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); } entity waypoint_spawnpersonal(entity this, vector position) @@ -1117,7 +1164,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; @@ -1246,7 +1293,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, 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); @@ -1262,8 +1309,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, walkfromwp, 1050)) - if(navigation_waypoint_will_link(it.origin, porg, p, 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; @@ -1271,7 +1318,7 @@ float botframe_autowaypoints_fix_from(entity p, float walkfromwp, entity wp, .en }); if(bestdist < maxdist) { - LOG_INFO("update chain to new nearest WP ", etos(p.(fld)), "\n"); + LOG_INFO("update chain to new nearest WP ", etos(p.(fld))); return 0; } @@ -1317,7 +1364,7 @@ float botframe_autowaypoints_fix_from(entity p, float walkfromwp, entity wp, .en if(wp) { - if(!navigation_waypoint_will_link(wp.origin, o, p, 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 @@ -1343,14 +1390,14 @@ 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, 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 tmax = t; } - LOG_INFO("spawning a waypoint for connecting to ", etos(wp), "\n"); + LOG_INFO("spawning a waypoint for connecting to ", etos(wp)); botframe_autowaypoints_createwp(o, p, fld, 0); return 1; } @@ -1366,7 +1413,7 @@ void botframe_autowaypoints_fix(entity p, float walkfromwp, .entity fld) if(r != -1) return; - LOG_INFO("emergency: got no good nearby WP to build a link from, starting a new chain\n"); + LOG_INFO("emergency: got no good nearby WP to build a link from, starting a new chain"); if(!botframe_autowaypoints_fixdown(p.origin)) return; // shouldn't happen, caught above botframe_autowaypoints_createwp(trace_endpos, p, fld, WAYPOINTFLAG_PROTECTED); @@ -1440,7 +1487,7 @@ LABEL(next) IL_EACH(g_waypoints, !(it.wpflags & (WAYPOINTFLAG_USEFUL | WAYPOINTFLAG_DEAD_END)), { - LOG_INFOF("Removed a waypoint at %v. Try again for more!\n", it.origin); + LOG_INFOF("Removed a waypoint at %v. Try again for more!", it.origin); te_explosion(it.origin); waypoint_remove(it); break; @@ -1454,12 +1501,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();