#include "cmd.qh"
-#include <server/defs.qh>
-#include <server/miscfunctions.qh>
-
#include <common/command/_mod.qh>
-
-#include "common.qh"
-#include "vote.qh"
-
-#include "../bot/api.qh"
-
-#include "../campaign.qh"
-#include "../cheats.qh"
-#include "../client.qh"
-#include "../clientkill.qh"
-#include "../player.qh"
-#include "../ipban.qh"
-#include "../mapvoting.qh"
-#include "../scores.qh"
-#include "../teamplay.qh"
-
-#include <server/mutators/_mod.qh>
-#include <common/gamemodes/_mod.qh>
-
-#ifdef SVQC
- #include <common/vehicles/all.qh>
-#endif
-
#include <common/constants.qh>
#include <common/deathtypes/all.qh>
#include <common/effects/all.qh>
+#include <common/gamemodes/_mod.qh>
#include <common/mapinfo.qh>
-#include <common/notifications/all.qh>
-#include <common/physics/player.qh>
-#include <common/teams.qh>
-#include <common/util.qh>
#include <common/mapobjects/triggers.qh>
-
#include <common/minigames/sv_minigames.qh>
-
#include <common/monsters/_mod.qh>
-#include <common/monsters/sv_spawn.qh>
#include <common/monsters/sv_monsters.qh>
-
+#include <common/monsters/sv_spawn.qh>
+#include <common/notifications/all.qh>
+#include <common/physics/player.qh>
+#include <common/teams.qh>
+#include <common/util.qh>
+#include <common/vehicles/all.qh>
#include <lib/warpzone/common.qh>
+#include <server/bot/api.qh>
+#include <server/bot/default/waypoints.qh>
+#include <server/campaign.qh>
+#include <server/chat.qh>
+#include <server/cheats.qh>
+#include <server/client.qh>
+#include <server/clientkill.qh>
+#include <server/command/common.qh>
+#include <server/command/getreplies.qh>
+#include <server/command/vote.qh>
+#include <server/ipban.qh>
+#include <server/mapvoting.qh>
+#include <server/mutators/_mod.qh>
+#include <server/player.qh>
+#include <server/scores.qh>
+#include <server/teamplay.qh>
+#include <server/world.qh>
// =========================================================
// Server side networked commands code, reworked by Samual
{
if (argv(1) != "")
{
- CS(caller).autoswitch = InterpretBoolean(argv(1));
- sprint(caller, strcat("^1autoswitch is currently turned ", (CS(caller).autoswitch ? "on" : "off"), ".\n"));
+ CS_CVAR(caller).autoswitch = InterpretBoolean(argv(1));
+ sprint(caller, strcat("^1autoswitch is currently turned ", (CS_CVAR(caller).autoswitch ? "on" : "off"), ".\n"));
return;
}
}
default:
- sprint(caller, "Incorrect parameters for ^2autoswitch^7\n");
+ sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
case CMD_REQUEST_USAGE:
{
- sprint(caller, "\nUsage:^3 cmd autoswitch selection\n");
- sprint(caller, " Where 'selection' controls if autoswitch is on or off.\n");
+ sprint(caller, "\nUsage:^3 cmd autoswitch <selection>\n");
+ sprint(caller, " Where <selection> controls if autoswitch is on or off.\n");
return;
}
}
}
default:
- sprint(caller, "Incorrect parameters for ^2clientversion^7\n");
+ sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
case CMD_REQUEST_USAGE:
{
- sprint(caller, "\nUsage:^3 cmd clientversion version\n");
- sprint(caller, " Where 'version' is the game version reported by caller.\n");
+ sprint(caller, "\nUsage:^3 cmd clientversion <version>\n");
+ sprint(caller, " Where <version> is the game version reported by caller.\n");
return;
}
}
}
default:
- sprint(caller, "Incorrect parameters for ^2mv_getpicture^7\n");
+ sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
case CMD_REQUEST_USAGE:
{
- sprint(caller, "\nUsage:^3 cmd mv_getpicture mapid\n");
- sprint(caller, " Where 'mapid' is the id number of the map to request an image of on the map vote selection menu.\n");
+ sprint(caller, "\nUsage:^3 cmd mv_getpicture <mapid>\n");
+ sprint(caller, " Where <mapid> is the id number of the map to request an image of on the map vote selection menu.\n");
return;
}
}
{
case CMD_REQUEST_COMMAND:
{
- if (!autocvar_g_waypointeditor)
+ if (!waypointeditor_enabled)
{
sprint(caller, "ERROR: this command works only if the waypoint editor is on\n");
return;
}
default:
- sprint(caller, "Incorrect parameters for ^2wpeditor^7\n");
+ sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
case CMD_REQUEST_USAGE:
{
- sprint(caller, "\nUsage:^3 cmd wpeditor action\n");
- sprint(caller, " Where 'action' can be:\n");
- sprint(caller, " ^5spawn^7: spawns a waypoint at player's position\n");
- sprint(caller, " ^5remove^7: remove player's nearest waypoint\n");
- sprint(caller, " ^5unreachable^7: useful to reveal waypoints and items unreachable from the current position and spawnpoints without a nearest waypoint\n");
- sprint(caller, " ^5saveall^7: saves all waypoints and links to file\n");
- sprint(caller, " ^5relinkall^7: relink all waypoints as if they were respawned\n");
- sprint(caller, " ^5spawn crosshair^7: spawns a waypoint at crosshair's position (in general useful to create special and hardwired links with ease from existing waypoints, in particular it's the only way to create custom jumppad waypoints (spawn another waypoint to create destination))\n");
- sprint(caller, " ^5spawn jump^7: spawns a jump waypoint (spawn another waypoint to create destination)\n");
- sprint(caller, " ^5spawn crouch^7: spawns a crouch waypoint\n");
- sprint(caller, " ^5spawn support^7: spawns a support waypoint (spawn another waypoint to create destination from which all incoming links are removed), useful to replace links to preblematic jumppad/teleport waypoints\n");
- sprint(caller, " ^5hardwire^7: marks the nearest waypoint as origin of a new hardwired link (spawn another waypoint over an existing one to create destination)\n");
- sprint(caller, " ^5hardwire crosshair^7: marks the waypoint at crosshair instead of the nearest waypoint\n");
- sprint(caller, " ^5lock^7: locks link display of the aimed waypoint (unlocks if no waypoint is found at crosshair's position)\n");
- sprint(caller, " ^5symorigin get|set\n");
- sprint(caller, " ^5symorigin get|set p1 p2 ... pX\n");
- sprint(caller, " ^5symaxis get|set p1 p2\n");
- sprint(caller, " ^7 where p1 p2 ... pX are positions (\"x y z\", z can be omitted) that you know are perfectly symmetrical");
- sprint(caller, " ^7 so you can determine origin/axis of symmetry of maps without ctf flags or where flags aren't perfectly symmetrical\n");
+ sprint(caller, "\nUsage:^3 cmd wpeditor <action>\n");
+ sprint(caller, " Where <action> can be:\n");
+ sprint(caller, " ^2spawn^7: spawns a waypoint at player's position\n");
+ sprint(caller, " ^2remove^7: removes player's nearest waypoint\n");
+ sprint(caller, " ^2unreachable^7: reveals waypoints and items unreachable from the current position and spawnpoints without a nearest waypoint\n");
+ sprint(caller, " ^2saveall^7: saves all waypoints and links to file\n");
+ sprint(caller, " ^2relinkall^7: relinks all waypoints as if they were respawned\n");
+ sprint(caller, " ^2spawn crosshair^7: spawns a waypoint at crosshair's position\n");
+ sprint(caller, " ^7 in general useful to create special and hardwired links with ease from existing waypoints\n");
+ sprint(caller, " ^7 in particular it's the only way to create custom jumppad waypoints (spawn another waypoint to create destination))\n");
+ sprint(caller, " ^2spawn jump^7: spawns a jump waypoint (place it at least 60 qu before jump start, spawn another waypoint to create destination)\n");
+ sprint(caller, " ^2spawn crouch^7: spawns a crouch waypoint (it links only to very close waypoints)\n");
+ sprint(caller, " ^2spawn support^7: spawns a support waypoint (spawn another waypoint to create destination from which all incoming links are removed)\n");
+ sprint(caller, " ^7 useful to replace links to problematic jumppad/teleport waypoints\n");
+ sprint(caller, " ^2hardwire^7: marks the nearest waypoint as origin of a new hardwired link (spawn another waypoint over an existing one to create destination)\n");
+ sprint(caller, " ^2hardwire crosshair^7: marks the waypoint at crosshair instead of the nearest waypoint\n");
+ sprint(caller, " ^2lock^7: locks link display of the aimed waypoint (unlocks if no waypoint is found at crosshair's position)\n");
+ sprint(caller, " ^2symorigin get|set\n");
+ sprint(caller, " ^2symorigin get|set <p1> <p2> ... <pX>\n");
+ sprint(caller, " ^2symaxis get|set <p1> <p2>\n");
+ sprint(caller, " ^7 where <p1> <p2> ... <pX> are positions (\"x y z\", z can be omitted) that you know are perfectly symmetrical"
+ " so you can determine origin/axis of symmetry of maps without ctf flags or where flags aren't perfectly symmetrical\n");
+ sprint(caller, " See ^5wpeditor_menu^7 for a selectable list of various commands and useful settings to edit waypoints.\n");
return;
}
}
{
case CMD_REQUEST_COMMAND:
{
- if (!game_stopped)
- if (IS_CLIENT(caller) && !IS_PLAYER(caller))
- if (joinAllowed(caller))
- Join(caller);
+ if (!game_stopped && IS_CLIENT(caller) && !IS_PLAYER(caller))
+ {
+ if (joinAllowed(caller))
+ Join(caller);
+ else if(time < CS(caller).jointime + MIN_SPEC_TIME)
+ CS(caller).autojoin_checked = -1;
+ }
return; // never fall through to usage
}
if (Physics_Valid(command) || command == "default")
{
- stuffcmd(caller, strcat("\nseta cl_physics ", command, "\nsendcvar cl_physics\n"));
+ stuffcmd(caller, strcat("\nseta cl_physics ", command, "\n"));
sprint(caller, strcat("^2Physics set successfully changed to ^3", command, "\n"));
return;
}
}
default:
- sprint(caller, strcat("Current physics set: ^3", CS(caller).cvar_cl_physics, "\n"));
+ sprint(caller, strcat("Current physics set: ^3", CS_CVAR(caller).cvar_cl_physics, "\n"));
case CMD_REQUEST_USAGE:
{
sprint(caller, "\nUsage:^3 cmd physics <physics>\n");
{
if (IS_CLIENT(caller))
{
- if (warmup_stage || sv_ready_restart || g_race_qualifying == 2)
+ if (warmup_stage || autocvar_sv_ready_restart || g_race_qualifying == 2)
{
- if (!readyrestart_happened || sv_ready_restart_repeatable)
+ if (!readyrestart_happened || autocvar_sv_ready_restart_repeatable)
{
if (time < game_starttime) // game is already restarting
return;
{
caller.ready = false;
if(IS_PLAYER(caller) || caller.caplayer == 1)
- bprint(playername(caller, false), "^2 is ^1NOT^2 ready\n");
+ bprint(playername(caller.netname, caller.team, false), "^2 is ^1NOT^2 ready\n");
}
else
{
caller.ready = true;
if(IS_PLAYER(caller) || caller.caplayer == 1)
- bprint(playername(caller, false), "^2 is ready\n");
+ bprint(playername(caller.netname, caller.team, false), "^2 is ready\n");
}
// cannot reset the game while a timeout is active!
case CMD_REQUEST_USAGE:
{
sprint(caller, "\nUsage:^3 cmd say <message>\n");
- sprint(caller, " Where 'message' is the string of text to say.\n");
+ sprint(caller, " Where <message> is the string of text to say.\n");
return;
}
}
case CMD_REQUEST_USAGE:
{
sprint(caller, "\nUsage:^3 cmd say_team <message>\n");
- sprint(caller, " Where 'message' is the string of text to say.\n");
+ sprint(caller, " Where <message> is the string of text to say.\n");
return;
}
}
sprint(caller, "^7The game has already begun, you must wait until the next map to be able to join a team.\n");
return;
}
- float selection;
- switch (argv(1))
- {
- case "red":
- {
- selection = NUM_TEAM_1;
- break;
- }
- case "blue":
- {
- selection = NUM_TEAM_2;
- break;
- }
- case "yellow":
- {
- selection = NUM_TEAM_3;
- break;
- }
- case "pink":
- {
- selection = NUM_TEAM_4;
- break;
- }
- case "auto":
- {
- selection = (-1);
- break;
- }
- default:
- {
- return;
- }
- }
- if (caller.team == selection && selection != -1 && !IS_DEAD(caller))
+
+ float team_num = Team_ColorToTeam(argv(1));
+ if (team_num == -1) // invalid
+ return;
+ if (caller.team == team_num && team_num && !IS_DEAD(caller))
{
sprint(caller, "^7You already are on that team.\n");
return;
sprint(caller, "^1You cannot change team, forbidden by the server.\n");
return;
}
- if ((selection != -1) && autocvar_g_balance_teams &&
- autocvar_g_balance_teams_prevent_imbalance)
+ if (team_num && autocvar_g_balance_teams && autocvar_g_balance_teams_prevent_imbalance)
{
entity balance = TeamBalance_CheckAllowedTeams(caller);
TeamBalance_GetTeamCounts(balance, caller);
- if ((Team_IndexToBit(Team_TeamToIndex(selection)) &
+ if ((Team_IndexToBit(Team_TeamToIndex(team_num)) &
TeamBalance_FindBestTeams(balance, caller, false)) == 0)
{
Send_Notification(NOTIF_ONE, caller, MSG_INFO, INFO_TEAMCHANGE_LARGERTEAM);
}
TeamBalance_Destroy(balance);
}
- ClientKill_TeamChange(caller, selection);
+ if (team_num)
+ ClientKill_TeamChange(caller, team_num);
+ else // auto
+ ClientKill_TeamChange(caller, -1);
+
if (!IS_PLAYER(caller))
{
caller.team_selected = true; // avoids asking again for team selection on join
return;
}
default:
- sprint(caller, "Incorrect parameters for ^2selectteam^7\n");
+ sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
case CMD_REQUEST_USAGE:
{
- sprint(caller, "\nUsage:^3 cmd selectteam team\n");
- sprint(caller, " Where 'team' is the prefered team to try and join.\n");
- sprint(caller, " Full list of options here: \"red, blue, yellow, pink, auto\"\n");
+ sprint(caller, "\nUsage:^3 cmd selectteam <team>\n");
+ sprint(caller, " Where <team> is the prefered team to try and join.\n");
+ sprint(caller, " Full list of options here: red, blue, yellow, pink, auto.\n");
return;
}
}
}
default:
- sprint(caller, "Incorrect parameters for ^2selfstuff^7\n");
+ sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
case CMD_REQUEST_USAGE:
{
sprint(caller, "\nUsage:^3 cmd selfstuff <command>\n");
- sprint(caller, " Where 'command' is the string to be stuffed to your client.\n");
+ sprint(caller, " Where <command> is the string to be stuffed to your client.\n");
return;
}
}
}
-void ClientCommand_sentcvar(entity caller, int request, int argc, string command)
+void ClientCommand_sentcvar(entity caller, int request, int argc)
{
switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if (argv(1) != "")
+ if (argc >= 3)
{
- // float tokens;
- string s;
-
+ // NOTE: client-side settings do not exist on the server, this functionality has been deprecated
+ #if 0
if (argc == 2) // undefined cvar: use the default value on the server then
{
- s = strcat(substring(command, argv_start_index(0), argv_end_index(1) - argv_start_index(0)), " \"", cvar_defstring(argv(1)), "\"");
+ string s = strcat(substring(command, argv_start_index(0), argv_end_index(1) - argv_start_index(0)), " \"", cvar_defstring(argv(1)), "\"");
tokenize_console(s);
}
+ #endif
- GetCvars(caller, CS(caller), 1);
+ GetCvars(caller, CS_CVAR(caller), 1);
return;
}
}
default:
- sprint(caller, "Incorrect parameters for ^2sentcvar^7\n");
+ sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
case CMD_REQUEST_USAGE:
{
- sprint(caller, "\nUsage:^3 cmd sentcvar <cvar>\n");
- sprint(caller, " Where 'cvar' is the cvar plus arguments to send to the server.\n");
+ sprint(caller, "\nUsage:^3 cmd sentcvar <cvar> <arguments>\n");
+ sprint(caller, " Where <cvar> is the cvar plus arguments to send to the server.\n");
return;
}
}
{
if (!intermission_running && IS_CLIENT(caller))
{
- if((IS_SPEC(caller) || IS_OBSERVER(caller)) && argv(1) != "")
+ if(argv(1) != "")
{
- entity client = GetFilteredEntity(argv(1));
- int spec_accepted = VerifyClientEntity(client, false, false);
- if(spec_accepted > 0 && IS_PLAYER(client))
+ if(IS_SPEC(caller) || IS_OBSERVER(caller))
{
- if(Spectate(caller, client))
- return; // fall back to regular handling
+ entity client = GetFilteredEntity(argv(1));
+ int spec_accepted = VerifyClientEntity(client, false, false);
+ if(spec_accepted > 0 && IS_PLAYER(client))
+ {
+ bool caller_is_observer = (IS_OBSERVER(caller));
+ Spectate(caller, client);
+ if (caller_is_observer)
+ TRANSMUTE(Spectator, caller);
+ }
+ else
+ sprint(caller, "Can't spectate ", argv(1), "^7\n");
}
+ else
+ sprint(caller, "cmd spectate <client> only works when you are spectator/observer\n");
+ return;
}
int mutator_returnvalue = MUTATOR_CALLHOOK(ClientCommand_Spectate, caller);
default:
case CMD_REQUEST_USAGE:
{
- sprint(caller, "\nUsage:^3 cmd spectate <client>\n");
- sprint(caller, " Where 'client' can be the player to spectate.\n");
+ sprint(caller, "\nUsage:^3 cmd spectate [<client>]\n");
+ sprint(caller, " Where <client> can be the player to spectate.\n");
return;
}
}
}
default:
- sprint(caller, "Incorrect parameters for ^2suggestmap^7\n");
+ sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
case CMD_REQUEST_USAGE:
{
- sprint(caller, "\nUsage:^3 cmd suggestmap map\n");
- sprint(caller, " Where 'map' is the name of the map to suggest.\n");
+ sprint(caller, "\nUsage:^3 cmd suggestmap <map>\n");
+ sprint(caller, " Where <map> is the name of the map to suggest.\n");
return;
}
}
}
default:
- sprint(caller, "Incorrect parameters for ^2tell^7\n");
+ sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
case CMD_REQUEST_USAGE:
{
- sprint(caller, "\nUsage:^3 cmd tell client <message>\n");
- sprint(caller, " Where 'client' is the entity number or name of the player to send 'message' to.\n");
+ sprint(caller, "\nUsage:^3 cmd tell <client> <message>\n");
+ sprint(caller, " Where <client> is the entity number or name of the player to send <message> to.\n");
return;
}
}
sprint(caller, sprintf("Invalid voice. Use one of: %s\n", allvoicesamples));
return;
}
+ if (IS_DEAD(caller))
+ {
+ // don't warn the caller when trying to taunt while dead, just don't play any sounds!
+ // we still allow them to see warnings if it's invalid, so a dead player can find out the sounds in peace
+ return;
+ }
+ if (IS_SPEC(caller) || IS_OBSERVER(caller))
+ {
+ // observers/spectators have no player model of their own to play taunts from
+ // again, allow them to see warnings
+ return;
+ }
string msg = "";
if (argc >= 3)
msg = substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2));
}
default:
- sprint(caller, "Incorrect parameters for ^2voice^7\n");
+ sprint(caller, sprintf("Incorrect parameters for ^2%s^7\n", argv(0)));
case CMD_REQUEST_USAGE:
{
- sprint(caller, "\nUsage:^3 cmd voice messagetype <soundname>\n");
- sprint(caller, " 'messagetype' is the type of broadcast to do, like team only or such,\n");
- sprint(caller, " and 'soundname' is the string/filename of the sound/voice message to play.\n");
+ sprint(caller, "\nUsage:^3 cmd voice <voicetype> [<message>]\n");
+ sprint(caller, " <voicetype> is the type of voice message, it can be one of these:\n");
+ sprint(caller, sprintf(" %s\n", allvoicesamples));
+ sprint(caller, " and <message> is the text message to send.\n");
return;
}
}
CLIENT_COMMAND("say_team", ClientCommand_say_team(ent, request, arguments, command), "Print a message to chat to all team mates") \
CLIENT_COMMAND("selectteam", ClientCommand_selectteam(ent, request, arguments), "Attempt to choose a team to join into") \
CLIENT_COMMAND("selfstuff", ClientCommand_selfstuff(ent, request, command), "Stuffcmd a command to your own client") \
- CLIENT_COMMAND("sentcvar", ClientCommand_sentcvar(ent, request, arguments, command), "New system for sending a client cvar to the server") \
+ CLIENT_COMMAND("sentcvar", ClientCommand_sentcvar(ent, request, arguments), "New system for sending a client cvar to the server") \
CLIENT_COMMAND("spectate", ClientCommand_spectate(ent, request), "Become an observer") \
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") \
case "prespawn": break; // handled by engine in host_cmd.c
case "sentcvar": break; // handled by server in this file
case "spawn": break; // handled by engine in host_cmd.c
+ case "color": case "topcolor": case "bottomcolor": // handled by engine in host_cmd.c
+ if(!IS_CLIENT(this)) // on connection
+ {
+ // since gamecode doesn't have any calls earlier than this, do the connecting message here
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_CONNECTING, this.netname);
+ }
+ if(teamplay)
+ return;
+ break;
case "c2s": Net_ClientCommand(this, command); return; // handled by net.qh
default:
sprint(this, "\nCommon networked commands:\n");
CommonCommand_macro_help(this);
- sprint(this, "\nUsage:^3 cmd COMMAND...^7, where possible commands are listed above.\n");
- sprint(this, "For help about a specific command, type cmd help COMMAND\n");
+ sprint(this, "\nUsage:^3 cmd <command>^7, where possible commands are listed above.\n");
+ sprint(this, "For help about a specific command, type cmd help <command>\n");
return;
}
else if (CommonCommand_macro_usage(argc, this)) // Instead of trying to call a command, we're going to see detailed information about it