📄 cl_ents.pas
字号:
state.kick_angles[1] := MSG_ReadChar(net_message) * 0.25;
state.kick_angles[2] := MSG_ReadChar(net_message) * 0.25;
end;
if (flags and PS_WEAPONINDEX <> 0) then
begin
state.gunindex := MSG_ReadByte(net_message);
end;
if (flags and PS_WEAPONFRAME <> 0) then
begin
state.gunframe := MSG_ReadByte(net_message);
state.gunoffset[0] := MSG_ReadChar(net_message) * 0.25;
state.gunoffset[1] := MSG_ReadChar(net_message) * 0.25;
state.gunoffset[2] := MSG_ReadChar(net_message) * 0.25;
state.gunangles[0] := MSG_ReadChar(net_message) * 0.25;
state.gunangles[1] := MSG_ReadChar(net_message) * 0.25;
state.gunangles[2] := MSG_ReadChar(net_message) * 0.25;
end;
if (flags and PS_BLEND <> 0) then
begin
state.blend[0] := MSG_ReadByte(net_message) / 255.0;
state.blend[1] := MSG_ReadByte(net_message) / 255.0;
state.blend[2] := MSG_ReadByte(net_message) / 255.0;
state.blend[3] := MSG_ReadByte(net_message) / 255.0;
end;
if (flags and PS_FOV <> 0) then
state.fov := MSG_ReadByte(net_message);
if (flags and PS_RDFLAGS <> 0) then
state.rdflags := MSG_ReadByte(net_message);
// parse stats
statbits := MSG_ReadLong(net_message);
for i := 0 to MAX_STATS - 1 do
if (statbits and (1 shl i) <> 0) then
state.stats[i] := MSG_ReadShort(net_message);
end;
{*
==================
CL_FireEntityEvents
==================
*}
procedure CL_FireEntityEvents(frame: frame_p);
var
s1: entity_state_p;
pnum, num: integer;
begin
for pnum := 0 to frame.num_entities - 1 do
begin
num := (frame.parse_entities + pnum) and (MAX_PARSE_ENTITIES - 1);
s1 := @cl_parse_entities[num];
if (Integer(s1.event) <> 0) then
CL_EntityEvent(s1);
// EF_TELEPORTER acts like an event, but is not cleared each frame
if (s1.effects and EF_TELEPORTER <> 0) then
CL_TeleporterParticles(s1);
end;
end;
{*
================
CL_ParseFrame
================
*}
procedure CL_ParseFrame;
var
cmd: integer;
len: integer;
old: frame_p;
begin
fillchar(cl.frame, sizeof(cl.frame), 0);
{
CL_ClearProjectiles(); // clear projectiles for new frame
}
cl.frame.serverframe := MSG_ReadLong(net_message);
cl.frame.deltaframe := MSG_ReadLong(net_message);
cl.frame.servertime := cl.frame.serverframe * 100;
// BIG HACK to let old demos continue to work
if (cls.serverProtocol <> 26) then
cl.surpressCount := MSG_ReadByte(net_message);
if (cl_shownet.value = 3) then
Com_Printf(' frame:%d delta:%d'#10, [cl.frame.serverframe,
cl.frame.deltaframe]);
// If the frame is delta compressed from data that we
// no longer have available, we must suck up the rest of
// the frame, but not use it, then ask for a non-compressed
// message
if (cl.frame.deltaframe <= 0) then
begin
cl.frame.valid := true; // uncompressed frame
old := nil;
cls.demowaiting := false; // we can start recording now
end
else
begin
old := @cl.frames[cl.frame.deltaframe and UPDATE_MASK];
if (not old.valid) then
begin // should never happen
Com_Printf('Delta from invalid frame (not supposed to happen!).'#10, []);
end;
if (old.serverframe <> cl.frame.deltaframe) then
begin // The frame that the server did the delta from
// is too old, so we can't reconstruct it properly.
Com_Printf('Delta frame too old.'#10, []);
end
else if (cl.parse_entities - old.parse_entities > MAX_PARSE_ENTITIES - 128) then
begin
Com_Printf('Delta parse_entities too old.'#10, []);
end
else
cl.frame.valid := true; // valid delta parse
end;
// clamp time
if (cl.time > cl.frame.servertime) then
cl.time := cl.frame.servertime
else if (cl.time < cl.frame.servertime - 100) then
cl.time := cl.frame.servertime - 100;
// read areabits
len := MSG_ReadByte(net_message);
MSG_ReadData(net_message, @cl.frame.areabits, len);
// read playerinfo
cmd := MSG_ReadByte(net_message);
SHOWNET(svc_strings[cmd]);
if (cmd <> Integer(svc_playerinfo)) then
Com_Error(ERR_DROP, 'CL_ParseFrame: not playerinfo', []);
CL_ParsePlayerstate(old, @cl.frame);
// read packet entities
cmd := MSG_ReadByte(net_message);
SHOWNET(svc_strings[cmd]);
if (cmd <> Integer(svc_packetentities)) then
Com_Error(ERR_DROP, 'CL_ParseFrame: not packetentities', []);
CL_ParsePacketEntities(old, @cl.frame);
{
if (cmd = svc_packetentities2) then
CL_ParseProjectiles();
}
// save the frame off in the backup array for later delta comparisons
cl.frames[cl.frame.serverframe and UPDATE_MASK] := cl.frame;
if (cl.frame.valid) then
begin // getting a valid frame message ends the connection process
if (cls.state <> ca_active) then
begin
cls.state := ca_active;
cl.force_refdef := true;
cl.predicted_origin[0] := cl.frame.playerstate.pmove.origin[0] * 0.125;
cl.predicted_origin[1] := cl.frame.playerstate.pmove.origin[1] * 0.125;
cl.predicted_origin[2] := cl.frame.playerstate.pmove.origin[2] * 0.125;
VectorCopy(cl.frame.playerstate.viewangles, cl.predicted_angles);
if (cls.disable_servercount <> cl.servercount) and
(cl.refresh_prepped) then
SCR_EndLoadingPlaque(); // get rid of loading plaque
end;
cl.sound_prepped := true; // can start mixing ambient sounds
// fire entity events
CL_FireEntityEvents(@cl.frame);
CL_CheckPredictionError();
end;
end;
{*
==========================================================================
INTERPOLATE BETWEEN FRAMES TO GET RENDERING PARMS
==========================================================================
*}
function S_RegisterSexedModel(ent: entity_state_p; base: pchar): model_p;
var
n: integer;
p: pchar;
mdl: model_p;
model: array[0..MAX_QPATH - 1] of char;
buffer: array[0..MAX_QPATH - 1] of char;
begin
// determine what model the client is using
model[0] := #0;
n := CS_PLAYERSKINS + ent.number - 1;
if (cl.configstrings[n][0] <> #0) then
begin
p := strchr(cl.configstrings[n], Byte('\'));
if (p <> nil) then
begin
p := p + 1;
strcpy(model, p);
p := strchr(model, Byte('/'));
if (p <> nil) then
p^ := #0;
end;
end;
// if we can't figure it out, they're male
if (model[0] = #0) then
strcpy(model, 'male');
Com_sprintf(buffer, sizeof(buffer), 'players/%s/%s', [model, base + 1]);
mdl := re.RegisterModel(buffer);
if (mdl = nil) then
begin
// not found, try default weapon model
Com_sprintf(buffer, sizeof(buffer), 'players/%s/weapon.md2', [model]);
mdl := re.RegisterModel(buffer);
if (mdl = nil) then
begin
// no, revert to the male model
Com_sprintf(buffer, sizeof(buffer), 'players/%s/%s', ['male', base + 1]);
mdl := re.RegisterModel(buffer);
if (mdl = nil) then
begin
// last try, default male weapon.md2
Com_sprintf(buffer, sizeof(buffer), 'players/male/weapon.md2', []);
mdl := re.RegisterModel(buffer);
end;
end;
end;
Result := mdl;
end;
{*
===============
CL_AddPacketEntities
===============
*}
var
bfg_lightramp: array[0..5] of integer = (300, 400, 600, 300, 150, 75);
procedure CL_AddPacketEntities(frame: frame_p);
var
ent: entity_t;
s1: entity_state_p;
autorotate: single;
i: integer;
pnum: integer;
cent: centity_p;
autoanim: integer;
ci: clientinfo_p;
effects, renderfx: LongWord;
forward_, start: vec3_t;
a1, a2: single;
intensity: single;
begin
// bonus items rotate at a fixed rate
autorotate := anglemod(cl.time / 10);
// brush models can auto animate their frames
autoanim := Trunc(2 * cl.time / 1000);
FillChar(ent, sizeof(ent), #0);
for pnum := 0 to frame.num_entities - 1 do
begin
s1 := @cl_parse_entities[(frame.parse_entities + pnum) and (MAX_PARSE_ENTITIES - 1)];
cent := @cl_entities[s1.number];
effects := s1.effects;
renderfx := s1.renderfx;
// set frame
if (effects and EF_ANIM01 <> 0) then
ent.frame := autoanim and 1
else if (effects and EF_ANIM23 <> 0) then
ent.frame := 2 + (autoanim and 1)
else if (effects and EF_ANIM_ALL <> 0) then
ent.frame := autoanim
else if (effects and EF_ANIM_ALLFAST <> 0) then
ent.frame := Trunc(cl.time / 100)
else
ent.frame := s1.frame;
// quad and pent can do different things on client
if (effects and EF_PENT <> 0) then
begin
effects := effects and (not EF_PENT);
effects := effects or EF_COLOR_SHELL;
renderfx := renderfx or RF_SHELL_RED;
end;
if (effects and EF_QUAD <> 0) then
begin
effects := effects and (not EF_QUAD);
effects := effects or EF_COLOR_SHELL;
renderfx := renderfx or RF_SHELL_BLUE;
end;
//======
// PMM
if (effects and EF_DOUBLE <> 0) then
begin
effects := effects and (not EF_DOUBLE);
effects := effects or EF_COLOR_SHELL;
renderfx := renderfx or RF_SHELL_DOUBLE;
end;
if (effects and EF_HALF_DAMAGE <> 0) then
begin
effects := effects and (not EF_HALF_DAMAGE);
effects := effects or EF_COLOR_SHELL;
renderfx := effects or RF_SHELL_HALF_DAM;
end;
// pmm
//======
ent.oldframe := cent.prev.frame;
ent.backlerp := 1.0 - cl.lerpfrac;
if ((renderfx and (RF_FRAMELERP or RF_BEAM)) <> 0) then
begin
// step origin discretely, because the frames
// do the animation properly
VectorCopy(cent.current.origin, vec3_t(ent.origin));
VectorCopy(cent.current.old_origin, vec3_t(ent.oldorigin));
end
else
begin // interpolate origin
for i := 0 to 2 do
begin
ent.origin[i] := cent.prev.origin[i] + cl.lerpfrac *
(cent.current.origin[i] - cent.prev.origin[i]);
ent.oldorigin[i] := ent.origin[i];
end;
end;
// create a new entity
// tweak the color of beams
if ((renderfx and RF_BEAM) <> 0) then
begin
// the four beam colors are encoded in 32 bits of skinnum (hack)
ent.alpha := 0.30;
ent.skinnum := (s1.skinnum shr ((rand() mod 4) * 8)) and $FF;
ent.model := nil;
end
else
begin
// set skin
if (s1.modelindex = 255) then
begin
// use custom player skin
ent.skinnum := 0;
ci := @cl.clientinfo[s1.skinnum and $FF];
ent.skin := ci.skin;
ent.model := ci.model;
if (ent.skin = nil) or (ent.model = nil) then
begin
ent.skin := cl.baseclientinfo.skin;
ent.model := cl.baseclientinfo.model;
end;
//============
//PGM
if ((renderfx and RF_USE_DISGUISE) <> 0) then
begin
if (strncmp(ent.skin, 'players/male', 12) = 0) then
begin
ent.skin := re.RegisterSkin('players/male/disguise.pcx');
ent.model := re.RegisterModel('players/male/tris.md2');
end
else if (strncmp(ent.skin, 'players/female', 14) = 0) then
begin
ent.skin := re.RegisterSkin('players/female/disguise.pcx');
ent.model := re.RegisterModel('players/female/tris.md2');
end
else if (strncmp(ent.skin, 'players/cyborg', 14) = 0) then
begin
ent.skin := re.RegisterSkin('players/cyborg/disguise.pcx');
ent.model := re.RegisterModel('players/cyborg/tris.md2');
end;
end;
//PGM
//============
end
else
begin
ent.skinnum := s1.skinnum;
ent.skin := nil;
ent.model := cl.model_draw[s1.modelindex];
end;
end;
// only used for black hole model right now, FIXME: do better
if (renderfx = RF_TRANSLUCENT) then
ent.alpha := 0.70;
// render effects (fullbright, translucent, etc)
if ((effects and EF_COLOR_SHELL) <> 0) then
ent.flags := 0 // renderfx go on color shell entity
else
ent.flags := renderfx;
// calculate angles
if ((effects and EF_ROTATE) <> 0) then
begin
// some bonus items auto-rotate
ent.angles[0] := 0;
ent.angles[1] := autorotate;
ent.angles[2] := 0;
end
// RAFAEL
else if ((effects and EF_SPINNINGLIGHTS) <> 0) then
begin
ent.angles[0] := 0;
ent.angles[1] := anglemod(cl.time / 2) + s1.angles[1];
ent.angles[2] := 180;
begin
AngleVectors(vec3_t(ent.angles), @forward_, nil, nil);
VectorMA(vec3_t(ent.origin), 64, forward_, start);
V_AddLight(start, 100, 1, 0, 0);
end;
end
else
begin // interpolate angles
for i := 0 to 2 do
begin
a1 := cent.current.angles[i];
a2 := cent.prev.angles[i];
ent.angles[i] := LerpAngle(a2, a1, cl.lerpfrac);
end;
end;
if (s1.number = cl.playernum + 1) then
begin
ent.flags := ent.flags or RF_VIEWERMODEL; // only draw from mirrors
// FIXME: still pass to refresh
if (effects and EF_FLAG1 <> 0) then
V_AddLight(vec3_t(ent.origin), 225, 1.0, 0.1, 0.1)
else if (effects and EF_FLAG2 <> 0) then
V_AddLight(vec3_t(ent.origin), 225, 0.1, 0.1, 1.0)
else if (effects and EF_TAGTRAIL <> 0) then //PGM
V_AddLight(vec3_t(ent.origin), 225, 1.0, 1.0, 0.0) //PGM
else if (effects and EF_TRACKERTRAIL <> 0) then //PGM
V_AddLight(vec3_t(ent.origin), 225, -1.0, -1.0, -1.0); //PGM
continue;
end;
// if set to invisible, skip
if (s1.modelindex = 0) then
continue;
if ((effects and EF_BFG) <> 0) then
begin
ent.flags := ent.flags or RF_TRANSLUCENT;
ent.alpha := 0.30;
end;
// RAFAEL
if ((effects and EF_PLASMA) <> 0) then
begin
ent.flags := ent.flags or RF_TRANSLUCENT;
ent.alpha := 0.6;
end;
if ((effects and EF_SPHERETRANS) <> 0) then
begin
ent.flags := ent.flags or RF_TRANSLUCENT;
// PMM - *sigh* yet more EF overloading
if ((effects and EF_TRACKERTRAIL) <> 0) then
ent.alpha := 0.6
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -