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}
38 MARK_BLOCKED
= MARK_WALL
+ MARK_DOOR
;
39 MARK_LIQUID
= MARK_WATER
+ MARK_ACID
;
40 MARK_LIFT
= MARK_LIFTDOWN
+ MARK_LIFTUP
+ MARK_LIFTLEFT
+ MARK_LIFTRIGHT
;
42 procedure g_GFX_Init();
43 procedure g_GFX_Free();
45 procedure g_GFX_Blood(fX
, fY
: Integer; Count
: Word; vx
, vy
: Integer;
46 DevX
, DevY
: Word; CR
, CG
, CB
: Byte; Kind
: Byte = BLOOD_NORMAL
);
47 procedure g_GFX_Spark(fX
, fY
: Integer; Count
: Word; Angle
: SmallInt; DevX
, DevY
: Byte);
48 procedure g_GFX_Water(fX
, fY
: Integer; Count
: Word; fVelX
, fVelY
: Single; DevX
, DevY
, Color
: Byte);
49 procedure g_GFX_SimpleWater(fX
, fY
: Integer; Count
: Word; fVelX
, fVelY
: Single; DefColor
, CR
, CG
, CB
: Byte);
50 procedure g_GFX_Bubbles(fX
, fY
: Integer; Count
: Word; DevX
, DevY
: Byte);
51 procedure g_GFX_SetMax(Count
: Integer);
52 function g_GFX_GetMax(): Integer;
54 procedure g_GFX_OnceAnim(X
, Y
: Integer; Anim
: TAnimation
; AnimType
: Byte = 0);
56 procedure g_Mark(x
, y
, Width
, Height
: Integer; t
: Byte; st
: Boolean);
58 procedure g_GFX_Update();
59 procedure g_GFX_Draw();
63 gpart_dbg_enabled
: Boolean = true;
64 gpart_dbg_phys_enabled
: Boolean = true;
70 g_map
, g_basic
, Math
, e_graphics
, GL
, GLExt
,
71 g_options
, g_console
, SysUtils
, g_triggers
, MAPDEF
,
72 g_game
, g_language
, g_net
;
75 PParticle
= ^TParticle
;
79 AccelX
, AccelY
: Single;
80 Red
, Green
, Blue
: Byte;
85 offsetX
, offsetY
: ShortInt;
87 liquidTopY
: Integer; // don't float higher than this
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): Boolean; inline;
114 if not gpart_dbg_phys_enabled
then begin result
:= false; exit
; end;
115 result
:= g_Map_HasAnyPanelAtPoint(x
, y
, (PANEL_WALL
or PANEL_CLOSEDOOR
or PANEL_STEP
));
119 function isWallAt (x
, y
: Integer): Boolean; inline;
121 if not gpart_dbg_phys_enabled
then begin result
:= false; exit
; end;
122 result
:= g_Map_HasAnyPanelAtPoint(x
, y
, (PANEL_WALL
or PANEL_STEP
));
125 function isLiftUpAt (x
, y
: Integer): Boolean; inline;
127 if not gpart_dbg_phys_enabled
then begin result
:= false; exit
; end;
128 result
:= g_Map_HasAnyPanelAtPoint(x
, y
, PANEL_LIFTUP
);
131 function isLiftDownAt (x
, y
: Integer): Boolean; inline;
133 if not gpart_dbg_phys_enabled
then begin result
:= false; exit
; end;
134 result
:= g_Map_HasAnyPanelAtPoint(x
, y
, PANEL_LIFTDOWN
);
137 function isLiftLeftAt (x
, y
: Integer): Boolean; inline;
139 if not gpart_dbg_phys_enabled
then begin result
:= false; exit
; end;
140 result
:= g_Map_HasAnyPanelAtPoint(x
, y
, PANEL_LIFTLEFT
);
143 function isLiftRightAt (x
, y
: Integer): Boolean; inline;
145 if not gpart_dbg_phys_enabled
then begin result
:= false; exit
; end;
146 result
:= g_Map_HasAnyPanelAtPoint(x
, y
, PANEL_LIFTRIGHT
);
149 function isLiquidAt (x
, y
: Integer): Boolean; inline;
151 if not gpart_dbg_phys_enabled
then begin result
:= false; exit
; end;
152 result
:= g_Map_HasAnyPanelAtPoint(x
, y
, (PANEL_WATER
or PANEL_ACID1
or PANEL_ACID2
));
155 function isAnythingAt (x
, y
: Integer): Boolean; inline;
157 if not gpart_dbg_phys_enabled
then begin result
:= false; exit
; end;
158 result
:= g_Map_HasAnyPanelAtPoint(x
, y
, (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
));
162 procedure g_Mark(x
, y
, Width
, Height
: Integer; t
: Byte; st
: Boolean);
163 {$IF not DEFINED(HAS_COLLIDE_BITMAP)}
168 yy
, y2
, xx
, x2
: Integer;
181 Height
:= Height
+ y
;
188 if x
> gMapInfo
.Width
then
190 if y
> gMapInfo
.Height
then
193 y2
:= y
+ Height
- 1;
194 if y2
> gMapInfo
.Height
then
195 y2
:= gMapInfo
.Height
;
198 if x2
> gMapInfo
.Width
then
199 x2
:= gMapInfo
.Width
;
202 begin // Óñòàíîâèòü ïðèçíàê
205 gCollideMap
[yy
][xx
] := gCollideMap
[yy
][xx
] or t
;
208 begin // Óáðàòü ïðèçíàê
212 gCollideMap
[yy
][xx
] := gCollideMap
[yy
][xx
] and t
;
218 {$IF DEFINED(HAS_COLLIDE_BITMAP)}
219 procedure CreateCollideMap();
223 g_Game_SetLoadingText(_lc
[I_LOAD_COLLIDE_MAP
]+' 1/6', 0, False);
224 SetLength(gCollideMap
, gMapInfo
.Height
+1);
225 for a
:= 0 to High(gCollideMap
) do
226 SetLength(gCollideMap
[a
], gMapInfo
.Width
+1);
228 if gWater
<> nil then
230 g_Game_SetLoadingText(_lc
[I_LOAD_COLLIDE_MAP
]+' 2/6', 0, True);
231 for a
:= 0 to High(gWater
) do
233 g_Mark(X
, Y
, Width
, Height
, MARK_WATER
, True);
236 if gAcid1
<> nil then
238 g_Game_SetLoadingText(_lc
[I_LOAD_COLLIDE_MAP
]+' 3/6', 0, True);
239 for a
:= 0 to High(gAcid1
) do
241 g_Mark(X
, Y
, Width
, Height
, MARK_ACID
, True);
244 if gAcid2
<> nil then
246 g_Game_SetLoadingText(_lc
[I_LOAD_COLLIDE_MAP
]+' 4/6', 0, True);
247 for a
:= 0 to High(gAcid2
) do
249 g_Mark(X
, Y
, Width
, Height
, MARK_ACID
, True);
252 if gLifts
<> nil then
254 g_Game_SetLoadingText(_lc
[I_LOAD_COLLIDE_MAP
]+' 5/6', 0, True);
255 for a
:= 0 to High(gLifts
) do
258 g_Mark(X
, Y
, Width
, Height
, MARK_LIFT
, False);
261 g_Mark(X
, Y
, Width
, Height
, MARK_LIFTUP
, True)
262 else if LiftType
= 1 then
263 g_Mark(X
, Y
, Width
, Height
, MARK_LIFTDOWN
, True)
264 else if LiftType
= 2 then
265 g_Mark(X
, Y
, Width
, Height
, MARK_LIFTLEFT
, True)
266 else if LiftType
= 3 then
267 g_Mark(X
, Y
, Width
, Height
, MARK_LIFTRIGHT
, True)
271 if gWalls
<> nil then
273 g_Game_SetLoadingText(_lc
[I_LOAD_COLLIDE_MAP
]+' 6/6', 0, True);
274 for a
:= 0 to High(gWalls
) do
276 if gWalls
[a
].Door
then
279 if gWalls
[a
].Enabled
then
281 g_Mark(X
, Y
, Width
, Height
, MARK_DOOR
, True)
282 else // Îòêðûòàÿ äâåðü:
283 if gWalls
[a
].Enabled
then
285 g_Mark(X
, Y
, Width
, Height
, MARK_DOOR
, False);
289 g_Mark(X
, Y
, Width
, Height
, MARK_WALL
, True);
296 procedure g_GFX_Init();
298 //CreateCollideMap();
302 procedure g_GFX_Free();
307 SetLength(Particles
, MaxParticles
);
308 for a
:= 0 to High(Particles
) do Particles
[a
].State
:= STATE_FREE
;
309 CurrentParticle
:= 0;
311 if OnceAnims
<> nil then
313 for a
:= 0 to High(OnceAnims
) do
314 OnceAnims
[a
].Animation
.Free();
322 procedure CorrectOffsets(id: Integer); inline;
326 part := @Particles[id];
329 // check for upper wall
330 if isBlockedAt(part.X, part.Y-1) then part.offsetY := 1;
331 // check for left wall
332 if isBlockedAt(part.X-1, part.Y) then part.offsetX := 1;
337 procedure g_GFX_SparkVel (fX
, fY
: Integer; Count
: Word; VX
, VY
: Integer; DevX
, DevY
: Byte);
344 l
:= Length(Particles
);
346 if Count
> l
then Count
:= l
;
353 for a
:= 1 to Count
do
355 with Particles
[CurrentParticle
] do
357 X
:= fX
-DevX1
+Random(DevX2
);
358 Y
:= fY
-DevY1
+Random(DevY2
);
360 VelX
:= VX
+ (Random
-Random
)*3;
361 VelY
:= VY
+ (Random
-Random
)*3;
369 AccelX
:= -Sign(VelX
)*Random
/100;
373 Green
:= 100+Random(155);
377 State
:= STATE_NORMAL
;
379 LiveTime
:= 30+Random(60);
380 ParticleType
:= PARTICLE_SPARK
;
382 {CorrectOffsets(CurrentParticle);}
385 if CurrentParticle
+2 > MaxParticles
then
388 CurrentParticle
:= CurrentParticle
+1;
393 procedure g_GFX_Blood(fX
, fY
: Integer; Count
: Word; vx
, vy
: Integer;
394 DevX
, DevY
: Word; CR
, CG
, CB
: Byte; Kind
: Byte = BLOOD_NORMAL
);
403 if Kind
= BLOOD_SPARKS
then
405 g_GFX_SparkVel(fX
, fY
, 2 + Random(2), -VX
div 2, -VY
div 2, DevX
, DevY
);
408 l
:= Length(Particles
);
419 for a
:= 1 to Count
do
421 with Particles
[CurrentParticle
] do
423 X
:= fX
- DevX1
+ Random(DevX2
);
424 Y
:= fY
- DevY1
+ Random(DevY2
);
427 if (X < 0) or (X > gMapInfo.Width-1) or
428 (Y < 0) or (Y > gMapInfo.Height-1) or
429 ByteBool(gCollideMap[Y, X] and MARK_WALL) then
432 if isWallAt(X
, Y
) then continue
;
434 VelX
:= vx
+ (Random
-Random
)*3;
435 VelY
:= vy
+ (Random
-Random
)*3;
443 AccelX
:= -Sign(VelX
)*Random
/100;
446 CRnd
:= 20*Random(6);
449 CC
:= CR
+ CRnd
- 50;
450 if CC
< 0 then CC
:= 0;
451 if CC
> 255 then CC
:= 255;
457 CC
:= CG
+ CRnd
- 50;
458 if CC
< 0 then CC
:= 0;
459 if CC
> 255 then CC
:= 255;
465 CC
:= CB
+ CRnd
- 50;
466 if CC
< 0 then CC
:= 0;
467 if CC
> 255 then CC
:= 255;
474 State
:= STATE_NORMAL
;
476 LiveTime
:= 120+Random(40);
477 ParticleType
:= PARTICLE_BLOOD
;
479 {CorrectOffsets(CurrentParticle);}
482 if CurrentParticle
>= MaxParticles
-1 then
485 CurrentParticle
:= CurrentParticle
+1;
490 procedure g_GFX_Spark(fX
, fY
: Integer; Count
: Word; Angle
: SmallInt; DevX
, DevY
: Byte);
496 BaseVelX
, BaseVelY
: Single;
499 l
:= Length(Particles
);
505 Angle
:= 360 - Angle
;
512 b
:= DegToRad(Angle
);
514 BaseVelY
:= 1.6*sin(b
);
515 if Abs(BaseVelX
) < 0.01 then
517 if Abs(BaseVelY
) < 0.01 then
519 for a
:= 1 to Count
do
521 with Particles
[CurrentParticle
] do
523 X
:= fX
-DevX1
+Random(DevX2
);
524 Y
:= fY
-DevY1
+Random(DevY2
);
526 VelX
:= BaseVelX
*Random
;
527 VelY
:= BaseVelY
-Random
;
532 Green
:= 100+Random(155);
536 State
:= STATE_NORMAL
;
538 LiveTime
:= 30+Random(60);
539 ParticleType
:= PARTICLE_SPARK
;
541 {CorrectOffsets(CurrentParticle);}
544 if CurrentParticle
+2 > MaxParticles
then
547 CurrentParticle
:= CurrentParticle
+1;
551 procedure g_GFX_Water(fX
, fY
: Integer; Count
: Word; fVelX
, fVelY
: Single; DevX
, DevY
, Color
: Byte);
558 l
:= Length(Particles
);
564 if Abs(fVelX
) < 3.0 then
565 fVelX
:= 3.0 - 6.0*Random
;
572 for a
:= 1 to Count
do
574 with Particles
[CurrentParticle
] do
576 X
:= fX
-DevX1
+Random(DevX2
);
577 Y
:= fY
-DevY1
+Random(DevY2
);
579 if Abs(fVelX
) < 0.5 then
580 VelX
:= 1.0 - 2.0*Random
582 VelX
:= fVelX
*Random
;
583 if Random(10) < 7 then
585 VelY
:= fVelY
*Random
;
592 Red
:= 155 + Random(9)*10;
593 Green
:= Trunc(150*Random
);
598 Red
:= Trunc(150*Random
);
599 Green
:= 175 + Random(9)*10;
604 Red
:= Trunc(200*Random
);
606 Blue
:= 175 + Random(9)*10;
610 Red
:= 90 + Random(12)*10;
618 State
:= STATE_NORMAL
;
620 LiveTime
:= 60+Random(60);
621 ParticleType
:= PARTICLE_WATER
;
623 {CorrectOffsets(CurrentParticle);}
626 if CurrentParticle
+2 > MaxParticles
then
629 CurrentParticle
:= CurrentParticle
+1;
633 procedure g_GFX_SimpleWater(fX
, fY
: Integer; Count
: Word; fVelX
, fVelY
: Single; DefColor
, CR
, CG
, CB
: Byte);
638 l
:= Length(Particles
);
644 for a
:= 1 to Count
do
646 with Particles
[CurrentParticle
] do
659 Red
:= 155 + Random(9)*10;
660 Green
:= Trunc(150*Random
);
665 Red
:= Trunc(150*Random
);
666 Green
:= 175 + Random(9)*10;
671 Red
:= Trunc(200*Random
);
673 Blue
:= 175 + Random(9)*10;
675 4: // Ñâîé öâåò, ñâåòëåå
677 Red
:= 20 + Random(19)*10;
680 Red
:= Min(Red
+ CR
, 255);
681 Green
:= Min(Green
+ CG
, 255);
682 Blue
:= Min(Blue
+ CB
, 255);
684 5: // Ñâîé öâåò, òåìíåå
686 Red
:= 20 + Random(19)*10;
689 Red
:= Max(CR
- Red
, 0);
690 Green
:= Max(CG
- Green
, 0);
691 Blue
:= Max(CB
- Blue
, 0);
695 Red
:= 90 + Random(12)*10;
703 State
:= STATE_NORMAL
;
705 LiveTime
:= 60+Random(60);
706 ParticleType
:= PARTICLE_WATER
;
708 {CorrectOffsets(CurrentParticle);}
711 if CurrentParticle
+2 > MaxParticles
then
714 CurrentParticle
:= CurrentParticle
+1;
719 procedure g_GFX_Bubbles(fX
, fY
: Integer; Count
: Word; DevX
, DevY
: Byte);
726 l
:= Length(Particles
);
737 for a
:= 1 to Count
do
739 with Particles
[CurrentParticle
] do
741 X
:= fX
-DevX1
+Random(DevX2
);
742 Y
:= fY
-DevY1
+Random(DevY2
);
744 if (X
>= gMapInfo
.Width
) or (X
<= 0) or
745 (Y
>= gMapInfo
.Height
) or (Y
<= 0) then
749 // don't spawn bubbles outside of the liquid
750 if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
754 // trace liquid, so we'll know where it ends; do it in 8px steps for speed
755 // tracer will return `false` if we started outside of the liquid
756 if not g_Map_TraceLiquid(X
, Y
, 0, -8, liquidx
, liquidTopY
) then continue
;
768 State
:= STATE_NORMAL
;
771 ParticleType
:= PARTICLE_BUBBLES
;
773 {CorrectOffsets(CurrentParticle);}
776 if CurrentParticle
+2 > MaxParticles
then
779 CurrentParticle
:= CurrentParticle
+1;
783 procedure g_GFX_SetMax(Count
: Integer);
787 if Count
> 50000 then Count
:= 50000;
788 if (Count
< 1) then Count
:= 1;
790 SetLength(Particles
, Count
);
791 for a
:= 0 to High(Particles
) do Particles
[a
].State
:= STATE_FREE
;
792 MaxParticles
:= Count
;
793 //if CurrentParticle >= Count then
794 CurrentParticle
:= 0;
797 function g_GFX_GetMax(): Integer;
799 Result
:= MaxParticles
;
802 function FindOnceAnim
: DWORD
;
806 if OnceAnims
<> nil then
807 for i
:= 0 to High(OnceAnims
) do
808 if OnceAnims
[i
].Animation
= nil then
814 if OnceAnims
= nil then
816 SetLength(OnceAnims
, 16);
821 Result
:= High(OnceAnims
) + 1;
822 SetLength(OnceAnims
, Length(OnceAnims
) + 16);
826 procedure g_GFX_OnceAnim(X
, Y
: Integer; Anim
: TAnimation
; AnimType
: Byte = 0);
833 find_id
:= FindOnceAnim();
835 OnceAnims
[find_id
].AnimType
:= AnimType
;
836 OnceAnims
[find_id
].Animation
:= TAnimation
.Create(Anim
.FramesID
, Anim
.Loop
, Anim
.Speed
);
837 OnceAnims
[find_id
].Animation
.Blending
:= Anim
.Blending
;
838 OnceAnims
[find_id
].Animation
.Alpha
:= Anim
.Alpha
;
839 OnceAnims
[find_id
].X
:= X
;
840 OnceAnims
[find_id
].Y
:= Y
;
843 procedure g_GFX_Update();
852 if not gpart_dbg_enabled
then exit
;
853 if Particles
<> nil then
856 h
:= gMapInfo
.Height
;
858 len
:= High(Particles
);
862 if Particles
[a
].State
<> STATE_FREE
then
866 if Time
= LiveTime
then State
:= STATE_FREE
;
867 if (X
+1 >= w
) or (Y
+1 >= h
) or (X
<= 0) or (Y
<= 0) then State
:= STATE_FREE
;
868 if State
= STATE_FREE
then Continue
;
869 //e_WriteLog(Format('particle #%d: %d', [State, ParticleType]), MSG_NOTIFY);
876 if (State
= STATE_STICK
) then
878 if (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
879 (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) and
880 (not ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)) and
881 (not ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED))
884 if (not isBlockedAt(X
, Y
-1)) and
885 (not isBlockedAt(X
, Y
+1)) and
886 (not isBlockedAt(X
-1, Y
)) and
887 (not isBlockedAt(X
+1, Y
))
889 begin // Îòëèïëà - êàïàåò
892 State
:= STATE_NORMAL
;
895 if Random(200) = 100 then
896 begin // Ïðèëåïëåíà - íî âîçìîæíî ñòåêàåò
902 if not isBlockedAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)} then
904 if isLiftUpAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_LIFTUP)} then
906 if VelY
> -4-Random(3) then
908 if Abs(VelX
) > 0.1 then
909 VelX
:= VelX
- VelX
/10.0;
910 VelX
:= VelX
+ (Random
-Random
)*0.2;
913 if isLiftLeftAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT)} then
915 if VelX
> -8-Random(3) then
919 if isLiftRightAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT)} then
920 begin // Ïîòîê âïðàâî
921 if VelX
< 8+Random(3) then
930 if (Abs(VelX
) < 0.1) and (Abs(VelY
) < 0.1) then
931 if (State
<> STATE_STICK
) and
932 (not isBlockedAt(X
, Y
-1) {ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)}) and
933 (not isBlockedAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)}) and
934 (not isBlockedAt(X
, Y
+1) {ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)}) then
935 begin // Âèñèò â âîçäóõå - êàïàåò
938 State
:= STATE_NORMAL
;
952 if (X
+s
>= w
) or (X
+s
<= 0) then
958 //c := gCollideMap[Y, X+s];
960 if isBlockedAt(X
+s
, Y
) {ByteBool(c and MARK_BLOCKED)} then
966 State
:= STATE_STICK
;
985 if (Y
+s
>= h
) or (Y
+s
<= 0) then
991 //c := gCollideMap[Y+s, X];
993 if isBlockedAt(X
, Y
+s
) {ByteBool(c and MARK_BLOCKED)} then
999 if (s
> 0) and (State
<> STATE_STICK
) then
1000 State
:= STATE_NORMAL
1002 State
:= STATE_STICK
;
1015 if (X
+dX
>= w
) or (Y
+dY
>= h
) or
1016 (X
+dX
<= 0) or (Y
+dY
<= 0) or
1017 isBlockedAt(X
+dX
, Y
+dY
) {ByteBool(gCollideMap[Y+dY, X+dX] and MARK_BLOCKED)} then
1018 begin // Ñòåíà/äâåðü/ãðàíèöà
1019 State
:= STATE_FREE
;
1030 VelX
:= VelX
+ AccelX
;
1031 VelY
:= VelY
+ AccelY
;
1033 // Êðîâü ðàñòâîðÿåòñÿ â æèäêîñòè:
1034 if isLiquidAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
1038 Alpha
:= 255 - Trunc((255.0 * Time
) / LiveTime
);
1047 if (Abs(VelX
) < 0.1) and (Abs(VelY
) < 0.1) and
1048 (not isBlockedAt(X
, Y
-1) {ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)}) and
1049 (not isBlockedAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)}) and
1050 (not isBlockedAt(X
, Y
+1) {ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)}) then
1051 begin // Âèñèò â âîçäóõå
1067 if (X
+s
>= w
) or (X
+s
<= 0) then
1069 State
:= STATE_FREE
;
1073 //c := gCollideMap[Y, X+s];
1075 if isBlockedAt(X
+s
, Y
) {ByteBool(c and MARK_BLOCKED)} then
1076 begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî
1082 if not isAnythingAt(X
+s
, Y
) {c = MARK_FREE} then
1086 State
:= STATE_FREE
;
1103 if (Y
+s
>= h
) or (Y
+s
<= 0) then
1105 State
:= STATE_FREE
;
1109 //c := gCollideMap[Y+s, X];
1111 if isBlockedAt(X
, Y
+s
) {ByteBool(c and MARK_BLOCKED)} then
1112 begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî
1116 AccelY
:= Abs(AccelY
);
1118 else // Èëè íå ïàäàåò
1129 if not isAnythingAt(X
, Y
+s
) {c = MARK_FREE} then
1133 State
:= STATE_FREE
;
1140 VelX
:= VelX
+ AccelX
;
1144 AccelY
:= AccelY
+ 0.08;
1145 VelY
:= VelY
+ AccelY
;
1153 if (State
= STATE_STICK
) and (Random(30) = 15) then
1154 begin // Ñòåêàåò/îòëèïàåò
1157 if (not isBlockedAt(X
-1, Y
) {ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)}) and
1158 (not isBlockedAt(X
+1, Y
) {ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED)}) then
1159 State
:= STATE_NORMAL
;
1163 if not isBlockedAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)} then
1165 if isLiftUpAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_LIFTUP)} then
1167 if VelY
> -4-Random(3) then
1169 if Abs(VelX
) > 0.1 then
1170 VelX
:= VelX
- VelX
/10.0;
1171 VelX
:= VelX
+ (Random
-Random
)*0.2;
1174 if isLiftLeftAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT)} then
1175 begin // Ïîòîê âëåâî
1176 if VelX
> -8-Random(3) then
1180 if isLiftRightAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT)} then
1181 begin // Ïîòîê âïðàâî
1182 if VelX
< 8+Random(3) then
1191 if (Abs(VelX
) < 0.1) and (Abs(VelY
) < 0.1) then
1192 if (State
<> STATE_STICK
) and
1193 (not isBlockedAt(X
, Y
-1) {ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)}) and
1194 (not isBlockedAt(X
, Y
) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)}) and
1195 (not isBlockedAt(X
, Y
+1) {ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)}) then
1196 begin // Âèñèò â âîçäóõå - êàïàåò
1199 State
:= STATE_NORMAL
;
1209 for b
:= 1 to Abs(dX
) do
1211 if (X
+s
>= w
) or (X
+s
<= 0) then
1212 begin // Ñáîêó ãðàíèöà
1213 State
:= STATE_FREE
;
1217 //c := gCollideMap[Y, X+s];
1219 if isLiquidAt(X
+s
, Y
) {ByteBool(c and MARK_LIQUID)} and (dY
> 0) then
1220 begin // Ñáîêó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
1221 State
:= STATE_FREE
;
1225 if isBlockedAt(X
+s
, Y
) {ByteBool(c and MARK_BLOCKED)} then
1226 begin // Ñòåíà/äâåðü
1231 State
:= STATE_STICK
;
1246 for b
:= 1 to Abs(dY
) do
1248 if (Y
+s
>= h
) or (Y
+s
<= 0) then
1249 begin // Ñíèçó/ñâåðõó ãðàíèöà
1250 State
:= STATE_FREE
;
1254 //c := gCollideMap[Y+s, X];
1256 if isLiquidAt(X
, Y
+s
) {ByteBool(c and MARK_LIQUID)} and (dY
> 0) then
1257 begin // Ñíèçó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
1258 State
:= STATE_FREE
;
1262 if isBlockedAt(X
, Y
+s
) {ByteBool(c and MARK_BLOCKED)} then
1263 begin // Ñòåíà/äâåðü
1268 if (s
> 0) and (State
<> STATE_STICK
) then
1269 State
:= STATE_NORMAL
1271 State
:= STATE_STICK
;
1279 VelX
:= VelX
+ AccelX
;
1280 VelY
:= VelY
+ AccelY
;
1296 for b
:= 1 to Abs(dY
) do
1298 if (Y
+s
>= h
) or (Y
+s
<= 0) then
1300 State
:= STATE_FREE
;
1304 if not isLiquidAt(X
, Y
+s
) {ByteBool(gCollideMap[Y+s, X] and MARK_LIQUID)} then
1305 begin // Óæå íå æèäêîñòü
1306 State
:= STATE_FREE
;
1315 VelY
:= VelY
+ AccelY
;
1321 {CorrectOffsets(a);}
1325 end; // Particles <> nil
1327 if OnceAnims
<> nil then
1329 for a
:= 0 to High(OnceAnims
) do
1330 if OnceAnims
[a
].Animation
<> nil then
1332 case OnceAnims
[a
].AnimType
of
1335 if Random(3) = 0 then
1336 OnceAnims
[a
].X
:= OnceAnims
[a
].X
-1+Random(3);
1337 if Random(2) = 0 then
1338 OnceAnims
[a
].Y
:= OnceAnims
[a
].Y
-Random(2);
1342 if OnceAnims
[a
].Animation
.Played
then
1344 OnceAnims
[a
].Animation
.Free();
1345 OnceAnims
[a
].Animation
:= nil;
1348 OnceAnims
[a
].Animation
.Update();
1353 procedure g_GFX_Draw();
1357 if Particles
<> nil then
1359 glDisable(GL_TEXTURE_2D
);
1363 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1367 len
:= High(Particles
);
1369 for a
:= 0 to len
do
1370 with Particles
[a
] do
1371 if (State
<> STATE_FREE
) and (X
>= sX
) and (Y
>= sY
) and
1372 (X
<= sX
+sWidth
) and (sY
<= sY
+sHeight
) then
1374 glColor4ub(Red
, Green
, Blue
, Alpha
);
1375 glVertex2i(X
+ offsetX
, Y
+ offsetY
);
1380 glDisable(GL_BLEND
);
1383 if OnceAnims
<> nil then
1384 for a
:= 0 to High(OnceAnims
) do
1385 if OnceAnims
[a
].Animation
<> nil then
1386 with OnceAnims
[a
] do
1387 Animation
.Draw(X
, Y
, M_NONE
);