📄 cl_main.pas
字号:
end;
precache_check := TEXTURE_CNT + 999;
end;
//ZOID
CL_RegisterSounds();
CL_PrepRefresh();
MSG_WriteByte(cls.netchan.message, Byte(clc_stringcmd));
MSG_WriteString(cls.netchan.message, va('begin %d'#10, [precache_spawncount]));
end;
{*
=================
CL_Precache_f
The server will send this command right
before allowing the client into the server
=================
*}
procedure CL_Precache_f; cdecl;
var
map_checksum: Cardinal; // for detecting cheater maps
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, length(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;
{
if (cls.frametime > (1.0 / cl_minfps.value))
cls.frametime = (1.0 / cl_minfps.value);
}
if (cls.frametime > (1.0 / 5)) then
cls.frametime := (1.0 / 5);
// 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();
{
Juha:
Quake2 -> Delphi conversion project was initially started by Jan Horn.
Jan Horn died in car accident in year 2002. This project is dedicated
to loving memory of Jan Horn.
}
SCR_CenterPrint('Quake ][ Delphi conversion'#10'dedicated to loving memory of '#10'Jan Horn.'#10);
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 + -