X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_player.pas;h=64e61666557c23ca74ea1011820a08725ee4d525;hb=05a8dcb37440aa1f010e418de05ecc153340956f;hp=90588ba10e31d4be1d60592fad315687274c8aff;hpb=39b5a33c63812024e33054658dad9bc72aebe4ac;p=d2df-sdl.git diff --git a/src/game/g_player.pas b/src/game/g_player.pas index 90588ba..64e6166 100644 --- a/src/game/g_player.pas +++ b/src/game/g_player.pas @@ -186,7 +186,9 @@ type FActionChanged: Boolean; FAngle: SmallInt; FFireAngle: SmallInt; + FIncCamOld: Integer; FIncCam: Integer; + FSlopeOld: Integer; FShellTimer: Integer; FShellType: Byte; FSawSound: TPlayableSound; @@ -237,7 +239,7 @@ type procedure doDamage (v: Integer); - function followCorpse(): Boolean; + function refreshCorpse(): Boolean; public FDamageBuffer: Integer; @@ -270,6 +272,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; @@ -325,6 +328,7 @@ type procedure DrawIndicator(Color: TRGB); procedure DrawBubble(); procedure DrawGUI(); + procedure PreUpdate(); procedure Update(); virtual; procedure RememberState(); procedure RecallState(); @@ -348,6 +352,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; @@ -379,6 +385,8 @@ type property GameAccelX: Integer read FObj.Accel.X write FObj.Accel.X; 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; @@ -525,7 +533,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); @@ -581,6 +589,7 @@ function g_Player_Create(ModelName: String; Color: TRGB; Team: Byte; Bot: Boole function g_Player_CreateFromState (st: TStream): Word; procedure g_Player_Remove(UID: Word); procedure g_Player_ResetTeams(); +procedure g_Player_PreUpdate(); procedure g_Player_UpdateAll(); procedure g_Player_DrawAll(); procedure g_Player_DrawDebug(p: TPlayer); @@ -591,7 +600,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(); @@ -1368,6 +1377,16 @@ begin SetLength(SavedStates, 0); end; +procedure g_Player_PreUpdate(); +var + i: Integer; +begin + if gPlayers = nil then Exit; + for i := 0 to High(gPlayers) do + if gPlayers[i] <> nil then + gPlayers[i].PreUpdate(); +end; + procedure g_Player_UpdateAll(); var i: Integer; @@ -1421,6 +1440,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(); @@ -1554,21 +1575,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; @@ -1596,6 +1620,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, @@ -1713,6 +1739,9 @@ begin if gGibs[i].alive then with gGibs[i] do begin + Obj.oldX := Obj.X; + Obj.oldY := Obj.Y; + vel := Obj.Vel; mr := g_Obj_Move(@Obj, True, False, True); positionChanged(); // this updates spatial accelerators @@ -1763,6 +1792,9 @@ begin if gShells[i].alive then with gShells[i] do begin + Obj.oldX := Obj.X; + Obj.oldY := Obj.Y; + vel := Obj.Vel; mr := g_Obj_Move(@Obj, True, False, True); positionChanged(); // this updates spatial accelerators @@ -1851,7 +1883,7 @@ procedure TShell.positionChanged (); inline; begin end; procedure g_Player_DrawCorpses(); var - i: Integer; + i, fX, fY: Integer; a: TDFPoint; begin if gGibs <> nil then @@ -1862,13 +1894,15 @@ begin if not g_Obj_Collide(sX, sY, sWidth, sHeight, @Obj) then Continue; + Obj.lerp(gLerpFactor, fX, fY); + a.X := Obj.Rect.X+(Obj.Rect.Width div 2); a.y := Obj.Rect.Y+(Obj.Rect.Height div 2); - e_DrawAdv(ID, Obj.X, Obj.Y, 0, True, False, RAngle, @a, TMirrorType.None); + e_DrawAdv(ID, fX, fY, 0, True, False, RAngle, @a, TMirrorType.None); e_Colors := Color; - e_DrawAdv(MaskID, Obj.X, Obj.Y, 0, True, False, RAngle, @a, TMirrorType.None); + e_DrawAdv(MaskID, fX, fY, 0, True, False, RAngle, @a, TMirrorType.None); e_Colors.R := 255; e_Colors.G := 255; e_Colors.B := 255; @@ -1882,7 +1916,7 @@ end; procedure g_Player_DrawShells(); var - i: Integer; + i, fX, fY: Integer; a: TDFPoint; begin if gShells <> nil then @@ -1893,10 +1927,12 @@ begin if not g_Obj_Collide(sX, sY, sWidth, sHeight, @Obj) then Continue; + Obj.lerp(gLerpFactor, fX, fY); + a.X := CX; a.Y := CY; - e_DrawAdv(SpriteID, Obj.X, Obj.Y, 0, True, False, RAngle, @a, TMirrorType.None); + e_DrawAdv(SpriteID, fX, fY, 0, True, False, RAngle, @a, TMirrorType.None); end; end; @@ -2173,6 +2209,7 @@ begin FFirePainTime := 0; FFireAttacker := 0; FHandicap := 100; + FCorpse := -1; FActualModelName := 'doomer'; @@ -2338,7 +2375,7 @@ end; procedure TPlayer.DrawIndicator(Color: TRGB); var - indX, indY: Integer; + indX, indY, fX, fY, fSlope: Integer; indW, indH: Word; indA: Single; a: TDFPoint; @@ -2347,6 +2384,10 @@ var c: TRGB; begin if FAlive then + begin + FObj.lerp(gLerpFactor, fX, fY); + fSlope := nlerp(FSlopeOld, FObj.slopeUpLeft, gLerpFactor); + case gPlayerIndicatorStyle of 0: begin @@ -2359,31 +2400,32 @@ begin if (FObj.X + FObj.Rect.X) < 0 then begin indA := 90; - indX := FObj.X + FObj.Rect.X + FObj.Rect.Width; - indY := FObj.Y + FObj.Rect.Y + (FObj.Rect.Height - indW) div 2; + indX := fX + FObj.Rect.X + FObj.Rect.Width; + indY := fY + FObj.Rect.Y + (FObj.Rect.Height - indW) div 2; end else if (FObj.X + FObj.Rect.X + FObj.Rect.Width) > Max(gMapInfo.Width, gPlayerScreenSize.X) then begin indA := 270; - indX := FObj.X + FObj.Rect.X - indH; - indY := FObj.Y + FObj.Rect.Y + (FObj.Rect.Height - indW) div 2; + indX := fX + FObj.Rect.X - indH; + indY := fY + FObj.Rect.Y + (FObj.Rect.Height - indW) div 2; end - else if (fObj.Y - indH) < 0 then + else if (FObj.Y - indH) < 0 then begin indA := 180; - indX := FObj.X + FObj.Rect.X + (FObj.Rect.Width - indW) div 2; - indY := FObj.Y + FObj.Rect.Y + FObj.Rect.Height; + indX := fX + FObj.Rect.X + (FObj.Rect.Width - indW) div 2; + indY := fY + FObj.Rect.Y + FObj.Rect.Height; end else begin indA := 0; - indX := FObj.X + FObj.Rect.X + (FObj.Rect.Width - indW) div 2; - indY := FObj.Y - indH; + indX := fX + FObj.Rect.X + (FObj.Rect.Width - indW) div 2; + 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); @@ -2397,23 +2439,28 @@ begin 1: begin e_TextureFontGetSize(gStdFont, nW, nH); - indX := FObj.X + FObj.Rect.X + (FObj.Rect.Width - Length(FName) * nW) div 2; - indY := FObj.Y - nH; + indX := fX + FObj.Rect.X + (FObj.Rect.Width - Length(FName) * nW) div 2; + indY := fY - nH + fSlope; e_TextureFontPrintEx(indX, indY, FName, gStdFont, Color.R, Color.G, Color.B, 1.0, True); end; end; + end; end; procedure TPlayer.DrawBubble(); var - bubX, bubY: Integer; + bubX, bubY, fX, fY: Integer; ID: LongWord; Rb, Gb, Bb, Rw, Gw, Bw: SmallInt; Dot: Byte; + CObj: TObj; begin - bubX := FObj.X+FObj.Rect.X + IfThen(FDirection = TDirection.D_LEFT, -4, 18); - bubY := FObj.Y+FObj.Rect.Y - 18; + 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; Gb := 64; Bb := 64; @@ -2423,8 +2470,8 @@ begin case gChatBubble of 1: // simple textual non-bubble begin - bubX := FObj.X+FObj.Rect.X - 11; - bubY := FObj.Y+FObj.Rect.Y - 17; + bubX := fX+FObj.Rect.X - 11; + bubY := fY+FObj.Rect.Y - 17; e_TextureFontPrint(bubX, bubY, '[...]', gStdFont); Exit; end; @@ -2491,7 +2538,11 @@ var w, h: Word; dr: Boolean; Mirror: TMirrorType; + fX, fY, fSlope: Integer; begin + FObj.lerp(gLerpFactor, fX, fY); + fSlope := nlerp(FSlopeOld, FObj.slopeUpLeft, gLerpFactor); + if FAlive then begin if Direction = TDirection.D_RIGHT then @@ -2501,8 +2552,8 @@ begin if FPunchAnim <> nil then begin - FPunchAnim.Draw(FObj.X+IfThen(Direction = TDirection.D_LEFT, 15-FObj.Rect.X, FObj.Rect.X-15), - FObj.Y+FObj.Rect.Y-11, Mirror); + FPunchAnim.Draw(fX+IfThen(Direction = TDirection.D_LEFT, 15-FObj.Rect.X, FObj.Rect.X-15), + fY+fSlope+FObj.Rect.Y-11, Mirror); if FPunchAnim.played then begin FPunchAnim.Free; @@ -2515,11 +2566,11 @@ begin begin e_GetTextureSize(ID, @w, @h); if FDirection = TDirection.D_LEFT then - e_Draw(ID, FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)-(w div 2)+4, - FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2)-(h div 2)-7+FObj.slopeUpLeft, 0, True, False) + 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+fSlope, 0, True, False) else - e_Draw(ID, FObj.X+FObj.Rect.X+(FObj.Rect.Width div 2)-(w div 2)-2, - FObj.Y+FObj.Rect.Y+(FObj.Rect.Height div 2)-(h div 2)-7+FObj.slopeUpLeft, 0, True, False); + 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+fSlope, 0, True, False); end; if FMegaRulez[MR_INVIS] > gTime then @@ -2532,15 +2583,15 @@ begin else dr := True; if dr then - FModel.Draw(FObj.X, FObj.Y+FObj.slopeUpLeft, 200) + FModel.Draw(fX, fY+fSlope, 200) else - FModel.Draw(FObj.X, FObj.Y+FObj.slopeUpLeft); + FModel.Draw(fX, fY+fSlope); end else - FModel.Draw(FObj.X, FObj.Y+FObj.slopeUpLeft, 254); + FModel.Draw(fX, fY+fSlope, 254); end else - FModel.Draw(FObj.X, FObj.Y+FObj.slopeUpLeft); + FModel.Draw(fX, fY+fSlope); end; if g_debug_Frames then @@ -3566,7 +3617,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 @@ -4377,6 +4428,7 @@ begin FDeath := 0; FSecrets := 0; FSpawnInvul := 0; + FCorpse := -1; FReady := False; if FNoRespawn then begin @@ -4396,6 +4448,8 @@ begin ReleaseKeys(); FDamageBuffer := 0; + FSlopeOld := 0; + FIncCamOld := 0; FIncCam := 0; FBFGFireCounter := -1; FShellTimer := -1; @@ -4418,143 +4472,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); @@ -4564,12 +4533,15 @@ var Anim: TAnimation; ID: DWORD; begin + FSlopeOld := 0; + FIncCamOld := 0; FIncCam := 0; FBFGFireCounter := -1; FShellTimer := -1; FPain := 0; FLastHit := 0; FSpawnInvul := 0; + FCorpse := -1; if not g_Game_IsServer then Exit; @@ -4665,6 +4637,8 @@ begin // Óñòàíîâêà êîîðäèíàò è ñáðîñ âñåõ ïàðàìåòðîâ: FObj.X := RespawnPoint.X-PLAYER_RECT.X; FObj.Y := RespawnPoint.Y-PLAYER_RECT.Y; + FObj.oldX := FObj.X; // don't interpolate after respawn + FObj.oldY := FObj.Y; FObj.Vel.X := 0; FObj.Vel.Y := 0; FObj.Accel.X := 0; @@ -4750,6 +4724,7 @@ begin FPhysics := False; FWantsInGame := False; FSpawned := False; + FCorpse := -1; if FNoRespawn then begin @@ -4922,6 +4897,8 @@ begin FObj.X := X-PLAYER_RECT.X; 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; @@ -4980,11 +4957,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 @@ -4994,16 +4972,34 @@ 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; + FIncCamOld := FIncCam; + FObj.oldX := FObj.X; + FObj.oldY := FObj.Y; +end; + procedure TPlayer.Update(); var b: Byte; @@ -5080,8 +5076,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; @@ -5215,8 +5210,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 else @@ -5698,16 +5692,20 @@ procedure TPlayer.SetLerp(XTo, YTo: Integer); 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 @@ -5974,6 +5972,7 @@ begin SavedState.MaxAmmo[i] := FMaxAmmo[i]; SavedState.Rulez := FRulez - [R_KEY_RED, R_KEY_GREEN, R_KEY_BLUE]; + FSavedStateNum := -1; for i := Low(SavedStates) to High(SavedStates) do if not SavedStates[i].Used then begin @@ -5987,7 +5986,7 @@ begin end; SavedState.Used := True; - SavedStates[i] := SavedState; + SavedStates[FSavedStateNum] := SavedState; end; procedure TPlayer.RecallState(); @@ -6538,7 +6537,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; @@ -6569,7 +6568,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 @@ -6585,17 +6584,21 @@ begin end; procedure TCorpse.Draw(); +var + fX, fY: Integer; begin if FState = CORPSE_STATE_REMOVEME then Exit; + FObj.lerp(gLerpFactor, fX, fY); + if FAnimation <> nil then - FAnimation.Draw(FObj.X, FObj.Y, TMirrorType.None); + FAnimation.Draw(fX, fY, TMirrorType.None); if FAnimationMask <> nil then begin e_Colors := FColor; - FAnimationMask.Draw(FObj.X, FObj.Y, TMirrorType.None); + FAnimationMask.Draw(fX, fY, TMirrorType.None); e_Colors.R := 255; e_Colors.G := 255; e_Colors.B := 255; @@ -6609,6 +6612,9 @@ begin if FState = CORPSE_STATE_REMOVEME then Exit; + FObj.oldX := FObj.X; + FObj.oldY := FObj.Y; + if gTime mod (GAME_TICK*2) <> 0 then begin g_Obj_Move(@FObj, True, True, True);