-/*
-==================
-Host_Quit_f
-==================
-*/
-
-void Host_Quit_f (void)
-{
- if(host_shuttingdown)
- Con_Printf("shutting down already!\n");
- else
- Sys_Quit (0);
-}
-
-/*
-==================
-Host_Status_f
-==================
-*/
-void Host_Status_f (void)
-{
- char qcstatus[256];
- client_t *client;
- int seconds = 0, minutes = 0, hours = 0, i, j, k, in, players, ping = 0, packetloss = 0;
- void (*print) (const char *fmt, ...);
- char ip[22];
- int frags;
-
- if (cmd_source == src_command)
- {
- // 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 ();
- return;
- }
- print = Con_Printf;
- }
- else
- print = SV_ClientPrintf;
-
- if (!sv.active)
- return;
-
- if(cmd_source == src_command)
- SV_VM_Begin();
-
- in = 0;
- if (Cmd_Argc() == 2)
- {
- if (strcmp(Cmd_Argv(1), "1") == 0)
- in = 1;
- else if (strcmp(Cmd_Argv(1), "2") == 0)
- in = 2;
- }
-
- for (players = 0, i = 0;i < svs.maxclients;i++)
- if (svs.clients[i].active)
- players++;
- print ("host: %s\n", Cvar_VariableString ("hostname"));
- 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);
-
- if (in == 1)
- print ("^2IP %%pl ping time frags no name\n");
- else if (in == 2)
- print ("^5IP no name\n");
-
- for (i = 0, k = 0, client = svs.clients;i < svs.maxclients;i++, client++)
- {
- if (!client->active)
- continue;
-
- ++k;
-
- if (in == 0 || in == 1)
- {
- seconds = (int)(realtime - client->connecttime);
- minutes = seconds / 60;
- if (minutes)
- {
- seconds -= (minutes * 60);
- hours = minutes / 60;
- if (hours)
- minutes -= (hours * 60);
- }
- else
- hours = 0;
-
- packetloss = 0;
- if (client->netconnection)
- for (j = 0;j < NETGRAPH_PACKETS;j++)
- if (client->netconnection->incoming_netgraph[j].unreliablebytes == NETGRAPH_LOSTPACKET)
- packetloss++;
- packetloss = (packetloss * 100 + NETGRAPH_PACKETS - 1) / NETGRAPH_PACKETS;
- ping = bound(0, (int)floor(client->ping*1000+0.5), 9999);
- }
-
- if(sv_status_privacy.integer && cmd_source != src_command)
- strlcpy(ip, client->netconnection ? "hidden" : "botclient" , 22);
- else
- strlcpy(ip, (client->netconnection && client->netconnection->address) ? client->netconnection->address : "botclient", 22);
-
- frags = client->frags;
-
- if(sv_status_show_qcstatus.integer && prog->fieldoffsets.clientstatus >= 0)
- {
- const char *str = PRVM_E_STRING(PRVM_EDICT_NUM(i + 1), prog->fieldoffsets.clientstatus);
- if(str && *str)
- {
- char *p;
- const char *q;
- p = qcstatus;
- for(q = str; *q && p != qcstatus + sizeof(qcstatus) - 1; ++q)
- if(*q != '\\' && *q != '"' && !ISWHITESPACE(*q))
- *p++ = *q;
- *p = 0;
- if(*qcstatus)
- frags = atoi(qcstatus);
- }
- }
-
- if (in == 0) // default layout
- {
- // LordHavoc: we must use multiple prints for ProQuake compatibility
- print ("#%-3u ", i+1);
- print ("%-16.16s ", client->name);
- print ("%4i ", frags);
- print ("%2i:%02i:%02i\n ", hours, minutes, seconds);
- print ("%s\n", ip);
-// print ("#%-3u %-16.16s %3i %2i:%02i:%02i\n", i+1, client->name, frags, hours, minutes, seconds);
-// print (" %s\n", ip);
- }
- else if (in == 1) // extended layout
- {
- print ("%s%-21s %2i %4i %2i:%02i:%02i %4i #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, packetloss, ping, hours, minutes, seconds, frags, i+1, client->name);
- }
- else if (in == 2) // reduced layout
- {
- print ("%s%-21s #%-3u ^7%s\n", k%2 ? "^3" : "^7", ip, i+1, client->name);
- }
- }
-
- if(cmd_source == src_command)
- SV_VM_End();
-}
-
-
-/*
-==================
-Host_God_f
-
-Sets client to godmode
-==================
-*/
-void Host_God_f (void)
-{
- if (!allowcheats)
- {
- SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
- return;
- }
-
- host_client->edict->fields.server->flags = (int)host_client->edict->fields.server->flags ^ FL_GODMODE;
- if (!((int)host_client->edict->fields.server->flags & FL_GODMODE) )
- SV_ClientPrint("godmode OFF\n");
- else
- SV_ClientPrint("godmode ON\n");
-}
-
-void Host_Notarget_f (void)
-{
- if (!allowcheats)
- {
- SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
- return;
- }
-
- host_client->edict->fields.server->flags = (int)host_client->edict->fields.server->flags ^ FL_NOTARGET;
- if (!((int)host_client->edict->fields.server->flags & FL_NOTARGET) )
- SV_ClientPrint("notarget OFF\n");
- else
- SV_ClientPrint("notarget ON\n");
-}
-
-qboolean noclip_anglehack;
-
-void Host_Noclip_f (void)
-{
- if (!allowcheats)
- {
- SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
- return;
- }
-
- if (host_client->edict->fields.server->movetype != MOVETYPE_NOCLIP)
- {
- noclip_anglehack = true;
- host_client->edict->fields.server->movetype = MOVETYPE_NOCLIP;
- SV_ClientPrint("noclip ON\n");
- }
- else
- {
- noclip_anglehack = false;
- host_client->edict->fields.server->movetype = MOVETYPE_WALK;
- SV_ClientPrint("noclip OFF\n");
- }
-}
-
-/*
-==================
-Host_Fly_f
-
-Sets client to flymode
-==================
-*/
-void Host_Fly_f (void)
-{
- if (!allowcheats)
- {
- SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
- return;
- }
-
- if (host_client->edict->fields.server->movetype != MOVETYPE_FLY)
- {
- host_client->edict->fields.server->movetype = MOVETYPE_FLY;
- SV_ClientPrint("flymode ON\n");
- }
- else
- {
- host_client->edict->fields.server->movetype = MOVETYPE_WALK;
- SV_ClientPrint("flymode OFF\n");
- }
-}
-
-
-/*
-==================
-Host_Ping_f
-
-==================
-*/
-void Host_Pings_f (void); // called by Host_Ping_f
-void Host_Ping_f (void)
-{
- int i;
- client_t *client;
- void (*print) (const char *fmt, ...);
-
- if (cmd_source == src_command)
- {
- // 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 ();
- return;
- }
- print = Con_Printf;
- }
- else
- print = SV_ClientPrintf;
-
- if (!sv.active)
- return;
-
- print("Client ping times:\n");
- for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
- {
- if (!client->active)
- continue;
- print("%4i %s\n", bound(0, (int)floor(client->ping*1000+0.5), 9999), client->name);
- }
-
- // 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)
- // actually, don't, it confuses old clients (resulting in "unknown command pingplreport" flooding the console)
- //Host_Pings_f();
-}
-
-/*
-===============================================================================
-
-SERVER TRANSITIONS
-
-===============================================================================
-*/
-
-/*
-======================
-Host_Map_f
-
-handle a
-map <servername>
-command from the console. Active clients are kicked off.
-======================
-*/
-void Host_Map_f (void)
-{
- char level[MAX_QPATH];
-
- if (Cmd_Argc() != 2)
- {
- Con_Print("map <levelname> : start a new game (kicks off all players)\n");
- return;
- }
-
- // GAME_DELUXEQUAKE - clear warpmark (used by QC)
- if (gamemode == GAME_DELUXEQUAKE)
- Cvar_Set("warpmark", "");
-
- cls.demonum = -1; // stop demo loop in case this fails
-
- CL_Disconnect ();
- Host_ShutdownServer();
-
- if(svs.maxclients != svs.maxclients_next)
- {
- svs.maxclients = svs.maxclients_next;
- if (svs.clients)
- Mem_Free(svs.clients);
- svs.clients = (client_t *)Mem_Alloc(sv_mempool, sizeof(client_t) * svs.maxclients);
- }
-
- // remove menu
- key_dest = key_game;
-
- svs.serverflags = 0; // haven't completed an episode yet
- allowcheats = sv_cheats.integer != 0;
- strlcpy(level, Cmd_Argv(1), sizeof(level));
- SV_SpawnServer(level);
- if (sv.active && cls.state == ca_disconnected)
- CL_EstablishConnection("local:1");
-}
-
-/*
-==================
-Host_Changelevel_f
-
-Goes to a new map, taking all clients along
-==================
-*/
-void Host_Changelevel_f (void)
-{
- char level[MAX_QPATH];
-
- if (Cmd_Argc() != 2)
- {
- Con_Print("changelevel <levelname> : continue game on a new level\n");
- return;
- }
- // HACKHACKHACK
- if (!sv.active) {
- Host_Map_f();
- return;
- }
-
- // remove menu
- key_dest = key_game;
-
- SV_VM_Begin();
- SV_SaveSpawnparms ();
- SV_VM_End();
- allowcheats = sv_cheats.integer != 0;
- strlcpy(level, Cmd_Argv(1), sizeof(level));
- SV_SpawnServer(level);
- if (sv.active && cls.state == ca_disconnected)
- CL_EstablishConnection("local:1");
-}
-
-/*
-==================
-Host_Restart_f
-
-Restarts the current server for a dead player
-==================
-*/
-void Host_Restart_f (void)
-{
- char mapname[MAX_QPATH];
-
- if (Cmd_Argc() != 1)
- {
- Con_Print("restart : restart current level\n");
- return;
- }
- if (!sv.active)
- {
- Con_Print("Only the server may restart\n");
- return;
- }
-
- // remove menu
- key_dest = key_game;
-
- allowcheats = sv_cheats.integer != 0;
- strlcpy(mapname, sv.name, sizeof(mapname));
- SV_SpawnServer(mapname);
- if (sv.active && cls.state == ca_disconnected)
- CL_EstablishConnection("local:1");
-}
-
-/*
-==================
-Host_Reconnect_f
-
-This command causes the client to wait for the signon messages again.
-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.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
- {
- // netquake uses reconnect on level changes (silly)
- if (Cmd_Argc() != 1)
- {
- Con_Print("reconnect : wait for signon messages again\n");
- return;
- }
- if (!cls.signon)
- {
- Con_Print("reconnect: no signon, ignoring reconnect\n");
- return;
- }
- cls.signon = 0; // need new connection messages
- }
-}
-
-/*
-=====================
-Host_Connect_f
-
-User command to connect to server
-=====================
-*/
-void Host_Connect_f (void)
-{
- if (Cmd_Argc() != 2)
- {
- Con_Print("connect <serveraddress> : connect to a multiplayer game\n");
- return;
- }
- // clear the rcon password, to prevent vulnerability by stuffcmd-ing a connect command
- if(rcon_secure.integer <= 0)
- Cvar_SetQuick(&rcon_password, "");
- CL_EstablishConnection(Cmd_Argv(1));
-}
-
-
-/*
-===============================================================================
-
-LOAD / SAVE GAME
-
-===============================================================================
-*/
-
-#define SAVEGAME_VERSION 5
-
-void Host_Savegame_to (const char *name)
-{
- qfile_t *f;
- int i, k, l, lightstyles = 64;
- char comment[SAVEGAME_COMMENT_LENGTH+1];
- char line[MAX_INPUTLINE];
- qboolean isserver;
- char *s;
-
- // first we have to figure out if this can be saved in 64 lightstyles
- // (for Quake compatibility)
- for (i=64 ; i<MAX_LIGHTSTYLES ; i++)
- if (sv.lightstyles[i][0])
- lightstyles = i+1;
-
- isserver = !strcmp(PRVM_NAME, "server");
-
- Con_Printf("Saving game to %s...\n", name);
- f = FS_OpenRealFile(name, "wb", false);
- if (!f)
- {
- Con_Print("ERROR: couldn't open.\n");
- return;
- }
-
- FS_Printf(f, "%i\n", SAVEGAME_VERSION);
-
- memset(comment, 0, sizeof(comment));
- if(isserver)
- dpsnprintf(comment, sizeof(comment), "%-21.21s kills:%3i/%3i", PRVM_GetString(prog->edicts->fields.server->message), (int)prog->globals.server->killed_monsters, (int)prog->globals.server->total_monsters);
- else
- dpsnprintf(comment, sizeof(comment), "(crash dump of %s progs)", PRVM_NAME);
- // convert space to _ to make stdio happy
- // LordHavoc: convert control characters to _ as well
- for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
- if (ISWHITESPACEORCONTROL(comment[i]))
- comment[i] = '_';
- comment[SAVEGAME_COMMENT_LENGTH] = '\0';
-
- FS_Printf(f, "%s\n", comment);
- if(isserver)
- {
- for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
- FS_Printf(f, "%f\n", svs.clients[0].spawn_parms[i]);
- FS_Printf(f, "%d\n", current_skill);
- FS_Printf(f, "%s\n", sv.name);
- FS_Printf(f, "%f\n",sv.time);
- }
- else
- {
- for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
- FS_Printf(f, "(dummy)\n");
- FS_Printf(f, "%d\n", 0);
- FS_Printf(f, "%s\n", "(dummy)");
- FS_Printf(f, "%f\n", realtime);
- }
-
- // write the light styles
- for (i=0 ; i<lightstyles ; i++)
- {
- if (isserver && sv.lightstyles[i][0])
- FS_Printf(f, "%s\n", sv.lightstyles[i]);
- else
- FS_Print(f,"m\n");
- }
-
- PRVM_ED_WriteGlobals (f);
- for (i=0 ; i<prog->num_edicts ; i++)
- {
- FS_Printf(f,"// edict %d\n", i);
- //Con_Printf("edict %d...\n", i);
- PRVM_ED_Write (f, PRVM_EDICT_NUM(i));
- }
-
-#if 1
- FS_Printf(f,"/*\n");
- FS_Printf(f,"// DarkPlaces extended savegame\n");
- // darkplaces extension - extra lightstyles, support for color lightstyles
- for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
- if (isserver && sv.lightstyles[i][0])
- FS_Printf(f, "sv.lightstyles %i %s\n", i, sv.lightstyles[i]);
-
- // darkplaces extension - model precaches
- for (i=1 ; i<MAX_MODELS ; i++)
- if (sv.model_precache[i][0])
- FS_Printf(f,"sv.model_precache %i %s\n", i, sv.model_precache[i]);
-
- // darkplaces extension - sound precaches
- for (i=1 ; i<MAX_SOUNDS ; i++)
- if (sv.sound_precache[i][0])
- FS_Printf(f,"sv.sound_precache %i %s\n", i, sv.sound_precache[i]);
-
- // darkplaces extension - save buffers
- for (i = 0; i < (int)Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray); i++)
- {
- prvm_stringbuffer_t *stringbuffer = (prvm_stringbuffer_t*) Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);
- if(stringbuffer && (stringbuffer->flags & STRINGBUFFER_SAVED))
- {
- for(k = 0; k < stringbuffer->num_strings; k++)
- {
- if (!stringbuffer->strings[k])
- continue;
- // Parse the string a bit to turn special characters
- // (like newline, specifically) into escape codes
- s = stringbuffer->strings[k];
- for (l = 0;l < (int)sizeof(line) - 2 && *s;)
- {
- if (*s == '\n')
- {
- line[l++] = '\\';
- line[l++] = 'n';
- }
- else if (*s == '\r')
- {
- line[l++] = '\\';
- line[l++] = 'r';
- }
- else if (*s == '\\')
- {
- line[l++] = '\\';
- line[l++] = '\\';
- }
- else if (*s == '"')
- {
- line[l++] = '\\';
- line[l++] = '"';
- }
- else
- line[l++] = *s;
- s++;
- }
- line[l] = '\0';
- FS_Printf(f,"sv.bufstr %i %i \"%s\"\n", i, k, line);
- }
- }
- }
- FS_Printf(f,"*/\n");
-#endif
-
- FS_Close (f);
- Con_Print("done.\n");
-}
-
-/*
-===============
-Host_Savegame_f
-===============
-*/
-void Host_Savegame_f (void)
-{
- char name[MAX_QPATH];
-
- if (!sv.active)
- {
- Con_Print("Can't save - no server running.\n");
- return;
- }
-
- if (cl.islocalgame)
- {
- // singleplayer checks
- if (cl.intermission)
- {
- Con_Print("Can't save in intermission.\n");
- return;
- }
-
- if (svs.clients[0].active && svs.clients[0].edict->fields.server->deadflag)
- {
- 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)
- {
- Con_Print("save <savename> : save a game\n");
- return;
- }
-
- if (strstr(Cmd_Argv(1), ".."))
- {
- Con_Print("Relative pathnames are not allowed.\n");
- return;
- }
-
- strlcpy (name, Cmd_Argv(1), sizeof (name));
- FS_DefaultExtension (name, ".sav", sizeof (name));
-
- SV_VM_Begin();
- Host_Savegame_to(name);
- SV_VM_End();
-}
-
-
-/*
-===============
-Host_Loadgame_f
-===============
-*/
-
-void Host_Loadgame_f (void)
-{
- char filename[MAX_QPATH];
- char mapname[MAX_QPATH];
- float time;
- const char *start;
- const char *end;
- const char *t;
- char *text;
- prvm_edict_t *ent;
- int i, k;
- int entnum;
- int version;
- float spawn_parms[NUM_SPAWN_PARMS];
- prvm_stringbuffer_t *stringbuffer;
- size_t alloclen;
-
- if (Cmd_Argc() != 2)
- {
- Con_Print("load <savename> : load a game\n");
- return;
- }
-
- strlcpy (filename, Cmd_Argv(1), sizeof(filename));
- FS_DefaultExtension (filename, ".sav", sizeof (filename));
-
- Con_Printf("Loading game from %s...\n", filename);
-
- // stop playing demos
- if (cls.demoplayback)
- CL_Disconnect ();
-
- // remove menu
- key_dest = key_game;
-
- cls.demonum = -1; // stop demo loop in case this fails
-
- t = text = (char *)FS_LoadFile (filename, tempmempool, false, NULL);
- if (!text)
- {
- Con_Print("ERROR: couldn't open.\n");
- return;
- }
-
- if(developer_entityparsing.integer)
- Con_Printf("Host_Loadgame_f: loading version\n");
-
- // version
- COM_ParseToken_Simple(&t, false, false);
- version = atoi(com_token);
- if (version != SAVEGAME_VERSION)
- {
- Mem_Free(text);
- Con_Printf("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
- return;
- }
-
- if(developer_entityparsing.integer)
- Con_Printf("Host_Loadgame_f: loading description\n");
-
- // description
- COM_ParseToken_Simple(&t, false, false);
-
- for (i = 0;i < NUM_SPAWN_PARMS;i++)
- {
- COM_ParseToken_Simple(&t, false, false);
- spawn_parms[i] = atof(com_token);
- }
- // skill
- COM_ParseToken_Simple(&t, false, 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);
-
- if(developer_entityparsing.integer)
- Con_Printf("Host_Loadgame_f: loading mapname\n");
-
- // mapname
- COM_ParseToken_Simple(&t, false, false);
- strlcpy (mapname, com_token, sizeof(mapname));
-
- if(developer_entityparsing.integer)
- Con_Printf("Host_Loadgame_f: loading time\n");
-
- // time
- COM_ParseToken_Simple(&t, false, false);
- time = atof(com_token);
-
- allowcheats = sv_cheats.integer != 0;
-
- if(developer_entityparsing.integer)
- Con_Printf("Host_Loadgame_f: spawning server\n");
-
- SV_SpawnServer (mapname);
- if (!sv.active)
- {
- Mem_Free(text);
- Con_Print("Couldn't load map\n");
- return;
- }
- sv.paused = true; // pause until all clients connect
- sv.loadgame = true;
-
- if(developer_entityparsing.integer)
- Con_Printf("Host_Loadgame_f: loading light styles\n");
-
-// load the light styles
-
- SV_VM_Begin();
- // -1 is the globals
- entnum = -1;
-
- for (i = 0;i < MAX_LIGHTSTYLES;i++)
- {
- // light style
- start = t;
- COM_ParseToken_Simple(&t, false, false);
- // if this is a 64 lightstyle savegame produced by Quake, stop now
- // we have to check this because darkplaces may save more than 64
- if (com_token[0] == '{')
- {
- t = start;
- break;
- }
- strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
- }
-
- if(developer_entityparsing.integer)
- Con_Printf("Host_Loadgame_f: skipping until globals\n");
-
- // now skip everything before the first opening brace
- // (this is for forward compatibility, so that older versions (at
- // least ones with this fix) can load savegames with extra data before the
- // first brace, as might be produced by a later engine version)
- for (;;)
- {
- start = t;
- if (!COM_ParseToken_Simple(&t, false, false))
- break;
- if (com_token[0] == '{')
- {
- t = start;
- break;
- }
- }
-
- // unlink all entities
- World_UnlinkAll(&sv.world);
-
-// load the edicts out of the savegame file
- end = t;
- for (;;)
- {
- start = t;
- while (COM_ParseToken_Simple(&t, false, false))
- if (!strcmp(com_token, "}"))
- break;
- if (!COM_ParseToken_Simple(&start, false, false))
- {
- // end of file
- break;
- }
- if (strcmp(com_token,"{"))
- {
- Mem_Free(text);
- Host_Error ("First token isn't a brace");
- }
-
- if (entnum == -1)
- {
- if(developer_entityparsing.integer)
- Con_Printf("Host_Loadgame_f: loading globals\n");
-
- // parse the global vars
- PRVM_ED_ParseGlobals (start);
- }
- else
- {
- // parse an edict
- if (entnum >= MAX_EDICTS)
- {
- Mem_Free(text);
- Host_Error("Host_PerformLoadGame: too many edicts in save file (reached MAX_EDICTS %i)", MAX_EDICTS);
- }
- while (entnum >= prog->max_edicts)
- PRVM_MEM_IncreaseEdicts();
- ent = PRVM_EDICT_NUM(entnum);
- memset (ent->fields.server, 0, prog->progs->entityfields * 4);
- ent->priv.server->free = false;
-
- if(developer_entityparsing.integer)
- Con_Printf("Host_Loadgame_f: loading edict %d\n", entnum);
-
- PRVM_ED_ParseEdict (start, ent);
-
- // link it into the bsp tree
- if (!ent->priv.server->free)
- SV_LinkEdict(ent);
- }
-
- end = t;
- entnum++;
- }
-
- prog->num_edicts = entnum;
- sv.time = time;
-
- for (i = 0;i < NUM_SPAWN_PARMS;i++)
- svs.clients[0].spawn_parms[i] = spawn_parms[i];
-
- if(developer_entityparsing.integer)
- Con_Printf("Host_Loadgame_f: skipping until extended data\n");
-
- // read extended data if present
- // the extended data is stored inside a /* */ comment block, which the
- // parser intentionally skips, so we have to check for it manually here
- if(end)
- {
- while (*end == '\r' || *end == '\n')
- end++;
- if (end[0] == '/' && end[1] == '*' && (end[2] == '\r' || end[2] == '\n'))
- {
- if(developer_entityparsing.integer)
- Con_Printf("Host_Loadgame_f: loading extended data\n");
-
- Con_Printf("Loading extended DarkPlaces savegame\n");
- t = end + 2;
- memset(sv.lightstyles[0], 0, sizeof(sv.lightstyles));
- memset(sv.model_precache[0], 0, sizeof(sv.model_precache));
- memset(sv.sound_precache[0], 0, sizeof(sv.sound_precache));
- while (COM_ParseToken_Simple(&t, false, false))
- {
- if (!strcmp(com_token, "sv.lightstyles"))
- {
- COM_ParseToken_Simple(&t, false, false);
- i = atoi(com_token);
- COM_ParseToken_Simple(&t, false, false);
- if (i >= 0 && i < MAX_LIGHTSTYLES)
- strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
- else
- Con_Printf("unsupported lightstyle %i \"%s\"\n", i, com_token);
- }
- else if (!strcmp(com_token, "sv.model_precache"))
- {
- COM_ParseToken_Simple(&t, false, false);
- i = atoi(com_token);
- COM_ParseToken_Simple(&t, false, false);
- if (i >= 0 && i < MAX_MODELS)
- {
- strlcpy(sv.model_precache[i], com_token, sizeof(sv.model_precache[i]));
- sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, sv.model_precache[i][0] == '*' ? sv.modelname : NULL);
- }
- else
- Con_Printf("unsupported model %i \"%s\"\n", i, com_token);
- }
- else if (!strcmp(com_token, "sv.sound_precache"))
- {
- COM_ParseToken_Simple(&t, false, false);
- i = atoi(com_token);
- COM_ParseToken_Simple(&t, false, false);
- if (i >= 0 && i < MAX_SOUNDS)
- strlcpy(sv.sound_precache[i], com_token, sizeof(sv.sound_precache[i]));
- else
- Con_Printf("unsupported sound %i \"%s\"\n", i, com_token);
- }
- else if (!strcmp(com_token, "sv.bufstr"))
- {
- COM_ParseToken_Simple(&t, false, false);
- i = atoi(com_token);
- COM_ParseToken_Simple(&t, false, false);
- k = atoi(com_token);
- COM_ParseToken_Simple(&t, false, false);
- stringbuffer = (prvm_stringbuffer_t*) Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);
- // VorteX: nasty code, cleanup required
- // create buffer at this index
- if(!stringbuffer)
- stringbuffer = (prvm_stringbuffer_t *) Mem_ExpandableArray_AllocRecordAtIndex(&prog->stringbuffersarray, i);
- if (!stringbuffer)
- Con_Printf("cant write string %i into buffer %i\n", k, i);
- else
- {
- // code copied from VM_bufstr_set
- // expand buffer
- if (stringbuffer->max_strings <= i)
- {
- char **oldstrings = stringbuffer->strings;
- stringbuffer->max_strings = max(stringbuffer->max_strings * 2, 128);
- while (stringbuffer->max_strings <= i)
- stringbuffer->max_strings *= 2;
- stringbuffer->strings = (char **) Mem_Alloc(prog->progs_mempool, stringbuffer->max_strings * sizeof(stringbuffer->strings[0]));
- if (stringbuffer->num_strings > 0)
- memcpy(stringbuffer->strings, oldstrings, stringbuffer->num_strings * sizeof(stringbuffer->strings[0]));
- if (oldstrings)
- Mem_Free(oldstrings);
- }
- // allocate string
- stringbuffer->num_strings = max(stringbuffer->num_strings, k + 1);
- if(stringbuffer->strings[k])
- Mem_Free(stringbuffer->strings[k]);
- stringbuffer->strings[k] = NULL;
- alloclen = strlen(com_token) + 1;
- stringbuffer->strings[k] = (char *)Mem_Alloc(prog->progs_mempool, alloclen);
- memcpy(stringbuffer->strings[k], com_token, alloclen);
- }
- }
- // skip any trailing text or unrecognized commands
- while (COM_ParseToken_Simple(&t, true, false) && strcmp(com_token, "\n"))
- ;
- }
- }
- }
- Mem_Free(text);
-
- if(developer_entityparsing.integer)
- Con_Printf("Host_Loadgame_f: finished\n");
-
- SV_VM_End();
-
- // make sure we're connected to loopback
- if (sv.active && cls.state == ca_disconnected)
- CL_EstablishConnection("local:1");
-}
-
-//============================================================================
-
-/*
-======================
-Host_Name_f
-======================
-*/
-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;
- const char *newNameSource;
- char newName[sizeof(host_client->name)];
-
- if (Cmd_Argc () == 1)
- {
- Con_Printf("name: %s\n", cl_name.string);
- return;
- }
-
- if (Cmd_Argc () == 2)
- newNameSource = Cmd_Argv(1);
- else
- newNameSource = Cmd_Args();
-
- strlcpy(newName, newNameSource, sizeof(newName));
-
- if (cmd_source == src_command)
- {
- Cvar_Set ("_cl_name", newName);
- if (strlen(newNameSource) >= sizeof(newName)) // overflowed
- {
- Con_Printf("Your name is longer than %i chars! It has been truncated.\n", (int) (sizeof(newName) - 1));
- Con_Printf("name: %s\n", cl_name.string);
- }
- return;
- }
-
- if (realtime < host_client->nametime)
- {
- SV_ClientPrintf("You can't change name more than once every 5 seconds!\n");
- return;
- }
-
- 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;
-
- 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);
-
- host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
- if (strcmp(host_client->old_name, host_client->name))
- {
- if (host_client->spawned)
- 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);
- }
-}
-
-/*
-======================
-Host_Playermodel_f
-======================
-*/
-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)
-{
- int i, j;
- char newPath[sizeof(host_client->playermodel)];
-
- if (Cmd_Argc () == 1)
- {
- Con_Printf("\"playermodel\" is \"%s\"\n", cl_playermodel.string);
- return;
- }
-
- if (Cmd_Argc () == 2)
- strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
- else
- strlcpy (newPath, Cmd_Args(), 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 (cmd_source == src_command)
- {
- Cvar_Set ("_cl_playermodel", newPath);
- return;
- }
-
- /*
- if (realtime < host_client->nametime)
- {
- SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
- return;
- }
-
- 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( 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));
- /*// 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);*/
- }
-}
-
-/*
-======================
-Host_Playerskin_f
-======================
-*/
-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;
- char newPath[sizeof(host_client->playerskin)];
-
- if (Cmd_Argc () == 1)
- {
- Con_Printf("\"playerskin\" is \"%s\"\n", cl_playerskin.string);
- return;
- }
-
- if (Cmd_Argc () == 2)
- strlcpy (newPath, Cmd_Argv(1), sizeof (newPath));
- else
- strlcpy (newPath, Cmd_Args(), 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 (cmd_source == src_command)
- {
- Cvar_Set ("_cl_playerskin", newPath);
- return;
- }
-
- /*
- if (realtime < host_client->nametime)
- {
- SV_ClientPrintf("You can't change playermodel more than once every 5 seconds!\n");
- return;
- }
-
- 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( 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)
- // 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);*/
- }
-}
-
-void Host_Version_f (void)
-{
- Con_Printf("Version: %s build %s\n", gamename, buildstring);
-}
-
-void Host_Say(qboolean teamonly)
-{
- client_t *save;
- int j, quoted;
- const char *p1;
- char *p2;
- // LordHavoc: long say messages
- char text[1024];
- qboolean fromServer = false;
-
- if (cmd_source == src_command)
- {
- if (cls.state == ca_dedicated)
- {
- fromServer = true;
- teamonly = false;
- }
- else
- {
- Cmd_ForwardToServer ();
- return;
- }
- }
-
- if (Cmd_Argc () < 2)
- return;
-
- if (!teamplay.integer)
- teamonly = false;
-
- p1 = Cmd_Args();
- quoted = false;
- if (*p1 == '\"')
- {
- quoted = true;
- p1++;
- }
- // note this uses the chat prefix \001
- 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> %s", sv_adminnick.string, p1);
- else
- 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)))
- {
- if (p2[-1] == '\"' && quoted)
- quoted = false;
- p2[-1] = 0;
- p2--;
- }
- strlcat(text, "\n", sizeof(text));
-
- // 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->active && (!teamonly || host_client->edict->fields.server->team == save->edict->fields.server->team))
- SV_ClientPrint(text);
- host_client = save;
-
- if (cls.state == ca_dedicated)
- Con_Print(&text[1]);
-}
-
-
-void Host_Say_f(void)
-{
- Host_Say(false);
-}
-
-
-void Host_Say_Team_f(void)
-{
- Host_Say(true);
-}
-
-
-void Host_Tell_f(void)
-{
- const char *playername_start = NULL;
- size_t playername_length = 0;
- int playernumber = 0;
- client_t *save;
- int j;
- const char *p1, *p2;
- char text[MAX_INPUTLINE]; // LordHavoc: FIXME: temporary buffer overflow fix (was 64)
- qboolean fromServer = false;
-
- if (cmd_source == src_command)
- {
- if (cls.state == ca_dedicated)
- fromServer = true;
- else
- {
- Cmd_ForwardToServer ();
- return;
- }
- }
-
- if (Cmd_Argc () < 2)
- return;
-
- // note this uses the chat prefix \001
- if (!fromServer)
- dpsnprintf (text, sizeof(text), "\001%s tells you: ", host_client->name);
- else if(*(sv_adminnick.string))
- dpsnprintf (text, sizeof(text), "\001<%s tells you> ", sv_adminnick.string);
- else
- dpsnprintf (text, sizeof(text), "\001<%s tells you> ", hostname.string);
-
- p1 = Cmd_Args();
- p2 = p1 + strlen(p1);
- // remove the target name
- while (p1 < p2 && *p1 == ' ')
- p1++;
- if(*p1 == '#')
- {
- ++p1;
- while (p1 < p2 && *p1 == ' ')
- p1++;
- while (p1 < p2 && isdigit(*p1))
- {
- playernumber = playernumber * 10 + (*p1 - '0');
- p1++;
- }
- --playernumber;
- }
- else if(*p1 == '"')
- {
- ++p1;
- playername_start = p1;
- while (p1 < p2 && *p1 != '"')
- p1++;
- playername_length = p1 - playername_start;
- if(p1 < p2)
- p1++;
- }
- else
- {
- playername_start = p1;
- while (p1 < p2 && *p1 != ' ')
- p1++;
- playername_length = p1 - playername_start;
- }
- while (p1 < p2 && *p1 == ' ')
- p1++;
- if(playername_start)
- {
- // set playernumber to the right client
- char namebuf[128];
- if(playername_length >= sizeof(namebuf))
- {
- if (fromServer)
- Con_Print("Host_Tell: too long player name/ID\n");
- else
- SV_ClientPrint("Host_Tell: too long player name/ID\n");
- return;
- }
- memcpy(namebuf, playername_start, playername_length);
- namebuf[playername_length] = 0;
- for (playernumber = 0; playernumber < svs.maxclients; playernumber++)
- {
- if (!svs.clients[playernumber].active)
- continue;
- if (strcasecmp(svs.clients[playernumber].name, namebuf) == 0)
- break;
- }
- }
- if(playernumber < 0 || playernumber >= svs.maxclients || !(svs.clients[playernumber].active))
- {
- if (fromServer)
- Con_Print("Host_Tell: invalid player name/ID\n");
- else
- SV_ClientPrint("Host_Tell: invalid player name/ID\n");
- return;
- }
- // remove trailing newlines
- while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
- p2--;
- // remove quotes if present
- if (*p1 == '"')
- {
- p1++;
- if (p2[-1] == '"')
- p2--;
- else if (fromServer)
- Con_Print("Host_Tell: missing end quote\n");
- else
- SV_ClientPrint("Host_Tell: missing end quote\n");
- }
- while (p2 > p1 && (p2[-1] == '\n' || p2[-1] == '\r'))
- p2--;
- if(p1 == p2)
- return; // empty say
- for (j = (int)strlen(text);j < (int)(sizeof(text) - 2) && p1 < p2;)
- text[j++] = *p1++;
- text[j++] = '\n';
- text[j++] = 0;
-
- save = host_client;
- host_client = svs.clients + playernumber;
- SV_ClientPrint(text);
- host_client = save;
-}
-
-
-/*
-==================
-Host_Color_f
-==================
-*/
-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;
-
- // get top and bottom either from the provided values or the current values
- // (allows changing only top or bottom, or both at once)
- top = changetop >= 0 ? changetop : (cl_color.integer >> 4);
- bottom = changebottom >= 0 ? changebottom : cl_color.integer;
-
- top &= 15;
- bottom &= 15;
- // LordHavoc: allowing skin colormaps 14 and 15 by commenting this out
- //if (top > 13)
- // top = 13;
- //if (bottom > 13)
- // bottom = 13;
-
- playercolor = top*16 + bottom;
-
- if (cmd_source == src_command)
- {
- Cvar_SetValueQuick(&cl_color, playercolor);
- return;
- }
-
- if (cls.protocol == PROTOCOL_QUAKEWORLD)
- return;
-
- 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(prog->funcoffsets.SV_ChangeTeam, "QC function SV_ChangeTeam is missing");
- }
- else
- {
- prvm_eval_t *val;
- if (host_client->edict)
- {
- if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
- val->_float = playercolor;
- host_client->edict->fields.server->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);
- }
- }
-}
-
-void Host_Color_f(void)
-{
- int top, bottom;
-
- if (Cmd_Argc() == 1)
- {
- Con_Printf("\"color\" is \"%i %i\"\n", cl_color.integer >> 4, cl_color.integer & 15);
- Con_Print("color <0-15> [0-15]\n");
- return;
- }
-
- if (Cmd_Argc() == 2)
- top = bottom = atoi(Cmd_Argv(1));
- else
- {
- top = atoi(Cmd_Argv(1));
- bottom = atoi(Cmd_Argv(2));
- }
- Host_Color(top, bottom);
-}
-
-void Host_TopColor_f(void)
-{
- if (Cmd_Argc() == 1)
- {
- Con_Printf("\"topcolor\" is \"%i\"\n", (cl_color.integer >> 4) & 15);
- Con_Print("topcolor <0-15>\n");
- return;
- }
-
- Host_Color(atoi(Cmd_Argv(1)), -1);
-}
-
-void Host_BottomColor_f(void)
-{
- if (Cmd_Argc() == 1)
- {
- Con_Printf("\"bottomcolor\" is \"%i\"\n", cl_color.integer & 15);
- Con_Print("bottomcolor <0-15>\n");
- return;
- }
-
- Host_Color(-1, atoi(Cmd_Argv(1)));
-}
-
-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;
-
- if (Cmd_Argc() != 2)
- {
- Con_Printf("\"rate\" is \"%i\"\n", cl_rate.integer);
- Con_Print("rate <bytespersecond>\n");
- return;
- }
-
- rate = atoi(Cmd_Argv(1));
-
- if (cmd_source == src_command)
- {
- Cvar_SetValue ("_cl_rate", max(NET_MINRATE, rate));
- return;
- }
-
- host_client->rate = rate;
-}
-
-/*
-==================
-Host_Kill_f
-==================
-*/
-void Host_Kill_f (void)
-{
- if (host_client->edict->fields.server->health <= 0)
- {
- SV_ClientPrint("Can't suicide -- already dead!\n");
- return;
- }
-
- prog->globals.server->time = sv.time;
- prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
- PRVM_ExecuteProgram (prog->globals.server->ClientKill, "QC function ClientKill is missing");
-}
-
-
-/*
-==================
-Host_Pause_f
-==================
-*/
-void Host_Pause_f (void)
-{
- if (!pausable.integer)
- SV_ClientPrint("Pause not allowed.\n");
- else
- {
- sv.paused ^= 1;
- SV_BroadcastPrintf("%s %spaused the game\n", host_client->name, sv.paused ? "" : "un");
- // send notification to all clients
- MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
- MSG_WriteByte(&sv.reliable_datagram, sv.paused);
- }
-}
-
-/*
-======================
-Host_PModel_f
-LordHavoc: only supported for Nehahra, I personally think this is dumb, but Mindcrime won't listen.
-LordHavoc: correction, Mindcrime will be removing pmodel in the future, but it's still stuck here for compatibility.
-======================
-*/
-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;
- prvm_eval_t *val;
-
- if (Cmd_Argc () == 1)
- {
- Con_Printf("\"pmodel\" is \"%s\"\n", cl_pmodel.string);
- return;
- }
- i = atoi(Cmd_Argv(1));
-
- if (cmd_source == src_command)
- {
- if (cl_pmodel.integer == i)
- return;
- Cvar_SetValue ("_cl_pmodel", i);
- if (cls.state == ca_connected)
- Cmd_ForwardToServer ();
- return;
- }
-
- if (host_client->edict && (val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.pmodel)))
- val->_float = i;
-}
-
-//===========================================================================
-
-
-/*
-==================
-Host_PreSpawn_f
-==================
-*/
-void Host_PreSpawn_f (void)
-{
- if (host_client->spawned)
- {
- Con_Print("prespawn not valid -- already spawned\n");
- return;
- }
-
- if (host_client->netconnection)
- {
- 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
- host_client->nametime = 0;
-}
-
-/*
-==================
-Host_Spawn_f
-==================
-*/
-void Host_Spawn_f (void)
-{
- int i;
- client_t *client;
- int stats[MAX_CL_STATS];
-
- if (host_client->spawned)
- {
- Con_Print("Spawn not valid -- already spawned\n");
- return;
- }
-
- // reset name change timer again because they might want to change name
- // again in the first 5 seconds after connecting
- host_client->nametime = 0;
-
- // LordHavoc: moved this above the QC calls at FrikaC's request
- // LordHavoc: commented this out
- //if (host_client->netconnection)
- // SZ_Clear (&host_client->netconnection->message);
-
- // run the entrance script
- if (sv.loadgame)
- {
- // loaded games are fully initialized already
- 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(prog->funcoffsets.RestoreGame, "QC function RestoreGame is missing");
- }
- }
- else
- {
- //Con_Printf("Host_Spawn_f: host_client->edict->netname = %s, host_client->edict->netname = %s, host_client->name = %s\n", PRVM_GetString(host_client->edict->fields.server->netname), PRVM_GetString(host_client->edict->fields.server->netname), host_client->name);
-
- // copy spawn parms out of the client_t
- for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
- (&prog->globals.server->parm1)[i] = host_client->spawn_parms[i];
-
- // call the spawn function
- host_client->clientconnectcalled = true;
- prog->globals.server->time = sv.time;
- prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
- PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
-
- if (cls.state == ca_dedicated)
- Con_Printf("%s connected\n", host_client->name);
-
- PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
- }
-
- if (!host_client->netconnection)
- return;
-
- // send time of update
- MSG_WriteByte (&host_client->netconnection->message, svc_time);
- MSG_WriteFloat (&host_client->netconnection->message, sv.time);
-
- // send all current names, colors, and frag counts
- for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
- {
- if (!client->active)
- continue;
- MSG_WriteByte (&host_client->netconnection->message, svc_updatename);
- MSG_WriteByte (&host_client->netconnection->message, i);
- MSG_WriteString (&host_client->netconnection->message, client->name);
- MSG_WriteByte (&host_client->netconnection->message, svc_updatefrags);
- MSG_WriteByte (&host_client->netconnection->message, i);
- MSG_WriteShort (&host_client->netconnection->message, client->frags);
- MSG_WriteByte (&host_client->netconnection->message, svc_updatecolors);
- MSG_WriteByte (&host_client->netconnection->message, i);
- MSG_WriteByte (&host_client->netconnection->message, client->colors);
- }
-
- // send all current light styles
- for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
- {
- if (sv.lightstyles[i][0])
- {
- MSG_WriteByte (&host_client->netconnection->message, svc_lightstyle);
- MSG_WriteByte (&host_client->netconnection->message, (char)i);
- MSG_WriteString (&host_client->netconnection->message, sv.lightstyles[i]);
- }
- }
-
- // send some stats
- MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
- MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALSECRETS);
- MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_secrets);
-
- MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
- MSG_WriteByte (&host_client->netconnection->message, STAT_TOTALMONSTERS);
- MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->total_monsters);
-
- MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
- MSG_WriteByte (&host_client->netconnection->message, STAT_SECRETS);
- MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->found_secrets);
-
- MSG_WriteByte (&host_client->netconnection->message, svc_updatestat);
- MSG_WriteByte (&host_client->netconnection->message, STAT_MONSTERS);
- MSG_WriteLong (&host_client->netconnection->message, (int)prog->globals.server->killed_monsters);
-
- // send a fixangle
- // Never send a roll angle, because savegames can catch the server
- // in a state where it is expecting the client to correct the angle
- // and it won't happen if the game was just loaded, so you wind up
- // with a permanent head tilt
- if (sv.loadgame)
- {
- MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
- MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[0], sv.protocol);
- MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->v_angle[1], sv.protocol);
- MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
- }
- else
- {
- MSG_WriteByte (&host_client->netconnection->message, svc_setangle);
- MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[0], sv.protocol);
- MSG_WriteAngle (&host_client->netconnection->message, host_client->edict->fields.server->angles[1], sv.protocol);
- MSG_WriteAngle (&host_client->netconnection->message, 0, sv.protocol);
- }
-
- SV_WriteClientdataToMessage (host_client, host_client->edict, &host_client->netconnection->message, stats);
-
- MSG_WriteByte (&host_client->netconnection->message, svc_signonnum);
- MSG_WriteByte (&host_client->netconnection->message, 3);
-}
-
-/*
-==================
-Host_Begin_f
-==================
-*/
-void Host_Begin_f (void)
-{
- host_client->spawned = true;
-
- // LordHavoc: note: this code also exists in SV_DropClient
- if (sv.loadgame)
- {
- int i;
- for (i = 0;i < svs.maxclients;i++)
- if (svs.clients[i].active && !svs.clients[i].spawned)
- break;
- if (i == svs.maxclients)
- {
- Con_Printf("Loaded game, everyone rejoined - unpausing\n");
- sv.paused = sv.loadgame = false; // we're basically done with loading now
- }
- }
-}
-
-//===========================================================================
-
-
-/*
-==================
-Host_Kick_f
-
-Kicks a user off of the server
-==================
-*/
-void Host_Kick_f (void)
-{
- char *who;
- const char *message = NULL;
- client_t *save;
- int i;
- qboolean byNumber = false;
-
- if (!sv.active)
- return;
-
- SV_VM_Begin();
- save = host_client;
-
- if (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), "#") == 0)
- {
- i = (int)(atof(Cmd_Argv(2)) - 1);
- if (i < 0 || i >= svs.maxclients || !(host_client = svs.clients + i)->active)
- return;
- byNumber = true;
- }
- else
- {
- for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
- {
- if (!host_client->active)
- continue;
- if (strcasecmp(host_client->name, Cmd_Argv(1)) == 0)
- break;
- }
- }
-
- if (i < svs.maxclients)
- {
- if (cmd_source == src_command)
- {
- if (cls.state == ca_dedicated)
- who = "Console";
- else
- who = cl_name.string;
- }
- else
- who = save->name;
-
- // can't kick yourself!
- if (host_client == save)
- return;
-
- if (Cmd_Argc() > 2)
- {
- message = Cmd_Args();
- COM_ParseToken_Simple(&message, false, false);
- if (byNumber)
- {
- message++; // skip the #
- while (*message == ' ') // skip white space
- message++;
- message += strlen(Cmd_Argv(2)); // skip the number
- }
- while (*message && *message == ' ')
- message++;
- }
- if (message)
- SV_ClientPrintf("Kicked by %s: %s\n", who, message);
- else
- SV_ClientPrintf("Kicked by %s\n", who);
- SV_DropClient (false); // kicked
- }
-
- host_client = save;
- SV_VM_End();
-}
-
-/*
-===============================================================================
-
-DEBUGGING TOOLS
-
-===============================================================================
-*/
-
-/*
-==================
-Host_Give_f
-==================
-*/
-void Host_Give_f (void)
-{
- const char *t;
- int v;
- prvm_eval_t *val;
-
- if (!allowcheats)
- {
- SV_ClientPrint("No cheats allowed, use sv_cheats 1 and restart level to enable.\n");
- return;
- }
-
- t = Cmd_Argv(1);
- v = atoi (Cmd_Argv(2));
-
- switch (t[0])
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- // MED 01/04/97 added hipnotic give stuff
- if (gamemode == GAME_HIPNOTIC)
- {
- if (t[0] == '6')
- {
- if (t[1] == 'a')
- host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_PROXIMITY_GUN;
- else
- host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | IT_GRENADE_LAUNCHER;
- }
- else if (t[0] == '9')
- host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_LASER_CANNON;
- else if (t[0] == '0')
- host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | HIT_MJOLNIR;
- else if (t[0] >= '2')
- host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
- }
- else
- {
- if (t[0] >= '2')
- host_client->edict->fields.server->items = (int)host_client->edict->fields.server->items | (IT_SHOTGUN << (t[0] - '2'));
- }
- break;
-
- case 's':
- 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;
- break;
- case 'n':
- if (gamemode == GAME_ROGUE)
- {
- if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_nails1)))
- {
- val->_float = v;
- if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
- host_client->edict->fields.server->ammo_nails = v;
- }
- }
- else
- {
- host_client->edict->fields.server->ammo_nails = v;
- }
- break;
- case 'l':
- if (gamemode == GAME_ROGUE)
- {
- val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_lava_nails);
- if (val)
- {
- val->_float = v;
- if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
- host_client->edict->fields.server->ammo_nails = v;
- }
- }
- break;
- case 'r':
- if (gamemode == GAME_ROGUE)
- {
- val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_rockets1);
- if (val)
- {
- val->_float = v;
- if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
- host_client->edict->fields.server->ammo_rockets = v;
- }
- }
- else
- {
- host_client->edict->fields.server->ammo_rockets = v;
- }
- break;
- case 'm':
- if (gamemode == GAME_ROGUE)
- {
- val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_multi_rockets);
- if (val)
- {
- val->_float = v;
- if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
- host_client->edict->fields.server->ammo_rockets = v;
- }
- }
- break;
- case 'h':
- host_client->edict->fields.server->health = v;
- break;
- case 'c':
- if (gamemode == GAME_ROGUE)
- {
- val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_cells1);
- if (val)
- {
- val->_float = v;
- if (host_client->edict->fields.server->weapon <= IT_LIGHTNING)
- host_client->edict->fields.server->ammo_cells = v;
- }
- }
- else
- {
- host_client->edict->fields.server->ammo_cells = v;
- }
- break;
- case 'p':
- if (gamemode == GAME_ROGUE)
- {
- val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.ammo_plasma);
- if (val)
- {
- val->_float = v;
- if (host_client->edict->fields.server->weapon > IT_LIGHTNING)
- host_client->edict->fields.server->ammo_cells = v;
- }
- }
- break;
- }
-}