X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=cmd.c;h=3526e079d688d9359c607595e5582e18feaf3224;hb=8eeb21d2f785d320e47d7133c2624774e742ab6a;hp=504a88d5a2bc30ecca50a0fe4053a3ffb073b850;hpb=cd7454f9df6b152a24c5a28750041d27023fbc1f;p=xonotic%2Fdarkplaces.git diff --git a/cmd.c b/cmd.c index 504a88d5..3526e079 100644 --- a/cmd.c +++ b/cmd.c @@ -216,7 +216,7 @@ qboolean host_stuffcmdsrun = false; void Cmd_StuffCmds_f (void) { int i, j, l; - // this is per command, and bounds checked (no buffer overflows) + // this is for all commandline options combined (and is bounds checked) char build[MAX_INPUTLINE]; if (Cmd_Argc () != 1) @@ -225,12 +225,17 @@ void Cmd_StuffCmds_f (void) return; } + // no reason to run the commandline arguments twice + if (host_stuffcmdsrun) + return; + host_stuffcmdsrun = true; + build[0] = 0; + l = 0; for (i = 0;i < com_argc;i++) { - if (com_argv[i] && com_argv[i][0] == '+' && (com_argv[i][1] < '0' || com_argv[i][1] > '9')) + if (com_argv[i] && com_argv[i][0] == '+' && (com_argv[i][1] < '0' || com_argv[i][1] > '9') && l + strlen(com_argv[i]) - 1 <= sizeof(build) - 1) { - l = 0; j = 1; while (com_argv[i][j]) build[l++] = com_argv[i][j++]; @@ -241,20 +246,24 @@ void Cmd_StuffCmds_f (void) continue; if ((com_argv[i][0] == '+' || com_argv[i][0] == '-') && (com_argv[i][1] < '0' || com_argv[i][1] > '9')) break; - if (l + strlen(com_argv[i]) + 5 > sizeof(build)) + if (l + strlen(com_argv[i]) + 4 > sizeof(build) - 1) break; build[l++] = ' '; - build[l++] = '\"'; + if (strchr(com_argv[i], ' ')) + build[l++] = '\"'; for (j = 0;com_argv[i][j];j++) build[l++] = com_argv[i][j]; - build[l++] = '\"'; + if (strchr(com_argv[i], ' ')) + build[l++] = '\"'; } build[l++] = '\n'; - build[l++] = 0; - Cbuf_InsertText (build); i--; } } + // now terminate the combined string and prepend it to the command buffer + // we already reserved space for the terminator + build[l++] = 0; + Cbuf_InsertText (build); } @@ -287,6 +296,9 @@ static void Cmd_Exec_f (void) if (!strcmp(Cmd_Argv(1), "default.cfg")) Cbuf_InsertText("\ncvar_lockdefaults\n"); + // insert newline after the text to make sure the last line is terminated (some text editors omit the trailing newline) + // (note: insertion order here is backwards from execution order, so this adds it after the text, by calling it before...) + Cbuf_InsertText ("\n"); Cbuf_InsertText (f); Mem_Free(f); } @@ -308,6 +320,25 @@ static void Cmd_Echo_f (void) Con_Print("\n"); } +// DRESK - 4/24/07 +/* +=============== +Cmd_ModelIndexList_f + +List all models in the model index +=============== +*/ +static void Cmd_ModelIndexList_f(void) +{ + int nModelIndexCnt = 3; + + while(cl.model_precache[nModelIndexCnt]) + { // Valid Model + Con_Printf("%i : %s\n", nModelIndexCnt, cl.model_precache[nModelIndexCnt]->name); + nModelIndexCnt++; + } +} + // DRESK - 5/14/06 // Support Doom3-style Toggle Console Command /* @@ -475,7 +506,8 @@ typedef struct cmd_function_s struct cmd_function_s *next; const char *name; const char *description; - xcommand_t function; + xcommand_t consolefunction; + xcommand_t clientfunction; qboolean csqcfunc; } cmd_function_t; @@ -678,6 +710,8 @@ void Cmd_Init_Commands (void) // DRESK - 5/14/06 // Support Doom3-style Toggle Command Cmd_AddCommand( "toggle", Cmd_Toggle_f, "toggles a console variable's values (use for more info)"); + // Add Model Index List Command + Cmd_AddCommand("modelindexlist", Cmd_ModelIndexList_f, "lists all models in the modelindex"); } /* @@ -788,7 +822,7 @@ static void Cmd_TokenizeString (const char *text) Cmd_AddCommand ============ */ -void Cmd_AddCommand (const char *cmd_name, xcommand_t function, const char *description) +void Cmd_AddCommand_WithClientCommand (const char *cmd_name, xcommand_t consolefunction, xcommand_t clientfunction, const char *description) { cmd_function_t *cmd; cmd_function_t *prev, *current; @@ -805,7 +839,7 @@ void Cmd_AddCommand (const char *cmd_name, xcommand_t function, const char *desc { if (!strcmp (cmd_name, cmd->name)) { - if (function) + if (consolefunction || clientfunction) { Con_Printf("Cmd_AddCommand: %s already defined\n", cmd_name); return; @@ -820,9 +854,10 @@ void Cmd_AddCommand (const char *cmd_name, xcommand_t function, const char *desc cmd = (cmd_function_t *)Mem_Alloc(cmd_mempool, sizeof(cmd_function_t)); cmd->name = cmd_name; - cmd->function = function; + cmd->consolefunction = consolefunction; + cmd->clientfunction = clientfunction; cmd->description = description; - if(!function) //[515]: csqc + if(!consolefunction && !clientfunction) //[515]: csqc cmd->csqcfunc = true; cmd->next = cmd_functions; @@ -837,6 +872,11 @@ void Cmd_AddCommand (const char *cmd_name, xcommand_t function, const char *desc cmd->next = current; } +void Cmd_AddCommand (const char *cmd_name, xcommand_t function, const char *description) +{ + Cmd_AddCommand_WithClientCommand (cmd_name, function, NULL, description); +} + /* ============ Cmd_Exists @@ -1081,19 +1121,47 @@ void Cmd_ExecuteString (const char *text, cmd_source_t src) { if (!strcasecmp (cmd_argv[0],cmd->name)) { - if(cmd->function && !cmd->csqcfunc) - cmd->function (); - else - if(CL_VM_ConsoleCommand (text)) //[515]: csqc - return; + if (cmd->csqcfunc && CL_VM_ConsoleCommand (text)) //[515]: csqc + return; + switch (src) + { + case src_command: + if (cmd->consolefunction) + cmd->consolefunction (); + else if (cmd->clientfunction) + { + if (cls.state == ca_connected) + { + // forward remote commands to the server for execution + Cmd_ForwardToServer(); + } + else + Con_Printf("Can not send command \"%s\", not connected.\n", Cmd_Argv(0)); + } else - if(cmd->function) - cmd->function (); - cmd_tokenizebufferpos = oldpos; - return; + Con_Printf("Command \"%s\" can not be executed\n", Cmd_Argv(0)); + cmd_tokenizebufferpos = oldpos; + return; + case src_client: + if (cmd->clientfunction) + { + cmd->clientfunction (); + cmd_tokenizebufferpos = oldpos; + return; + } + break; + } + break; } } + // if it's a client command and no command was found, say so. + if (cmd_source == src_client) + { + Con_Printf("player \"%s\" tried to %s\n", host_client->name, text); + return; + } + // check alias for (a=cmd_alias ; a ; a=a->next) { @@ -1122,6 +1190,7 @@ Sends an entire command string over to the server, unprocessed */ void Cmd_ForwardStringToServer (const char *s) { + char temp[128]; if (cls.state != ca_connected) { Con_Printf("Can't \"%s\", not connected\n", s); @@ -1138,7 +1207,105 @@ void Cmd_ForwardStringToServer (const char *s) MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd); else MSG_WriteByte(&cls.netcon->message, clc_stringcmd); - SZ_Write(&cls.netcon->message, (const unsigned char *)s, (int)strlen(s) + 1); + if ((!strncmp(s, "say ", 4) || !strncmp(s, "say_team ", 9)) && cl_locs_enable.integer) + { + // say/say_team commands can replace % character codes with status info + while (*s) + { + if (*s == '%' && s[1]) + { + // handle proquake message macros + temp[0] = 0; + switch (s[1]) + { + case 'l': // current location + CL_Locs_FindLocationName(temp, sizeof(temp), cl.movement_origin); + break; + case 'h': // current health + dpsnprintf(temp, sizeof(temp), "%i", cl.stats[STAT_HEALTH]); + break; + case 'a': // current armor + dpsnprintf(temp, sizeof(temp), "%i", cl.stats[STAT_ARMOR]); + break; + case 'x': // current rockets + dpsnprintf(temp, sizeof(temp), "%i", cl.stats[STAT_ROCKETS]); + break; + case 'c': // current cells + dpsnprintf(temp, sizeof(temp), "%i", cl.stats[STAT_CELLS]); + break; + // silly proquake macros + case 'd': // loc at last death + CL_Locs_FindLocationName(temp, sizeof(temp), cl.lastdeathorigin); + break; + case 't': // current time + dpsnprintf(temp, sizeof(temp), "%.0f:%.0f", floor(cl.time / 60), cl.time - floor(cl.time / 60) * 60); + break; + case 'r': // rocket launcher status ("I have RL", "I need rockets", "I need RL") + if (!(cl.stats[STAT_ITEMS] & IT_ROCKET_LAUNCHER)) + dpsnprintf(temp, sizeof(temp), "I need RL"); + else if (!cl.stats[STAT_ROCKETS]) + dpsnprintf(temp, sizeof(temp), "I need rockets"); + else + dpsnprintf(temp, sizeof(temp), "I have RL"); + break; + case 'p': // powerup status (outputs "quad" "pent" and "eyes" according to status) + if (cl.stats[STAT_ITEMS] & IT_QUAD) + { + if (temp[0]) + strlcat(temp, " ", sizeof(temp)); + strlcat(temp, "quad", sizeof(temp)); + } + if (cl.stats[STAT_ITEMS] & IT_INVULNERABILITY) + { + if (temp[0]) + strlcat(temp, " ", sizeof(temp)); + strlcat(temp, "pent", sizeof(temp)); + } + if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY) + { + if (temp[0]) + strlcat(temp, " ", sizeof(temp)); + strlcat(temp, "eyes", sizeof(temp)); + } + break; + case 'w': // weapon status (outputs "SSG:NG:SNG:GL:RL:LG" with the text between : characters omitted if you lack the weapon) + if (cl.stats[STAT_ITEMS] & IT_SUPER_SHOTGUN) + strlcat(temp, "SSG", sizeof(temp)); + strlcat(temp, ":", sizeof(temp)); + if (cl.stats[STAT_ITEMS] & IT_NAILGUN) + strlcat(temp, "NG", sizeof(temp)); + strlcat(temp, ":", sizeof(temp)); + if (cl.stats[STAT_ITEMS] & IT_SUPER_NAILGUN) + strlcat(temp, "SNG", sizeof(temp)); + strlcat(temp, ":", sizeof(temp)); + if (cl.stats[STAT_ITEMS] & IT_GRENADE_LAUNCHER) + strlcat(temp, "GL", sizeof(temp)); + strlcat(temp, ":", sizeof(temp)); + if (cl.stats[STAT_ITEMS] & IT_ROCKET_LAUNCHER) + strlcat(temp, "RL", sizeof(temp)); + strlcat(temp, ":", sizeof(temp)); + if (cl.stats[STAT_ITEMS] & IT_LIGHTNING) + strlcat(temp, "LG", sizeof(temp)); + break; + default: + // not a recognized macro, print it as-is... + temp[0] = s[0]; + temp[1] = s[1]; + temp[2] = 0; + break; + } + // write the resulting text + SZ_Write(&cls.netcon->message, (unsigned char *)temp, strlen(temp)); + s += 2; + continue; + } + MSG_WriteByte(&cls.netcon->message, *s); + s++; + } + MSG_WriteByte(&cls.netcon->message, 0); + } + else // any other command is passed on as-is + SZ_Write(&cls.netcon->message, (const unsigned char *)s, (int)strlen(s) + 1); } /*