diff --git a/src/game/g_phys.pas b/src/game/g_phys.pas
index 498bd7587489f9faf6e72ffca873c72e06de6702..69199797b06237a4ac9023f44ced5fc1868a4ad2 100644 (file)
--- a/src/game/g_phys.pas
+++ b/src/game/g_phys.pas
-(* Copyright (C) DooM 2D:Forever Developers
+(* Copyright (C) Doom 2D: Forever Developers
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation, version 3 of the License ONLY.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
interface
-uses
- e_graphics;
+ uses g_base;
type
PObj = ^TObj;
Rect: TRectWH;
Vel: TPoint2i;
Accel: TPoint2i;
+ // going up the slope will set this, and renderer will adjust the position
+ // 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
MOVE_HITAIR = 64;
MOVE_BLOCK = 128;
-procedure g_Obj_Init(Obj: PObj);
-function g_Obj_Move(Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean = False): Word;
-function g_Obj_Collide(Obj1, Obj2: PObj): Boolean; overload;
-function g_Obj_Collide(X, Y: Integer; Width, Height: Word; Obj: PObj): Boolean; overload;
-function g_Obj_CollidePoint(X, Y: Integer; Obj: PObj): Boolean;
-function g_Obj_CollideLevel(Obj: PObj; XInc, YInc: Integer): Boolean;
-function g_Obj_CollideStep(Obj: PObj; XInc, YInc: Integer): Boolean;
-function g_Obj_CollideWater(Obj: PObj; XInc, YInc: Integer): Boolean;
-function g_Obj_CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean;
-function g_Obj_CollidePanel(Obj: PObj; XInc, YInc: Integer; PanelType: Word): Boolean;
-function g_Obj_StayOnStep(Obj: PObj): Boolean;
-procedure g_Obj_Push(Obj: PObj; VelX, VelY: Integer);
-procedure g_Obj_PushA(Obj: PObj; Vel: Integer; Angle: SmallInt);
-procedure g_Obj_SetSpeed(Obj: PObj; s: Integer);
-function z_dec(a, b: Integer): Integer;
-function z_fdec(a, b: Double): Double;
+procedure g_Obj_Init(Obj: PObj); inline;
+function g_Obj_Move(Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean=False; asProjectile: Boolean=false): Word;
+function g_Obj_Move_Projectile (Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean=False): Word;
+function g_Obj_Collide(Obj1, Obj2: PObj): Boolean; inline; overload;
+function g_Obj_Collide(X, Y: Integer; Width, Height: Word; Obj: PObj): Boolean; inline; overload;
+function g_Obj_CollidePoint(X, Y: Integer; Obj: PObj): Boolean; inline;
+function g_Obj_CollideLevel(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
+function g_Obj_CollideStep(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
+function g_Obj_CollideWater(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
+function g_Obj_CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
+function g_Obj_CollidePanel(Obj: PObj; XInc, YInc: Integer; PanelType: Word): Boolean; inline;
+function g_Obj_StayOnStep(Obj: PObj): Boolean; inline;
+function g_Obj_CanMoveY(Obj: PObj; YInc: Integer): Boolean; inline;
+procedure g_Obj_Push(Obj: PObj; VelX, VelY: Integer); inline;
+procedure g_Obj_PushA(Obj: PObj; Vel: Integer; Angle: SmallInt); inline;
+procedure g_Obj_SetSpeed(Obj: PObj; s: Integer); inline;
+function g_Obj_GetSpeedDirF(Obj: PObj; var dirx, diry, speed: Double): Boolean; inline; // `false`: zero speed
+function g_Obj_GetAccelDirF(Obj: PObj; var dirx, diry, speed: Double): Boolean; inline; // `false`: zero speed
+function z_dec(a, b: Integer): Integer; inline;
+function z_fdec(a, b: Double): Double; inline;
var
gMon: Boolean = False;
uses
g_map, g_basic, Math, g_player, g_console, SysUtils,
- g_sound, g_gfx, MAPDEF, g_monsters, g_game, BinEditor;
+ g_sound, g_gfx, MAPDEF, g_monsters, g_game, utils;
+
+
+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;
+function g_Obj_StayOnStep(Obj: PObj): Boolean; inline;
begin
Result := not g_Map_CollidePanel(Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y+Obj^.Rect.Height-1,
Obj^.Rect.Width, 1,
PANEL_STEP, False);
end;
-function CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean;
+function g_Obj_CanMoveY(Obj: PObj; YInc: Integer): Boolean; inline;
+begin
+ // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì ñòåíà => øàãàòü íåëüçÿ
+ // Èëè åñëè øàãíóòü âíèç, à òàì ñòóïåíü => øàãàòü íåëüçÿ
+ Result := not(g_Obj_CollideLevel(Obj, 0, YInc) or ((YInc > 0) and g_Obj_StayOnStep(Obj)));
+end;
+
+function CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
begin
Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj^.Rect.Y+YInc,
Obj^.Rect.Width, Obj^.Rect.Height*2 div 3,
PANEL_WATER or PANEL_ACID1 or PANEL_ACID2, False);
end;
-function CollideLift(Obj: PObj; XInc, YInc: Integer): Integer;
+function CollideLift(Obj: PObj; XInc, YInc: Integer): Integer; inline;
begin
if g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj^.Rect.Y+YInc,
Obj^.Rect.Width, Obj^.Rect.Height,
Result := 0;
end;
-function CollideHorLift(Obj: PObj; XInc, YInc: Integer): Integer;
+function CollideHorLift(Obj: PObj; XInc, YInc: Integer): Integer; inline;
var
left, right: Boolean;
begin
function CollidePlayers(_Obj: PObj; XInc, YInc: Integer): Boolean;
var
- a: Integer;
+ plr: TPlayer;
begin
- Result := False;
-
- if gPlayers = nil then
- Exit;
-
- for a := 0 to High(gPlayers) do
- if gPlayers[a] <> nil then
- with gPlayers[a] do
- if Live and
- g_Collide(GameX+PLAYER_RECT.X, GameY+PLAYER_RECT.Y,
- PLAYER_RECT.Width, PLAYER_RECT.Height,
- _Obj^.X+_Obj^.Rect.X+XInc, _Obj^.Y+_Obj^.Rect.Y+YInc,
- _Obj^.Rect.Width, _Obj^.Rect.Height) then
- begin
- Result := True;
- Exit;
- end;
+ result := false;
+ if (gPlayers = nil) then exit;
+ for plr in gPlayers do
+ begin
+ if (plr = nil) then continue;
+ if not plr.alive then continue;
+ with plr do
+ begin
+ if g_Collide(GameX+PLAYER_RECT.X, GameY+PLAYER_RECT.Y,
+ PLAYER_RECT.Width, PLAYER_RECT.Height,
+ _Obj^.X+_Obj^.Rect.X+XInc, _Obj^.Y+_Obj^.Rect.Y+YInc,
+ _Obj^.Rect.Width, _Obj^.Rect.Height) then
+ begin
+ result := true;
+ exit;
+ end;
+ end;
+ end;
end;
-function Blocked(Obj: PObj; XInc, YInc: Integer): Boolean;
+function Blocked(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
begin
Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc,
Obj^.Rect.Width, Obj^.Rect.Height,
PANEL_BLOCKMON, False);
end;
-function g_Obj_CollideLevel(Obj: PObj; XInc, YInc: Integer): Boolean;
+function g_Obj_CollideLevel(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
begin
Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc,
Obj^.Rect.Width, Obj^.Rect.Height,
PANEL_WALL, False);
end;
-function g_Obj_CollideStep(Obj: PObj; XInc, YInc: Integer): Boolean;
+function g_Obj_CollideStep(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
begin
Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc,
Obj^.Rect.Width, Obj^.Rect.Height,
PANEL_STEP, False);
end;
-function g_Obj_CollideWater(Obj: PObj; XInc, YInc: Integer): Boolean;
+function g_Obj_CollideWater(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
begin
Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc,
Obj^.Rect.Width, Obj^.Rect.Height,
PANEL_WATER, False);
end;
-function g_Obj_CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean;
+function g_Obj_CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
begin
Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc,
Obj^.Rect.Width, Obj^.Rect.Height,
PANEL_WATER or PANEL_ACID1 or PANEL_ACID2, False);
end;
-function g_Obj_CollidePanel(Obj: PObj; XInc, YInc: Integer; PanelType: Word): Boolean;
+function g_Obj_CollidePanel(Obj: PObj; XInc, YInc: Integer; PanelType: Word): Boolean; inline;
begin
Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc,
Obj^.Rect.Width, Obj^.Rect.Height,
var
MaxVel: Integer;
begin
- MaxVel := Max(Abs(Obj^.Vel.X), Abs(Obj^.Vel.Y));
- if MaxVel > 4 then begin
+ MaxVel := nmax(abs(Obj^.Vel.X), abs(Obj^.Vel.Y));
+ if MaxVel > 4 then
+ begin
if MaxVel < 10 then
g_Sound_PlayExAt('SOUND_GAME_BULK1', Obj^.X, Obj^.Y)
else
g_GFX_Water(Obj^.X+Obj^.Rect.X+(Obj^.Rect.Width div 2),
Obj^.Y+Obj^.Rect.Y+(Obj^.Rect.Height div 2),
- Min(5*(Abs(Obj^.Vel.X)+Abs(Obj^.Vel.Y)), 50),
+ Min(5*(abs(Obj^.Vel.X)+abs(Obj^.Vel.Y)), 50),
-Obj^.Vel.X, -Obj^.Vel.Y,
Obj^.Rect.Width, 16, Color);
end;
-function move(Obj: PObj; dx, dy: Integer; ClimbSlopes: Boolean): Word;
+
+function move (Obj: PObj; dx, dy: Integer; ClimbSlopes: Boolean): Word;
var
i: Integer;
sx, sy: ShortInt;
st: Word;
- procedure slope(s: Integer);
+ procedure slope (s: Integer);
var
i: Integer;
begin
i := 0;
while g_Obj_CollideLevel(Obj, sx, 0) and (i < 4) do
begin
- Obj^.Y := Obj^.Y + s;
+ Obj^.Y += s;
Inc(i);
end;
- Obj^.X := Obj^.X + sx;
+ Obj^.X += sx;
+ if (s < 0) then
+ begin
+ Obj.slopeUpLeft += i*(-s);
+ Obj.slopeFramesLeft := SmoothSlopeFrames;
+ end;
end;
- function movex(): Boolean;
+ function movex (): Boolean;
begin
- Result := False;
+ result := false;
- // Åñëè ìîíñòðó øàãíóòü â ñòîðîíó, à òàì áëîêìîí:
- if gMon and not WordBool(st and MOVE_BLOCK) then
- if Blocked(Obj, sx, 0) then
- st := st or MOVE_BLOCK;
+ // Åñëè ìîíñòðó øàãíóòü â ñòîðîíó, à òàì áëîêìîí
+ if gMon and ((st and MOVE_BLOCK) = 0) then
+ begin
+ if Blocked(Obj, sx, 0) then st := st or MOVE_BLOCK;
+ end;
- // Åñëè øàãíóòü â ñòîðîíó, à òàì ñòåíà => øàãàòü íåëüçÿ:
+ // Åñëè øàãíóòü â ñòîðîíó, à òàì ñòåíà => øàãàòü íåëüçÿ
if g_Obj_CollideLevel(Obj, sx, 0) then
+ begin
+ if ClimbSlopes and (abs(dy) < 2) then
begin
- if ClimbSlopes and (Abs(dy) < 2) then
- begin
- Result := True;
- if (not g_Obj_CollideLevel(Obj, sx, -12)) // çàáèðàåìñÿ íà 12 ïèêñåëåé âëåâî/âïðàâî
- and g_Obj_CollidePanel(Obj, 0, 1, PANEL_WALL or PANEL_STEP) // òîëüêî åñëè åñòü çåìëÿ ïîä íîãàìè
- then
- slope(-1)
- else
- begin
- Result := False;
- st := st or MOVE_HITWALL;
- end;
- end
- else
- st := st or MOVE_HITWALL;
+ result := true;
+ if (not g_Obj_CollideLevel(Obj, sx, -12)) and // çàáèðàåìñÿ íà 12 ïèêñåëåé âëåâî/âïðàâî
+ (sy >= 0) and (not g_Obj_CanMoveY(Obj, sy)) then // òîëüêî åñëè åñòü çåìëÿ ïîä íîãàìè
+ begin
+ slope(-1);
+ end
+ else
+ begin
+ result := false;
+ st := st or MOVE_HITWALL;
+ end;
end
+ else
+ begin
+ st := st or MOVE_HITWALL;
+ end;
+ end
else // Òàì ñòåíû íåò
+ begin
+ if CollideLiquid(Obj, sx, 0) then
+ begin // Åñëè øàãíóòü â ñòîðîíó, à òàì òåïåðü æèäêîñòü
+ if ((st and MOVE_INWATER) = 0) then st := st or MOVE_HITWATER;
+ end
+ else // Åñëè øàãíóòü â ñòîðîíó, à òàì óæå íåò æèäêîñòè
begin
- if CollideLiquid(Obj, sx, 0) then
- begin // Åñëè øàãíóòü â ñòîðîíó, à òàì òåïåðü æèäêîñòü
- if not WordBool(st and MOVE_INWATER) then
- st := st or MOVE_HITWATER;
- end
- else // Åñëè øàãíóòü â ñòîðîíó, à òàì óæå íåò æèäêîñòè
- if WordBool(st and MOVE_INWATER) then
- st := st or MOVE_HITAIR;
-
- // Øàã:
- Obj^.X := Obj^.X + sx;
- Result := True;
+ if ((st and MOVE_INWATER) <> 0) then st := st or MOVE_HITAIR;
end;
+
+ // Øàã
+ Obj^.X += sx;
+ result := true;
+ end;
end;
- function movey(): Boolean;
+ function movey (): Boolean;
begin
- Result := False;
+ result := false;
- // Åñëè ìîíñòðó øàãíóòü ïî âåðòèêàëè, à òàì áëîêìîí:
- if gMon and not WordBool(st and MOVE_BLOCK) then
- if Blocked(Obj, 0, sy) then
- st := st or MOVE_BLOCK;
+ // Åñëè ìîíñòðó øàãíóòü ïî âåðòèêàëè, à òàì áëîêìîí
+ if gMon and ((st and MOVE_BLOCK) = 0) then
+ begin
+ if Blocked(Obj, 0, sy) then st := st or MOVE_BLOCK;
+ end;
- // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì ñòåíà => øàãàòü íåëüçÿ:
- // Èëè åñëè øàãíóòü âíèç, à òàì ñòóïåíü => øàãàòü íåëüçÿ:
- if g_Obj_CollideLevel(Obj, 0, sy) or
- ((sy > 0) and g_Obj_StayOnStep(Obj)) then
- begin
- if sy > 0 then
- st := st or MOVE_HITLAND
- else
- st := st or MOVE_HITCEIL;
- end
+ // Åñëè øàãàòü íåëüçÿ
+ if not g_Obj_CanMoveY(Obj, sy) then
+ begin
+ if sy > 0 then
+ st := st or MOVE_HITLAND
+ else
+ st := st or MOVE_HITCEIL;
+ end
else // Òàì ñòåíû íåò. È ñòóïåíè ñíèçó òîæå íåò
+ begin
+ if CollideLiquid(Obj, 0, sy) then
+ begin // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì òåïåðü æèäêîñòü
+ if ((st and MOVE_INWATER) = 0) then st := st or MOVE_HITWATER;
+ end
+ else // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì óæå íåò æèäêîñòè
begin
- if CollideLiquid(Obj, 0, sy) then
- begin // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì òåïåðü æèäêîñòü
- if not WordBool(st and MOVE_INWATER) then
- st := st or MOVE_HITWATER;
- end
- else // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì óæå íåò æèäêîñòè
- if WordBool(st and MOVE_INWATER) then
- st := st or MOVE_HITAIR;
-
- // Øàã:
- Obj^.Y := Obj^.Y + sy;
-
- Result := True;
+ if ((st and MOVE_INWATER) <> 0) then st := st or MOVE_HITAIR;
end;
+
+ // Øàã
+ Obj^.Y += sy;
+ result := true;
+ end;
end;
begin
st := MOVE_NONE;
-// Îáúåêò â æèäêîñòè:
- if CollideLiquid(Obj, 0, 0) then
- st := st or MOVE_INWATER;
+ // Îáúåêò â æèäêîñòè?
+ if CollideLiquid(Obj, 0, 0) then st := st or MOVE_INWATER;
-// Ìîíñòð â áëîêìîíå:
+ // Ìîíñòð â áëîêìîíå?
if gMon then
- if Blocked(Obj, 0, 0) then
- st := st or MOVE_BLOCK;
-
-// Äâèãàòüñÿ íå íàäî:
- if (dx = 0) and (dy = 0) then
begin
- Result := st;
- Exit;
+ if Blocked(Obj, 0, 0) then st := st or MOVE_BLOCK;
end;
+ // Äâèãàòüñÿ íå íàäî?
+ if (dx = 0) and (dy = 0) then begin result := st; exit; end;
+
sx := g_basic.Sign(dx);
sy := g_basic.Sign(dy);
- dx := Abs(dx);
- dy := Abs(dy);
-
- for i := 1 to dx do
- if not movex() then
- Break;
+ dx := abs(dx);
+ dy := abs(dy);
- for i := 1 to dy do
- if not movey() then
- Break;
+ for i := 1 to dx do if not movex() then break;
+ for i := 1 to dy do if not movey() then break;
- Result := st;
+ result := st;
end;
-procedure g_Obj_Init(Obj: PObj);
+
+procedure g_Obj_Init (Obj: PObj); inline;
begin
ZeroMemory(Obj, SizeOf(TObj));
end;
-function g_Obj_Move(Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean = False): Word;
+
+function g_Obj_Move_Projectile (Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean=False): Word;
+begin
+ result := g_Obj_Move(Obj, Fallable, Splash, ClimbSlopes, true);
+end;
+
+function g_Obj_Move (Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean=False; asProjectile: Boolean=false): Word;
var
xv, yv, dx, dy: Integer;
inwater: Boolean;
c: Boolean;
wtx: DWORD;
+ slopeStep: Integer;
+ dirx, diry, speed: Double;
label
_move;
begin
-// Ëèìèòû íà ñêîðîñòü è óñêîðåíèå
+ // Ëèìèòû íà ñêîðîñòü è óñêîðåíèå
+ Obj^.Vel.X := nclamp(Obj^.Vel.X, -LIMIT_VEL, LIMIT_VEL);
+ Obj^.Vel.Y := nclamp(Obj^.Vel.Y, -LIMIT_VEL, LIMIT_VEL);
+ Obj^.Accel.X := nclamp(Obj^.Accel.X, -LIMIT_ACCEL, LIMIT_ACCEL);
+ Obj^.Accel.Y := nclamp(Obj^.Accel.Y, -LIMIT_ACCEL, LIMIT_ACCEL);
+ {
if Obj^.Vel.X < -LIMIT_VEL then Obj^.Vel.X := -LIMIT_VEL
else if Obj^.Vel.X > LIMIT_VEL then Obj^.Vel.X := LIMIT_VEL;
if Obj^.Vel.Y < -LIMIT_VEL then Obj^.Vel.Y := -LIMIT_VEL
else if Obj^.Accel.X > LIMIT_ACCEL then Obj^.Accel.X := LIMIT_ACCEL;
if Obj^.Accel.Y < -LIMIT_ACCEL then Obj^.Accel.Y := -LIMIT_ACCEL
else if Obj^.Accel.Y > LIMIT_ACCEL then Obj^.Accel.Y := LIMIT_ACCEL;
+ }
+
+ // Âûëåòåë çà íèæíþþ ãðàíèöó êàðòû?
+ if (Obj^.Y > Integer(gMapInfo.Height)+128) then begin result := MOVE_FALLOUT; Obj.slopeUpLeft := 0; Obj.slopeFramesLeft := 0; exit; end;
-// Âûëåòåë çà íèæíþþ ãðàíèöó êàðòû:
- if Obj^.Y > gMapInfo.Height+128 then
+ // Ìåíÿåì ñêîðîñòü è óñêîðåíèå òîëüêî ïî ÷åòíûì êàäðàì
+ c := (gTime mod (GAME_TICK*2) <> 0);
+
+ // smoothed slopes
+ if {not c and} (Obj.slopeUpLeft > 0) then
begin
- Result := MOVE_FALLOUT;
- Exit;
+ if (Obj.slopeFramesLeft < 1) then
+ begin
+ //conwritefln('SLOPE DONE: slopeUpLeft=%s', [Obj.slopeUpLeft]);
+ Obj.slopeUpLeft := 0; // oops
+ end
+ else
+ begin
+ slopeStep := Obj.slopeUpLeft div Obj.slopeFramesLeft;
+ if (slopeStep < 1) then slopeStep := 1;
+ //conwritefln('SLOPE STEP: slopeUpLeft=%s; slopeFramesLeft=%s; slopeStep=%d', [Obj.slopeUpLeft, Obj.slopeFramesLeft, slopeStep]);
+ Dec(Obj.slopeFramesLeft);
+ Obj.slopeUpLeft -= slopeStep;
+ if (Obj.slopeUpLeft < 1) then
+ begin
+ Obj.slopeUpLeft := 0;
+ Obj.slopeFramesLeft := 0;
+ end;
+ end;
end;
-// Ìåíÿåì ñêîðîñòü è óñêîðåíèå òîëüêî ïî ÷åòíûì êàäðàì:
- c := gTime mod (GAME_TICK*2) <> 0;
-
- if c then
- goto _move;
+ if c then goto _move;
case CollideLift(Obj, 0, 0) of
-1: //up
begin
- Obj^.Vel.Y := Obj^.Vel.Y - 1; // Ëèôò ââåðõ
- if Obj^.Vel.Y < -5 then
- Obj^.Vel.Y := Obj^.Vel.Y + 1;
+ Obj^.Vel.Y -= 1; // Ëèôò ââåðõ
+ if (Obj^.Vel.Y < -5) then Obj^.Vel.Y += 1;
end;
-
1: //down
begin
- if Obj^.Vel.Y > 5 then
- Obj^.Vel.Y := Obj^.Vel.Y - 1;
- Obj^.Vel.Y := Obj^.Vel.Y + 1; // Ãðàâèòàöèÿ èëè ëèôò âíèç
+ if (Obj^.Vel.Y > 5) then Obj^.Vel.Y -= 1;
+ Obj^.Vel.Y += 1; // Ãðàâèòàöèÿ èëè ëèôò âíèç
end;
-
- 0:
+ 0: //???
begin
- if Fallable then
- Obj^.Vel.Y := Obj^.Vel.Y + 1; // Ãðàâèòàöèÿ
- if Obj^.Vel.Y > MAX_YV then
- Obj^.Vel.Y := Obj^.Vel.Y - 1;
+ if Fallable then Obj^.Vel.Y += 1; // Ãðàâèòàöèÿ
+ if (Obj^.Vel.Y > MAX_YV) then Obj^.Vel.Y -= 1;
end;
end;
case CollideHorLift(Obj, 0, 0) of
-1: //left
begin
- Obj^.Vel.X := Obj^.Vel.X - 3; // Ëèôò ââåðõ
- if Obj^.Vel.X < -9 then
- Obj^.Vel.X := Obj^.Vel.X + 3;
+ Obj^.Vel.X -= 3;
+ if (Obj^.Vel.X < -9) then Obj^.Vel.X += 3;
end;
-
1: //right
begin
- Obj^.Vel.X := Obj^.Vel.X + 3;
- if Obj^.Vel.X > 9 then
- Obj^.Vel.X := Obj^.Vel.X - 3;
+ Obj^.Vel.X += 3;
+ if (Obj^.Vel.X > 9) then Obj^.Vel.X -= 3;
end;
// 0 is not needed here
end;
+ // Â âîäå?
inwater := CollideLiquid(Obj, 0, 0);
if inwater then
begin
- xv := Abs(Obj^.Vel.X)+1;
- if xv > 5 then
- Obj^.Vel.X := z_dec(Obj^.Vel.X, (xv div 2)-2);
-
- yv := Abs(Obj^.Vel.Y)+1;
- if yv > 5 then
- Obj^.Vel.Y := z_dec(Obj^.Vel.Y, (yv div 2)-2);
-
- xv := Abs(Obj^.Accel.X)+1;
- if xv > 5 then
- Obj^.Accel.X := z_dec(Obj^.Accel.X, (xv div 2)-2);
+ if asProjectile then
+ begin
+ //writeln('velocity=(', Obj^.Vel.X, ',', Obj^.Vel.Y, '); acceleration=(', Obj^.Accel.X, ',', Obj^.Accel.Y, ')');
+ if (g_Obj_GetSpeedDirF(Obj, dirx, diry, speed)) then
+ begin
+ //writeln('SPEED: ', speed);
+ if (speed > 5) then
+ begin
+ speed := speed/1.4;
+ Obj^.Vel.X := round(dirx*speed);
+ Obj^.Vel.Y := round(diry*speed);
+ end;
+ end;
- yv := Abs(Obj^.Accel.Y)+1;
- if yv > 5 then
- Obj^.Accel.Y := z_dec(Obj^.Accel.Y, (yv div 2)-2);
+ // acceleration
+ if (g_Obj_GetAccelDirF(Obj, dirx, diry, speed)) then
+ begin
+ if (speed > 5) then
+ begin
+ speed := speed/1.4;
+ Obj^.Accel.X := round(dirx*speed);
+ Obj^.Accel.Y := round(diry*speed);
+ end;
+ end;
+ end
+ else
+ begin
+ // velocity
+ xv := abs(Obj^.Vel.X)+1;
+ if (xv > 5) then Obj^.Vel.X := z_dec(Obj^.Vel.X, (xv div 2)-2);
+ yv := abs(Obj^.Vel.Y)+1;
+ if (yv > 5) then Obj^.Vel.Y := z_dec(Obj^.Vel.Y, (yv div 2)-2);
+
+ // acceleration
+ xv := abs(Obj^.Accel.X)+1;
+ if (xv > 5) then Obj^.Accel.X := z_dec(Obj^.Accel.X, (xv div 2)-2);
+ yv := abs(Obj^.Accel.Y)+1;
+ if (yv > 5) then Obj^.Accel.Y := z_dec(Obj^.Accel.Y, (yv div 2)-2);
+ end;
end;
-// Óìåíüøàåì ïðèáàâêó ê ñêîðîñòè:
+ // Óìåíüøàåì ïðèáàâêó ê ñêîðîñòè
Obj^.Accel.X := z_dec(Obj^.Accel.X, 1);
Obj^.Accel.Y := z_dec(Obj^.Accel.Y, 1);
_move:
- xv := Obj^.Vel.X + Obj^.Accel.X;
- yv := Obj^.Vel.Y + Obj^.Accel.Y;
+ xv := Obj^.Vel.X+Obj^.Accel.X;
+ yv := Obj^.Vel.Y+Obj^.Accel.Y;
dx := xv;
dy := yv;
- Result := move(Obj, dx, dy, ClimbSlopes);
+ result := move(Obj, dx, dy, ClimbSlopes);
-// Áðûçãè (åñëè íóæíû):
+ // Áðûçãè (åñëè íóæíû)
if Splash then
+ begin
if WordBool(Result and MOVE_HITWATER) then
begin
- wtx := g_Map_CollideLiquid_Texture(Obj^.X+Obj^.Rect.X,
- Obj^.Y+Obj^.Rect.Y,
- Obj^.Rect.Width,
- Obj^.Rect.Height*2 div 3);
+ wtx := g_Map_CollideLiquid_Texture(Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y,
+ Obj^.Rect.Width, Obj^.Rect.Height*2 div 3);
case wtx of
- LongWord(TEXTURE_SPECIAL_WATER):
- g_Obj_Splash(Obj, 3);
- LongWord(TEXTURE_SPECIAL_ACID1):
- g_Obj_Splash(Obj, 2);
- LongWord(TEXTURE_SPECIAL_ACID2):
- g_Obj_Splash(Obj, 1);
- LongWord(TEXTURE_NONE):
- ;
- else
- g_Obj_Splash(Obj, 0);
+ LongWord(TEXTURE_SPECIAL_WATER): g_Obj_Splash(Obj, 3);
+ LongWord(TEXTURE_SPECIAL_ACID1): g_Obj_Splash(Obj, 2);
+ LongWord(TEXTURE_SPECIAL_ACID2): g_Obj_Splash(Obj, 1);
+ LongWord(TEXTURE_NONE): begin end;
+ else g_Obj_Splash(Obj, 0);
end;
end;
+ end;
-// Ìåíÿåì ñêîðîñòü è óñêîðåíèå òîëüêî ïî ÷åòíûì êàäðàì:
- if c then
- Exit;
+ // Ìåíÿåì ñêîðîñòü è óñêîðåíèå òîëüêî ïî ÷åòíûì êàäðàì
+ if c then exit;
-// Âðåçàëèñü â ñòåíó - ñòîï:
- if WordBool(Result and MOVE_HITWALL) then
+ // Âðåçàëèñü â ñòåíó - ñòîï
+ if ((Result and MOVE_HITWALL) <> 0) then
begin
Obj^.Vel.X := 0;
Obj^.Accel.X := 0;
end;
-// Âðåçàëèñü â ïîë èëè ïîòîëîê - ñòîï:
- if WordBool(Result and (MOVE_HITCEIL or MOVE_HITLAND)) then
+ // Âðåçàëèñü â ïîë èëè ïîòîëîê - ñòîï
+ if ((Result and (MOVE_HITCEIL or MOVE_HITLAND)) <> 0) then
begin
Obj^.Vel.Y := 0;
Obj^.Accel.Y := 0;
end;
end;
-function g_Obj_Collide(Obj1, Obj2: PObj): Boolean;
+
+function g_Obj_Collide(Obj1, Obj2: PObj): Boolean; inline;
begin
Result := g_Collide(Obj1^.X+Obj1^.Rect.X, Obj1^.Y+Obj1^.Rect.Y,
Obj1^.Rect.Width, Obj1^.Rect.Height,
Obj2^.Rect.Width, Obj2^.Rect.Height);
end;
-function g_Obj_Collide(X, Y: Integer; Width, Height: Word; Obj: PObj): Boolean;
+function g_Obj_Collide(X, Y: Integer; Width, Height: Word; Obj: PObj): Boolean; inline;
begin
Result := g_Collide(X, Y,
Width, Height,
Obj^.Rect.Width, Obj^.Rect.Height);
end;
-function g_Obj_CollidePoint(X, Y: Integer; Obj: PObj): Boolean;
+function g_Obj_CollidePoint(X, Y: Integer; Obj: PObj): Boolean; inline;
begin
Result := g_CollidePoint(X, Y, Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y,
Obj^.Rect.Width, Obj^.Rect.Height);
end;
-procedure g_Obj_Push(Obj: PObj; VelX, VelY: Integer);
+procedure g_Obj_Push(Obj: PObj; VelX, VelY: Integer); inline;
begin
Obj^.Vel.X := Obj^.Vel.X + VelX;
Obj^.Vel.Y := Obj^.Vel.Y + VelY;
end;
-procedure g_Obj_PushA(Obj: PObj; Vel: Integer; Angle: SmallInt);
+procedure g_Obj_PushA(Obj: PObj; Vel: Integer; Angle: SmallInt); inline;
var
s, c: Extended;
Obj^.Vel.Y := Obj^.Vel.Y + Round(Vel*s);
end;
-procedure g_Obj_SetSpeed(Obj: PObj; s: Integer);
+procedure g_Obj_SetSpeed(Obj: PObj; s: Integer); inline;
var
m, vx, vy: Integer;
begin
vx := Obj^.Vel.X;
vy := Obj^.Vel.Y;
- m := Max(Abs(vx), Abs(vy));
+ m := Max(abs(vx), abs(vy));
if m = 0 then
m := 1;
Obj^.Vel.Y := (vy*s) div m;
end;
-function z_dec(a, b: Integer): Integer;
+// `false`: zero speed
+function g_Obj_GetSpeedDirF(Obj: PObj; var dirx, diry, speed: Double): Boolean; inline;
+var
+ len, vx, vy: Double;
begin
-// Ïðèáëèæàåì a ê 0 íà b åäèíèö:
- if Abs(a) < b then
- Result := 0
- else
- if a > 0 then
- Result := a - b
- else
- if a < 0 then
- Result := a + b
- else // a = 0
- Result := 0;
+ if (Obj^.Vel.X = 0) and (Obj^.Vel.Y = 0) then
+ begin
+ dirx := 0;
+ diry := 0;
+ speed := 0;
+ result := false;
+ exit;
+ end;
+
+ vx := Obj^.Vel.X;
+ vy := Obj^.Vel.Y;
+ len := sqrt(vx*vx+vy*vy);
+ dirx := vx/len;
+ diry := vy/len;
+ speed := len;
+ result := true;
end;
-function z_fdec(a, b: Double): Double;
+// `false`: zero acceleratin
+function g_Obj_GetAccelDirF(Obj: PObj; var dirx, diry, speed: Double): Boolean; inline;
+var
+ len, vx, vy: Double;
begin
+ if (Obj^.Accel.X = 0) and (Obj^.Accel.Y = 0) then
+ begin
+ dirx := 0;
+ diry := 0;
+ speed := 0;
+ result := false;
+ exit;
+ end;
+
+ vx := Obj^.Accel.X;
+ vy := Obj^.Accel.Y;
+ len := sqrt(vx*vx+vy*vy);
+ dirx := vx/len;
+ diry := vy/len;
+ speed := len;
+ result := true;
+end;
+
+
+// Ïðèáëèæàåì a ê 0 íà b åäèíèö:
+function z_dec (a, b: Integer): Integer; inline;
+begin
+ if (abs(a) < b) then result := 0
+ else if (a > 0) then result := a-b
+ else if (a < 0) then result := a+b
+ else result := 0; // a = 0
+end;
+
+
// Ïðèáëèæàåì a ê 0.0 íà b åäèíèö:
- if Abs(a) < b then
- Result := 0.0
- else
- if a > 0.0 then
- Result := a - b
- else
- if a < 0.0 then
- Result := a + b
- else // a = 0.0
- Result := 0.0;
+function z_fdec (a, b: Double): Double; inline;
+begin
+ if (abs(a) < b) then result := 0.0
+ else if (a > 0.0) then result := a-b
+ else if (a < 0.0) then result := a+b
+ else result := 0.0; // a = 0.0
end;
+
end.