1 (* Copyright (C) 2016 - The Doom2D.org team & involved community members <http://www.doom2d.org>.
2 * This file is part of Doom2D Forever.
4 * This program is free software: you can redistribute it and/or modify it under the terms of
5 * the GNU General Public License as published by the Free Software Foundation, version 3 of
8 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 * See the GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License along with this program.
13 * If not, see <http://www.gnu.org/licenses/>.
16 {$INCLUDE ../shared/a_modes.inc}
31 // going up the slope will set this, and renderer will adjust the position
32 // this is purely visual change, it won't affect anything else
33 slopeUpLeft
: Integer; // left to go
34 slopeFramesLeft
: Integer; // frames left to go
35 // for frame interpolation
37 procedure lerp(t
: Single; out fX
, fY
: Integer);
55 procedure g_Obj_Init(Obj
: PObj
); inline;
56 function g_Obj_Move(Obj
: PObj
; Fallable
: Boolean; Splash
: Boolean; ClimbSlopes
: Boolean=False; asProjectile
: Boolean=false): Word;
57 function g_Obj_Move_Projectile (Obj
: PObj
; Fallable
: Boolean; Splash
: Boolean; ClimbSlopes
: Boolean=False): Word;
58 function g_Obj_Collide(Obj1
, Obj2
: PObj
): Boolean; inline; overload
;
59 function g_Obj_Collide(X
, Y
: Integer; Width
, Height
: Word; Obj
: PObj
): Boolean; inline; overload
;
60 function g_Obj_CollidePoint(X
, Y
: Integer; Obj
: PObj
): Boolean; inline;
61 function g_Obj_CollideLevel(Obj
: PObj
; XInc
, YInc
: Integer): Boolean; inline;
62 function g_Obj_CollideStep(Obj
: PObj
; XInc
, YInc
: Integer): Boolean; inline;
63 function g_Obj_CollideWater(Obj
: PObj
; XInc
, YInc
: Integer): Boolean; inline;
64 function g_Obj_CollideLiquid(Obj
: PObj
; XInc
, YInc
: Integer): Boolean; inline;
65 function g_Obj_CollidePanel(Obj
: PObj
; XInc
, YInc
: Integer; PanelType
: Word): Boolean; inline;
66 function g_Obj_StayOnStep(Obj
: PObj
): Boolean; inline;
67 function g_Obj_CanMoveY(Obj
: PObj
; YInc
: Integer): Boolean; inline;
68 procedure g_Obj_Push(Obj
: PObj
; VelX
, VelY
: Integer); inline;
69 procedure g_Obj_PushA(Obj
: PObj
; Vel
: Integer; Angle
: SmallInt); inline;
70 procedure g_Obj_SetSpeed(Obj
: PObj
; s
: Integer); inline;
71 function g_Obj_GetSpeedDirF(Obj
: PObj
; var dirx
, diry
, speed
: Double): Boolean; inline; // `false`: zero speed
72 function g_Obj_GetAccelDirF(Obj
: PObj
; var dirx
, diry
, speed
: Double): Boolean; inline; // `false`: zero speed
73 function z_dec(a
, b
: Integer): Integer; inline;
74 function z_fdec(a
, b
: Double): Double; inline;
77 gMon
: Boolean = False;
85 g_map
, g_basic
, Math
, g_player
, g_console
, SysUtils
,
86 g_gfx
, MAPDEF
, g_monsters
, g_game
, utils
;
90 SmoothSlopeFrames
= 4;
92 procedure TObj
.lerp(t
: Single; out fX
, fY
: Integer);
94 fX
:= nlerp(oldX
, X
, t
);
95 fY
:= nlerp(oldY
, Y
, t
);
98 function g_Obj_StayOnStep(Obj
: PObj
): Boolean; inline;
100 Result
:= not g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
, Obj
^.Y
+Obj
^.Rect
.Y
+Obj
^.Rect
.Height
-1,
103 and g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
, Obj
^.Y
+Obj
^.Rect
.Y
+Obj
^.Rect
.Height
,
108 function g_Obj_CanMoveY(Obj
: PObj
; YInc
: Integer): Boolean; inline;
110 // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì ñòåíà => øàãàòü íåëüçÿ
111 // Èëè åñëè øàãíóòü âíèç, à òàì ñòóïåíü => øàãàòü íåëüçÿ
112 Result
:= not(g_Obj_CollideLevel(Obj
, 0, YInc
) or ((YInc
> 0) and g_Obj_StayOnStep(Obj
)));
115 function CollideLiquid(Obj
: PObj
; XInc
, YInc
: Integer): Boolean; inline;
117 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
^.Rect
.Y
+YInc
,
118 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
*2 div 3,
119 PANEL_WATER
or PANEL_ACID1
or PANEL_ACID2
, False);
122 function CollideLift(Obj
: PObj
; XInc
, YInc
: Integer): Integer; inline;
124 if g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
^.Rect
.Y
+YInc
,
125 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
126 PANEL_LIFTUP
, False) then
128 else if g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
^.Rect
.Y
+YInc
,
129 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
130 PANEL_LIFTDOWN
, False) then
136 function CollideHorLift(Obj
: PObj
; XInc
, YInc
: Integer): Integer; inline;
138 left
, right
: Boolean;
140 left
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
^.Rect
.Y
+YInc
,
141 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
142 PANEL_LIFTLEFT
, False);
143 right
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
^.Rect
.Y
+YInc
,
144 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
145 PANEL_LIFTRIGHT
, False);
146 if left
and not right
then
148 else if right
and not left
then
154 function CollidePlayers(_Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
159 if (gPlayers
= nil) then exit
;
160 for plr
in gPlayers
do
162 if (plr
= nil) then continue
;
163 if not plr
.alive
then continue
;
166 if g_Collide(GameX
+PLAYER_RECT
.X
, GameY
+PLAYER_RECT
.Y
,
167 PLAYER_RECT
.Width
, PLAYER_RECT
.Height
,
168 _Obj
^.X
+_Obj
^.Rect
.X
+XInc
, _Obj
^.Y
+_Obj
^.Rect
.Y
+YInc
,
169 _Obj
^.Rect
.Width
, _Obj
^.Rect
.Height
) then
178 function Blocked(Obj
: PObj
; XInc
, YInc
: Integer): Boolean; inline;
180 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
181 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
182 PANEL_BLOCKMON
, False);
185 function g_Obj_CollideLevel(Obj
: PObj
; XInc
, YInc
: Integer): Boolean; inline;
187 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
188 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
192 function g_Obj_CollideStep(Obj
: PObj
; XInc
, YInc
: Integer): Boolean; inline;
194 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
195 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
199 function g_Obj_CollideWater(Obj
: PObj
; XInc
, YInc
: Integer): Boolean; inline;
201 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
202 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
206 function g_Obj_CollideLiquid(Obj
: PObj
; XInc
, YInc
: Integer): Boolean; inline;
208 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
209 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
210 PANEL_WATER
or PANEL_ACID1
or PANEL_ACID2
, False);
213 function g_Obj_CollidePanel(Obj
: PObj
; XInc
, YInc
: Integer; PanelType
: Word): Boolean; inline;
215 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
216 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
220 procedure g_Obj_Splash(Obj
: PObj
; Color
: Byte);
221 {$IFDEF ENABLE_SOUND}
225 {$IFDEF ENABLE_SOUND}
226 MaxVel
:= nmax(abs(Obj
^.Vel
.X
), abs(Obj
^.Vel
.Y
));
230 g_Sound_PlayExAt('SOUND_GAME_BULK1', Obj
^.X
, Obj
^.Y
)
232 g_Sound_PlayExAt('SOUND_GAME_BULK2', Obj
^.X
, Obj
^.Y
);
236 g_GFX_Water(Obj
^.X
+Obj
^.Rect
.X
+(Obj
^.Rect
.Width
div 2),
237 Obj
^.Y
+Obj
^.Rect
.Y
+(Obj
^.Rect
.Height
div 2),
238 Min(5*(abs(Obj
^.Vel
.X
)+abs(Obj
^.Vel
.Y
)), 50),
239 -Obj
^.Vel
.X
, -Obj
^.Vel
.Y
,
240 Obj
^.Rect
.Width
, 16, Color
);
244 function move (Obj
: PObj
; dx
, dy
: Integer; ClimbSlopes
: Boolean): Word;
250 procedure slope (s
: Integer);
255 while g_Obj_CollideLevel(Obj
, sx
, 0) and (i
< 4) do
263 Obj
.slopeUpLeft
+= i
*(-s
);
264 Obj
.slopeFramesLeft
:= SmoothSlopeFrames
;
268 function movex (): Boolean;
272 // Åñëè ìîíñòðó øàãíóòü â ñòîðîíó, à òàì áëîêìîí
273 if gMon
and ((st
and MOVE_BLOCK
) = 0) then
275 if Blocked(Obj
, sx
, 0) then st
:= st
or MOVE_BLOCK
;
278 // Åñëè øàãíóòü â ñòîðîíó, à òàì ñòåíà => øàãàòü íåëüçÿ
279 if g_Obj_CollideLevel(Obj
, sx
, 0) then
281 if ClimbSlopes
and (abs(dy
) < 2) then
284 if (not g_Obj_CollideLevel(Obj
, sx
, -12)) and // çàáèðàåìñÿ íà 12 ïèêñåëåé âëåâî/âïðàâî
285 (sy
>= 0) and (not g_Obj_CanMoveY(Obj
, sy
)) then // òîëüêî åñëè åñòü çåìëÿ ïîä íîãàìè
292 st
:= st
or MOVE_HITWALL
;
297 st
:= st
or MOVE_HITWALL
;
300 else // Òàì ñòåíû íåò
302 if CollideLiquid(Obj
, sx
, 0) then
303 begin // Åñëè øàãíóòü â ñòîðîíó, à òàì òåïåðü æèäêîñòü
304 if ((st
and MOVE_INWATER
) = 0) then st
:= st
or MOVE_HITWATER
;
306 else // Åñëè øàãíóòü â ñòîðîíó, à òàì óæå íåò æèäêîñòè
308 if ((st
and MOVE_INWATER
) <> 0) then st
:= st
or MOVE_HITAIR
;
317 function movey (): Boolean;
321 // Åñëè ìîíñòðó øàãíóòü ïî âåðòèêàëè, à òàì áëîêìîí
322 if gMon
and ((st
and MOVE_BLOCK
) = 0) then
324 if Blocked(Obj
, 0, sy
) then st
:= st
or MOVE_BLOCK
;
327 // Åñëè øàãàòü íåëüçÿ
328 if not g_Obj_CanMoveY(Obj
, sy
) then
331 st
:= st
or MOVE_HITLAND
333 st
:= st
or MOVE_HITCEIL
;
335 else // Òàì ñòåíû íåò. È ñòóïåíè ñíèçó òîæå íåò
337 if CollideLiquid(Obj
, 0, sy
) then
338 begin // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì òåïåðü æèäêîñòü
339 if ((st
and MOVE_INWATER
) = 0) then st
:= st
or MOVE_HITWATER
;
341 else // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì óæå íåò æèäêîñòè
343 if ((st
and MOVE_INWATER
) <> 0) then st
:= st
or MOVE_HITAIR
;
355 // Îáúåêò â æèäêîñòè?
356 if CollideLiquid(Obj
, 0, 0) then st
:= st
or MOVE_INWATER
;
358 // Ìîíñòð â áëîêìîíå?
361 if Blocked(Obj
, 0, 0) then st
:= st
or MOVE_BLOCK
;
364 // Äâèãàòüñÿ íå íàäî?
365 if (dx
= 0) and (dy
= 0) then begin result
:= st
; exit
; end;
367 sx
:= g_basic
.Sign(dx
);
368 sy
:= g_basic
.Sign(dy
);
372 for i
:= 1 to dx
do if not movex() then break
;
373 for i
:= 1 to dy
do if not movey() then break
;
379 procedure g_Obj_Init (Obj
: PObj
); inline;
381 ZeroMemory(Obj
, SizeOf(TObj
));
385 function g_Obj_Move_Projectile (Obj
: PObj
; Fallable
: Boolean; Splash
: Boolean; ClimbSlopes
: Boolean=False): Word;
387 result
:= g_Obj_Move(Obj
, Fallable
, Splash
, ClimbSlopes
, true);
390 function g_Obj_Move (Obj
: PObj
; Fallable
: Boolean; Splash
: Boolean; ClimbSlopes
: Boolean=False; asProjectile
: Boolean=false): Word;
392 xv
, yv
, dx
, dy
: Integer;
397 dirx
, diry
, speed
: Double;
401 // Ëèìèòû íà ñêîðîñòü è óñêîðåíèå
402 Obj
^.Vel
.X
:= nclamp(Obj
^.Vel
.X
, -LIMIT_VEL
, LIMIT_VEL
);
403 Obj
^.Vel
.Y
:= nclamp(Obj
^.Vel
.Y
, -LIMIT_VEL
, LIMIT_VEL
);
404 Obj
^.Accel
.X
:= nclamp(Obj
^.Accel
.X
, -LIMIT_ACCEL
, LIMIT_ACCEL
);
405 Obj
^.Accel
.Y
:= nclamp(Obj
^.Accel
.Y
, -LIMIT_ACCEL
, LIMIT_ACCEL
);
407 if Obj^.Vel.X < -LIMIT_VEL then Obj^.Vel.X := -LIMIT_VEL
408 else if Obj^.Vel.X > LIMIT_VEL then Obj^.Vel.X := LIMIT_VEL;
409 if Obj^.Vel.Y < -LIMIT_VEL then Obj^.Vel.Y := -LIMIT_VEL
410 else if Obj^.Vel.Y > LIMIT_VEL then Obj^.Vel.Y := LIMIT_VEL;
411 if Obj^.Accel.X < -LIMIT_ACCEL then Obj^.Accel.X := -LIMIT_ACCEL
412 else if Obj^.Accel.X > LIMIT_ACCEL then Obj^.Accel.X := LIMIT_ACCEL;
413 if Obj^.Accel.Y < -LIMIT_ACCEL then Obj^.Accel.Y := -LIMIT_ACCEL
414 else if Obj^.Accel.Y > LIMIT_ACCEL then Obj^.Accel.Y := LIMIT_ACCEL;
417 // Âûëåòåë çà íèæíþþ ãðàíèöó êàðòû?
418 if (Obj
^.Y
> Integer(gMapInfo
.Height
)+128) then begin result
:= MOVE_FALLOUT
; Obj
.slopeUpLeft
:= 0; Obj
.slopeFramesLeft
:= 0; exit
; end;
420 // Ìåíÿåì ñêîðîñòü è óñêîðåíèå òîëüêî ïî ÷åòíûì êàäðàì
421 c
:= (gTime
mod (GAME_TICK
*2) <> 0);
424 if {not c and} (Obj
.slopeUpLeft
> 0) then
426 if (Obj
.slopeFramesLeft
< 1) then
428 //conwritefln('SLOPE DONE: slopeUpLeft=%s', [Obj.slopeUpLeft]);
429 Obj
.slopeUpLeft
:= 0; // oops
433 slopeStep
:= Obj
.slopeUpLeft
div Obj
.slopeFramesLeft
;
434 if (slopeStep
< 1) then slopeStep
:= 1;
435 //conwritefln('SLOPE STEP: slopeUpLeft=%s; slopeFramesLeft=%s; slopeStep=%d', [Obj.slopeUpLeft, Obj.slopeFramesLeft, slopeStep]);
436 Dec(Obj
.slopeFramesLeft
);
437 Obj
.slopeUpLeft
-= slopeStep
;
438 if (Obj
.slopeUpLeft
< 1) then
440 Obj
.slopeUpLeft
:= 0;
441 Obj
.slopeFramesLeft
:= 0;
446 if c
then goto _move
;
448 case CollideLift(Obj
, 0, 0) of
451 Obj
^.Vel
.Y
-= 1; // Ëèôò ââåðõ
452 if (Obj
^.Vel
.Y
< -5) then Obj
^.Vel
.Y
+= 1;
456 if (Obj
^.Vel
.Y
> 5) then Obj
^.Vel
.Y
-= 1;
457 Obj
^.Vel
.Y
+= 1; // Ãðàâèòàöèÿ èëè ëèôò âíèç
461 if Fallable
then Obj
^.Vel
.Y
+= 1; // Ãðàâèòàöèÿ
462 if (Obj
^.Vel
.Y
> MAX_YV
) then Obj
^.Vel
.Y
-= 1;
466 case CollideHorLift(Obj
, 0, 0) of
470 if (Obj
^.Vel
.X
< -9) then Obj
^.Vel
.X
+= 3;
475 if (Obj
^.Vel
.X
> 9) then Obj
^.Vel
.X
-= 3;
477 // 0 is not needed here
481 inwater
:= CollideLiquid(Obj
, 0, 0);
486 //writeln('velocity=(', Obj^.Vel.X, ',', Obj^.Vel.Y, '); acceleration=(', Obj^.Accel.X, ',', Obj^.Accel.Y, ')');
487 if (g_Obj_GetSpeedDirF(Obj
, dirx
, diry
, speed
)) then
489 //writeln('SPEED: ', speed);
493 Obj
^.Vel
.X
:= round(dirx
*speed
);
494 Obj
^.Vel
.Y
:= round(diry
*speed
);
499 if (g_Obj_GetAccelDirF(Obj
, dirx
, diry
, speed
)) then
504 Obj
^.Accel
.X
:= round(dirx
*speed
);
505 Obj
^.Accel
.Y
:= round(diry
*speed
);
512 xv
:= abs(Obj
^.Vel
.X
)+1;
513 if (xv
> 5) then Obj
^.Vel
.X
:= z_dec(Obj
^.Vel
.X
, (xv
div 2)-2);
514 yv
:= abs(Obj
^.Vel
.Y
)+1;
515 if (yv
> 5) then Obj
^.Vel
.Y
:= z_dec(Obj
^.Vel
.Y
, (yv
div 2)-2);
518 xv
:= abs(Obj
^.Accel
.X
)+1;
519 if (xv
> 5) then Obj
^.Accel
.X
:= z_dec(Obj
^.Accel
.X
, (xv
div 2)-2);
520 yv
:= abs(Obj
^.Accel
.Y
)+1;
521 if (yv
> 5) then Obj
^.Accel
.Y
:= z_dec(Obj
^.Accel
.Y
, (yv
div 2)-2);
525 // Óìåíüøàåì ïðèáàâêó ê ñêîðîñòè
526 Obj
^.Accel
.X
:= z_dec(Obj
^.Accel
.X
, 1);
527 Obj
^.Accel
.Y
:= z_dec(Obj
^.Accel
.Y
, 1);
531 xv
:= Obj
^.Vel
.X
+Obj
^.Accel
.X
;
532 yv
:= Obj
^.Vel
.Y
+Obj
^.Accel
.Y
;
537 result
:= move(Obj
, dx
, dy
, ClimbSlopes
);
539 // Áðûçãè (åñëè íóæíû)
542 if WordBool(Result
and MOVE_HITWATER
) then
544 wtx
:= g_Map_CollideLiquid_Texture(Obj
^.X
+Obj
^.Rect
.X
, Obj
^.Y
+Obj
^.Rect
.Y
,
545 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
*2 div 3);
547 LongWord(TEXTURE_SPECIAL_WATER
): g_Obj_Splash(Obj
, 3);
548 LongWord(TEXTURE_SPECIAL_ACID1
): g_Obj_Splash(Obj
, 2);
549 LongWord(TEXTURE_SPECIAL_ACID2
): g_Obj_Splash(Obj
, 1);
550 LongWord(TEXTURE_NONE
): begin end;
551 else g_Obj_Splash(Obj
, 0);
556 // Ìåíÿåì ñêîðîñòü è óñêîðåíèå òîëüêî ïî ÷åòíûì êàäðàì
559 // Âðåçàëèñü â ñòåíó - ñòîï
560 if ((Result
and MOVE_HITWALL
) <> 0) then
566 // Âðåçàëèñü â ïîë èëè ïîòîëîê - ñòîï
567 if ((Result
and (MOVE_HITCEIL
or MOVE_HITLAND
)) <> 0) then
575 function g_Obj_Collide(Obj1
, Obj2
: PObj
): Boolean; inline;
577 Result
:= g_Collide(Obj1
^.X
+Obj1
^.Rect
.X
, Obj1
^.Y
+Obj1
^.Rect
.Y
,
578 Obj1
^.Rect
.Width
, Obj1
^.Rect
.Height
,
579 Obj2
^.X
+Obj2
^.Rect
.X
, Obj2
^.Y
+Obj2
^.Rect
.Y
,
580 Obj2
^.Rect
.Width
, Obj2
^.Rect
.Height
);
583 function g_Obj_Collide(X
, Y
: Integer; Width
, Height
: Word; Obj
: PObj
): Boolean; inline;
585 Result
:= g_Collide(X
, Y
,
587 Obj
^.X
+Obj
^.Rect
.X
, Obj
^.Y
+Obj
^.Rect
.Y
,
588 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
);
591 function g_Obj_CollidePoint(X
, Y
: Integer; Obj
: PObj
): Boolean; inline;
593 Result
:= g_CollidePoint(X
, Y
, Obj
^.X
+Obj
^.Rect
.X
, Obj
^.Y
+Obj
^.Rect
.Y
,
594 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
);
597 procedure g_Obj_Push(Obj
: PObj
; VelX
, VelY
: Integer); inline;
599 Obj
^.Vel
.X
:= Obj
^.Vel
.X
+ VelX
;
600 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
+ VelY
;
603 procedure g_Obj_PushA(Obj
: PObj
; Vel
: Integer; Angle
: SmallInt); inline;
608 SinCos(DegToRad(-Angle
), s
, c
);
610 Obj
^.Vel
.X
:= Obj
^.Vel
.X
+ Round(Vel
*c
);
611 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
+ Round(Vel
*s
);
614 procedure g_Obj_SetSpeed(Obj
: PObj
; s
: Integer); inline;
621 m
:= Max(abs(vx
), abs(vy
));
625 Obj
^.Vel
.X
:= (vx
*s
) div m
;
626 Obj
^.Vel
.Y
:= (vy
*s
) div m
;
629 // `false`: zero speed
630 function g_Obj_GetSpeedDirF(Obj
: PObj
; var dirx
, diry
, speed
: Double): Boolean; inline;
634 if (Obj
^.Vel
.X
= 0) and (Obj
^.Vel
.Y
= 0) then
645 len
:= sqrt(vx
*vx
+vy
*vy
);
652 // `false`: zero acceleratin
653 function g_Obj_GetAccelDirF(Obj
: PObj
; var dirx
, diry
, speed
: Double): Boolean; inline;
657 if (Obj
^.Accel
.X
= 0) and (Obj
^.Accel
.Y
= 0) then
668 len
:= sqrt(vx
*vx
+vy
*vy
);
676 // Ïðèáëèæàåì a ê 0 íà b åäèíèö:
677 function z_dec (a
, b
: Integer): Integer; inline;
679 if (abs(a
) < b
) then result
:= 0
680 else if (a
> 0) then result
:= a
-b
681 else if (a
< 0) then result
:= a
+b
682 else result
:= 0; // a = 0
686 // Ïðèáëèæàåì a ê 0.0 íà b åäèíèö:
687 function z_fdec (a
, b
: Double): Double; inline;
689 if (abs(a
) < b
) then result
:= 0.0
690 else if (a
> 0.0) then result
:= a
-b
691 else if (a
< 0.0) then result
:= a
+b
692 else result
:= 0.0; // a = 0.0