if (j) LOG_INFOF("%d items have no nearest waypoint and cannot be walked to (marked with blue light)\n", j);
}
+void waypoint_getSymmetricalAxis_cmd(entity caller, bool save, int arg_idx)
+{
+ vector v1 = stov(argv(arg_idx++));
+ vector v2 = stov(argv(arg_idx++));
+ vector mid = (v1 + v2) / 2;
+
+ float diffy = (v2.y - v1.y);
+ float diffx = (v2.x - v1.x);
+ if (v1.y == v2.y)
+ diffy = 0.000001;
+ if (v1.x == v2.x)
+ diffx = 0.000001;
+ float m = - diffx / diffy;
+ float q = - m * mid.x + mid.y;
+ if (fabs(m) <= 0.000001) m = 0;
+ if (fabs(q) <= 0.000001) q = 0;
+
+ string axis_str = strcat(ftos(m), " ", ftos(q));
+ if (save)
+ cvar_set("g_waypointeditor_symmetrical_axis", axis_str);
+ axis_str = strcat("\"", axis_str, "\"");
+ sprint(caller, strcat("Axis of symmetry based on input points: ", axis_str, "\n"));
+ if (save)
+ sprint(caller, sprintf(" ^3saved to %s\n", "g_waypointeditor_symmetrical_axis"));
+ if (save)
+ {
+ cvar_set("g_waypointeditor_symmetrical", "-2");
+ sprint(caller, strcat("g_waypointeditor_symmetrical", " has been set to ",
+ cvar_string("g_waypointeditor_symmetrical"), "\n"));
+ }
+}
+
+void waypoint_getSymmetricalOrigin_cmd(entity caller, bool save, int arg_idx)
+{
+ vector org = '0 0 0';
+ int ctf_flags = 0;
+ for (int i = 0; i < 6; i++)
+ {
+ if (argv(arg_idx + i) != "")
+ ctf_flags++;
+ }
+ if (ctf_flags < 2)
+ {
+ ctf_flags = 0;
+ org = vec2(havocbot_middlepoint);
+ if (argv(arg_idx) != "")
+ sprint(caller, "WARNING: Ignoring single input point\n");
+ if (havocbot_middlepoint_radius == 0)
+ {
+ sprint(caller, "Origin of symmetry can't be automatically determined\n");
+ return;
+ }
+ }
+ else
+ {
+ vector v1, v2, v3, v4, v5, v6;
+ for (int i = 1; i <= ctf_flags; i++)
+ {
+ if (i == 1) { v1 = stov(argv(arg_idx++)); org = v1 / ctf_flags; }
+ else if (i == 2) { v2 = stov(argv(arg_idx++)); org += v2 / ctf_flags; }
+ else if (i == 3) { v3 = stov(argv(arg_idx++)); org += v3 / ctf_flags; }
+ else if (i == 4) { v4 = stov(argv(arg_idx++)); org += v4 / ctf_flags; }
+ else if (i == 5) { v5 = stov(argv(arg_idx++)); org += v5 / ctf_flags; }
+ else if (i == 6) { v6 = stov(argv(arg_idx++)); org += v6 / ctf_flags; }
+ }
+ }
+
+ if (fabs(org.x) <= 0.000001) org.x = 0;
+ if (fabs(org.y) <= 0.000001) org.y = 0;
+ string org_str = strcat(ftos(org.x), " ", ftos(org.y));
+ if (save)
+ {
+ cvar_set("g_waypointeditor_symmetrical_origin", org_str);
+ cvar_set("g_waypointeditor_symmetrical_order", ftos(ctf_flags));
+ }
+ org_str = strcat("\"", org_str, "\"");
+
+ if (ctf_flags < 2)
+ sprint(caller, strcat("Origin of symmetry based on flag positions: ", org_str, "\n"));
+ else
+ sprint(caller, strcat("Origin of symmetry based on input points: ", org_str, "\n"));
+ if (save)
+ sprint(caller, sprintf(" ^3saved to %s\n", "g_waypointeditor_symmetrical_origin"));
+
+ if (ctf_flags < 2)
+ sprint(caller, "Order of symmetry: 0 (autodetected)\n");
+ else
+ sprint(caller, strcat("Order of symmetry: ", ftos(ctf_flags), "\n"));
+ if (save)
+ sprint(caller, sprintf(" ^3saved to %s\n", "g_waypointeditor_symmetrical_order"));
+
+ if (save)
+ {
+ if (ctf_flags < 2)
+ cvar_set("g_waypointeditor_symmetrical", "0");
+ else
+ cvar_set("g_waypointeditor_symmetrical", "-1");
+ sprint(caller, strcat("g_waypointeditor_symmetrical", " has been set to ",
+ cvar_string("g_waypointeditor_symmetrical"), "\n"));
+ }
+}
+
vector waypoint_getSymmetricalPoint(vector org, int ctf_flags)
{
vector new_org = org;
waypoint_showlink(wp.wp15, wp, display_type); waypoint_showlink(wp.wp31, wp, display_type);
}
+void crosshair_trace_waypoints(entity pl)
+{
+ IL_EACH(g_waypoints, true, {
+ it.solid = SOLID_BSP;
+ if (!it.wpisbox)
+ setsize(it, '-16 -16 -16', '16 16 16');
+ });
+
+ crosshair_trace(pl);
+
+ IL_EACH(g_waypoints, true, {
+ it.solid = SOLID_TRIGGER;
+ if (!it.wpisbox)
+ setsize(it, '0 0 0', '0 0 0');
+ });
+ if (trace_ent.classname != "waypoint")
+ trace_ent = NULL;
+}
+
void botframe_showwaypointlinks()
{
if (time < botframe_waypointeditorlightningtime)
FOREACH_CLIENT(IS_PLAYER(it) && !it.isbot,
{
int display_type = 0;
- entity head = navigation_findnearestwaypoint(it, false);
+ if (wasfreed(it.wp_aimed))
+ it.wp_aimed = NULL;
+ if (wasfreed(it.wp_locked))
+ it.wp_locked = NULL;
+ if (PHYS_INPUT_BUTTON_USE(it))
+ it.wp_locked = it.wp_aimed;
+ entity head = it.wp_locked;
+ if (!head)
+ head = navigation_findnearestwaypoint(it, false);
it.nearestwaypoint = head; // mainly useful for debug
it.nearestwaypointtimeout = time + 2; // while I'm at it...
- if (IS_ONGROUND(it) || it.waterlevel > WATERLEVEL_NONE)
+ if (IS_ONGROUND(it) || it.waterlevel > WATERLEVEL_NONE || it.wp_locked)
display_type = 1; // default
else if(head && (head.wphardwired))
display_type = 2; // only hardwired
waypoint_showlinks_from(head, display_type);
}
}
+ string str;
+ entity wp = NULL;
+ if (vdist(vec2(it.velocity), <, autocvar_sv_maxspeed * 1.1))
+ {
+ crosshair_trace_waypoints(it);
+ if (trace_ent)
+ {
+ wp = trace_ent;
+ if (wp != it.wp_aimed)
+ {
+ str = sprintf("\necho ^2WP info^7: entity: %d, flags: %d, origin: '%s'\n", etof(wp), wp.wpflags, vtos(wp.origin));
+ if (wp.wpisbox)
+ str = strcat(str, sprintf("echo \" absmin: '%s', absmax: '%s'\"\n", vtos(wp.absmin), vtos(wp.absmax)));
+ stuffcmd(it, str);
+ str = sprintf("entity: %d\nflags: %d\norigin: \'%s\'", etof(wp), wp.wpflags, vtos(wp.origin));
+ if (wp.wpisbox)
+ str = strcat(str, sprintf(" \nabsmin: '%s'\nabsmax: '%s'", vtos(wp.absmin), vtos(wp.absmax)));
+ debug_text_3d(wp.origin, str, 0, 7, '0 0 0');
+ }
+ }
+ }
+ if (it.wp_aimed != wp)
+ it.wp_aimed = wp;
});
}
sprint(caller, "ERROR: this command works only if you are player\n");
else
waypoint_spawn_fromeditor(caller);
+ return;
}
else if (argv(1) == "remove")
{
sprint(caller, "ERROR: this command works only if you are player\n");
else
waypoint_remove_fromeditor(caller);
+ return;
}
else if (argv(1) == "unreachable")
{
sprint(caller, "ERROR: this command works only if you are player\n");
else
waypoint_unreachable(caller);
+ return;
}
else if (argv(1) == "saveall")
+ {
waypoint_saveall();
+ return;
+ }
else if (argv(1) == "relinkall")
+ {
waypoint_schedulerelinkall();
-
- return;
+ return;
+ }
+ else if (argv(1) == "symaxis")
+ {
+ if (argv(2) == "set" || argv(2) == "get")
+ {
+ waypoint_getSymmetricalAxis_cmd(caller, (argv(2) == "set"), 3);
+ return;
+ }
+ }
+ else if (argv(1) == "symorigin")
+ {
+ if (argv(2) == "set" || argv(2) == "get")
+ {
+ waypoint_getSymmetricalOrigin_cmd(caller, (argv(2) == "set"), 3);
+ return;
+ }
+ }
}
}
case CMD_REQUEST_USAGE:
{
sprint(caller, "\nUsage:^3 cmd wpeditor action\n");
- sprint(caller, " Where 'action' can be: spawn, remove, unreachable, saveall, relinkall\n");
+ sprint(caller, " Where 'action' can be: spawn, remove, unreachable, saveall, relinkall,\n");
+ sprint(caller, " symorigin get|set\n");
+ sprint(caller, " symorigin get|set p1 p2 ... pX\n");
+ sprint(caller, " symaxis get|set p1 p2\n");
+ sprint(caller, " where p1 p2 ... pX are positions \"x y z\" (z can be omitted)\n");
+ sprint(caller, " symorigin and symaxis commands are useful to determine origin/axis of symmetry"
+ " on maps without ctf flags or where flags aren't perfectly symmetrical\n");
return;
}
}