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}
17 {.$DEFINE HAS_COLLIDE_BITMAP}
39 MARK_BLOCKED
= MARK_WALL
+ MARK_DOOR
;
40 MARK_LIQUID
= MARK_WATER
+ MARK_ACID
;
41 MARK_LIFT
= MARK_LIFTDOWN
+ MARK_LIFTUP
+ MARK_LIFTLEFT
+ MARK_LIFTRIGHT
;
43 procedure g_GFX_Init();
44 procedure g_GFX_Free();
46 procedure g_GFX_Blood(fX
, fY
: Integer; Count
: Word; vx
, vy
: Integer;
47 DevX
, DevY
: Word; CR
, CG
, CB
: Byte; Kind
: Byte = BLOOD_NORMAL
);
48 procedure g_GFX_Spark(fX
, fY
: Integer; Count
: Word; Angle
: SmallInt; DevX
, DevY
: Byte);
49 procedure g_GFX_Water(fX
, fY
: Integer; Count
: Word; fVelX
, fVelY
: Single; DevX
, DevY
, Color
: Byte);
50 procedure g_GFX_SimpleWater(fX
, fY
: Integer; Count
: Word; fVelX
, fVelY
: Single; DefColor
, CR
, CG
, CB
: Byte);
51 procedure g_GFX_Bubbles(fX
, fY
: Integer; Count
: Word; DevX
, DevY
: Byte);
52 procedure g_GFX_SetMax(Count
: Integer);
53 function g_GFX_GetMax(): Integer;
55 procedure g_GFX_OnceAnim(X
, Y
: Integer; Anim
: TAnimation
; AnimType
: Byte = 0);
57 procedure g_Mark(x
, y
, Width
, Height
: Integer; t
: Byte; st
: Boolean);
59 procedure g_GFX_Update();
60 procedure g_GFX_Draw();
63 {$IF DEFINED(HAS_COLLIDE_BITMAP)}
65 gCollideMap
: Array of Array of Byte;
72 g_map
, g_basic
, Math
, e_graphics
, GL
, GLExt
,
73 g_options
, g_console
, SysUtils
, g_triggers
, MAPDEF
,
74 g_game
, g_language
, g_net
;
77 PParticle
= ^TParticle
;
81 AccelX
, AccelY
: Single;
82 Red
, Green
, Blue
: Byte;
87 offsetX
, offsetY
: ShortInt;
93 Animation
: TAnimation
;
106 Particles
: Array of TParticle
;
107 OnceAnims
: Array of TOnceAnim
;
108 MaxParticles
: Integer;
109 CurrentParticle
: Integer;
112 function isBlockedAt (x
, y
: Integer; w
: Integer=1; h
: Integer=1): Boolean; inline;
114 result
:= g_Map_CollidePanel(x
, y
, w
, h
, (PANEL_WALL
or PANEL_CLOSEDOOR
or PANEL_STEP
));
119 function isWallAt (x
, y
: Integer; w
: Integer=1; h
: Integer=1): Boolean; inline;
121 result
:= g_Map_CollidePanel(x
, y
, w
, h
, (PANEL_WALL
or PANEL_STEP
));
125 function isLiftUpAt (x
, y
: Integer; w
: Integer=1; h
: Integer=1): Boolean; inline;
127 result
:= g_Map_CollidePanel(x
, y
, w
, h
, PANEL_LIFTUP
);
130 function isLiftDownAt (x
, y
: Integer; w
: Integer=1; h
: Integer=1): Boolean; inline;
132 result
:= g_Map_CollidePanel(x
, y
, w
, h
, PANEL_LIFTDOWN
);
135 function isLiftLeftAt (x
, y
: Integer; w
: Integer=1; h
: Integer=1): Boolean; inline;
137 result
:= g_Map_CollidePanel(x
, y
, w
, h
, PANEL_LIFTLEFT
);
140 function isLiftRightAt (x
, y
: Integer; w
: Integer=1; h
: Integer=1): Boolean; inline;
142 result
:= g_Map_CollidePanel(x
, y
, w
, h
, PANEL_LIFTRIGHT
);
146 function isLiquidAt (x
, y
: Integer; w
: Integer=1; h
: Integer=1): Boolean; inline;
148 result
:= g_Map_CollidePanel(x
, y
, w
, h
, (PANEL_WATER
or PANEL_ACID1
or PANEL_ACID2
));
152 function isAnythingAt (x
, y
: Integer; w
: Integer=1; h
: Integer=1): Boolean; inline;
154 result
:= g_Map_CollidePanel(x
, y
, w
, h
, (PANEL_WALL
or PANEL_CLOSEDOOR
or PANEL_OPENDOOR
or PANEL_WATER
or PANEL_ACID1
or PANEL_ACID2
or PANEL_STEP
or PANEL_LIFTUP
or PANEL_LIFTDOWN
or PANEL_LIFTLEFT
or PANEL_LIFTRIGHT
));
158 procedure g_Mark(x
, y
, Width
, Height
: Integer; t
: Byte; st
: Boolean);
159 {$IF DEFINED(HAS_COLLIDE_BITMAP)}
161 yy
, y2
, xx
, x2
: Integer;
164 {$IF DEFINED(HAS_COLLIDE_BITMAP)}
176 Height
:= Height
+ y
;
183 if x
> gMapInfo
.Width
then
185 if y
> gMapInfo
.Height
then
188 y2
:= y
+ Height
- 1;
189 if y2
> gMapInfo
.Height
then
190 y2
:= gMapInfo
.Height
;
193 if x2
> gMapInfo
.Width
then
194 x2
:= gMapInfo
.Width
;
197 begin // Óñòàíîâèòü ïðèçíàê
200 gCollideMap
[yy
][xx
] := gCollideMap
[yy
][xx
] or t
;
203 begin // Óáðàòü ïðèçíàê
207 gCollideMap
[yy
][xx
] := gCollideMap
[yy
][xx
] and t
;
212 procedure CreateCollideMap();
213 {$IF DEFINED(HAS_COLLIDE_BITMAP)}
218 {$IF DEFINED(HAS_COLLIDE_BITMAP)}
219 g_Game_SetLoadingText(_lc
[I_LOAD_COLLIDE_MAP
]+' 1/6', 0, False);
220 SetLength(gCollideMap
, gMapInfo
.Height
+1);
221 for a
:= 0 to High(gCollideMap
) do
222 SetLength(gCollideMap
[a
], gMapInfo
.Width
+1);
224 if gWater
<> nil then
226 g_Game_SetLoadingText(_lc
[I_LOAD_COLLIDE_MAP
]+' 2/6', 0, True);
227 for a
:= 0 to High(gWater
) do
229 g_Mark(X
, Y
, Width
, Height
, MARK_WATER
, True);
232 if gAcid1
<> nil then
234 g_Game_SetLoadingText(_lc
[I_LOAD_COLLIDE_MAP
]+' 3/6', 0, True);
235 for a
:= 0 to High(gAcid1
) do
237 g_Mark(X
, Y
, Width
, Height
, MARK_ACID
, True);
240 if gAcid2
<> nil then
242 g_Game_SetLoadingText(_lc
[I_LOAD_COLLIDE_MAP
]+' 4/6', 0, True);
243 for a
:= 0 to High(gAcid2
) do
245 g_Mark(X
, Y
, Width
, Height
, MARK_ACID
, True);
248 if gLifts
<> nil then
250 g_Game_SetLoadingText(_lc
[I_LOAD_COLLIDE_MAP
]+' 5/6', 0, True);
251 for a
:= 0 to High(gLifts
) do
254 g_Mark(X
, Y
, Width
, Height
, MARK_LIFT
, False);
257 g_Mark(X
, Y
, Width
, Height
, MARK_LIFTUP
, True)
258 else if LiftType
= 1 then
259 g_Mark(X
, Y
, Width
, Height
, MARK_LIFTDOWN
, True)
260 else if LiftType
= 2 then
261 g_Mark(X
, Y
, Width
, Height
, MARK_LIFTLEFT
, True)
262 else if LiftType
= 3 then
263 g_Mark(X
, Y
, Width
, Height
, MARK_LIFTRIGHT
, True)
267 if gWalls
<> nil then
269 g_Game_SetLoadingText(_lc
[I_LOAD_COLLIDE_MAP
]+' 6/6', 0, True);
270 for a
:= 0 to High(gWalls
) do
272 if gWalls
[a
].Door
then
275 if gWalls
[a
].Enabled
then
277 g_Mark(X
, Y
, Width
, Height
, MARK_DOOR
, True)
278 else // Îòêðûòàÿ äâåðü:
279 if gWalls
[a
].Enabled
then
281 g_Mark(X
, Y
, Width
, Height
, MARK_DOOR
, False);
285 g_Mark(X
, Y
, Width
, Height
, MARK_WALL
, True);
291 procedure g_GFX_Init();
296 procedure g_GFX_Free();
301 SetLength(Particles
, MaxParticles
);
302 CurrentParticle
:= 0;
304 if OnceAnims
<> nil then
306 for a
:= 0 to High(OnceAnims
) do
307 OnceAnims
[a
].Animation
.Free();
312 {$IF DEFINED(HAS_COLLIDE_BITMAP)}
318 procedure CorrectOffsets(id
: Integer);
319 {$IF not DEFINED(HAS_COLLIDE_BITMAP)}
324 {$IF DEFINED(HAS_COLLIDE_BITMAP)}
325 with Particles
[id
] do
327 if (X
>= 0) and (Y
> 0) and
328 (Y
< Length(gCollideMap
)) and (X
< Length(gCollideMap
[0])) and
329 (ByteBool(gCollideMap
[Y
-1, X
] and MARK_BLOCKED
)) then
330 offsetY
:= 1 // Ñòåíà ñâåðõó
334 if (X
> 0) and (Y
>= 0) and
335 (Y
< Length(gCollideMap
)) and (X
< Length(gCollideMap
[0])) and
336 (ByteBool(gCollideMap
[Y
, X
-1] and MARK_BLOCKED
)) then
337 offsetX
:= 1 // Ñòåíà ñëåâà
342 part
:= @Particles
[id
];
345 // check for upper wall
346 if isBlockedAt(part
.X
, part
.Y
-1) then part
.offsetY
:= 1;
347 // check for left wall
348 if isBlockedAt(part
.X
-1, part
.Y
) then part
.offsetX
:= 1;
353 procedure g_GFX_SparkVel (fX
, fY
: Integer; Count
: Word; VX
, VY
: Integer; DevX
, DevY
: Byte);
360 l
:= Length(Particles
);
362 if Count
> l
then Count
:= l
;
369 for a
:= 1 to Count
do
371 with Particles
[CurrentParticle
] do
373 X
:= fX
-DevX1
+Random(DevX2
);
374 Y
:= fY
-DevY1
+Random(DevY2
);
376 VelX
:= VX
+ (Random
-Random
)*3;
377 VelY
:= VY
+ (Random
-Random
)*3;
385 AccelX
:= -Sign(VelX
)*Random
/100;
389 Green
:= 100+Random(155);
393 State
:= STATE_NORMAL
;
395 LiveTime
:= 30+Random(60);
396 ParticleType
:= PARTICLE_SPARK
;
398 CorrectOffsets(CurrentParticle
);
401 if CurrentParticle
+2 > MaxParticles
then
404 CurrentParticle
:= CurrentParticle
+1;
409 procedure g_GFX_Blood(fX
, fY
: Integer; Count
: Word; vx
, vy
: Integer;
410 DevX
, DevY
: Word; CR
, CG
, CB
: Byte; Kind
: Byte = BLOOD_NORMAL
);
419 if Kind
= BLOOD_SPARKS
then
421 g_GFX_SparkVel(fX
, fY
, 2 + Random(2), -VX
div 2, -VY
div 2, DevX
, DevY
);
424 l
:= Length(Particles
);
435 for a
:= 1 to Count
do
437 with Particles
[CurrentParticle
] do
439 X
:= fX
- DevX1
+ Random(DevX2
);
440 Y
:= fY
- DevY1
+ Random(DevY2
);
443 if (X < 0) or (X > gMapInfo.Width-1) or
444 (Y < 0) or (Y > gMapInfo.Height-1) or
445 ByteBool(gCollideMap[Y, X] and MARK_WALL) then
448 if isWallAt(X
, Y
) then continue
;
450 VelX
:= vx
+ (Random
-Random
)*3;
451 VelY
:= vy
+ (Random
-Random
)*3;
459 AccelX
:= -Sign(VelX
)*Random
/100;
462 CRnd
:= 20*Random(6);
465 CC
:= CR
+ CRnd
- 50;
466 if CC
< 0 then CC
:= 0;
467 if CC
> 255 then CC
:= 255;
473 CC
:= CG
+ CRnd
- 50;
474 if CC
< 0 then CC
:= 0;
475 if CC
> 255 then CC
:= 255;
481 CC
:= CB
+ CRnd
- 50;
482 if CC
< 0 then CC
:= 0;
483 if CC
> 255 then CC
:= 255;
490 State
:= STATE_NORMAL
;
492 LiveTime
:= 120+Random(40);
493 ParticleType
:= PARTICLE_BLOOD
;
495 CorrectOffsets(CurrentParticle
);
498 if CurrentParticle
>= MaxParticles
-1 then
501 CurrentParticle
:= CurrentParticle
+1;
506 procedure g_GFX_Spark(fX
, fY
: Integer; Count
: Word; Angle
: SmallInt; DevX
, DevY
: Byte);
512 BaseVelX
, BaseVelY
: Single;
515 l
:= Length(Particles
);
521 Angle
:= 360 - Angle
;
528 b
:= DegToRad(Angle
);
530 BaseVelY
:= 1.6*sin(b
);
531 if Abs(BaseVelX
) < 0.01 then
533 if Abs(BaseVelY
) < 0.01 then
535 for a
:= 1 to Count
do
537 with Particles
[CurrentParticle
] do
539 X
:= fX
-DevX1
+Random(DevX2
);
540 Y
:= fY
-DevY1
+Random(DevY2
);
542 VelX
:= BaseVelX
*Random
;
543 VelY
:= BaseVelY
-Random
;
548 Green
:= 100+Random(155);
552 State
:= STATE_NORMAL
;
554 LiveTime
:= 30+Random(60);
555 ParticleType
:= PARTICLE_SPARK
;
557 CorrectOffsets(CurrentParticle
);
560 if CurrentParticle
+2 > MaxParticles
then
563 CurrentParticle
:= CurrentParticle
+1;
567 procedure g_GFX_Water(fX
, fY
: Integer; Count
: Word; fVelX
, fVelY
: Single; DevX
, DevY
, Color
: Byte);
574 l
:= Length(Particles
);
580 if Abs(fVelX
) < 3.0 then
581 fVelX
:= 3.0 - 6.0*Random
;
588 for a
:= 1 to Count
do
590 with Particles
[CurrentParticle
] do
592 X
:= fX
-DevX1
+Random(DevX2
);
593 Y
:= fY
-DevY1
+Random(DevY2
);
595 if Abs(fVelX
) < 0.5 then
596 VelX
:= 1.0 - 2.0*Random
598 VelX
:= fVelX
*Random
;
599 if Random(10) < 7 then
601 VelY
:= fVelY
*Random
;
608 Red
:= 155 + Random(9)*10;
609 Green
:= Trunc(150*Random
);
614 Red
:= Trunc(150*Random
);
615 Green
:= 175 + Random(9)*10;
620 Red
:= Trunc(200*Random
);
622 Blue
:= 175 + Random(9)*10;
626 Red
:= 90 + Random(12)*10;
634 State
:= STATE_NORMAL
;
636 LiveTime
:= 60+Random(60);
637 ParticleType
:= PARTICLE_WATER
;
639 CorrectOffsets(CurrentParticle
);
642 if CurrentParticle
+2 > MaxParticles
then
645 CurrentParticle
:= CurrentParticle
+1;
649 procedure g_GFX_SimpleWater(fX
, fY
: Integer; Count
: Word; fVelX
, fVelY
: Single; DefColor
, CR
, CG
, CB
: Byte);
654 l
:= Length(Particles
);
660 for a
:= 1 to Count
do
662 with Particles
[CurrentParticle
] do
675 Red
:= 155 + Random(9)*10;
676 Green
:= Trunc(150*Random
);
681 Red
:= Trunc(150*Random
);
682 Green
:= 175 + Random(9)*10;
687 Red
:= Trunc(200*Random
);
689 Blue
:= 175 + Random(9)*10;
691 4: // Ñâîé öâåò, ñâåòëåå
693 Red
:= 20 + Random(19)*10;
696 Red
:= Min(Red
+ CR
, 255);
697 Green
:= Min(Green
+ CG
, 255);
698 Blue
:= Min(Blue
+ CB
, 255);
700 5: // Ñâîé öâåò, òåìíåå
702 Red
:= 20 + Random(19)*10;
705 Red
:= Max(CR
- Red
, 0);
706 Green
:= Max(CG
- Green
, 0);
707 Blue
:= Max(CB
- Blue
, 0);
711 Red
:= 90 + Random(12)*10;
719 State
:= STATE_NORMAL
;
721 LiveTime
:= 60+Random(60);
722 ParticleType
:= PARTICLE_WATER
;
724 CorrectOffsets(CurrentParticle
);
727 if CurrentParticle
+2 > MaxParticles
then
730 CurrentParticle
:= CurrentParticle
+1;
734 procedure g_GFX_Bubbles(fX
, fY
: Integer; Count
: Word; DevX
, DevY
: Byte);
741 l
:= Length(Particles
);
752 for a
:= 1 to Count
do
754 with Particles
[CurrentParticle
] do
756 X
:= fX
-DevX1
+Random(DevX2
);
757 Y
:= fY
-DevY1
+Random(DevY2
);
759 if (X
>= gMapInfo
.Width
) or (X
<= 0) or
760 (Y
>= gMapInfo
.Height
) or (Y
<= 0) then
763 if not isLiquidAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
776 State
:= STATE_NORMAL
;
779 ParticleType
:= PARTICLE_BUBBLES
;
781 CorrectOffsets(CurrentParticle
);
784 if CurrentParticle
+2 > MaxParticles
then
787 CurrentParticle
:= CurrentParticle
+1;
791 procedure g_GFX_SetMax(Count
: Integer);
793 if Count
> 50000 then
796 SetLength(Particles
, Count
);
797 MaxParticles
:= Count
;
798 if CurrentParticle
>= Count
then
799 CurrentParticle
:= 0;
802 function g_GFX_GetMax(): Integer;
804 Result
:= MaxParticles
;
807 function FindOnceAnim
: DWORD
;
811 if OnceAnims
<> nil then
812 for i
:= 0 to High(OnceAnims
) do
813 if OnceAnims
[i
].Animation
= nil then
819 if OnceAnims
= nil then
821 SetLength(OnceAnims
, 16);
826 Result
:= High(OnceAnims
) + 1;
827 SetLength(OnceAnims
, Length(OnceAnims
) + 16);
831 procedure g_GFX_OnceAnim(X
, Y
: Integer; Anim
: TAnimation
; AnimType
: Byte = 0);
838 find_id
:= FindOnceAnim();
840 OnceAnims
[find_id
].AnimType
:= AnimType
;
841 OnceAnims
[find_id
].Animation
:= TAnimation
.Create(Anim
.FramesID
, Anim
.Loop
, Anim
.Speed
);
842 OnceAnims
[find_id
].Animation
.Blending
:= Anim
.Blending
;
843 OnceAnims
[find_id
].Animation
.Alpha
:= Anim
.Alpha
;
844 OnceAnims
[find_id
].X
:= X
;
845 OnceAnims
[find_id
].Y
:= Y
;
848 procedure g_GFX_Update();
857 if Particles
<> nil then
860 h
:= gMapInfo
.Height
;
862 len
:= High(Particles
);
865 if Particles
[a
].State
<> 0 then
868 if Time
= LiveTime
then
870 if (X
+1 >= w
) or (Y
+1 >= h
) or (X
<= 0) or (Y
<= 0) then
872 if State
= STATE_FREE
then
880 if (State
= STATE_STICK
) then
882 if (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
883 (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) and
884 (not ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)) and
885 (not ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED))
888 if (not isBlockedAt(X
, Y
-1)) and
889 (not isBlockedAt(X
, Y
+1)) and
890 (not isBlockedAt(X
-1, Y
)) and
891 (not isBlockedAt(X
+1, Y
))
893 begin // Îòëèïëà - êàïàåò
896 State
:= STATE_NORMAL
;
899 if Random(200) = 100 then
900 begin // Ïðèëåïëåíà - íî âîçìîæíî ñòåêàåò
906 if not isBlockedAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)} then
908 if isLiftUpAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_LIFTUP)} then
910 if VelY
> -4-Random(3) then
912 if Abs(VelX
) > 0.1 then
913 VelX
:= VelX
- VelX
/10.0;
914 VelX
:= VelX
+ (Random
-Random
)*0.2;
917 if isLiftLeftAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT)} then
919 if VelX
> -8-Random(3) then
923 if isLiftRightAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT)} then
924 begin // Ïîòîê âïðàâî
925 if VelX
< 8+Random(3) then
934 if (Abs(VelX
) < 0.1) and (Abs(VelY
) < 0.1) then
935 if (State
<> STATE_STICK
) and
936 (not isBlockedAt(X
, Y
-1) {ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)}) and
937 (not isBlockedAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)}) and
938 (not isBlockedAt(X
, Y
+1) {ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)}) then
939 begin // Âèñèò â âîçäóõå - êàïàåò
942 State
:= STATE_NORMAL
;
956 if (X
+s
>= w
) or (X
+s
<= 0) then
962 //c := gCollideMap[Y, X+s];
964 if isBlockedAt(X
+s
, Y
) {ByteBool(c and MARK_BLOCKED)} then
970 State
:= STATE_STICK
;
989 if (Y
+s
>= h
) or (Y
+s
<= 0) then
995 //c := gCollideMap[Y+s, X];
997 if isBlockedAt(X
, Y
+s
) {ByteBool(c and MARK_BLOCKED)} then
1003 if (s
> 0) and (State
<> STATE_STICK
) then
1004 State
:= STATE_NORMAL
1006 State
:= STATE_STICK
;
1019 if (X
+dX
>= w
) or (Y
+dY
>= h
) or
1020 (X
+dX
<= 0) or (Y
+dY
<= 0) or
1021 isBlockedAt(X
+dX
, Y
+dY
) {ByteBool(gCollideMap[Y+dY, X+dX] and MARK_BLOCKED)} then
1022 begin // Ñòåíà/äâåðü/ãðàíèöà
1023 State
:= STATE_FREE
;
1034 VelX
:= VelX
+ AccelX
;
1035 VelY
:= VelY
+ AccelY
;
1037 // Êðîâü ðàñòâîðÿåòñÿ â æèäêîñòè:
1038 if isLiquidAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
1042 Alpha
:= 255 - Trunc((255.0 * Time
) / LiveTime
);
1051 if (Abs(VelX
) < 0.1) and (Abs(VelY
) < 0.1) and
1052 (not isBlockedAt(X
, Y
-1) {ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)}) and
1053 (not isBlockedAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)}) and
1054 (not isBlockedAt(X
, Y
+1) {ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)}) then
1055 begin // Âèñèò â âîçäóõå
1071 if (X
+s
>= w
) or (X
+s
<= 0) then
1073 State
:= STATE_FREE
;
1077 //c := gCollideMap[Y, X+s];
1079 if isBlockedAt(X
+s
, Y
) {ByteBool(c and MARK_BLOCKED)} then
1080 begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî
1086 if not isAnythingAt(X
+s
, Y
) {c = MARK_FREE} then
1090 State
:= STATE_FREE
;
1107 if (Y
+s
>= h
) or (Y
+s
<= 0) then
1109 State
:= STATE_FREE
;
1113 //c := gCollideMap[Y+s, X];
1115 if isBlockedAt(X
, Y
+s
) {ByteBool(c and MARK_BLOCKED)} then
1116 begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî
1120 AccelY
:= Abs(AccelY
);
1122 else // Èëè íå ïàäàåò
1133 if not isAnythingAt(X
, Y
+s
) {c = MARK_FREE} then
1137 State
:= STATE_FREE
;
1144 VelX
:= VelX
+ AccelX
;
1148 AccelY
:= AccelY
+ 0.08;
1149 VelY
:= VelY
+ AccelY
;
1157 if (State
= STATE_STICK
) and (Random(30) = 15) then
1158 begin // Ñòåêàåò/îòëèïàåò
1161 if (not isBlockedAt(X
-1, Y
) {ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)}) and
1162 (not isBlockedAt(X
+1, Y
) {ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED)}) then
1163 State
:= STATE_NORMAL
;
1167 if not isBlockedAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)} then
1169 if isLiftUpAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_LIFTUP)} then
1171 if VelY
> -4-Random(3) then
1173 if Abs(VelX
) > 0.1 then
1174 VelX
:= VelX
- VelX
/10.0;
1175 VelX
:= VelX
+ (Random
-Random
)*0.2;
1178 if isLiftLeftAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT)} then
1179 begin // Ïîòîê âëåâî
1180 if VelX
> -8-Random(3) then
1184 if isLiftRightAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT)} then
1185 begin // Ïîòîê âïðàâî
1186 if VelX
< 8+Random(3) then
1195 if (Abs(VelX
) < 0.1) and (Abs(VelY
) < 0.1) then
1196 if (State
<> STATE_STICK
) and
1197 (not isBlockedAt(X
, Y
-1) {ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)}) and
1198 (not isBlockedAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)}) and
1199 (not isBlockedAt(X
, Y
+1) {ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)}) then
1200 begin // Âèñèò â âîçäóõå - êàïàåò
1203 State
:= STATE_NORMAL
;
1213 for b
:= 1 to Abs(dX
) do
1215 if (X
+s
>= w
) or (X
+s
<= 0) then
1216 begin // Ñáîêó ãðàíèöà
1217 State
:= STATE_FREE
;
1221 //c := gCollideMap[Y, X+s];
1223 if isLiquidAt(X
+s
, Y
) {ByteBool(c and MARK_LIQUID)} and (dY
> 0) then
1224 begin // Ñáîêó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
1225 State
:= STATE_FREE
;
1229 if isBlockedAt(X
+s
, Y
) {ByteBool(c and MARK_BLOCKED)} then
1230 begin // Ñòåíà/äâåðü
1235 State
:= STATE_STICK
;
1250 for b
:= 1 to Abs(dY
) do
1252 if (Y
+s
>= h
) or (Y
+s
<= 0) then
1253 begin // Ñíèçó/ñâåðõó ãðàíèöà
1254 State
:= STATE_FREE
;
1258 //c := gCollideMap[Y+s, X];
1260 if isLiquidAt(X
, Y
+s
) {ByteBool(c and MARK_LIQUID)} and (dY
> 0) then
1261 begin // Ñíèçó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
1262 State
:= STATE_FREE
;
1266 if isBlockedAt(X
, Y
+s
) {ByteBool(c and MARK_BLOCKED)} then
1267 begin // Ñòåíà/äâåðü
1272 if (s
> 0) and (State
<> STATE_STICK
) then
1273 State
:= STATE_NORMAL
1275 State
:= STATE_STICK
;
1283 VelX
:= VelX
+ AccelX
;
1284 VelY
:= VelY
+ AccelY
;
1300 for b
:= 1 to Abs(dY
) do
1302 if (Y
+s
>= h
) or (Y
+s
<= 0) then
1304 State
:= STATE_FREE
;
1308 if not isLiquidAt(X
, Y
+s
) {ByteBool(gCollideMap[Y+s, X] and MARK_LIQUID)} then
1309 begin // Óæå íå æèäêîñòü
1310 State
:= STATE_FREE
;
1319 VelY
:= VelY
+ AccelY
;
1327 end; // Particles <> nil
1329 if OnceAnims
<> nil then
1331 for a
:= 0 to High(OnceAnims
) do
1332 if OnceAnims
[a
].Animation
<> nil then
1334 case OnceAnims
[a
].AnimType
of
1337 if Random(3) = 0 then
1338 OnceAnims
[a
].X
:= OnceAnims
[a
].X
-1+Random(3);
1339 if Random(2) = 0 then
1340 OnceAnims
[a
].Y
:= OnceAnims
[a
].Y
-Random(2);
1344 if OnceAnims
[a
].Animation
.Played
then
1346 OnceAnims
[a
].Animation
.Free();
1347 OnceAnims
[a
].Animation
:= nil;
1350 OnceAnims
[a
].Animation
.Update();
1355 procedure g_GFX_Draw();
1359 if Particles
<> nil then
1361 glDisable(GL_TEXTURE_2D
);
1365 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1369 len
:= High(Particles
);
1371 for a
:= 0 to len
do
1372 with Particles
[a
] do
1373 if (State
<> STATE_FREE
) and (X
>= sX
) and (Y
>= sY
) and
1374 (X
<= sX
+sWidth
) and (sY
<= sY
+sHeight
) then
1376 glColor4ub(Red
, Green
, Blue
, Alpha
);
1377 glVertex2i(X
+ offsetX
, Y
+ offsetY
);
1382 glDisable(GL_BLEND
);
1385 if OnceAnims
<> nil then
1386 for a
:= 0 to High(OnceAnims
) do
1387 if OnceAnims
[a
].Animation
<> nil then
1388 with OnceAnims
[a
] do
1389 Animation
.Draw(X
, Y
, M_NONE
);