Merge branch 'Lyberta/TeamplayOverhaul2' into 'master'
authorMario <zacjardine@y7mail.com>
Fri, 7 Sep 2018 19:12:55 +0000 (19:12 +0000)
committerMario <zacjardine@y7mail.com>
Fri, 7 Sep 2018 19:12:55 +0000 (19:12 +0000)
Teamplay overhaul - step 2

Closes #1982 and #2071

See merge request xonotic/xonotic-data.pk3dir!581

commands.cfg
qcsrc/common/gamemodes/gamemode/keyhunt/sv_keyhunt.qc
qcsrc/common/impulses/all.qh
qcsrc/common/physics/player.qc
qcsrc/common/viewloc.qc
qcsrc/server/bot/default/waypoints.qc
qcsrc/server/client.qc
qcsrc/server/command/cmd.qc
qcsrc/server/impulse.qc
qcsrc/server/player.qc
xonotic-client.cfg

index 3e5e78e0ef5d5581404ff021824f3bb741013776..0f2e5689253e3ef06acfc3c4b0cef282e7da7419 100644 (file)
@@ -175,6 +175,7 @@ alias spectate             "qc_cmd_cmd    spectate             ${* ?}" // Become
 alias suggestmap           "qc_cmd_cmd    suggestmap           ${* ?}" // Suggest a map to the mapvote at match end
 //alias tell               "qc_cmd_cmd    tell                 ${* ?}" // Send a message directly to a player
 alias voice                "qc_cmd_cmd    voice                ${* ?}" // Send voice message via sound
+alias wpeditor             "qc_cmd_cmd    wpeditor             ${* ?}" // Waypoint editor commands
 
 // other aliases for client-to-server commands
 alias autoswitch "set cl_autoswitch ${1 ?} ; cmd autoswitch ${1 ?}" // todo
index cce2ffb747076bf03485eb9fbee059037de3a3dc..f8456734caa0f528e93b7b0b6b50cfdbfae3ef75 100644 (file)
@@ -52,12 +52,6 @@ bool kh_no_radar_circles;
 .float siren_time;  //  time delay the siren
 //.float stuff_time;  //  time delay to stuffcmd a cvar
 
-int kh_keystatus[17];
-//kh_keystatus[0] = status of dropped keys, kh_keystatus[1 - 16] = player #
-//replace 17 with cvar("maxplayers") or similar !!!!!!!!!
-//for(i = 0; i < maxplayers; ++i)
-//     kh_keystatus[i] = "0";
-
 int kh_Team_ByID(int t)
 {
        if(t == 0) return NUM_TEAM_1;
@@ -340,18 +334,6 @@ void kh_Key_AssignTo(entity key, entity player)  // runs every time a key is pic
                if(key.kh_next)
                        key.kh_next.kh_prev = key;
 
-               float i;
-               i = kh_keystatus[key.owner.playerid];
-                       if(key.netname == "^1red key")
-                               i += 1;
-                       if(key.netname == "^4blue key")
-                               i += 2;
-                       if(key.netname == "^3yellow key")
-                               i += 4;
-                       if(key.netname == "^6pink key")
-                               i += 8;
-               kh_keystatus[key.owner.playerid] = i;
-
                kh_Key_Attach(key);
 
                if(key.kh_next == NULL)
index 45a8f1323b9f142bd02b5eae8ad61202a273ae63..8bd0c41dab29ec33e9f4f2877f00638e9578eb45 100644 (file)
@@ -186,20 +186,6 @@ LEGACY_IMPULSE(g_waypointsprite_clear_personal, 47, "waypoint_clear_personal")
 REGISTER_IMPULSE(waypoint_clear, 48)
 LEGACY_IMPULSE(g_waypointsprite_clear, 48, "waypoint_clear")
 
-REGISTER_IMPULSE(navwaypoint_spawn, 103)
-LEGACY_IMPULSE(g_waypointeditor_spawn, 103, "navwaypoint_spawn")
-
-REGISTER_IMPULSE(navwaypoint_remove, 104)
-LEGACY_IMPULSE(g_waypointeditor_remove, 104, "navwaypoint_remove")
-
-REGISTER_IMPULSE(navwaypoint_relink, 105)
-LEGACY_IMPULSE(g_waypointeditor_relinkall, 105, "navwaypoint_relink")
-
-REGISTER_IMPULSE(navwaypoint_save, 106)
-LEGACY_IMPULSE(g_waypointeditor_saveall, 106, "navwaypoint_save")
-
-REGISTER_IMPULSE(navwaypoint_unreachable, 107)
-LEGACY_IMPULSE(g_waypointeditor_unreachable, 107, "navwaypoint_unreachable")
 
 #define CHIMPULSE(id, n) _CHIMPULSE(CHIMPULSE_##id, n)
 #define _CHIMPULSE(id, n) \
index f6ab29715a298c07a7bc9c317d0a69d4d9636298..572bee349f205ca81caac2d23d0ff6da1d839696 100644 (file)
@@ -119,6 +119,8 @@ void PM_ClientMovement_UpdateStatus(entity this)
                }
        }
        bool do_crouch = PHYS_INPUT_BUTTON_CROUCH(this);
+       if(this.viewloc && !(this.viewloc.spawnflags & VIEWLOC_FREEMOVE) && PHYS_CS(this).movement.x < 0)
+               do_crouch = true;
        if (have_hook) {
                do_crouch = false;
        //} else if (this.waterlevel >= WATERLEVEL_SWIMMING) {
index f2dab7bfd22cd7c8620f3b69e7c10d9f37ece242..e1be43af0d41f9826993c9b9a7e1dceb247b9e16 100644 (file)
@@ -48,7 +48,7 @@ void viewloc_PlayerPhysics(entity this)
                        if(PHYS_CS(this).movement_x > 0) // right
                                this.angles_y = forward.y;
                }
-
+       #if 0
                //if(!PHYS_INPUT_BUTTON_CROUCH(this) && !IS_DUCKED(this))
                if(!(this.viewloc.spawnflags & VIEWLOC_FREEMOVE))
                {
@@ -65,6 +65,7 @@ void viewloc_PlayerPhysics(entity this)
                        //else { input_buttons &= ~16; this.flags &= ~FL_DUCKED; }
 #endif
                }
+       #endif
        }
 }
 
index f75829aecd8595d8a69087e9a035708d53cf14ef..2ea30b50fe31ab5f742df66155f60c327ce3e073 100644 (file)
@@ -128,7 +128,7 @@ void waypoint_unreachable(entity pl)
        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 waypoint_getSymmetricalPoint(vector org, int ctf_flags)
 {
        vector new_org = org;
        if (fabs(autocvar_g_waypointeditor_symmetrical) == 1)
@@ -281,7 +281,7 @@ void waypoint_spawn_fromeditor(entity pl)
        bprint(strcat("Waypoint spawned at ", vtos(e.origin), "\n"));
        if(sym)
        {
-               org = waypoint_getSymmetricalOrigin(e.origin, ctf_flags);
+               org = waypoint_getSymmetricalPoint(e.origin, ctf_flags);
                if (vdist(org - pl.origin, >, 32))
                {
                        if(wp_num > 2)
@@ -329,7 +329,7 @@ void waypoint_remove_fromeditor(entity pl)
        entity wp_sym = NULL;
        if (sym)
        {
-               vector org = waypoint_getSymmetricalOrigin(e.origin, ctf_flags);
+               vector org = waypoint_getSymmetricalPoint(e.origin, ctf_flags);
                FOREACH_ENTITY_CLASS("waypoint", !(it.wpflags & WAYPOINTFLAG_GENERATED), {
                        if(vdist(org - it.origin, <, 3))
                        {
@@ -1016,6 +1016,7 @@ void waypoint_save_links()
                        entity link = waypoint_get_link(it, j);
                        if(link)
                        {
+                               // NOTE: vtos rounds vector components to 1 decimal place
                                string s = strcat(vtos(it.origin), "*", vtos(link.origin), "\n");
                                fputs(file, s);
                                ++c;
@@ -1088,6 +1089,7 @@ void waypoint_saveall()
                        continue;
 
                string s;
+               // NOTE: vtos rounds vector components to 1 decimal place
                s = strcat(vtos(it.origin + it.mins), "\n");
                s = strcat(s, vtos(it.origin + it.maxs));
                s = strcat(s, "\n");
index 2d0ec2617b2c826dd9dff87608f0bf83752fbaf0..8e6a26961b02c6b845103254f56222496d24a10e 100644 (file)
@@ -1612,7 +1612,7 @@ void GetPressedKeys(entity this)
        keys = BITSET(keys, KEY_LEFT,           CS(this).movement.y < 0);
 
        keys = BITSET(keys, KEY_JUMP,           PHYS_INPUT_BUTTON_JUMP(this));
-       keys = BITSET(keys, KEY_CROUCH,         PHYS_INPUT_BUTTON_CROUCH(this));
+       keys = BITSET(keys, KEY_CROUCH,         IS_DUCKED(this)); // workaround: player can't un-crouch until their path is clear, so we keep the button held here
        keys = BITSET(keys, KEY_ATCK,           PHYS_INPUT_BUTTON_ATCK(this));
        keys = BITSET(keys, KEY_ATCK2,          PHYS_INPUT_BUTTON_ATCK2(this));
        CS(this).pressedkeys = keys; // store for other users
index 6f1d60dd9bffe1a9dd9970408ec715f3071f29f1..915fea7ee0ca2ca02ffb14d9341d539b4b4a7d14 100644 (file)
@@ -8,6 +8,8 @@
 #include "common.qh"
 #include "vote.qh"
 
+#include "../bot/api.qh"
+
 #include "../campaign.qh"
 #include "../cheats.qh"
 #include "../client.qh"
@@ -166,6 +168,61 @@ void ClientCommand_mv_getpicture(entity caller, int request, int argc)  // inter
        }
 }
 
+void ClientCommand_wpeditor(entity caller, int request, int argc)
+{
+       switch (request)
+       {
+               case CMD_REQUEST_COMMAND:
+               {
+                       if (!autocvar_g_waypointeditor)
+                       {
+                               sprint(caller, "ERROR: this command works only if the waypoint editor is on\n");
+                               return;
+                       }
+
+                       if (argv(1) != "")
+                       {
+                               if (argv(1) == "spawn")
+                               {
+                                       if (!IS_PLAYER(caller))
+                                               sprint(caller, "ERROR: this command works only if you are player\n");
+                                       else
+                                               waypoint_spawn_fromeditor(caller);
+                               }
+                               else if (argv(1) == "remove")
+                               {
+                                       if (!IS_PLAYER(caller))
+                                               sprint(caller, "ERROR: this command works only if you are player\n");
+                                       else
+                                               waypoint_remove_fromeditor(caller);
+                               }
+                               else if (argv(1) == "unreachable")
+                               {
+                                       if (!IS_PLAYER(caller))
+                                               sprint(caller, "ERROR: this command works only if you are player\n");
+                                       else
+                                               waypoint_unreachable(caller);
+                               }
+                               else if (argv(1) == "saveall")
+                                       waypoint_saveall();
+                               else if (argv(1) == "relinkall")
+                                       waypoint_schedulerelinkall();
+
+                               return;
+                       }
+               }
+
+               default:
+                       sprint(caller, "Incorrect parameters for ^2wpeditor^7\n");
+               case CMD_REQUEST_USAGE:
+               {
+                       sprint(caller, "\nUsage:^3 cmd wpeditor action\n");
+                       sprint(caller, "  Where 'action' can be: spawn, remove, unreachable, saveall, relinkall\n");
+                       return;
+               }
+       }
+}
+
 void ClientCommand_join(entity caller, int request)
 {
        switch (request)
@@ -306,19 +363,7 @@ void ClientCommand_say_team(entity caller, int request, int argc, string command
                case CMD_REQUEST_COMMAND:
                {
                        if (argc >= 2)
-                       {
-                               string _classname = string_null;
-                               if (!IS_PLAYER(caller) && caller.caplayer)
-                               {
-                                       // CA: make work team chat for killed players
-                                       _classname = caller.classname;
-                                       caller.classname = STR_PLAYER;
-                               }
-
                                Say(caller, true, NULL, substring(command, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1);
-                               if (_classname)
-                                       caller.classname = _classname;
-                       }
                        return;  // never fall through to usage
                }
 
@@ -698,6 +743,7 @@ void ClientCommand_(entity caller, int request)
        CLIENT_COMMAND("suggestmap", ClientCommand_suggestmap(ent, request, arguments), "Suggest a map to the mapvote at match end") \
        CLIENT_COMMAND("tell", ClientCommand_tell(ent, request, arguments, command), "Send a message directly to a player") \
        CLIENT_COMMAND("voice", ClientCommand_voice(ent, request, arguments, command), "Send voice message via sound") \
+       CLIENT_COMMAND("wpeditor", ClientCommand_wpeditor(ent, request, arguments), "Waypoint editor commands") \
        /* nothing */
 
 void ClientCommand_macro_help(entity caller)
@@ -772,6 +818,7 @@ void SV_ParseClientCommand(entity this, string command)
                case "begin": break;                               // handled by engine in host_cmd.c
                case "download": break;                            // handled by engine in cl_parse.c
                case "mv_getpicture": break;                       // handled by server in this file
+               case "wpeditor": break;                            // handled by server in this file
                case "pause": break;                               // handled by engine in host_cmd.c
                case "prespawn": break;                            // handled by engine in host_cmd.c
                case "sentcvar": break;                            // handled by server in this file
index 5d71b95afa829d84ba7885516b458a92d40a3dd2..cce5963990893d7a4178e8b7d5e0ddd7895b886e 100644 (file)
@@ -1,8 +1,6 @@
 #include "impulse.qh"
 #include "round_handler.qh"
 
-#include "bot/api.qh"
-
 #include "weapons/throwing.qh"
 #include "command/common.qh"
 #include "cheats.qh"
@@ -572,33 +570,3 @@ IMPULSE(waypoint_clear)
        }
        sprint(this, "all waypoints cleared\n");
 }
-
-IMPULSE(navwaypoint_spawn)
-{
-       if (!autocvar_g_waypointeditor) return;
-       waypoint_spawn_fromeditor(this);
-}
-
-IMPULSE(navwaypoint_remove)
-{
-       if (!autocvar_g_waypointeditor) return;
-       waypoint_remove_fromeditor(this);
-}
-
-IMPULSE(navwaypoint_relink)
-{
-       if (!autocvar_g_waypointeditor) return;
-       waypoint_schedulerelinkall();
-}
-
-IMPULSE(navwaypoint_save)
-{
-       if (!autocvar_g_waypointeditor) return;
-       waypoint_saveall();
-}
-
-IMPULSE(navwaypoint_unreachable)
-{
-       if (!autocvar_g_waypointeditor) return;
-       waypoint_unreachable(this);
-}
index 5d69c0aa1a4b88dde931bd63ec6f967dd525cdad..6c64f2feabed42452d713e933b50357d23a20488 100644 (file)
@@ -551,8 +551,8 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
                if(this.classname != "body")
                        Obituary (attacker, inflictor, this, deathtype, weaponentity);
 
-        // increment frag counter for used weapon type
-        Weapon w = DEATH_WEAPONOF(deathtype);
+               // increment frag counter for used weapon type
+               Weapon w = DEATH_WEAPONOF(deathtype);
                if(w != WEP_Null && accuracy_isgooddamage(attacker, this))
                        CS(attacker).accuracy.(accuracy_frags[w.m_id-1]) += 1;
 
@@ -686,13 +686,13 @@ bool PlayerHeal(entity targ, entity inflictor, float amount, float limit)
 int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodcontrol)
 {
        if (!teamsay && !privatesay && substring(msgin, 0, 1) == " ")
-        msgin = substring(msgin, 1, -1); // work around DP say bug (say_team does not have this!)
+               msgin = substring(msgin, 1, -1); // work around DP say bug (say_team does not have this!)
 
-    if(source)
+       if (source)
                msgin = formatmessage(source, msgin);
 
-    string colorstr;
-       if (!IS_PLAYER(source))
+       string colorstr;
+       if (!(IS_PLAYER(source) || source.caplayer))
                colorstr = "^0"; // black for spectators
        else if(teamplay)
                colorstr = Team_ColorCode(source.team);
@@ -705,10 +705,10 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
        if(game_stopped)
                teamsay = false;
 
-    if (!source) {
+       if (!source) {
                colorstr = "";
                teamsay = false;
-    }
+       }
 
        if(msgin != "")
                msgin = trigger_magicear_processmessage_forallears(source, teamsay, privatesay, msgin);
@@ -724,18 +724,17 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
        }
        */
 
-    string namestr = "";
-    if (source)
-        namestr = playername(source, autocvar_g_chat_teamcolors);
+       string namestr = "";
+       if (source)
+               namestr = playername(source, autocvar_g_chat_teamcolors);
 
-    string colorprefix = (strdecolorize(namestr) == namestr) ? "^3" : "^7";
+       string colorprefix = (strdecolorize(namestr) == namestr) ? "^3" : "^7";
 
-    string msgstr, cmsgstr;
-    string privatemsgprefix = string_null;
-    int privatemsgprefixlen = 0;
-       if (msgin == "") {
-        msgstr = cmsgstr = "";
-       } else {
+       string msgstr = "", cmsgstr = "";
+       string privatemsgprefix = string_null;
+       int privatemsgprefixlen = 0;
+       if (msgin != "")
+       {
                if(privatesay)
                {
                        msgstr = strcat("\{1}\{13}* ", colorprefix, namestr, "^3 tells you: ^7");
@@ -767,10 +766,10 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
                                msgstr = strcat("\{1}^4* ", "^7", msgin);
                        }
                        else {
-                msgstr = "\{1}";
-                msgstr = strcat(msgstr, (namestr != "") ? strcat(colorprefix, namestr, "^7: ") : "^7");
-                msgstr = strcat(msgstr, msgin);
-            }
+                               msgstr = "\{1}";
+                               msgstr = strcat(msgstr, (namestr != "") ? strcat(colorprefix, namestr, "^7: ") : "^7");
+                               msgstr = strcat(msgstr, msgin);
+                       }
                        cmsgstr = "";
                }
                msgstr = strcat(strreplace("\n", " ", msgstr), "\n"); // newlines only are good for centerprint
@@ -853,7 +852,7 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
                        source.(flood_field) = flood = 0;
        }
 
-    string sourcemsgstr, sourcecmsgstr;
+       string sourcemsgstr, sourcecmsgstr;
        if(flood == 2) // cannot happen for empty msgstr
        {
                if(autocvar_g_chat_flood_notify_flooder)
@@ -874,7 +873,7 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
                sourcecmsgstr = cmsgstr;
        }
 
-       if (!privatesay && source && !IS_PLAYER(source))
+       if (!privatesay && source && !(IS_PLAYER(source) || source.caplayer))
        {
                if (!game_stopped)
                if (teamsay || (autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !warmup_stage))
@@ -888,7 +887,7 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
        if(privatesay)
                sourcemsgstr = strcat(privatemsgprefix, substring(sourcemsgstr, privatemsgprefixlen, -1));
 
-    int ret;
+       int ret;
        if(source && CS(source).muted)
        {
                // always fake the message
@@ -909,10 +908,10 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
                ret = 1;
        }
 
-       if (privatesay && source && !IS_PLAYER(source))
+       if (privatesay && source && !(IS_PLAYER(source) || source.caplayer))
        {
                if (!game_stopped)
-               if ((privatesay && IS_PLAYER(privatesay)) && ((autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !warmup_stage)))
+               if ((privatesay && (IS_PLAYER(privatesay) || privatesay.caplayer)) && ((autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !warmup_stage)))
                        ret = -1; // just hide the message completely
        }
 
@@ -942,7 +941,9 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
                {
                        sprint(source, sourcemsgstr);
                        dedicated_print(msgstr); // send to server console too
-                       FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source && CS(it).active_minigame == CS(source).active_minigame && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), sprint(it, msgstr));
+                       FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source && CS(it).active_minigame == CS(source).active_minigame && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), {
+                               sprint(it, msgstr);
+                       });
                }
                else if(teamsay > 0) // team message, only sent to team mates
                {
@@ -950,7 +951,7 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
                        dedicated_print(msgstr); // send to server console too
                        if(sourcecmsgstr != "")
                                centerprint(source, sourcecmsgstr);
-                       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && it != source && it.team == source.team && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), {
+                       FOREACH_CLIENT((IS_PLAYER(it) || it.caplayer) && IS_REAL_CLIENT(it) && it != source && it.team == source.team && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), {
                                sprint(it, msgstr);
                                if(cmsgstr != "")
                                        centerprint(it, cmsgstr);
@@ -960,17 +961,21 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
                {
                        sprint(source, sourcemsgstr);
                        dedicated_print(msgstr); // send to server console too
-                       FOREACH_CLIENT(!IS_PLAYER(it) && IS_REAL_CLIENT(it) && it != source && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), sprint(it, msgstr));
+                       FOREACH_CLIENT(!(IS_PLAYER(it) || it.caplayer) && IS_REAL_CLIENT(it) && it != source && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), {
+                               sprint(it, msgstr);
+                       });
                }
                else
                {
-            if (source) {
-                sprint(source, sourcemsgstr);
-                dedicated_print(msgstr); // send to server console too
-                MX_Say(strcat(playername(source, true), "^7: ", msgin));
-            }
-            FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), sprint(it, msgstr));
-        }
+                       if (source) {
+                               sprint(source, sourcemsgstr);
+                               dedicated_print(msgstr); // send to server console too
+                               MX_Say(strcat(playername(source, true), "^7: ", msgin));
+                       }
+                       FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != source && !MUTATOR_CALLHOOK(ChatMessageTo, it, source), {
+                               sprint(it, msgstr);
+                       });
+               }
        }
 
        return ret;
index 8517818d6406c902715a967507f55b6eed28e669..548616908e06c893763a09fa3ea99ed248162a6c 100644 (file)
@@ -229,11 +229,17 @@ cl_movement 1
 cl_movement_track_canjump 0
 cl_stairsmoothspeed 200
 
-alias g_waypointeditor_spawn "impulse 103"
-alias g_waypointeditor_remove "impulse 104"
-alias g_waypointeditor_relinkall "impulse 105"
-alias g_waypointeditor_saveall "impulse 106"
-alias g_waypointeditor_unreachable "impulse 107"
+alias g_waypointeditor_spawn         "wpeditor spawn"
+alias g_waypointeditor_remove        "wpeditor remove"
+alias g_waypointeditor_relinkall     "wpeditor relinkall"
+alias g_waypointeditor_saveall       "wpeditor saveall"
+alias g_waypointeditor_unreachable   "wpeditor unreachable"
+
+alias navwaypoint_relink        g_waypointeditor_spawn
+alias navwaypoint_remove        g_waypointeditor_remove
+alias navwaypoint_save          g_waypointeditor_relinkall
+alias navwaypoint_spawn         g_waypointeditor_saveall
+alias navwaypoint_unreachable   g_waypointeditor_unreachable
 
 seta menu_sandbox_spawn_model ""
 seta menu_sandbox_attach_bone ""