]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_ccmds.c
Rename q3shaderinfo_t to shader_t, to be in line with other engines
[xonotic/darkplaces.git] / sv_ccmds.c
index 2ed5540559e0add6d2eb03db445bd04ab5dce19e..cf70e6dc095e17d8a082087138c4645a206689a8 100644 (file)
@@ -18,8 +18,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 */
 
-#include <quakedef.h>
-#include <server.h>
+#include "quakedef.h"
+#include "utf8lib.h"
+#include "server.h"
+#include "sv_demo.h"
 
 int current_skill;
 cvar_t sv_cheats = {CVAR_SERVER | CVAR_NOTIFY, "sv_cheats", "0", "enables cheat commands in any game, and cheat impulses in dpmod"};
@@ -102,9 +104,10 @@ static void SV_Changelevel_f(cmd_state_t *cmd)
                Con_Print("changelevel <levelname> : continue game on a new level\n");
                return;
        }
-       // HACKHACKHACK
-       if (!sv.active) {
-               SV_Map_f(cmd);
+
+       if (!sv.active)
+       {
+               Con_Printf("You must be running a server to changelevel. Use 'map %s' instead\n", Cmd_Argv(cmd, 1));
                return;
        }
 
@@ -160,12 +163,12 @@ static void SV_Restart_f(cmd_state_t *cmd)
 //===========================================================================
 
 // Disable cheats if sv_cheats is turned off
-static void SV_DisableCheats_c(char *value)
+static void SV_DisableCheats_c(cvar_t *var)
 {
        prvm_prog_t *prog = SVVM_prog;
        int i = 0;
 
-       if (value[0] == '0' && !value[1])
+       if (var->value == 0)
        {
                while (svs.clients[i].edict)
                {
@@ -410,7 +413,7 @@ static void SV_Pause_f(cmd_state_t *cmd)
                // if running a client, try to send over network so the pause is handled by the server
                if (cls.state == ca_connected)
                {
-                       Cmd_ForwardToServer_f(cmd);
+                       CL_ForwardToServer_f(cmd);
                        return;
                }
                print = Con_Printf;
@@ -462,7 +465,7 @@ static void SV_Say(cmd_state_t *cmd, qboolean teamonly)
                }
                else
                {
-                       Cmd_ForwardToServer_f(cmd);
+                       CL_ForwardToServer_f(cmd);
                        return;
                }
        }
@@ -537,7 +540,7 @@ static void SV_Tell_f(cmd_state_t *cmd)
                        fromServer = true;
                else
                {
-                       Cmd_ForwardToServer_f(cmd);
+                       CL_ForwardToServer_f(cmd);
                        return;
                }
        }
@@ -665,7 +668,7 @@ static void SV_Ping_f(cmd_state_t *cmd)
                // if running a client, try to send over network so the client's ping report parser will see the report
                if (cls.state == ca_connected)
                {
-                       Cmd_ForwardToServer_f(cmd);
+                       CL_ForwardToServer_f(cmd);
                        return;
                }
                print = Con_Printf;
@@ -827,7 +830,7 @@ static void SV_Status_f(cmd_state_t *cmd)
                // if running a client, try to send over network so the client's status report parser will see the report
                if (cls.state == ca_connected)
                {
-                       Cmd_ForwardToServer_f(cmd);
+                       CL_ForwardToServer_f(cmd);
                        return;
                }
                print = Con_Printf;
@@ -943,6 +946,187 @@ static void SV_Status_f(cmd_state_t *cmd)
        }
 }
 
