DEADSOFTWARE

bye-bye, bineditor, we won't miss you
[d2df-sdl.git] / src / game / g_phys.pas
1 (* Copyright (C) DooM 2D:Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *)
16 {$INCLUDE ../shared/a_modes.inc}
17 unit g_phys;
19 interface
21 uses
22 e_graphics;
24 type
25 PObj = ^TObj;
26 TObj = record
27 X, Y: Integer;
28 Rect: TRectWH;
29 Vel: TPoint2i;
30 Accel: TPoint2i;
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 end;
37 const
38 MAX_YV = 30;
39 LIMIT_VEL = 16384;
40 LIMIT_ACCEL = 1024;
42 MOVE_NONE = 0;
43 MOVE_HITWALL = 1;
44 MOVE_HITCEIL = 2;
45 MOVE_HITLAND = 4;
46 MOVE_FALLOUT = 8;
47 MOVE_INWATER = 16;
48 MOVE_HITWATER = 32;
49 MOVE_HITAIR = 64;
50 MOVE_BLOCK = 128;
52 procedure g_Obj_Init(Obj: PObj); inline;
53 function g_Obj_Move(Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean = False): Word;
54 function g_Obj_Collide(Obj1, Obj2: PObj): Boolean; inline; overload;
55 function g_Obj_Collide(X, Y: Integer; Width, Height: Word; Obj: PObj): Boolean; inline; overload;
56 function g_Obj_CollidePoint(X, Y: Integer; Obj: PObj): Boolean; inline;
57 function g_Obj_CollideLevel(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
58 function g_Obj_CollideStep(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
59 function g_Obj_CollideWater(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
60 function g_Obj_CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
61 function g_Obj_CollidePanel(Obj: PObj; XInc, YInc: Integer; PanelType: Word): Boolean; inline;
62 function g_Obj_StayOnStep(Obj: PObj): Boolean; inline;
63 procedure g_Obj_Push(Obj: PObj; VelX, VelY: Integer); inline;
64 procedure g_Obj_PushA(Obj: PObj; Vel: Integer; Angle: SmallInt); inline;
65 procedure g_Obj_SetSpeed(Obj: PObj; s: Integer); inline;
66 function z_dec(a, b: Integer): Integer; inline;
67 function z_fdec(a, b: Double): Double; inline;
69 var
70 gMon: Boolean = False;
72 implementation
74 uses
75 g_map, g_basic, Math, g_player, g_console, SysUtils,
76 g_sound, g_gfx, MAPDEF, g_monsters, g_game, utils;
79 const
80 SmoothSlopeFrames = 4;
83 function g_Obj_StayOnStep(Obj: PObj): Boolean; inline;
84 begin
85 Result := not g_Map_CollidePanel(Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y+Obj^.Rect.Height-1,
86 Obj^.Rect.Width, 1,
87 PANEL_STEP, False)
88 and g_Map_CollidePanel(Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y+Obj^.Rect.Height,
89 Obj^.Rect.Width, 1,
90 PANEL_STEP, False);
91 end;
93 function CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
94 begin
95 Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj^.Rect.Y+YInc,
96 Obj^.Rect.Width, Obj^.Rect.Height*2 div 3,
97 PANEL_WATER or PANEL_ACID1 or PANEL_ACID2, False);
98 end;
100 function CollideLift(Obj: PObj; XInc, YInc: Integer): Integer; inline;
101 begin
102 if g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj^.Rect.Y+YInc,
103 Obj^.Rect.Width, Obj^.Rect.Height,
104 PANEL_LIFTUP, False) then
105 Result := -1
106 else if g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj^.Rect.Y+YInc,
107 Obj^.Rect.Width, Obj^.Rect.Height,
108 PANEL_LIFTDOWN, False) then
109 Result := 1
110 else
111 Result := 0;
112 end;
114 function CollideHorLift(Obj: PObj; XInc, YInc: Integer): Integer; inline;
115 var
116 left, right: Boolean;
117 begin
118 left := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj^.Rect.Y+YInc,
119 Obj^.Rect.Width, Obj^.Rect.Height,
120 PANEL_LIFTLEFT, False);
121 right := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj^.Rect.Y+YInc,
122 Obj^.Rect.Width, Obj^.Rect.Height,
123 PANEL_LIFTRIGHT, False);
124 if left and not right then
125 Result := -1
126 else if right and not left then
127 Result := 1
128 else
129 Result := 0;
130 end;
132 function CollidePlayers(_Obj: PObj; XInc, YInc: Integer): Boolean;
133 var
134 plr: TPlayer;
135 begin
136 result := false;
137 if (gPlayers = nil) then exit;
138 for plr in gPlayers do
139 begin
140 if (plr = nil) then continue;
141 if not plr.alive then continue;
142 with plr do
143 begin
144 if g_Collide(GameX+PLAYER_RECT.X, GameY+PLAYER_RECT.Y,
145 PLAYER_RECT.Width, PLAYER_RECT.Height,
146 _Obj^.X+_Obj^.Rect.X+XInc, _Obj^.Y+_Obj^.Rect.Y+YInc,
147 _Obj^.Rect.Width, _Obj^.Rect.Height) then
148 begin
149 result := true;
150 exit;
151 end;
152 end;
153 end;
154 end;
156 function Blocked(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
157 begin
158 Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc,
159 Obj^.Rect.Width, Obj^.Rect.Height,
160 PANEL_BLOCKMON, False);
161 end;
163 function g_Obj_CollideLevel(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
164 begin
165 Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc,
166 Obj^.Rect.Width, Obj^.Rect.Height,
167 PANEL_WALL, False);
168 end;
170 function g_Obj_CollideStep(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
171 begin
172 Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc,
173 Obj^.Rect.Width, Obj^.Rect.Height,
174 PANEL_STEP, False);
175 end;
177 function g_Obj_CollideWater(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
178 begin
179 Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc,
180 Obj^.Rect.Width, Obj^.Rect.Height,
181 PANEL_WATER, False);
182 end;
184 function g_Obj_CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
185 begin
186 Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc,
187 Obj^.Rect.Width, Obj^.Rect.Height,
188 PANEL_WATER or PANEL_ACID1 or PANEL_ACID2, False);
189 end;
191 function g_Obj_CollidePanel(Obj: PObj; XInc, YInc: Integer; PanelType: Word): Boolean; inline;
192 begin
193 Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc,
194 Obj^.Rect.Width, Obj^.Rect.Height,
195 PanelType, False);
196 end;
198 procedure g_Obj_Splash(Obj: PObj; Color: Byte);
199 var
200 MaxVel: Integer;
201 begin
202 MaxVel := nmax(abs(Obj^.Vel.X), abs(Obj^.Vel.Y));
203 if MaxVel > 4 then
204 begin
205 if MaxVel < 10 then
206 g_Sound_PlayExAt('SOUND_GAME_BULK1', Obj^.X, Obj^.Y)
207 else
208 g_Sound_PlayExAt('SOUND_GAME_BULK2', Obj^.X, Obj^.Y);
209 end;
211 g_GFX_Water(Obj^.X+Obj^.Rect.X+(Obj^.Rect.Width div 2),
212 Obj^.Y+Obj^.Rect.Y+(Obj^.Rect.Height div 2),
213 Min(5*(abs(Obj^.Vel.X)+abs(Obj^.Vel.Y)), 50),
214 -Obj^.Vel.X, -Obj^.Vel.Y,
215 Obj^.Rect.Width, 16, Color);
216 end;
219 function move (Obj: PObj; dx, dy: Integer; ClimbSlopes: Boolean): Word;
220 var
221 i: Integer;
222 sx, sy: ShortInt;
223 st: Word;
225 procedure slope (s: Integer);
226 var
227 i: Integer;
228 begin
229 i := 0;
230 while g_Obj_CollideLevel(Obj, sx, 0) and (i < 4) do
231 begin
232 Obj^.Y += s;
233 Inc(i);
234 end;
235 Obj^.X += sx;
236 if (s < 0) then
237 begin
238 Obj.slopeUpLeft += i*(-s);
239 Obj.slopeFramesLeft := SmoothSlopeFrames;
240 end;
241 end;
243 function movex (): Boolean;
244 begin
245 result := false;
247 // Åñëè ìîíñòðó øàãíóòü â ñòîðîíó, à òàì áëîêìîí
248 if gMon and ((st and MOVE_BLOCK) = 0) then
249 begin
250 if Blocked(Obj, sx, 0) then st := st or MOVE_BLOCK;
251 end;
253 // Åñëè øàãíóòü â ñòîðîíó, à òàì ñòåíà => øàãàòü íåëüçÿ
254 if g_Obj_CollideLevel(Obj, sx, 0) then
255 begin
256 if ClimbSlopes and (abs(dy) < 2) then
257 begin
258 result := true;
259 if (not g_Obj_CollideLevel(Obj, sx, -12)) and // çàáèðàåìñÿ íà 12 ïèêñåëåé âëåâî/âïðàâî
260 g_Obj_CollidePanel(Obj, 0, 1, PANEL_WALL or PANEL_STEP) then // òîëüêî åñëè åñòü çåìëÿ ïîä íîãàìè
261 begin
262 slope(-1);
263 end
264 else
265 begin
266 result := false;
267 st := st or MOVE_HITWALL;
268 end;
269 end
270 else
271 begin
272 st := st or MOVE_HITWALL;
273 end;
274 end
275 else // Òàì ñòåíû íåò
276 begin
277 if CollideLiquid(Obj, sx, 0) then
278 begin // Åñëè øàãíóòü â ñòîðîíó, à òàì òåïåðü æèäêîñòü
279 if ((st and MOVE_INWATER) = 0) then st := st or MOVE_HITWATER;
280 end
281 else // Åñëè øàãíóòü â ñòîðîíó, à òàì óæå íåò æèäêîñòè
282 begin
283 if ((st and MOVE_INWATER) <> 0) then st := st or MOVE_HITAIR;
284 end;
286 // Øàã
287 Obj^.X += sx;
288 result := true;
289 end;
290 end;
292 function movey (): Boolean;
293 begin
294 result := false;
296 // Åñëè ìîíñòðó øàãíóòü ïî âåðòèêàëè, à òàì áëîêìîí
297 if gMon and ((st and MOVE_BLOCK) = 0) then
298 begin
299 if Blocked(Obj, 0, sy) then st := st or MOVE_BLOCK;
300 end;
302 // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì ñòåíà => øàãàòü íåëüçÿ
303 // Èëè åñëè øàãíóòü âíèç, à òàì ñòóïåíü => øàãàòü íåëüçÿ
304 if g_Obj_CollideLevel(Obj, 0, sy) or ((sy > 0) and g_Obj_StayOnStep(Obj)) then
305 begin
306 if sy > 0 then
307 st := st or MOVE_HITLAND
308 else
309 st := st or MOVE_HITCEIL;
310 end
311 else // Òàì ñòåíû íåò. È ñòóïåíè ñíèçó òîæå íåò
312 begin
313 if CollideLiquid(Obj, 0, sy) then
314 begin // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì òåïåðü æèäêîñòü
315 if ((st and MOVE_INWATER) = 0) then st := st or MOVE_HITWATER;
316 end
317 else // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì óæå íåò æèäêîñòè
318 begin
319 if ((st and MOVE_INWATER) <> 0) then st := st or MOVE_HITAIR;
320 end;
322 // Øàã
323 Obj^.Y += sy;
324 result := true;
325 end;
326 end;
328 begin
329 st := MOVE_NONE;
331 // Îáúåêò â æèäêîñòè?
332 if CollideLiquid(Obj, 0, 0) then st := st or MOVE_INWATER;
334 // Ìîíñòð â áëîêìîíå?
335 if gMon then
336 begin
337 if Blocked(Obj, 0, 0) then st := st or MOVE_BLOCK;
338 end;
340 // Äâèãàòüñÿ íå íàäî?
341 if (dx = 0) and (dy = 0) then begin result := st; exit; end;
343 sx := g_basic.Sign(dx);
344 sy := g_basic.Sign(dy);
345 dx := abs(dx);
346 dy := abs(dy);
348 for i := 1 to dx do if not movex() then break;
349 for i := 1 to dy do if not movey() then break;
351 result := st;
352 end;
355 procedure g_Obj_Init (Obj: PObj); inline;
356 begin
357 ZeroMemory(Obj, SizeOf(TObj));
358 end;
361 function g_Obj_Move (Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean=False): Word;
362 var
363 xv, yv, dx, dy: Integer;
364 inwater: Boolean;
365 c: Boolean;
366 wtx: DWORD;
367 slopeStep: Integer;
368 label
369 _move;
370 begin
371 // Ëèìèòû íà ñêîðîñòü è óñêîðåíèå
372 Obj^.Vel.X := nclamp(Obj^.Vel.X, -LIMIT_VEL, LIMIT_VEL);
373 Obj^.Vel.Y := nclamp(Obj^.Vel.Y, -LIMIT_VEL, LIMIT_VEL);
374 Obj^.Accel.X := nclamp(Obj^.Accel.X, -LIMIT_ACCEL, LIMIT_ACCEL);
375 Obj^.Accel.Y := nclamp(Obj^.Accel.Y, -LIMIT_ACCEL, LIMIT_ACCEL);
377 if Obj^.Vel.X < -LIMIT_VEL then Obj^.Vel.X := -LIMIT_VEL
378 else if Obj^.Vel.X > LIMIT_VEL then Obj^.Vel.X := LIMIT_VEL;
379 if Obj^.Vel.Y < -LIMIT_VEL then Obj^.Vel.Y := -LIMIT_VEL
380 else if Obj^.Vel.Y > LIMIT_VEL then Obj^.Vel.Y := LIMIT_VEL;
381 if Obj^.Accel.X < -LIMIT_ACCEL then Obj^.Accel.X := -LIMIT_ACCEL
382 else if Obj^.Accel.X > LIMIT_ACCEL then Obj^.Accel.X := LIMIT_ACCEL;
383 if Obj^.Accel.Y < -LIMIT_ACCEL then Obj^.Accel.Y := -LIMIT_ACCEL
384 else if Obj^.Accel.Y > LIMIT_ACCEL then Obj^.Accel.Y := LIMIT_ACCEL;
387 // Âûëåòåë çà íèæíþþ ãðàíèöó êàðòû?
388 if (Obj^.Y > gMapInfo.Height+128) then begin result := MOVE_FALLOUT; Obj.slopeUpLeft := 0; Obj.slopeFramesLeft := 0; exit; end;
390 // Ìåíÿåì ñêîðîñòü è óñêîðåíèå òîëüêî ïî ÷åòíûì êàäðàì
391 c := (gTime mod (GAME_TICK*2) <> 0);
393 // smoothed slopes
394 if {not c and} (Obj.slopeUpLeft > 0) then
395 begin
396 if (Obj.slopeFramesLeft < 1) then
397 begin
398 //conwritefln('SLOPE DONE: slopeUpLeft=%s', [Obj.slopeUpLeft]);
399 Obj.slopeUpLeft := 0; // oops
400 end
401 else
402 begin
403 slopeStep := Obj.slopeUpLeft div Obj.slopeFramesLeft;
404 if (slopeStep < 1) then slopeStep := 1;
405 //conwritefln('SLOPE STEP: slopeUpLeft=%s; slopeFramesLeft=%s; slopeStep=%d', [Obj.slopeUpLeft, Obj.slopeFramesLeft, slopeStep]);
406 Dec(Obj.slopeFramesLeft);
407 Obj.slopeUpLeft -= slopeStep;
408 if (Obj.slopeUpLeft < 1) then
409 begin
410 Obj.slopeUpLeft := 0;
411 Obj.slopeFramesLeft := 0;
412 end;
413 end;
414 end;
416 if c then goto _move;
418 case CollideLift(Obj, 0, 0) of
419 -1: //up
420 begin
421 Obj^.Vel.Y -= 1; // Ëèôò ââåðõ
422 if (Obj^.Vel.Y < -5) then Obj^.Vel.Y += 1;
423 end;
424 1: //down
425 begin
426 if (Obj^.Vel.Y > 5) then Obj^.Vel.Y -= 1;
427 Obj^.Vel.Y += 1; // Ãðàâèòàöèÿ èëè ëèôò âíèç
428 end;
429 0: //???
430 begin
431 if Fallable then Obj^.Vel.Y += 1; // Ãðàâèòàöèÿ
432 if (Obj^.Vel.Y > MAX_YV) then Obj^.Vel.Y -= 1;
433 end;
434 end;
436 case CollideHorLift(Obj, 0, 0) of
437 -1: //left
438 begin
439 Obj^.Vel.X -= 3;
440 if (Obj^.Vel.X < -9) then Obj^.Vel.X += 3;
441 end;
442 1: //right
443 begin
444 Obj^.Vel.X += 3;
445 if (Obj^.Vel.X > 9) then Obj^.Vel.X -= 3;
446 end;
447 // 0 is not needed here
448 end;
450 // Â âîäå?
451 inwater := CollideLiquid(Obj, 0, 0);
452 if inwater then
453 begin
454 xv := abs(Obj^.Vel.X)+1;
455 if (xv > 5) then Obj^.Vel.X := z_dec(Obj^.Vel.X, (xv div 2)-2);
457 yv := abs(Obj^.Vel.Y)+1;
458 if (yv > 5) then Obj^.Vel.Y := z_dec(Obj^.Vel.Y, (yv div 2)-2);
460 xv := abs(Obj^.Accel.X)+1;
461 if (xv > 5) then Obj^.Accel.X := z_dec(Obj^.Accel.X, (xv div 2)-2);
463 yv := abs(Obj^.Accel.Y)+1;
464 if (yv > 5) then Obj^.Accel.Y := z_dec(Obj^.Accel.Y, (yv div 2)-2);
465 end;
467 // Óìåíüøàåì ïðèáàâêó ê ñêîðîñòè
468 Obj^.Accel.X := z_dec(Obj^.Accel.X, 1);
469 Obj^.Accel.Y := z_dec(Obj^.Accel.Y, 1);
471 _move:
473 xv := Obj^.Vel.X+Obj^.Accel.X;
474 yv := Obj^.Vel.Y+Obj^.Accel.Y;
476 dx := xv;
477 dy := yv;
479 result := move(Obj, dx, dy, ClimbSlopes);
481 // Áðûçãè (åñëè íóæíû)
482 if Splash then
483 begin
484 if WordBool(Result and MOVE_HITWATER) then
485 begin
486 wtx := g_Map_CollideLiquid_Texture(Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y,
487 Obj^.Rect.Width, Obj^.Rect.Height*2 div 3);
488 case wtx of
489 LongWord(TEXTURE_SPECIAL_WATER): g_Obj_Splash(Obj, 3);
490 LongWord(TEXTURE_SPECIAL_ACID1): g_Obj_Splash(Obj, 2);
491 LongWord(TEXTURE_SPECIAL_ACID2): g_Obj_Splash(Obj, 1);
492 LongWord(TEXTURE_NONE): begin end;
493 else g_Obj_Splash(Obj, 0);
494 end;
495 end;
496 end;
498 // Ìåíÿåì ñêîðîñòü è óñêîðåíèå òîëüêî ïî ÷åòíûì êàäðàì
499 if c then exit;
501 // Âðåçàëèñü â ñòåíó - ñòîï
502 if ((Result and MOVE_HITWALL) <> 0) then
503 begin
504 Obj^.Vel.X := 0;
505 Obj^.Accel.X := 0;
506 end;
508 // Âðåçàëèñü â ïîë èëè ïîòîëîê - ñòîï
509 if ((Result and (MOVE_HITCEIL or MOVE_HITLAND)) <> 0) then
510 begin
511 Obj^.Vel.Y := 0;
512 Obj^.Accel.Y := 0;
513 end;
514 end;
517 function g_Obj_Collide(Obj1, Obj2: PObj): Boolean; inline;
518 begin
519 Result := g_Collide(Obj1^.X+Obj1^.Rect.X, Obj1^.Y+Obj1^.Rect.Y,
520 Obj1^.Rect.Width, Obj1^.Rect.Height,
521 Obj2^.X+Obj2^.Rect.X, Obj2^.Y+Obj2^.Rect.Y,
522 Obj2^.Rect.Width, Obj2^.Rect.Height);
523 end;
525 function g_Obj_Collide(X, Y: Integer; Width, Height: Word; Obj: PObj): Boolean; inline;
526 begin
527 Result := g_Collide(X, Y,
528 Width, Height,
529 Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y,
530 Obj^.Rect.Width, Obj^.Rect.Height);
531 end;
533 function g_Obj_CollidePoint(X, Y: Integer; Obj: PObj): Boolean; inline;
534 begin
535 Result := g_CollidePoint(X, Y, Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y,
536 Obj^.Rect.Width, Obj^.Rect.Height);
537 end;
539 procedure g_Obj_Push(Obj: PObj; VelX, VelY: Integer); inline;
540 begin
541 Obj^.Vel.X := Obj^.Vel.X + VelX;
542 Obj^.Vel.Y := Obj^.Vel.Y + VelY;
543 end;
545 procedure g_Obj_PushA(Obj: PObj; Vel: Integer; Angle: SmallInt); inline;
546 var
547 s, c: Extended;
549 begin
550 SinCos(DegToRad(-Angle), s, c);
552 Obj^.Vel.X := Obj^.Vel.X + Round(Vel*c);
553 Obj^.Vel.Y := Obj^.Vel.Y + Round(Vel*s);
554 end;
556 procedure g_Obj_SetSpeed(Obj: PObj; s: Integer); inline;
557 var
558 m, vx, vy: Integer;
559 begin
560 vx := Obj^.Vel.X;
561 vy := Obj^.Vel.Y;
563 m := Max(abs(vx), abs(vy));
564 if m = 0 then
565 m := 1;
567 Obj^.Vel.X := (vx*s) div m;
568 Obj^.Vel.Y := (vy*s) div m;
569 end;
572 // Ïðèáëèæàåì a ê 0 íà b åäèíèö:
573 function z_dec (a, b: Integer): Integer; inline;
574 begin
575 if (abs(a) < b) then result := 0
576 else if (a > 0) then result := a-b
577 else if (a < 0) then result := a+b
578 else result := 0; // a = 0
579 end;
582 // Ïðèáëèæàåì a ê 0.0 íà b åäèíèö:
583 function z_fdec (a, b: Double): Double; inline;
584 begin
585 if (abs(a) < b) then result := 0.0
586 else if (a > 0.0) then result := a-b
587 else if (a < 0.0) then result := a+b
588 else result := 0.0; // a = 0.0
589 end;
592 end.