DEADSOFTWARE

render: remove from render some common types
[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, version 3 of the License ONLY.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *)
15 {$INCLUDE ../shared/a_modes.inc}
16 unit g_phys;
18 interface
20 uses g_base;
22 type
23 PObj = ^TObj;
24 TObj = record
25 X, Y: Integer;
26 Rect: TRectWH;
27 Vel: TPoint2i;
28 Accel: TPoint2i;
29 // going up the slope will set this, and renderer will adjust the position
30 // this is purely visual change, it won't affect anything else
31 slopeUpLeft: Integer; // left to go
32 slopeFramesLeft: Integer; // frames left to go
33 // for frame interpolation
34 oldX, oldY: Integer;
35 procedure lerp(t: Single; out fX, fY: Integer);
36 end;
38 const
39 MAX_YV = 30;
40 LIMIT_VEL = 16384;
41 LIMIT_ACCEL = 1024;
43 MOVE_NONE = 0;
44 MOVE_HITWALL = 1;
45 MOVE_HITCEIL = 2;
46 MOVE_HITLAND = 4;
47 MOVE_FALLOUT = 8;
48 MOVE_INWATER = 16;
49 MOVE_HITWATER = 32;
50 MOVE_HITAIR = 64;
51 MOVE_BLOCK = 128;
53 procedure g_Obj_Init(Obj: PObj); inline;
54 function g_Obj_Move(Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean=False; asProjectile: Boolean=false): Word;
55 function g_Obj_Move_Projectile (Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean=False): Word;
56 function g_Obj_Collide(Obj1, Obj2: PObj): Boolean; inline; overload;
57 function g_Obj_Collide(X, Y: Integer; Width, Height: Word; Obj: PObj): Boolean; inline; overload;
58 function g_Obj_CollidePoint(X, Y: Integer; Obj: PObj): Boolean; inline;
59 function g_Obj_CollideLevel(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
60 function g_Obj_CollideStep(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
61 function g_Obj_CollideWater(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
62 function g_Obj_CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
63 function g_Obj_CollidePanel(Obj: PObj; XInc, YInc: Integer; PanelType: Word): Boolean; inline;
64 function g_Obj_StayOnStep(Obj: PObj): Boolean; inline;
65 function g_Obj_CanMoveY(Obj: PObj; YInc: Integer): Boolean; inline;
66 procedure g_Obj_Push(Obj: PObj; VelX, VelY: Integer); inline;
67 procedure g_Obj_PushA(Obj: PObj; Vel: Integer; Angle: SmallInt); inline;
68 procedure g_Obj_SetSpeed(Obj: PObj; s: Integer); inline;
69 function g_Obj_GetSpeedDirF(Obj: PObj; var dirx, diry, speed: Double): Boolean; inline; // `false`: zero speed
70 function g_Obj_GetAccelDirF(Obj: PObj; var dirx, diry, speed: Double): Boolean; inline; // `false`: zero speed
71 function z_dec(a, b: Integer): Integer; inline;
72 function z_fdec(a, b: Double): Double; inline;
74 var
75 gMon: Boolean = False;
77 implementation
79 uses
80 g_map, g_basic, Math, g_player, g_console, SysUtils,
81 g_sound, g_gfx, MAPDEF, g_monsters, g_game, utils;
84 const
85 SmoothSlopeFrames = 4;
87 procedure TObj.lerp(t: Single; out fX, fY: Integer);
88 begin
89 fX := nlerp(oldX, X, t);
90 fY := nlerp(oldY, Y, t);
91 end;
93 function g_Obj_StayOnStep(Obj: PObj): Boolean; inline;
94 begin
95 Result := not g_Map_CollidePanel(Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y+Obj^.Rect.Height-1,
96 Obj^.Rect.Width, 1,
97 PANEL_STEP, False)
98 and g_Map_CollidePanel(Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y+Obj^.Rect.Height,
99 Obj^.Rect.Width, 1,
100 PANEL_STEP, False);
101 end;
103 function g_Obj_CanMoveY(Obj: PObj; YInc: Integer): Boolean; inline;
104 begin
105 // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì ñòåíà => øàãàòü íåëüçÿ
106 // Èëè åñëè øàãíóòü âíèç, à òàì ñòóïåíü => øàãàòü íåëüçÿ
107 Result := not(g_Obj_CollideLevel(Obj, 0, YInc) or ((YInc > 0) and g_Obj_StayOnStep(Obj)));
108 end;
110 function CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
111 begin
112 Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj^.Rect.Y+YInc,
113 Obj^.Rect.Width, Obj^.Rect.Height*2 div 3,
114 PANEL_WATER or PANEL_ACID1 or PANEL_ACID2, False);
115 end;
117 function CollideLift(Obj: PObj; XInc, YInc: Integer): Integer; inline;
118 begin
119 if g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj^.Rect.Y+YInc,
120 Obj^.Rect.Width, Obj^.Rect.Height,
121 PANEL_LIFTUP, False) then
122 Result := -1
123 else if g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj^.Rect.Y+YInc,
124 Obj^.Rect.Width, Obj^.Rect.Height,
125 PANEL_LIFTDOWN, False) then
126 Result := 1
127 else
128 Result := 0;
129 end;
131 function CollideHorLift(Obj: PObj; XInc, YInc: Integer): Integer; inline;
132 var
133 left, right: Boolean;
134 begin
135 left := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj^.Rect.Y+YInc,
136 Obj^.Rect.Width, Obj^.Rect.Height,
137 PANEL_LIFTLEFT, False);
138 right := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj^.Rect.Y+YInc,
139 Obj^.Rect.Width, Obj^.Rect.Height,
140 PANEL_LIFTRIGHT, False);
141 if left and not right then
142 Result := -1
143 else if right and not left then
144 Result := 1
145 else
146 Result := 0;
147 end;
149 function CollidePlayers(_Obj: PObj; XInc, YInc: Integer): Boolean;
150 var
151 plr: TPlayer;
152 begin
153 result := false;
154 if (gPlayers = nil) then exit;
155 for plr in gPlayers do
156 begin
157 if (plr = nil) then continue;
158 if not plr.alive then continue;
159 with plr do
160 begin
161 if g_Collide(GameX+PLAYER_RECT.X, GameY+PLAYER_RECT.Y,
162 PLAYER_RECT.Width, PLAYER_RECT.Height,
163 _Obj^.X+_Obj^.Rect.X+XInc, _Obj^.Y+_Obj^.Rect.Y+YInc,
164 _Obj^.Rect.Width, _Obj^.Rect.Height) then
165 begin
166 result := true;
167 exit;
168 end;
169 end;
170 end;
171 end;
173 function Blocked(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
174 begin
175 Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc,
176 Obj^.Rect.Width, Obj^.Rect.Height,
177 PANEL_BLOCKMON, False);
178 end;
180 function g_Obj_CollideLevel(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
181 begin
182 Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc,
183 Obj^.Rect.Width, Obj^.Rect.Height,
184 PANEL_WALL, False);
185 end;
187 function g_Obj_CollideStep(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
188 begin
189 Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc,
190 Obj^.Rect.Width, Obj^.Rect.Height,
191 PANEL_STEP, False);
192 end;
194 function g_Obj_CollideWater(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
195 begin
196 Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc,
197 Obj^.Rect.Width, Obj^.Rect.Height,
198 PANEL_WATER, False);
199 end;
201 function g_Obj_CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
202 begin
203 Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc,
204 Obj^.Rect.Width, Obj^.Rect.Height,
205 PANEL_WATER or PANEL_ACID1 or PANEL_ACID2, False);
206 end;
208 function g_Obj_CollidePanel(Obj: PObj; XInc, YInc: Integer; PanelType: Word): Boolean; inline;
209 begin
210 Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc,
211 Obj^.Rect.Width, Obj^.Rect.Height,
212 PanelType, False);
213 end;
215 procedure g_Obj_Splash(Obj: PObj; Color: Byte);
216 var
217 MaxVel: Integer;
218 begin
219 MaxVel := nmax(abs(Obj^.Vel.X), abs(Obj^.Vel.Y));
220 if MaxVel > 4 then
221 begin
222 if MaxVel < 10 then
223 g_Sound_PlayExAt('SOUND_GAME_BULK1', Obj^.X, Obj^.Y)
224 else
225 g_Sound_PlayExAt('SOUND_GAME_BULK2', Obj^.X, Obj^.Y);
226 end;
228 g_GFX_Water(Obj^.X+Obj^.Rect.X+(Obj^.Rect.Width div 2),
229 Obj^.Y+Obj^.Rect.Y+(Obj^.Rect.Height div 2),
230 Min(5*(abs(Obj^.Vel.X)+abs(Obj^.Vel.Y)), 50),
231 -Obj^.Vel.X, -Obj^.Vel.Y,
232 Obj^.Rect.Width, 16, Color);
233 end;
236 function move (Obj: PObj; dx, dy: Integer; ClimbSlopes: Boolean): Word;
237 var
238 i: Integer;
239 sx, sy: ShortInt;
240 st: Word;
242 procedure slope (s: Integer);
243 var
244 i: Integer;
245 begin
246 i := 0;
247 while g_Obj_CollideLevel(Obj, sx, 0) and (i < 4) do
248 begin
249 Obj^.Y += s;
250 Inc(i);
251 end;
252 Obj^.X += sx;
253 if (s < 0) then
254 begin
255 Obj.slopeUpLeft += i*(-s);
256 Obj.slopeFramesLeft := SmoothSlopeFrames;
257 end;
258 end;
260 function movex (): Boolean;
261 begin
262 result := false;
264 // Åñëè ìîíñòðó øàãíóòü â ñòîðîíó, à òàì áëîêìîí
265 if gMon and ((st and MOVE_BLOCK) = 0) then
266 begin
267 if Blocked(Obj, sx, 0) then st := st or MOVE_BLOCK;
268 end;
270 // Åñëè øàãíóòü â ñòîðîíó, à òàì ñòåíà => øàãàòü íåëüçÿ
271 if g_Obj_CollideLevel(Obj, sx, 0) then
272 begin
273 if ClimbSlopes and (abs(dy) < 2) then
274 begin
275 result := true;
276 if (not g_Obj_CollideLevel(Obj, sx, -12)) and // çàáèðàåìñÿ íà 12 ïèêñåëåé âëåâî/âïðàâî
277 (sy >= 0) and (not g_Obj_CanMoveY(Obj, sy)) then // òîëüêî åñëè åñòü çåìëÿ ïîä íîãàìè
278 begin
279 slope(-1);
280 end
281 else
282 begin
283 result := false;
284 st := st or MOVE_HITWALL;
285 end;
286 end
287 else
288 begin
289 st := st or MOVE_HITWALL;
290 end;
291 end
292 else // Òàì ñòåíû íåò
293 begin
294 if CollideLiquid(Obj, sx, 0) then
295 begin // Åñëè øàãíóòü â ñòîðîíó, à òàì òåïåðü æèäêîñòü
296 if ((st and MOVE_INWATER) = 0) then st := st or MOVE_HITWATER;
297 end
298 else // Åñëè øàãíóòü â ñòîðîíó, à òàì óæå íåò æèäêîñòè
299 begin
300 if ((st and MOVE_INWATER) <> 0) then st := st or MOVE_HITAIR;
301 end;
303 // Øàã
304 Obj^.X += sx;
305 result := true;
306 end;
307 end;
309 function movey (): Boolean;
310 begin
311 result := false;
313 // Åñëè ìîíñòðó øàãíóòü ïî âåðòèêàëè, à òàì áëîêìîí
314 if gMon and ((st and MOVE_BLOCK) = 0) then
315 begin
316 if Blocked(Obj, 0, sy) then st := st or MOVE_BLOCK;
317 end;
319 // Åñëè øàãàòü íåëüçÿ
320 if not g_Obj_CanMoveY(Obj, sy) then
321 begin
322 if sy > 0 then
323 st := st or MOVE_HITLAND
324 else
325 st := st or MOVE_HITCEIL;
326 end
327 else // Òàì ñòåíû íåò. È ñòóïåíè ñíèçó òîæå íåò
328 begin
329 if CollideLiquid(Obj, 0, sy) then
330 begin // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì òåïåðü æèäêîñòü
331 if ((st and MOVE_INWATER) = 0) then st := st or MOVE_HITWATER;
332 end
333 else // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì óæå íåò æèäêîñòè
334 begin
335 if ((st and MOVE_INWATER) <> 0) then st := st or MOVE_HITAIR;
336 end;
338 // Øàã
339 Obj^.Y += sy;
340 result := true;
341 end;
342 end;
344 begin
345 st := MOVE_NONE;
347 // Îáúåêò â æèäêîñòè?
348 if CollideLiquid(Obj, 0, 0) then st := st or MOVE_INWATER;
350 // Ìîíñòð â áëîêìîíå?
351 if gMon then
352 begin
353 if Blocked(Obj, 0, 0) then st := st or MOVE_BLOCK;
354 end;
356 // Äâèãàòüñÿ íå íàäî?
357 if (dx = 0) and (dy = 0) then begin result := st; exit; end;
359 sx := g_basic.Sign(dx);
360 sy := g_basic.Sign(dy);
361 dx := abs(dx);
362 dy := abs(dy);
364 for i := 1 to dx do if not movex() then break;
365 for i := 1 to dy do if not movey() then break;
367 result := st;
368 end;
371 procedure g_Obj_Init (Obj: PObj); inline;
372 begin
373 ZeroMemory(Obj, SizeOf(TObj));
374 end;
377 function g_Obj_Move_Projectile (Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean=False): Word;
378 begin
379 result := g_Obj_Move(Obj, Fallable, Splash, ClimbSlopes, true);
380 end;
382 function g_Obj_Move (Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean=False; asProjectile: Boolean=false): Word;
383 var
384 xv, yv, dx, dy: Integer;
385 inwater: Boolean;
386 c: Boolean;
387 wtx: DWORD;
388 slopeStep: Integer;
389 dirx, diry, speed: Double;
390 label
391 _move;
392 begin
393 // Ëèìèòû íà ñêîðîñòü è óñêîðåíèå
394 Obj^.Vel.X := nclamp(Obj^.Vel.X, -LIMIT_VEL, LIMIT_VEL);
395 Obj^.Vel.Y := nclamp(Obj^.Vel.Y, -LIMIT_VEL, LIMIT_VEL);
396 Obj^.Accel.X := nclamp(Obj^.Accel.X, -LIMIT_ACCEL, LIMIT_ACCEL);
397 Obj^.Accel.Y := nclamp(Obj^.Accel.Y, -LIMIT_ACCEL, LIMIT_ACCEL);
399 if Obj^.Vel.X < -LIMIT_VEL then Obj^.Vel.X := -LIMIT_VEL
400 else if Obj^.Vel.X > LIMIT_VEL then Obj^.Vel.X := LIMIT_VEL;
401 if Obj^.Vel.Y < -LIMIT_VEL then Obj^.Vel.Y := -LIMIT_VEL
402 else if Obj^.Vel.Y > LIMIT_VEL then Obj^.Vel.Y := LIMIT_VEL;
403 if Obj^.Accel.X < -LIMIT_ACCEL then Obj^.Accel.X := -LIMIT_ACCEL
404 else if Obj^.Accel.X > LIMIT_ACCEL then Obj^.Accel.X := LIMIT_ACCEL;
405 if Obj^.Accel.Y < -LIMIT_ACCEL then Obj^.Accel.Y := -LIMIT_ACCEL
406 else if Obj^.Accel.Y > LIMIT_ACCEL then Obj^.Accel.Y := LIMIT_ACCEL;
409 // Âûëåòåë çà íèæíþþ ãðàíèöó êàðòû?
410 if (Obj^.Y > Integer(gMapInfo.Height)+128) then begin result := MOVE_FALLOUT; Obj.slopeUpLeft := 0; Obj.slopeFramesLeft := 0; exit; end;
412 // Ìåíÿåì ñêîðîñòü è óñêîðåíèå òîëüêî ïî ÷åòíûì êàäðàì
413 c := (gTime mod (GAME_TICK*2) <> 0);
415 // smoothed slopes
416 if {not c and} (Obj.slopeUpLeft > 0) then
417 begin
418 if (Obj.slopeFramesLeft < 1) then
419 begin
420 //conwritefln('SLOPE DONE: slopeUpLeft=%s', [Obj.slopeUpLeft]);
421 Obj.slopeUpLeft := 0; // oops
422 end
423 else
424 begin
425 slopeStep := Obj.slopeUpLeft div Obj.slopeFramesLeft;
426 if (slopeStep < 1) then slopeStep := 1;
427 //conwritefln('SLOPE STEP: slopeUpLeft=%s; slopeFramesLeft=%s; slopeStep=%d', [Obj.slopeUpLeft, Obj.slopeFramesLeft, slopeStep]);
428 Dec(Obj.slopeFramesLeft);
429 Obj.slopeUpLeft -= slopeStep;
430 if (Obj.slopeUpLeft < 1) then
431 begin
432 Obj.slopeUpLeft := 0;
433 Obj.slopeFramesLeft := 0;
434 end;
435 end;
436 end;
438 if c then goto _move;
440 case CollideLift(Obj, 0, 0) of
441 -1: //up
442 begin
443 Obj^.Vel.Y -= 1; // Ëèôò ââåðõ
444 if (Obj^.Vel.Y < -5) then Obj^.Vel.Y += 1;
445 end;
446 1: //down
447 begin
448 if (Obj^.Vel.Y > 5) then Obj^.Vel.Y -= 1;
449 Obj^.Vel.Y += 1; // Ãðàâèòàöèÿ èëè ëèôò âíèç
450 end;
451 0: //???
452 begin
453 if Fallable then Obj^.Vel.Y += 1; // Ãðàâèòàöèÿ
454 if (Obj^.Vel.Y > MAX_YV) then Obj^.Vel.Y -= 1;
455 end;
456 end;
458 case CollideHorLift(Obj, 0, 0) of
459 -1: //left
460 begin
461 Obj^.Vel.X -= 3;
462 if (Obj^.Vel.X < -9) then Obj^.Vel.X += 3;
463 end;
464 1: //right
465 begin
466 Obj^.Vel.X += 3;
467 if (Obj^.Vel.X > 9) then Obj^.Vel.X -= 3;
468 end;
469 // 0 is not needed here
470 end;
472 // Â âîäå?
473 inwater := CollideLiquid(Obj, 0, 0);
474 if inwater then
475 begin
476 if asProjectile then
477 begin
478 //writeln('velocity=(', Obj^.Vel.X, ',', Obj^.Vel.Y, '); acceleration=(', Obj^.Accel.X, ',', Obj^.Accel.Y, ')');
479 if (g_Obj_GetSpeedDirF(Obj, dirx, diry, speed)) then
480 begin
481 //writeln('SPEED: ', speed);
482 if (speed > 5) then
483 begin
484 speed := speed/1.4;
485 Obj^.Vel.X := round(dirx*speed);
486 Obj^.Vel.Y := round(diry*speed);
487 end;
488 end;
490 // acceleration
491 if (g_Obj_GetAccelDirF(Obj, dirx, diry, speed)) then
492 begin
493 if (speed > 5) then
494 begin
495 speed := speed/1.4;
496 Obj^.Accel.X := round(dirx*speed);
497 Obj^.Accel.Y := round(diry*speed);
498 end;
499 end;
500 end
501 else
502 begin
503 // velocity
504 xv := abs(Obj^.Vel.X)+1;
505 if (xv > 5) then Obj^.Vel.X := z_dec(Obj^.Vel.X, (xv div 2)-2);
506 yv := abs(Obj^.Vel.Y)+1;
507 if (yv > 5) then Obj^.Vel.Y := z_dec(Obj^.Vel.Y, (yv div 2)-2);
509 // acceleration
510 xv := abs(Obj^.Accel.X)+1;
511 if (xv > 5) then Obj^.Accel.X := z_dec(Obj^.Accel.X, (xv div 2)-2);
512 yv := abs(Obj^.Accel.Y)+1;
513 if (yv > 5) then Obj^.Accel.Y := z_dec(Obj^.Accel.Y, (yv div 2)-2);
514 end;
515 end;
517 // Óìåíüøàåì ïðèáàâêó ê ñêîðîñòè
518 Obj^.Accel.X := z_dec(Obj^.Accel.X, 1);
519 Obj^.Accel.Y := z_dec(Obj^.Accel.Y, 1);
521 _move:
523 xv := Obj^.Vel.X+Obj^.Accel.X;
524 yv := Obj^.Vel.Y+Obj^.Accel.Y;
526 dx := xv;
527 dy := yv;
529 result := move(Obj, dx, dy, ClimbSlopes);
531 // Áðûçãè (åñëè íóæíû)
532 if Splash then
533 begin
534 if WordBool(Result and MOVE_HITWATER) then
535 begin
536 wtx := g_Map_CollideLiquid_Texture(Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y,
537 Obj^.Rect.Width, Obj^.Rect.Height*2 div 3);
538 case wtx of
539 LongWord(TEXTURE_SPECIAL_WATER): g_Obj_Splash(Obj, 3);
540 LongWord(TEXTURE_SPECIAL_ACID1): g_Obj_Splash(Obj, 2);
541 LongWord(TEXTURE_SPECIAL_ACID2): g_Obj_Splash(Obj, 1);
542 LongWord(TEXTURE_NONE): begin end;
543 else g_Obj_Splash(Obj, 0);
544 end;
545 end;
546 end;
548 // Ìåíÿåì ñêîðîñòü è óñêîðåíèå òîëüêî ïî ÷åòíûì êàäðàì
549 if c then exit;
551 // Âðåçàëèñü â ñòåíó - ñòîï
552 if ((Result and MOVE_HITWALL) <> 0) then
553 begin
554 Obj^.Vel.X := 0;
555 Obj^.Accel.X := 0;
556 end;
558 // Âðåçàëèñü â ïîë èëè ïîòîëîê - ñòîï
559 if ((Result and (MOVE_HITCEIL or MOVE_HITLAND)) <> 0) then
560 begin
561 Obj^.Vel.Y := 0;
562 Obj^.Accel.Y := 0;
563 end;
564 end;
567 function g_Obj_Collide(Obj1, Obj2: PObj): Boolean; inline;
568 begin
569 Result := g_Collide(Obj1^.X+Obj1^.Rect.X, Obj1^.Y+Obj1^.Rect.Y,
570 Obj1^.Rect.Width, Obj1^.Rect.Height,
571 Obj2^.X+Obj2^.Rect.X, Obj2^.Y+Obj2^.Rect.Y,
572 Obj2^.Rect.Width, Obj2^.Rect.Height);
573 end;
575 function g_Obj_Collide(X, Y: Integer; Width, Height: Word; Obj: PObj): Boolean; inline;
576 begin
577 Result := g_Collide(X, Y,
578 Width, Height,
579 Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y,
580 Obj^.Rect.Width, Obj^.Rect.Height);
581 end;
583 function g_Obj_CollidePoint(X, Y: Integer; Obj: PObj): Boolean; inline;
584 begin
585 Result := g_CollidePoint(X, Y, Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y,
586 Obj^.Rect.Width, Obj^.Rect.Height);
587 end;
589 procedure g_Obj_Push(Obj: PObj; VelX, VelY: Integer); inline;
590 begin
591 Obj^.Vel.X := Obj^.Vel.X + VelX;
592 Obj^.Vel.Y := Obj^.Vel.Y + VelY;
593 end;
595 procedure g_Obj_PushA(Obj: PObj; Vel: Integer; Angle: SmallInt); inline;
596 var
597 s, c: Extended;
599 begin
600 SinCos(DegToRad(-Angle), s, c);
602 Obj^.Vel.X := Obj^.Vel.X + Round(Vel*c);
603 Obj^.Vel.Y := Obj^.Vel.Y + Round(Vel*s);
604 end;
606 procedure g_Obj_SetSpeed(Obj: PObj; s: Integer); inline;
607 var
608 m, vx, vy: Integer;
609 begin
610 vx := Obj^.Vel.X;
611 vy := Obj^.Vel.Y;
613 m := Max(abs(vx), abs(vy));
614 if m = 0 then
615 m := 1;
617 Obj^.Vel.X := (vx*s) div m;
618 Obj^.Vel.Y := (vy*s) div m;
619 end;
621 // `false`: zero speed
622 function g_Obj_GetSpeedDirF(Obj: PObj; var dirx, diry, speed: Double): Boolean; inline;
623 var
624 len, vx, vy: Double;
625 begin
626 if (Obj^.Vel.X = 0) and (Obj^.Vel.Y = 0) then
627 begin
628 dirx := 0;
629 diry := 0;
630 speed := 0;
631 result := false;
632 exit;
633 end;
635 vx := Obj^.Vel.X;
636 vy := Obj^.Vel.Y;
637 len := sqrt(vx*vx+vy*vy);
638 dirx := vx/len;
639 diry := vy/len;
640 speed := len;
641 result := true;
642 end;
644 // `false`: zero acceleratin
645 function g_Obj_GetAccelDirF(Obj: PObj; var dirx, diry, speed: Double): Boolean; inline;
646 var
647 len, vx, vy: Double;
648 begin
649 if (Obj^.Accel.X = 0) and (Obj^.Accel.Y = 0) then
650 begin
651 dirx := 0;
652 diry := 0;
653 speed := 0;
654 result := false;
655 exit;
656 end;
658 vx := Obj^.Accel.X;
659 vy := Obj^.Accel.Y;
660 len := sqrt(vx*vx+vy*vy);
661 dirx := vx/len;
662 diry := vy/len;
663 speed := len;
664 result := true;
665 end;
668 // Ïðèáëèæàåì a ê 0 íà b åäèíèö:
669 function z_dec (a, b: Integer): Integer; inline;
670 begin
671 if (abs(a) < b) then result := 0
672 else if (a > 0) then result := a-b
673 else if (a < 0) then result := a+b
674 else result := 0; // a = 0
675 end;
678 // Ïðèáëèæàåì a ê 0.0 íà b åäèíèö:
679 function z_fdec (a, b: Double): Double; inline;
680 begin
681 if (abs(a) < b) then result := 0.0
682 else if (a > 0.0) then result := a-b
683 else if (a < 0.0) then result := a+b
684 else result := 0.0; // a = 0.0
685 end;
688 end.