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

📄 p_client.pas

📁 delphi编的不错的贪吃蛇
💻 PAS
📖 第 1 页 / 共 4 页
字号:
begin
  // grab a body que and cycle to the next one
  body := @g_edicts^[trunc(maxclients^.Value) + level.body_que + 1];
  level.body_que := (level.body_que + 1) MOD BODY_QUEUE_SIZE;

  // FIXME: send an effect on the removed body

  gi.unlinkentity (ent);

  gi.unlinkentity (body);
  body^.s := ent^.s;
  body^.s.number := (Cardinal(body) - Cardinal(g_edicts)) div SizeOf(edict_t);

  body^.svflags := ent^.svflags;
  VectorCopy (ent^.mins, body^.mins);
  VectorCopy (ent^.maxs, body^.maxs);
  VectorCopy (ent^.absmin, body^.absmin);
  VectorCopy (ent^.absmax, body^.absmax);
  VectorCopy (ent^.size, body^.size);
  body^.solid := ent^.solid;
  body^.clipmask := ent^.clipmask;
  body^.owner := ent^.owner;
  body^.movetype := ent^.movetype;

  body^.die := body_die;
  body^.takedamage := DAMAGE_YES;

  gi.linkentity (body);
end;


procedure respawn (self : edict_p);
begin
  if (deathmatch^.value <> 0) OR (coop^.value <> 0) then
  begin
    // spectator's don't leave bodies
    if (self^.movetype <> MOVETYPE_NOCLIP) then
      CopyToBodyQue (self);
    self^.svflags := self^.svflags AND (NOT SVF_NOCLIENT);
    PutClientInServer (self);

    // add a teleportation effect
    self^.s.event := EV_PLAYER_TELEPORT;

    // hold in place briefly
    self^.client^.ps.pmove.pm_flags := PMF_TIME_TELEPORT;
    self^.client^.ps.pmove.pm_time := 14;

    self^.client^.respawn_time := level.time;

    Exit;
  end;

  // restart the entire server
  gi.AddCommandString ('menu_loadgame'#10);
end;


{$IFNDEF CTF}  //onlyGAME (noneCTF)
{*
 * only called when pers.spectator changes
 * note that resp.spectator should be the opposite of pers.spectator here
 *}
procedure spectator_respawn (ent : edict_p); //imp
var
  i, numspec : integer;
  value      : PChar;
begin
  // if the user wants to become a spectator, make sure he doesn't
  // exceed max_spectators

  if (ent^.client^.pers.spectator) then
  begin
    value := Info_ValueForKey (ent^.client^.pers.userinfo, 'spectator');
    if ( (spectator_password^.string_ <> nil) AND
         (strcmp(spectator_password^.string_, 'none') <> 0) AND
         (strcmp(spectator_password^.string_, value) <> 0)) then
    begin
      gi.cprintf(ent, PRINT_HIGH, 'Spectator password incorrect.'#10);
      ent^.client^.pers.spectator := false;
      gi.WriteByte (svc_stufftext);
      gi.WriteString ('spectator 0'#10);
      gi.unicast(ent, true);
      Exit;
    end;

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

    if (numspec >= maxspectators^.value) then
    begin
      gi.cprintf(ent, PRINT_HIGH, 'Server spectator limit is full.');
      ent^.client^.pers.spectator := false;
      // reset his spectator var
      gi.WriteByte (svc_stufftext);
      gi.WriteString ('spectator 0'#10);
      gi.unicast(ent, true);
      Exit;
    end;
  end
  else
  begin
    // he was a spectator and wants to join the game
    // he must have the right password
    value := Info_ValueForKey (ent^.client^.pers.userinfo, 'password');
    { if ( (password^.string_^ <> #0) AND   // <<-- Truer to Original Conversion }
    if ( (password^.string_ <> nil) AND
         (strcmp(password^.string_, 'none') <> 0) AND
         (strcmp(password^.string_, value) <> 0)) then
    begin
      gi.cprintf(ent, PRINT_HIGH, 'Password incorrect.'#10);
      ent^.client^.pers.spectator := true;
      gi.WriteByte (svc_stufftext);
      gi.WriteString ('spectator 1'#10);
      gi.unicast(ent, true);
      Exit;
    end;
  end;

  // clear score on respawn
//  ent->client->resp.score = ent->client->pers.score = 0;
  ent^.client^.pers.score := 0;
  ent.client.resp.score := ent^.client^.pers.score;

  ent^.svflags := ent^.svflags AND (NOT SVF_NOCLIENT);
  PutClientInServer (ent);

  // add a teleportation effect
  if (NOT ent^.client^.pers.spectator) then
  begin
    // send effect
    gi.WriteByte (svc_muzzleflash);
    gi.WriteShort ((Cardinal(ent)-Cardinal(g_edicts)) div SizeOf(edict_t));
    gi.WriteByte (MZ_LOGIN);
    gi.multicast (@ent^.s.origin, MULTICAST_PVS);

    // hold in place briefly
    ent^.client^.ps.pmove.pm_flags := PMF_TIME_TELEPORT;
    ent^.client^.ps.pmove.pm_time := 14;
  end;

  ent^.client^.respawn_time := level.time;

  if (ent^.client^.pers.spectator) then
    gi.bprintf (PRINT_HIGH, '%s has moved to the sidelines'#10, ent^.client^.pers.netname)
  else
    gi.bprintf (PRINT_HIGH, '%s joined the game'#10, ent^.client^.pers.netname);
end;
{$ENDIF}

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


{*
===========
PutClientInServer

Called when a player connects to a server or respawns in
a deathmatch.
============
*}
procedure PutClientInServer (ent : edict_p);
const
  mins : vec3_t = (-16, -16, -24);
  maxs : vec3_t = ( 16,  16,  32);
var
  index   : integer;
  spawn_origin,
  spawn_angles  : vec3_t;
  client        : gclient_p;
  i             : integer;
  saved         : client_persistant_t;
  resp          : client_respawn_t;

  userinfo      : array[0..MAX_INFO_STRING-1] of char;

begin
  // find a spawn point
  // do it before setting health back up, so farthest
  // ranging doesn't count this client
  SelectSpawnPoint (ent, spawn_origin, spawn_angles);

  index := (Cardinal(ent) - Cardinal(g_edicts)) div SizeOf(edict_t) - 1;
  client := ent^.client;

  // deathmatch wipes most client data every spawn
  if (deathmatch^.value <> 0) then
  begin
    resp := client^.resp;
    memcpy (@userinfo, @client^.pers.userinfo, SizeOf(userinfo));
    InitClientPersistant (client);
    ClientUserinfoChanged (ent, userinfo);
  end
  else if (coop^.value <> 0) then
  begin
    resp := client^.resp;
    memcpy (@userinfo, @client^.pers.userinfo, SizeOf(userinfo));

{$IFDEF CTF}
    for n:=0 to MAX_ITEMS-1 do
      if ((itemlist[n].flags AND IT_KEY) <> 0) then
        resp.coop_respawn.inventory[n] := client.pers.inventory[n];
{$ELSE}
      // this is kind of ugly, but it's how we want to handle keys in coop
(*idsoft
//		for (n = 0; n < game.num_items; n++)
//		{
//			if (itemlist[n].flags & IT_KEY)
//				resp.coop_respawn.inventory[n] = client->pers.inventory[n];
//		}
*)
    resp.coop_respawn.game_helpchanged := client^.pers.game_helpchanged;
    resp.coop_respawn.helpchanged := client^.pers.helpchanged;
{$ENDIF}

    client^.pers := resp.coop_respawn;
    ClientUserinfoChanged (ent, userinfo);
    if (resp.score > client^.pers.score) then
      client^.pers.score := resp.score;
  end
  else
    FillChar(resp, SizeOf(resp), 0);

  // clear everything but the persistant data
  saved := client^.pers;
  FillChar(client^, SizeOf(gclient_t), 0);
  client^.pers := saved;
  if (client^.pers.health <= 0) then
    InitClientPersistant(client);
  client^.resp := resp;

  // copy some data from the client to the entity
  FetchClientEntData (ent);

  // clear entity values
  ent^.groundentity := Nil;
  ent^.client := @gclient_a(game.clients)[index];
  ent^.takedamage := DAMAGE_AIM;
  ent^.movetype := MOVETYPE_WALK;
  ent^.viewheight := 22;
  ent^.inuse := true;
  ent^.classname := 'player';
  ent^.mass := 200;
  ent^.solid := SOLID_BBOX;
  ent^.deadflag := DEAD_NO;
  ent^.air_finished := level.time + 12;
  ent^.clipmask := MASK_PLAYERSOLID;
  ent^.model := 'players/male/tris.md2';
  ent^.pain := player_pain;
  ent^.die := player_die;
  ent^.waterlevel := 0;
  ent^.watertype := 0;
  ent^.flags := ent^.flags AND (NOT FL_NO_KNOCKBACK);
  ent^.svflags := ent^.svflags AND (NOT SVF_DEADMONSTER);

  VectorCopy (mins, ent^.mins);
  VectorCopy (maxs, ent^.maxs);
  VectorClear (ent^.velocity);

  // clear playerstate values
  FillChar(ent^.client^.ps, SizeOf(client^.ps), 0);

  client^.ps.pmove.origin[0] := trunc(spawn_origin[0]*8);
  client^.ps.pmove.origin[1] := trunc(spawn_origin[1]*8);
  client^.ps.pmove.origin[2] := trunc(spawn_origin[2]*8);

{$IFDEF CTF}  //onlyCTF
//ZOID
  client^.ps.pmove.pm_flags := client^.ps.pmove.pm_flags AND (NOT PMF_NO_PREDICTION);
//ZOID
{$ENDIF}

  if (deathmatch^.Value <> 0) AND ((trunc(dmflags^.Value) and DF_FIXED_FOV) <> 0) then
  begin
    client^.ps.fov := 90
  end
  else
  begin
    client^.ps.fov := atoi(Info_ValueForKey(client^.pers.userinfo, 'fov'));
    if (client^.ps.fov < 1) then
      client^.ps.fov := 90
    else if (client^.ps.fov > 160) then
      client^.ps.fov := 160;
  end;

  client^.ps.gunindex := gi.modelindex(client^.pers.weapon^.view_model);

  // clear entity state values
  ent^.s.effects := 0;
  ent^.s.modelindex := 255;		// will use the skin specified model
  ent^.s.modelindex2 := 255;		// custom gun model
  // sknum is player num and weapon number
  // weapon number will be added in changeweapon
  ent^.s.skinnum := (Cardinal(ent) - Cardinal(g_edicts)) div SizeOf(edict_t) - 1;

  ent^.s.frame := 0;
  VectorCopy (spawn_origin, ent^.s.origin);
  ent^.s.origin[2] := ent^.s.origin[2] +1;	// make sure off ground
  VectorCopy (ent^.s.origin, ent^.s.old_origin);

  // set the delta angle
  for i := 0 to 2 do
    client^.ps.pmove.delta_angles[i] := ANGLE2SHORT(spawn_angles[i] - client^.resp.cmd_angles[i]);

  ent^.s.angles[PITCH] := 0;
  ent^.s.angles[YAW] := spawn_angles[YAW];
  ent^.s.angles[ROLL] := 0;
  VectorCopy (ent^.s.angles, client^.ps.viewangles);
  VectorCopy (ent^.s.angles, client^.v_angle);

{$IFDEF CTF}
(*Y//ZOID
  if (CTFStartClient(ent)) then
    Exit;
//ZOID*)
{$ELSE}
  // spawn a spectator
  if (client^.pers.spectator) then
  begin
    client^.chase_target := Nil;

    client^.resp.spectator := true;

    ent^.movetype := MOVETYPE_NOCLIP;
    ent^.solid := SOLID_NOT;
    ent^.svflags := ent^.svflags OR SVF_NOCLIENT;
    ent^.client^.ps.gunindex := 0;
    gi.linkentity (ent);
    Exit;
  end
  else
    client^.resp.spectator := false;
{$ENDIF}

  if (not KillBox (ent)) then
  begin
    // could't spawn in?
  end;

  gi.linkentity (ent);

  // force the current weapon up
  client^.newweapon := client^.pers.weapon;
  ChangeWeapon (ent);
end;


{*
=====================
ClientBeginDeathmatch

A client has just connected to the server in
deathmatch mode, so clear everything out before starting them.
=====================
*}
procedure ClientBeginDeathmatch (ent : edict_p);
begin
  G_InitEdict (ent);

  InitClientResp (ent^.client);

  // locate ent at a spawn point
  PutClientInServer (ent);

  if (level.intermissiontime <> 0) then
  begin
    MoveClientToIntermission (ent);
  end
  else
  begin
    // send effect
    gi.WriteByte (svc_muzzleflash);
    gi.WriteShort ((Cardinal(ent) - Cardinal(g_edicts)) div SizeOf(edict_t));
    gi.WriteByte (MZ_LOGIN);
    gi.multicast (@ent^.s.origin, MULTICAST_PVS);
  end;

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

  // make sure all view stuff is valid
  ClientEndServerFrame (ent);
end;


{*
===========
ClientBegin

called when a client has finished connecting, and is ready
to be placed into the game.  This will happen every level load.
============
*}
procedure ClientBegin (ent : edict_p); //g_main
var
  i : integer;
begin
  ent^.client := @gclient_a(game.clients)[((Cardinal(ent) - Cardinal(g_edicts)) div sizeof(edict_t)- 1)];

  if (deathmatch^.value <> 0) then
  begin
    ClientBeginDeathmatch (ent);
    Exit;
  end;

  // if there is already a body waiting for us (a loadgame), just
  // take it, otherwise spawn one from scratch
  if (ent^.inuse = true) then
  begin
    // the client has cleared the client side viewangles upon
    // connecting to the server, which is different than the
    // state when the game is saved, so we need to compensate
    // with deltaangles
    for i := 0 to 2 do
      ent^.client^.ps.pmove.delta_angles[i] := ANGLE2SHORT(ent^.client^.ps.viewangles[i]);
  end
  else
  begin
    // a spawn point will completely reinitialize the entity
    // except for the persistant data that was initialized at
    // ClientConnect() time
    G_InitEdict (ent);
    ent^.classname := 'player';
    InitClientResp (ent^.client);
    PutClientInServer (ent);
  end;

  if (level.intermissiontime <> 0) then
  begin
    MoveClientToIntermission (ent)
  end
  else
  begin
    // send effect if in a multiplayer game
    if (game.maxclients > 1) then
    begin
      gi.WriteByte (svc_muzzleflash);
      gi.WriteShort (Cardinal(ent)-Cardinal(g_edicts) div SizeOf(edict_t));
      gi.WriteByte (MZ_LOGIN);
      gi.multicast (@ent^.s.origin, MULTICAST_PVS);

      gi.bprintf (PRINT_HIGH, '%s entered the game'#10, ent^.client^.pers.netname);
    end;
  end;

  // make sure all view stuff is valid
  ClientEndServerFrame (ent);
end;


{*
===========
ClientUserInfoChanged

called whenever the player updates a userinfo variable.

The game can override any of the settings in place
(forcing skins or names, etc) before copying it off.
============
*}
procedure ClientUserinfoChanged (ent : edict_p; userinfo : PChar); //g_main
var
  s : PChar;
  playernum : integer;
begin
  // check for malformed or illegal info strings
  if (not Info_Validate(userinfo)) then
    strcpy (userinfo, '\name\badinfo\skin\male/grunt');

  // set name
  s := Info_ValueForKey (userinfo, 'name');
  strncpy (ent^.client^.pers.netname, s, sizeof(ent^.client^.pers.netname)-1);

{$IFNDEF CTF}  //onlyGAME (noneCTF)
  // set spectator
  s := Info_ValueForKey (userinfo, 'spectator');
  // spectators are only supported in deathmatch
  { 2003-05-08-SP:  Alternative more Literal Conversion in case chosen option is under doubt
  if (deathmatch^.value <> 0) and (s^ <> #0) and (strcmp(s, '0') <> 0) then }
  if (deathmatch^.value <> 0) and (s <> nil) and (strcmp(s, '0') <> 0) then
    ent^.client^.pers.spectator := true
  else
    ent^.client^.pers.spectator := false;
{$ENDIF}

  // set skin
  s := Info_ValueForKey (userinfo, 'skin');

  playernum := ((Cardinal(ent) - Cardinal(g_edicts)) div SizeOf(edict_t)) - 1;

  // combine name and skin into a configstring
{$IFDEF CTF}  //onlyCTF
(*Y//ZOID
  if (ctf.value)
  then CTFAssignSkin(ent, s)
  else
//ZOID*)
{$ENDIF}
    gi.configstring (CS_PLAYERSKINS+playernum, va('%s\%s', [ent^.client^.pers.netname, s]));

  // fov
  if (deathmatch^.value <> 0)  AND ((trunc(dmflags^.Value) and DF_FIXED_FOV) <> 0) then
  begin
    ent^.client^.ps.fov := 90
  end
  else
  begin
    ent^.client^.ps.fov := atoi(Info_ValueForKey(userinfo, 'fov'));
    if (ent^.client^.ps.fov < 1) then
      ent^.client^.ps.fov := 90
    else if (ent^.client^.ps.fov > 160) then
      ent^.client^.ps.fov := 160;
  end;

  // handedness
  s := Info_ValueForKey (userinfo, 'hand');
  if (strlen(s) <> 0) then
    ent^.client^.pers.hand := atoi(s);

  // save off the userinfo in case we want to check something later
  strncpy (ent^.client^.pers.userinfo, userinfo, sizeof(ent^.client^.pers.userinfo)-1);
end;

⌨️ 快捷键说明

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