📄 host_cmd.c
字号:
/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "quakedef.h"
extern cvar_t *pausable;
extern cvar_t *contact; // 2000-01-31 Contact cvar by Maddes
int current_skill;
void Mod_Print (void);
// 2000-01-09 QCExec by FrikaC/Maddes start
/*
==================
Host_QC_Exec_f
Execute QC commands from the console
==================
*/
void Host_QC_Exec_f (void)
{
dfunction_t *f;
int num;
edict_t *e;
void (*print) (char *fmt, ...);
if (cmd_source == src_command)
{
if (cls.state != ca_dedicated) // not a dedicated server
{
Cmd_ForwardToServer (); // client forgot to add "cmd", so forward to server
return; // this a server only command, sorry
}
print = Con_Printf; // directly print to dedicated server console
}
else
{
print = SV_ClientPrintf; // print to client's console
}
if (!developer->value)
{
print ("Developer only functionality\n");
return;
}
if (Cmd_Argc() < 2)
{
print ("Syntax: qcexec <qc function> [self [other]]\n-1 is this client\n%i Entities available\n", sv.num_edicts);
return;
}
f = 0;
if ((f = ED_FindFunction(Cmd_Argv(1))) != NULL)
{
pr_global_struct->self = EDICT_TO_PROG(sv.edicts); // initialize with world
pr_global_struct->other = EDICT_TO_PROG(sv.edicts); // initialize with world
if (Cmd_Argc() > 2)
{
num = Q_atoi(Cmd_Argv(2));
if (num == -1)
{
if (cmd_source == src_command) // called from dedicated server console
{
print ("Parameter -1 only valid from clients\n", num);
return;
}
pr_global_struct->self = EDICT_TO_PROG(sv_player);
}
else if (num < 0 || num >= sv.num_edicts)
{
print ("Entity %i for self does not exist\n", num);
return;
}
else
{
e = EDICT_NUM(num);
pr_global_struct->self = EDICT_TO_PROG(e);
}
}
if (Cmd_Argc() > 3)
{
num = Q_atoi(Cmd_Argv(3));
if (num == -1)
{
if (cmd_source == src_command) // called from dedicated server console
{
print ("Parameter -1 only valid from clients\n", num);
return;
}
pr_global_struct->other = EDICT_TO_PROG(sv_player);
}
else if (num < 0 || num >= sv.num_edicts)
{
print ("Entity %i for other does not exist\n", num);
return;
}
else
{
e = EDICT_NUM(num);
pr_global_struct->other = EDICT_TO_PROG(e);
}
}
print ("Executing QuakeC function...\n"); // 2000-07-30 compiler warning fix by Norberto Alfredo Bensa/Maddes
PR_ExecuteProgram ((func_t)(f - pr_functions));
print ("...QuakeC function done\n"); // 2000-07-30 compiler warning fix by Norberto Alfredo Bensa/Maddes
}
else
{
print ("QuakeC function \"%s\" does not exist\n", Cmd_Argv(1));
}
}
// 2000-01-09 QCExec by FrikaC/Maddes end
/*
==================
Host_Quit_f
==================
*/
extern void M_Menu_Quit_f (void);
void Host_Quit_f (void)
{
if (key_dest != key_console && cls.state != ca_dedicated)
{
M_Menu_Quit_f ();
return;
}
CL_Disconnect ();
Host_ShutdownServer(false);
Sys_Quit ();
}
/*
==================
Host_Status_f
==================
*/
void Host_Status_f (void)
{
client_t *client;
int seconds;
int minutes;
int hours = 0;
int j;
void (*print) (char *fmt, ...);
if (cmd_source == src_command)
{
if (!sv.active)
{
Cmd_ForwardToServer ();
return;
}
print = Con_Printf;
}
else
print = SV_ClientPrintf;
print ("Host: %s\n", hostname->string); // 2001-09-18 New cvar system by Maddes
print ("Version: %1.2f (%s)\n", VERSION, QIP_VERSION); // 2001-10-25 QIP version in the console background by Maddes
if (tcpipAvailable)
print ("TCP/IP: %s\n", my_tcpip_address);
if (ipxAvailable)
print ("IPX: %s\n", my_ipx_address);
print ("Map: %s\n", sv.name);
print ("Players: %i active (%i max)\n\n", net_activeconnections, svs.maxclients);
for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
{
if (!client->active)
continue;
seconds = (int)(net_time - client->netconnection->connecttime);
minutes = seconds / 60;
if (minutes)
{
seconds -= (minutes * 60);
hours = minutes / 60;
if (hours)
minutes -= (hours * 60);
}
else
hours = 0;
// 2000-04-30 NVS COMMON by Maddes start
// print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", j+1, client->name, (int)client->edict->v.frags, hours, minutes, seconds);
print ("#%-2u %-16.16s %3i %2i:%02i:%02i %1.2f/%1.2f/%1.2f\n", j+1, client->name, (int)client->edict->v.frags, hours, minutes, seconds, client->nvs_csvc, client->nvs_cclc, client->nvs_cmax);
// 2000-04-30 NVS COMMON by Maddes end
print (" %s\n", client->netconnection->address);
}
}
/*
==================
Host_God_f
Sets client to godmode
==================
*/
void Host_God_f (void)
{
if (cmd_source == src_command)
{
Cmd_ForwardToServer ();
return;
}
if (pr_global_struct->deathmatch && !host_client->privileged)
return;
sv_player->v.flags = (int)sv_player->v.flags ^ FL_GODMODE;
if (!((int)sv_player->v.flags & FL_GODMODE) )
SV_ClientPrintf ("godmode OFF\n");
else
SV_ClientPrintf ("godmode ON\n");
}
void Host_Notarget_f (void)
{
if (cmd_source == src_command)
{
Cmd_ForwardToServer ();
return;
}
if (pr_global_struct->deathmatch && !host_client->privileged)
return;
sv_player->v.flags = (int)sv_player->v.flags ^ FL_NOTARGET;
if (!((int)sv_player->v.flags & FL_NOTARGET) )
SV_ClientPrintf ("notarget OFF\n");
else
SV_ClientPrintf ("notarget ON\n");
}
qboolean noclip_anglehack;
void Host_Noclip_f (void)
{
if (cmd_source == src_command)
{
Cmd_ForwardToServer ();
return;
}
if (pr_global_struct->deathmatch && !host_client->privileged)
return;
if (sv_player->v.movetype != MOVETYPE_NOCLIP)
{
noclip_anglehack = true;
sv_player->v.movetype = MOVETYPE_NOCLIP;
SV_ClientPrintf ("noclip ON\n");
}
else
{
noclip_anglehack = false;
sv_player->v.movetype = MOVETYPE_WALK;
SV_ClientPrintf ("noclip OFF\n");
}
}
/*
==================
Host_Fly_f
Sets client to flymode
==================
*/
void Host_Fly_f (void)
{
if (cmd_source == src_command)
{
Cmd_ForwardToServer ();
return;
}
if (pr_global_struct->deathmatch && !host_client->privileged)
return;
if (sv_player->v.movetype != MOVETYPE_FLY)
{
sv_player->v.movetype = MOVETYPE_FLY;
SV_ClientPrintf ("flymode ON\n");
}
else
{
sv_player->v.movetype = MOVETYPE_WALK;
SV_ClientPrintf ("flymode OFF\n");
}
}
/*
==================
Host_Ping_f
==================
*/
void Host_Ping_f (void)
{
int i, j;
float total;
client_t *client;
if (cmd_source == src_command)
{
Cmd_ForwardToServer ();
return;
}
SV_ClientPrintf ("Client ping times:\n");
for (i=0, client = svs.clients ; i<svs.maxclients ; i++, client++)
{
if (!client->active)
continue;
total = 0;
for (j=0 ; j<NUM_PING_TIMES ; j++)
total+=client->ping_times[j];
total /= NUM_PING_TIMES;
SV_ClientPrintf ("%4i %s\n", (int)(total*1000), client->name);
}
}
/*
===============================================================================
SERVER TRANSITIONS
===============================================================================
*/
/*
======================
Host_Map_f
handle a
map <servername>
command from the console. Active clients are kicked off.
======================
*/
void Host_Map_f (void)
{
int i;
char name[MAX_QPATH];
if (cmd_source != src_command)
return;
cls.demonum = -1; // stop demo loop in case this fails
CL_Disconnect ();
Host_ShutdownServer(false);
key_dest = key_game; // remove console or menu
SCR_BeginLoadingPlaque ();
cls.mapstring[0] = 0;
for (i=0 ; i<Cmd_Argc() ; i++)
{
strcat (cls.mapstring, Cmd_Argv(i));
strcat (cls.mapstring, " ");
}
strcat (cls.mapstring, "\n");
svs.serverflags = 0; // haven't completed an episode yet
strcpy (name, Cmd_Argv(1));
#ifdef QUAKE2
SV_SpawnServer (name, NULL);
#else
SV_SpawnServer (name);
#endif
if (!sv.active)
return;
if (cls.state != ca_dedicated)
{
strcpy (cls.spawnparms, "");
for (i=2 ; i<Cmd_Argc() ; i++)
{
strcat (cls.spawnparms, Cmd_Argv(i));
strcat (cls.spawnparms, " ");
}
Cmd_ExecuteString ("connect local", src_command);
}
}
/*
==================
Host_Changelevel_f
Goes to a new map, taking all clients along
==================
*/
void Host_Changelevel_f (void)
{
#ifdef QUAKE2
char level[MAX_QPATH];
char _startspot[MAX_QPATH];
char *startspot;
if (Cmd_Argc() < 2)
{
Con_Printf ("changelevel <levelname> : continue game on a new level\n");
return;
}
if (!sv.active || cls.demoplayback)
{
Con_Printf ("Only the server may changelevel\n");
return;
}
strcpy (level, Cmd_Argv(1));
if (Cmd_Argc() == 2)
startspot = NULL;
else
{
strcpy (_startspot, Cmd_Argv(2));
startspot = _startspot;
}
SV_SaveSpawnparms ();
SV_SpawnServer (level, startspot);
#else
char level[MAX_QPATH];
if (Cmd_Argc() != 2)
{
Con_Printf ("changelevel <levelname> : continue game on a new level\n");
return;
}
if (!sv.active || cls.demoplayback)
{
Con_Printf ("Only the server may changelevel\n");
return;
}
SV_SaveSpawnparms ();
strcpy (level, Cmd_Argv(1));
SV_SpawnServer (level);
#endif
}
/*
==================
Host_Restart_f
Restarts the current server for a dead player
==================
*/
void Host_Restart_f (void)
{
char mapname[MAX_QPATH];
#ifdef QUAKE2
char startspot[MAX_QPATH];
#endif
if (cls.demoplayback || !sv.active)
return;
if (cmd_source != src_command)
return;
strcpy (mapname, sv.name); // must copy out, because it gets cleared
// in sv_spawnserver
#ifdef QUAKE2
strcpy(startspot, sv.startspot);
SV_SpawnServer (mapname, startspot);
#else
SV_SpawnServer (mapname);
#endif
}
/*
==================
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)
{
SCR_BeginLoadingPlaque ();
cls.signon = 0; // need new connection messages
}
/*
=====================
Host_Connect_f
User command to connect to server
=====================
*/
void Host_Connect_f (void)
{
char name[MAX_QPATH];
cls.demonum = -1; // stop demo loop in case this fails
if (cls.demoplayback)
{
CL_StopPlayback ();
CL_Disconnect ();
}
strcpy (name, Cmd_Argv(1));
CL_EstablishConnection (name);
Host_Reconnect_f ();
}
/*
===============================================================================
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 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
text[i] = ' ';
memcpy (text, cl.levelname, strlen(cl.levelname));
sprintf (kills,"kills:%3i/%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);
memcpy (text+22, kills, strlen(kills));
// convert space to _ to make stdio happy
for (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)
if (text[i] == ' ')
text[i] = '_';
text[SAVEGAME_COMMENT_LENGTH] = '\0';
}
/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -