diff --git a/src/game/g_player.pas b/src/game/g_player.pas
index db39cb84b0961e1260f840fb8a885e710648b1a8..28032e95d4ea5c2b767c165ff8b6993915e5af21 100644 (file)
--- a/src/game/g_player.pas
+++ b/src/game/g_player.pas
Kills: Word;
Color: TRGB;
Spectator: Boolean;
+ UID: Word;
end;
TPlayerStatArray = Array of TPlayerStat;
FFireAngle: SmallInt;
FIncCamOld: Integer;
FIncCam: Integer;
+ FSlopeOld: Integer;
FShellTimer: Integer;
FShellType: Byte;
FSawSound: TPlayableSound;
procedure doDamage (v: Integer);
- function followCorpse(): Boolean;
+ function refreshCorpse(): Boolean;
public
FDamageBuffer: Integer;
FSpawnInvul: Integer;
FHandicap: Integer;
FWaitForFirstSpawn: Boolean; // set to `true` in server, used to spawn a player on first full state request
+ FCorpse: Integer;
// debug: viewport offset
viewPortX, viewPortY, viewPortW, viewPortH: Integer;
procedure getMapBox (out x, y, w, h: Integer); inline;
procedure moveBy (dx, dy: Integer); inline;
+ function getCameraObj(): TObj;
+
public
property Vel: TPoint2i read FObj.Vel;
property Obj: TObj read FObj;
property GameAccelY: Integer read FObj.Accel.Y write FObj.Accel.Y;
property IncCam: Integer read FIncCam write FIncCam;
property IncCamOld: Integer read FIncCamOld write FIncCamOld;
+ property SlopeOld: Integer read FSlopeOld write FSlopeOld;
property UID: Word read FUID write FUID;
property JustTeleported: Boolean read FJustTeleported write FJustTeleported;
property NetTime: LongWord read FNetTime write FNetTime;
public
constructor Create(X, Y: Integer; ModelName: String; aMess: Boolean);
destructor Destroy(); override;
- procedure Damage(Value: Word; vx, vy: Integer);
+ procedure Damage(Value: Word; SpawnerUID: Word; vx, vy: Integer);
procedure Update();
procedure Draw();
procedure SaveState (st: TStream);
function g_Player_GetCount(): Byte;
function g_Player_GetStats(): TPlayerStatArray;
function g_Player_ValidName(Name: String): Boolean;
-procedure g_Player_CreateCorpse(Player: TPlayer);
+function g_Player_CreateCorpse(Player: TPlayer): Integer;
procedure g_Player_CreateGibs(fX, fY: Integer; ModelName: String; fColor: TRGB);
procedure g_Player_CreateShell(fX, fY, dX, dY: Integer; T: Byte);
procedure g_Player_UpdatePhysicalObjects();
e_TextureFontPrint(0, fH * 3, 'Vel Y: ' + IntToStr(p.FObj.Vel.Y), gStdFont);
e_TextureFontPrint(0, fH * 4, 'Acc X: ' + IntToStr(p.FObj.Accel.X), gStdFont);
e_TextureFontPrint(0, fH * 5, 'Acc Y: ' + IntToStr(p.FObj.Accel.Y), gStdFont);
+ e_TextureFontPrint(0, fH * 6, 'Old X: ' + IntToStr(p.FObj.oldX), gStdFont);
+ e_TextureFontPrint(0, fH * 7, 'Old Y: ' + IntToStr(p.FObj.oldY), gStdFont);
end;
procedure g_Player_DrawHealth();
Color := gPlayers[a].FModel.Color;
Lives := gPlayers[a].FLives;
Spectator := gPlayers[a].FSpectator;
+ UID := gPlayers[a].FUID;
end;
end;
end;
end;
end;
-procedure g_Player_CreateCorpse(Player: TPlayer);
+function g_Player_CreateCorpse(Player: TPlayer): Integer;
var
i: Integer;
find_id: DWORD;
ok: Boolean;
begin
+ Result := -1;
+
if Player.alive then
Exit;
// Ðàçðûâàåì ñâÿçü ñ ïðåæíèì òðóïîì:
- if gCorpses <> nil then
- for i := 0 to High(gCorpses) do
- if gCorpses[i] <> nil then
- if gCorpses[i].FPlayerUID = Player.FUID then
- gCorpses[i].FPlayerUID := 0;
+ i := Player.FCorpse;
+ if (i >= 0) and (i < Length(gCorpses)) then
+ begin
+ if (gCorpses[i] <> nil) and (gCorpses[i].FPlayerUID = Player.FUID) then
+ gCorpses[i].FPlayerUID := 0;
+ end;
if Player.FObj.Y >= gMapInfo.Height+128 then
Exit;
gCorpses[find_id].FObj.Vel := FObj.Vel;
gCorpses[find_id].FObj.Accel := FObj.Accel;
gCorpses[find_id].FPlayerUID := FUID;
+
+ Result := find_id;
end
else
g_Player_CreateGibs(FObj.X + PLAYER_RECT_CX,
FFirePainTime := 0;
FFireAttacker := 0;
FHandicap := 100;
+ FCorpse := -1;
FActualModelName := 'doomer';
procedure TPlayer.DrawIndicator(Color: TRGB);
var
- indX, indY, fX, fY: Integer;
+ indX, indY, fX, fY, fSlope: Integer;
indW, indH: Word;
indA: Single;
a: TDFPoint;
if FAlive then
begin
FObj.lerp(gLerpFactor, fX, fY);
+ fSlope := nlerp(FSlopeOld, FObj.slopeUpLeft, gLerpFactor);
+
case gPlayerIndicatorStyle of
0:
begin
indY := fY - indH;
end;
+ indY := indY + fSlope;
indX := EnsureRange(indX, 0, Max(gMapInfo.Width, gPlayerScreenSize.X) - indW);
indY := EnsureRange(indY, 0, Max(gMapInfo.Height, gPlayerScreenSize.Y) - indH);
begin
e_TextureFontGetSize(gStdFont, nW, nH);
indX := fX + FObj.Rect.X + (FObj.Rect.Width - Length(FName) * nW) div 2;
- indY := fY - nH;
+ indY := fY - nH + fSlope;
e_TextureFontPrintEx(indX, indY, FName, gStdFont, Color.R, Color.G, Color.B, 1.0, True);
end;
end;
Rb, Gb, Bb,
Rw, Gw, Bw: SmallInt;
Dot: Byte;
+ CObj: TObj;
begin
- FObj.lerp(gLerpFactor, fX, fY);
+ CObj := getCameraObj();
+ CObj.lerp(gLerpFactor, fX, fY);
+ // NB: _F_Obj.Rect is used to keep the bubble higher; this is not a mistake
bubX := fX+FObj.Rect.X + IfThen(FDirection = TDirection.D_LEFT, -4, 18);
bubY := fY+FObj.Rect.Y - 18;
Rb := 64;
w, h: Word;
dr: Boolean;
Mirror: TMirrorType;
- fX, fY: Integer;
+ fX, fY, fSlope: Integer;
begin
FObj.lerp(gLerpFactor, fX, fY);
+ fSlope := nlerp(FSlopeOld, FObj.slopeUpLeft, gLerpFactor);
if FAlive then
begin
if FPunchAnim <> nil then
begin
FPunchAnim.Draw(fX+IfThen(Direction = TDirection.D_LEFT, 15-FObj.Rect.X, FObj.Rect.X-15),
- fY+FObj.Rect.Y-11, Mirror);
+ fY+fSlope+FObj.Rect.Y-11, Mirror);
if FPunchAnim.played then
begin
FPunchAnim.Free;
e_GetTextureSize(ID, @w, @h);
if FDirection = TDirection.D_LEFT then
e_Draw(ID, fX+FObj.Rect.X+(FObj.Rect.Width div 2)-(w div 2)+4,
- fY+FObj.Rect.Y+(FObj.Rect.Height div 2)-(h div 2)-7+FObj.slopeUpLeft, 0, True, False)
+ fY+FObj.Rect.Y+(FObj.Rect.Height div 2)-(h div 2)-7+fSlope, 0, True, False)
else
e_Draw(ID, fX+FObj.Rect.X+(FObj.Rect.Width div 2)-(w div 2)-2,
- fY+FObj.Rect.Y+(FObj.Rect.Height div 2)-(h div 2)-7+FObj.slopeUpLeft, 0, True, False);
+ fY+FObj.Rect.Y+(FObj.Rect.Height div 2)-(h div 2)-7+fSlope, 0, True, False);
end;
if FMegaRulez[MR_INVIS] > gTime then
else
dr := True;
if dr then
- FModel.Draw(fX, fY+FObj.slopeUpLeft, 200)
+ FModel.Draw(fX, fY+fSlope, 200)
else
- FModel.Draw(fX, fY+FObj.slopeUpLeft);
+ FModel.Draw(fX, fY+fSlope);
end
else
- FModel.Draw(fX, fY+FObj.slopeUpLeft, 254);
+ FModel.Draw(fX, fY+fSlope, 254);
end
else
- FModel.Draw(fX, fY+FObj.slopeUpLeft);
+ FModel.Draw(fX, fY+fSlope);
end;
if g_debug_Frames then
DropFlag(KillType = K_FALLKILL);
end;
- g_Player_CreateCorpse(Self);
+ FCorpse := g_Player_CreateCorpse(Self);
if Srv and (gGameSettings.MaxLives > 0) and FNoRespawn and
(gLMSRespawn = LMS_RESPAWN_NONE) then
FDeath := 0;
FSecrets := 0;
FSpawnInvul := 0;
+ FCorpse := -1;
FReady := False;
if FNoRespawn then
begin
ReleaseKeys();
FDamageBuffer := 0;
+ FSlopeOld := 0;
FIncCamOld := 0;
FIncCam := 0;
FBFGFireCounter := -1;
// Îäèíî÷íàÿ èãðà/êîîïåðàòèâ
if gGameSettings.GameMode in [GM_COOP, GM_SINGLE] then
begin
- if (Self = gPlayer1) or (Self = gPlayer2) then
+ if Self = gPlayer1 then
begin
- // Òî÷êà ïîÿâëåíèÿ ñâîåãî èãðîêà
- if Self = gPlayer1 then
- c := RESPAWNPOINT_PLAYER1
- else
- c := RESPAWNPOINT_PLAYER2;
- if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
-
- // Òî÷êà ïîÿâëåíèÿ äðóãîãî èãðîêà
- if Self = gPlayer1 then
- c := RESPAWNPOINT_PLAYER2
- else
- c := RESPAWNPOINT_PLAYER1;
- if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
- end else
+ // player 1 should try to spawn on the player 1 point
+ if g_Map_GetPointCount(RESPAWNPOINT_PLAYER1) > 0 then
+ Exit(RESPAWNPOINT_PLAYER1)
+ else if g_Map_GetPointCount(RESPAWNPOINT_PLAYER2) > 0 then
+ Exit(RESPAWNPOINT_PLAYER2);
+ end
+ else if Self = gPlayer2 then
begin
- // Òî÷êà ïîÿâëåíèÿ ëþáîãî èãðîêà (áîòà)
- if Random(2) = 0 then
- c := RESPAWNPOINT_PLAYER1
- else
- c := RESPAWNPOINT_PLAYER2;
- if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
- end;
-
- // Òî÷êà ëþáîé èç êîìàíä
- if Random(2) = 0 then
- c := RESPAWNPOINT_RED
+ // player 2 should try to spawn on the player 2 point
+ if g_Map_GetPointCount(RESPAWNPOINT_PLAYER2) > 0 then
+ Exit(RESPAWNPOINT_PLAYER2)
+ else if g_Map_GetPointCount(RESPAWNPOINT_PLAYER1) > 0 then
+ Exit(RESPAWNPOINT_PLAYER1);
+ end
else
- c := RESPAWNPOINT_BLUE;
- if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
-
- // Òî÷êà DM
- c := RESPAWNPOINT_DM;
- if g_Map_GetPointCount(c) > 0 then
begin
- Result := c;
- Exit;
+ // other players randomly pick either the first or the second point
+ c := IfThen((Random(2) = 0), RESPAWNPOINT_PLAYER1, RESPAWNPOINT_PLAYER2);
+ if g_Map_GetPointCount(c) > 0 then
+ Exit(c);
+ // try the other one
+ c := IfThen((c = RESPAWNPOINT_PLAYER1), RESPAWNPOINT_PLAYER2, RESPAWNPOINT_PLAYER1);
+ if g_Map_GetPointCount(c) > 0 then
+ Exit(c);
end;
end;
// Ìÿñîïîâàë
if gGameSettings.GameMode = GM_DM then
begin
- // Òî÷êà DM
- c := RESPAWNPOINT_DM;
- if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
-
- // Òî÷êà ïîÿâëåíèÿ ëþáîãî èãðîêà
- if Random(2) = 0 then
- c := RESPAWNPOINT_PLAYER1
- else
- c := RESPAWNPOINT_PLAYER2;
- if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
-
- // Òî÷êà ëþáîé èç êîìàíä
- if Random(2) = 0 then
- c := RESPAWNPOINT_RED
- else
- c := RESPAWNPOINT_BLUE;
- if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
+ // try DM points first
+ if g_Map_GetPointCount(RESPAWNPOINT_DM) > 0 then
+ Exit(RESPAWNPOINT_DM);
end;
// Êîìàíäíûå
if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
begin
- // Òî÷êà ñâîåé êîìàíäû
- c := RESPAWNPOINT_DM;
- if FTeam = TEAM_RED then
- c := RESPAWNPOINT_RED;
- if FTeam = TEAM_BLUE then
- c := RESPAWNPOINT_BLUE;
- if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
-
- // Òî÷êà DM
- c := RESPAWNPOINT_DM;
- if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
-
- // Òî÷êà ïîÿâëåíèÿ ëþáîãî èãðîêà
- if Random(2) = 0 then
- c := RESPAWNPOINT_PLAYER1
- else
- c := RESPAWNPOINT_PLAYER2;
- if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
-
- // Òî÷êà äðóãîé êîìàíäû
+ // try team points first
c := RESPAWNPOINT_DM;
if FTeam = TEAM_RED then
+ c := RESPAWNPOINT_RED
+ else if FTeam = TEAM_BLUE then
c := RESPAWNPOINT_BLUE;
- if FTeam = TEAM_BLUE then
- c := RESPAWNPOINT_RED;
if g_Map_GetPointCount(c) > 0 then
- begin
- Result := c;
- Exit;
- end;
+ Exit(c);
end;
+
+ // still haven't found a spawnpoint, try random shit
+ Result := g_Map_GetRandomPointType();
end;
procedure TPlayer.Respawn(Silent: Boolean; Force: Boolean = False);
Anim: TAnimation;
ID: DWORD;
begin
+ FSlopeOld := 0;
FIncCamOld := 0;
FIncCam := 0;
FBFGFireCounter := -1;
FPain := 0;
FLastHit := 0;
FSpawnInvul := 0;
+ FCorpse := -1;
if not g_Game_IsServer then
Exit;
FPhysics := False;
FWantsInGame := False;
FSpawned := False;
+ FCorpse := -1;
if FNoRespawn then
begin
Result := 1;
end;
-function TPlayer.followCorpse(): Boolean;
+function TPlayer.refreshCorpse(): Boolean;
var
i: Integer;
begin
Result := False;
+ FCorpse := -1;
if FAlive or FSpectator then
Exit;
if (gCorpses = nil) or (Length(gCorpses) = 0) then
if gCorpses[i].FPlayerUID = FUID then
begin
Result := True;
- FObj.X := gCorpses[i].FObj.X;
- FObj.Y := gCorpses[i].FObj.Y;
- FObj.Vel.X := gCorpses[i].FObj.Vel.X;
- FObj.Vel.Y := gCorpses[i].FObj.Vel.Y;
- FObj.Accel.X := gCorpses[i].FObj.Accel.X;
- FObj.Accel.Y := gCorpses[i].FObj.Accel.Y;
+ FCorpse := i;
break;
end;
end;
+function TPlayer.getCameraObj(): TObj;
+begin
+ if (not FAlive) and (not FSpectator) and
+ (FCorpse >= 0) and (FCorpse < Length(gCorpses)) and
+ (gCorpses[FCorpse] <> nil) and (gCorpses[FCorpse].FPlayerUID = FUID) then
+ begin
+ gCorpses[FCorpse].FObj.slopeUpLeft := FObj.slopeUpLeft;
+ Result := gCorpses[FCorpse].FObj;
+ end
+ else
+ begin
+ Result := FObj;
+ end;
+end;
+
procedure TPlayer.PreUpdate();
begin
+ FSlopeOld := FObj.slopeUpLeft;
FIncCamOld := FIncCam;
FObj.oldX := FObj.X;
FObj.oldY := FObj.Y;
NetServer := g_Game_IsNet and g_Game_IsServer;
AnyServer := g_Game_IsServer;
- if FGhost then
- DoLerp(4);
+ if g_Game_IsClient and (NetInterpLevel > 0) then
+ DoLerp(NetInterpLevel + 1)
+ else
+ if FGhost then
+ DoLerp(4);
if NetServer then
if FClientID >= 0 then
if FPhysics then
begin
- if not followCorpse() then
- g_Obj_Move(@FObj, True, True, True);
+ g_Obj_Move(@FObj, True, True, True);
positionChanged(); // this updates spatial accelerators
end;
if FPhysics then
begin
- if not followCorpse() then
- g_Obj_Move(@FObj, True, True, True);
+ g_Obj_Move(@FObj, True, True, True);
positionChanged(); // this updates spatial accelerators
end
else
var
AX, AY: Integer;
begin
- if NetInterpLevel < 1 then
+ FXTo := XTo;
+ FYTo := YTo;
+ if FJustTeleported or (NetInterpLevel < 1) then
begin
FObj.X := XTo;
FObj.Y := YTo;
+ if FJustTeleported then
+ begin
+ FObj.oldX := FObj.X;
+ FObj.oldY := FObj.Y;
+ end;
end
else
begin
- FXTo := XTo;
- FYTo := YTo;
-
AX := Abs(FXTo - FObj.X);
AY := Abs(FYTo - FObj.Y);
if (AX > 32) or (AX <= NetInterpLevel) then
end;
-procedure TCorpse.Damage(Value: Word; vx, vy: Integer);
+procedure TCorpse.Damage(Value: Word; SpawnerUID: Word; vx, vy: Integer);
var
pm: TPlayerModel;
Blood: TModelBlood;
if (gBodyKillEvent <> -1)
and gDelayedEvents[gBodyKillEvent].Pending then
gDelayedEvents[gBodyKillEvent].Pending := False;
- gBodyKillEvent := g_Game_DelayEvent(DE_BODYKILL, 1050, 0);
+ gBodyKillEvent := g_Game_DelayEvent(DE_BODYKILL, 1050, SpawnerUID);
end;
end
else