X-Git-Url: https://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_player.pas;h=28032e95d4ea5c2b767c165ff8b6993915e5af21;hb=a64e75f513d36924da087b8d68d725918b2639f8;hp=362c2833ecbe9a7393caf11622c1ccb5bbfdb67e;hpb=cb61300b61ba18d486d19edf315f05b5b494fac3;p=d2df-sdl.git diff --git a/src/game/g_player.pas b/src/game/g_player.pas index 362c283..28032e9 100644 --- a/src/game/g_player.pas +++ b/src/game/g_player.pas @@ -114,6 +114,7 @@ type Kills: Word; Color: TRGB; Spectator: Boolean; + UID: Word; end; TPlayerStatArray = Array of TPlayerStat; @@ -171,6 +172,7 @@ type FLastSpawnerUID: Word; FLastHit: Byte; FObj: TObj; + FXTo, FYTo: Integer; FSpectatePlayer: Integer; FFirePainTime: Integer; FFireAttacker: Word; @@ -238,7 +240,7 @@ type procedure doDamage (v: Integer); - function followCorpse(): Boolean; + function refreshCorpse(): Boolean; public FDamageBuffer: Integer; @@ -271,6 +273,7 @@ type 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; @@ -334,6 +337,8 @@ type procedure LoadState (st: TStream); virtual; procedure PauseSounds(Enable: Boolean); procedure NetFire(Wpn: Byte; X, Y, AX, AY: Integer; WID: Integer = -1); + procedure DoLerp(Level: Integer = 2); + procedure SetLerp(XTo, YTo: Integer); procedure QueueWeaponSwitch(Weapon: Byte); procedure RealizeCurrentWeapon(); procedure FlamerOn; @@ -348,6 +353,8 @@ type 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; @@ -527,7 +534,7 @@ type 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); @@ -594,7 +601,7 @@ function g_Player_Get(UID: Word): TPlayer; 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(); @@ -1434,6 +1441,8 @@ begin 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(); @@ -1513,6 +1522,7 @@ begin Color := gPlayers[a].FModel.Color; Lives := gPlayers[a].FLives; Spectator := gPlayers[a].FSpectator; + UID := gPlayers[a].FUID; end; end; end; @@ -1567,21 +1577,24 @@ begin 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; @@ -1609,6 +1622,8 @@ begin 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, @@ -2196,6 +2211,7 @@ begin FFirePainTime := 0; FFireAttacker := 0; FHandicap := 100; + FCorpse := -1; FActualModelName := 'doomer'; @@ -2440,8 +2456,11 @@ var 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; @@ -3600,7 +3619,7 @@ begin 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 @@ -4411,6 +4430,7 @@ begin FDeath := 0; FSecrets := 0; FSpawnInvul := 0; + FCorpse := -1; FReady := False; if FNoRespawn then begin @@ -4454,143 +4474,58 @@ begin // Îäèíî÷íàÿ èãðà/êîîïåðàòèâ 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); @@ -4608,6 +4543,7 @@ begin FPain := 0; FLastHit := 0; FSpawnInvul := 0; + FCorpse := -1; if not g_Game_IsServer then Exit; @@ -4781,6 +4717,8 @@ begin GameX := gMapInfo.Width div 2; GameY := gMapInfo.Height div 2; end; + FXTo := GameX; + FYTo := GameY; FAlive := False; FSpectator := True; @@ -4788,6 +4726,7 @@ begin FPhysics := False; FWantsInGame := False; FSpawned := False; + FCorpse := -1; if FNoRespawn then begin @@ -4813,7 +4752,11 @@ begin Exit; FGhost := not FGhost; FPhysics := not FGhost; - if not FGhost then + if FGhost then + begin + FXTo := FObj.X; + FYTo := FObj.Y; + end else begin FObj.Accel.X := 0; FObj.Accel.Y := 0; @@ -4958,6 +4901,11 @@ begin FObj.Y := Y-PLAYER_RECT.Y; FObj.oldX := FObj.X; // don't interpolate after respawn FObj.oldY := FObj.Y; + if FAlive and FGhost then + begin + FXTo := FObj.X; + FYTo := FObj.Y; + end; if not g_Game_IsNet then begin @@ -5011,11 +4959,12 @@ 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 @@ -5025,16 +4974,26 @@ begin 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; @@ -5055,6 +5014,12 @@ begin NetServer := g_Game_IsNet and g_Game_IsServer; AnyServer := g_Game_IsServer; + if g_Game_IsClient and (NetInterpLevel > 0) then + DoLerp(NetInterpLevel + 1) + else + if FGhost then + DoLerp(4); + if NetServer then if FClientID >= 0 then begin @@ -5113,8 +5078,7 @@ begin 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; @@ -5217,39 +5181,38 @@ begin begin if FKeys[KEY_UP].Pressed or FKeys[KEY_JUMP].Pressed then begin - FObj.Y := FObj.Y - 32; + FYTo := FObj.Y - 32; FSpectatePlayer := -1; end; if FKeys[KEY_DOWN].Pressed then begin - FObj.Y := FObj.Y + 32; + FYTo := FObj.Y + 32; FSpectatePlayer := -1; end; if FKeys[KEY_LEFT].Pressed then begin - FObj.X := FObj.X - 32; + FXTo := FObj.X - 32; FSpectatePlayer := -1; end; if FKeys[KEY_RIGHT].Pressed then begin - FObj.X := FObj.X + 32; + FXTo := FObj.X + 32; FSpectatePlayer := -1; end; - if (FObj.X < -64) then - FObj.X := -64 - else if (FObj.X > gMapInfo.Width + 32) then - FObj.X := gMapInfo.Width + 32; - if (FObj.Y < -72) then - FObj.Y := -72 - else if (FObj.Y > gMapInfo.Height + 32) then - FObj.Y := gMapInfo.Height + 32; + if (FXTo < -64) then + FXTo := -64 + else if (FXTo > gMapInfo.Width + 32) then + FXTo := gMapInfo.Width + 32; + if (FYTo < -72) then + FYTo := -72 + else if (FYTo > gMapInfo.Height + 32) then + FYTo := gMapInfo.Height + 32; 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 @@ -5261,8 +5224,8 @@ begin if gPlayers[FSpectatePlayer] <> nil then if gPlayers[FSpectatePlayer].alive then begin - FObj.X := gPlayers[FSpectatePlayer].GameX; - FObj.Y := gPlayers[FSpectatePlayer].GameY; + FXTo := gPlayers[FSpectatePlayer].GameX; + FYTo := gPlayers[FSpectatePlayer].GameY; end; end; @@ -5721,6 +5684,39 @@ begin else if (FAngle = ANGLE_LEFTUP) or (FAngle = ANGLE_RIGHTUP) then SetAction(A_ATTACKUP); end; +procedure TPlayer.DoLerp(Level: Integer = 2); +begin + if FObj.X <> FXTo then FObj.X := Lerp(FObj.X, FXTo, Level); + if FObj.Y <> FYTo then FObj.Y := Lerp(FObj.Y, FYTo, Level); +end; + +procedure TPlayer.SetLerp(XTo, YTo: Integer); +var + AX, AY: Integer; +begin + 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 + AX := Abs(FXTo - FObj.X); + AY := Abs(FYTo - FObj.Y); + if (AX > 32) or (AX <= NetInterpLevel) then + FObj.X := FXTo; + if (AY > 32) or (AY <= NetInterpLevel) then + FObj.Y := FYTo; + end; +end; + function TPlayer.FullInLift(XInc, YInc: Integer): Integer; begin if g_Map_CollidePanel(FObj.X+PLAYER_RECT.X+XInc, FObj.Y+PLAYER_RECT.Y+YInc, @@ -6543,7 +6539,7 @@ begin end; -procedure TCorpse.Damage(Value: Word; vx, vy: Integer); +procedure TCorpse.Damage(Value: Word; SpawnerUID: Word; vx, vy: Integer); var pm: TPlayerModel; Blood: TModelBlood; @@ -6574,7 +6570,7 @@ begin 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