X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;ds=sidebyside;f=qcsrc%2Fserver%2Fbot%2Fdefault%2Fwaypoints.qc;h=c3b67a378fef08ac1a7823ceeb7064f049ef86a3;hb=042089583dd3eae6bbe1cbdf85bd694d5bd1bb0c;hp=44fd9da42a1e23f7640ecb93983ce8078cbb3a7c;hpb=94add1f553e1ac7cf7de8d8c2d89ea3025bb3eb0;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/bot/default/waypoints.qc b/qcsrc/server/bot/default/waypoints.qc index 44fd9da42..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" @@ -221,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"); } } @@ -268,6 +270,11 @@ 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(e.origin), "\n")); if(sym) @@ -450,8 +457,11 @@ float waypoint_getlinearcost_underwater(float dist) return dist / (autocvar_sv_maxspeed * 0.7); } -float waypoint_gettravelcost(vector from, vector to, bool submerged_from, bool submerged_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)); @@ -477,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, SUBMERGED(v1), SUBMERGED(v2)); + return waypoint_gettravelcost(v1, v2, from, to); } // add a new link to the spawnfunc_waypoint, replacing the furthest link it already has @@ -549,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(); @@ -691,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) @@ -815,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; } } @@ -837,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; } @@ -851,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); @@ -859,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) @@ -912,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, { @@ -933,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(); } @@ -948,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, { @@ -971,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 @@ -985,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, @@ -1076,16 +1136,24 @@ 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); + 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); } @@ -1096,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; @@ -1225,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, 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); @@ -1241,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, 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; @@ -1250,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; } @@ -1296,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, 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 @@ -1322,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, 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 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; } @@ -1345,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); @@ -1419,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; @@ -1433,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();