DEADSOFTWARE

f6558892a8263b9a338cbded80607b1cee17ed2a
[d2df-sdl.git] / src / game / g_gfx.pas
1 unit g_gfx;
3 interface
5 uses
6 g_textures;
8 const
9 BLOOD_NORMAL = 0;
10 BLOOD_SPARKS = 1;
11 ONCEANIM_NONE = 0;
12 ONCEANIM_SMOKE = 1;
13 MARK_FREE = 0;
14 MARK_WALL = 1;
15 MARK_WATER = 2;
16 MARK_ACID = 4;
17 MARK_LIFTDOWN = 8;
18 MARK_LIFTUP = 16;
19 MARK_DOOR = 32;
20 MARK_LIFTLEFT = 64;
21 MARK_LIFTRIGHT = 128;
22 MARK_BLOCKED = MARK_WALL + MARK_DOOR;
23 MARK_LIQUID = MARK_WATER + MARK_ACID;
24 MARK_LIFT = MARK_LIFTDOWN + MARK_LIFTUP + MARK_LIFTLEFT + MARK_LIFTRIGHT;
26 procedure g_GFX_Init();
27 procedure g_GFX_Free();
29 procedure g_GFX_Blood(fX, fY: Integer; Count: Word; vx, vy: Integer;
30 DevX, DevY: Word; CR, CG, CB: Byte; Kind: Byte = BLOOD_NORMAL);
31 procedure g_GFX_Spark(fX, fY: Integer; Count: Word; Angle: SmallInt; DevX, DevY: Byte);
32 procedure g_GFX_Water(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DevX, DevY, Color: Byte);
33 procedure g_GFX_SimpleWater(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DefColor, CR, CG, CB: Byte);
34 procedure g_GFX_Bubbles(fX, fY: Integer; Count: Word; DevX, DevY: Byte);
35 procedure g_GFX_SetMax(Count: Integer);
36 function g_GFX_GetMax(): Integer;
38 procedure g_GFX_OnceAnim(X, Y: Integer; Anim: TAnimation; AnimType: Byte = 0);
40 procedure g_Mark(x, y, Width, Height: Integer; t: Byte; st: Boolean);
42 procedure g_GFX_Update();
43 procedure g_GFX_Draw();
45 var
46 gCollideMap: Array of Array of Byte;
48 implementation
50 uses
51 g_map, g_basic, Math, e_graphics, GL, GLExt,
52 g_options, g_console, SysUtils, g_triggers, MAPDEF,
53 g_game, g_language, g_net;
55 type
56 TParticle = record
57 X, Y: Integer;
58 VelX, VelY: Single;
59 AccelX, AccelY: Single;
60 Red, Green, Blue: Byte;
61 Alpha: Byte;
62 Time, LiveTime: Word;
63 State: Byte;
64 ParticleType: Byte;
65 offsetX, offsetY: ShortInt;
66 end;
68 TOnceAnim = record
69 AnimType: Byte;
70 X, Y: Integer;
71 Animation: TAnimation;
72 end;
74 const
75 PARTICLE_BLOOD = 0;
76 PARTICLE_SPARK = 1;
77 PARTICLE_BUBBLES = 2;
78 PARTICLE_WATER = 3;
79 STATE_FREE = 0;
80 STATE_NORMAL = 1;
81 STATE_STICK = 2;
83 var
84 Particles: Array of TParticle;
85 OnceAnims: Array of TOnceAnim;
86 MaxParticles: Integer;
87 CurrentParticle: Integer;
89 procedure g_Mark(x, y, Width, Height: Integer; t: Byte; st: Boolean);
90 var
91 yy, y2, xx, x2: Integer;
92 begin
93 if x < 0 then
94 begin
95 Width := Width + x;
96 x := 0;
97 end;
99 if Width < 0 then
100 Exit;
102 if y < 0 then
103 begin
104 Height := Height + y;
105 y := 0;
106 end;
108 if Height < 0 then
109 Exit;
111 if x > gMapInfo.Width then
112 Exit;
113 if y > gMapInfo.Height then
114 Exit;
116 y2 := y + Height - 1;
117 if y2 > gMapInfo.Height then
118 y2 := gMapInfo.Height;
120 x2 := x + Width - 1;
121 if x2 > gMapInfo.Width then
122 x2 := gMapInfo.Width;
124 if st then
125 begin // Óñòàíîâèòü ïðèçíàê
126 for yy := y to y2 do
127 for xx := x to x2 do
128 gCollideMap[yy][xx] := gCollideMap[yy][xx] or t;
129 end
130 else
131 begin // Óáðàòü ïðèçíàê
132 t := not t;
133 for yy := y to y2 do
134 for xx := x to x2 do
135 gCollideMap[yy][xx] := gCollideMap[yy][xx] and t;
136 end;
137 end;
139 procedure CreateCollideMap();
140 var
141 a: Integer;
142 begin
143 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
144 SetLength(gCollideMap, gMapInfo.Height+1);
145 for a := 0 to High(gCollideMap) do
146 SetLength(gCollideMap[a], gMapInfo.Width+1);
148 if gWater <> nil then
149 begin
150 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 2/6', 0, True);
151 for a := 0 to High(gWater) do
152 with gWater[a] do
153 g_Mark(X, Y, Width, Height, MARK_WATER, True);
154 end;
156 if gAcid1 <> nil then
157 begin
158 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 3/6', 0, True);
159 for a := 0 to High(gAcid1) do
160 with gAcid1[a] do
161 g_Mark(X, Y, Width, Height, MARK_ACID, True);
162 end;
164 if gAcid2 <> nil then
165 begin
166 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 4/6', 0, True);
167 for a := 0 to High(gAcid2) do
168 with gAcid2[a] do
169 g_Mark(X, Y, Width, Height, MARK_ACID, True);
170 end;
172 if gLifts <> nil then
173 begin
174 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 5/6', 0, True);
175 for a := 0 to High(gLifts) do
176 with gLifts[a] do
177 begin
178 g_Mark(X, Y, Width, Height, MARK_LIFT, False);
180 if LiftType = 0 then
181 g_Mark(X, Y, Width, Height, MARK_LIFTUP, True)
182 else if LiftType = 1 then
183 g_Mark(X, Y, Width, Height, MARK_LIFTDOWN, True)
184 else if LiftType = 2 then
185 g_Mark(X, Y, Width, Height, MARK_LIFTLEFT, True)
186 else if LiftType = 3 then
187 g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT, True)
188 end;
189 end;
191 if gWalls <> nil then
192 begin
193 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 6/6', 0, True);
194 for a := 0 to High(gWalls) do
195 begin
196 if gWalls[a].Door then
197 begin
198 // Çàêðûòàÿ äâåðü:
199 if gWalls[a].Enabled then
200 with gWalls[a] do
201 g_Mark(X, Y, Width, Height, MARK_DOOR, True)
202 else // Îòêðûòàÿ äâåðü:
203 if gWalls[a].Enabled then
204 with gWalls[a] do
205 g_Mark(X, Y, Width, Height, MARK_DOOR, False);
206 end
207 else // Ñòåíà
208 with gWalls[a] do
209 g_Mark(X, Y, Width, Height, MARK_WALL, True);
210 end;
211 end;
212 end;
214 procedure g_GFX_Init();
215 begin
216 CreateCollideMap();
217 end;
219 procedure g_GFX_Free();
220 var
221 a: Integer;
222 begin
223 Particles := nil;
224 SetLength(Particles, MaxParticles);
225 CurrentParticle := 0;
227 if OnceAnims <> nil then
228 begin
229 for a := 0 to High(OnceAnims) do
230 OnceAnims[a].Animation.Free();
232 OnceAnims := nil;
233 end;
235 gCollideMap := nil;
236 end;
238 procedure CorrectOffsets(id: Integer);
239 begin
240 with Particles[id] do
241 begin
242 if (X >= 0) and (Y > 0) and
243 (Y < Length(gCollideMap)) and (X < Length(gCollideMap[0])) and
244 (ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) then
245 offsetY := 1 // Ñòåíà ñâåðõó
246 else
247 offsetY := 0;
249 if (X > 0) and (Y >= 0) and
250 (Y < Length(gCollideMap)) and (X < Length(gCollideMap[0])) and
251 (ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)) then
252 offsetX := 1 // Ñòåíà ñëåâà
253 else
254 offsetX := 0;
255 end;
256 end;
258 procedure g_GFX_SparkVel(fX, fY: Integer; Count: Word; VX, VY: Integer; DevX, DevY: Byte);
259 var
260 a: Integer;
261 DevX1, DevX2,
262 DevY1, DevY2: Byte;
263 l: Integer;
264 begin
265 l := Length(Particles);
266 if l = 0 then
267 Exit;
268 if Count > l then
269 Count := l;
271 DevX1 := DevX div 2;
272 DevX2 := DevX + 1;
273 DevY1 := DevY div 2;
274 DevY2 := DevY + 1;
276 for a := 1 to Count do
277 begin
278 with Particles[CurrentParticle] do
279 begin
280 X := fX-DevX1+Random(DevX2);
281 Y := fY-DevY1+Random(DevY2);
283 VelX := VX + (Random-Random)*3;
284 VelY := VY + (Random-Random)*3;
286 if VelY > -4 then
287 if VelY-4 < -4 then
288 VelY := -4
289 else
290 VelY := VelY-4;
292 AccelX := -Sign(VelX)*Random/100;
293 AccelY := 0.8;
295 Red := 255;
296 Green := 100+Random(155);
297 Blue := 64;
298 Alpha := 255;
300 State := STATE_NORMAL;
301 Time := 0;
302 LiveTime := 30+Random(60);
303 ParticleType := PARTICLE_SPARK;
305 CorrectOffsets(CurrentParticle);
306 end;
308 if CurrentParticle+2 > MaxParticles then
309 CurrentParticle := 0
310 else
311 CurrentParticle := CurrentParticle+1;
312 end;
313 end;
315 procedure g_GFX_Blood(fX, fY: Integer; Count: Word; vx, vy: Integer;
316 DevX, DevY: Word; CR, CG, CB: Byte; Kind: Byte = BLOOD_NORMAL);
317 var
318 a: Integer;
319 DevX1, DevX2,
320 DevY1, DevY2: Word;
321 l: Integer;
322 CRnd: Byte;
323 CC: SmallInt;
324 begin
325 if Kind = BLOOD_SPARKS then
326 begin
327 g_GFX_SparkVel(fX, fY, 2 + Random(2), -VX div 2, -VY div 2, DevX, DevY);
328 Exit;
329 end;
330 l := Length(Particles);
331 if l = 0 then
332 Exit;
333 if Count > l then
334 Count := l;
336 DevX1 := DevX div 2;
337 DevX2 := DevX + 1;
338 DevY1 := DevY div 2;
339 DevY2 := DevY + 1;
341 for a := 1 to Count do
342 begin
343 with Particles[CurrentParticle] do
344 begin
345 X := fX - DevX1 + Random(DevX2);
346 Y := fY - DevY1 + Random(DevY2);
348 if (X < 0) or (X > gMapInfo.Width-1) or
349 (Y < 0) or (Y > gMapInfo.Height-1) or
350 ByteBool(gCollideMap[Y, X] and MARK_WALL) then
351 Continue;
353 VelX := vx + (Random-Random)*3;
354 VelY := vy + (Random-Random)*3;
356 if VelY > -4 then
357 if VelY-4 < -4 then
358 VelY := -4
359 else
360 VelY := VelY-4;
362 AccelX := -Sign(VelX)*Random/100;
363 AccelY := 0.8;
365 CRnd := 20*Random(6);
366 if CR > 0 then
367 begin
368 CC := CR + CRnd - 50;
369 if CC < 0 then CC := 0;
370 if CC > 255 then CC := 255;
371 Red := CC;
372 end else
373 Red := 0;
374 if CG > 0 then
375 begin
376 CC := CG + CRnd - 50;
377 if CC < 0 then CC := 0;
378 if CC > 255 then CC := 255;
379 Green := CC;
380 end else
381 Green := 0;
382 if CB > 0 then
383 begin
384 CC := CB + CRnd - 50;
385 if CC < 0 then CC := 0;
386 if CC > 255 then CC := 255;
387 Blue := CC;
388 end else
389 Blue := 0;
391 Alpha := 255;
393 State := STATE_NORMAL;
394 Time := 0;
395 LiveTime := 120+Random(40);
396 ParticleType := PARTICLE_BLOOD;
398 CorrectOffsets(CurrentParticle);
399 end;
401 if CurrentParticle >= MaxParticles-1 then
402 CurrentParticle := 0
403 else
404 CurrentParticle := CurrentParticle+1;
405 end;
406 end;
408 procedure g_GFX_Spark(fX, fY: Integer; Count: Word; Angle: SmallInt; DevX, DevY: Byte);
409 var
410 a: Integer;
411 b: Single;
412 DevX1, DevX2,
413 DevY1, DevY2: Byte;
414 BaseVelX, BaseVelY: Single;
415 l: Integer;
416 begin
417 l := Length(Particles);
418 if l = 0 then
419 Exit;
420 if Count > l then
421 Count := l;
423 Angle := 360 - Angle;
425 DevX1 := DevX div 2;
426 DevX2 := DevX + 1;
427 DevY1 := DevY div 2;
428 DevY2 := DevY + 1;
430 b := DegToRad(Angle);
431 BaseVelX := cos(b);
432 BaseVelY := 1.6*sin(b);
433 if Abs(BaseVelX) < 0.01 then
434 BaseVelX := 0.0;
435 if Abs(BaseVelY) < 0.01 then
436 BaseVelY := 0.0;
437 for a := 1 to Count do
438 begin
439 with Particles[CurrentParticle] do
440 begin
441 X := fX-DevX1+Random(DevX2);
442 Y := fY-DevY1+Random(DevY2);
444 VelX := BaseVelX*Random;
445 VelY := BaseVelY-Random;
446 AccelX := VelX/3.0;
447 AccelY := VelY/5.0;
449 Red := 255;
450 Green := 100+Random(155);
451 Blue := 64;
452 Alpha := 255;
454 State := STATE_NORMAL;
455 Time := 0;
456 LiveTime := 30+Random(60);
457 ParticleType := PARTICLE_SPARK;
459 CorrectOffsets(CurrentParticle);
460 end;
462 if CurrentParticle+2 > MaxParticles then
463 CurrentParticle := 0
464 else
465 CurrentParticle := CurrentParticle+1;
466 end;
467 end;
469 procedure g_GFX_Water(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DevX, DevY, Color: Byte);
470 var
471 a: Integer;
472 DevX1, DevX2,
473 DevY1, DevY2: Byte;
474 l: Integer;
475 begin
476 l := Length(Particles);
477 if l = 0 then
478 Exit;
479 if Count > l then
480 Count := l;
482 if Abs(fVelX) < 3.0 then
483 fVelX := 3.0 - 6.0*Random;
485 DevX1 := DevX div 2;
486 DevX2 := DevX + 1;
487 DevY1 := DevY div 2;
488 DevY2 := DevY + 1;
490 for a := 1 to Count do
491 begin
492 with Particles[CurrentParticle] do
493 begin
494 X := fX-DevX1+Random(DevX2);
495 Y := fY-DevY1+Random(DevY2);
497 if Abs(fVelX) < 0.5 then
498 VelX := 1.0 - 2.0*Random
499 else
500 VelX := fVelX*Random;
501 if Random(10) < 7 then
502 VelX := -VelX;
503 VelY := fVelY*Random;
504 AccelX := 0.0;
505 AccelY := 0.8;
507 case Color of
508 1: // Êðàñíûé
509 begin
510 Red := 155 + Random(9)*10;
511 Green := Trunc(150*Random);
512 Blue := Green;
513 end;
514 2: // Çåëåíûé
515 begin
516 Red := Trunc(150*Random);
517 Green := 175 + Random(9)*10;
518 Blue := Red;
519 end;
520 3: // Ñèíèé
521 begin
522 Red := Trunc(200*Random);
523 Green := Red;
524 Blue := 175 + Random(9)*10;
525 end;
526 else // Ñåðûé
527 begin
528 Red := 90 + Random(12)*10;
529 Green := Red;
530 Blue := Red;
531 end;
532 end;
534 Alpha := 255;
536 State := STATE_NORMAL;
537 Time := 0;
538 LiveTime := 60+Random(60);
539 ParticleType := PARTICLE_WATER;
541 CorrectOffsets(CurrentParticle);
542 end;
544 if CurrentParticle+2 > MaxParticles then
545 CurrentParticle := 0
546 else
547 CurrentParticle := CurrentParticle+1;
548 end;
549 end;
551 procedure g_GFX_SimpleWater(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DefColor, CR, CG, CB: Byte);
552 var
553 a: Integer;
554 l: Integer;
555 begin
556 l := Length(Particles);
557 if l = 0 then
558 Exit;
559 if Count > l then
560 Count := l;
562 for a := 1 to Count do
563 begin
564 with Particles[CurrentParticle] do
565 begin
566 X := fX;
567 Y := fY;
569 VelX := fVelX;
570 VelY := fVelY;
571 AccelX := 0.0;
572 AccelY := 0.8;
574 case DefColor of
575 1: // Êðàñíûé
576 begin
577 Red := 155 + Random(9)*10;
578 Green := Trunc(150*Random);
579 Blue := Green;
580 end;
581 2: // Çåëåíûé
582 begin
583 Red := Trunc(150*Random);
584 Green := 175 + Random(9)*10;
585 Blue := Red;
586 end;
587 3: // Ñèíèé
588 begin
589 Red := Trunc(200*Random);
590 Green := Red;
591 Blue := 175 + Random(9)*10;
592 end;
593 4: // Ñâîé öâåò, ñâåòëåå
594 begin
595 Red := 20 + Random(19)*10;
596 Green := Red;
597 Blue := Red;
598 Red := Min(Red + CR, 255);
599 Green := Min(Green + CG, 255);
600 Blue := Min(Blue + CB, 255);
601 end;
602 5: // Ñâîé öâåò, òåìíåå
603 begin
604 Red := 20 + Random(19)*10;
605 Green := Red;
606 Blue := Red;
607 Red := Max(CR - Red, 0);
608 Green := Max(CG - Green, 0);
609 Blue := Max(CB - Blue, 0);
610 end;
611 else // Ñåðûé
612 begin
613 Red := 90 + Random(12)*10;
614 Green := Red;
615 Blue := Red;
616 end;
617 end;
619 Alpha := 255;
621 State := STATE_NORMAL;
622 Time := 0;
623 LiveTime := 60+Random(60);
624 ParticleType := PARTICLE_WATER;
626 CorrectOffsets(CurrentParticle);
627 end;
629 if CurrentParticle+2 > MaxParticles then
630 CurrentParticle := 0
631 else
632 CurrentParticle := CurrentParticle+1;
633 end;
634 end;
636 procedure g_GFX_Bubbles(fX, fY: Integer; Count: Word; DevX, DevY: Byte);
637 var
638 a: Integer;
639 DevX1, DevX2,
640 DevY1, DevY2: Byte;
641 l: Integer;
642 begin
643 l := Length(Particles);
644 if l = 0 then
645 Exit;
646 if Count > l then
647 Count := l;
649 DevX1 := DevX div 2;
650 DevX2 := DevX + 1;
651 DevY1 := DevY div 2;
652 DevY2 := DevY + 1;
654 for a := 1 to Count do
655 begin
656 with Particles[CurrentParticle] do
657 begin
658 X := fX-DevX1+Random(DevX2);
659 Y := fY-DevY1+Random(DevY2);
661 if (X >= gMapInfo.Width) or (X <= 0) or
662 (Y >= gMapInfo.Height) or (Y <= 0) then
663 Continue;
665 if not ByteBool(gCollideMap[Y, X] and MARK_LIQUID) then
666 Continue;
668 VelX := 0;
669 VelY := -1-Random;
670 AccelX := 0;
671 AccelY := VelY/10;
673 Red := 255;
674 Green := 255;
675 Blue := 255;
676 Alpha := 255;
678 State := STATE_NORMAL;
679 Time := 0;
680 LiveTime := 65535;
681 ParticleType := PARTICLE_BUBBLES;
683 CorrectOffsets(CurrentParticle);
684 end;
686 if CurrentParticle+2 > MaxParticles then
687 CurrentParticle := 0
688 else
689 CurrentParticle := CurrentParticle+1;
690 end;
691 end;
693 procedure g_GFX_SetMax(Count: Integer);
694 begin
695 if Count > 50000 then
696 Count := 50000;
698 SetLength(Particles, Count);
699 MaxParticles := Count;
700 if CurrentParticle >= Count then
701 CurrentParticle := 0;
702 end;
704 function g_GFX_GetMax(): Integer;
705 begin
706 Result := MaxParticles;
707 end;
709 function FindOnceAnim: DWORD;
710 var
711 i: Integer;
712 begin
713 if OnceAnims <> nil then
714 for i := 0 to High(OnceAnims) do
715 if OnceAnims[i].Animation = nil then
716 begin
717 Result := i;
718 Exit;
719 end;
721 if OnceAnims = nil then
722 begin
723 SetLength(OnceAnims, 16);
724 Result := 0;
725 end
726 else
727 begin
728 Result := High(OnceAnims) + 1;
729 SetLength(OnceAnims, Length(OnceAnims) + 16);
730 end;
731 end;
733 procedure g_GFX_OnceAnim(X, Y: Integer; Anim: TAnimation; AnimType: Byte = 0);
734 var
735 find_id: DWORD;
736 begin
737 if Anim = nil then
738 Exit;
740 find_id := FindOnceAnim();
742 OnceAnims[find_id].AnimType := AnimType;
743 OnceAnims[find_id].Animation := TAnimation.Create(Anim.FramesID, Anim.Loop, Anim.Speed);
744 OnceAnims[find_id].Animation.Blending := Anim.Blending;
745 OnceAnims[find_id].Animation.Alpha := Anim.Alpha;
746 OnceAnims[find_id].X := X;
747 OnceAnims[find_id].Y := Y;
748 end;
750 procedure g_GFX_Update();
751 var
752 a: Integer;
753 w, h: Integer;
754 dX, dY: SmallInt;
755 b, len: Integer;
756 s: ShortInt;
757 c: Byte;
758 begin
759 if Particles <> nil then
760 begin
761 w := gMapInfo.Width;
762 h := gMapInfo.Height;
764 len := High(Particles);
766 for a := 0 to len do
767 if Particles[a].State <> 0 then
768 with Particles[a] do
769 begin
770 if Time = LiveTime then
771 State := STATE_FREE;
772 if (X+1 >= w) or (Y+1 >= h) or (X <= 0) or (Y <= 0) then
773 State := STATE_FREE;
774 if State = STATE_FREE then
775 Continue;
777 case ParticleType of
778 PARTICLE_BLOOD:
779 begin
780 if gAdvBlood then
781 begin
782 if (State = STATE_STICK) then
783 if (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
784 (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) and
785 (not ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)) and
786 (not ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED)) then
787 begin // Îòëèïëà - êàïàåò
788 VelY := 0.5;
789 AccelY := 0.15;
790 State := STATE_NORMAL;
791 end
792 else
793 if Random(200) = 100 then
794 begin // Ïðèëåïëåíà - íî âîçìîæíî ñòåêàåò
795 VelY := 0.5;
796 AccelY := 0.15;
797 Continue;
798 end;
800 if not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED) then
801 begin
802 if ByteBool(gCollideMap[Y, X] and MARK_LIFTUP) then
803 begin // Ëèôò ââåðõ
804 if VelY > -4-Random(3) then
805 VelY := VelY - 0.8;
806 if Abs(VelX) > 0.1 then
807 VelX := VelX - VelX/10.0;
808 VelX := VelX + (Random-Random)*0.2;
809 AccelY := 0.15;
810 end;
811 if ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT) then
812 begin // Ïîòîê âëåâî
813 if VelX > -8-Random(3) then
814 VelX := VelX - 0.8;
815 AccelY := 0.15;
816 end;
817 if ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT) then
818 begin // Ïîòîê âïðàâî
819 if VelX < 8+Random(3) then
820 VelX := VelX + 0.8;
821 AccelY := 0.15;
822 end;
823 end;
825 dX := Round(VelX);
826 dY := Round(VelY);
828 if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) then
829 if (State <> STATE_STICK) and
830 (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
831 (not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)) and
832 (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) then
833 begin // Âèñèò â âîçäóõå - êàïàåò
834 VelY := 0.8;
835 AccelY := 0.5;
836 State := STATE_NORMAL;
837 end;
839 if dX <> 0 then
840 begin
841 if dX > 0 then
842 s := 1
843 else
844 s := -1;
846 dX := Abs(dX);
848 for b := 1 to dX do
849 begin
850 if (X+s >= w) or (X+s <= 0) then
851 begin
852 State := STATE_FREE;
853 Break;
854 end;
856 c := gCollideMap[Y, X+s];
858 if ByteBool(c and MARK_BLOCKED) then
859 begin // Ñòåíà/äâåðü
860 VelX := 0;
861 VelY := 0;
862 AccelX := 0;
863 AccelY := 0;
864 State := STATE_STICK;
865 Break;
866 end;
868 X := X+s;
869 end;
870 end;
872 if dY <> 0 then
873 begin
874 if dY > 0 then
875 s := 1
876 else
877 s := -1;
879 dY := Abs(dY);
881 for b := 1 to dY do
882 begin
883 if (Y+s >= h) or (Y+s <= 0) then
884 begin
885 State := STATE_FREE;
886 Break;
887 end;
889 c := gCollideMap[Y+s, X];
891 if ByteBool(c and MARK_BLOCKED) then
892 begin // Ñòåíà/äâåðü
893 VelX := 0;
894 VelY := 0;
895 AccelX := 0;
896 AccelY := 0;
897 if (s > 0) and (State <> STATE_STICK) then
898 State := STATE_NORMAL
899 else
900 State := STATE_STICK;
901 Break;
902 end;
904 Y := Y+s;
905 end;
906 end;
907 end // if gAdvBlood
908 else
909 begin
910 dX := Round(VelX);
911 dY := Round(VelY);
913 if (X+dX >= w) or (Y+dY >= h) or
914 (X+dX <= 0) or (Y+dY <= 0) or
915 ByteBool(gCollideMap[Y+dY, X+dX] and MARK_BLOCKED) then
916 begin // Ñòåíà/äâåðü/ãðàíèöà
917 State := STATE_FREE;
918 VelX := 0;
919 VelY := 0;
920 end
921 else
922 begin
923 Y := Y + dY;
924 X := X + dX;
925 end;
926 end;
928 VelX := VelX + AccelX;
929 VelY := VelY + AccelY;
931 // Êðîâü ðàñòâîðÿåòñÿ â æèäêîñòè:
932 if ByteBool(gCollideMap[Y, X] and MARK_LIQUID) then
933 begin
934 Inc(Time);
936 Alpha := 255 - Trunc((255.0 * Time) / LiveTime);
937 end;
938 end;
940 PARTICLE_SPARK:
941 begin
942 dX := Round(VelX);
943 dY := Round(VelY);
945 if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) and
946 (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
947 (not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)) and
948 (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) then
949 begin // Âèñèò â âîçäóõå
950 VelY := 0.8;
951 AccelY := 0.5;
952 end;
954 if dX <> 0 then
955 begin
956 if dX > 0 then
957 s := 1
958 else
959 s := -1;
961 dX := Abs(dX);
963 for b := 1 to dX do
964 begin
965 if (X+s >= w) or (X+s <= 0) then
966 begin
967 State := STATE_FREE;
968 Break;
969 end;
971 c := gCollideMap[Y, X+s];
973 if ByteBool(c and MARK_BLOCKED) then
974 begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî
975 VelX := 0;
976 AccelX := 0;
977 Break;
978 end
979 else // Ïóñòî:
980 if c = MARK_FREE then
981 X := X + s
982 else // Îñòàëüíîå:
983 begin
984 State := STATE_FREE;
985 Break;
986 end;
987 end;
988 end;
990 if dY <> 0 then
991 begin
992 if dY > 0 then
993 s := 1
994 else
995 s := -1;
997 dY := Abs(dY);
999 for b := 1 to dY do
1000 begin
1001 if (Y+s >= h) or (Y+s <= 0) then
1002 begin
1003 State := STATE_FREE;
1004 Break;
1005 end;
1007 c := gCollideMap[Y+s, X];
1009 if ByteBool(c and MARK_BLOCKED) then
1010 begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî
1011 if s < 0 then
1012 begin
1013 VelY := -VelY;
1014 AccelY := Abs(AccelY);
1015 end
1016 else // Èëè íå ïàäàåò
1017 begin
1018 VelX := 0;
1019 AccelX := 0;
1020 VelY := 0;
1021 AccelY := 0.8;
1022 end;
1024 Break;
1025 end
1026 else // Ïóñòî:
1027 if c = MARK_FREE then
1028 Y := Y + s
1029 else // Îñàëüíîå:
1030 begin
1031 State := STATE_FREE;
1032 Break;
1033 end;
1034 end;
1035 end;
1037 if VelX <> 0.0 then
1038 VelX := VelX + AccelX;
1039 if VelY <> 0.0 then
1040 begin
1041 if AccelY < 10 then
1042 AccelY := AccelY + 0.08;
1043 VelY := VelY + AccelY;
1044 end;
1046 Time := Time + 1;
1047 end;
1049 PARTICLE_WATER:
1050 begin
1051 if (State = STATE_STICK) and (Random(30) = 15) then
1052 begin // Ñòåêàåò/îòëèïàåò
1053 VelY := 0.5;
1054 AccelY := 0.15;
1055 if (not ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)) and
1056 (not ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED)) then
1057 State := STATE_NORMAL;
1058 Continue;
1059 end;
1061 if not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED) then
1062 begin
1063 if ByteBool(gCollideMap[Y, X] and MARK_LIFTUP) then
1064 begin // Ëèôò ââåðõ
1065 if VelY > -4-Random(3) then
1066 VelY := VelY - 0.8;
1067 if Abs(VelX) > 0.1 then
1068 VelX := VelX - VelX/10.0;
1069 VelX := VelX + (Random-Random)*0.2;
1070 AccelY := 0.15;
1071 end;
1072 if ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT) then
1073 begin // Ïîòîê âëåâî
1074 if VelX > -8-Random(3) then
1075 VelX := VelX - 0.8;
1076 AccelY := 0.15;
1077 end;
1078 if ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT) then
1079 begin // Ïîòîê âïðàâî
1080 if VelX < 8+Random(3) then
1081 VelX := VelX + 0.8;
1082 AccelY := 0.15;
1083 end;
1084 end;
1086 dX := Round(VelX);
1087 dY := Round(VelY);
1089 if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) then
1090 if (State <> STATE_STICK) and
1091 (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
1092 (not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)) and
1093 (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) then
1094 begin // Âèñèò â âîçäóõå - êàïàåò
1095 VelY := 0.8;
1096 AccelY := 0.5;
1097 State := STATE_NORMAL;
1098 end;
1100 if dX <> 0 then
1101 begin
1102 if dX > 0 then
1103 s := 1
1104 else
1105 s := -1;
1107 for b := 1 to Abs(dX) do
1108 begin
1109 if (X+s >= w) or (X+s <= 0) then
1110 begin // Ñáîêó ãðàíèöà
1111 State := STATE_FREE;
1112 Break;
1113 end;
1115 c := gCollideMap[Y, X+s];
1117 if ByteBool(c and MARK_LIQUID) and (dY > 0) then
1118 begin // Ñáîêó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
1119 State := STATE_FREE;
1120 Break;
1121 end;
1123 if ByteBool(c and MARK_BLOCKED) then
1124 begin // Ñòåíà/äâåðü
1125 VelX := 0;
1126 VelY := 0;
1127 AccelX := 0;
1128 AccelY := 0;
1129 State := STATE_STICK;
1130 Break;
1131 end;
1133 X := X+s;
1134 end;
1135 end;
1137 if dY <> 0 then
1138 begin
1139 if dY > 0 then
1140 s := 1
1141 else
1142 s := -1;
1144 for b := 1 to Abs(dY) do
1145 begin
1146 if (Y+s >= h) or (Y+s <= 0) then
1147 begin // Ñíèçó/ñâåðõó ãðàíèöà
1148 State := STATE_FREE;
1149 Break;
1150 end;
1152 c := gCollideMap[Y+s, X];
1154 if ByteBool(c and MARK_LIQUID) and (dY > 0) then
1155 begin // Ñíèçó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
1156 State := STATE_FREE;
1157 Break;
1158 end;
1160 if ByteBool(c and MARK_BLOCKED) then
1161 begin // Ñòåíà/äâåðü
1162 VelX := 0;
1163 VelY := 0;
1164 AccelX := 0;
1165 AccelY := 0;
1166 if (s > 0) and (State <> STATE_STICK) then
1167 State := STATE_NORMAL
1168 else
1169 State := STATE_STICK;
1170 Break;
1171 end;
1173 Y := Y+s;
1174 end;
1175 end;
1177 VelX := VelX + AccelX;
1178 VelY := VelY + AccelY;
1180 Time := Time + 1;
1181 end;
1183 PARTICLE_BUBBLES:
1184 begin
1185 dY := Round(VelY);
1187 if dY <> 0 then
1188 begin
1189 if dY > 0 then
1190 s := 1
1191 else
1192 s := -1;
1194 for b := 1 to Abs(dY) do
1195 begin
1196 if (Y+s >= h) or (Y+s <= 0) then
1197 begin
1198 State := STATE_FREE;
1199 Break;
1200 end;
1202 if not ByteBool(gCollideMap[Y+s, X] and MARK_LIQUID) then
1203 begin // Óæå íå æèäêîñòü
1204 State := STATE_FREE;
1205 Break;
1206 end;
1208 Y := Y+s;
1209 end;
1210 end;
1212 if VelY > -4 then
1213 VelY := VelY + AccelY;
1215 Time := Time + 1;
1216 end;
1217 end; // case
1219 CorrectOffsets(a);
1220 end;
1221 end; // Particles <> nil
1223 if OnceAnims <> nil then
1224 begin
1225 for a := 0 to High(OnceAnims) do
1226 if OnceAnims[a].Animation <> nil then
1227 begin
1228 case OnceAnims[a].AnimType of
1229 ONCEANIM_SMOKE:
1230 begin
1231 if Random(3) = 0 then
1232 OnceAnims[a].X := OnceAnims[a].X-1+Random(3);
1233 if Random(2) = 0 then
1234 OnceAnims[a].Y := OnceAnims[a].Y-Random(2);
1235 end;
1236 end;
1238 if OnceAnims[a].Animation.Played then
1239 begin
1240 OnceAnims[a].Animation.Free();
1241 OnceAnims[a].Animation := nil;
1242 end
1243 else
1244 OnceAnims[a].Animation.Update();
1245 end;
1246 end;
1247 end;
1249 procedure g_GFX_Draw();
1250 var
1251 a, len: Integer;
1252 begin
1253 if Particles <> nil then
1254 begin
1255 glDisable(GL_TEXTURE_2D);
1256 glPointSize(2);
1258 glEnable(GL_BLEND);
1259 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1261 glBegin(GL_POINTS);
1263 len := High(Particles);
1265 for a := 0 to len do
1266 with Particles[a] do
1267 if (State <> STATE_FREE) and (X >= sX) and (Y >= sY) and
1268 (X <= sX+sWidth) and (sY <= sY+sHeight) then
1269 begin
1270 glColor4ub(Red, Green, Blue, Alpha);
1271 glVertex2i(X + offsetX, Y + offsetY);
1272 end;
1274 glEnd();
1276 glDisable(GL_BLEND);
1277 end;
1279 if OnceAnims <> nil then
1280 for a := 0 to High(OnceAnims) do
1281 if OnceAnims[a].Animation <> nil then
1282 with OnceAnims[a] do
1283 Animation.Draw(X, Y, M_NONE);
1284 end;
1286 end.