1 (* Copyright (C) DooM 2D:Forever Developers
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.
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.
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/>.
16 {$INCLUDE ../shared/a_modes.inc}
48 procedure g_Obj_Init(Obj
: PObj
);
49 function g_Obj_Move(Obj
: PObj
; Fallable
: Boolean; Splash
: Boolean; ClimbSlopes
: Boolean = False): Word;
50 function g_Obj_Collide(Obj1
, Obj2
: PObj
): Boolean; overload
;
51 function g_Obj_Collide(X
, Y
: Integer; Width
, Height
: Word; Obj
: PObj
): Boolean; overload
;
52 function g_Obj_CollidePoint(X
, Y
: Integer; Obj
: PObj
): Boolean;
53 function g_Obj_CollideLevel(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
54 function g_Obj_CollideStep(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
55 function g_Obj_CollideWater(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
56 function g_Obj_CollideLiquid(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
57 function g_Obj_CollidePanel(Obj
: PObj
; XInc
, YInc
: Integer; PanelType
: Word): Boolean;
58 function g_Obj_StayOnStep(Obj
: PObj
): Boolean;
59 procedure g_Obj_Push(Obj
: PObj
; VelX
, VelY
: Integer);
60 procedure g_Obj_PushA(Obj
: PObj
; Vel
: Integer; Angle
: SmallInt);
61 procedure g_Obj_SetSpeed(Obj
: PObj
; s
: Integer);
62 function z_dec(a
, b
: Integer): Integer;
63 function z_fdec(a
, b
: Double): Double;
66 gMon
: Boolean = False;
71 g_map
, g_basic
, Math
, g_player
, g_console
, SysUtils
,
72 g_sound
, g_gfx
, MAPDEF
, g_monsters
, g_game
, BinEditor
;
74 function g_Obj_StayOnStep(Obj
: PObj
): Boolean;
76 Result
:= not g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
, Obj
^.Y
+Obj
^.Rect
.Y
+Obj
^.Rect
.Height
-1,
79 and g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
, Obj
^.Y
+Obj
^.Rect
.Y
+Obj
^.Rect
.Height
,
84 function CollideLiquid(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
86 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
^.Rect
.Y
+YInc
,
87 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
*2 div 3,
88 PANEL_WATER
or PANEL_ACID1
or PANEL_ACID2
, False);
91 function CollideLift(Obj
: PObj
; XInc
, YInc
: Integer): Integer;
93 if g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
^.Rect
.Y
+YInc
,
94 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
95 PANEL_LIFTUP
, False) then
97 else if g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
^.Rect
.Y
+YInc
,
98 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
99 PANEL_LIFTDOWN
, False) then
105 function CollideHorLift(Obj
: PObj
; XInc
, YInc
: Integer): Integer;
107 left
, right
: Boolean;
109 left
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
^.Rect
.Y
+YInc
,
110 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
111 PANEL_LIFTLEFT
, False);
112 right
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
^.Rect
.Y
+YInc
,
113 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
114 PANEL_LIFTRIGHT
, False);
115 if left
and not right
then
117 else if right
and not left
then
123 function CollidePlayers(_Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
129 if gPlayers
= nil then
132 for a
:= 0 to High(gPlayers
) do
133 if gPlayers
[a
] <> nil then
136 g_Collide(GameX
+PLAYER_RECT
.X
, GameY
+PLAYER_RECT
.Y
,
137 PLAYER_RECT
.Width
, PLAYER_RECT
.Height
,
138 _Obj
^.X
+_Obj
^.Rect
.X
+XInc
, _Obj
^.Y
+_Obj
^.Rect
.Y
+YInc
,
139 _Obj
^.Rect
.Width
, _Obj
^.Rect
.Height
) then
146 function Blocked(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
148 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
149 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
150 PANEL_BLOCKMON
, False);
153 function g_Obj_CollideLevel(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
155 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
156 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
160 function g_Obj_CollideStep(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
162 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
163 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
167 function g_Obj_CollideWater(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
169 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
170 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
174 function g_Obj_CollideLiquid(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
176 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
177 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
178 PANEL_WATER
or PANEL_ACID1
or PANEL_ACID2
, False);
181 function g_Obj_CollidePanel(Obj
: PObj
; XInc
, YInc
: Integer; PanelType
: Word): Boolean;
183 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
184 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
188 procedure g_Obj_Splash(Obj
: PObj
; Color
: Byte);
192 MaxVel
:= Max(Abs(Obj
^.Vel
.X
), Abs(Obj
^.Vel
.Y
));
193 if MaxVel
> 4 then begin
195 g_Sound_PlayExAt('SOUND_GAME_BULK1', Obj
^.X
, Obj
^.Y
)
197 g_Sound_PlayExAt('SOUND_GAME_BULK2', Obj
^.X
, Obj
^.Y
);
200 g_GFX_Water(Obj
^.X
+Obj
^.Rect
.X
+(Obj
^.Rect
.Width
div 2),
201 Obj
^.Y
+Obj
^.Rect
.Y
+(Obj
^.Rect
.Height
div 2),
202 Min(5*(Abs(Obj
^.Vel
.X
)+Abs(Obj
^.Vel
.Y
)), 50),
203 -Obj
^.Vel
.X
, -Obj
^.Vel
.Y
,
204 Obj
^.Rect
.Width
, 16, Color
);
207 function move(Obj
: PObj
; dx
, dy
: Integer; ClimbSlopes
: Boolean): Word;
213 procedure slope(s
: Integer);
218 while g_Obj_CollideLevel(Obj
, sx
, 0) and (i
< 4) do
220 Obj
^.Y
:= Obj
^.Y
+ s
;
223 Obj
^.X
:= Obj
^.X
+ sx
;
226 function movex(): Boolean;
230 // Åñëè ìîíñòðó øàãíóòü â ñòîðîíó, à òàì áëîêìîí:
231 if gMon
and not WordBool(st
and MOVE_BLOCK
) then
232 if Blocked(Obj
, sx
, 0) then
233 st
:= st
or MOVE_BLOCK
;
235 // Åñëè øàãíóòü â ñòîðîíó, à òàì ñòåíà => øàãàòü íåëüçÿ:
236 if g_Obj_CollideLevel(Obj
, sx
, 0) then
238 if ClimbSlopes
and (Abs(dy
) < 2) then
241 if (not g_Obj_CollideLevel(Obj
, sx
, -12)) // çàáèðàåìñÿ íà 12 ïèêñåëåé âëåâî/âïðàâî
242 and g_Obj_CollidePanel(Obj
, 0, 1, PANEL_WALL
or PANEL_STEP
) // òîëüêî åñëè åñòü çåìëÿ ïîä íîãàìè
248 st
:= st
or MOVE_HITWALL
;
252 st
:= st
or MOVE_HITWALL
;
254 else // Òàì ñòåíû íåò
256 if CollideLiquid(Obj
, sx
, 0) then
257 begin // Åñëè øàãíóòü â ñòîðîíó, à òàì òåïåðü æèäêîñòü
258 if not WordBool(st
and MOVE_INWATER
) then
259 st
:= st
or MOVE_HITWATER
;
261 else // Åñëè øàãíóòü â ñòîðîíó, à òàì óæå íåò æèäêîñòè
262 if WordBool(st
and MOVE_INWATER
) then
263 st
:= st
or MOVE_HITAIR
;
266 Obj
^.X
:= Obj
^.X
+ sx
;
271 function movey(): Boolean;
275 // Åñëè ìîíñòðó øàãíóòü ïî âåðòèêàëè, à òàì áëîêìîí:
276 if gMon
and not WordBool(st
and MOVE_BLOCK
) then
277 if Blocked(Obj
, 0, sy
) then
278 st
:= st
or MOVE_BLOCK
;
280 // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì ñòåíà => øàãàòü íåëüçÿ:
281 // Èëè åñëè øàãíóòü âíèç, à òàì ñòóïåíü => øàãàòü íåëüçÿ:
282 if g_Obj_CollideLevel(Obj
, 0, sy
) or
283 ((sy
> 0) and g_Obj_StayOnStep(Obj
)) then
286 st
:= st
or MOVE_HITLAND
288 st
:= st
or MOVE_HITCEIL
;
290 else // Òàì ñòåíû íåò. È ñòóïåíè ñíèçó òîæå íåò
292 if CollideLiquid(Obj
, 0, sy
) then
293 begin // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì òåïåðü æèäêîñòü
294 if not WordBool(st
and MOVE_INWATER
) then
295 st
:= st
or MOVE_HITWATER
;
297 else // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì óæå íåò æèäêîñòè
298 if WordBool(st
and MOVE_INWATER
) then
299 st
:= st
or MOVE_HITAIR
;
302 Obj
^.Y
:= Obj
^.Y
+ sy
;
311 // Îáúåêò â æèäêîñòè:
312 if CollideLiquid(Obj
, 0, 0) then
313 st
:= st
or MOVE_INWATER
;
315 // Ìîíñòð â áëîêìîíå:
317 if Blocked(Obj
, 0, 0) then
318 st
:= st
or MOVE_BLOCK
;
320 // Äâèãàòüñÿ íå íàäî:
321 if (dx
= 0) and (dy
= 0) then
327 sx
:= g_basic
.Sign(dx
);
328 sy
:= g_basic
.Sign(dy
);
343 procedure g_Obj_Init(Obj
: PObj
);
345 ZeroMemory(Obj
, SizeOf(TObj
));
348 function g_Obj_Move(Obj
: PObj
; Fallable
: Boolean; Splash
: Boolean; ClimbSlopes
: Boolean = False): Word;
350 xv
, yv
, dx
, dy
: Integer;
357 // Ëèìèòû íà ñêîðîñòü è óñêîðåíèå
358 if Obj
^.Vel
.X
< -LIMIT_VEL
then Obj
^.Vel
.X
:= -LIMIT_VEL
359 else if Obj
^.Vel
.X
> LIMIT_VEL
then Obj
^.Vel
.X
:= LIMIT_VEL
;
360 if Obj
^.Vel
.Y
< -LIMIT_VEL
then Obj
^.Vel
.Y
:= -LIMIT_VEL
361 else if Obj
^.Vel
.Y
> LIMIT_VEL
then Obj
^.Vel
.Y
:= LIMIT_VEL
;
362 if Obj
^.Accel
.X
< -LIMIT_ACCEL
then Obj
^.Accel
.X
:= -LIMIT_ACCEL
363 else if Obj
^.Accel
.X
> LIMIT_ACCEL
then Obj
^.Accel
.X
:= LIMIT_ACCEL
;
364 if Obj
^.Accel
.Y
< -LIMIT_ACCEL
then Obj
^.Accel
.Y
:= -LIMIT_ACCEL
365 else if Obj
^.Accel
.Y
> LIMIT_ACCEL
then Obj
^.Accel
.Y
:= LIMIT_ACCEL
;
367 // Âûëåòåë çà íèæíþþ ãðàíèöó êàðòû:
368 if Obj
^.Y
> gMapInfo
.Height
+128 then
370 Result
:= MOVE_FALLOUT
;
374 // Ìåíÿåì ñêîðîñòü è óñêîðåíèå òîëüêî ïî ÷åòíûì êàäðàì:
375 c
:= gTime
mod (GAME_TICK
*2) <> 0;
380 case CollideLift(Obj
, 0, 0) of
383 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
- 1; // Ëèôò ââåðõ
384 if Obj
^.Vel
.Y
< -5 then
385 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
+ 1;
390 if Obj
^.Vel
.Y
> 5 then
391 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
- 1;
392 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
+ 1; // Ãðàâèòàöèÿ èëè ëèôò âíèç
398 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
+ 1; // Ãðàâèòàöèÿ
399 if Obj
^.Vel
.Y
> MAX_YV
then
400 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
- 1;
404 case CollideHorLift(Obj
, 0, 0) of
407 Obj
^.Vel
.X
:= Obj
^.Vel
.X
- 3; // Ëèôò ââåðõ
408 if Obj
^.Vel
.X
< -9 then
409 Obj
^.Vel
.X
:= Obj
^.Vel
.X
+ 3;
414 Obj
^.Vel
.X
:= Obj
^.Vel
.X
+ 3;
415 if Obj
^.Vel
.X
> 9 then
416 Obj
^.Vel
.X
:= Obj
^.Vel
.X
- 3;
418 // 0 is not needed here
421 inwater
:= CollideLiquid(Obj
, 0, 0);
424 xv
:= Abs(Obj
^.Vel
.X
)+1;
426 Obj
^.Vel
.X
:= z_dec(Obj
^.Vel
.X
, (xv
div 2)-2);
428 yv
:= Abs(Obj
^.Vel
.Y
)+1;
430 Obj
^.Vel
.Y
:= z_dec(Obj
^.Vel
.Y
, (yv
div 2)-2);
432 xv
:= Abs(Obj
^.Accel
.X
)+1;
434 Obj
^.Accel
.X
:= z_dec(Obj
^.Accel
.X
, (xv
div 2)-2);
436 yv
:= Abs(Obj
^.Accel
.Y
)+1;
438 Obj
^.Accel
.Y
:= z_dec(Obj
^.Accel
.Y
, (yv
div 2)-2);
441 // Óìåíüøàåì ïðèáàâêó ê ñêîðîñòè:
442 Obj
^.Accel
.X
:= z_dec(Obj
^.Accel
.X
, 1);
443 Obj
^.Accel
.Y
:= z_dec(Obj
^.Accel
.Y
, 1);
447 xv
:= Obj
^.Vel
.X
+ Obj
^.Accel
.X
;
448 yv
:= Obj
^.Vel
.Y
+ Obj
^.Accel
.Y
;
453 Result
:= move(Obj
, dx
, dy
, ClimbSlopes
);
455 // Áðûçãè (åñëè íóæíû):
457 if WordBool(Result
and MOVE_HITWATER
) then
459 wtx
:= g_Map_CollideLiquid_Texture(Obj
^.X
+Obj
^.Rect
.X
,
462 Obj
^.Rect
.Height
*2 div 3);
464 TEXTURE_SPECIAL_WATER
:
465 g_Obj_Splash(Obj
, 3);
466 TEXTURE_SPECIAL_ACID1
:
467 g_Obj_Splash(Obj
, 2);
468 TEXTURE_SPECIAL_ACID2
:
469 g_Obj_Splash(Obj
, 1);
473 g_Obj_Splash(Obj
, 0);
477 // Ìåíÿåì ñêîðîñòü è óñêîðåíèå òîëüêî ïî ÷åòíûì êàäðàì:
481 // Âðåçàëèñü â ñòåíó - ñòîï:
482 if WordBool(Result
and MOVE_HITWALL
) then
488 // Âðåçàëèñü â ïîë èëè ïîòîëîê - ñòîï:
489 if WordBool(Result
and (MOVE_HITCEIL
or MOVE_HITLAND
)) then
496 function g_Obj_Collide(Obj1
, Obj2
: PObj
): Boolean;
498 Result
:= g_Collide(Obj1
^.X
+Obj1
^.Rect
.X
, Obj1
^.Y
+Obj1
^.Rect
.Y
,
499 Obj1
^.Rect
.Width
, Obj1
^.Rect
.Height
,
500 Obj2
^.X
+Obj2
^.Rect
.X
, Obj2
^.Y
+Obj2
^.Rect
.Y
,
501 Obj2
^.Rect
.Width
, Obj2
^.Rect
.Height
);
504 function g_Obj_Collide(X
, Y
: Integer; Width
, Height
: Word; Obj
: PObj
): Boolean;
506 Result
:= g_Collide(X
, Y
,
508 Obj
^.X
+Obj
^.Rect
.X
, Obj
^.Y
+Obj
^.Rect
.Y
,
509 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
);
512 function g_Obj_CollidePoint(X
, Y
: Integer; Obj
: PObj
): Boolean;
514 Result
:= g_CollidePoint(X
, Y
, Obj
^.X
+Obj
^.Rect
.X
, Obj
^.Y
+Obj
^.Rect
.Y
,
515 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
);
518 procedure g_Obj_Push(Obj
: PObj
; VelX
, VelY
: Integer);
520 Obj
^.Vel
.X
:= Obj
^.Vel
.X
+ VelX
;
521 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
+ VelY
;
524 procedure g_Obj_PushA(Obj
: PObj
; Vel
: Integer; Angle
: SmallInt);
529 SinCos(DegToRad(-Angle
), s
, c
);
531 Obj
^.Vel
.X
:= Obj
^.Vel
.X
+ Round(Vel
*c
);
532 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
+ Round(Vel
*s
);
535 procedure g_Obj_SetSpeed(Obj
: PObj
; s
: Integer);
542 m
:= Max(Abs(vx
), Abs(vy
));
546 Obj
^.Vel
.X
:= (vx
*s
) div m
;
547 Obj
^.Vel
.Y
:= (vy
*s
) div m
;
550 function z_dec(a
, b
: Integer): Integer;
552 // Ïðèáëèæàåì a ê 0 íà b åäèíèö:
565 function z_fdec(a
, b
: Double): Double;
567 // Ïðèáëèæàåì a ê 0.0 íà b åäèíèö: