⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 p_client.pas

📁 delphi编的不错的贪吃蛇
💻 PAS
📖 第 1 页 / 共 4 页
字号:

{*
===========
ClientConnect

Called when a player begins connecting to the server.
The game can refuse entrance to a client by returning false.
If the client is allowed, the connection process will continue
and eventually get to ClientBegin()
Changing levels will NOT cause this to be called again, but
loadgames will.
============
*}
function ClientConnect (ent : edict_p; userinfo : PChar) : qboolean; //g_main
var
  value      : PChar;
  i, numspec : Integer;
begin
  // check to see if they are on the banned IP list
  value := Info_ValueForKey (userinfo, 'ip');

{$IFNDEF CTF}  //onlyGAME (noneCTF)
  if (SV_FilterPacket(value)) then
  begin
    Info_SetValueForKey (userinfo, 'rejmsg', 'Banned.');
    Result := false;
    Exit;
  end;

  // check for a spectator
  value := Info_ValueForKey (userinfo, 'spectator');
  { 2003-05-08-SP:  Alternative more Literal Conversion in case chosen option is under doubt
  if (deathmatch^.Value <> 0) and (value^ <> #0) and (strcmp(value, '0') <> 0) then }
  if (deathmatch^.Value <> 0) and (value <> nil) and (strcmp(value, '0') <> 0) then
  begin
    { 2003-05-08-SP:  Alternative more Literal Conversion in case chosen option is under doubt
    if ( (spectator_password^.string_^ <> #0) AND }
    if ( (spectator_password^.string_ <> nil) AND
         (strcmp(spectator_password^.string_, 'none') <> 0) AND
         (strcmp(spectator_password^.string_, value) <> 0)) then
    begin
      Info_SetValueForKey(userinfo, 'rejmsg', 'Spectator password required or incorrect.');
      Result := false;
      Exit;
    end;

    // count spectators
    numspec := 0;
    for i := 0 to trunc(maxclients^.Value)-1 do
      if (g_edicts^[i+1].inuse) AND (g_edicts^[i+1].client^.pers.spectator) then
        Inc(numspec);

    if (numspec >= maxspectators^.value) then
    begin
      Info_SetValueForKey(userinfo, 'rejmsg', 'Server spectator limit is full.');
      Result := false;
      Exit;
    end;
  end
  else
  begin
{$ENDIF}
    // check for a password
    value := Info_ValueForKey (userinfo, 'password');
    { 2003-05-08-SP:  Alternative more Literal Conversion in case chosen option is under doubt
    if ( (password.string_^ <> #0) AND }
    if ( (password^.string_ <> nil) AND
         (strcmp(password^.string_, 'none') <> 0) AND
         (strcmp(password^.string_, value) <> 0)) then
    begin
      Info_SetValueForKey(userinfo, 'rejmsg', 'Password required or incorrect.');
      Result := false;
      Exit;
    end;
{$IFNDEF CTF}
  end;
{$ENDIF}


  // they can connect
  ent^.client := @gclient_a(game.clients)[((Cardinal(ent) - Cardinal(g_edicts)) div SizeOf(edict_t)) - 1];

  // if there is already a body waiting for us (a loadgame), just
  // take it, otherwise spawn one from scratch
  if (ent^.inuse = false) then
  begin
    // clear the respawning variables

{$IFDEF CTF}  //onlyCTF
//ZOID -- force team join
    ent^.client^.resp.ctf_team := -1;
    ent.^client^.resp.id_state := false;
//ZOID
{$ENDIF}

    InitClientResp (ent^.client);
    if (not game.autosaved) OR (ent^.client^.pers.weapon = nil) then
      InitClientPersistant (ent^.client);
  end;

  ClientUserinfoChanged (ent, userinfo);

  if (game.maxclients > 1) then
    gi.dprintf ('%s connected'#10, ent^.client^.pers.netname);

  ent^.svflags := 0;
  ent^.client^.pers.connected := true;
  Result := true;
end;


{*
===========
ClientDisconnect

Called when a player drops from the server.
Will not be called between levels.
============
*}
procedure ClientDisconnect (ent : edict_p); //g_main
var
  playernum : integer;
begin
  if (ent^.client = Nil) then
    Exit;

  gi.bprintf (PRINT_HIGH, '%s disconnected'#10, ent^.client^.pers.netname);

{$IFDEF CTF}  //onlyCTF
(*Y//ZOID
  CTFDeadDropFlag(ent);
  CTFDeadDropTech(ent);
//ZOID*)
{$ENDIF}

  // send effect
  gi.WriteByte (svc_muzzleflash);
  gi.WriteShort ((Cardinal(ent) - Cardinal(g_edicts)) div SizeOf(edict_t));
  gi.WriteByte (MZ_LOGOUT);
  gi.multicast (@ent^.s.origin, MULTICAST_PVS);

  gi.unlinkentity (ent);
  ent^.s.modelindex := 0;
  ent^.solid := SOLID_NOT;
  ent^.inuse := false;
  ent^.classname := 'disconnected';
  ent^.client^.pers.connected := false;

  playernum := (Cardinal(ent) - Cardinal(g_edicts)) div SizeOf(edict_t) - 1;
  gi.configstring (CS_PLAYERSKINS+playernum, '');
end;


//==============================================================


var
  pm_passent : edict_p;

// pmove doesn't need to know about passent and contentmask
function PM_trace (var start, mins, maxs, end_: vec3_t) : trace_t; cdecl;
begin
  if (pm_passent^.health > 0) then
    Result := gi.trace (@start, @mins, @maxs, @end_, pm_passent, MASK_PLAYERSOLID)
  else
    Result := gi.trace (@start, @mins, @maxs, @end_, pm_passent, MASK_DEADSOLID);
end;


function CheckBlock (b : PByteArray; c : integer) : integer;
var
  v, i : integer;
begin
  v := 0;
  for i := 0 to c-1 do
    Inc(v, b^[i]);
  Result := v;
end;

procedure PrintPmove (pm : pmove_p);
var
  c1, c2 : cardinal;
begin
  c1 := CheckBlock (@pm^.s,   sizeof(pm^.s));
  c2 := CheckBlock (@pm^.cmd, sizeof(pm^.cmd));
  Com_Printf ('sv %3i:%i %i'#10, [pm^.cmd.impulse, c1, c2]);
end;


{*
==============
ClientThink

This will be called once for each client frame, which will
usually be a couple times for each server frame.
==============
*}
procedure ClientThink (ent : edict_p; ucmd : usercmd_p);
var
  client : gclient_p;
  other  : edict_p;
  i, j   : integer;
  pm     : pmove_t;
begin
  level.current_entity := ent;
  client := ent^.client;

  if (level.intermissiontime <> 0) then
  begin
    client^.ps.pmove.pm_type := PM_FREEZE;
    // can exit intermission after five seconds
    if (level.time > level.intermissiontime + 5.0) AND ((ucmd^.buttons AND BUTTON_ANY) <> 0) then
      level.exitintermission := Integer(True);
    Exit;
  end;

  pm_passent := ent;

  if (ent^.client^.chase_target <> Nil) then
  begin
    client^.resp.cmd_angles[0] := SHORT2ANGLE(ucmd^.angles[0]);
    client^.resp.cmd_angles[1] := SHORT2ANGLE(ucmd^.angles[1]);
    client^.resp.cmd_angles[2] := SHORT2ANGLE(ucmd^.angles[2]);

{$IFDEF CTF}
//ZOID
    Exit;
  end;
{$ELSE}
  end
  else
  begin
{$ENDIF}

    // set up for pmove
    FillChar(pm, sizeof(pm), 0);

    if (ent^.movetype = MOVETYPE_NOCLIP) then
      client^.ps.pmove.pm_type := PM_SPECTATOR
    else if (ent^.s.modelindex <> 255) then
      client^.ps.pmove.pm_type := PM_GIB
    else if (ent^.deadflag <> 0) then
      client^.ps.pmove.pm_type := PM_DEAD
    else
      client^.ps.pmove.pm_type := PM_NORMAL;

    client^.ps.pmove.gravity := trunc(sv_gravity^.Value);
    pm.s := client^.ps.pmove;

    for i := 0 to 2 do
    begin
      pm.s.origin[i] := trunc(ent^.s.origin[i]*8);
      pm.s.velocity[i] := trunc(ent^.velocity[i]*8);
    end;

    if (memcmp(@client^.old_pmove, @pm.s, sizeof(pm.s)) <> 0) then
    begin
      pm.snapinitial := true;
//idsoft	gi.dprintf ("pmove changed!\n");
    end;

    pm.cmd := ucmd^;

    pm.trace := PM_trace;   // adds default parms
    pm.pointcontents := gi.pointcontents;

    // perform a pmove
    gi.Pmove (@pm);

    // save results of pmove
    client^.ps.pmove := pm.s;
    client^.old_pmove := pm.s;

    for i := 0 to 2 do
    begin
      ent^.s.origin[i] := pm.s.origin[i]*0.125;
      ent^.velocity[i] := pm.s.velocity[i]*0.125;
    end;

    VectorCopy (pm.mins, ent^.mins);
    VectorCopy (pm.maxs, ent^.maxs);

    client^.resp.cmd_angles[0] := SHORT2ANGLE(ucmd^.angles[0]);
    client^.resp.cmd_angles[1] := SHORT2ANGLE(ucmd^.angles[1]);
    client^.resp.cmd_angles[2] := SHORT2ANGLE(ucmd^.angles[2]);

    if (ent^.groundentity <> Nil) AND (pm.groundentity = Nil) AND (pm.cmd.upmove >= 10) AND (pm.waterlevel = 0) then
    begin
      gi.sound (ent, CHAN_VOICE, gi.soundindex('*jump1.wav'), 1, ATTN_NORM, 0);
      PlayerNoise (ent, ent^.s.origin, PNOISE_SELF);
    end;

    ent^.viewheight := trunc(pm.viewheight);
    ent^.waterlevel := pm.waterlevel;
    ent^.watertype := pm.watertype;
    ent^.groundentity := pm.groundentity;
    if (pm.groundentity <> Nil) then
      ent^.groundentity_linkcount := edict_p(pm.groundentity)^.linkcount;

    if (ent^.deadflag <> 0) then
    begin
      client^.ps.viewangles[ROLL] := 40;
      client^.ps.viewangles[PITCH] := -15;
      client^.ps.viewangles[YAW] := client^.killer_yaw;
    end
    else
    begin
      VectorCopy (pm.viewangles, client^.v_angle);
      VectorCopy (pm.viewangles, client^.ps.viewangles);
    end;

{$IFDEF CTF}  //onlyCTF
(*Y//ZOID
  if (client.ctf_grapple <> Nil) then
    CTFGrapplePull (client.ctf_grapple);
//ZOID*)
{$ENDIF}

    gi.linkentity (ent);

    if (ent^.movetype <> MOVETYPE_NOCLIP) then
      G_TouchTriggers (ent);

    // touch other objects
    for i := 0 to pm.numtouch-1 do
    begin
      other := pm.touchents[i];
      j := 0;
      while j < i do
      begin
        if (pm.touchents[j] = other) then
          Break;

        Inc(j);
      end;
      if (j <> i) then
        Continue;  // duplicated
      if NOT Assigned(other^.touch) then
        Continue;
      other^.touch (other, ent, Nil, Nil);
    end;

{$IFNDEF CTF}
  end;
{$ENDIF}

  client^.oldbuttons := client^.buttons;
  client^.buttons := ucmd^.buttons;
  client^.latched_buttons := client^.latched_buttons OR (client^.buttons AND (NOT client^.oldbuttons));

  // save light level the player is standing on for
  // monster sighting AI
  ent^.light_level := ucmd^.lightlevel;

  // fire weapon from final position if needed
{$IFDEF CTF}
  if ((client^.latched_buttons AND BUTTON_ATTACK) <> 0)
//ZOID
     AND (ent^.movetype <> MOVETYPE_NOCLIP
//ZOID
     )
  then
    if (NOT client^.weapon_thunk) then
    begin
      client^.weapon_thunk := true;
      Think_Weapon (ent);
    end;
{$ELSE}
  if (client^.latched_buttons AND BUTTON_ATTACK) <> 0 then
  begin
    if (client^.resp.spectator) then
    begin
      client^.latched_buttons := 0;

      if (client^.chase_target <> Nil) then
      begin
        client^.chase_target := Nil;
        client^.ps.pmove.pm_flags := client^.ps.pmove.pm_flags AND (NOT PMF_NO_PREDICTION);
      end
      else
        GetChaseTarget(ent);
    end
    else if (NOT client^.weapon_thunk) then
    begin
      client^.weapon_thunk := true;
      Think_Weapon (ent);
    end;
  end;
{$ENDIF}


{$IFDEF CTF}
(*Y//ZOID
//regen tech
  CTFApplyRegeneration(ent);
//ZOID*)

//ZOID
  for i:=1 to maxclients.value do
  begin
    other := g_edicts + i;
    if (other.inuse) AND (other.client.chase_target = ent) then
      UpdateChaseCam(other);
  end;

  if (client.menudirty) AND (client.menutime <= level.time) then
  begin
    PMenu_Do_Update(ent);
    gi.unicast (ent, true);
    client.menutime := level.time;
    client.menudirty := false;
  end;
//ZOID
{$ELSE}
  if (client^.resp.spectator) then
  begin
    if (ucmd^.upmove >= 10) then
    begin
      if (client^.ps.pmove.pm_flags AND PMF_JUMP_HELD) = 0 then
      begin
        client^.ps.pmove.pm_flags := client^.ps.pmove.pm_flags OR PMF_JUMP_HELD;
        if (client^.chase_target <> nil) then
          ChaseNext(ent)
        else
          GetChaseTarget(ent);
      end;
    end
    else
      client^.ps.pmove.pm_flags := client^.ps.pmove.pm_flags AND (NOT PMF_JUMP_HELD);
  end;

  // update chase cam if being followed
  for i := 1 to trunc(maxclients^.Value) do
  begin
    other := @g_edicts^[i];
    if (other^.inuse) AND (other^.client^.chase_target = ent) then
      UpdateChaseCam(other);
  end;
{$ENDIF}
end;


{*
==============
ClientBeginServerFrame

This will be called once for each server frame, before running
any other entities in the world.
==============
*}
procedure ClientBeginServerFrame (ent : edict_p);
var
  client : gclient_p;
  buttonMask : integer;
begin
  if (level.intermissiontime <> 0) then
    Exit;

  client := ent^.client;


{$IFDEF CTF}
  // run weapon animations if it hasn't been done by a ucmd_t
  if (NOT client.weapon_thunk)
//ZOID
     AND (ent.movetype <> MOVETYPE_NOCLIP
//ZOID
          )
  then Think_Weapon (ent)
  else client.weapon_thunk := false;
{$ELSE}
  if (deathmatch^.value <> 0) AND
     (client^.pers.spectator <> client^.resp.spectator) AND
     ((level.time - client^.respawn_time) >= 5) then
  begin
    spectator_respawn(ent);
    Exit;
  end;

  // run weapon animations if it hasn't been done by a ucmd_t
  if (NOT client^.weapon_thunk) AND (NOT client^.resp.spectator) then
    Think_Weapon (ent)
  else
    client^.weapon_thunk := false;
{$ENDIF}

  if (ent^.deadflag <> 0) then
  begin
    // wait for any button just going down
    if (level.time > client^.respawn_time) then
    begin
      // in deathmatch, only wait for attack button
      if (deathmatch^.value <> 0) then
        buttonMask := BUTTON_ATTACK
      else
        buttonMask := -1;

{$IFDEF CTF}
      if ((client.latched_buttons AND buttonMask) <> 0) OR
         ( (deathmatch.value <> 0) AND (({(int)}Trunc(dmflags.value) AND DF_FORCE_RESPAWN) <> 0) ) (*YOR
         CTFMatchOn()*) then
{$ELSE}
      if ((client^.latched_buttons AND buttonMask) <> 0) OR
         ( (deathmatch^.value <> 0) AND ((Trunc(dmflags^.value) AND DF_FORCE_RESPAWN) <> 0) ) then
{$ENDIF}
      begin
        respawn(ent);
        client^.latched_buttons := 0;
      end;
    end;
    Exit;
  end;

  // add player trail so monsters can follow
  if (deathmatch^.value = 0) then
    if (not visible (ent, PlayerTrail_LastSpot())) then
      PlayerTrail_Add (ent^.s.old_origin);

  client^.latched_buttons := 0;
end;

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -