+.entity spawnpointmodel;
+void waypoint_unreachable(entity pl)
+{
+ IL_EACH(g_waypoints, true,
+ {
+ it.colormod = '0.5 0.5 0.5';
+ it.effects &= ~(EF_NODEPTHTEST | EF_RED | EF_BLUE);
+ });
+
+ entity e2 = navigation_findnearestwaypoint(pl, false);
+ if(!e2)
+ {
+ LOG_INFOF("Can't find any waypoint nearby\n");
+ return;
+ }
+
+ navigation_markroutes(pl, e2);
+
+ int j = 0;
+ int m = 0;
+ IL_EACH(g_waypoints, it.wpcost >= 10000000,
+ {
+ LOG_INFO("unreachable: ", etos(it), " ", vtos(it.origin), "\n");
+ it.colormod_z = 8;
+ it.effects |= EF_NODEPTHTEST | EF_BLUE;
+ j++;
+ m++;
+ });
+ if (j) LOG_INFOF("%d waypoints cannot be reached from here in any way (marked with blue light)\n", j);
+ navigation_markroutes_inverted(e2);
+
+ j = 0;
+ IL_EACH(g_waypoints, it.wpcost >= 10000000,
+ {
+ LOG_INFO("cannot reach me: ", etos(it), " ", vtos(it.origin), "\n");
+ it.colormod_x = 8;
+ if (!(it.effects & EF_NODEPTHTEST)) // not already reported before
+ m++;
+ it.effects |= EF_NODEPTHTEST | EF_RED;
+ j++;
+ });
+ if (j) LOG_INFOF("%d waypoints cannot walk to here in any way (marked with red light)\n", j);
+ if (m) LOG_INFOF("%d waypoints have been marked total\n", m);
+
+ j = 0;
+ IL_EACH(g_spawnpoints, true,
+ {
+ if (navigation_findnearestwaypoint(it, false))
+ {
+ if(it.spawnpointmodel)
+ {
+ delete(it.spawnpointmodel);
+ it.spawnpointmodel = NULL;
+ }
+ }
+ else
+ {
+ if(!it.spawnpointmodel)
+ {
+ tracebox(it.origin, PL_MIN_CONST, PL_MAX_CONST, it.origin - '0 0 512', MOVE_NOMONSTERS, NULL);
+ entity e = new(spawnpointmodel);
+ vector org = trace_endpos + eZ;
+ setorigin(e, org);
+ e.solid = SOLID_TRIGGER;
+ it.spawnpointmodel = e;
+ }
+ LOG_INFO("spawn without waypoint: ", etos(it), " ", vtos(it.origin), "\n");
+ it.spawnpointmodel.effects |= EF_NODEPTHTEST;
+ _setmodel(it.spawnpointmodel, pl.model);
+ it.spawnpointmodel.frame = pl.frame;
+ it.spawnpointmodel.skin = pl.skin;
+ it.spawnpointmodel.colormap = pl.colormap;
+ it.spawnpointmodel.colormod = pl.colormod;
+ it.spawnpointmodel.glowmod = pl.glowmod;
+ setsize(it.spawnpointmodel, PL_MIN_CONST, PL_MAX_CONST);
+ j++;
+ }
+ });
+ if (j) LOG_INFOF("%d spawnpoints have no nearest waypoint (marked by player model)\n", j);
+
+ j = 0;
+ IL_EACH(g_items, true,
+ {
+ it.effects &= ~(EF_NODEPTHTEST | EF_RED | EF_BLUE);
+ it.colormod = '0.5 0.5 0.5';
+ });
+ IL_EACH(g_items, true,
+ {
+ if (navigation_findnearestwaypoint(it, false))
+ continue;
+ LOG_INFO("item without waypoint: ", etos(it), " ", vtos(it.origin), "\n");
+ it.effects |= EF_NODEPTHTEST | EF_RED;
+ it.colormod_x = 8;
+ j++;
+ });
+ if (j) LOG_INFOF("%d items have no nearest waypoint and cannot be walked away from (marked with red light)\n", j);
+
+ j = 0;
+ IL_EACH(g_items, true,
+ {
+ if (navigation_findnearestwaypoint(it, true))
+ continue;
+ LOG_INFO("item without waypoint: ", etos(it), " ", vtos(it.origin), "\n");
+ it.effects |= EF_NODEPTHTEST | EF_BLUE;
+ it.colormod_z = 8;
+ j++;
+ });
+ if (j) LOG_INFOF("%d items have no nearest waypoint and cannot be walked to (marked with blue light)\n", j);
+}
+
+vector waypoint_getSymmetricalOrigin(vector org, int ctf_flags)
+{
+ vector new_org = org;
+ if (fabs(autocvar_g_waypointeditor_symmetrical) == 1)
+ {
+ vector map_center = havocbot_middlepoint;
+ if (autocvar_g_waypointeditor_symmetrical == -1)
+ map_center = autocvar_g_waypointeditor_symmetrical_origin;
+
+ new_org = Rotate(org - map_center, 360 * DEG2RAD / ctf_flags) + map_center;
+ }
+ else if (fabs(autocvar_g_waypointeditor_symmetrical) == 2)
+ {
+ float m = havocbot_symmetryaxis_equation.x;
+ float q = havocbot_symmetryaxis_equation.y;
+ if (autocvar_g_waypointeditor_symmetrical == -2)
+ {
+ m = autocvar_g_waypointeditor_symmetrical_axis.x;
+ q = autocvar_g_waypointeditor_symmetrical_axis.y;
+ }
+
+ new_org.x = (1 / (1 + m*m)) * ((1 - m*m) * org.x + 2 * m * org.y - 2 * m * q);
+ new_org.y = (1 / (1 + m*m)) * (2 * m * org.x + (m*m - 1) * org.y + 2 * q);
+ }
+ new_org.z = org.z;
+ return new_org;
+}
+