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 CollideMonsters(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
152 if gMonsters
= nil then
155 for a
:= 0 to High(gMonsters
) do
156 if gMonsters
[a
] <> nil then
157 if gMonsters
[a
].Live
and
158 gMonsters
[a
].Collide(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
^.Rect
.Y
+YInc
,
159 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
) then
166 function Blocked(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
168 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
169 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
170 PANEL_BLOCKMON
, False);
173 function g_Obj_CollideLevel(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
175 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
176 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
180 function g_Obj_CollideStep(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
182 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
183 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
187 function g_Obj_CollideWater(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
189 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
190 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
194 function g_Obj_CollideLiquid(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
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
or PANEL_ACID1
or PANEL_ACID2
, False);
201 function g_Obj_CollidePanel(Obj
: PObj
; XInc
, YInc
: Integer; PanelType
: Word): Boolean;
203 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
204 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
208 procedure g_Obj_Splash(Obj
: PObj
; Color
: Byte);
212 MaxVel
:= Max(Abs(Obj
^.Vel
.X
), Abs(Obj
^.Vel
.Y
));
213 if MaxVel
> 4 then begin
215 g_Sound_PlayExAt('SOUND_GAME_BULK1', Obj
^.X
, Obj
^.Y
)
217 g_Sound_PlayExAt('SOUND_GAME_BULK2', Obj
^.X
, Obj
^.Y
);
220 g_GFX_Water(Obj
^.X
+Obj
^.Rect
.X
+(Obj
^.Rect
.Width
div 2),
221 Obj
^.Y
+Obj
^.Rect
.Y
+(Obj
^.Rect
.Height
div 2),
222 Min(5*(Abs(Obj
^.Vel
.X
)+Abs(Obj
^.Vel
.Y
)), 50),
223 -Obj
^.Vel
.X
, -Obj
^.Vel
.Y
,
224 Obj
^.Rect
.Width
, 16, Color
);
227 function move(Obj
: PObj
; dx
, dy
: Integer; ClimbSlopes
: Boolean): Word;
233 procedure slope(s
: Integer);
238 while g_Obj_CollideLevel(Obj
, sx
, 0) and (i
< 4) do
240 Obj
^.Y
:= Obj
^.Y
+ s
;
243 Obj
^.X
:= Obj
^.X
+ sx
;
246 function movex(): Boolean;
250 // Åñëè ìîíñòðó øàãíóòü â ñòîðîíó, à òàì áëîêìîí:
251 if gMon
and not WordBool(st
and MOVE_BLOCK
) then
252 if Blocked(Obj
, sx
, 0) then
253 st
:= st
or MOVE_BLOCK
;
255 // Åñëè øàãíóòü â ñòîðîíó, à òàì ñòåíà => øàãàòü íåëüçÿ:
256 if g_Obj_CollideLevel(Obj
, sx
, 0) then
258 if ClimbSlopes
and (Abs(dy
) < 2) then
261 if (not g_Obj_CollideLevel(Obj
, sx
, -12)) // çàáèðàåìñÿ íà 12 ïèêñåëåé âëåâî/âïðàâî
262 and g_Obj_CollidePanel(Obj
, 0, 1, PANEL_WALL
or PANEL_STEP
) // òîëüêî åñëè åñòü çåìëÿ ïîä íîãàìè
268 st
:= st
or MOVE_HITWALL
;
272 st
:= st
or MOVE_HITWALL
;
274 else // Òàì ñòåíû íåò
276 if CollideLiquid(Obj
, sx
, 0) then
277 begin // Åñëè øàãíóòü â ñòîðîíó, à òàì òåïåðü æèäêîñòü
278 if not WordBool(st
and MOVE_INWATER
) then
279 st
:= st
or MOVE_HITWATER
;
281 else // Åñëè øàãíóòü â ñòîðîíó, à òàì óæå íåò æèäêîñòè
282 if WordBool(st
and MOVE_INWATER
) then
283 st
:= st
or MOVE_HITAIR
;
286 Obj
^.X
:= Obj
^.X
+ sx
;
291 function movey(): Boolean;
295 // Åñëè ìîíñòðó øàãíóòü ïî âåðòèêàëè, à òàì áëîêìîí:
296 if gMon
and not WordBool(st
and MOVE_BLOCK
) then
297 if Blocked(Obj
, 0, sy
) then
298 st
:= st
or MOVE_BLOCK
;
300 // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì ñòåíà => øàãàòü íåëüçÿ:
301 // Èëè åñëè øàãíóòü âíèç, à òàì ñòóïåíü => øàãàòü íåëüçÿ:
302 if g_Obj_CollideLevel(Obj
, 0, sy
) or
303 ((sy
> 0) and g_Obj_StayOnStep(Obj
)) then
306 st
:= st
or MOVE_HITLAND
308 st
:= st
or MOVE_HITCEIL
;
310 else // Òàì ñòåíû íåò. È ñòóïåíè ñíèçó òîæå íåò
312 if CollideLiquid(Obj
, 0, sy
) then
313 begin // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì òåïåðü æèäêîñòü
314 if not WordBool(st
and MOVE_INWATER
) then
315 st
:= st
or MOVE_HITWATER
;
317 else // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì óæå íåò æèäêîñòè
318 if WordBool(st
and MOVE_INWATER
) then
319 st
:= st
or MOVE_HITAIR
;
322 Obj
^.Y
:= Obj
^.Y
+ sy
;
331 // Îáúåêò â æèäêîñòè:
332 if CollideLiquid(Obj
, 0, 0) then
333 st
:= st
or MOVE_INWATER
;
335 // Ìîíñòð â áëîêìîíå:
337 if Blocked(Obj
, 0, 0) then
338 st
:= st
or MOVE_BLOCK
;
340 // Äâèãàòüñÿ íå íàäî:
341 if (dx
= 0) and (dy
= 0) then
347 sx
:= g_basic
.Sign(dx
);
348 sy
:= g_basic
.Sign(dy
);
363 procedure g_Obj_Init(Obj
: PObj
);
365 ZeroMemory(Obj
, SizeOf(TObj
));
368 function g_Obj_Move(Obj
: PObj
; Fallable
: Boolean; Splash
: Boolean; ClimbSlopes
: Boolean = False): Word;
370 xv
, yv
, dx
, dy
: Integer;
377 // Ëèìèòû íà ñêîðîñòü è óñêîðåíèå
378 if Obj
^.Vel
.X
< -LIMIT_VEL
then Obj
^.Vel
.X
:= -LIMIT_VEL
379 else if Obj
^.Vel
.X
> LIMIT_VEL
then Obj
^.Vel
.X
:= LIMIT_VEL
;
380 if Obj
^.Vel
.Y
< -LIMIT_VEL
then Obj
^.Vel
.Y
:= -LIMIT_VEL
381 else if Obj
^.Vel
.Y
> LIMIT_VEL
then Obj
^.Vel
.Y
:= LIMIT_VEL
;
382 if Obj
^.Accel
.X
< -LIMIT_ACCEL
then Obj
^.Accel
.X
:= -LIMIT_ACCEL
383 else if Obj
^.Accel
.X
> LIMIT_ACCEL
then Obj
^.Accel
.X
:= LIMIT_ACCEL
;
384 if Obj
^.Accel
.Y
< -LIMIT_ACCEL
then Obj
^.Accel
.Y
:= -LIMIT_ACCEL
385 else if Obj
^.Accel
.Y
> LIMIT_ACCEL
then Obj
^.Accel
.Y
:= LIMIT_ACCEL
;
387 // Âûëåòåë çà íèæíþþ ãðàíèöó êàðòû:
388 if Obj
^.Y
> gMapInfo
.Height
+128 then
390 Result
:= MOVE_FALLOUT
;
394 // Ìåíÿåì ñêîðîñòü è óñêîðåíèå òîëüêî ïî ÷åòíûì êàäðàì:
395 c
:= gTime
mod (GAME_TICK
*2) <> 0;
400 case CollideLift(Obj
, 0, 0) of
403 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
- 1; // Ëèôò ââåðõ
404 if Obj
^.Vel
.Y
< -5 then
405 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
+ 1;
410 if Obj
^.Vel
.Y
> 5 then
411 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
- 1;
412 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
+ 1; // Ãðàâèòàöèÿ èëè ëèôò âíèç
418 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
+ 1; // Ãðàâèòàöèÿ
419 if Obj
^.Vel
.Y
> MAX_YV
then
420 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
- 1;
424 case CollideHorLift(Obj
, 0, 0) of
427 Obj
^.Vel
.X
:= Obj
^.Vel
.X
- 3; // Ëèôò ââåðõ
428 if Obj
^.Vel
.X
< -9 then
429 Obj
^.Vel
.X
:= Obj
^.Vel
.X
+ 3;
434 Obj
^.Vel
.X
:= Obj
^.Vel
.X
+ 3;
435 if Obj
^.Vel
.X
> 9 then
436 Obj
^.Vel
.X
:= Obj
^.Vel
.X
- 3;
438 // 0 is not needed here
441 inwater
:= CollideLiquid(Obj
, 0, 0);
444 xv
:= Abs(Obj
^.Vel
.X
)+1;
446 Obj
^.Vel
.X
:= z_dec(Obj
^.Vel
.X
, (xv
div 2)-2);
448 yv
:= Abs(Obj
^.Vel
.Y
)+1;
450 Obj
^.Vel
.Y
:= z_dec(Obj
^.Vel
.Y
, (yv
div 2)-2);
452 xv
:= Abs(Obj
^.Accel
.X
)+1;
454 Obj
^.Accel
.X
:= z_dec(Obj
^.Accel
.X
, (xv
div 2)-2);
456 yv
:= Abs(Obj
^.Accel
.Y
)+1;
458 Obj
^.Accel
.Y
:= z_dec(Obj
^.Accel
.Y
, (yv
div 2)-2);
461 // Óìåíüøàåì ïðèáàâêó ê ñêîðîñòè:
462 Obj
^.Accel
.X
:= z_dec(Obj
^.Accel
.X
, 1);
463 Obj
^.Accel
.Y
:= z_dec(Obj
^.Accel
.Y
, 1);
467 xv
:= Obj
^.Vel
.X
+ Obj
^.Accel
.X
;
468 yv
:= Obj
^.Vel
.Y
+ Obj
^.Accel
.Y
;
473 Result
:= move(Obj
, dx
, dy
, ClimbSlopes
);
475 // Áðûçãè (åñëè íóæíû):
477 if WordBool(Result
and MOVE_HITWATER
) then
479 wtx
:= g_Map_CollideLiquid_Texture(Obj
^.X
+Obj
^.Rect
.X
,
482 Obj
^.Rect
.Height
*2 div 3);
484 TEXTURE_SPECIAL_WATER
:
485 g_Obj_Splash(Obj
, 3);
486 TEXTURE_SPECIAL_ACID1
:
487 g_Obj_Splash(Obj
, 2);
488 TEXTURE_SPECIAL_ACID2
:
489 g_Obj_Splash(Obj
, 1);
493 g_Obj_Splash(Obj
, 0);
497 // Ìåíÿåì ñêîðîñòü è óñêîðåíèå òîëüêî ïî ÷åòíûì êàäðàì:
501 // Âðåçàëèñü â ñòåíó - ñòîï:
502 if WordBool(Result
and MOVE_HITWALL
) then
508 // Âðåçàëèñü â ïîë èëè ïîòîëîê - ñòîï:
509 if WordBool(Result
and (MOVE_HITCEIL
or MOVE_HITLAND
)) then
516 function g_Obj_Collide(Obj1
, Obj2
: PObj
): Boolean;
518 Result
:= g_Collide(Obj1
^.X
+Obj1
^.Rect
.X
, Obj1
^.Y
+Obj1
^.Rect
.Y
,
519 Obj1
^.Rect
.Width
, Obj1
^.Rect
.Height
,
520 Obj2
^.X
+Obj2
^.Rect
.X
, Obj2
^.Y
+Obj2
^.Rect
.Y
,
521 Obj2
^.Rect
.Width
, Obj2
^.Rect
.Height
);
524 function g_Obj_Collide(X
, Y
: Integer; Width
, Height
: Word; Obj
: PObj
): Boolean;
526 Result
:= g_Collide(X
, Y
,
528 Obj
^.X
+Obj
^.Rect
.X
, Obj
^.Y
+Obj
^.Rect
.Y
,
529 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
);
532 function g_Obj_CollidePoint(X
, Y
: Integer; Obj
: PObj
): Boolean;
534 Result
:= g_CollidePoint(X
, Y
, Obj
^.X
+Obj
^.Rect
.X
, Obj
^.Y
+Obj
^.Rect
.Y
,
535 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
);
538 procedure g_Obj_Push(Obj
: PObj
; VelX
, VelY
: Integer);
540 Obj
^.Vel
.X
:= Obj
^.Vel
.X
+ VelX
;
541 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
+ VelY
;
544 procedure g_Obj_PushA(Obj
: PObj
; Vel
: Integer; Angle
: SmallInt);
549 SinCos(DegToRad(-Angle
), s
, c
);
551 Obj
^.Vel
.X
:= Obj
^.Vel
.X
+ Round(Vel
*c
);
552 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
+ Round(Vel
*s
);
555 procedure g_Obj_SetSpeed(Obj
: PObj
; s
: Integer);
562 m
:= Max(Abs(vx
), Abs(vy
));
566 Obj
^.Vel
.X
:= (vx
*s
) div m
;
567 Obj
^.Vel
.Y
:= (vy
*s
) div m
;
570 function z_dec(a
, b
: Integer): Integer;
572 // Ïðèáëèæàåì a ê 0 íà b åäèíèö:
585 function z_fdec(a
, b
: Double): Double;
587 // Ïðèáëèæàåì a ê 0.0 íà b åäèíèö: