/* Relay -- a tool to record and play Quake2 demos Copyright (C) 2000 Conor Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Conor Davis cedavis@planetquake.com */ #include #include "sv_local.h" // // CLIENT COMMANDS // void clcmd_use(client_t *client) { const char *s; int index, i; menu_t *menu; s = Cmd_Args(); index = 0; if (!Q_stricmp(s, "Blaster")) index = 1; else if (!Q_stricmp(s, "Shotgun")) index = 2; else if (!Q_stricmp(s, "Super Shotgun")) index = 3; else if (!Q_stricmp(s, "Machinegun")) index = 4; else if (!Q_stricmp(s, "Chaingun")) index = 5; else if (!Q_stricmp(s, "Grenade Launcher")) index = 6; else if (!Q_stricmp(s, "Rocket Launcher")) index = 7; else if (!Q_stricmp(s, "Hyperblaster")) index = 8; else if (!Q_stricmp(s, "Railgun")) index = 9; else if (!Q_stricmp(s, "BFG10K")) index = 10; if (!index) return; menu = client->curmenu; if (menu) { for (i = 0; i < 10; i++) { if (menu->top + i >= menu->num) return; if (menu->items[i].Select) { index--; if (!index) { menu->cur = menu->top + i; UpdateLayout(client); Menu_Select(client->curmenu, 0); } } } return; } if (index == 10) CL_ChangePlayer(client, -1); else { if (CL_ChangePlayer(client, index - 1) == 0) CL_cprintf(&client->unreliable, PRINT_HIGH, "Tracking player %d\n", index); else CL_cprintf(&client->unreliable, PRINT_HIGH, "%d is not a valid player\n", index); } } void ClientCommand(client_t *client) { const char *cmd; cmd = Cmd_Argv(0); if (!Q_stricmp(cmd, "player")) { CL_ChangePlayer(client, atoi(Cmd_Argv(1) - 1)); return; } if (!Q_stricmp(cmd, "lockpos")) { client->flags ^= RC_LOCKPOS; CL_cprintf(&client->unreliable, PRINT_MEDIUM, "Lockpos %s\n", (client->flags & RC_LOCKPOS ? "on" : "off")); return; } if (!Q_stricmp(cmd, "lockview")) { client->flags ^= RC_LOCKVIEW; client->ps.viewangles[ROLL] = 0; CL_cprintf(&client->unreliable, PRINT_MEDIUM, "Lockview %s\n", (client->flags & RC_LOCKVIEW ? "on" : "off")); return; } if (!Q_stricmp(cmd, "chaseview")) { client->flags ^= RC_CHASEVIEW; CL_cprintf(&client->unreliable, PRINT_MEDIUM, "Chaseview %s\n", (client->flags & RC_CHASEVIEW ? "on" : "off")); return; } if (!Q_stricmp(cmd, "statusbar")) { client->flags ^= RC_STATUSBAR; WriteByte(&client->nextreliable, SVC_CONFIGSTRING); DM2_WriteConfigstring(&client->nextreliable, CS_STATUSBAR, (client->flags & RC_STATUSBAR ? dm2in.configstrings[CS_STATUSBAR] : "")); return; } if (!Q_stricmp(cmd, "use")) { clcmd_use(client); return; } if (!Q_stricmp(cmd, "inven")) { if (client->curmenu) CloseAllMenus(client); else OpenMenu(client, MainMenu_Show); return; } if (!Q_stricmp(cmd, "invprev")) { if (client->curmenu) { Menu_Prev(client->curmenu); UpdateLayout(client); } return; } if (!Q_stricmp(cmd, "invnext")) { if (client->curmenu) { Menu_Next(client->curmenu); UpdateLayout(client); } return; } if (!Q_stricmp(cmd, "invuse")) { if (client->curmenu) Menu_Select(client->curmenu, 0); return; } if (!Q_stricmp(cmd, "invdrop")) { if (client->curmenu) CloseMenu(client); return; } if (!Q_stricmp(cmd, "putaway")) { CloseAllMenus(client); return; } CL_cprintf(&client->unreliable, PRINT_MEDIUM, "Unknown command: %s\n", cmd); } void CL_StringCommand(client_t *client) { const char *cmd; int i; char buf[64]; if (Cmd_Argc() == 0) return; cmd = Cmd_Argv(0); if (!strcmp(cmd, "disconnect")) { ClientDisconnect(client); return; } switch (client->status) { case CL_UNCONNECTED: break; case CL_CONNECTING: if (!strcmp(cmd, "new")) { serverdata_t svd; if (Cmd_Argc() != 1) return; svd = dm2in.svd; svd.version = client->protocol; svd.isdemo = RECORD_NETWORK; svd.player = -1; client->status = CL_CONFIGSTRINGS; WriteByte(&client->nextreliable, SVC_SERVERDATA); DM2_WriteServerdata(&client->nextreliable, &svd); i = DM2_WriteConfigstrings(&client->nextreliable, dm2in.configstrings, 0, 1024); if (i == MAX_CONFIGSTRINGS) { WriteByte(&client->nextreliable, SVC_STUFFTEXT); DM2_WriteStufftext(&client->nextreliable, "cmd baselines 0\n"); client->status = CL_BASELINES; } else { sprintf(buf, "cmd configstrings %d\n", i); WriteByte(&client->nextreliable, SVC_STUFFTEXT); DM2_WriteStufftext(&client->nextreliable, buf); } return; } break; case CL_CONFIGSTRINGS: if (!strcmp(cmd, "configstrings")) { if (Cmd_Argc() != 2) return; i = DM2_WriteConfigstrings(&client->nextreliable, dm2in.configstrings, atoi(Cmd_Argv(1)), 1024); if (i == MAX_CONFIGSTRINGS) { WriteByte(&client->nextreliable, SVC_STUFFTEXT); DM2_WriteStufftext(&client->nextreliable, "cmd baselines 0\n"); client->status = CL_BASELINES; } else { sprintf(buf, "cmd configstrings %d\n", i); WriteByte(&client->nextreliable, SVC_STUFFTEXT); DM2_WriteStufftext(&client->nextreliable, buf); } return; } break; case CL_BASELINES: if (!strcmp(cmd, "baselines")) { if (Cmd_Argc() != 2) return; i = DM2_WriteBaselines(&client->nextreliable, &dm2in.baselines, atoi(Cmd_Argv(1)), 1024); if (i == MAX_EDICTS) { WriteByte(&client->nextreliable, SVC_STUFFTEXT); DM2_WriteStufftext(&client->nextreliable, "precache;cmd begin\n"); client->status = CL_PRECACHING; } else { sprintf(buf, "cmd baselines %d\n", i); WriteByte(&client->nextreliable, SVC_STUFFTEXT); DM2_WriteStufftext(&client->nextreliable, buf); } return; } break; case CL_PRECACHING: if (!strcmp(cmd, "begin")) { if (Cmd_Argc() != 1) return; client->status = CL_CONNECTED; ClientBegin(client); return; } case CL_CONNECTED: ClientCommand(client); return; } } // // CONNECTIONLESS COMMANDS // static client_t *FindFreeClient(struct sockaddr_in *addr) { int i; client_t *client, *ret; ret = NULL; for (i = 0, client = server.clients; i < server.maxclients; i++, client++) { if (!UDP_AddrCompare(addr, &client->net.addr)) return client; if (!ret && client->status == CL_UNCONNECTED) ret = client; } return ret; } void ConnectionlessCommand(struct sockaddr_in *addr) { const char *cmd; if (Cmd_Argc() == 0) return; cmd = Cmd_Argv(0); if (!strcmp(cmd, "status")) { if (Cmd_Argc() != 1) return; return; } if (!strcmp(cmd, "getchallenge")) { int id; char buf[64]; if (Cmd_Argc() != 1) return; if (server.numclients == server.maxclients) { UDP_SendConnectionless(server.socket, "print Server is full.\n", 22, addr); return; } id = NewChallenge(addr); sprintf(buf, "challenge %d\n", id); UDP_SendConnectionless(server.socket, buf, strlen(buf), addr); return; } if (!strcmp(cmd, "connect")) { client_t *client; if (Cmd_Argc() != 5) return; if (!FindChallenge(addr, atoi(Cmd_Argv(3)))) return; if (server.numclients == server.maxclients || (client = FindFreeClient(addr)) == NULL) { UDP_SendConnectionless(server.socket, "print Server is full.\n", 22, addr); return; } InitClient(client); client->status = CL_CONNECTING; client->protocol = atoi(Cmd_Argv(1)); client->net.qport = atoi(Cmd_Argv(2)); client->net.addr = *addr; client->timeout_time = mstime() + 30000; if (!ClientConnect(client, Cmd_Argv(4))) { InitClient(client); return; } UDP_SendConnectionless(server.socket, "client_connect\n", 15, addr); return; } }