32 procedure g_Obj_Init(Obj
: PObj
);
33 function g_Obj_Move(Obj
: PObj
; Fallable
: Boolean; Splash
: Boolean; ClimbSlopes
: Boolean = False): Word;
34 function g_Obj_Collide(Obj1
, Obj2
: PObj
): Boolean; overload
;
35 function g_Obj_Collide(X
, Y
: Integer; Width
, Height
: Word; Obj
: PObj
): Boolean; overload
;
36 function g_Obj_CollidePoint(X
, Y
: Integer; Obj
: PObj
): Boolean;
37 function g_Obj_CollideLevel(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
38 function g_Obj_CollideStep(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
39 function g_Obj_CollideWater(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
40 function g_Obj_CollideLiquid(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
41 function g_Obj_CollidePanel(Obj
: PObj
; XInc
, YInc
: Integer; PanelType
: Word): Boolean;
42 function g_Obj_StayOnStep(Obj
: PObj
): Boolean;
43 procedure g_Obj_Push(Obj
: PObj
; VelX
, VelY
: Integer);
44 procedure g_Obj_PushA(Obj
: PObj
; Vel
: Integer; Angle
: SmallInt);
45 procedure g_Obj_SetSpeed(Obj
: PObj
; s
: Integer);
46 function z_dec(a
, b
: Integer): Integer;
47 function z_fdec(a
, b
: Double): Double;
50 gMon
: Boolean = False;
55 g_map
, g_basic
, Math
, g_player
, g_console
, SysUtils
,
56 g_sound
, g_gfx
, MAPDEF
, g_monsters
, g_game
, BinEditor
;
58 function g_Obj_StayOnStep(Obj
: PObj
): Boolean;
60 Result
:= not g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
, Obj
^.Y
+Obj
^.Rect
.Y
+Obj
^.Rect
.Height
-1,
63 and g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
, Obj
^.Y
+Obj
^.Rect
.Y
+Obj
^.Rect
.Height
,
68 function CollideLiquid(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
70 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
^.Rect
.Y
+YInc
,
71 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
*2 div 3,
72 PANEL_WATER
or PANEL_ACID1
or PANEL_ACID2
, False);
75 function CollideLift(Obj
: PObj
; XInc
, YInc
: Integer): Integer;
77 if g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
^.Rect
.Y
+YInc
,
78 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
79 PANEL_LIFTUP
, False) then
81 else if g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
^.Rect
.Y
+YInc
,
82 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
83 PANEL_LIFTDOWN
, False) then
89 function CollideHorLift(Obj
: PObj
; XInc
, YInc
: Integer): Integer;
93 left
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
^.Rect
.Y
+YInc
,
94 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
95 PANEL_LIFTLEFT
, False);
96 right
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
^.Rect
.Y
+YInc
,
97 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
98 PANEL_LIFTRIGHT
, False);
99 if left
and not right
then
101 else if right
and not left
then
107 function CollidePlayers(_Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
113 if gPlayers
= nil then
116 for a
:= 0 to High(gPlayers
) do
117 if gPlayers
[a
] <> nil then
120 g_Collide(GameX
+PLAYER_RECT
.X
, GameY
+PLAYER_RECT
.Y
,
121 PLAYER_RECT
.Width
, PLAYER_RECT
.Height
,
122 _Obj
^.X
+_Obj
^.Rect
.X
+XInc
, _Obj
^.Y
+_Obj
^.Rect
.Y
+YInc
,
123 _Obj
^.Rect
.Width
, _Obj
^.Rect
.Height
) then
130 function CollideMonsters(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
136 if gMonsters
= nil then
139 for a
:= 0 to High(gMonsters
) do
140 if gMonsters
[a
] <> nil then
141 if gMonsters
[a
].Live
and
142 gMonsters
[a
].Collide(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
^.Rect
.Y
+YInc
,
143 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
) then
150 function Blocked(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
152 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
153 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
154 PANEL_BLOCKMON
, False);
157 function g_Obj_CollideLevel(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
159 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
160 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
164 function g_Obj_CollideStep(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
166 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
167 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
171 function g_Obj_CollideWater(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
173 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
174 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
178 function g_Obj_CollideLiquid(Obj
: PObj
; XInc
, YInc
: Integer): Boolean;
180 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
181 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
182 PANEL_WATER
or PANEL_ACID1
or PANEL_ACID2
, False);
185 function g_Obj_CollidePanel(Obj
: PObj
; XInc
, YInc
: Integer; PanelType
: Word): Boolean;
187 Result
:= g_Map_CollidePanel(Obj
^.X
+Obj
^.Rect
.X
+XInc
, Obj
^.Y
+Obj
.Rect
.Y
+YInc
,
188 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
,
192 procedure g_Obj_Splash(Obj
: PObj
; Color
: Byte);
196 MaxVel
:= Max(Abs(Obj
^.Vel
.X
), Abs(Obj
^.Vel
.Y
));
197 if MaxVel
> 4 then begin
199 g_Sound_PlayExAt('SOUND_GAME_BULK1', Obj
^.X
, Obj
^.Y
)
201 g_Sound_PlayExAt('SOUND_GAME_BULK2', Obj
^.X
, Obj
^.Y
);
204 g_GFX_Water(Obj
^.X
+Obj
^.Rect
.X
+(Obj
^.Rect
.Width
div 2),
205 Obj
^.Y
+Obj
^.Rect
.Y
+(Obj
^.Rect
.Height
div 2),
206 Min(5*(Abs(Obj
^.Vel
.X
)+Abs(Obj
^.Vel
.Y
)), 50),
207 -Obj
^.Vel
.X
, -Obj
^.Vel
.Y
,
208 Obj
^.Rect
.Width
, 16, Color
);
211 function move(Obj
: PObj
; dx
, dy
: Integer; ClimbSlopes
: Boolean): Word;
217 procedure slope(s
: Integer);
222 while g_Obj_CollideLevel(Obj
, sx
, 0) and (i
< 4) do
224 Obj
^.Y
:= Obj
^.Y
+ s
;
227 Obj
^.X
:= Obj
^.X
+ sx
;
230 function movex(): Boolean;
234 // Åñëè ìîíñòðó øàãíóòü â ñòîðîíó, à òàì áëîêìîí:
235 if gMon
and not WordBool(st
and MOVE_BLOCK
) then
236 if Blocked(Obj
, sx
, 0) then
237 st
:= st
or MOVE_BLOCK
;
239 // Åñëè øàãíóòü â ñòîðîíó, à òàì ñòåíà => øàãàòü íåëüçÿ:
240 if g_Obj_CollideLevel(Obj
, sx
, 0) then
242 if ClimbSlopes
and (Abs(dy
) < 2) then
245 if (not g_Obj_CollideLevel(Obj
, sx
, -12)) // çàáèðàåìñÿ íà 12 ïèêñåëåé âëåâî/âïðàâî
246 and g_Obj_CollidePanel(Obj
, 0, 1, PANEL_WALL
or PANEL_STEP
) // òîëüêî åñëè åñòü çåìëÿ ïîä íîãàìè
252 st
:= st
or MOVE_HITWALL
;
256 st
:= st
or MOVE_HITWALL
;
258 else // Òàì ñòåíû íåò
260 if CollideLiquid(Obj
, sx
, 0) then
261 begin // Åñëè øàãíóòü â ñòîðîíó, à òàì òåïåðü æèäêîñòü
262 if not WordBool(st
and MOVE_INWATER
) then
263 st
:= st
or MOVE_HITWATER
;
265 else // Åñëè øàãíóòü â ñòîðîíó, à òàì óæå íåò æèäêîñòè
266 if WordBool(st
and MOVE_INWATER
) then
267 st
:= st
or MOVE_HITAIR
;
270 Obj
^.X
:= Obj
^.X
+ sx
;
275 function movey(): Boolean;
279 // Åñëè ìîíñòðó øàãíóòü ïî âåðòèêàëè, à òàì áëîêìîí:
280 if gMon
and not WordBool(st
and MOVE_BLOCK
) then
281 if Blocked(Obj
, 0, sy
) then
282 st
:= st
or MOVE_BLOCK
;
284 // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì ñòåíà => øàãàòü íåëüçÿ:
285 // Èëè åñëè øàãíóòü âíèç, à òàì ñòóïåíü => øàãàòü íåëüçÿ:
286 if g_Obj_CollideLevel(Obj
, 0, sy
) or
287 ((sy
> 0) and g_Obj_StayOnStep(Obj
)) then
290 st
:= st
or MOVE_HITLAND
292 st
:= st
or MOVE_HITCEIL
;
294 else // Òàì ñòåíû íåò. È ñòóïåíè ñíèçó òîæå íåò
296 if CollideLiquid(Obj
, 0, sy
) then
297 begin // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì òåïåðü æèäêîñòü
298 if not WordBool(st
and MOVE_INWATER
) then
299 st
:= st
or MOVE_HITWATER
;
301 else // Åñëè øàãíóòü â ïî âåðòèêàëè, à òàì óæå íåò æèäêîñòè
302 if WordBool(st
and MOVE_INWATER
) then
303 st
:= st
or MOVE_HITAIR
;
306 Obj
^.Y
:= Obj
^.Y
+ sy
;
315 // Îáúåêò â æèäêîñòè:
316 if CollideLiquid(Obj
, 0, 0) then
317 st
:= st
or MOVE_INWATER
;
319 // Ìîíñòð â áëîêìîíå:
321 if Blocked(Obj
, 0, 0) then
322 st
:= st
or MOVE_BLOCK
;
324 // Äâèãàòüñÿ íå íàäî:
325 if (dx
= 0) and (dy
= 0) then
331 sx
:= g_basic
.Sign(dx
);
332 sy
:= g_basic
.Sign(dy
);
347 procedure g_Obj_Init(Obj
: PObj
);
349 ZeroMemory(Obj
, SizeOf(TObj
));
352 function g_Obj_Move(Obj
: PObj
; Fallable
: Boolean; Splash
: Boolean; ClimbSlopes
: Boolean = False): Word;
354 xv
, yv
, dx
, dy
: Integer;
361 // Ëèìèòû íà ñêîðîñòü è óñêîðåíèå
362 if Obj
^.Vel
.X
< -LIMIT_VEL
then Obj
^.Vel
.X
:= -LIMIT_VEL
363 else if Obj
^.Vel
.X
> LIMIT_VEL
then Obj
^.Vel
.X
:= LIMIT_VEL
;
364 if Obj
^.Vel
.Y
< -LIMIT_VEL
then Obj
^.Vel
.Y
:= -LIMIT_VEL
365 else if Obj
^.Vel
.Y
> LIMIT_VEL
then Obj
^.Vel
.Y
:= LIMIT_VEL
;
366 if Obj
^.Accel
.X
< -LIMIT_ACCEL
then Obj
^.Accel
.X
:= -LIMIT_ACCEL
367 else if Obj
^.Accel
.X
> LIMIT_ACCEL
then Obj
^.Accel
.X
:= LIMIT_ACCEL
;
368 if Obj
^.Accel
.Y
< -LIMIT_ACCEL
then Obj
^.Accel
.Y
:= -LIMIT_ACCEL
369 else if Obj
^.Accel
.Y
> LIMIT_ACCEL
then Obj
^.Accel
.Y
:= LIMIT_ACCEL
;
371 // Âûëåòåë çà íèæíþþ ãðàíèöó êàðòû:
372 if Obj
^.Y
> gMapInfo
.Height
+128 then
374 Result
:= MOVE_FALLOUT
;
378 // Ìåíÿåì ñêîðîñòü è óñêîðåíèå òîëüêî ïî ÷åòíûì êàäðàì:
379 c
:= gTime
mod (GAME_TICK
*2) <> 0;
384 case CollideLift(Obj
, 0, 0) of
387 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
- 1; // Ëèôò ââåðõ
388 if Obj
^.Vel
.Y
< -5 then
389 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
+ 1;
394 if Obj
^.Vel
.Y
> 5 then
395 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
- 1;
396 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
+ 1; // Ãðàâèòàöèÿ èëè ëèôò âíèç
402 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
+ 1; // Ãðàâèòàöèÿ
403 if Obj
^.Vel
.Y
> MAX_YV
then
404 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
- 1;
408 case CollideHorLift(Obj
, 0, 0) of
411 Obj
^.Vel
.X
:= Obj
^.Vel
.X
- 3; // Ëèôò ââåðõ
412 if Obj
^.Vel
.X
< -9 then
413 Obj
^.Vel
.X
:= Obj
^.Vel
.X
+ 3;
418 Obj
^.Vel
.X
:= Obj
^.Vel
.X
+ 3;
419 if Obj
^.Vel
.X
> 9 then
420 Obj
^.Vel
.X
:= Obj
^.Vel
.X
- 3;
422 // 0 is not needed here
425 inwater
:= CollideLiquid(Obj
, 0, 0);
428 xv
:= Abs(Obj
^.Vel
.X
)+1;
430 Obj
^.Vel
.X
:= z_dec(Obj
^.Vel
.X
, (xv
div 2)-2);
432 yv
:= Abs(Obj
^.Vel
.Y
)+1;
434 Obj
^.Vel
.Y
:= z_dec(Obj
^.Vel
.Y
, (yv
div 2)-2);
436 xv
:= Abs(Obj
^.Accel
.X
)+1;
438 Obj
^.Accel
.X
:= z_dec(Obj
^.Accel
.X
, (xv
div 2)-2);
440 yv
:= Abs(Obj
^.Accel
.Y
)+1;
442 Obj
^.Accel
.Y
:= z_dec(Obj
^.Accel
.Y
, (yv
div 2)-2);
445 // Óìåíüøàåì ïðèáàâêó ê ñêîðîñòè:
446 Obj
^.Accel
.X
:= z_dec(Obj
^.Accel
.X
, 1);
447 Obj
^.Accel
.Y
:= z_dec(Obj
^.Accel
.Y
, 1);
451 xv
:= Obj
^.Vel
.X
+ Obj
^.Accel
.X
;
452 yv
:= Obj
^.Vel
.Y
+ Obj
^.Accel
.Y
;
457 Result
:= move(Obj
, dx
, dy
, ClimbSlopes
);
459 // Áðûçãè (åñëè íóæíû):
461 if WordBool(Result
and MOVE_HITWATER
) then
463 wtx
:= g_Map_CollideLiquid_Texture(Obj
^.X
+Obj
^.Rect
.X
,
466 Obj
^.Rect
.Height
*2 div 3);
468 TEXTURE_SPECIAL_WATER
:
469 g_Obj_Splash(Obj
, 3);
470 TEXTURE_SPECIAL_ACID1
:
471 g_Obj_Splash(Obj
, 2);
472 TEXTURE_SPECIAL_ACID2
:
473 g_Obj_Splash(Obj
, 1);
477 g_Obj_Splash(Obj
, 0);
481 // Ìåíÿåì ñêîðîñòü è óñêîðåíèå òîëüêî ïî ÷åòíûì êàäðàì:
485 // Âðåçàëèñü â ñòåíó - ñòîï:
486 if WordBool(Result
and MOVE_HITWALL
) then
492 // Âðåçàëèñü â ïîë èëè ïîòîëîê - ñòîï:
493 if WordBool(Result
and (MOVE_HITCEIL
or MOVE_HITLAND
)) then
500 function g_Obj_Collide(Obj1
, Obj2
: PObj
): Boolean;
502 Result
:= g_Collide(Obj1
^.X
+Obj1
^.Rect
.X
, Obj1
^.Y
+Obj1
^.Rect
.Y
,
503 Obj1
^.Rect
.Width
, Obj1
^.Rect
.Height
,
504 Obj2
^.X
+Obj2
^.Rect
.X
, Obj2
^.Y
+Obj2
^.Rect
.Y
,
505 Obj2
^.Rect
.Width
, Obj2
^.Rect
.Height
);
508 function g_Obj_Collide(X
, Y
: Integer; Width
, Height
: Word; Obj
: PObj
): Boolean;
510 Result
:= g_Collide(X
, Y
,
512 Obj
^.X
+Obj
^.Rect
.X
, Obj
^.Y
+Obj
^.Rect
.Y
,
513 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
);
516 function g_Obj_CollidePoint(X
, Y
: Integer; Obj
: PObj
): Boolean;
518 Result
:= g_CollidePoint(X
, Y
, Obj
^.X
+Obj
^.Rect
.X
, Obj
^.Y
+Obj
^.Rect
.Y
,
519 Obj
^.Rect
.Width
, Obj
^.Rect
.Height
);
522 procedure g_Obj_Push(Obj
: PObj
; VelX
, VelY
: Integer);
524 Obj
^.Vel
.X
:= Obj
^.Vel
.X
+ VelX
;
525 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
+ VelY
;
528 procedure g_Obj_PushA(Obj
: PObj
; Vel
: Integer; Angle
: SmallInt);
533 SinCos(DegToRad(-Angle
), s
, c
);
535 Obj
^.Vel
.X
:= Obj
^.Vel
.X
+ Round(Vel
*c
);
536 Obj
^.Vel
.Y
:= Obj
^.Vel
.Y
+ Round(Vel
*s
);
539 procedure g_Obj_SetSpeed(Obj
: PObj
; s
: Integer);
546 m
:= Max(Abs(vx
), Abs(vy
));
550 Obj
^.Vel
.X
:= (vx
*s
) div m
;
551 Obj
^.Vel
.Y
:= (vy
*s
) div m
;
554 function z_dec(a
, b
: Integer): Integer;
556 // Ïðèáëèæàåì a ê 0 íà b åäèíèö:
569 function z_fdec(a
, b
: Double): Double;
571 // Ïðèáëèæàåì a ê 0.0 íà b åäèíèö: