summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 2f006e5)
raw | patch | inline | side by side (parent: 2f006e5)
author | fgsfds <pvt.fgsfds@gmail.com> | |
Mon, 2 Mar 2020 21:59:55 +0000 (00:59 +0300) | ||
committer | fgsfds <pvt.fgsfds@gmail.com> | |
Mon, 2 Mar 2020 21:59:55 +0000 (00:59 +0300) |
diff --git a/src/game/g_game.pas b/src/game/g_game.pas
index affc870bddbdb010228895f4b25277a4af62d0e9..b0e9e01feb36fd0bf5cbfb7e46c6c67b5134d917 100644 (file)
--- a/src/game/g_game.pas
+++ b/src/game/g_game.pas
gPlayer2: TPlayer = nil;
gPlayerDrawn: TPlayer = nil;
gTime: LongWord;
+ gLerpFactor: Single = 1.0;
gSwitchGameMode: Byte = GM_DM;
gHearPoint1, gHearPoint2: THearPoint;
gSoundEffectsDF: Boolean = False;
end;
end;
+ // these are in separate PreUpdate functions because they can interact during Update()
+ // we don't care that much about corpses and gibs
+ g_Player_PreUpdate();
+ g_Monsters_PreUpdate();
+ g_Items_PreUpdate();
+ g_Weapon_PreUpdate();
+
// Îáíîâëÿåì âñå îñòàëüíîå:
g_Map_Update();
g_Items_Update();
procedure DrawPlayer(p: TPlayer);
var
- px, py, a, b, c, d, i: Integer;
+ px, py, a, b, c, d, i, fX, fY: Integer;
//R: TRect;
begin
if (p = nil) or (p.FDummy) then
glPushMatrix();
- px := p.GameX + PLAYER_RECT_CX;
- py := p.GameY + PLAYER_RECT_CY+p.Obj.slopeUpLeft;
+ p.Obj.lerp(gLerpFactor, fX, fY);
+ px := fX + PLAYER_RECT_CX;
+ py := fY + PLAYER_RECT_CY+p.Obj.slopeUpLeft;
if (g_dbg_scale = 1.0) and (not g_dbg_ignore_bounds) then
begin
p.IncCam := nclamp(p.IncCam, min(0, -120 - i), 0);
end;
- sY := sY - p.IncCam;
+ sY := sY - nlerp(p.IncCamOld, p.IncCam, gLerpFactor);
if (not g_dbg_ignore_bounds) then
begin
end;
'r_reset':
begin
- sys_EnableVSync(gVSync);
gRC_Width := Max(1, gRC_Width);
gRC_Height := Max(1, gRC_Height);
gBPP := Max(1, gBPP);
e_LogWriteln('resolution changed')
else
e_LogWriteln('resolution not changed');
+ sys_EnableVSync(gVSync);
end;
'g_language':
begin
diff --git a/src/game/g_gfx.pas b/src/game/g_gfx.pas
index 8094c4e4e1af00e578f2f6d82d70340e75c565f0..bf8fc5aa2fd8a5e4d90b3dbd8ca47cbfb13ecfaa 100644 (file)
--- a/src/game/g_gfx.pas
+++ b/src/game/g_gfx.pas
PParticle = ^TParticle;
TParticle = record
x, y: Integer;
+ oldX, oldY: Integer;
velX, velY: Single;
accelX, accelY: Single;
state: TPartState;
TOnceAnim = record
AnimType: Byte;
x, y: Integer;
+ oldX, oldY: Integer;
Animation: TAnimation;
end;
end;
begin
+ oldx := x;
+ oldy := y;
// awake sleeping particle, if necessary
if awakeDirty then
begin
begin
x := fX-devX1+Random(devX2);
y := fY-devY1+Random(devY2);
+ oldx := x;
+ oldy := y;
// check for level bounds
if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then continue;
accelY := 0.8;
end;
+ oldx := x;
+ oldy := y;
+
// check for level bounds
if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then continue;
begin
x := fX-devX1+Random(devX2);
y := fY-devY1+Random(devY2);
+ oldx := x;
+ oldy := y;
// check for level bounds
if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then continue;
begin
x := fX-devX1+Random(devX2);
y := fY-devY1+Random(devY2);
+ oldx := x;
+ oldy := y;
// check for level bounds
if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then continue;
begin
x := fX-devX1+Random(devX2);
y := fY-devY1+Random(devY2);
+ oldx := x;
+ oldy := y;
// check for level bounds
if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then continue;
for a := 0 to High(OnceAnims) do
if OnceAnims[a].Animation <> nil then
begin
+ OnceAnims[a].oldx := OnceAnims[a].x;
+ OnceAnims[a].oldy := OnceAnims[a].y;
+
case OnceAnims[a].AnimType of
ONCEANIM_SMOKE:
begin
procedure g_GFX_Draw ();
var
- a, len: Integer;
+ a, len, fx, fy: Integer;
begin
if not gpart_dbg_enabled then exit;
if not alive then continue;
if (x >= sX) and (y >= sY) and (x <= sX+sWidth) and (sY <= sY+sHeight) then
begin
+ fx := nlerp(oldx, x, gLerpFactor);
+ fy := nlerp(oldy, y, gLerpFactor);
glColor4ub(red, green, blue, alpha);
- glVertex2f(x+0.37, y+0.37);
+ glVertex2f(fx+0.37, fy+0.37);
end;
end;
end;
begin
if (OnceAnims[a].Animation <> nil) then
begin
- with OnceAnims[a] do Animation.Draw(x, y, TMirrorType.None);
+ with OnceAnims[a] do
+ begin
+ fx := nlerp(oldx, x, gLerpFactor);
+ fy := nlerp(oldy, y, gLerpFactor);
+ Animation.Draw(x, y, TMirrorType.None);
+ end;
end;
end;
end;
diff --git a/src/game/g_items.pas b/src/game/g_items.pas
index 8d476efe76e6fa3fc1c27f98644e2def961704b4..88a9cba1c433057f3ede53d4bf118ad43aecbc9c 100644 (file)
--- a/src/game/g_items.pas
+++ b/src/game/g_items.pas
function g_Items_Create(X, Y: Integer; ItemType: Byte;
Fall, Respawnable: Boolean; AdjCoord: Boolean = False; ForcedID: Integer = -1): DWORD;
procedure g_Items_SetDrop (ID: DWORD);
+procedure g_Items_PreUpdate();
procedure g_Items_Update();
procedure g_Items_Draw();
procedure g_Items_DrawDrop();
it.dropped := false;
g_Obj_Init(@it.Obj);
+ it.Obj.oldX := X;
+ it.Obj.oldY := Y;
it.Obj.X := X;
it.Obj.Y := Y;
it.Obj.Rect.Width := ITEMSIZE[ItemType][0];
result := find_id;
end;
+procedure g_Items_PreUpdate ();
+var
+ i: Integer;
+begin
+ if (ggItems = nil) then Exit;
+ for i := 0 to High(ggItems) do
+ if (ggItems[i].ItemType <> ITEM_NONE) and ggItems[i].slotIsUsed then
+ begin
+ ggItems[i].Obj.oldX := ggItems[i].Obj.X;
+ ggItems[i].Obj.oldY := ggItems[i].Obj.Y;
+ end;
+end;
procedure g_Items_Update ();
var
Anim.Free();
end;
+ Obj.oldX := InitX;
+ Obj.oldY := InitY;
Obj.X := InitX;
Obj.Y := InitY;
Obj.Vel.X := 0;
procedure itemsDrawInternal (dropflag: Boolean);
var
- i: Integer;
+ i, fX, fY: Integer;
it: PItem;
begin
if (ggItems = nil) then exit;
begin
if g_Collide(Obj.X, Obj.Y, Obj.Rect.Width, Obj.Rect.Height, sX, sY, sWidth, sHeight) then
begin
+ Obj.lerp(gLerpFactor, fX, fY);
if (Animation = nil) then
begin
- e_Draw(gItemsTexturesID[ItemType], Obj.X, Obj.Y, 0, true, false);
+ e_Draw(gItemsTexturesID[ItemType], fX, fY, 0, true, false);
end
else
begin
- Animation.Draw(Obj.X, Obj.Y, TMirrorType.None);
+ Animation.Draw(fX, fY, TMirrorType.None);
end;
if g_debug_Frames then
begin
if (ID < Length(ggItems)) then
begin
+ ggItems[ID].Obj.oldX := ggItems[ID].Obj.X;
+ ggItems[ID].Obj.oldY := ggItems[ID].Obj.Y;
ggItems[ID].alive := false;
ggItems[ID].RespawnTime := IfThen(gLMSRespawn = LMS_RESPAWN_NONE, gGameSettings.ItemRespawnTime, 15) * 36;
end;
it := @ggItems[ID];
if (it.arrIdx <> Integer(ID)) then raise Exception.Create('g_Items_Remove: arrIdx desync');
+ it.Obj.oldX := it.Obj.X;
+ it.Obj.oldY := it.Obj.Y;
trig := it.SpawnTrigger;
releaseItem(ID);
for i := 0 to High(ggItems) do
begin
it := @ggItems[i];
+ it.Obj.oldX := it.Obj.X;
+ it.Obj.oldY := it.Obj.Y;
if not it.slotIsUsed then continue;
if it.Respawnable and (it.ItemType <> ITEM_NONE) then
begin
index ac28f340a08b8fcd694d0aee764a53a32b086c4c..02e7ed589ae6fa4b69b7b686ebd50f69ee5752af 100644 (file)
--- a/src/game/g_monsters.pas
+++ b/src/game/g_monsters.pas
function Damage(aDamage: Word; VelX, VelY: Integer; SpawnerUID: Word; t: Byte): Boolean;
function Heal(Value: Word): Boolean;
procedure BFGHit();
+ procedure PreUpdate();
procedure Update();
procedure ClientUpdate();
procedure ClientAttack(wx, wy, atx, aty: Integer);
procedure g_Monsters_Free (clearGrid: Boolean=true);
function g_Monsters_Create (MonsterType: Byte; X, Y: Integer; Direction: TDirection;
AdjCoord: Boolean = False; ForcedUID: Integer = -1): TMonster;
+procedure g_Monsters_PreUpdate ();
procedure g_Monsters_Update ();
procedure g_Monsters_Draw ();
procedure g_Monsters_DrawHealth ();
FStartDirection := Direction;
FStartX := GameX;
FStartY := GameY;
+ FObj.oldX := FObj.X;
+ FObj.oldY := FObj.Y;
end;
mon.positionChanged();
end;
end;
+procedure g_Monsters_PreUpdate();
+var
+ a: Integer;
+begin
+ if gMonsters = nil then Exit;
+ for a := 0 to High(gMonsters) do
+ if (gMonsters[a] <> nil) and (not gMonsters[a].FRemoved) then
+ gMonsters[a].PreUpdate();
+end;
+
procedure g_Monsters_Update();
var
a: Integer;
procedure TMonster.Draw();
var
m: TMirrorType;
- dx, dy, c: Integer;
+ dx, dy, c, fX, fY: Integer;
o: TObj;
begin
//e_CharFont_Print(gMenuSmallFont, Obj.X+Obj.Rect.X, Obj.Y+Obj.Rect.Y, 'TYPE: '+IntToStr(FMonsterType));
//e_CharFont_Print(gMenuSmallFont, Obj.X+Obj.Rect.X, Obj.Y+Obj.Rect.Y+16, 'STATE: '+IntToStr(FState));
+ FObj.lerp(gLerpFactor, fX, fY);
+
// Åñëè êîëäóí ñòðåëÿåò, òî ðèñóåì îãîíü:
if FMonsterType = MONSTER_VILE then
if FState = MONSTATE_SHOOT then
end;
// Ðèñóåì:
- FAnim[FCurAnim, FDirection].Draw(Obj.X+dx, Obj.Y+dy, m);
+ FAnim[FCurAnim, FDirection].Draw(fX+dx, fY+dy, m);
end;
if g_debug_Frames then
FObj.X := X - FObj.Rect.X;
FObj.Y := Y - FObj.Rect.Y;
+ FObj.oldX := FObj.X; // don't interpolate after teleport
+ FObj.oldY := FObj.Y;
positionChanged();
if dir = 1 then
Result := True;
end;
+procedure TMonster.PreUpdate();
+begin
+ FObj.oldX := FObj.X;
+ FObj.oldY := FObj.Y;
+end;
+
procedure TMonster.Update();
var
a, b, sx, sy, wx, wy, oldvelx: Integer;
diff --git a/src/game/g_netmsg.pas b/src/game/g_netmsg.pas
index 5e95a6a57dd97b42a4d31178c153e94589092816..92084b1304662060019422a77096ad59f138a132 100644 (file)
--- a/src/game/g_netmsg.pas
+++ b/src/game/g_netmsg.pas
GameVelY := M.ReadLongInt();
GameAccelX := M.ReadLongInt();
GameAccelY := M.ReadLongInt();
- SetLerp(TmpX, TmpY);
+ GameX := TmpX;
+ GameY := TmpY;
if NetForcePlayerUpdate then Update();
end;
end;
diff --git a/src/game/g_options.pas b/src/game/g_options.pas
index 3f53262185953dc4fc8a1a306df54d3ef49cdd62..4a561e090c08bfa6670a3102abc6c3d5c84741c1 100644 (file)
--- a/src/game/g_options.pas
+++ b/src/game/g_options.pas
glLegacyNPOT: Boolean;
glRenderToFBO: Boolean = True;
gTextureFilter: Boolean;
+ gLerpActors: Boolean = True;
gNoSound: Boolean;
gSoundLevel: Integer;
gMusicLevel: Integer;
conRegVar('r_vsync', @gVSync, '', '');
conRegVar('r_texfilter', @gTextureFilter, '', '');
conRegVar('r_npot', @glNPOTOverride, '', '');
+ conRegVar('r_interp', @gLerpActors, '', 'interpolate actors');
(* Sound *)
conRegVar('s_nosound', @gNoSound, '', '');
diff --git a/src/game/g_phys.pas b/src/game/g_phys.pas
index 9d93a5b560ec059d0dc6e5d984103f66acf88d57..af569ea1e1784185f70f13aa5ae47f0ef955fa1d 100644 (file)
--- a/src/game/g_phys.pas
+++ b/src/game/g_phys.pas
// this is purely visual change, it won't affect anything else
slopeUpLeft: Integer; // left to go
slopeFramesLeft: Integer; // frames left to go
+ // for frame interpolation
+ oldX, oldY: Integer;
+ procedure lerp(t: Single; out fX, fY: Integer);
end;
const
const
SmoothSlopeFrames = 4;
+procedure TObj.lerp(t: Single; out fX, fY: Integer);
+begin
+ fX := nlerp(oldX, X, t);
+ fY := nlerp(oldY, Y, t);
+end;
function g_Obj_StayOnStep(Obj: PObj): Boolean; inline;
begin
diff --git a/src/game/g_player.pas b/src/game/g_player.pas
index 49cd657bb73ba05a37606ec76588e011be622590..db39cb84b0961e1260f840fb8a885e710648b1a8 100644 (file)
--- a/src/game/g_player.pas
+++ b/src/game/g_player.pas
FActionChanged: Boolean;
FAngle: SmallInt;
FFireAngle: SmallInt;
+ FIncCamOld: Integer;
FIncCam: Integer;
FShellTimer: Integer;
FShellType: Byte;
procedure DrawIndicator(Color: TRGB);
procedure DrawBubble();
procedure DrawGUI();
+ procedure PreUpdate();
procedure Update(); virtual;
procedure RememberState();
procedure RecallState();
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 UID: Word read FUID write FUID;
property JustTeleported: Boolean read FJustTeleported write FJustTeleported;
property NetTime: LongWord read FNetTime write FNetTime;
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);
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;
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
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
procedure g_Player_DrawCorpses();
var
- i: Integer;
+ i, fX, fY: Integer;
a: TDFPoint;
begin
if gGibs <> nil then
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;
procedure g_Player_DrawShells();
var
- i: Integer;
+ i, fX, fY: Integer;
a: TDFPoint;
begin
if gShells <> nil then
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;
procedure TPlayer.DrawIndicator(Color: TRGB);
var
- indX, indY: Integer;
+ indX, indY, fX, fY: Integer;
indW, indH: Word;
indA: Single;
a: TDFPoint;
c: TRGB;
begin
if FAlive then
+ begin
+ FObj.lerp(gLerpFactor, fX, fY);
case gPlayerIndicatorStyle of
0:
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;
indX := EnsureRange(indX, 0, Max(gMapInfo.Width, gPlayerScreenSize.X) - indW);
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;
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;
begin
- bubX := FObj.X+FObj.Rect.X + IfThen(FDirection = TDirection.D_LEFT, -4, 18);
- bubY := FObj.Y+FObj.Rect.Y - 18;
+ FObj.lerp(gLerpFactor, fX, fY);
+ bubX := fX+FObj.Rect.X + IfThen(FDirection = TDirection.D_LEFT, -4, 18);
+ bubY := fY+FObj.Rect.Y - 18;
Rb := 64;
Gb := 64;
Bb := 64;
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;
w, h: Word;
dr: Boolean;
Mirror: TMirrorType;
+ fX, fY: Integer;
begin
+ FObj.lerp(gLerpFactor, fX, fY);
+
if FAlive then
begin
if Direction = TDirection.D_RIGHT then
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+FObj.Rect.Y-11, Mirror);
if FPunchAnim.played then
begin
FPunchAnim.Free;
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+FObj.slopeUpLeft, 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+FObj.slopeUpLeft, 0, True, False);
end;
if FMegaRulez[MR_INVIS] > gTime then
else
dr := True;
if dr then
- FModel.Draw(FObj.X, FObj.Y+FObj.slopeUpLeft, 200)
+ FModel.Draw(fX, fY+FObj.slopeUpLeft, 200)
else
- FModel.Draw(FObj.X, FObj.Y+FObj.slopeUpLeft);
+ FModel.Draw(fX, fY+FObj.slopeUpLeft);
end
else
- FModel.Draw(FObj.X, FObj.Y+FObj.slopeUpLeft, 254);
+ FModel.Draw(fX, fY+FObj.slopeUpLeft, 254);
end
else
- FModel.Draw(FObj.X, FObj.Y+FObj.slopeUpLeft);
+ FModel.Draw(fX, fY+FObj.slopeUpLeft);
end;
if g_debug_Frames then
ReleaseKeys();
FDamageBuffer := 0;
+ FIncCamOld := 0;
FIncCam := 0;
FBFGFireCounter := -1;
FShellTimer := -1;
Anim: TAnimation;
ID: DWORD;
begin
+ FIncCamOld := 0;
FIncCam := 0;
FBFGFireCounter := -1;
FShellTimer := -1;
// Óñòàíîâêà êîîðäèíàò è ñáðîñ âñåõ ïàðàìåòðîâ:
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;
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;
end;
end;
+procedure TPlayer.PreUpdate();
+begin
+ FIncCamOld := FIncCam;
+ FObj.oldX := FObj.X;
+ FObj.oldY := FObj.Y;
+end;
+
procedure TPlayer.Update();
var
b: Byte;
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 FGhost then
+ DoLerp(4);
if NetServer then
if FClientID >= 0 then
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;
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);
diff --git a/src/game/g_weapons.pas b/src/game/g_weapons.pas
index 632cb1344c3e4728f37478e4e683e1d1ac652cb0..bb17a4138972d82f07ac7674dc966e543cec69d3 100644 (file)
--- a/src/game/g_weapons.pas
+++ b/src/game/g_weapons.pas
function g_Weapon_Explode(X, Y: Integer; rad: Integer; SpawnerUID: Word): Boolean;
procedure g_Weapon_BFG9000(X, Y: Integer; SpawnerUID: Word);
+procedure g_Weapon_PreUpdate();
procedure g_Weapon_Update();
procedure g_Weapon_Draw();
function g_Weapon_Danger(UID: Word; X, Y: Integer; Width, Height: Word; Time: Byte): Boolean;
end;
end;
+ Shots[find_id].Obj.oldX := X;
+ Shots[find_id].Obj.oldY := Y;
Shots[find_id].Obj.X := X;
Shots[find_id].Obj.Y := Y;
Shots[find_id].Obj.Vel.X := XV;
if a = 0 then
a := 1;
+ Shots[i].Obj.oldX := x;
+ Shots[i].Obj.oldY := y;
Shots[i].Obj.X := x;
Shots[i].Obj.Y := y;
Shots[i].Obj.Vel.X := (xd*s) div a;
end;
end;
+procedure g_Weapon_PreUpdate();
+var
+ i: Integer;
+begin
+ if Shots = nil then Exit;
+ for i := 0 to High(Shots) do
+ if Shots[i].ShotType <> 0 then
+ begin
+ Shots[i].Obj.oldX := Shots[i].Obj.X;
+ Shots[i].Obj.oldY := Shots[i].Obj.Y;
+ end;
+end;
+
procedure g_Weapon_Update();
var
i, a, h, cx, cy, oldvx, oldvy, tf: Integer;
procedure g_Weapon_Draw();
var
- i: Integer;
+ i, fX, fY: Integer;
a: SmallInt;
p: TDFPoint;
begin
else
a := 0;
+ Obj.lerp(gLerpFactor, fX, fY);
p.X := Obj.Rect.Width div 2;
p.Y := Obj.Rect.Height div 2;
if (Shots[i].ShotType = WEAPON_BARON_FIRE) or
(Shots[i].ShotType = WEAPON_MANCUB_FIRE) or
(Shots[i].ShotType = WEAPON_SKEL_FIRE) then
- Animation.DrawEx(Obj.X, Obj.Y, TMirrorType.None, p, a)
+ Animation.DrawEx(fX, fY, TMirrorType.None, p, a)
else
- Animation.Draw(Obj.X, Obj.Y, TMirrorType.None);
+ Animation.Draw(fX, fY, TMirrorType.None);
end
else if TextureID <> 0 then
begin
if (Shots[i].ShotType = WEAPON_ROCKETLAUNCHER) then
- e_DrawAdv(TextureID, Obj.X, Obj.Y, 0, True, False, a, @p, TMirrorType.None)
+ e_DrawAdv(TextureID, fX, fY, 0, True, False, a, @p, TMirrorType.None)
else if (Shots[i].ShotType <> WEAPON_FLAMETHROWER) then
- e_Draw(TextureID, Obj.X, Obj.Y, 0, True, False);
+ e_Draw(TextureID, fX, fY, 0, True, False);
end;
if g_debug_Frames then
diff --git a/src/game/g_window.pas b/src/game/g_window.pas
index 7774c0a34c0c03b2bda5fd5418ece817dc492963..351edf913e91396a154c5ae8a5c52a08cf32c5e2 100644 (file)
--- a/src/game/g_window.pas
+++ b/src/game/g_window.pas
var
Time, Time_Delta, Time_Old: Int64;
+ Frame: Int64;
flag: Boolean;
wNeedTimeReset: Boolean = false;
wMinimized: Boolean = false;
if wNeedTimeReset then
begin
+ Frame := 0;
Time_Delta := 28;
wNeedTimeReset := false;
end;
// Âðåìÿ ïðåäûäóùåãî îáíîâëåíèÿ
if flag then
- begin
Time_Old := Time - (Time_Delta mod 28);
+
+ if (Time - Frame > 4) then
+ begin
if (not wMinimized) then
begin
+ if gPause or not gLerpActors then
+ gLerpFactor := 1.0
+ else
+ gLerpFactor := nmin(1.0, (Time - Time_Old) / 28.0);
Draw;
sys_Repaint
- end
+ end;
+ Frame := Time
end
else
- begin
- sys_Delay(1) // release time slice, so we won't eat 100% CPU
- end;
+ sys_Delay(1);
e_SoundUpdate();
end;
diff --git a/src/shared/utils.pas b/src/shared/utils.pas
index 946e4f5a07c7a31a5422fad1f2f479fb83ffce6a..57ce782cad7f8a10c7186575b5143de7b0753888 100644 (file)
--- a/src/shared/utils.pas
+++ b/src/shared/utils.pas
function readInt64BE (st: TStream): Int64;
function readUInt64BE (st: TStream): UInt64;
+function nlerp (a, b: Integer; t: Single): Integer; inline;
function nmin (a, b: Byte): Byte; inline; overload;
function nmin (a, b: ShortInt): ShortInt; inline; overload;
@@ -1528,6 +1529,8 @@ function readUInt64BE (st: TStream): UInt64; begin readIntegerBE(st, @result, 8)
// ////////////////////////////////////////////////////////////////////////// //
+function nlerp (a, b: Integer; t: Single): Integer; inline; begin result := round((1.0 - t) * a + t * b); end;
+
function nmin (a, b: Byte): Byte; inline; overload; begin if (a < b) then result := a else result := b; end;
function nmin (a, b: ShortInt): ShortInt; inline; overload; begin if (a < b) then result := a else result := b; end;
function nmin (a, b: Word): Word; inline; overload; begin if (a < b) then result := a else result := b; end;