📄 p_client.pas
字号:
self^.client^.killer_yaw := self^.s.angles[YAW];
Exit;
end;
if (dir[0] <> 0) then
self^.client^.killer_yaw := 180/M_PI * arctan2(dir[1], dir[0])
else
begin
self^.client^.killer_yaw := 0;
if (dir[1] > 0) then
self^.client^.killer_yaw := 90
else if (dir[1] < 0) then
self^.client^.killer_yaw := -90;
end;
if (self^.client^.killer_yaw < 0) then
self^.client^.killer_yaw := self^.client^.killer_yaw + 360;
end;
{*
==================
player_die
==================
*}
var
i : integer = 0;
procedure player_die (self, inflictor, attacker : edict_p; damage : integer; const point : vec3_t); //a few files
var
n : integer;
begin
VectorClear (self^.avelocity);
self^.takedamage := DAMAGE_YES;
self^.movetype := MOVETYPE_TOSS;
self^.s.modelindex2 := 0; // remove linked weapon model
self^.s.angles[0] := 0;
self^.s.angles[2] := 0;
self^.s.sound := 0;
self^.client^.weapon_sound := 0;
self^.maxs[2] := -8;
//idsoft self->solid = SOLID_NOT;
self^.svflags := self^.svflags OR SVF_DEADMONSTER;
if (self^.deadflag = 0) then
begin
self^.client^.respawn_time := level.time + 1.0;
LookAtKiller (self, inflictor, attacker);
self^.client^.ps.pmove.pm_type := PM_DEAD;
ClientObituary (self, inflictor, attacker);
TossClientWeapon (self);
if (deathmatch^.value <> 0) then
Cmd_Help_f (self); // show scores
// clear inventory
// this is kind of ugly, but it's how we want to handle keys in coop
for n := 0 to game.num_items-1 do
begin
if (coop^.value <> 0) AND ((itemlist[n].flags AND IT_KEY) <> 0) then
self^.client^.resp.coop_respawn.inventory[n] := self^.client^.pers.inventory[n];
self^.client^.pers.inventory[n] := 0;
end;
end;
// remove powerups
self^.client^.quad_framenum := 0;
self^.client^.invincible_framenum := 0;
self^.client^.breather_framenum := 0;
self^.client^.enviro_framenum := 0;
self^.flags := self^.flags AND (NOT FL_POWER_ARMOR);
if (self^.health < -40) then
begin
// gib
gi.sound (self, CHAN_BODY, gi.soundindex ('misc/udeath.wav'), 1, ATTN_NORM, 0);
for n := 0 to 3 do
ThrowGib (self, 'models/objects/gibs/sm_meat/tris.md2', damage, GIB_ORGANIC);
ThrowClientHead (self, damage);
self^.takedamage := DAMAGE_NO;
end
else
begin // normal death
if (self^.deadflag = 0) then
begin
i := (i+1) MOD 3;
// start a death animation
self^.client^.anim_priority := ANIM_DEATH;
if (self^.client^.ps.pmove.pm_flags AND PMF_DUCKED) <> 0 then
begin
self^.s.frame := FRAME_crdeath1-1;
self^.client^.anim_end := FRAME_crdeath5;
end
else
begin
Case i of
0: begin
self^.s.frame := FRAME_death101-1;
self^.client^.anim_end := FRAME_death106;
end;
1: begin
self^.s.frame := FRAME_death201-1;
self^.client^.anim_end := FRAME_death206;
end;
2: begin
self^.s.frame := FRAME_death301-1;
self^.client^.anim_end := FRAME_death308;
end;
end;
end;
gi.sound (self, CHAN_VOICE,
gi.soundindex(va('*death%i.wav', [(rand() mod 4)+1])),
1, ATTN_NORM, 0);
end;
end;
self^.deadflag := DEAD_DEAD;
gi.linkentity (self);
end;
//=======================================================================
{*
==============
InitClientPersistant
This is only called when the game first initializes in single player,
but is called after each death and level change in deathmatch
==============
*}
procedure InitClientPersistant (client : gclient_p);
var
item : gitem_p;
begin
FillChar(client^.pers, SizeOf(client^.pers), 0);
item := FindItem('Blaster');
client^.pers.selected_item := ITEM_INDEX(item);
client^.pers.inventory[client^.pers.selected_item] := 1;
client^.pers.weapon := item;
client^.pers.health := 100;
client^.pers.max_health := 100;
client^.pers.max_bullets := 200;
client^.pers.max_shells := 100;
client^.pers.max_rockets := 50;
client^.pers.max_grenades := 50;
client^.pers.max_cells := 200;
client^.pers.max_slugs := 50;
client^.pers.connected := true;
end;
procedure InitClientResp (client : gclient_p);
begin
FillChar(client^.resp, SizeOf(client^.resp), 0);
client^.resp.enterframe := level.framenum;
client^.resp.coop_respawn := client^.pers;
end;
{*
==================
SaveClientData
Some information that should be persistant, like health,
is still stored in the edict structure, so it needs to
be mirrored out to the client structure before all the
edicts are wiped.
==================
*}
procedure SaveClientData; //a few files
var
i : integer;
ent : edict_p;
begin
for i := 0 to game.maxclients-1 do
begin
ent := @g_edicts^[1+i];
if (NOT ent^.inuse) then
Continue;
gclient_a(game.clients)[i].pers.health := ent^.health;
gclient_a(game.clients)[i].pers.max_health := ent^.max_health;
gclient_a(game.clients)[i].pers.savedFlags := (ent^.flags AND (FL_GODMODE OR FL_NOTARGET OR FL_POWER_ARMOR));
if (coop^.Value <> 0) then
gclient_a(game.clients)[i].pers.score := ent^.client^.resp.score;
end;
end;
procedure FetchClientEntData (ent : edict_p);
begin
ent^.health := ent^.client^.pers.health;
ent^.max_health := ent^.client^.pers.max_health;
ent^.flags := ent^.flags OR ent^.client^.pers.savedFlags;
if (coop^.value <> 0) then
ent^.client^.resp.score := ent^.client^.pers.score;
end;
{*
=======================================================================
SelectSpawnPoint
=======================================================================
*}
{*
================
PlayersRangeFromSpot
Returns the distance to the nearest player from the given spot
================
*}
function PlayersRangeFromSpot (spot : edict_p) : Single;
var
player : edict_p;
bestplayerdistance,
playerdistance : Single;
v : vec3_t;
n : integer;
begin
bestplayerdistance := 9999999;
for n := 1 to trunc(maxclients^.Value) do
begin
player := @g_edicts^[n];
if (NOT player^.inuse) then
Continue;
if (player^.health <= 0) then
Continue;
VectorSubtract (spot^.s.origin, player^.s.origin, v);
playerdistance := VectorLength (v);
if (playerdistance < bestplayerdistance) then
bestplayerdistance := playerdistance;
end;
Result := bestplayerdistance;
end;
{*
================
SelectRandomDeathmatchSpawnPoint
go to a random point, but NOT the two points closest
to other players
================
*}
function SelectionTest(var iSelection: Integer): Boolean;
begin
Result := (iSelection = 0);
Dec(iSelection);
end;
function SelectRandomDeathmatchSpawnPoint : edict_p;
var
spot, spot1, spot2 : edict_p;
selection : integer;
range, range1, range2 : Single;
count : integer;
begin
count := 0;
spot := Nil;
range2 := 99999;
range1 := range2;
spot2 := Nil;
spot1 := spot2;
spot := G_Find (spot, FOFS_classname, 'info_player_deathmatch');
while (spot <> Nil) do
begin
Inc(count);
range := PlayersRangeFromSpot(spot);
if (range < range1)
then
begin
range1 := range;
spot1 := spot;
end
else if (range < range2) then
begin
range2 := range;
spot2 := spot;
end;
spot := G_Find (spot, FOFS_classname, 'info_player_deathmatch')
end;
if (count = 0) then
begin
Result := Nil;
Exit;
end;
if (count <= 2) then
begin
spot2 := Nil;
spot1 := spot2;
end
else
Dec (count, 2);
selection := rand() mod count;
spot := Nil;
{ NOTE: Changed this section to react to exactly the C code, which actually
would decrement the selection After the evaluation of the code, which
meant that the Dec(selection) before hand was incorrect }
repeat
spot := G_Find (spot, FOFS_classname, 'info_player_deathmatch');
if (spot = spot1) OR (spot = spot2) then
Inc(selection);
until SelectionTest(selection);
Result := spot;
end;
{*
================
SelectFarthestDeathmatchSpawnPoint
================
*}
function SelectFarthestDeathmatchSpawnPoint : edict_p;
var
bestspot, spot : edict_p;
bestdistance,
bestplayerdistance : single;
begin
spot := Nil;
bestspot := Nil;
bestdistance := 0;
spot := G_Find (spot, FOFS_classname, 'info_player_deathmatch');
while (spot <> Nil) do
begin
bestplayerdistance := PlayersRangeFromSpot (spot);
if (bestplayerdistance > bestdistance) then
begin
bestspot := spot;
bestdistance := bestplayerdistance;
end;
spot := G_Find (spot, FOFS_classname, 'info_player_deathmatch');
end;
if (bestspot <> Nil) then
begin
Result := bestspot;
Exit;
end;
// if there is a player just spawned on each and every start spot
// we have no choice to turn one into a telefrag meltdown
spot := G_Find (nil, FOFS_classname, 'info_player_deathmatch');
Result := spot;
end;
function SelectDeathmatchSpawnPoint : edict_p;
begin
if (Trunc(dmflags^.value) AND DF_SPAWN_FARTHEST) <> 0 then
Result := SelectFarthestDeathmatchSpawnPoint ()
else
Result := SelectRandomDeathmatchSpawnPoint ();
end;
function SelectCoopSpawnPoint (ent : edict_p) : edict_p;
var
index : integer;
target : PChar;
spot : edict_p;
begin
// spot := nil;
index := (Cardinal(ent^.client) - Cardinal(game.clients)) div SizeOf(edict_t);
// player 0 starts in normal player spawn point
if (index = 0) then
begin
Result := Nil;
Exit;
end;
spot := nil;
// assume there are four coop spots at each spawnpoint
while True do
begin
spot := G_Find (spot, FOFS_classname, 'info_player_coop');
if (spot = Nil) then
begin
Result := Nil; // we didn't have enough...
Exit;
end;
target := spot^.targetname;
if (target = nil) then
target := '';
if (Q_stricmp(game.spawnpoint, target) = 0) then
begin
// this is a coop spawn point for one of the clients here
Dec(index);
if (index = 0) then
begin
Result := spot; // this is it
Exit;
end;
end;
end;
Result := spot;
end;
{*
===========
SelectSpawnPoint
Chooses a player start, deathmatch start, coop start, etc
============
*}
procedure SelectSpawnPoint (ent : edict_p; var origin, angles : vec3_t);
var
spot : edict_p;
label
continue_;
begin
spot := Nil;
if (deathmatch^.value <> 0) then
spot := SelectDeathmatchSpawnPoint ()
else if (coop^.value <> 0) then
spot := SelectCoopSpawnPoint (ent);
// find a single player start spot
if (spot = Nil) then
begin
spot := G_Find (spot, FOFS_classname, 'info_player_start');
while (spot <> Nil) do
begin
if (game.spawnpoint[0] = #0) AND (spot^.targetname = nil) then
Break;
if (game.spawnpoint[0] = #0) OR (spot^.targetname = nil) then
goto continue_;
if (Q_stricmp(game.spawnpoint, spot^.targetname) = 0) then
Break;
continue_:
spot := G_Find (spot, FOFS_classname, 'info_player_start');
end;
if (spot = Nil) then
begin
if (game.spawnpoint[0] = #0) then
// there wasn't a spawnpoint without a target, so use any
spot := G_Find (spot, FOFS_classname, 'info_player_start');
if (spot = Nil) then
gi.error ('Couldn''t find spawn point %s'#10, game.spawnpoint);
end;
end;
VectorCopy (spot^.s.origin, origin);
origin[2] := origin[2] + 9;
VectorCopy (spot^.s.angles, angles);
end;
//======================================================================
procedure InitBodyQue; //g_spawn
var
i : integer;
ent : edict_p;
begin
level.body_que := 0;
for i := 0 to BODY_QUEUE_SIZE-1 do
begin
ent := G_Spawn();
ent^.classname := 'bodyque';
end;
end;
procedure body_die (self, inflictor, attacker : edict_p; damage : integer; const point : vec3_t); cdecl;
var
n : integer;
begin
if (self^.health < -40) then
begin
gi.sound (self, CHAN_BODY, gi.soundindex ('misc/udeath.wav'), 1, ATTN_NORM, 0);
for n := 0 to 3 do
ThrowGib (self, 'models/objects/gibs/sm_meat/tris.md2', damage, GIB_ORGANIC);
self^.s.origin[2] := self^.s.origin[2] -48;
ThrowClientHead (self, damage);
self^.takedamage := DAMAGE_NO;
end;
end;
procedure CopyToBodyQue (ent : edict_p);
var
body : edict_p;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -