📄 cl_main.pas
字号:
begin
//Yet another hack to let old demos work
//the old precache sequence
if (Cmd_Argc() < 2) then begin
CM_LoadMap (cl.configstrings[CS_MODELS+1], true, map_checksum);
CL_RegisterSounds ();
CL_PrepRefresh ();
exit;
end;
precache_check := CS_MODELS;
precache_spawncount := StrToInt(Cmd_Argv(1));
precache_model := nil;
precache_model_skin := 0;
CL_RequestNextDownload();
end;
(*
=================
CL_InitLocal
=================
*)
procedure CL_InitLocal;
begin
cls.state := ca_disconnected;
cls.realtime := Sys_Milliseconds ();
CL_InitInput ();
adr0 := Cvar_Get( 'adr0', '', CVAR_ARCHIVE );
adr1 := Cvar_Get( 'adr1', '', CVAR_ARCHIVE );
adr2 := Cvar_Get( 'adr2', '', CVAR_ARCHIVE );
adr3 := Cvar_Get( 'adr3', '', CVAR_ARCHIVE );
adr4 := Cvar_Get( 'adr4', '', CVAR_ARCHIVE );
adr5 := Cvar_Get( 'adr5', '', CVAR_ARCHIVE );
adr6 := Cvar_Get( 'adr6', '', CVAR_ARCHIVE );
adr7 := Cvar_Get( 'adr7', '', CVAR_ARCHIVE );
adr8 := Cvar_Get( 'adr8', '', CVAR_ARCHIVE );
//
// register our variables
//
cl_stereo_separation := Cvar_Get( 'cl_stereo_separation', '0.4', CVAR_ARCHIVE );
cl_stereo := Cvar_Get( 'cl_stereo', '0', 0 );
cl_add_blend := Cvar_Get ('cl_blend', '1', 0);
cl_add_lights := Cvar_Get ('cl_lights', '1', 0);
cl_add_particles := Cvar_Get ('cl_particles', '1', 0);
cl_add_entities := Cvar_Get ('cl_entities', '1', 0);
cl_gun := Cvar_Get ('cl_gun', '1', 0);
cl_footsteps := Cvar_Get ('cl_footsteps', '1', 0);
cl_noskins := Cvar_Get ('cl_noskins', '0', 0);
cl_autoskins := Cvar_Get ('cl_autoskins', '0', 0);
cl_predict := Cvar_Get ('cl_predict', '1', 0);
// cl_minfps := Cvar_Get ('cl_minfps', '5', 0);
cl_maxfps := Cvar_Get ('cl_maxfps', '90', 0);
cl_upspeed := Cvar_Get ('cl_upspeed', '200', 0);
cl_forwardspeed := Cvar_Get ('cl_forwardspeed', '200', 0);
cl_sidespeed := Cvar_Get ('cl_sidespeed', '200', 0);
cl_yawspeed := Cvar_Get ('cl_yawspeed', '140', 0);
cl_pitchspeed := Cvar_Get ('cl_pitchspeed', '150', 0);
cl_anglespeedkey := Cvar_Get ('cl_anglespeedkey', '1.5', 0);
cl_run := Cvar_Get ('cl_run', '0', CVAR_ARCHIVE);
freelook := Cvar_Get( 'freelook', '0', CVAR_ARCHIVE );
lookspring := Cvar_Get ('lookspring', '0', CVAR_ARCHIVE);
lookstrafe := Cvar_Get ('lookstrafe', '0', CVAR_ARCHIVE);
sensitivity := Cvar_Get ('sensitivity', '3', CVAR_ARCHIVE);
m_pitch := Cvar_Get ('m_pitch', '0.022', CVAR_ARCHIVE);
m_yaw := Cvar_Get ('m_yaw', '0.022', 0);
m_forward := Cvar_Get ('m_forward', '1', 0);
m_side := Cvar_Get ('m_side', '1', 0);
cl_shownet := Cvar_Get ('cl_shownet', '0', 0);
cl_showmiss := Cvar_Get ('cl_showmiss', '0', 0);
cl_showclamp := Cvar_Get ('showclamp', '0', 0);
cl_timeout := Cvar_Get ('cl_timeout', '120', 0);
cl_paused := Cvar_Get ('paused', '0', 0);
cl_timedemo := Cvar_Get ('timedemo', '0', 0);
rcon_client_password := Cvar_Get ('rcon_password', '', 0);
rcon_address := Cvar_Get ('rcon_address', '', 0);
cl_lightlevel := Cvar_Get ('r_lightlevel', '0', 0);
//
// userinfo
//
info_password := Cvar_Get ('password', '', CVAR_USERINFO);
info_spectator := Cvar_Get ('spectator', '0', CVAR_USERINFO);
name := Cvar_Get ('name', 'unnamed', CVAR_USERINFO or CVAR_ARCHIVE);
skin := Cvar_Get ('skin', 'male/grunt', CVAR_USERINFO or CVAR_ARCHIVE);
rate := Cvar_Get ('rate', '25000', CVAR_USERINFO or CVAR_ARCHIVE); // FIXME
msg := Cvar_Get ('msg', '1', CVAR_USERINFO or CVAR_ARCHIVE);
hand := Cvar_Get ('hand', '0', CVAR_USERINFO or CVAR_ARCHIVE);
fov := Cvar_Get ('fov', '90', CVAR_USERINFO or CVAR_ARCHIVE);
gender := Cvar_Get ('gender', 'male', CVAR_USERINFO or CVAR_ARCHIVE);
gender_auto := Cvar_Get ('gender_auto', '1', CVAR_ARCHIVE);
gender.modified := false; // clear this so we know when user sets it manually
cl_vwep := Cvar_Get ('cl_vwep', '1', CVAR_ARCHIVE);
//
// register our commands
//
Cmd_AddCommand ('cmd', CL_ForwardToServer_f);
Cmd_AddCommand ('pause', CL_Pause_f);
Cmd_AddCommand ('pingservers', CL_PingServers_f);
Cmd_AddCommand ('skins', CL_Skins_f);
Cmd_AddCommand ('userinfo', CL_Userinfo_f);
Cmd_AddCommand ('snd_restart', CL_Snd_Restart_f);
Cmd_AddCommand ('changing', CL_Changing_f);
Cmd_AddCommand ('disconnect', CL_Disconnect_f);
Cmd_AddCommand ('record', CL_Record_f);
Cmd_AddCommand ('stop', CL_Stop_f);
Cmd_AddCommand ('quit', CL_Quit_f);
Cmd_AddCommand ('connect', CL_Connect_f);
Cmd_AddCommand ('reconnect', CL_Reconnect_f);
Cmd_AddCommand ('rcon', CL_Rcon_f);
// Cmd_AddCommand ('packet', CL_Packet_f); // this is dangerous to leave in
Cmd_AddCommand ('setenv', CL_Setenv_f );
Cmd_AddCommand ('precache', CL_Precache_f);
Cmd_AddCommand ('download', CL_Download_f);
//
// forward to server commands
//
// the only thing this does is allow command completion
// to work -- all unknown commands are automatically
// forwarded to the server
Cmd_AddCommand ('wave', nil);
Cmd_AddCommand ('inven', nil);
Cmd_AddCommand ('kill', nil);
Cmd_AddCommand ('use', nil);
Cmd_AddCommand ('drop', nil);
Cmd_AddCommand ('say', nil);
Cmd_AddCommand ('say_team', nil);
Cmd_AddCommand ('info', nil);
Cmd_AddCommand ('prog', nil);
Cmd_AddCommand ('give', nil);
Cmd_AddCommand ('god', nil);
Cmd_AddCommand ('notarget', nil);
Cmd_AddCommand ('noclip', nil);
Cmd_AddCommand ('invuse', nil);
Cmd_AddCommand ('invprev', nil);
Cmd_AddCommand ('invnext', nil);
Cmd_AddCommand ('invdrop', nil);
Cmd_AddCommand ('weapnext', nil);
Cmd_AddCommand ('weapprev', nil);
end;
(*
===============
CL_WriteConfiguration
Writes key bindings and archived cvars to config.cfg
===============
*)
procedure CL_WriteConfiguration;
const
FILEGENTAG = '// generated by quake, do not modify'#10;
var
f: integer;
path: array[0..MAX_QPATH-1] of char;
begin
if (cls.state = ca_uninitialized) then
exit;
Com_sprintf (path, sizeof(path),'%s/config.cfg', [FS_Gamedir()]);
If FileExists(path) then DeleteFile(path);
f := FileCreate (path);
if (f = -1) then begin
Com_Printf ('Couldn''t write config.cfg.'#10);
exit;
end;
FileWrite (f, FILEGENTAG, sizeof(FILEGENTAG));
Key_WriteBindings (f);
FileClose (f);
Cvar_WriteVariables (path);
end;
(*
==================
CL_FixCvarCheats
==================
*)
type
cheatvar_p = ^cheatvar_t;
cheatvar_t = record
name: pchar;
value: pchar;
var_ : cvar_p;
end;
var
cheatvars: array[0..11] of cheatvar_t = (
(name: 'timescale'; value: '1'; var_: nil),
(name: 'timedemo'; value: '0'; var_: nil),
(name: 'r_drawworld'; value: '1'; var_: nil),
(name: 'cl_testlights'; value: '0'; var_: nil),
(name: 'r_fullbright'; value: '0'; var_: nil),
(name: 'r_drawflat'; value: '0'; var_: nil),
(name: 'paused'; value: '0'; var_: nil),
(name: 'fixedtime'; value: '0'; var_: nil),
(name: 'sw_draworder'; value: '0'; var_: nil),
(name: 'gl_lightmap'; value: '0'; var_: nil),
(name: 'gl_saturatelighting'; value: '0'; var_: nil),
(name: nil; value: nil; var_: nil)
);
numcheatvars: integer;
procedure CL_FixCvarCheats;
var
i: Integer;
var_: cheatvar_p;
begin
if (strcmp(cl.configstrings[CS_MAXCLIENTS], '1') = 0) or
(cl.configstrings[CS_MAXCLIENTS][0]=#0) then
exit; // single player can cheat
// find all the cvars if we haven't done it yet
if (numcheatvars = 0) then begin
while (cheatvars[numcheatvars].name<>nil) do begin
cheatvars[numcheatvars].var_ := Cvar_Get (cheatvars[numcheatvars].name,
cheatvars[numcheatvars].value, 0);
Inc(numcheatvars);
end;
end;
// make sure they are all set to the proper values
i := 0;
var_ := @cheatvars;
while (i < numcheatvars) do begin
if (strcmp(var_.var_.string_, var_.value))<>0 then begin
Cvar_Set (var_.name, var_.value);
end;
Inc(i);
Inc(Var_);
end;
end;
//============================================================================
(*
==================
CL_SendCommand
==================
*)
procedure CL_SendCommand;
begin
// get new key events
Sys_SendKeyEvents ();
// allow mice or other external controllers to add commands
IN_Commands ();
// process console commands
Cbuf_Execute ();
// fix any cheating cvars
CL_FixCvarCheats ();
// send intentions now
CL_SendCmd ();
// resend a connection request if necessary
CL_CheckForResend ();
end;
(*
==================
CL_Frame
==================
*)
var
extratime: integer;
lasttimecalled: integer;
procedure CL_Frame (msec: Integer);
var
now_: integer;
tmp: string;
begin
if (dedicated.value<>0) then
exit;
extratime := extratime + msec;
if (cl_timedemo.value = 0) then begin
if (cls.state = ca_connected) and (extratime < 100) then
exit; // don't flood packets out while connecting
if (extratime < 1000/cl_maxfps.value) then
exit; // framerate is too high
end;
// let the mouse activate or deactivate
IN_Frame ();
// decide the simulation time
cls.frametime := extratime/1000.0;
cl.time := cl.time + extratime;
cls.realtime := curtime;
extratime := 0;
{$ifdef neverever}
if (cls.frametime > (1.0 / cl_minfps.value))
cls.frametime = (1.0 / cl_minfps.value);
{$else}
if (cls.frametime > (1.0 / 5)) then
cls.frametime := (1.0 / 5);
{$endif}
// if in the debugger last frame, don't timeout
if (msec > 5000) then
cls.netchan.last_received := Sys_Milliseconds ();
// fetch results from server
CL_ReadPackets ();
// send a new command message to the server
CL_SendCommand ();
// predict all unacknowledged movements
CL_PredictMovement ();
// allow rendering DLL change
VID_CheckChanges ();
if (not cl.refresh_prepped) and (cls.state = ca_active) then
CL_PrepRefresh ();
// update the screen
if (host_speeds.value<>0) then
time_before_ref := Sys_Milliseconds ();
SCR_UpdateScreen ();
if (host_speeds.value<>0) then
time_after_ref := Sys_Milliseconds ();
// update audio
S_Update (vec3_t(cl.refdef.vieworg), cl.v_forward, cl.v_right, cl.v_up);
CDAudio_Update();
// advance local effects for next frame
CL_RunDLights ();
CL_RunLightStyles ();
SCR_RunCinematic ();
SCR_RunConsole ();
Inc(cls.framecount);
if ( log_stats.value <>0) then begin
if ( cls.state = ca_active ) then begin
if ( lasttimecalled = 0 ) then begin
lasttimecalled := Sys_Milliseconds();
if ( log_stats_file<>0 ) then
FileWrite( log_stats_file, '0'#10, 2 );
end
else
begin
now_ := Sys_Milliseconds();
if ( log_stats_file<>0 ) then begin
tmp := Format('%d'#10, [now_ - lasttimecalled]);
FileWrite( log_stats_file, tmp[1], length(tmp));
end;
lasttimecalled := now_;
end;
end;
end;
end;
//============================================================================
(*
====================
CL_Init
====================
*)
procedure CL_Init;
begin
if (dedicated.value<>0) then
exit; // nothing running on the client
// all archived variables will now be loaded
Con_Init ();
{$IFDEF LINUX}
S_Init ();
VID_Init ();
{$ELSE}
VID_Init ();
S_Init (); // sound must be initialized after window is created
{$ENDIF}
V_Init ();
net_message.data := @net_message_buffer;
net_message.maxsize := sizeof(net_message_buffer);
M_Init ();
SCR_Init ();
cls.disable_screen := Integer(true); // don't draw yet
CDAudio_Init ();
CL_InitLocal ();
IN_Init ();
// Cbuf_AddText ("exec autoexec.cfg"#10);
FS_ExecAutoexec ();
Cbuf_Execute ();
end;
(*
===============
CL_Shutdown
FIXME: this is a callback from Sys_Quit and Com_Error. It would be better
to run quit through here before the final handoff to the sys code.
===============
*)
var
isdown: qboolean = false;
procedure CL_Shutdown;
begin
if (isdown) then begin
Com_printf ('recursive shutdown'#10);
exit;
end;
isdown := true;
CL_WriteConfiguration ();
CDAudio_Shutdown ();
S_Shutdown();
IN_Shutdown ();
VID_Shutdown();
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -