DEADSOFTWARE

f39d0710c683638f30b61674a1b3e1b287a64705
[d2df-sdl.git] / src / game / g_gfx.pas
1 (* Copyright (C) DooM 2D:Forever Developers
2 *
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.
7 *
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.
12 *
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/>.
15 *)
16 {$MODE DELPHI}
17 unit g_gfx;
19 interface
21 uses
22 g_textures;
24 const
25 BLOOD_NORMAL = 0;
26 BLOOD_SPARKS = 1;
27 ONCEANIM_NONE = 0;
28 ONCEANIM_SMOKE = 1;
29 MARK_FREE = 0;
30 MARK_WALL = 1;
31 MARK_WATER = 2;
32 MARK_ACID = 4;
33 MARK_LIFTDOWN = 8;
34 MARK_LIFTUP = 16;
35 MARK_DOOR = 32;
36 MARK_LIFTLEFT = 64;
37 MARK_LIFTRIGHT = 128;
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();
61 var
62 gCollideMap: Array of Array of Byte;
64 implementation
66 uses
67 g_map, g_basic, Math, e_graphics, GL, GLExt,
68 g_options, g_console, SysUtils, g_triggers, MAPDEF,
69 g_game, g_language, g_net;
71 type
72 TParticle = record
73 X, Y: Integer;
74 VelX, VelY: Single;
75 AccelX, AccelY: Single;
76 Red, Green, Blue: Byte;
77 Alpha: Byte;
78 Time, LiveTime: Word;
79 State: Byte;
80 ParticleType: Byte;
81 offsetX, offsetY: ShortInt;
82 end;
84 TOnceAnim = record
85 AnimType: Byte;
86 X, Y: Integer;
87 Animation: TAnimation;
88 end;
90 const
91 PARTICLE_BLOOD = 0;
92 PARTICLE_SPARK = 1;
93 PARTICLE_BUBBLES = 2;
94 PARTICLE_WATER = 3;
95 STATE_FREE = 0;
96 STATE_NORMAL = 1;
97 STATE_STICK = 2;
99 var
100 Particles: Array of TParticle;
101 OnceAnims: Array of TOnceAnim;
102 MaxParticles: Integer;
103 CurrentParticle: Integer;
105 procedure g_Mark(x, y, Width, Height: Integer; t: Byte; st: Boolean);
106 var
107 yy, y2, xx, x2: Integer;
108 begin
109 if x < 0 then
110 begin
111 Width := Width + x;
112 x := 0;
113 end;
115 if Width < 0 then
116 Exit;
118 if y < 0 then
119 begin
120 Height := Height + y;
121 y := 0;
122 end;
124 if Height < 0 then
125 Exit;
127 if x > gMapInfo.Width then
128 Exit;
129 if y > gMapInfo.Height then
130 Exit;
132 y2 := y + Height - 1;
133 if y2 > gMapInfo.Height then
134 y2 := gMapInfo.Height;
136 x2 := x + Width - 1;
137 if x2 > gMapInfo.Width then
138 x2 := gMapInfo.Width;
140 if st then
141 begin // Óñòàíîâèòü ïðèçíàê
142 for yy := y to y2 do
143 for xx := x to x2 do
144 gCollideMap[yy][xx] := gCollideMap[yy][xx] or t;
145 end
146 else
147 begin // Óáðàòü ïðèçíàê
148 t := not t;
149 for yy := y to y2 do
150 for xx := x to x2 do
151 gCollideMap[yy][xx] := gCollideMap[yy][xx] and t;
152 end;
153 end;
155 procedure CreateCollideMap();
156 var
157 a: Integer;
158 begin
159 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
160 SetLength(gCollideMap, gMapInfo.Height+1);
161 for a := 0 to High(gCollideMap) do
162 SetLength(gCollideMap[a], gMapInfo.Width+1);
164 if gWater <> nil then
165 begin
166 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 2/6', 0, True);
167 for a := 0 to High(gWater) do
168 with gWater[a] do
169 g_Mark(X, Y, Width, Height, MARK_WATER, True);
170 end;
172 if gAcid1 <> nil then
173 begin
174 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 3/6', 0, True);
175 for a := 0 to High(gAcid1) do
176 with gAcid1[a] do
177 g_Mark(X, Y, Width, Height, MARK_ACID, True);
178 end;
180 if gAcid2 <> nil then
181 begin
182 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 4/6', 0, True);
183 for a := 0 to High(gAcid2) do
184 with gAcid2[a] do
185 g_Mark(X, Y, Width, Height, MARK_ACID, True);
186 end;
188 if gLifts <> nil then
189 begin
190 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 5/6', 0, True);
191 for a := 0 to High(gLifts) do
192 with gLifts[a] do
193 begin
194 g_Mark(X, Y, Width, Height, MARK_LIFT, False);
196 if LiftType = 0 then
197 g_Mark(X, Y, Width, Height, MARK_LIFTUP, True)
198 else if LiftType = 1 then
199 g_Mark(X, Y, Width, Height, MARK_LIFTDOWN, True)
200 else if LiftType = 2 then
201 g_Mark(X, Y, Width, Height, MARK_LIFTLEFT, True)
202 else if LiftType = 3 then
203 g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT, True)
204 end;
205 end;
207 if gWalls <> nil then
208 begin
209 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 6/6', 0, True);
210 for a := 0 to High(gWalls) do
211 begin
212 if gWalls[a].Door then
213 begin
214 // Çàêðûòàÿ äâåðü:
215 if gWalls[a].Enabled then
216 with gWalls[a] do
217 g_Mark(X, Y, Width, Height, MARK_DOOR, True)
218 else // Îòêðûòàÿ äâåðü:
219 if gWalls[a].Enabled then
220 with gWalls[a] do
221 g_Mark(X, Y, Width, Height, MARK_DOOR, False);
222 end
223 else // Ñòåíà
224 with gWalls[a] do
225 g_Mark(X, Y, Width, Height, MARK_WALL, True);
226 end;
227 end;
228 end;
230 procedure g_GFX_Init();
231 begin
232 CreateCollideMap();
233 end;
235 procedure g_GFX_Free();
236 var
237 a: Integer;
238 begin
239 Particles := nil;
240 SetLength(Particles, MaxParticles);
241 CurrentParticle := 0;
243 if OnceAnims <> nil then
244 begin
245 for a := 0 to High(OnceAnims) do
246 OnceAnims[a].Animation.Free();
248 OnceAnims := nil;
249 end;
251 gCollideMap := nil;
252 end;
254 procedure CorrectOffsets(id: Integer);
255 begin
256 with Particles[id] do
257 begin
258 if (X >= 0) and (Y > 0) and
259 (Y < Length(gCollideMap)) and (X < Length(gCollideMap[0])) and
260 (ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) then
261 offsetY := 1 // Ñòåíà ñâåðõó
262 else
263 offsetY := 0;
265 if (X > 0) and (Y >= 0) and
266 (Y < Length(gCollideMap)) and (X < Length(gCollideMap[0])) and
267 (ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)) then
268 offsetX := 1 // Ñòåíà ñëåâà
269 else
270 offsetX := 0;
271 end;
272 end;
274 procedure g_GFX_SparkVel(fX, fY: Integer; Count: Word; VX, VY: Integer; DevX, DevY: Byte);
275 var
276 a: Integer;
277 DevX1, DevX2,
278 DevY1, DevY2: Byte;
279 l: Integer;
280 begin
281 l := Length(Particles);
282 if l = 0 then
283 Exit;
284 if Count > l then
285 Count := l;
287 DevX1 := DevX div 2;
288 DevX2 := DevX + 1;
289 DevY1 := DevY div 2;
290 DevY2 := DevY + 1;
292 for a := 1 to Count do
293 begin
294 with Particles[CurrentParticle] do
295 begin
296 X := fX-DevX1+Random(DevX2);
297 Y := fY-DevY1+Random(DevY2);
299 VelX := VX + (Random-Random)*3;
300 VelY := VY + (Random-Random)*3;
302 if VelY > -4 then
303 if VelY-4 < -4 then
304 VelY := -4
305 else
306 VelY := VelY-4;
308 AccelX := -Sign(VelX)*Random/100;
309 AccelY := 0.8;
311 Red := 255;
312 Green := 100+Random(155);
313 Blue := 64;
314 Alpha := 255;
316 State := STATE_NORMAL;
317 Time := 0;
318 LiveTime := 30+Random(60);
319 ParticleType := PARTICLE_SPARK;
321 CorrectOffsets(CurrentParticle);
322 end;
324 if CurrentParticle+2 > MaxParticles then
325 CurrentParticle := 0
326 else
327 CurrentParticle := CurrentParticle+1;
328 end;
329 end;
331 procedure g_GFX_Blood(fX, fY: Integer; Count: Word; vx, vy: Integer;
332 DevX, DevY: Word; CR, CG, CB: Byte; Kind: Byte = BLOOD_NORMAL);
333 var
334 a: Integer;
335 DevX1, DevX2,
336 DevY1, DevY2: Word;
337 l: Integer;
338 CRnd: Byte;
339 CC: SmallInt;
340 begin
341 if Kind = BLOOD_SPARKS then
342 begin
343 g_GFX_SparkVel(fX, fY, 2 + Random(2), -VX div 2, -VY div 2, DevX, DevY);
344 Exit;
345 end;
346 l := Length(Particles);
347 if l = 0 then
348 Exit;
349 if Count > l then
350 Count := l;
352 DevX1 := DevX div 2;
353 DevX2 := DevX + 1;
354 DevY1 := DevY div 2;
355 DevY2 := DevY + 1;
357 for a := 1 to Count do
358 begin
359 with Particles[CurrentParticle] do
360 begin
361 X := fX - DevX1 + Random(DevX2);
362 Y := fY - DevY1 + Random(DevY2);
364 if (X < 0) or (X > gMapInfo.Width-1) or
365 (Y < 0) or (Y > gMapInfo.Height-1) or
366 ByteBool(gCollideMap[Y, X] and MARK_WALL) then
367 Continue;
369 VelX := vx + (Random-Random)*3;
370 VelY := vy + (Random-Random)*3;
372 if VelY > -4 then
373 if VelY-4 < -4 then
374 VelY := -4
375 else
376 VelY := VelY-4;
378 AccelX := -Sign(VelX)*Random/100;
379 AccelY := 0.8;
381 CRnd := 20*Random(6);
382 if CR > 0 then
383 begin
384 CC := CR + CRnd - 50;
385 if CC < 0 then CC := 0;
386 if CC > 255 then CC := 255;
387 Red := CC;
388 end else
389 Red := 0;
390 if CG > 0 then
391 begin
392 CC := CG + CRnd - 50;
393 if CC < 0 then CC := 0;
394 if CC > 255 then CC := 255;
395 Green := CC;
396 end else
397 Green := 0;
398 if CB > 0 then
399 begin
400 CC := CB + CRnd - 50;
401 if CC < 0 then CC := 0;
402 if CC > 255 then CC := 255;
403 Blue := CC;
404 end else
405 Blue := 0;
407 Alpha := 255;
409 State := STATE_NORMAL;
410 Time := 0;
411 LiveTime := 120+Random(40);
412 ParticleType := PARTICLE_BLOOD;
414 CorrectOffsets(CurrentParticle);
415 end;
417 if CurrentParticle >= MaxParticles-1 then
418 CurrentParticle := 0
419 else
420 CurrentParticle := CurrentParticle+1;
421 end;
422 end;
424 procedure g_GFX_Spark(fX, fY: Integer; Count: Word; Angle: SmallInt; DevX, DevY: Byte);
425 var
426 a: Integer;
427 b: Single;
428 DevX1, DevX2,
429 DevY1, DevY2: Byte;
430 BaseVelX, BaseVelY: Single;
431 l: Integer;
432 begin
433 l := Length(Particles);
434 if l = 0 then
435 Exit;
436 if Count > l then
437 Count := l;
439 Angle := 360 - Angle;
441 DevX1 := DevX div 2;
442 DevX2 := DevX + 1;
443 DevY1 := DevY div 2;
444 DevY2 := DevY + 1;
446 b := DegToRad(Angle);
447 BaseVelX := cos(b);
448 BaseVelY := 1.6*sin(b);
449 if Abs(BaseVelX) < 0.01 then
450 BaseVelX := 0.0;
451 if Abs(BaseVelY) < 0.01 then
452 BaseVelY := 0.0;
453 for a := 1 to Count do
454 begin
455 with Particles[CurrentParticle] do
456 begin
457 X := fX-DevX1+Random(DevX2);
458 Y := fY-DevY1+Random(DevY2);
460 VelX := BaseVelX*Random;
461 VelY := BaseVelY-Random;
462 AccelX := VelX/3.0;
463 AccelY := VelY/5.0;
465 Red := 255;
466 Green := 100+Random(155);
467 Blue := 64;
468 Alpha := 255;
470 State := STATE_NORMAL;
471 Time := 0;
472 LiveTime := 30+Random(60);
473 ParticleType := PARTICLE_SPARK;
475 CorrectOffsets(CurrentParticle);
476 end;
478 if CurrentParticle+2 > MaxParticles then
479 CurrentParticle := 0
480 else
481 CurrentParticle := CurrentParticle+1;
482 end;
483 end;
485 procedure g_GFX_Water(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DevX, DevY, Color: Byte);
486 var
487 a: Integer;
488 DevX1, DevX2,
489 DevY1, DevY2: Byte;
490 l: Integer;
491 begin
492 l := Length(Particles);
493 if l = 0 then
494 Exit;
495 if Count > l then
496 Count := l;
498 if Abs(fVelX) < 3.0 then
499 fVelX := 3.0 - 6.0*Random;
501 DevX1 := DevX div 2;
502 DevX2 := DevX + 1;
503 DevY1 := DevY div 2;
504 DevY2 := DevY + 1;
506 for a := 1 to Count do
507 begin
508 with Particles[CurrentParticle] do
509 begin
510 X := fX-DevX1+Random(DevX2);
511 Y := fY-DevY1+Random(DevY2);
513 if Abs(fVelX) < 0.5 then
514 VelX := 1.0 - 2.0*Random
515 else
516 VelX := fVelX*Random;
517 if Random(10) < 7 then
518 VelX := -VelX;
519 VelY := fVelY*Random;
520 AccelX := 0.0;
521 AccelY := 0.8;
523 case Color of
524 1: // Êðàñíûé
525 begin
526 Red := 155 + Random(9)*10;
527 Green := Trunc(150*Random);
528 Blue := Green;
529 end;
530 2: // Çåëåíûé
531 begin
532 Red := Trunc(150*Random);
533 Green := 175 + Random(9)*10;
534 Blue := Red;
535 end;
536 3: // Ñèíèé
537 begin
538 Red := Trunc(200*Random);
539 Green := Red;
540 Blue := 175 + Random(9)*10;
541 end;
542 else // Ñåðûé
543 begin
544 Red := 90 + Random(12)*10;
545 Green := Red;
546 Blue := Red;
547 end;
548 end;
550 Alpha := 255;
552 State := STATE_NORMAL;
553 Time := 0;
554 LiveTime := 60+Random(60);
555 ParticleType := PARTICLE_WATER;
557 CorrectOffsets(CurrentParticle);
558 end;
560 if CurrentParticle+2 > MaxParticles then
561 CurrentParticle := 0
562 else
563 CurrentParticle := CurrentParticle+1;
564 end;
565 end;
567 procedure g_GFX_SimpleWater(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DefColor, CR, CG, CB: Byte);
568 var
569 a: Integer;
570 l: Integer;
571 begin
572 l := Length(Particles);
573 if l = 0 then
574 Exit;
575 if Count > l then
576 Count := l;
578 for a := 1 to Count do
579 begin
580 with Particles[CurrentParticle] do
581 begin
582 X := fX;
583 Y := fY;
585 VelX := fVelX;
586 VelY := fVelY;
587 AccelX := 0.0;
588 AccelY := 0.8;
590 case DefColor of
591 1: // Êðàñíûé
592 begin
593 Red := 155 + Random(9)*10;
594 Green := Trunc(150*Random);
595 Blue := Green;
596 end;
597 2: // Çåëåíûé
598 begin
599 Red := Trunc(150*Random);
600 Green := 175 + Random(9)*10;
601 Blue := Red;
602 end;
603 3: // Ñèíèé
604 begin
605 Red := Trunc(200*Random);
606 Green := Red;
607 Blue := 175 + Random(9)*10;
608 end;
609 4: // Ñâîé öâåò, ñâåòëåå
610 begin
611 Red := 20 + Random(19)*10;
612 Green := Red;
613 Blue := Red;
614 Red := Min(Red + CR, 255);
615 Green := Min(Green + CG, 255);
616 Blue := Min(Blue + CB, 255);
617 end;
618 5: // Ñâîé öâåò, òåìíåå
619 begin
620 Red := 20 + Random(19)*10;
621 Green := Red;
622 Blue := Red;
623 Red := Max(CR - Red, 0);
624 Green := Max(CG - Green, 0);
625 Blue := Max(CB - Blue, 0);
626 end;
627 else // Ñåðûé
628 begin
629 Red := 90 + Random(12)*10;
630 Green := Red;
631 Blue := Red;
632 end;
633 end;
635 Alpha := 255;
637 State := STATE_NORMAL;
638 Time := 0;
639 LiveTime := 60+Random(60);
640 ParticleType := PARTICLE_WATER;
642 CorrectOffsets(CurrentParticle);
643 end;
645 if CurrentParticle+2 > MaxParticles then
646 CurrentParticle := 0
647 else
648 CurrentParticle := CurrentParticle+1;
649 end;
650 end;
652 procedure g_GFX_Bubbles(fX, fY: Integer; Count: Word; DevX, DevY: Byte);
653 var
654 a: Integer;
655 DevX1, DevX2,
656 DevY1, DevY2: Byte;
657 l: Integer;
658 begin
659 l := Length(Particles);
660 if l = 0 then
661 Exit;
662 if Count > l then
663 Count := l;
665 DevX1 := DevX div 2;
666 DevX2 := DevX + 1;
667 DevY1 := DevY div 2;
668 DevY2 := DevY + 1;
670 for a := 1 to Count do
671 begin
672 with Particles[CurrentParticle] do
673 begin
674 X := fX-DevX1+Random(DevX2);
675 Y := fY-DevY1+Random(DevY2);
677 if (X >= gMapInfo.Width) or (X <= 0) or
678 (Y >= gMapInfo.Height) or (Y <= 0) then
679 Continue;
681 if not ByteBool(gCollideMap[Y, X] and MARK_LIQUID) then
682 Continue;
684 VelX := 0;
685 VelY := -1-Random;
686 AccelX := 0;
687 AccelY := VelY/10;
689 Red := 255;
690 Green := 255;
691 Blue := 255;
692 Alpha := 255;
694 State := STATE_NORMAL;
695 Time := 0;
696 LiveTime := 65535;
697 ParticleType := PARTICLE_BUBBLES;
699 CorrectOffsets(CurrentParticle);
700 end;
702 if CurrentParticle+2 > MaxParticles then
703 CurrentParticle := 0
704 else
705 CurrentParticle := CurrentParticle+1;
706 end;
707 end;
709 procedure g_GFX_SetMax(Count: Integer);
710 begin
711 if Count > 50000 then
712 Count := 50000;
714 SetLength(Particles, Count);
715 MaxParticles := Count;
716 if CurrentParticle >= Count then
717 CurrentParticle := 0;
718 end;
720 function g_GFX_GetMax(): Integer;
721 begin
722 Result := MaxParticles;
723 end;
725 function FindOnceAnim: DWORD;
726 var
727 i: Integer;
728 begin
729 if OnceAnims <> nil then
730 for i := 0 to High(OnceAnims) do
731 if OnceAnims[i].Animation = nil then
732 begin
733 Result := i;
734 Exit;
735 end;
737 if OnceAnims = nil then
738 begin
739 SetLength(OnceAnims, 16);
740 Result := 0;
741 end
742 else
743 begin
744 Result := High(OnceAnims) + 1;
745 SetLength(OnceAnims, Length(OnceAnims) + 16);
746 end;
747 end;
749 procedure g_GFX_OnceAnim(X, Y: Integer; Anim: TAnimation; AnimType: Byte = 0);
750 var
751 find_id: DWORD;
752 begin
753 if Anim = nil then
754 Exit;
756 find_id := FindOnceAnim();
758 OnceAnims[find_id].AnimType := AnimType;
759 OnceAnims[find_id].Animation := TAnimation.Create(Anim.FramesID, Anim.Loop, Anim.Speed);
760 OnceAnims[find_id].Animation.Blending := Anim.Blending;
761 OnceAnims[find_id].Animation.Alpha := Anim.Alpha;
762 OnceAnims[find_id].X := X;
763 OnceAnims[find_id].Y := Y;
764 end;
766 procedure g_GFX_Update();
767 var
768 a: Integer;
769 w, h: Integer;
770 dX, dY: SmallInt;
771 b, len: Integer;
772 s: ShortInt;
773 c: Byte;
774 begin
775 if Particles <> nil then
776 begin
777 w := gMapInfo.Width;
778 h := gMapInfo.Height;
780 len := High(Particles);
782 for a := 0 to len do
783 if Particles[a].State <> 0 then
784 with Particles[a] do
785 begin
786 if Time = LiveTime then
787 State := STATE_FREE;
788 if (X+1 >= w) or (Y+1 >= h) or (X <= 0) or (Y <= 0) then
789 State := STATE_FREE;
790 if State = STATE_FREE then
791 Continue;
793 case ParticleType of
794 PARTICLE_BLOOD:
795 begin
796 if gAdvBlood then
797 begin
798 if (State = STATE_STICK) then
799 if (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
800 (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) and
801 (not ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)) and
802 (not ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED)) then
803 begin // Îòëèïëà - êàïàåò
804 VelY := 0.5;
805 AccelY := 0.15;
806 State := STATE_NORMAL;
807 end
808 else
809 if Random(200) = 100 then
810 begin // Ïðèëåïëåíà - íî âîçìîæíî ñòåêàåò
811 VelY := 0.5;
812 AccelY := 0.15;
813 Continue;
814 end;
816 if not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED) then
817 begin
818 if ByteBool(gCollideMap[Y, X] and MARK_LIFTUP) then
819 begin // Ëèôò ââåðõ
820 if VelY > -4-Random(3) then
821 VelY := VelY - 0.8;
822 if Abs(VelX) > 0.1 then
823 VelX := VelX - VelX/10.0;
824 VelX := VelX + (Random-Random)*0.2;
825 AccelY := 0.15;
826 end;
827 if ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT) then
828 begin // Ïîòîê âëåâî
829 if VelX > -8-Random(3) then
830 VelX := VelX - 0.8;
831 AccelY := 0.15;
832 end;
833 if ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT) then
834 begin // Ïîòîê âïðàâî
835 if VelX < 8+Random(3) then
836 VelX := VelX + 0.8;
837 AccelY := 0.15;
838 end;
839 end;
841 dX := Round(VelX);
842 dY := Round(VelY);
844 if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) then
845 if (State <> STATE_STICK) and
846 (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
847 (not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)) and
848 (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) then
849 begin // Âèñèò â âîçäóõå - êàïàåò
850 VelY := 0.8;
851 AccelY := 0.5;
852 State := STATE_NORMAL;
853 end;
855 if dX <> 0 then
856 begin
857 if dX > 0 then
858 s := 1
859 else
860 s := -1;
862 dX := Abs(dX);
864 for b := 1 to dX do
865 begin
866 if (X+s >= w) or (X+s <= 0) then
867 begin
868 State := STATE_FREE;
869 Break;
870 end;
872 c := gCollideMap[Y, X+s];
874 if ByteBool(c and MARK_BLOCKED) then
875 begin // Ñòåíà/äâåðü
876 VelX := 0;
877 VelY := 0;
878 AccelX := 0;
879 AccelY := 0;
880 State := STATE_STICK;
881 Break;
882 end;
884 X := X+s;
885 end;
886 end;
888 if dY <> 0 then
889 begin
890 if dY > 0 then
891 s := 1
892 else
893 s := -1;
895 dY := Abs(dY);
897 for b := 1 to dY do
898 begin
899 if (Y+s >= h) or (Y+s <= 0) then
900 begin
901 State := STATE_FREE;
902 Break;
903 end;
905 c := gCollideMap[Y+s, X];
907 if ByteBool(c and MARK_BLOCKED) then
908 begin // Ñòåíà/äâåðü
909 VelX := 0;
910 VelY := 0;
911 AccelX := 0;
912 AccelY := 0;
913 if (s > 0) and (State <> STATE_STICK) then
914 State := STATE_NORMAL
915 else
916 State := STATE_STICK;
917 Break;
918 end;
920 Y := Y+s;
921 end;
922 end;
923 end // if gAdvBlood
924 else
925 begin
926 dX := Round(VelX);
927 dY := Round(VelY);
929 if (X+dX >= w) or (Y+dY >= h) or
930 (X+dX <= 0) or (Y+dY <= 0) or
931 ByteBool(gCollideMap[Y+dY, X+dX] and MARK_BLOCKED) then
932 begin // Ñòåíà/äâåðü/ãðàíèöà
933 State := STATE_FREE;
934 VelX := 0;
935 VelY := 0;
936 end
937 else
938 begin
939 Y := Y + dY;
940 X := X + dX;
941 end;
942 end;
944 VelX := VelX + AccelX;
945 VelY := VelY + AccelY;
947 // Êðîâü ðàñòâîðÿåòñÿ â æèäêîñòè:
948 if ByteBool(gCollideMap[Y, X] and MARK_LIQUID) then
949 begin
950 Inc(Time);
952 Alpha := 255 - Trunc((255.0 * Time) / LiveTime);
953 end;
954 end;
956 PARTICLE_SPARK:
957 begin
958 dX := Round(VelX);
959 dY := Round(VelY);
961 if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) and
962 (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
963 (not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)) and
964 (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) then
965 begin // Âèñèò â âîçäóõå
966 VelY := 0.8;
967 AccelY := 0.5;
968 end;
970 if dX <> 0 then
971 begin
972 if dX > 0 then
973 s := 1
974 else
975 s := -1;
977 dX := Abs(dX);
979 for b := 1 to dX do
980 begin
981 if (X+s >= w) or (X+s <= 0) then
982 begin
983 State := STATE_FREE;
984 Break;
985 end;
987 c := gCollideMap[Y, X+s];
989 if ByteBool(c and MARK_BLOCKED) then
990 begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî
991 VelX := 0;
992 AccelX := 0;
993 Break;
994 end
995 else // Ïóñòî:
996 if c = MARK_FREE then
997 X := X + s
998 else // Îñòàëüíîå:
999 begin
1000 State := STATE_FREE;
1001 Break;
1002 end;
1003 end;
1004 end;
1006 if dY <> 0 then
1007 begin
1008 if dY > 0 then
1009 s := 1
1010 else
1011 s := -1;
1013 dY := Abs(dY);
1015 for b := 1 to dY do
1016 begin
1017 if (Y+s >= h) or (Y+s <= 0) then
1018 begin
1019 State := STATE_FREE;
1020 Break;
1021 end;
1023 c := gCollideMap[Y+s, X];
1025 if ByteBool(c and MARK_BLOCKED) then
1026 begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî
1027 if s < 0 then
1028 begin
1029 VelY := -VelY;
1030 AccelY := Abs(AccelY);
1031 end
1032 else // Èëè íå ïàäàåò
1033 begin
1034 VelX := 0;
1035 AccelX := 0;
1036 VelY := 0;
1037 AccelY := 0.8;
1038 end;
1040 Break;
1041 end
1042 else // Ïóñòî:
1043 if c = MARK_FREE then
1044 Y := Y + s
1045 else // Îñàëüíîå:
1046 begin
1047 State := STATE_FREE;
1048 Break;
1049 end;
1050 end;
1051 end;
1053 if VelX <> 0.0 then
1054 VelX := VelX + AccelX;
1055 if VelY <> 0.0 then
1056 begin
1057 if AccelY < 10 then
1058 AccelY := AccelY + 0.08;
1059 VelY := VelY + AccelY;
1060 end;
1062 Time := Time + 1;
1063 end;
1065 PARTICLE_WATER:
1066 begin
1067 if (State = STATE_STICK) and (Random(30) = 15) then
1068 begin // Ñòåêàåò/îòëèïàåò
1069 VelY := 0.5;
1070 AccelY := 0.15;
1071 if (not ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)) and
1072 (not ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED)) then
1073 State := STATE_NORMAL;
1074 Continue;
1075 end;
1077 if not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED) then
1078 begin
1079 if ByteBool(gCollideMap[Y, X] and MARK_LIFTUP) then
1080 begin // Ëèôò ââåðõ
1081 if VelY > -4-Random(3) then
1082 VelY := VelY - 0.8;
1083 if Abs(VelX) > 0.1 then
1084 VelX := VelX - VelX/10.0;
1085 VelX := VelX + (Random-Random)*0.2;
1086 AccelY := 0.15;
1087 end;
1088 if ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT) then
1089 begin // Ïîòîê âëåâî
1090 if VelX > -8-Random(3) then
1091 VelX := VelX - 0.8;
1092 AccelY := 0.15;
1093 end;
1094 if ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT) then
1095 begin // Ïîòîê âïðàâî
1096 if VelX < 8+Random(3) then
1097 VelX := VelX + 0.8;
1098 AccelY := 0.15;
1099 end;
1100 end;
1102 dX := Round(VelX);
1103 dY := Round(VelY);
1105 if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) then
1106 if (State <> STATE_STICK) and
1107 (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
1108 (not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)) and
1109 (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) then
1110 begin // Âèñèò â âîçäóõå - êàïàåò
1111 VelY := 0.8;
1112 AccelY := 0.5;
1113 State := STATE_NORMAL;
1114 end;
1116 if dX <> 0 then
1117 begin
1118 if dX > 0 then
1119 s := 1
1120 else
1121 s := -1;
1123 for b := 1 to Abs(dX) do
1124 begin
1125 if (X+s >= w) or (X+s <= 0) then
1126 begin // Ñáîêó ãðàíèöà
1127 State := STATE_FREE;
1128 Break;
1129 end;
1131 c := gCollideMap[Y, X+s];
1133 if ByteBool(c and MARK_LIQUID) and (dY > 0) then
1134 begin // Ñáîêó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
1135 State := STATE_FREE;
1136 Break;
1137 end;
1139 if ByteBool(c and MARK_BLOCKED) then
1140 begin // Ñòåíà/äâåðü
1141 VelX := 0;
1142 VelY := 0;
1143 AccelX := 0;
1144 AccelY := 0;
1145 State := STATE_STICK;
1146 Break;
1147 end;
1149 X := X+s;
1150 end;
1151 end;
1153 if dY <> 0 then
1154 begin
1155 if dY > 0 then
1156 s := 1
1157 else
1158 s := -1;
1160 for b := 1 to Abs(dY) do
1161 begin
1162 if (Y+s >= h) or (Y+s <= 0) then
1163 begin // Ñíèçó/ñâåðõó ãðàíèöà
1164 State := STATE_FREE;
1165 Break;
1166 end;
1168 c := gCollideMap[Y+s, X];
1170 if ByteBool(c and MARK_LIQUID) and (dY > 0) then
1171 begin // Ñíèçó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
1172 State := STATE_FREE;
1173 Break;
1174 end;
1176 if ByteBool(c and MARK_BLOCKED) then
1177 begin // Ñòåíà/äâåðü
1178 VelX := 0;
1179 VelY := 0;
1180 AccelX := 0;
1181 AccelY := 0;
1182 if (s > 0) and (State <> STATE_STICK) then
1183 State := STATE_NORMAL
1184 else
1185 State := STATE_STICK;
1186 Break;
1187 end;
1189 Y := Y+s;
1190 end;
1191 end;
1193 VelX := VelX + AccelX;
1194 VelY := VelY + AccelY;
1196 Time := Time + 1;
1197 end;
1199 PARTICLE_BUBBLES:
1200 begin
1201 dY := Round(VelY);
1203 if dY <> 0 then
1204 begin
1205 if dY > 0 then
1206 s := 1
1207 else
1208 s := -1;
1210 for b := 1 to Abs(dY) do
1211 begin
1212 if (Y+s >= h) or (Y+s <= 0) then
1213 begin
1214 State := STATE_FREE;
1215 Break;
1216 end;
1218 if not ByteBool(gCollideMap[Y+s, X] and MARK_LIQUID) then
1219 begin // Óæå íå æèäêîñòü
1220 State := STATE_FREE;
1221 Break;
1222 end;
1224 Y := Y+s;
1225 end;
1226 end;
1228 if VelY > -4 then
1229 VelY := VelY + AccelY;
1231 Time := Time + 1;
1232 end;
1233 end; // case
1235 CorrectOffsets(a);
1236 end;
1237 end; // Particles <> nil
1239 if OnceAnims <> nil then
1240 begin
1241 for a := 0 to High(OnceAnims) do
1242 if OnceAnims[a].Animation <> nil then
1243 begin
1244 case OnceAnims[a].AnimType of
1245 ONCEANIM_SMOKE:
1246 begin
1247 if Random(3) = 0 then
1248 OnceAnims[a].X := OnceAnims[a].X-1+Random(3);
1249 if Random(2) = 0 then
1250 OnceAnims[a].Y := OnceAnims[a].Y-Random(2);
1251 end;
1252 end;
1254 if OnceAnims[a].Animation.Played then
1255 begin
1256 OnceAnims[a].Animation.Free();
1257 OnceAnims[a].Animation := nil;
1258 end
1259 else
1260 OnceAnims[a].Animation.Update();
1261 end;
1262 end;
1263 end;
1265 procedure g_GFX_Draw();
1266 var
1267 a, len: Integer;
1268 begin
1269 if Particles <> nil then
1270 begin
1271 glDisable(GL_TEXTURE_2D);
1272 glPointSize(2);
1274 glEnable(GL_BLEND);
1275 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1277 glBegin(GL_POINTS);
1279 len := High(Particles);
1281 for a := 0 to len do
1282 with Particles[a] do
1283 if (State <> STATE_FREE) and (X >= sX) and (Y >= sY) and
1284 (X <= sX+sWidth) and (sY <= sY+sHeight) then
1285 begin
1286 glColor4ub(Red, Green, Blue, Alpha);
1287 glVertex2i(X + offsetX, Y + offsetY);
1288 end;
1290 glEnd();
1292 glDisable(GL_BLEND);
1293 end;
1295 if OnceAnims <> nil then
1296 for a := 0 to High(OnceAnims) do
1297 if OnceAnims[a].Animation <> nil then
1298 with OnceAnims[a] do
1299 Animation.Draw(X, Y, M_NONE);
1300 end;
1302 end.