+/*
+======================
+SV_Name_f
+======================
+*/
+static void SV_Name_f(cmd_state_t *cmd)
+{
+       prvm_prog_t *prog = SVVM_prog;
+       int i, j;
+       qboolean valid_colors;
+       const char *newNameSource;
+       char newName[sizeof(host_client->name)];
+
+       if (Cmd_Argc (cmd) == 1)
+               return;
+
+       if (Cmd_Argc (cmd) == 2)
+               newNameSource = Cmd_Argv(cmd, 1);
+       else
+               newNameSource = Cmd_Args(cmd);
+
+       strlcpy(newName, newNameSource, sizeof(newName));
+
+       if (cmd->source == src_command)
+               return;
+
+       if (host.realtime < host_client->nametime && strcmp(newName, host_client->name))
+       {
+               SV_ClientPrintf("You can't change name more than once every %.1f seconds!\n", max(0.0f, sv_namechangetimer.value));
+               return;
+       }
+
+       host_client->nametime = host.realtime + max(0.0f, sv_namechangetimer.value);
+
+       // point the string back at updateclient->name to keep it safe
+       strlcpy (host_client->name, newName, sizeof (host_client->name));
+
+       for (i = 0, j = 0;host_client->name[i];i++)
+               if (host_client->name[i] != '\r' && host_client->name[i] != '\n')
+                       host_client->name[j++] = host_client->name[i];
+       host_client->name[j] = 0;
+
+       if(host_client->name[0] == 1 || host_client->name[0] == 2)
+       // may interfere with chat area, and will needlessly beep; so let's add a ^7
+       {
+               memmove(host_client->name + 2, host_client->name, sizeof(host_client->name) - 2);
+               host_client->name[sizeof(host_client->name) - 1] = 0;
+               host_client->name[0] = STRING_COLOR_TAG;
+               host_client->name[1] = '0' + STRING_COLOR_DEFAULT;
+       }
+
+       u8_COM_StringLengthNoColors(host_client->name, 0, &valid_colors);
+       if(!valid_colors) // NOTE: this also proves the string is not empty, as "" is a valid colored string
+       {
+               size_t l;
+               l = strlen(host_client->name);
+               if(l < sizeof(host_client->name) - 1)
+               {
+                       // duplicate the color tag to escape it
+                       host_client->name[i] = STRING_COLOR_TAG;
+                       host_client->name[i+1] = 0;
+                       //Con_DPrintf("abuse detected, adding another trailing color tag\n");
+               }
+               else
+               {
+                       // remove the last character to fix the color code
+                       host_client->name[l-1] = 0;
+                       //Con_DPrintf("abuse detected, removing a trailing color tag\n");
+               }
+       }
+
+       // find the last color tag offset and decide if we need to add a reset tag
+       for (i = 0, j = -1;host_client->name[i];i++)
+       {
+               if (host_client->name[i] == STRING_COLOR_TAG)
+               {
+                       if (host_client->name[i+1] >= '0' && host_client->name[i+1] <= '9')
+                       {
+                               j = i;
+                               // if this happens to be a reset  tag then we don't need one
+                               if (host_client->name[i+1] == '0' + STRING_COLOR_DEFAULT)
+                                       j = -1;
+                               i++;
+                               continue;
+                       }
+                       if (host_client->name[i+1] == STRING_COLOR_RGB_TAG_CHAR && isxdigit(host_client->name[i+2]) && isxdigit(host_client->name[i+3]) && isxdigit(host_client->name[i+4]))
+                       {
+                               j = i;
+                               i += 4;
+                               continue;
+                       }
+                       if (host_client->name[i+1] == STRING_COLOR_TAG)
+                       {
+                               i++;
+                               continue;
+                       }
+               }
+       }
+       // does not end in the default color string, so add it
+       if (j >= 0 && strlen(host_client->name) < sizeof(host_client->name) - 2)
+               memcpy(host_client->name + strlen(host_client->name), STRING_COLOR_DEFAULT_STR, strlen(STRING_COLOR_DEFAULT_STR) + 1);
+
+       PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name);
+       if (strcmp(host_client->old_name, host_client->name))
+       {
+               if (host_client->begun)
+                       SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name);
+               strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
+               // send notification to all clients
+               MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
+               MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
+               MSG_WriteString (&sv.reliable_datagram, host_client->name);
+               SV_WriteNetnameIntoDemo(host_client);
+       }
+}
+
+static void SV_Rate_f(cmd_state_t *cmd)
+{
+       int rate;
+
+       rate = atoi(Cmd_Argv(cmd, 1));
+
+       if (cmd->source == src_command)
+               return;
+
+       host_client->rate = rate;
+}
+
+static void SV_Rate_BurstSize_f(cmd_state_t *cmd)
+{
+       int rate_burstsize;
+
+       if (Cmd_Argc(cmd) != 2)
+               return;
+
+       rate_burstsize = atoi(Cmd_Argv(cmd, 1));
+
+       host_client->rate_burstsize = rate_burstsize;
+}
+
+static void SV_Color_f(cmd_state_t *cmd)
+{
+       prvm_prog_t *prog = SVVM_prog;
+
+       int top, bottom, playercolor;
+
+       top = atoi(Cmd_Argv(cmd, 1));
+       bottom = atoi(Cmd_Argv(cmd, 2));
+
+       top &= 15;
+       bottom &= 15;
+
+       playercolor = top*16 + bottom;
+
+       if (host_client->edict && PRVM_serverfunction(SV_ChangeTeam))
+       {
+               Con_DPrint("Calling SV_ChangeTeam\n");
+               prog->globals.fp[OFS_PARM0] = playercolor;
+               PRVM_serverglobalfloat(time) = sv.time;
+               PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
+               prog->ExecuteProgram(prog, PRVM_serverfunction(SV_ChangeTeam), "QC function SV_ChangeTeam is missing");
+       }
+       else
+       {
+               if (host_client->edict)
+               {
+                       PRVM_serveredictfloat(host_client->edict, clientcolors) = playercolor;
+                       PRVM_serveredictfloat(host_client->edict, team) = bottom + 1;
+               }
+               host_client->colors = playercolor;
+               if (host_client->old_colors != host_client->colors)
+               {
+                       host_client->old_colors = host_client->colors;
+                       // send notification to all clients
+                       MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
+                       MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
+                       MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
+               }
+       }
+}
+
 /*
 ==================
 SV_Kick_f
@@ -988,7 +1172,7 @@ static void SV_Kick_f(cmd_state_t *cmd)
                        if (cls.state == ca_dedicated)
                                who = "Console";
                        else
-                               who = name.string;
+                               who = cl_name.string;
                }
                else
                        who = save->name;
@@ -1048,6 +1232,120 @@ static void SV_MaxPlayers_f(cmd_state_t *cmd)
                Cvar_Set (&cvars_all, "deathmatch", "1");
 }
 
+/*
+======================
+SV_Playermodel_f
+======================
+*/
+// the old playermodel in cl_main has been renamed to __cl_playermodel
+static void SV_Playermodel_f(cmd_state_t *cmd)
+{
+       prvm_prog_t *prog = SVVM_prog;
+       int i, j;
+       char newPath[sizeof(host_client->playermodel)];
+
+       if (Cmd_Argc (cmd) == 1)
+               return;
+
+       if (Cmd_Argc (cmd) == 2)
+               strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
+       else
+               strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
+
+       for (i = 0, j = 0;newPath[i];i++)
+               if (newPath[i] != '\r' && newPath[i] != '\n')
+                       newPath[j++] = newPath[i];
+       newPath[j] = 0;
+
+       /*
+       if (host.realtime < host_client->nametime)
+       {
+               SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
+               return;
+       }
+
+       host_client->nametime = host.realtime + 5;
+       */
+
+       // point the string back at updateclient->name to keep it safe
+       strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel));
+       PRVM_serveredictstring(host_client->edict, playermodel) = PRVM_SetEngineString(prog, host_client->playermodel);
+       if (strcmp(host_client->old_model, host_client->playermodel))
+       {
+               strlcpy(host_client->old_model, host_client->playermodel, sizeof(host_client->old_model));
+               /*// send notification to all clients
+               MSG_WriteByte (&sv.reliable_datagram, svc_updatepmodel);
+               MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
+               MSG_WriteString (&sv.reliable_datagram, host_client->playermodel);*/
+       }
+}
+
+/*
+======================
+SV_Playerskin_f
+======================
+*/
+static void SV_Playerskin_f(cmd_state_t *cmd)
+{
+       prvm_prog_t *prog = SVVM_prog;
+       int i, j;
+       char newPath[sizeof(host_client->playerskin)];
+
+       if (Cmd_Argc (cmd) == 1)
+               return;
+
+       if (Cmd_Argc (cmd) == 2)
+               strlcpy (newPath, Cmd_Argv(cmd, 1), sizeof (newPath));
+       else
+               strlcpy (newPath, Cmd_Args(cmd), sizeof (newPath));
+
+       for (i = 0, j = 0;newPath[i];i++)
+               if (newPath[i] != '\r' && newPath[i] != '\n')
+                       newPath[j++] = newPath[i];
+       newPath[j] = 0;
+
+       /*
+       if (host.realtime < host_client->nametime)
+       {
+               SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
+               return;
+       }
+
+       host_client->nametime = host.realtime + 5;
+       */
+
+       // point the string back at updateclient->name to keep it safe
+       strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin));
+       PRVM_serveredictstring(host_client->edict, playerskin) = PRVM_SetEngineString(prog, host_client->playerskin);
+       if (strcmp(host_client->old_skin, host_client->playerskin))
+       {
+               //if (host_client->begun)
+               //      SV_BroadcastPrintf("%s changed skin to %s\n", host_client->name, host_client->playerskin);
+               strlcpy(host_client->old_skin, host_client->playerskin, sizeof(host_client->old_skin));
+               /*// send notification to all clients
+               MSG_WriteByte (&sv.reliable_datagram, svc_updatepskin);
+               MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);
+               MSG_WriteString (&sv.reliable_datagram, host_client->playerskin);*/
+       }
+}
+
+/*
+======================
+SV_PModel_f
+LadyHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
+LadyHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
+======================
+*/
+static void SV_PModel_f(cmd_state_t *cmd)
+{
+       prvm_prog_t *prog = SVVM_prog;
+
+       if (Cmd_Argc (cmd) == 1)
+               return;
+
+       PRVM_serveredictfloat(host_client->edict, pmodel) = atoi(Cmd_Argv(cmd, 1));
+}
+
 /*
 ===============================================================================
 
@@ -1189,6 +1487,34 @@ static void SV_Viewprev_f(cmd_state_t *cmd)
        }
 }
 
+static void SV_SendCvar_f(cmd_state_t *cmd)
+{
+       int i;  
+       const char *cvarname;
+       client_t *old;
+       
+       if(Cmd_Argc(cmd) != 2)
+               return;
+
+       if(!sv.active)// || !PRVM_serverfunction(SV_ParseClientCommand))
+               return;
+
+       cvarname = Cmd_Argv(cmd, 1);
+
+       old = host_client;
+       if (cls.state != ca_dedicated)
+               i = 1;
+       else
+               i = 0;
+       for(;i<svs.maxclients;i++)
+               if(svs.clients[i].active && svs.clients[i].netconnection)
+               {
+                       host_client = &svs.clients[i];
+                       SV_ClientCommands("sendcvar %s\n", cvarname);
+               }
+       host_client = old;
+}
+
 void SV_InitOperatorCommands(void)
 {
        Cvar_RegisterVariable(&sv_cheats);
@@ -1217,6 +1543,7 @@ void SV_InitOperatorCommands(void)
        Cmd_AddCommand(CMD_SHARED, "maxplayers", SV_MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once");
        Cmd_AddCommand(CMD_SHARED, "user", SV_User_f, "prints additional information about a player number or name on the scoreboard");
        Cmd_AddCommand(CMD_SHARED, "users", SV_Users_f, "prints additional information about all players on the scoreboard");
+       Cmd_AddCommand(CMD_SERVER, "sendcvar", SV_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC");
 
        // commands that do not have automatic forwarding from cmd_client, these are internal details of the network protocol and not of interest to users (if they know what they are doing they can still use a generic "cmd prespawn" or similar)
        Cmd_AddCommand(CMD_SERVER_FROM_CLIENT, "prespawn", SV_PreSpawn_f, "internal use - signon 1 (client acknowledges that server information has been received)");
@@ -1230,4 +1557,12 @@ void SV_InitOperatorCommands(void)
        Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "noclip", SV_Noclip_f, "noclip mode (flight without collisions, move through walls)");
        Cmd_AddCommand(CMD_CHEAT | CMD_SERVER_FROM_CLIENT, "give", SV_Give_f, "alter inventory");
        Cmd_AddCommand(CMD_SERVER_FROM_CLIENT, "kill", SV_Kill_f, "die instantly");
-}
\ No newline at end of file
+       
+       Cmd_AddCommand(CMD_USERINFO, "color", SV_Color_f, "change your player shirt and pants colors");
+       Cmd_AddCommand(CMD_USERINFO, "name", SV_Name_f, "change your player name");
+       Cmd_AddCommand(CMD_USERINFO, "rate", SV_Rate_f, "change your network connection speed");
+       Cmd_AddCommand(CMD_USERINFO, "rate_burstsize", SV_Rate_BurstSize_f, "change your network connection speed");
+       Cmd_AddCommand(CMD_USERINFO, "pmodel", SV_PModel_f, "(Nehahra-only) change your player model choice");
+       Cmd_AddCommand(CMD_USERINFO, "playermodel", SV_Playermodel_f, "change your player model");
+       Cmd_AddCommand(CMD_USERINFO, "playerskin", SV_Playerskin_f, "change your player skin number");  
+}