2020-12-23 06:53:43 +00:00
|
|
|
/*
|
2021-01-05 14:51:49 +00:00
|
|
|
* Copyright (c) 2016-2021 Marco Hladik <marco@icculus.org>
|
2020-12-23 06:53:43 +00:00
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
|
|
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
typedef struct waypoint_s
|
|
|
|
{
|
2021-01-02 17:52:09 +00:00
|
|
|
vector m_vecOrigin;
|
|
|
|
float m_flRadius; /* used for picking the closest waypoint. aka proximity weight. also relaxes routes inside the area. */
|
2020-12-23 06:53:43 +00:00
|
|
|
struct wpneighbour_s
|
|
|
|
{
|
2021-01-02 17:52:09 +00:00
|
|
|
int m_iNode;
|
|
|
|
float m_flCost;
|
|
|
|
int m_iFlags;
|
|
|
|
} *m_pNeighbour;
|
|
|
|
int m_numNeighbours;
|
2020-12-23 06:53:43 +00:00
|
|
|
} waypoint_t;
|
|
|
|
|
|
|
|
static waypoint_t *g_pWaypoints;
|
|
|
|
static int g_iWaypoints;
|
|
|
|
|
2021-01-02 20:31:56 +00:00
|
|
|
static int g_waylink_status;
|
|
|
|
var int g_way1 = -1;
|
|
|
|
var int g_way2 = -1;
|
|
|
|
|
2020-12-23 06:53:43 +00:00
|
|
|
static void
|
|
|
|
Way_WipeWaypoints(void)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < g_iWaypoints; i++) {
|
2021-01-02 17:52:09 +00:00
|
|
|
memfree(g_pWaypoints[i].m_pNeighbour);
|
2020-12-23 06:53:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
memfree(g_pWaypoints);
|
|
|
|
g_iWaypoints = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-01-02 17:52:09 +00:00
|
|
|
Way_LinkNodes(waypoint_t *wp, waypoint_t *w2)
|
2020-12-23 06:53:43 +00:00
|
|
|
{
|
|
|
|
int w2n = w2 - g_pWaypoints;
|
2021-01-02 10:17:14 +00:00
|
|
|
|
|
|
|
/* don't bother if we're already linked */
|
2021-01-02 17:52:09 +00:00
|
|
|
for (int i = 0i; i < wp->m_numNeighbours; i++) {
|
|
|
|
if (wp->m_pNeighbour[i].m_iNode == w2n) {
|
2020-12-23 06:53:43 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2021-01-02 10:17:14 +00:00
|
|
|
|
2021-01-02 17:52:09 +00:00
|
|
|
int idx = wp->m_numNeighbours++;
|
2021-02-08 12:35:15 +00:00
|
|
|
wp->m_pNeighbour = (wpneighbour_s *)memrealloc(wp->m_pNeighbour, sizeof(*wp->m_pNeighbour), idx, wp->m_numNeighbours);
|
2021-01-02 17:52:09 +00:00
|
|
|
local struct wpneighbour_s *n = wp->m_pNeighbour+idx;
|
|
|
|
n->m_iNode = w2n;
|
|
|
|
n->m_flCost = vlen(w2->m_vecOrigin - wp->m_vecOrigin);
|
|
|
|
n->m_iFlags = 0;
|
2020-12-23 06:53:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-02-08 12:35:15 +00:00
|
|
|
Way_AutoLink(int wpidx)
|
2020-12-23 06:53:43 +00:00
|
|
|
{
|
|
|
|
for (int i = 0i; i < g_iWaypoints; i++) {
|
|
|
|
//don't link to ourself...
|
|
|
|
if (i == wpidx) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
//autolink distance cutoff.
|
2021-02-08 12:35:15 +00:00
|
|
|
if (vlen(g_pWaypoints[wpidx].m_vecOrigin - g_pWaypoints[i].m_vecOrigin) > autocvar_nav_linksize) {
|
2020-12-23 06:53:43 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
//not going to use the full player size because that makes steps really messy.
|
|
|
|
//however, we do need a little size, for sanity's sake
|
2021-02-08 12:35:15 +00:00
|
|
|
tracebox(g_pWaypoints[wpidx].m_vecOrigin, '-16 -16 0', '16 16 32', g_pWaypoints[i].m_vecOrigin, TRUE, world);
|
2020-12-23 06:53:43 +00:00
|
|
|
|
|
|
|
//light of sight blocked, don't try autolinking.
|
|
|
|
if (trace_fraction < 1) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-02-08 12:35:15 +00:00
|
|
|
Way_LinkNodes(&g_pWaypoints[wpidx], &g_pWaypoints[i]);
|
|
|
|
Way_LinkNodes(&g_pWaypoints[i], &g_pWaypoints[wpidx]);
|
2020-12-23 06:53:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2021-01-02 17:52:09 +00:00
|
|
|
Way_CreateNode(entity ePlayer, int iAutoLink)
|
2020-12-23 06:53:43 +00:00
|
|
|
{
|
|
|
|
int iID = g_iWaypoints++;
|
2021-02-08 12:35:15 +00:00
|
|
|
g_pWaypoints = (waypoint_t *)memrealloc(g_pWaypoints, sizeof(waypoint_t), iID, g_iWaypoints);
|
2020-12-23 06:53:43 +00:00
|
|
|
waypoint_t *n = g_pWaypoints + iID;
|
2021-01-02 17:52:09 +00:00
|
|
|
n->m_vecOrigin = ePlayer.origin;
|
|
|
|
n->m_pNeighbour = __NULL__;
|
|
|
|
n->m_numNeighbours = 0;
|
|
|
|
n->m_flRadius = autocvar_nav_radius;
|
2020-12-23 06:53:43 +00:00
|
|
|
|
2020-12-26 06:27:34 +00:00
|
|
|
if (iAutoLink == 1) {
|
2021-02-08 12:35:15 +00:00
|
|
|
Way_AutoLink(iID);
|
2020-12-23 06:53:43 +00:00
|
|
|
} else {
|
|
|
|
if (iID != 0) {
|
2020-12-26 06:27:34 +00:00
|
|
|
if (iAutoLink == 0) {
|
2021-01-02 17:52:09 +00:00
|
|
|
Way_LinkNodes(n, &g_pWaypoints[iID-1]);
|
|
|
|
Way_LinkNodes(&g_pWaypoints[iID-1], n);
|
2020-12-29 06:17:41 +00:00
|
|
|
} else if (iAutoLink == -1) {
|
2021-01-02 17:52:09 +00:00
|
|
|
Way_LinkNodes(&g_pWaypoints[iID-1], n);
|
2020-12-29 06:17:41 +00:00
|
|
|
} else if (iAutoLink == -2) {
|
2021-01-02 17:52:09 +00:00
|
|
|
Way_LinkNodes(n, &g_pWaypoints[iID-1]);
|
2020-12-26 06:27:34 +00:00
|
|
|
}
|
2020-12-23 06:53:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2021-01-02 17:52:09 +00:00
|
|
|
Way_DeleteNode(int iID)
|
2020-12-23 06:53:43 +00:00
|
|
|
{
|
|
|
|
if (iID < 0i || iID >= g_iWaypoints) {
|
2021-01-02 20:22:56 +00:00
|
|
|
print("Way_DeleteNode: invalid waypoint\n");
|
2020-12-23 06:53:43 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//wipe the waypoint
|
2021-01-02 17:52:09 +00:00
|
|
|
memfree(g_pWaypoints[iID].m_pNeighbour);
|
2020-12-23 06:53:43 +00:00
|
|
|
memcpy(g_pWaypoints + iID, g_pWaypoints + iID + 1, (g_iWaypoints - (iID + 1)) * sizeof(*g_pWaypoints));
|
|
|
|
g_iWaypoints--;
|
|
|
|
|
|
|
|
//clean up any links to it.
|
|
|
|
for (int i = 0; i < g_iWaypoints; i++) {
|
2021-01-02 17:52:09 +00:00
|
|
|
for (int j = 0; j < g_pWaypoints[i].m_numNeighbours;) {
|
|
|
|
int l = g_pWaypoints[i].m_pNeighbour[j].m_iNode;
|
2020-12-23 06:53:43 +00:00
|
|
|
if (l == iID) {
|
2021-01-02 17:52:09 +00:00
|
|
|
memcpy(g_pWaypoints[i].m_pNeighbour+j, g_pWaypoints[i].m_pNeighbour+j+1, (g_pWaypoints[i].m_numNeighbours-(j+1))*sizeof(*g_pWaypoints[i].m_pNeighbour));
|
|
|
|
g_pWaypoints[i].m_numNeighbours--;
|
2020-12-23 06:53:43 +00:00
|
|
|
continue;
|
|
|
|
} else if (l > iID) {
|
2021-01-02 17:52:09 +00:00
|
|
|
g_pWaypoints[i].m_pNeighbour[j].m_iNode = l-1;
|
2020-12-23 06:53:43 +00:00
|
|
|
}
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2021-01-02 17:52:09 +00:00
|
|
|
Way_SetRadius(int iID, float flRadValue)
|
2020-12-23 06:53:43 +00:00
|
|
|
{
|
|
|
|
if (iID < 0i || iID >= g_iWaypoints) {
|
2021-01-02 20:22:56 +00:00
|
|
|
print("Way_SetRadius: invalid waypoint\n");
|
2020-12-23 06:53:43 +00:00
|
|
|
return;
|
|
|
|
}
|
2021-01-02 17:52:09 +00:00
|
|
|
g_pWaypoints[iID].m_flRadius = flRadValue;
|
2020-12-23 06:53:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2021-01-02 17:52:09 +00:00
|
|
|
Way_FindClosestNode(vector vecOrigin)
|
2020-12-23 06:53:43 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
/* -1 for no nodes anywhere... */
|
|
|
|
int r = -1i;
|
|
|
|
float flBestDist = COST_INFINITE;
|
|
|
|
|
|
|
|
for (int i = 0i; i < g_iWaypoints; i++) {
|
2021-01-02 17:52:09 +00:00
|
|
|
float fDist = vlen(g_pWaypoints[i].m_vecOrigin - vecOrigin) - g_pWaypoints[i].m_flRadius;
|
2020-12-23 06:53:43 +00:00
|
|
|
if (fDist < flBestDist) {
|
|
|
|
/* within the waypoint's radius */
|
|
|
|
if (fDist < 0) {
|
|
|
|
flBestDist = fDist;
|
|
|
|
r = i;
|
|
|
|
} else {
|
|
|
|
/* outside the waypoint, make sure its valid. */
|
2021-01-02 17:52:09 +00:00
|
|
|
traceline(vecOrigin, g_pWaypoints[i].m_vecOrigin, TRUE, world);
|
2020-12-23 06:53:43 +00:00
|
|
|
if (trace_fraction == 1) {
|
|
|
|
/* FIXME: sort them frst, to avoid traces? */
|
|
|
|
flBestDist = fDist;
|
|
|
|
r = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2020-12-29 08:10:21 +00:00
|
|
|
void
|
2021-01-02 17:52:09 +00:00
|
|
|
Way_FlagJump(void)
|
2020-12-29 08:10:21 +00:00
|
|
|
{
|
2021-01-02 20:31:56 +00:00
|
|
|
if (g_waylink_status == 0) {
|
|
|
|
g_way1 = Way_FindClosestNode(self.origin);
|
|
|
|
g_waylink_status = 1;
|
2021-01-02 20:22:56 +00:00
|
|
|
env_message_single(self, "^2Selected first waypoint!\n");
|
2021-01-02 20:31:56 +00:00
|
|
|
} else if (g_waylink_status == 1) {
|
|
|
|
g_way2 = Way_FindClosestNode(self.origin);
|
|
|
|
g_waylink_status = 0;
|
|
|
|
|
|
|
|
if (g_way1 != g_way2) {
|
|
|
|
for (int b = 0i; b < g_pWaypoints[g_way1].m_numNeighbours; b++) {
|
|
|
|
if (g_pWaypoints[g_way1].m_pNeighbour[b].m_iNode == g_way2) {
|
|
|
|
g_pWaypoints[g_way1].m_pNeighbour[b].m_iFlags |= LF_JUMP;
|
2021-01-02 20:22:56 +00:00
|
|
|
env_message_single(self, "^2Jump-linked the two points!\n");
|
2020-12-29 08:10:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2021-01-02 20:22:56 +00:00
|
|
|
env_message_single(self, "^1Failed to link, the two points are the same!\n");
|
2020-12-29 08:10:21 +00:00
|
|
|
}
|
2021-01-02 20:31:56 +00:00
|
|
|
g_way1 = g_way2 = -1;
|
2020-12-29 08:10:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2021-01-02 17:52:09 +00:00
|
|
|
Way_FlagCrouch(void)
|
2020-12-29 08:10:21 +00:00
|
|
|
{
|
2021-01-02 20:31:56 +00:00
|
|
|
if (g_waylink_status == 0) {
|
|
|
|
g_way1 = Way_FindClosestNode(self.origin);
|
|
|
|
g_waylink_status = 1;
|
2021-01-02 20:22:56 +00:00
|
|
|
env_message_single(self, "^2Selected first waypoint!\n");
|
2021-01-02 20:31:56 +00:00
|
|
|
} else if (g_waylink_status == 1) {
|
|
|
|
g_way2 = Way_FindClosestNode(self.origin);
|
|
|
|
g_waylink_status = 0;
|
|
|
|
|
|
|
|
if (g_way1 != g_way2) {
|
|
|
|
for (int b = 0i; b < g_pWaypoints[g_way1].m_numNeighbours; b++) {
|
|
|
|
if (g_pWaypoints[g_way1].m_pNeighbour[b].m_iNode == g_way2) {
|
|
|
|
g_pWaypoints[g_way1].m_pNeighbour[b].m_iFlags |= LF_CROUCH;
|
2021-01-02 20:22:56 +00:00
|
|
|
env_message_single(self, "^2Crouch-linked the two points!\n");
|
2020-12-29 08:10:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2021-01-02 20:22:56 +00:00
|
|
|
env_message_single(self, "^1Failed to link, the two points are the same!\n");
|
2020-12-29 08:10:21 +00:00
|
|
|
}
|
2021-01-02 20:31:56 +00:00
|
|
|
g_way1 = g_way2 = -1;
|
2020-12-29 08:10:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2021-01-02 17:52:09 +00:00
|
|
|
Way_FlagWalk(void)
|
2020-12-29 08:10:21 +00:00
|
|
|
{
|
2021-01-02 20:31:56 +00:00
|
|
|
if (g_waylink_status == 0) {
|
|
|
|
g_way1 = Way_FindClosestNode(self.origin);
|
|
|
|
g_waylink_status = 1;
|
2021-01-02 20:22:56 +00:00
|
|
|
env_message_single(self, "^2Selected first waypoint!\n");
|
2021-01-02 20:31:56 +00:00
|
|
|
} else if (g_waylink_status == 1) {
|
|
|
|
g_way2 = Way_FindClosestNode(self.origin);
|
|
|
|
g_waylink_status = 0;
|
|
|
|
|
|
|
|
if (g_way1 != g_way2) {
|
|
|
|
for (int b = 0i; b < g_pWaypoints[g_way1].m_numNeighbours; b++) {
|
|
|
|
if (g_pWaypoints[g_way1].m_pNeighbour[b].m_iNode == g_way2) {
|
|
|
|
g_pWaypoints[g_way1].m_pNeighbour[b].m_iFlags |= LF_WALK;
|
2021-01-02 20:22:56 +00:00
|
|
|
env_message_single(self, "^2Walk-linked the two points!\n");
|
2020-12-29 08:10:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2021-01-02 20:22:56 +00:00
|
|
|
env_message_single(self, "^1Failed to link, the two points are the same!\n");
|
2020-12-29 08:10:21 +00:00
|
|
|
}
|
2021-01-02 20:31:56 +00:00
|
|
|
g_way1 = g_way2 = -1;
|
2020-12-29 08:10:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-16 16:34:04 +00:00
|
|
|
void
|
|
|
|
Way_FlagAim(void)
|
|
|
|
{
|
|
|
|
if (g_waylink_status == 0) {
|
|
|
|
g_way1 = Way_FindClosestNode(self.origin);
|
|
|
|
g_waylink_status = 1;
|
|
|
|
env_message_single(self, "^2Selected first waypoint!\n");
|
|
|
|
} else if (g_waylink_status == 1) {
|
|
|
|
g_way2 = Way_FindClosestNode(self.origin);
|
|
|
|
g_waylink_status = 0;
|
|
|
|
|
|
|
|
if (g_way1 != g_way2) {
|
|
|
|
for (int b = 0i; b < g_pWaypoints[g_way1].m_numNeighbours; b++) {
|
|
|
|
if (g_pWaypoints[g_way1].m_pNeighbour[b].m_iNode == g_way2) {
|
|
|
|
g_pWaypoints[g_way1].m_pNeighbour[b].m_iFlags |= LF_AIM;
|
|
|
|
env_message_single(self, "^2Walk-linked the two points!\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
env_message_single(self, "^1Failed to link, the two points are the same!\n");
|
|
|
|
}
|
|
|
|
g_way1 = g_way2 = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-27 06:48:46 +00:00
|
|
|
void
|
|
|
|
Way_FlagUse(void)
|
|
|
|
{
|
|
|
|
if (g_waylink_status == 0) {
|
|
|
|
g_way1 = Way_FindClosestNode(self.origin);
|
|
|
|
g_waylink_status = 1;
|
|
|
|
env_message_single(self, "^2Selected first waypoint!\n");
|
|
|
|
} else if (g_waylink_status == 1) {
|
|
|
|
g_way2 = Way_FindClosestNode(self.origin);
|
|
|
|
g_waylink_status = 0;
|
|
|
|
|
|
|
|
if (g_way1 != g_way2) {
|
|
|
|
for (int b = 0i; b < g_pWaypoints[g_way1].m_numNeighbours; b++) {
|
|
|
|
if (g_pWaypoints[g_way1].m_pNeighbour[b].m_iNode == g_way2) {
|
|
|
|
g_pWaypoints[g_way1].m_pNeighbour[b].m_iFlags |= LF_USER;
|
|
|
|
env_message_single(self, "^2Walk-linked the two points!\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
env_message_single(self, "^1Failed to link, the two points are the same!\n");
|
|
|
|
}
|
|
|
|
g_way1 = g_way2 = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-02 17:52:09 +00:00
|
|
|
void
|
|
|
|
Way_HelperSpawns()
|
|
|
|
{
|
|
|
|
for (entity a = world; (a = find(a, ::classname, "info_player_deathmatch"));) {
|
|
|
|
Way_CreateNode(a, TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-26 06:27:34 +00:00
|
|
|
void
|
|
|
|
Way_GoToPoint(entity pl)
|
|
|
|
{
|
|
|
|
vector vecSrc;
|
|
|
|
makevectors(pl.v_angle);
|
|
|
|
vecSrc = pl.origin + pl.view_ofs;
|
|
|
|
traceline(vecSrc, vecSrc + (v_forward * 4096), FALSE, pl);
|
|
|
|
print(sprintf("Telling all bots to go to %v\n", trace_endpos));
|
|
|
|
|
2021-01-03 11:52:51 +00:00
|
|
|
for (entity a = world; (a = find(a, classname, "player"));) {
|
|
|
|
if (clienttype(a) != CLIENTTYPE_REAL) {
|
2020-12-26 06:27:34 +00:00
|
|
|
bot targ;
|
|
|
|
targ = (bot)a;
|
|
|
|
targ.RouteClear();
|
|
|
|
route_calculate(targ, pl.origin, 0, Bot_RouteCB);
|
|
|
|
print(sprintf("Told bot to go to %v\n", trace_endpos));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-12-23 06:53:43 +00:00
|
|
|
void
|
2021-01-02 17:52:09 +00:00
|
|
|
Way_SaveFile(string filename)
|
2020-12-23 06:53:43 +00:00
|
|
|
{
|
2021-01-02 17:52:09 +00:00
|
|
|
filestream file;
|
|
|
|
|
2020-12-23 06:53:43 +00:00
|
|
|
if (!g_iWaypoints) {
|
2021-01-02 20:22:56 +00:00
|
|
|
env_message_single(self, "^1ERROR: Tried to save empty waypoints.\n");
|
2020-12-23 06:53:43 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-01-02 17:52:09 +00:00
|
|
|
file = fopen(filename, FILE_WRITE);
|
2020-12-23 06:53:43 +00:00
|
|
|
|
2021-01-02 17:52:09 +00:00
|
|
|
if (file < 0) {
|
2021-01-02 20:22:56 +00:00
|
|
|
print("Way_SaveFile: unable to open ", filename, "\n");
|
2021-01-02 17:52:09 +00:00
|
|
|
return;
|
2020-12-23 06:53:43 +00:00
|
|
|
}
|
2021-01-02 10:17:14 +00:00
|
|
|
|
2021-01-02 17:52:09 +00:00
|
|
|
fputs(file, sprintf("%i\n", g_iWaypoints));
|
2021-01-02 10:17:14 +00:00
|
|
|
|
2021-01-02 17:52:09 +00:00
|
|
|
for (int i = 0i; i < g_iWaypoints; i++) {
|
|
|
|
fputs(file, sprintf("%v %f %i\n", g_pWaypoints[i].m_vecOrigin, g_pWaypoints[i].m_flRadius, g_pWaypoints[i].m_numNeighbours));
|
|
|
|
|
|
|
|
for(int j = 0i; j < g_pWaypoints[i].m_numNeighbours; j++) {
|
2021-03-27 06:48:46 +00:00
|
|
|
fputs(file, sprintf(" %i %f %i\n", g_pWaypoints[i].m_pNeighbour[j].m_iNode, g_pWaypoints[i].m_pNeighbour[j].m_flCost, g_pWaypoints[i].m_pNeighbour[j].m_iFlags));
|
2020-12-23 06:53:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-02 17:52:09 +00:00
|
|
|
fclose(file);
|
|
|
|
}
|
2020-12-23 06:53:43 +00:00
|
|
|
|
2021-01-02 17:52:09 +00:00
|
|
|
void
|
|
|
|
Way_ReadFile(string strFile)
|
|
|
|
{
|
|
|
|
float file = fopen(strFile, FILE_READ);
|
|
|
|
if (file < 0) {
|
2021-01-02 20:22:56 +00:00
|
|
|
print("Way_ReadFile: unable to open ", strFile, "\n");
|
2021-01-02 17:52:09 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-12-23 06:53:43 +00:00
|
|
|
|
2021-01-02 17:52:09 +00:00
|
|
|
Way_WipeWaypoints();
|
2020-12-29 08:10:21 +00:00
|
|
|
|
2021-01-02 17:52:09 +00:00
|
|
|
tokenize(fgets(file));
|
|
|
|
g_iWaypoints = stoi(argv(0));
|
|
|
|
g_pWaypoints = memalloc(sizeof(*g_pWaypoints) * g_iWaypoints);
|
2020-12-29 08:10:21 +00:00
|
|
|
|
2021-01-02 17:52:09 +00:00
|
|
|
for (int i = 0i; i < g_iWaypoints; i++) {
|
|
|
|
tokenize(fgets(file));
|
|
|
|
g_pWaypoints[i].m_vecOrigin[0] = stof(argv(0));
|
|
|
|
g_pWaypoints[i].m_vecOrigin[1] = stof(argv(1));
|
|
|
|
g_pWaypoints[i].m_vecOrigin[2] = stof(argv(2));
|
|
|
|
g_pWaypoints[i].m_flRadius = stof(argv(3));
|
|
|
|
g_pWaypoints[i].m_numNeighbours = stoi(argv(4));
|
|
|
|
g_pWaypoints[i].m_pNeighbour = memalloc(sizeof(*g_pWaypoints[i].m_pNeighbour) * g_pWaypoints[i].m_numNeighbours);
|
|
|
|
|
|
|
|
for (int j = 0i; j < g_pWaypoints[i].m_numNeighbours; j++) {
|
|
|
|
tokenize(fgets(file));
|
|
|
|
g_pWaypoints[i].m_pNeighbour[j].m_iNode = stoi(argv(0));
|
|
|
|
g_pWaypoints[i].m_pNeighbour[j].m_flCost = stof(argv(1));
|
2021-03-27 06:48:46 +00:00
|
|
|
g_pWaypoints[i].m_pNeighbour[j].m_iFlags = stoi(argv(2));
|
2020-12-23 06:53:43 +00:00
|
|
|
}
|
|
|
|
}
|
2021-01-02 17:52:09 +00:00
|
|
|
fclose(file);
|
2020-12-23 06:53:43 +00:00
|
|
|
}
|
2020-12-26 06:27:34 +00:00
|
|
|
|
2021-01-02 17:52:09 +00:00
|
|
|
|
2020-12-29 06:17:41 +00:00
|
|
|
void
|
|
|
|
Way_ConnectOne(void)
|
|
|
|
{
|
2021-01-02 20:31:56 +00:00
|
|
|
if (g_waylink_status == 0) {
|
|
|
|
g_way1 = Way_FindClosestNode(self.origin);
|
|
|
|
g_waylink_status = 1;
|
2021-01-02 20:22:56 +00:00
|
|
|
env_message_single(self, "^21/2 nodes selected... \n");
|
2021-01-02 20:31:56 +00:00
|
|
|
} else if (g_waylink_status == 1) {
|
|
|
|
g_way2 = Way_FindClosestNode(self.origin);
|
|
|
|
g_waylink_status = 0;
|
2020-12-29 06:17:41 +00:00
|
|
|
|
2021-01-02 20:31:56 +00:00
|
|
|
if (g_way1 != g_way2) {
|
|
|
|
Way_LinkNodes(&g_pWaypoints[g_way1], &g_pWaypoints[g_way2]);
|
2021-01-02 20:22:56 +00:00
|
|
|
env_message_single(self, "^22/2 nodes selected, done!\n");
|
2020-12-29 06:17:41 +00:00
|
|
|
} else {
|
2021-01-02 20:22:56 +00:00
|
|
|
env_message_single(self, "^1Failed to link, the two points are the same!\n");
|
2020-12-29 06:17:41 +00:00
|
|
|
}
|
2021-01-02 20:31:56 +00:00
|
|
|
g_way1 = g_way2 = -1;
|
2020-12-29 06:17:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-28 18:59:37 +00:00
|
|
|
void
|
|
|
|
Way_ConnectTwo(void)
|
|
|
|
{
|
2021-01-02 20:31:56 +00:00
|
|
|
if (g_waylink_status == 0) {
|
|
|
|
g_way1 = Way_FindClosestNode(self.origin);
|
|
|
|
g_waylink_status = 1;
|
2021-01-02 20:22:56 +00:00
|
|
|
env_message_single(self, "^21/2 nodes selected... \n");
|
2021-01-02 20:31:56 +00:00
|
|
|
} else if (g_waylink_status == 1) {
|
|
|
|
g_way2 = Way_FindClosestNode(self.origin);
|
|
|
|
g_waylink_status = 0;
|
2020-12-28 18:59:37 +00:00
|
|
|
|
2021-01-02 20:31:56 +00:00
|
|
|
if (g_way1 != g_way2) {
|
|
|
|
Way_LinkNodes(&g_pWaypoints[g_way1], &g_pWaypoints[g_way2]);
|
|
|
|
Way_LinkNodes(&g_pWaypoints[g_way2], &g_pWaypoints[g_way1]);
|
2021-01-02 20:22:56 +00:00
|
|
|
env_message_single(self, "^22/2 nodes selected, done!\n");
|
2020-12-28 18:59:37 +00:00
|
|
|
} else {
|
2021-01-02 20:22:56 +00:00
|
|
|
env_message_single(self, "^1Failed to link, the two points are the same!\n");
|
2020-12-28 18:59:37 +00:00
|
|
|
}
|
2021-01-02 20:31:56 +00:00
|
|
|
g_way1 = g_way2 = -1;
|
2020-12-28 18:59:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-02 17:52:09 +00:00
|
|
|
void
|
|
|
|
Way_DrawDebugInfo(void)
|
|
|
|
{
|
|
|
|
if (!g_iWaypoints) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int iNearest = Way_FindClosestNode(self.origin);
|
|
|
|
makevectors(self.v_angle);
|
|
|
|
R_BeginPolygon("", 0, 0);
|
|
|
|
|
|
|
|
for (int i = 0i; i < g_iWaypoints; i++) {
|
|
|
|
waypoint_t *w = g_pWaypoints + i;
|
|
|
|
vector org = w->m_vecOrigin;
|
|
|
|
vector rgb = [1,1,1];
|
|
|
|
|
|
|
|
if (iNearest == i) {
|
|
|
|
rgb = [0,1,0];
|
|
|
|
}
|
|
|
|
|
|
|
|
R_PolygonVertex(org + v_right * 4 - v_up * 4, [1,1], rgb, 1);
|
|
|
|
R_PolygonVertex(org - v_right * 4 - v_up * 4, [0,1], rgb, 1);
|
|
|
|
R_PolygonVertex(org - v_right * 4 + v_up * 4, [0,0], rgb, 1);
|
|
|
|
R_PolygonVertex(org + v_right * 4 + v_up * 4, [1,0], rgb, 1);
|
|
|
|
R_EndPolygon();
|
|
|
|
}
|
|
|
|
|
|
|
|
R_BeginPolygon("", 1, 0);
|
|
|
|
for (int i = 0i; i < g_iWaypoints; i++) {
|
|
|
|
waypoint_t *w = g_pWaypoints+i;
|
|
|
|
vector org = w->m_vecOrigin;
|
|
|
|
vector rgb = [1,1,1];
|
|
|
|
|
|
|
|
for (int j = 0i; j < w->m_numNeighbours; j++) {
|
|
|
|
int k = w->m_pNeighbour[j].m_iNode;
|
|
|
|
int fl = w->m_pNeighbour[j].m_iFlags;
|
|
|
|
|
|
|
|
if (k < 0i || k >= g_iWaypoints) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
waypoint_t *w2 = &g_pWaypoints[k];
|
|
|
|
|
|
|
|
if (fl & LF_JUMP) {
|
|
|
|
vector middle;
|
|
|
|
middle = (w2->m_vecOrigin + org) / 2;
|
|
|
|
R_PolygonVertex(org + [0,0,1], [0,1], [1,1,0], 1);
|
|
|
|
R_PolygonVertex(middle + [0,0,32], [0,1], [0.5,0.5,0], 1);
|
|
|
|
R_EndPolygon();
|
|
|
|
R_PolygonVertex(middle + [0,0,32], [0,1], [0.5,0.5,0], 1);
|
|
|
|
R_PolygonVertex(w2->m_vecOrigin + [0,0,1], [1,1], [0,0,0], 1);
|
|
|
|
R_EndPolygon();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fl & LF_CROUCH) {
|
2021-01-02 20:52:35 +00:00
|
|
|
R_PolygonVertex(org + [0,0,-2], [0,1], [0,1,0], 1);
|
|
|
|
R_PolygonVertex(w2->m_vecOrigin + [0,0,-2], [1,1], [0,0,0], 1);
|
|
|
|
R_EndPolygon();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fl & LF_WALK) {
|
|
|
|
R_PolygonVertex(org + [0,0,-1], [0,1], [1,0,0], 1);
|
|
|
|
R_PolygonVertex(w2->m_vecOrigin + [0,0,-1], [1,1], [0,0,0], 1);
|
2021-01-02 17:52:09 +00:00
|
|
|
R_EndPolygon();
|
|
|
|
}
|
|
|
|
|
2021-01-16 16:34:04 +00:00
|
|
|
if (fl & LF_AIM) {
|
|
|
|
R_PolygonVertex(org + [0,0,4], [0,1], [0.25,0.25,1], 1);
|
|
|
|
R_PolygonVertex(w2->m_vecOrigin + [0,0,4], [1,1], [0,0,0], 1);
|
|
|
|
R_EndPolygon();
|
|
|
|
}
|
|
|
|
|
2021-01-02 17:52:09 +00:00
|
|
|
R_PolygonVertex(org, [0,1], [1,0,1], 1);
|
|
|
|
R_PolygonVertex(w2->m_vecOrigin, [1,1], [0,1,0], 1);
|
|
|
|
R_EndPolygon();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-02 20:31:56 +00:00
|
|
|
if (g_way1 >= 0) {
|
|
|
|
R_PolygonVertex(g_pWaypoints[g_way1]->m_vecOrigin, [0,1], [0,1,0], 1);
|
|
|
|
R_PolygonVertex(self.origin, [1,1], [0,1,0], 1);
|
|
|
|
R_EndPolygon();
|
|
|
|
}
|
|
|
|
|
2021-01-02 17:52:09 +00:00
|
|
|
R_BeginPolygon("", 0, 0);
|
|
|
|
for (int i = 0i; i < g_iWaypoints; i++) {
|
|
|
|
vector rgb;
|
|
|
|
waypoint_t *w = g_pWaypoints + i;
|
|
|
|
vector org = w->m_vecOrigin;
|
|
|
|
|
|
|
|
if (iNearest == i) {
|
|
|
|
rgb = [0,1,0];
|
|
|
|
} else {
|
|
|
|
rgb = [0.5,0,1.0];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (w->m_flRadius) {
|
|
|
|
for(int j = 0; j < 16; j++) {
|
|
|
|
float theta = 2.0f * M_PI * j / 16;
|
|
|
|
vector p = (v_right * sin(theta)) + (v_up * cos(theta));
|
|
|
|
R_PolygonVertex(org + (p * w->m_flRadius), [1,1], rgb, 0.1f);
|
|
|
|
|
|
|
|
}
|
|
|
|
R_EndPolygon();
|
|
|
|
for(int j = 0; j < 16; j++) {
|
|
|
|
float theta = 2.0f * M_PI * j / 16;
|
|
|
|
R_PolygonVertex(org + [sin(theta), cos(theta)] * w->m_flRadius, [1,1], rgb, 0.2f);
|
|
|
|
|
|
|
|
}
|
|
|
|
R_EndPolygon();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-02-08 12:35:15 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
Way_Cmd(void)
|
|
|
|
{
|
|
|
|
if (!self) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (argv(1)) {
|
|
|
|
case "goto":
|
|
|
|
Way_GoToPoint(self);
|
|
|
|
break;
|
|
|
|
case "autolink":
|
|
|
|
Way_AutoLink(Way_FindClosestNode(self.origin));
|
|
|
|
break;
|
|
|
|
case "connect1":
|
|
|
|
Way_ConnectOne();
|
|
|
|
break;
|
|
|
|
case "connect2":
|
|
|
|
Way_ConnectTwo();
|
|
|
|
break;
|
|
|
|
case "add":
|
|
|
|
Way_CreateNode(self, 1);
|
|
|
|
break;
|
|
|
|
case "addchain":
|
|
|
|
Way_CreateNode(self, 0);
|
|
|
|
break;
|
|
|
|
case "addsingle":
|
|
|
|
Way_CreateNode(self, -3);
|
|
|
|
break;
|
|
|
|
case "addltn":
|
|
|
|
Way_CreateNode(self, -1);
|
|
|
|
break;
|
|
|
|
case "addntl":
|
|
|
|
Way_CreateNode(self, -2);
|
|
|
|
break;
|
|
|
|
case "addspawns":
|
|
|
|
Way_HelperSpawns();
|
|
|
|
break;
|
|
|
|
case "delete":
|
|
|
|
Way_DeleteNode(Way_FindClosestNode(self.origin));
|
|
|
|
break;
|
|
|
|
case "purge":
|
|
|
|
Way_WipeWaypoints();
|
|
|
|
break;
|
|
|
|
case "radius":
|
|
|
|
Way_SetRadius(Way_FindClosestNode(self.origin), stof(argv(2)));
|
|
|
|
break;
|
|
|
|
case "radiushack":
|
|
|
|
for (int i = 0i; i < g_iWaypoints; i++) {
|
|
|
|
g_pWaypoints[i].m_flRadius = autocvar_nav_radius;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "linkjump":
|
|
|
|
Way_FlagJump();
|
|
|
|
break;
|
|
|
|
case "linkcrouch":
|
|
|
|
Way_FlagCrouch();
|
|
|
|
break;
|
|
|
|
case "linkwalk":
|
|
|
|
Way_FlagWalk();
|
|
|
|
break;
|
|
|
|
case "linkaim":
|
|
|
|
Way_FlagAim();
|
|
|
|
break;
|
2021-03-27 06:48:46 +00:00
|
|
|
case "linkuse":
|
|
|
|
Way_FlagUse();
|
|
|
|
break;
|
2021-02-08 12:35:15 +00:00
|
|
|
case "move":
|
|
|
|
vector p;
|
|
|
|
int n = Way_FindClosestNode(self.origin);
|
|
|
|
if (n >= 0) {
|
|
|
|
p[0] = stof(argv(2));
|
|
|
|
p[1] = stof(argv(3));
|
|
|
|
p[2] = stof(argv(4));
|
|
|
|
g_pWaypoints[n].m_vecOrigin += p;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "movetopos":
|
|
|
|
int nearest = Way_FindClosestNode(self.origin);
|
|
|
|
if (nearest >= 0) {
|
|
|
|
g_pWaypoints[nearest].m_vecOrigin = self.origin;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "save":
|
|
|
|
Way_SaveFile(argv(2));
|
|
|
|
break;
|
|
|
|
case "load":
|
|
|
|
Way_ReadFile(argv(2));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|