📄 cl_main.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.
*/
// cl_main.c -- client main loop
#include "quakedef.h"
// we need to declare some mouse variables here, because the menu system
// references them even when on a unix system.
// these two are not intended to be set directly
cvar_t *cl_name;
cvar_t *cl_color;
cvar_t *cl_shownet; // can be 0, 1, or 2
cvar_t *cl_nolerp;
cvar_t *lookspring;
cvar_t *lookstrafe;
cvar_t *sensitivity;
cvar_t *m_pitch;
cvar_t *m_yaw;
cvar_t *m_forward;
cvar_t *m_side;
cvar_t *m_look; // 2001-12-16 M_LOOK cvar by Heffo/Maddes
cvar_t *cl_showfps; // 2001-11-31 FPS display by QuakeForge/Muff
cvar_t *cl_compatibility; // 2001-12-24 Keeping full backwards compatibility by Maddes
// 2001-09-20 Configurable entity limits by Maddes start
cvar_t *cl_entities_min;
cvar_t *cl_entities_min_static;
cvar_t *cl_entities_min_temp;
// 2001-09-20 Configurable entity limits by Maddes end
client_static_t cls;
client_state_t cl;
// FIXME: put these on hunk?
efrag_t cl_efrags[MAX_EFRAGS];
// 2001-09-20 Configurable entity limits by Maddes start
/*
entity_t cl_entities[MAX_EDICTS];
entity_t cl_static_entities[MAX_STATIC_ENTITIES];
*/
entity_t *cl_entities;
entity_t *cl_static_entities;
// 2001-09-20 Configurable entity limits by Maddes end
lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
dlight_t cl_dlights[MAX_DLIGHTS];
int cl_numvisedicts;
entity_t *cl_visedicts[MAX_VISEDICTS];
/*
=====================
CL_ClearState
=====================
*/
void CL_ClearState (void)
{
int i;
if (!sv.active)
Host_ClearMemory ();
// wipe the entire cl structure
memset (&cl, 0, sizeof(cl));
SZ_Clear (&cls.message);
// clear other arrays
memset (cl_efrags, 0, sizeof(cl_efrags));
// memset (cl_entities, 0, sizeof(cl_entities)); // 2001-09-20 Configurable entity limits by Maddes
memset (cl_dlights, 0, sizeof(cl_dlights));
memset (cl_lightstyle, 0, sizeof(cl_lightstyle));
// memset (cl_temp_entities, 0, sizeof(cl_temp_entities)); // 2001-09-20 Configurable entity limits by Maddes
memset (cl_beams, 0, sizeof(cl_beams));
//
// allocate the efrags and chain together into a free list
//
cl.free_efrags = cl_efrags;
for (i=0 ; i<MAX_EFRAGS-1 ; i++)
cl.free_efrags[i].entnext = &cl.free_efrags[i+1];
cl.free_efrags[i].entnext = NULL;
}
/*
=====================
CL_Disconnect
Sends a disconnect message to the server
This is also called on Host_Error, so it shouldn't cause any errors
=====================
*/
void CL_Disconnect (void)
{
// stop sounds (especially looping!)
S_StopAllSounds (true);
// bring the console down and fade the colors back to normal
// SCR_BringDownConsole ();
// if running a local server, shut it down
if (cls.demoplayback)
CL_StopPlayback ();
else if (cls.state == ca_connected)
{
if (cls.demorecording)
CL_Stop_f ();
Con_DPrintf ("Sending clc_disconnect\n");
SZ_Clear (&cls.message);
MSG_WriteByte (&cls.message, clc_disconnect);
NET_SendUnreliableMessage (cls.netcon, &cls.message);
SZ_Clear (&cls.message);
NET_Close (cls.netcon);
cls.state = ca_disconnected;
if (sv.active)
Host_ShutdownServer(false);
}
cls.demoplayback = cls.timedemo = false;
cls.signon = 0;
}
void CL_Disconnect_f (void)
{
CL_Disconnect ();
if (sv.active)
Host_ShutdownServer (false);
}
/*
=====================
CL_EstablishConnection
Host should be either "local" or a net address to be passed on
=====================
*/
void CL_EstablishConnection (char *host)
{
if (cls.state == ca_dedicated)
return;
if (cls.demoplayback)
return;
CL_Disconnect ();
cls.netcon = NET_Connect (host);
if (!cls.netcon)
Host_Error ("CL_Connect: connect failed");
Con_DPrintf ("CL_EstablishConnection: connected to %s\n", host);
cls.demonum = -1; // not in the demo loop now
cls.state = ca_connected;
cls.signon = 0; // need all the signon messages before playing
}
/*
=====================
CL_SignonReply
An svc_signonnum has been received, perform a client side setup
=====================
*/
void CL_SignonReply (void)
{
char str[8192];
Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
switch (cls.signon)
{
case 1:
// 2000-04-30 NVS HANDSHAKE SRV<->CL by Maddes start
if (!sv.active)
{
Cvar_Set(nvs_current_ssvc, "0");
}
Cvar_Set(nvs_current_csvc, "0");
Cvar_Set(nvs_current_cclc, "0");
// 2001-12-24 Keeping full backwards compatibility by Maddes start
if (!(cl_compatibility->value)) // request, unlike the original Quake executable
{
// 2001-12-24 Keeping full backwards compatibility by Maddes end
MSG_WriteByte (&cls.message, clc_stringcmd);
MSG_WriteString (&cls.message, va("nvs_request %1.2f\n", nvs_current_cclc->maxvalue));
} // 2001-12-24 Keeping full backwards compatibility by Maddes
// 2000-04-30 NVS HANDSHAKE SRV<->CL by Maddes end
// 2001-09-20 Configurable limits by Maddes start
// 2001-09-20 Configurable entity limits by Maddes start
cl.max_edicts = 0;
cl.max_static_edicts = 0;
cl.max_temp_edicts = 0;
cl_entities = NULL;
cl_static_entities = NULL;
cl_temp_entities = NULL;
// 2001-09-20 Configurable entity limits by Maddes end
// 2001-12-24 Keeping full backwards compatibility by Maddes start
if (!(cl_compatibility->value)) // request, unlike the original Quake executable
{
// 2001-12-24 Keeping full backwards compatibility by Maddes end
MSG_WriteByte (&cls.message, clc_stringcmd);
MSG_WriteString (&cls.message, "limit_request\n");
} // 2001-12-24 Keeping full backwards compatibility by Maddes
// 2001-09-20 Configurable limits by Maddes end
MSG_WriteByte (&cls.message, clc_stringcmd);
MSG_WriteString (&cls.message, "prespawn\n");
break;
case 2:
MSG_WriteByte (&cls.message, clc_stringcmd);
MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name->string));
MSG_WriteByte (&cls.message, clc_stringcmd);
MSG_WriteString (&cls.message, va("color %i %i\n", ((int)cl_color->value)>>4, ((int)cl_color->value)&15));
MSG_WriteByte (&cls.message, clc_stringcmd);
sprintf (str, "spawn %s\n", cls.spawnparms);
MSG_WriteString (&cls.message, str);
break;
case 3:
MSG_WriteByte (&cls.message, clc_stringcmd);
MSG_WriteString (&cls.message, "begin\n");
Cache_Report (); // print remaining memory
break;
case 4:
SCR_EndLoadingPlaque (); // allow normal screen updates
break;
}
}
/*
=====================
CL_NextDemo
Called to play the next demo in the demo loop
=====================
*/
void CL_NextDemo (void)
{
char str[1024];
if (cls.demonum == -1)
return; // don't play demos
SCR_BeginLoadingPlaque ();
if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS)
{
cls.demonum = 0;
if (!cls.demos[cls.demonum][0])
{
Con_Printf ("No demos listed with startdemos\n");
cls.demonum = -1;
return;
}
}
sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]);
Cbuf_InsertText (str);
cls.demonum++;
}
/*
==============
CL_PrintEntities_f
==============
*/
void CL_PrintEntities_f (void)
{
entity_t *ent;
int i;
for (i=0,ent=cl_entities ; i<cl.num_entities ; i++,ent++)
{
Con_Printf ("%3i:",i);
if (!ent->model)
{
Con_Printf ("EMPTY\n");
continue;
}
Con_Printf ("%s:%2i (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n"
,ent->model->name,ent->frame, ent->origin[0], ent->origin[1], ent->origin[2], ent->angles[0], ent->angles[1], ent->angles[2]);
}
}
/*
===============
SetPal
Debugging tool, just flashes the screen
===============
*/
void SetPal (int i)
{
#if 0
static int old;
byte pal[768];
int c;
if (i == old)
return;
old = i;
if (i==0)
VID_SetPalette (host_basepal);
else if (i==1)
{
for (c=0 ; c<768 ; c+=3)
{
pal[c] = 0;
pal[c+1] = 255;
pal[c+2] = 0;
}
VID_SetPalette (pal);
}
else
{
for (c=0 ; c<768 ; c+=3)
{
pal[c] = 0;
pal[c+1] = 0;
pal[c+2] = 255;
}
VID_SetPalette (pal);
}
#endif
}
/*
===============
CL_AllocDlight
===============
*/
dlight_t *CL_AllocDlight (int key)
{
int i;
dlight_t *dl;
// first look for an exact key match
if (key)
{
dl = cl_dlights;
for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
{
if (dl->key == key)
{
memset (dl, 0, sizeof(*dl));
dl->key = key;
// 2001-09-11 Colored lightning by LordHavoc/Sarcazm/Maddes start
dl->color[0] = dl->color[1] = dl->color[2] = 1.0f;
dl->flashcolor[0] = 1.0f;
dl->flashcolor[1] = 0.5f;
dl->flashcolor[2] = 0.0f;
dl->flashcolor[3] = 0.2f;
// 2001-09-11 Colored lightning by LordHavoc/Sarcazm/Maddes end
return dl;
}
}
}
// then look for anything else
dl = cl_dlights;
for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
{
if (dl->die < cl.time)
{
memset (dl, 0, sizeof(*dl));
dl->key = key;
// 2001-09-11 Colored lightning by LordHavoc/Sarcazm/Maddes start
dl->color[0] = dl->color[1] = dl->color[2] = 1.0f;
dl->flashcolor[0] = 1.0f;
dl->flashcolor[1] = 0.5f;
dl->flashcolor[2] = 0.0f;
dl->flashcolor[3] = 0.2f;
// 2001-09-11 Colored lightning by LordHavoc/Sarcazm/Maddes end
return dl;
}
}
dl = &cl_dlights[0];
memset (dl, 0, sizeof(*dl));
dl->key = key;
// 2001-09-11 Colored lightning by LordHavoc/Sarcazm/Maddes start
dl->color[0] = dl->color[1] = dl->color[2] = 1.0f;
dl->flashcolor[0] = 1.0f;
dl->flashcolor[1] = 0.5f;
dl->flashcolor[2] = 0.0f;
dl->flashcolor[3] = 0.2f;
// 2001-09-11 Colored lightning by LordHavoc/Sarcazm/Maddes end
return dl;
}
/*
===============
CL_DecayLights
===============
*/
void CL_DecayLights (void)
{
int i;
dlight_t *dl;
float time;
time = cl.time - cl.oldtime;
dl = cl_dlights;
for (i=0 ; i<MAX_DLIGHTS ; i++, dl++)
{
if (dl->die < cl.time || !dl->radius)
continue;
dl->radius -= time*dl->decay;
if (dl->radius < 0)
dl->radius = 0;
}
}
/*
===============
CL_LerpPoint
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -