DEADSOFTWARE

gl: interpolate platforms
[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 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; asProjectile: Boolean=false): Word;
54 function g_Obj_Move_Projectile (Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean=False): Word;
55 function g_Obj_Collide(Obj1, Obj2: PObj): Boolean; inline; overload;
56 function g_Obj_Collide(X, Y: Integer; Width, Height: Word; Obj: PObj): Boolean; inline; overload;
57 function g_Obj_CollidePoint(X, Y: Integer; Obj: PObj): Boolean; inline;
58 function g_Obj_CollideLevel(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
59 function g_Obj_CollideStep(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
60 function g_Obj_CollideWater(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
61 function g_Obj_CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
62 function g_Obj_CollidePanel(Obj: PObj; XInc, YInc: Integer; PanelType: Word): Boolean; inline;
63 function g_Obj_StayOnStep(Obj: PObj): Boolean; inline;
64 function g_Obj_CanMoveY(Obj: PObj; YInc: Integer): Boolean; inline;
65 procedure g_Obj_Push(Obj: PObj; VelX, VelY: Integer); inline;
66 procedure g_Obj_PushA(Obj: PObj; Vel: Integer; Angle: SmallInt); inline;
67 procedure g_Obj_SetSpeed(Obj: PObj; s: Integer); inline;
68 function g_Obj_GetSpeedDirF(Obj: PObj; var dirx, diry, speed: Double): Boolean; inline; // `false`: zero speed
69 function g_Obj_GetAccelDirF(Obj: PObj; var dirx, diry, speed: Double): Boolean; inline; // `false`: zero speed
70 function z_dec(a, b: Integer): Integer; inline;
71 function z_fdec(a, b: Double): Double; inline;
73 var
74 gMon: Boolean = False;
76 implementation
78 uses
79 {$IFDEF ENABLE_GFX}
80 g_gfx,
81 {$ENDIF}
82 g_map, g_basic, Math, g_player, g_console, SysUtils,
83 g_sound, MAPDEF, g_monsters, g_game, utils
84 ;
87 const
88 SmoothSlopeFrames = 4;
90 function g_Obj_StayOnStep(Obj: PObj): Boolean; inline;
91 begin
92 Result := not g_Map_CollidePanel(Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y+Obj^.Rect.Height-1,
93 Obj^.Rect.Width, 1,
94 PANEL_STEP, False)
95 and g_Map_CollidePanel(Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y+Obj^.Rect.Height,
96 Obj^.Rect.Width, 1,
97 PANEL_STEP, False);
98 end;
100 function g_Obj_CanMoveY(Obj: PObj; YInc: Integer): Boolean; inline;
101 begin
102 // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì ñòåíà => øàãàòü íåëüçÿ
103 // Èëè åñëè øàãíóòü âíèç, à òàì ñòóïåíü => øàãàòü íåëüçÿ
104 Result := not(g_Obj_CollideLevel(Obj, 0, YInc) or ((YInc > 0) and g_Obj_StayOnStep(Obj)));
105 end;
107 function CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
108 begin
109 Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj^.Rect.Y+YInc,
110 Obj^.Rect.Width, Obj^.Rect.Height*2 div 3,
111 PANEL_WATER or PANEL_ACID1 or PANEL_ACID2, False);
112 end;
114 function CollideLift(Obj: PObj; XInc, YInc: Integer): Integer; inline;
115 begin
116 if g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj^.Rect.Y+YInc,
117 Obj^.Rect.Width, Obj^.Rect.Height,
118 PANEL_LIFTUP, False) then
119 Result := -1
120 else if g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj^.Rect.Y+YInc,
121 Obj^.Rect.Width, Obj^.Rect.Height,
122 PANEL_LIFTDOWN, False) then
123 Result := 1
124 else
125 Result := 0;
126 end;
128 function CollideHorLift(Obj: PObj; XInc, YInc: Integer): Integer; inline;
129 var
130 left, right: Boolean;
131 begin
132 left := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj^.Rect.Y+YInc,
133 Obj^.Rect.Width, Obj^.Rect.Height,
134 PANEL_LIFTLEFT, False);
135 right := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj^.Rect.Y+YInc,
136 Obj^.Rect.Width, Obj^.Rect.Height,
137 PANEL_LIFTRIGHT, False);
138 if left and not right then
139 Result := -1
140 else if right and not left then
141 Result := 1
142 else
143 Result := 0;
144 end;
146 function CollidePlayers(_Obj: PObj; XInc, YInc: Integer): Boolean;
147 var
148 plr: TPlayer;
149 begin
150 result := false;
151 if (gPlayers = nil) then exit;
152 for plr in gPlayers do
153 begin
154 if (plr = nil) then continue;
155 if not plr.alive then continue;
156 with plr do
157 begin
158 if g_Collide(GameX+PLAYER_RECT.X, GameY+PLAYER_RECT.Y,
159 PLAYER_RECT.Width, PLAYER_RECT.Height,
160 _Obj^.X+_Obj^.Rect.X+XInc, _Obj^.Y+_Obj^.Rect.Y+YInc,
161 _Obj^.Rect.Width, _Obj^.Rect.Height) then
162 begin
163 result := true;
164 exit;
165 end;
166 end;
167 end;
168 end;
170 function Blocked(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_BLOCKMON, False);
175 end;
177 function g_Obj_CollideLevel(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_WALL, False);
182 end;
184 function g_Obj_CollideStep(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_STEP, False);
189 end;
191 function g_Obj_CollideWater(Obj: PObj; XInc, YInc: Integer): 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 PANEL_WATER, False);
196 end;
198 function g_Obj_CollideLiquid(Obj: PObj; XInc, YInc: Integer): Boolean; inline;
199 begin
200 Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc,
201 Obj^.Rect.Width, Obj^.Rect.Height,
202 PANEL_WATER or PANEL_ACID1 or PANEL_ACID2, False);
203 end;
205 function g_Obj_CollidePanel(Obj: PObj; XInc, YInc: Integer; PanelType: Word): Boolean; inline;
206 begin
207 Result := g_Map_CollidePanel(Obj^.X+Obj^.Rect.X+XInc, Obj^.Y+Obj.Rect.Y+YInc,
208 Obj^.Rect.Width, Obj^.Rect.Height,
209 PanelType, False);
210 end;
212 procedure g_Obj_Splash(Obj: PObj; Color: Byte);
213 var
214 MaxVel: Integer;
215 begin
216 MaxVel := nmax(abs(Obj^.Vel.X), abs(Obj^.Vel.Y));
217 if MaxVel > 4 then
218 begin
219 if MaxVel < 10 then
220 g_Sound_PlayExAt('SOUND_GAME_BULK1', Obj^.X, Obj^.Y)
221 else
222 g_Sound_PlayExAt('SOUND_GAME_BULK2', Obj^.X, Obj^.Y);
223 end;
225 {$IFDEF ENABLE_GFX}
226 g_GFX_Water(Obj^.X+Obj^.Rect.X+(Obj^.Rect.Width div 2),
227 Obj^.Y+Obj^.Rect.Y+(Obj^.Rect.Height div 2),
228 Min(5*(abs(Obj^.Vel.X)+abs(Obj^.Vel.Y)), 50),
229 -Obj^.Vel.X, -Obj^.Vel.Y,
230 Obj^.Rect.Width, 16, Color);
231 {$ENDIF}
232 end;
235 function move (Obj: PObj; dx, dy: Integer; ClimbSlopes: Boolean): Word;
236 var
237 i: Integer;
238 sx, sy: ShortInt;
239 st: Word;
241 procedure slope (s: Integer);
242 var
243 i: Integer;
244 begin
245 i := 0;
246 while g_Obj_CollideLevel(Obj, sx, 0) and (i < 4) do
247 begin
248 Obj^.Y += s;
249 Inc(i);
250 end;
251 Obj^.X += sx;
252 if (s < 0) then
253 begin
254 Obj.slopeUpLeft += i*(-s);
255 Obj.slopeFramesLeft := SmoothSlopeFrames;
256 end;
257 end;
259 function movex (): Boolean;
260 begin
261 result := false;
263 // Åñëè ìîíñòðó øàãíóòü â ñòîðîíó, à òàì áëîêìîí
264 if gMon and ((st and MOVE_BLOCK) = 0) then
265 begin
266 if Blocked(Obj, sx, 0) then st := st or MOVE_BLOCK;
267 end;
269 // Åñëè øàãíóòü â ñòîðîíó, à òàì ñòåíà => øàãàòü íåëüçÿ
270 if g_Obj_CollideLevel(Obj, sx, 0) then
271 begin
272 if ClimbSlopes and (abs(dy) < 2) then
273 begin
274 result := true;
275 if (not g_Obj_CollideLevel(Obj, sx, -12)) and // çàáèðàåìñÿ íà 12 ïèêñåëåé âëåâî/âïðàâî
276 (sy >= 0) and (not g_Obj_CanMoveY(Obj, sy)) then // òîëüêî åñëè åñòü çåìëÿ ïîä íîãàìè
277 begin
278 slope(-1);
279 end
280 else
281 begin
282 result := false;
283 st := st or MOVE_HITWALL;
284 end;
285 end
286 else
287 begin
288 st := st or MOVE_HITWALL;
289 end;
290 end
291 else // Òàì ñòåíû íåò
292 begin
293 if CollideLiquid(Obj, sx, 0) then
294 begin // Åñëè øàãíóòü â ñòîðîíó, à òàì òåïåðü æèäêîñòü
295 if ((st and MOVE_INWATER) = 0) then st := st or MOVE_HITWATER;
296 end
297 else // Åñëè øàãíóòü â ñòîðîíó, à òàì óæå íåò æèäêîñòè
298 begin
299 if ((st and MOVE_INWATER) <> 0) then st := st or MOVE_HITAIR;
300 end;
302 // Øàã
303 Obj^.X += sx;
304 result := true;
305 end;
306 end;
308 function movey (): Boolean;
309 begin
310 result := false;
312 // Åñëè ìîíñòðó øàãíóòü ïî âåðòèêàëè, à òàì áëîêìîí
313 if gMon and ((st and MOVE_BLOCK) = 0) then
314 begin
315 if Blocked(Obj, 0, sy) then st := st or MOVE_BLOCK;
316 end;
318 // Åñëè øàãàòü íåëüçÿ
319 if not g_Obj_CanMoveY(Obj, sy) then
320 begin
321 if sy > 0 then
322 st := st or MOVE_HITLAND
323 else
324 st := st or MOVE_HITCEIL;
325 end
326 else // Òàì ñòåíû íåò. È ñòóïåíè ñíèçó òîæå íåò
327 begin
328 if CollideLiquid(Obj, 0, sy) then
329 begin // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì òåïåðü æèäêîñòü
330 if ((st and MOVE_INWATER) = 0) then st := st or MOVE_HITWATER;
331 end
332 else // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì óæå íåò æèäêîñòè
333 begin
334 if ((st and MOVE_INWATER) <> 0) then st := st or MOVE_HITAIR;
335 end;
337 // Øàã
338 Obj^.Y += sy;
339 result := true;
340 end;
341 end;
343 begin
344 st := MOVE_NONE;
346 // Îáúåêò â æèäêîñòè?
347 if CollideLiquid(Obj, 0, 0) then st := st or MOVE_INWATER;
349 // Ìîíñòð â áëîêìîíå?
350 if gMon then
351 begin
352 if Blocked(Obj, 0, 0) then st := st or MOVE_BLOCK;
353 end;
355 // Äâèãàòüñÿ íå íàäî?
356 if (dx = 0) and (dy = 0) then begin result := st; exit; end;
358 sx := g_basic.Sign(dx);
359 sy := g_basic.Sign(dy);
360 dx := abs(dx);
361 dy := abs(dy);
363 for i := 1 to dx do if not movex() then break;
364 for i := 1 to dy do if not movey() then break;
366 result := st;
367 end;
370 procedure g_Obj_Init (Obj: PObj); inline;
371 begin
372 ZeroMemory(Obj, SizeOf(TObj));
373 end;
376 function g_Obj_Move_Projectile (Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean=False): Word;
377 begin
378 result := g_Obj_Move(Obj, Fallable, Splash, ClimbSlopes, true);
379 end;
381 function g_Obj_Move (Obj: PObj; Fallable: Boolean; Splash: Boolean; ClimbSlopes: Boolean=False; asProjectile: Boolean=false): Word;
382 var
383 xv, yv, dx, dy: Integer;
384 inwater: Boolean;
385 c: Boolean;
386 wtx: DWORD;
387 slopeStep: Integer;
388 dirx, diry, speed: Double;
389 label
390 _move;
391 begin
392 // Ëèìèòû íà ñêîðîñòü è óñêîðåíèå
393 Obj^.Vel.X := nclamp(Obj^.Vel.X, -LIMIT_VEL, LIMIT_VEL);
394 Obj^.Vel.Y := nclamp(Obj^.Vel.Y, -LIMIT_VEL, LIMIT_VEL);
395 Obj^.Accel.X := nclamp(Obj^.Accel.X, -LIMIT_ACCEL, LIMIT_ACCEL);
396 Obj^.Accel.Y := nclamp(Obj^.Accel.Y, -LIMIT_ACCEL, LIMIT_ACCEL);
398 if Obj^.Vel.X < -LIMIT_VEL then Obj^.Vel.X := -LIMIT_VEL
399 else if Obj^.Vel.X > LIMIT_VEL then Obj^.Vel.X := LIMIT_VEL;
400 if Obj^.Vel.Y < -LIMIT_VEL then Obj^.Vel.Y := -LIMIT_VEL
401 else if Obj^.Vel.Y > LIMIT_VEL then Obj^.Vel.Y := LIMIT_VEL;
402 if Obj^.Accel.X < -LIMIT_ACCEL then Obj^.Accel.X := -LIMIT_ACCEL
403 else if Obj^.Accel.X > LIMIT_ACCEL then Obj^.Accel.X := LIMIT_ACCEL;
404 if Obj^.Accel.Y < -LIMIT_ACCEL then Obj^.Accel.Y := -LIMIT_ACCEL
405 else if Obj^.Accel.Y > LIMIT_ACCEL then Obj^.Accel.Y := LIMIT_ACCEL;
408 // Âûëåòåë çà íèæíþþ ãðàíèöó êàðòû?
409 if (Obj^.Y > Integer(gMapInfo.Height)+128) then begin result := MOVE_FALLOUT; Obj.slopeUpLeft := 0; Obj.slopeFramesLeft := 0; exit; end;
411 // Ìåíÿåì ñêîðîñòü è óñêîðåíèå òîëüêî ïî ÷åòíûì êàäðàì
412 c := (gTime mod (GAME_TICK*2) <> 0);
414 // smoothed slopes
415 if {not c and} (Obj.slopeUpLeft > 0) then
416 begin
417 if (Obj.slopeFramesLeft < 1) then
418 begin
419 //conwritefln('SLOPE DONE: slopeUpLeft=%s', [Obj.slopeUpLeft]);
420 Obj.slopeUpLeft := 0; // oops
421 end
422 else
423 begin
424 slopeStep := Obj.slopeUpLeft div Obj.slopeFramesLeft;
425 if (slopeStep < 1) then slopeStep := 1;
426 //conwritefln('SLOPE STEP: slopeUpLeft=%s; slopeFramesLeft=%s; slopeStep=%d', [Obj.slopeUpLeft, Obj.slopeFramesLeft, slopeStep]);
427 Dec(Obj.slopeFramesLeft);
428 Obj.slopeUpLeft -= slopeStep;
429 if (Obj.slopeUpLeft < 1) then
430 begin
431 Obj.slopeUpLeft := 0;
432 Obj.slopeFramesLeft := 0;
433 end;
434 end;
435 end;
437 if c then goto _move;
439 case CollideLift(Obj, 0, 0) of
440 -1: //up
441 begin
442 Obj^.Vel.Y -= 1; // Ëèôò ââåðõ
443 if (Obj^.Vel.Y < -5) then Obj^.Vel.Y += 1;
444 end;
445 1: //down
446 begin
447 if (Obj^.Vel.Y > 5) then Obj^.Vel.Y -= 1;
448 Obj^.Vel.Y += 1; // Ãðàâèòàöèÿ èëè ëèôò âíèç
449 end;
450 0: //???
451 begin
452 if Fallable then Obj^.Vel.Y += 1; // Ãðàâèòàöèÿ
453 if (Obj^.Vel.Y > MAX_YV) then Obj^.Vel.Y -= 1;
454 end;
455 end;
457 case CollideHorLift(Obj, 0, 0) of
458 -1: //left
459 begin
460 Obj^.Vel.X -= 3;
461 if (Obj^.Vel.X < -9) then Obj^.Vel.X += 3;
462 end;
463 1: //right
464 begin
465 Obj^.Vel.X += 3;
466 if (Obj^.Vel.X > 9) then Obj^.Vel.X -= 3;
467 end;
468 // 0 is not needed here
469 end;
471 // Â âîäå?
472 inwater := CollideLiquid(Obj, 0, 0);
473 if inwater then
474 begin
475 if asProjectile then
476 begin
477 //writeln('velocity=(', Obj^.Vel.X, ',', Obj^.Vel.Y, '); acceleration=(', Obj^.Accel.X, ',', Obj^.Accel.Y, ')');
478 if (g_Obj_GetSpeedDirF(Obj, dirx, diry, speed)) then
479 begin
480 //writeln('SPEED: ', speed);
481 if (speed > 5) then
482 begin
483 speed := speed/1.4;
484 Obj^.Vel.X := round(dirx*speed);
485 Obj^.Vel.Y := round(diry*speed);
486 end;
487 end;
489 // acceleration
490 if (g_Obj_GetAccelDirF(Obj, dirx, diry, speed)) then
491 begin
492 if (speed > 5) then
493 begin
494 speed := speed/1.4;
495 Obj^.Accel.X := round(dirx*speed);
496 Obj^.Accel.Y := round(diry*speed);
497 end;
498 end;
499 end
500 else
501 begin
502 // velocity
503 xv := abs(Obj^.Vel.X)+1;
504 if (xv > 5) then Obj^.Vel.X := z_dec(Obj^.Vel.X, (xv div 2)-2);
505 yv := abs(Obj^.Vel.Y)+1;
506 if (yv > 5) then Obj^.Vel.Y := z_dec(Obj^.Vel.Y, (yv div 2)-2);
508 // acceleration
509 xv := abs(Obj^.Accel.X)+1;
510 if (xv > 5) then Obj^.Accel.X := z_dec(Obj^.Accel.X, (xv div 2)-2);
511 yv := abs(Obj^.Accel.Y)+1;
512 if (yv > 5) then Obj^.Accel.Y := z_dec(Obj^.Accel.Y, (yv div 2)-2);
513 end;
514 end;
516 // Óìåíüøàåì ïðèáàâêó ê ñêîðîñòè
517 Obj^.Accel.X := z_dec(Obj^.Accel.X, 1);
518 Obj^.Accel.Y := z_dec(Obj^.Accel.Y, 1);
520 _move:
522 xv := Obj^.Vel.X+Obj^.Accel.X;
523 yv := Obj^.Vel.Y+Obj^.Accel.Y;
525 dx := xv;
526 dy := yv;
528 result := move(Obj, dx, dy, ClimbSlopes);
530 // Áðûçãè (åñëè íóæíû)
531 if Splash then
532 begin
533 if WordBool(Result and MOVE_HITWATER) then
534 begin
535 wtx := g_Map_CollideLiquid_Texture(Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y,
536 Obj^.Rect.Width, Obj^.Rect.Height*2 div 3);
537 case wtx of
538 LongWord(TEXTURE_SPECIAL_WATER): g_Obj_Splash(Obj, 3);
539 LongWord(TEXTURE_SPECIAL_ACID1): g_Obj_Splash(Obj, 2);
540 LongWord(TEXTURE_SPECIAL_ACID2): g_Obj_Splash(Obj, 1);
541 LongWord(TEXTURE_NONE): begin end;
542 else g_Obj_Splash(Obj, 0);
543 end;
544 end;
545 end;
547 // Ìåíÿåì ñêîðîñòü è óñêîðåíèå òîëüêî ïî ÷åòíûì êàäðàì
548 if c then exit;
550 // Âðåçàëèñü â ñòåíó - ñòîï
551 if ((Result and MOVE_HITWALL) <> 0) then
552 begin
553 Obj^.Vel.X := 0;
554 Obj^.Accel.X := 0;
555 end;
557 // Âðåçàëèñü â ïîë èëè ïîòîëîê - ñòîï
558 if ((Result and (MOVE_HITCEIL or MOVE_HITLAND)) <> 0) then
559 begin
560 Obj^.Vel.Y := 0;
561 Obj^.Accel.Y := 0;
562 end;
563 end;
566 function g_Obj_Collide(Obj1, Obj2: PObj): Boolean; inline;
567 begin
568 Result := g_Collide(Obj1^.X+Obj1^.Rect.X, Obj1^.Y+Obj1^.Rect.Y,
569 Obj1^.Rect.Width, Obj1^.Rect.Height,
570 Obj2^.X+Obj2^.Rect.X, Obj2^.Y+Obj2^.Rect.Y,
571 Obj2^.Rect.Width, Obj2^.Rect.Height);
572 end;
574 function g_Obj_Collide(X, Y: Integer; Width, Height: Word; Obj: PObj): Boolean; inline;
575 begin
576 Result := g_Collide(X, Y,
577 Width, Height,
578 Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y,
579 Obj^.Rect.Width, Obj^.Rect.Height);
580 end;
582 function g_Obj_CollidePoint(X, Y: Integer; Obj: PObj): Boolean; inline;
583 begin
584 Result := g_CollidePoint(X, Y, Obj^.X+Obj^.Rect.X, Obj^.Y+Obj^.Rect.Y,
585 Obj^.Rect.Width, Obj^.Rect.Height);
586 end;
588 procedure g_Obj_Push(Obj: PObj; VelX, VelY: Integer); inline;
589 begin
590 Obj^.Vel.X := Obj^.Vel.X + VelX;
591 Obj^.Vel.Y := Obj^.Vel.Y + VelY;
592 end;
594 procedure g_Obj_PushA(Obj: PObj; Vel: Integer; Angle: SmallInt); inline;
595 var
596 s, c: Extended;
598 begin
599 SinCos(DegToRad(-Angle), s, c);
601 Obj^.Vel.X := Obj^.Vel.X + Round(Vel*c);
602 Obj^.Vel.Y := Obj^.Vel.Y + Round(Vel*s);
603 end;
605 procedure g_Obj_SetSpeed(Obj: PObj; s: Integer); inline;
606 var
607 m, vx, vy: Integer;
608 begin
609 vx := Obj^.Vel.X;
610 vy := Obj^.Vel.Y;
612 m := Max(abs(vx), abs(vy));
613 if m = 0 then
614 m := 1;
616 Obj^.Vel.X := (vx*s) div m;
617 Obj^.Vel.Y := (vy*s) div m;
618 end;
620 // `false`: zero speed
621 function g_Obj_GetSpeedDirF(Obj: PObj; var dirx, diry, speed: Double): Boolean; inline;
622 var
623 len, vx, vy: Double;
624 begin
625 if (Obj^.Vel.X = 0) and (Obj^.Vel.Y = 0) then
626 begin
627 dirx := 0;
628 diry := 0;
629 speed := 0;
630 result := false;
631 exit;
632 end;
634 vx := Obj^.Vel.X;
635 vy := Obj^.Vel.Y;
636 len := sqrt(vx*vx+vy*vy);
637 dirx := vx/len;
638 diry := vy/len;
639 speed := len;
640 result := true;
641 end;
643 // `false`: zero acceleratin
644 function g_Obj_GetAccelDirF(Obj: PObj; var dirx, diry, speed: Double): Boolean; inline;
645 var
646 len, vx, vy: Double;
647 begin
648 if (Obj^.Accel.X = 0) and (Obj^.Accel.Y = 0) then
649 begin
650 dirx := 0;
651 diry := 0;
652 speed := 0;
653 result := false;
654 exit;
655 end;
657 vx := Obj^.Accel.X;
658 vy := Obj^.Accel.Y;
659 len := sqrt(vx*vx+vy*vy);
660 dirx := vx/len;
661 diry := vy/len;
662 speed := len;
663 result := true;
664 end;
667 // Ïðèáëèæàåì a ê 0 íà b åäèíèö:
668 function z_dec (a, b: Integer): Integer; inline;
669 begin
670 if (abs(a) < b) then result := 0
671 else if (a > 0) then result := a-b
672 else if (a < 0) then result := a+b
673 else result := 0; // a = 0
674 end;
677 // Ïðèáëèæàåì a ê 0.0 íà b åäèíèö:
678 function z_fdec (a, b: Double): Double; inline;
679 begin
680 if (abs(a) < b) then result := 0.0
681 else if (a > 0.0) then result := a-b
682 else if (a < 0.0) then result := a+b
683 else result := 0.0; // a = 0.0
684 end;
687 end.