X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=host_cmd.c;h=dbd917dc66b7909b64caa62b4bb8c1b96ba1a89c;hb=daf428090715c897752063d21daac449a0d541b0;hp=97e45251e88e40b733e632997b26217054c855b1;hpb=c0e5e09cc36d7a225ff7f6b1ab2bfb278310168d;p=xonotic%2Fdarkplaces.git diff --git a/host_cmd.c b/host_cmd.c index 97e45251..dbd917dc 100644 --- a/host_cmd.c +++ b/host_cmd.c @@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" +#include "sv_demo.h" int current_skill; cvar_t sv_cheats = {0, "sv_cheats", "0", "enables cheat commands in any game, and cheat impulses in dpmod"}; @@ -30,6 +31,8 @@ cvar_t skin = {CVAR_USERINFO | CVAR_SAVE, "skin", "", "QW player skin name (exam cvar_t noaim = {CVAR_USERINFO | CVAR_SAVE, "noaim", "1", "QW option to disable vertical autoaim"}; qboolean allowcheats = false; +extern qboolean host_shuttingdown; + /* ================== Host_Quit_f @@ -38,10 +41,12 @@ Host_Quit_f void Host_Quit_f (void) { - Sys_Quit (); + if(host_shuttingdown) + Con_Printf("shutting down already!\n"); + else + Sys_Quit (0); } - /* ================== Host_Status_f @@ -76,6 +81,7 @@ void Host_Status_f (void) print ("version: %s build %s\n", gamename, buildstring); print ("protocol: %i (%s)\n", Protocol_NumberForEnum(sv.protocol), Protocol_NameForEnum(sv.protocol)); print ("map: %s\n", sv.name); + print ("timing: %s\n", Host_TimingReport()); print ("players: %i active (%i max)\n\n", players, svs.maxclients); for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++) { @@ -92,7 +98,7 @@ void Host_Status_f (void) } else hours = 0; - print ("#%-3u %-16.16s %3i %2i:%02i:%02i\n", j+1, client->name, (int)client->edict->fields.server->frags, hours, minutes, seconds); + print ("#%-3u %-16.16s %3i %2i:%02i:%02i\n", j+1, client->name, client->frags, hours, minutes, seconds); print (" %s\n", client->netconnection ? client->netconnection->address : "botclient"); } } @@ -225,7 +231,8 @@ void Host_Ping_f (void) } // now call the Pings command also, which will send a report that contains packet loss for the scoreboard (as well as a simpler ping report) - Host_Pings_f(); + // actually, don't, it confuses old clients (resulting in "unknown command pingplreport" flooding the console) + //Host_Pings_f(); } /* @@ -269,29 +276,6 @@ void Host_Map_f (void) SV_SpawnServer(level); if (sv.active && cls.state == ca_disconnected) CL_EstablishConnection("local:1"); - -#ifdef AUTODEMO_BROKEN -// if cl_autodemo is set, automatically start recording a demo if one isn't being recorded already - if (cl_autodemo.integer && !cls.demorecording) - { - char demofile[MAX_OSPATH]; - - dpsnprintf (demofile, sizeof(demofile), "%s_%s.dem", Sys_TimeString (cl_autodemo_nameformat.string), level); - - Con_Printf ("Recording to %s.\n", demofile); - - cls.demofile = FS_Open (demofile, "wb", false, false); - if (cls.demofile) - { - cls.forcetrack = -1; - FS_Printf (cls.demofile, "%i\n", cls.forcetrack); - } - else - Con_Print ("ERROR: couldn't open.\n"); - - cls.demorecording = true; - } -#endif } /* @@ -371,36 +355,38 @@ This is sent just before a server changes levels */ void Host_Reconnect_f (void) { + char temp[128]; + // if not connected, reconnect to the most recent server + if (!cls.netcon) + { + // if we have connected to a server recently, the userinfo + // will still contain its IP address, so get the address... + InfoString_GetValue(cls.userinfo, "*ip", temp, sizeof(temp)); + if (temp[0]) + CL_EstablishConnection(temp); + else + Con_Printf("Reconnect to what server? (you have not connected to a server yet)\n"); + return; + } + // if connected, do something based on protocol if (cls.protocol == PROTOCOL_QUAKEWORLD) { + // quakeworld can just re-login if (cls.qw_downloadmemory) // don't change when downloading return; S_StopAllSounds(); - if (cls.netcon) + if (cls.state == ca_connected && cls.signon < SIGNONS) { - if (cls.state == ca_connected && cls.signon < SIGNONS) - { - Con_Printf("reconnecting...\n"); - MSG_WriteChar(&cls.netcon->message, qw_clc_stringcmd); - MSG_WriteString(&cls.netcon->message, "new"); - } - else - { - char temp[128]; - // if we have connected to a server recently, the userinfo - // will still contain its IP address, so get the address... - InfoString_GetValue(cls.userinfo, "*ip", temp, sizeof(temp)); - if (temp[0]) - CL_EstablishConnection(temp); - else - Con_Printf("Reconnect to what server? (you have not connected to a server yet)\n"); - } + Con_Printf("reconnecting...\n"); + MSG_WriteChar(&cls.netcon->message, qw_clc_stringcmd); + MSG_WriteString(&cls.netcon->message, "new"); } } else { + // netquake uses reconnect on level changes (silly) if (Cmd_Argc() != 1) { Con_Print("reconnect : wait for signon messages again\n"); @@ -443,33 +429,6 @@ LOAD / SAVE GAME #define SAVEGAME_VERSION 5 -/* -=============== -Host_SavegameComment - -Writes a SAVEGAME_COMMENT_LENGTH character comment describing the current -=============== -*/ -void Host_SavegameComment (char *text) -{ - int i; - char kills[20]; - - for (i=0 ; ifields.server->deadflag) { - if (i > 0) - { - Con_Print("Can't save multiplayer games.\n"); - return; - } - if (svs.clients[i].edict->fields.server->deadflag) - { - Con_Print("Can't savegame with a dead player\n"); - return; - } + Con_Print("Can't savegame with a dead player\n"); + return; } } + else + Con_Print("Warning: saving a multiplayer game may have strange results when restored (to properly resume, all players must join in the same player slots and then the game can be reloaded).\n"); if (Cmd_Argc() != 2) { @@ -534,8 +488,19 @@ void Host_Savegame_f (void) return; } + SV_VM_Begin(); + FS_Printf(f, "%i\n", SAVEGAME_VERSION); - Host_SavegameComment (comment); + + memset(comment, 0, sizeof(comment)); + sprintf(comment, "%-21s kills:%3i/%3i", PRVM_GetString(prog->edicts->fields.server->message), (int)prog->globals.server->killed_monsters, (int)prog->globals.server->total_monsters); + // convert space to _ to make stdio happy + // LordHavoc: convert control characters to _ as well + for (i=0 ; inum_edicts ; i++) PRVM_ED_Write (f, PRVM_EDICT_NUM(i)); @@ -606,7 +569,7 @@ void Host_Loadgame_f (void) } // version - COM_ParseTokenConsole(&t); + COM_ParseToken_Simple(&t, false); version = atoi(com_token); if (version != SAVEGAME_VERSION) { @@ -616,27 +579,25 @@ void Host_Loadgame_f (void) } // description - // this is a little hard to parse, as : is a separator in COM_ParseToken, - // so use the console parser instead - COM_ParseTokenConsole(&t); + COM_ParseToken_Simple(&t, false); for (i = 0;i < NUM_SPAWN_PARMS;i++) { - COM_ParseTokenConsole(&t); + COM_ParseToken_Simple(&t, false); spawn_parms[i] = atof(com_token); } // skill - COM_ParseTokenConsole(&t); + COM_ParseToken_Simple(&t, false); // this silliness is so we can load 1.06 save files, which have float skill values current_skill = (int)(atof(com_token) + 0.5); Cvar_SetValue ("skill", (float)current_skill); // mapname - COM_ParseTokenConsole(&t); + COM_ParseToken_Simple(&t, false); strlcpy (mapname, com_token, sizeof(mapname)); // time - COM_ParseTokenConsole(&t); + COM_ParseToken_Simple(&t, false); time = atof(com_token); allowcheats = sv_cheats.integer != 0; @@ -657,7 +618,7 @@ void Host_Loadgame_f (void) { // light style oldt = t; - COM_ParseTokenConsole(&t); + COM_ParseToken_Simple(&t, false); // if this is a 64 lightstyle savegame produced by Quake, stop now // we have to check this because darkplaces saves 256 lightstyle savegames if (com_token[0] == '{') @@ -675,7 +636,7 @@ void Host_Loadgame_f (void) for(;;) { oldt = t; - COM_ParseTokenConsole(&t); + COM_ParseToken_Simple(&t, false); if (com_token[0] == '{') { t = oldt; @@ -690,10 +651,10 @@ void Host_Loadgame_f (void) for (;;) { start = t; - while (COM_ParseTokenConsole(&t)) + while (COM_ParseToken_Simple(&t, false)) if (!strcmp(com_token, "}")) break; - if (!COM_ParseTokenConsole(&start)) + if (!COM_ParseToken_Simple(&start, false)) { // end of file break; @@ -718,7 +679,6 @@ void Host_Loadgame_f (void) Host_Error("Host_PerformLoadGame: too many edicts in save file (reached MAX_EDICTS %i)", MAX_EDICTS); } while (entnum >= prog->max_edicts) - //SV_IncreaseEdicts(); PRVM_MEM_IncreaseEdicts(); ent = PRVM_EDICT_NUM(entnum); memset (ent->fields.server, 0, prog->progs->entityfields * 4); @@ -743,7 +703,7 @@ void Host_Loadgame_f (void) SV_VM_End(); // make sure we're connected to loopback - if (cls.state == ca_disconnected || !(cls.state == ca_connected && cls.netcon != NULL && LHNETADDRESS_GetAddressType(&cls.netcon->peeraddress) == LHNETADDRESSTYPE_LOOP)) + if (sv.active && cls.state == ca_disconnected) CL_EstablishConnection("local:1"); } @@ -754,10 +714,11 @@ void Host_Loadgame_f (void) Host_Name_f ====================== */ -cvar_t cl_name = {CVAR_SAVE, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"}; +cvar_t cl_name = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_name", "player", "internal storage cvar for current player name (changed by name command)"}; void Host_Name_f (void) { int i, j; + qboolean valid_colors; char newName[sizeof(host_client->name)]; if (Cmd_Argc () == 1) @@ -771,28 +732,73 @@ void Host_Name_f (void) else strlcpy (newName, Cmd_Args(), sizeof (newName)); - for (i = 0, j = 0;newName[i];i++) - if (newName[i] != '\r' && newName[i] != '\n') - newName[j++] = newName[i]; - newName[j] = 0; - if (cmd_source == src_command) { Cvar_Set ("_cl_name", newName); - CL_SetInfo("name", newName, true, false, false, false); return; } - if (sv.time < host_client->nametime) + if (realtime < host_client->nametime) { SV_ClientPrintf("You can't change name more than once every 5 seconds!\n"); return; } - host_client->nametime = sv.time + 5; + host_client->nametime = realtime + 5; // 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; + + 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_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); + host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name); if (strcmp(host_client->old_name, host_client->name)) { @@ -803,6 +809,7 @@ void Host_Name_f (void) 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); } } @@ -811,7 +818,7 @@ void Host_Name_f (void) Host_Playermodel_f ====================== */ -cvar_t cl_playermodel = {CVAR_SAVE, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz (changed by playermodel command)"}; +cvar_t cl_playermodel = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playermodel", "", "internal storage cvar for current player model in Nexuiz (changed by playermodel command)"}; // the old cl_playermodel in cl_main has been renamed to __cl_playermodel void Host_Playermodel_f (void) { @@ -837,24 +844,23 @@ void Host_Playermodel_f (void) if (cmd_source == src_command) { Cvar_Set ("_cl_playermodel", newPath); - CL_SetInfo("playermodel", newPath, true, false, false, false); return; } /* - if (sv.time < host_client->nametime) + if (realtime < host_client->nametime) { SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n"); return; } - host_client->nametime = sv.time + 5; + host_client->nametime = realtime + 5; */ // point the string back at updateclient->name to keep it safe strlcpy (host_client->playermodel, newPath, sizeof (host_client->playermodel)); - if( eval_playermodel ) - PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel); + if( prog->fieldoffsets.playermodel >= 0 ) + PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(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)); @@ -870,7 +876,7 @@ void Host_Playermodel_f (void) Host_Playerskin_f ====================== */ -cvar_t cl_playerskin = {CVAR_SAVE, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz (changed by playerskin command)"}; +cvar_t cl_playerskin = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_playerskin", "", "internal storage cvar for current player skin in Nexuiz (changed by playerskin command)"}; void Host_Playerskin_f (void) { int i, j; @@ -895,24 +901,23 @@ void Host_Playerskin_f (void) if (cmd_source == src_command) { Cvar_Set ("_cl_playerskin", newPath); - CL_SetInfo("playerskin", newPath, true, false, false, false); return; } /* - if (sv.time < host_client->nametime) + if (realtime < host_client->nametime) { SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n"); return; } - host_client->nametime = sv.time + 5; + host_client->nametime = realtime + 5; */ // point the string back at updateclient->name to keep it safe strlcpy (host_client->playerskin, newPath, sizeof (host_client->playerskin)); - if( eval_playerskin ) - PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin); + if( prog->fieldoffsets.playerskin >= 0 ) + PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin); if (strcmp(host_client->old_skin, host_client->playerskin)) { //if (host_client->spawned) @@ -968,12 +973,14 @@ void Host_Say(qboolean teamonly) p1++; } // note this uses the chat prefix \001 - if (!fromServer) - dpsnprintf (text, sizeof(text), "\001%s" STRING_COLOR_DEFAULT_STR ": %s", host_client->name, p1); + if (!fromServer && !teamonly) + dpsnprintf (text, sizeof(text), "\001%s: %s", host_client->name, p1); + else if (!fromServer && teamonly) + dpsnprintf (text, sizeof(text), "\001(%s): %s", host_client->name, p1); else if(*(sv_adminnick.string)) - dpsnprintf (text, sizeof(text), "\001<%s" STRING_COLOR_DEFAULT_STR "> %s", sv_adminnick.string, p1); + dpsnprintf (text, sizeof(text), "\001<%s> %s", sv_adminnick.string, p1); else - dpsnprintf (text, sizeof(text), "\001<%s" STRING_COLOR_DEFAULT_STR "> %s", hostname.string, p1); + dpsnprintf (text, sizeof(text), "\001<%s> %s", hostname.string, p1); p2 = text + strlen(text); while ((const char *)p2 > (const char *)text && (p2[-1] == '\r' || p2[-1] == '\n' || (p2[-1] == '\"' && quoted))) { @@ -987,7 +994,7 @@ void Host_Say(qboolean teamonly) // note: save is not a valid edict if fromServer is true save = host_client; for (j = 0, host_client = svs.clients;j < svs.maxclients;j++, host_client++) - if (host_client->spawned && (!teamonly || host_client->edict->fields.server->team == save->edict->fields.server->team)) + if (host_client->active && (!teamonly || host_client->edict->fields.server->team == save->edict->fields.server->team)) SV_ClientPrint(text); host_client = save; @@ -1093,13 +1100,13 @@ void Host_Tell_f(void) namebuf[playername_length] = 0; for (playernumber = 0; playernumber < svs.maxclients; playernumber++) { - if (!svs.clients[playernumber].spawned) + if (!svs.clients[playernumber].active) continue; if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0) break; } } - if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].spawned)) + if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active)) { if (fromServer) Con_Print("Host_Tell: invalid player name/ID\n"); @@ -1142,12 +1149,10 @@ void Host_Tell_f(void) Host_Color_f ================== */ -cvar_t cl_color = {CVAR_SAVE, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"}; +cvar_t cl_color = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_color", "0", "internal storage cvar for current player colors (changed by color command)"}; void Host_Color(int changetop, int changebottom) { int top, bottom, playercolor; - mfunction_t *f; - func_t SV_ChangeTeam; // get top and bottom either from the provided values or the current values // (allows changing only top or bottom, or both at once) @@ -1167,35 +1172,26 @@ void Host_Color(int changetop, int changebottom) if (cmd_source == src_command) { Cvar_SetValueQuick(&cl_color, playercolor); - if (changetop >= 0) - CL_SetInfo("topcolor", va("%i", top), true, false, false, false); - if (changebottom >= 0) - CL_SetInfo("bottomcolor", va("%i", bottom), true, false, false, false); - if (cls.protocol != PROTOCOL_QUAKEWORLD && cls.netcon) - { - MSG_WriteByte(&cls.netcon->message, clc_stringcmd); - MSG_WriteString(&cls.netcon->message, va("color %i %i", top, bottom)); - } return; } if (cls.protocol == PROTOCOL_QUAKEWORLD) return; - if (host_client->edict && (f = PRVM_ED_FindFunction ("SV_ChangeTeam")) && (SV_ChangeTeam = (func_t)(f - prog->functions))) + if (host_client->edict && prog->funcoffsets.SV_ChangeTeam) { Con_DPrint("Calling SV_ChangeTeam\n"); prog->globals.server->time = sv.time; prog->globals.generic[OFS_PARM0] = playercolor; prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict); - PRVM_ExecuteProgram (SV_ChangeTeam, "QC function SV_ChangeTeam is missing"); + PRVM_ExecuteProgram(prog->funcoffsets.SV_ChangeTeam, "QC function SV_ChangeTeam is missing"); } else { prvm_eval_t *val; if (host_client->edict) { - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors))) + if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors))) val->_float = playercolor; host_client->edict->fields.server->team = bottom + 1; } @@ -1256,7 +1252,7 @@ void Host_BottomColor_f(void) Host_Color(-1, atoi(Cmd_Argv(1))); } -cvar_t cl_rate = {CVAR_SAVE, "_cl_rate", "10000", "internal storage cvar for current rate (changed by rate command)"}; +cvar_t cl_rate = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_rate", "20000", "internal storage cvar for current rate (changed by rate command)"}; void Host_Rate_f(void) { int rate; @@ -1273,7 +1269,6 @@ void Host_Rate_f(void) if (cmd_source == src_command) { Cvar_SetValue ("_cl_rate", max(NET_MINRATE, rate)); - CL_SetInfo("rate", va("%i", rate), true, false, false, false); return; } @@ -1325,7 +1320,7 @@ LordHavoc: only supported for Nehahra, I personally think this is dumb, but Mind LordHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility. ====================== */ -cvar_t cl_pmodel = {CVAR_SAVE, "_cl_pmodel", "0", "internal storage cvar for current player model number in nehahra (changed by pmodel command)"}; +cvar_t cl_pmodel = {CVAR_SAVE | CVAR_NQUSERINFOHACK, "_cl_pmodel", "0", "internal storage cvar for current player model number in nehahra (changed by pmodel command)"}; static void Host_PModel_f (void) { int i; @@ -1348,7 +1343,7 @@ static void Host_PModel_f (void) return; } - if (host_client->edict && (val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_pmodel))) + if (host_client->edict && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.pmodel))) val->_float = i; } @@ -1373,6 +1368,7 @@ void Host_PreSpawn_f (void) SZ_Write (&host_client->netconnection->message, sv.signon.data, sv.signon.cursize); MSG_WriteByte (&host_client->netconnection->message, svc_signonnum); MSG_WriteByte (&host_client->netconnection->message, 2); + host_client->sendsignon = 0; // enable unlimited sends again } // reset the name change timer because the client will send name soon @@ -1388,8 +1384,6 @@ void Host_Spawn_f (void) { int i; client_t *client; - func_t RestoreGame; - mfunction_t *f; int stats[MAX_CL_STATS]; if (host_client->spawned) @@ -1414,13 +1408,12 @@ void Host_Spawn_f (void) // if this is the last client to be connected, unpause sv.paused = false; - if ((f = PRVM_ED_FindFunction ("RestoreGame"))) - if ((RestoreGame = (func_t)(f - prog->functions))) + if (prog->funcoffsets.RestoreGame) { Con_DPrint("Calling RestoreGame\n"); prog->globals.server->time = sv.time; prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict); - PRVM_ExecuteProgram (RestoreGame, "QC function RestoreGame is missing"); + PRVM_ExecuteProgram(prog->funcoffsets.RestoreGame, "QC function RestoreGame is missing"); } } else @@ -1437,7 +1430,7 @@ void Host_Spawn_f (void) prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict); PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing"); - if ((Sys_DoubleTime() - host_client->connecttime) <= sv.time) + if (svs.maxclients > 1 || cls.state == ca_dedicated) Con_Printf("%s entered the game\n", host_client->name); PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing"); @@ -1592,7 +1585,7 @@ void Host_Kick_f (void) if (Cmd_Argc() > 2) { message = Cmd_Args(); - COM_ParseTokenConsole(&message); + COM_ParseToken_Simple(&message, false); if (byNumber) { message++; // skip the # @@ -1679,7 +1672,7 @@ void Host_Give_f (void) break; case 's': - if (gamemode == GAME_ROGUE && (val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_shells1))) + if (gamemode == GAME_ROGUE && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_shells1))) val->_float = v; host_client->edict->fields.server->ammo_shells = v; @@ -1687,7 +1680,7 @@ void Host_Give_f (void) case 'n': if (gamemode == GAME_ROGUE) { - if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_nails1))) + if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_nails1))) { val->_float = v; if (host_client->edict->fields.server->weapon <= IT_LIGHTNING) @@ -1702,7 +1695,7 @@ void Host_Give_f (void) case 'l': if (gamemode == GAME_ROGUE) { - val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_lava_nails); + val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_lava_nails); if (val) { val->_float = v; @@ -1714,7 +1707,7 @@ void Host_Give_f (void) case 'r': if (gamemode == GAME_ROGUE) { - val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_rockets1); + val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_rockets1); if (val) { val->_float = v; @@ -1730,7 +1723,7 @@ void Host_Give_f (void) case 'm': if (gamemode == GAME_ROGUE) { - val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_multi_rockets); + val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_multi_rockets); if (val) { val->_float = v; @@ -1745,7 +1738,7 @@ void Host_Give_f (void) case 'c': if (gamemode == GAME_ROGUE) { - val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_cells1); + val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_cells1); if (val) { val->_float = v; @@ -1761,7 +1754,7 @@ void Host_Give_f (void) case 'p': if (gamemode == GAME_ROGUE) { - val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ammo_plasma); + val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_plasma); if (val) { val->_float = v; @@ -1928,7 +1921,7 @@ void Host_Startdemos_f (void) { int i, c; - if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo") || COM_CheckParm("-demolooponly")) + if (cls.state == ca_dedicated || COM_CheckParm("-listen") || COM_CheckParm("-benchmark") || COM_CheckParm("-demo") || COM_CheckParm("-capturedemo")) return; c = Cmd_Argc() - 1; @@ -1992,15 +1985,24 @@ void Host_SendCvar_f (void) { int i; cvar_t *c; + const char *cvarname; client_t *old; if(Cmd_Argc() != 2) return; - if(!(c = Cvar_FindVar(Cmd_Argv(1))) || (c->flags & CVAR_PRIVATE)) + cvarname = Cmd_Argv(1); + if (cls.state == ca_connected) + { + c = Cvar_FindVar(cvarname); + // LordHavoc: if there is no such cvar or if it is private, send a + // reply indicating that it has no value + if(!c || (c->flags & CVAR_PRIVATE)) + Cmd_ForwardStringToServer(va("sentcvar %s", cvarname)); + else + Cmd_ForwardStringToServer(va("sentcvar %s \"%s\"", c->name, c->string)); return; - if (cls.state != ca_dedicated) - Cmd_ForwardStringToServer(va("sentcvar %s %s\n", c->name, c->string)); - if(!sv.active)// || !SV_ParseClientCommandQC) + } + if(!sv.active)// || !prog->funcoffsets.SV_ParseClientCommand) return; old = host_client; @@ -2012,7 +2014,7 @@ void Host_SendCvar_f (void) if(svs.clients[i].active && svs.clients[i].netconnection) { host_client = &svs.clients[i]; - Host_ClientCommands(va("sendcvar %s\n", c->name)); + Host_ClientCommands(va("sendcvar %s\n", cvarname)); } host_client = old; } @@ -2352,8 +2354,10 @@ void Host_Pings_f (void) { packetloss = 0; if (svs.clients[i].netconnection) - for (j = 0;j < 100;j++) - packetloss += svs.clients[i].netconnection->packetlost[j]; + for (j = 0;j < NETGRAPH_PACKETS;j++) + if (svs.clients[i].netconnection->incoming_unreliablesize[j] == NETGRAPH_LOSTPACKET) + packetloss++; + packetloss = packetloss * 100 / NETGRAPH_PACKETS; ping = (int)floor(svs.clients[i].ping*1000+0.5); ping = bound(0, ping, 9999); if (sv.protocol == PROTOCOL_QUAKEWORLD) @@ -2397,7 +2401,7 @@ Host_InitCommands */ void Host_InitCommands (void) { - dpsnprintf(cls.userinfo, sizeof(cls.userinfo), "\\name\\player\\team\\none\\topcolor\\0\\bottomcolor\\0\\rate\\10000\\msg\\1\\noaim\\1\\*ver\\%s", engineversion); + dpsnprintf(cls.userinfo, sizeof(cls.userinfo), "\\name\\player\\team\\none\\topcolor\\0\\bottomcolor\\0\\rate\\10000\\msg\\1\\noaim\\1\\*ver\\dp"); Cmd_AddCommand_WithClientCommand ("status", Host_Status_f, Host_Status_f, "print server status information"); Cmd_AddCommand ("quit", Host_Quit_f, "quit the game"); @@ -2421,7 +2425,7 @@ void Host_InitCommands (void) Cmd_AddCommand ("restart", Host_Restart_f, "restart current level"); Cmd_AddCommand ("changelevel", Host_Changelevel_f, "change to another level, bringing along all connected clients"); Cmd_AddCommand ("connect", Host_Connect_f, "connect to a server by IP address or hostname"); - Cmd_AddCommand ("reconnect", Host_Reconnect_f, "reset signon level in preparation for a new level (do not use)"); + Cmd_AddCommand ("reconnect", Host_Reconnect_f, "reconnect to the last server you were on, or resets a quakeworld connection (do not use if currently playing on a netquake server)"); Cmd_AddCommand ("version", Host_Version_f, "print engine version"); Cmd_AddCommand_WithClientCommand ("say", Host_Say_f, Host_Say_f, "send a chat message to everyone on the server"); Cmd_AddCommand_WithClientCommand ("say_team", Host_Say_Team_f, Host_Say_Team_f, "send a chat message to your team on the server"); @@ -2465,7 +2469,7 @@ void Host_InitCommands (void) Cmd_AddCommand_WithClientCommand ("begin", NULL, Host_Begin_f, "signon 3 (client asks server to start sending entities, and will go to signon 4 (playing) when the first entity update is received)"); Cmd_AddCommand ("maxplayers", MaxPlayers_f, "sets limit on how many players (or bots) may be connected to the server at once"); - Cmd_AddCommand ("sendcvar", Host_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC"); // By [515] + Cmd_AddCommand ("sendcvar", Host_SendCvar_f, "sends the value of a cvar to the server as a sentcvar command, for use by QuakeC"); Cvar_RegisterVariable (&rcon_password); Cvar_RegisterVariable (&rcon_address);