X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_phys.pas;h=af569ea1e1784185f70f13aa5ae47f0ef955fa1d;hb=dffafd305d0df029f317cc92c1968ba0065c0cd8;hp=d581eb3903e325e6fc8ba94a7f659df01167a7a0;hpb=7292fe409145dfcbb2776e34bb64d56e32985b9d;p=d2df-sdl.git diff --git a/src/game/g_phys.pas b/src/game/g_phys.pas index d581eb3..af569ea 100644 --- a/src/game/g_phys.pas +++ b/src/game/g_phys.pas @@ -1,9 +1,8 @@ -(* 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 @@ -13,7 +12,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . *) -{$INCLUDE g_amodes.inc} +{$INCLUDE ../shared/a_modes.inc} unit g_phys; interface @@ -28,6 +27,13 @@ type 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 @@ -45,22 +51,26 @@ 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; @@ -69,9 +79,19 @@ implementation 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; -function g_Obj_StayOnStep(Obj: PObj): Boolean; + +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 Result := not g_Map_CollidePanel(Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y+Obj^.Rect.Height-1, Obj^.Rect.Width, 1, @@ -81,14 +101,21 @@ begin 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, @@ -102,7 +129,7 @@ begin 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 @@ -122,83 +149,64 @@ end; function CollidePlayers(_Obj: PObj; XInc, YInc: Integer): Boolean; var - a: Integer; -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; -end; - -function CollideMonsters(Obj: PObj; XInc, YInc: Integer): Boolean; -var - a: Integer; + plr: TPlayer; begin - Result := False; - - if gMonsters = nil then - Exit; - - for a := 0 to High(gMonsters) do - if gMonsters[a] <> nil then - if gMonsters[a].Live and - gMonsters[a].Collide(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj^.Rect.Y+YInc, - Obj^.Rect.Width, Obj^.Rect.Height) then + 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; + 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, @@ -209,8 +217,9 @@ procedure g_Obj_Splash(Obj: PObj; Color: Byte); 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 @@ -219,162 +228,175 @@ begin 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 @@ -383,137 +405,167 @@ begin 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 > gMapInfo.Height+128 then + // Âûëåòåë çà íèæíþþ ãðàíèöó êàðòû? + if (Obj^.Y > Integer(gMapInfo.Height)+128) then begin result := MOVE_FALLOUT; Obj.slopeUpLeft := 0; Obj.slopeFramesLeft := 0; exit; end; + + // Ìåíÿåì ñêîðîñòü è óñêîðåíèå òîëüêî ïî ÷åòíûì êàäðàì + 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 - TEXTURE_SPECIAL_WATER: - g_Obj_Splash(Obj, 3); - TEXTURE_SPECIAL_ACID1: - g_Obj_Splash(Obj, 2); - TEXTURE_SPECIAL_ACID2: - g_Obj_Splash(Obj, 1); - 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, @@ -521,7 +573,7 @@ begin 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, @@ -529,19 +581,19 @@ begin 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; @@ -552,14 +604,14 @@ begin 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; @@ -567,34 +619,71 @@ begin 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.