From 3df1d2edb58f2044cd0b077f0f15055540280164 Mon Sep 17 00:00:00 2001 From: terencehill Date: Sat, 29 Jun 2019 15:58:59 +0200 Subject: [PATCH] Bot waypoints: save jump and custom jumppad links to .waypoints.hardwired in a format that is backward compatible: they can't be read by previous Xonotic versions, normal hardwired links can still be added/edited manually in the beginning of the file and won't be touched on save --- qcsrc/server/bot/api.qh | 1 + qcsrc/server/bot/default/waypoints.qc | 136 ++++++++++++++++++++++++-- qcsrc/server/bot/default/waypoints.qh | 3 + 3 files changed, 133 insertions(+), 7 deletions(-) diff --git a/qcsrc/server/bot/api.qh b/qcsrc/server/bot/api.qh index f0d1f4541b..5d74a98a1e 100644 --- a/qcsrc/server/bot/api.qh +++ b/qcsrc/server/bot/api.qh @@ -14,6 +14,7 @@ const int WAYPOINTFLAG_USEFUL = BIT(17); // Useless WP detection temporary flag const int WAYPOINTFLAG_DEAD_END = BIT(16); // Useless WP detection temporary flag. 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) entity kh_worldkeylist; .entity kh_worldkeynext; diff --git a/qcsrc/server/bot/default/waypoints.qc b/qcsrc/server/bot/default/waypoints.qc index 4a73af1c7d..e9edec6bf2 100644 --- a/qcsrc/server/bot/default/waypoints.qc +++ b/qcsrc/server/bot/default/waypoints.qc @@ -512,6 +512,13 @@ void waypoint_spawn_fromeditor(entity pl, bool at_crosshair, bool is_jump_wp) { pl.wp_locked = NULL; waypoint_schedulerelink(start_wp); + if (start_wp.wpflags & WAYPOINTFLAG_TELEPORT) + { + if (start_wp.wp00_original == start_wp.wp00) + start_wp.wpflags &= ~WAYPOINTFLAG_CUSTOM_JP; + else + start_wp.wpflags |= WAYPOINTFLAG_CUSTOM_JP; + } } if (sym) @@ -576,6 +583,7 @@ void waypoint_remove_fromeditor(entity pl) LABEL(remove_wp); if (!e) return; + if (e.wpflags & WAYPOINTFLAG_GENERATED) { if (start_wp_is_spawned) @@ -1106,6 +1114,8 @@ bool waypoint_load_links() ++c; waypoint_addlink(wp_from, wp_to); + if (wp_from.wp00_original && wp_from.wp00_original != wp_from.wp00) + wp_from.wpflags |= WAYPOINTFLAG_CUSTOM_JP; } fclose(file); @@ -1156,6 +1166,7 @@ void waypoint_load_or_remove_links_hardwired(bool removal_mode) return; } + bool is_special = false; while ((s = fgets(file))) { if(substring(s, 0, 2)=="//") @@ -1164,6 +1175,14 @@ void waypoint_load_or_remove_links_hardwired(bool removal_mode) if(substring(s, 0, 1)=="#") continue; + // special links start with *, so old xonotic versions don't load them + is_special = false; + if (substring(s, 0, 1) == "*") + { + is_special = true; + s = substring(s, 1, -1); + } + tokens = tokenizebyseparator(s, "*"); if (tokens!=2) @@ -1218,17 +1237,24 @@ void waypoint_load_or_remove_links_hardwired(bool removal_mode) } ++c; - if(removal_mode) + if (removal_mode && !is_special) { waypoint_removelink(wp_from, wp_to); continue; } - waypoint_addlink(wp_from, wp_to); - wp_from.wphardwired = true; - wp_to.wphardwired = true; - waypoint_setupmodel(wp_from); - waypoint_setupmodel(wp_to); + if (!is_special) + { + waypoint_addlink(wp_from, wp_to); + wp_from.wphardwired = true; + wp_to.wphardwired = true; + waypoint_setupmodel(wp_from); + waypoint_setupmodel(wp_to); + } else if (wp_from.wpflags & WAYPOINTFLAG_NORELINK + && (wp_from.wpflags & WAYPOINTFLAG_JUMP || (wp_from.wpisbox && wp_from.wpflags & WAYPOINTFLAG_TELEPORT))) + { + waypoint_addlink(wp_from, wp_to); + } } fclose(file); @@ -1277,6 +1303,99 @@ entity waypoint_get_link(entity w, float i) } } +// Save all hardwired waypoint links to a file +void waypoint_save_links_hardwired() +{ + string gt_ext = GET_GAMETYPE_EXTENSION(); + + string filename = sprintf("maps/%s.waypoints.hardwired", strcat(mapname, gt_ext)); + int file = fopen(filename, FILE_READ); + + if (gt_ext != "" && file < 0) + { + // if race waypoint file doesn't exist load the default one + filename = sprintf("maps/%s.waypoints.hardwired", mapname); + file = fopen(filename, FILE_READ); + } + + if (file < 0) + { + filename = sprintf("maps/%s.waypoints.hardwired", strcat(mapname, gt_ext)); + file = fopen(filename, FILE_WRITE); + if (file < 0) + { + LOG_TRACE("waypoint hardwired links ", filename, " creation failed"); + return; + } + fputs(file, "// HARDWIRED LINKS\n\n"); + fclose(file); + fopen(filename, FILE_READ); + if (file < 0) + { + LOG_TRACE("waypoint hardwired links load from ", filename, " failed"); + return; + } + } + + int buf = buf_create(); + string s; + int pos = 0; + + // read comments and hardwired links from file to buf, they won't be changed + while ((s = fgets(file))) + { + // special links start with *, so old xonotic versions don't load them + if (substring(s, 0, 1) == "*") + break; + bufstr_add(buf, s, false); + ++pos; + } + fclose(file); + + // read links to buf + bool special_link_found = false; + IL_EACH(g_waypoints, it.wpflags & (WAYPOINTFLAG_JUMP | WAYPOINTFLAG_CUSTOM_JP), + { + for (int j = 0; j < 32; ++j) + { + entity link = waypoint_get_link(it, j); + if (link) + { + if (!special_link_found) + { + special_link_found = true; + if (pos == 0 || substring(bufstr_get(buf, pos - 1), 0, 16) != "// SPECIAL LINKS") + { + bufstr_add(buf, "// SPECIAL LINKS (saved in the waypoint editor, comments added hereby won't be preserved)", false); + } + } + // NOTE: vtos rounds vector components to 1 decimal place + string s = strcat("*", vtos(it.origin), "*", vtos(link.origin)); + bufstr_add(buf, s, false); + } + } + }); + + // write buf to file + gt_ext = GET_GAMETYPE_EXTENSION(); + filename = sprintf("maps/%s.waypoints.hardwired", strcat(mapname, gt_ext)); + file = fopen(filename, FILE_WRITE); + if (file < 0) + { + LOG_INFOF("waypoint hardwired link save to %s failed", filename); + return; + } + int n = buf_getsize(buf); + for (int i = 0; i < n; ++i) + { + fputs(file, (strcat(bufstr_get(buf, i), "\n"))); + } + buf_del(buf); + fclose(file); + + LOG_INFOF("saved hardwired waypoint links to %s", filename); +} + // Save all waypoint links to a file void waypoint_save_links() { @@ -1298,7 +1417,7 @@ void waypoint_save_links() fputs(file, strcat("//", "WAYPOINT_TIME ", waypoint_time, "\n")); int c = 0; - IL_EACH(g_waypoints, true, + IL_EACH(g_waypoints, !(it.wpflags & (WAYPOINTFLAG_JUMP | WAYPOINTFLAG_CUSTOM_JP)), { for(int j = 0; j < 32; ++j) { @@ -1389,6 +1508,8 @@ void waypoint_saveall() }); fclose(file); waypoint_save_links(); + waypoint_save_links_hardwired(); + botframe_loadedforcedlinks = false; LOG_INFOF("saved %d waypoints to %s", c, filename); @@ -1566,6 +1687,7 @@ void waypoint_spawnforteleporter_boxes(entity e, int teleport_flag, vector org1, w = waypoint_spawn(org1, org2, WAYPOINTFLAG_GENERATED | teleport_flag | WAYPOINTFLAG_NORELINK); dw = waypoint_spawn(destination1, destination2, WAYPOINTFLAG_GENERATED); // one way link to the destination + w.wp00_original = dw; w.wp00 = dw; w.wp00mincost = timetaken; // this is just for jump pads // the teleporter's nearest spawnfunc_waypoint is this one diff --git a/qcsrc/server/bot/default/waypoints.qh b/qcsrc/server/bot/default/waypoints.qh index 9c8b507a56..920d6a8db2 100644 --- a/qcsrc/server/bot/default/waypoints.qh +++ b/qcsrc/server/bot/default/waypoints.qh @@ -21,6 +21,9 @@ float botframe_cachedwaypointlinks; .entity wp00, wp01, wp02, wp03, wp04, wp05, wp06, wp07, wp08, wp09, wp10, wp11, wp12, wp13, wp14, wp15; .entity wp16, wp17, wp18, wp19, wp20, wp21, wp22, wp23, wp24, wp25, wp26, wp27, wp28, wp29, wp30, wp31; +// used by jumppads to store original destination wp, used in case it gets changed in the editor +.entity wp00_original; + .float wp00mincost, wp01mincost, wp02mincost, wp03mincost, wp04mincost, wp05mincost, wp06mincost, wp07mincost; .float wp08mincost, wp09mincost, wp10mincost, wp11mincost, wp12mincost, wp13mincost, wp14mincost, wp15mincost; .float wp16mincost, wp17mincost, wp18mincost, wp19mincost, wp20mincost, wp21mincost, wp22mincost, wp23mincost; -- 2.39.2