DEADSOFTWARE

put "{$MODE ...}" directive in each source file; removed trailing spaces, and convert...
[d2df-sdl.git] / src / game / g_gfx.pas
1 {$MODE DELPHI}
2 unit g_gfx;
4 interface
6 uses
7 g_textures;
9 const
10 BLOOD_NORMAL = 0;
11 BLOOD_SPARKS = 1;
12 ONCEANIM_NONE = 0;
13 ONCEANIM_SMOKE = 1;
14 MARK_FREE = 0;
15 MARK_WALL = 1;
16 MARK_WATER = 2;
17 MARK_ACID = 4;
18 MARK_LIFTDOWN = 8;
19 MARK_LIFTUP = 16;
20 MARK_DOOR = 32;
21 MARK_LIFTLEFT = 64;
22 MARK_LIFTRIGHT = 128;
23 MARK_BLOCKED = MARK_WALL + MARK_DOOR;
24 MARK_LIQUID = MARK_WATER + MARK_ACID;
25 MARK_LIFT = MARK_LIFTDOWN + MARK_LIFTUP + MARK_LIFTLEFT + MARK_LIFTRIGHT;
27 procedure g_GFX_Init();
28 procedure g_GFX_Free();
30 procedure g_GFX_Blood(fX, fY: Integer; Count: Word; vx, vy: Integer;
31 DevX, DevY: Word; CR, CG, CB: Byte; Kind: Byte = BLOOD_NORMAL);
32 procedure g_GFX_Spark(fX, fY: Integer; Count: Word; Angle: SmallInt; DevX, DevY: Byte);
33 procedure g_GFX_Water(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DevX, DevY, Color: Byte);
34 procedure g_GFX_SimpleWater(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DefColor, CR, CG, CB: Byte);
35 procedure g_GFX_Bubbles(fX, fY: Integer; Count: Word; DevX, DevY: Byte);
36 procedure g_GFX_SetMax(Count: Integer);
37 function g_GFX_GetMax(): Integer;
39 procedure g_GFX_OnceAnim(X, Y: Integer; Anim: TAnimation; AnimType: Byte = 0);
41 procedure g_Mark(x, y, Width, Height: Integer; t: Byte; st: Boolean);
43 procedure g_GFX_Update();
44 procedure g_GFX_Draw();
46 var
47 gCollideMap: Array of Array of Byte;
49 implementation
51 uses
52 g_map, g_basic, Math, e_graphics, GL, GLExt,
53 g_options, g_console, SysUtils, g_triggers, MAPDEF,
54 g_game, g_language, g_net;
56 type
57 TParticle = record
58 X, Y: Integer;
59 VelX, VelY: Single;
60 AccelX, AccelY: Single;
61 Red, Green, Blue: Byte;
62 Alpha: Byte;
63 Time, LiveTime: Word;
64 State: Byte;
65 ParticleType: Byte;
66 offsetX, offsetY: ShortInt;
67 end;
69 TOnceAnim = record
70 AnimType: Byte;
71 X, Y: Integer;
72 Animation: TAnimation;
73 end;
75 const
76 PARTICLE_BLOOD = 0;
77 PARTICLE_SPARK = 1;
78 PARTICLE_BUBBLES = 2;
79 PARTICLE_WATER = 3;
80 STATE_FREE = 0;
81 STATE_NORMAL = 1;
82 STATE_STICK = 2;
84 var
85 Particles: Array of TParticle;
86 OnceAnims: Array of TOnceAnim;
87 MaxParticles: Integer;
88 CurrentParticle: Integer;
90 procedure g_Mark(x, y, Width, Height: Integer; t: Byte; st: Boolean);
91 var
92 yy, y2, xx, x2: Integer;
93 begin
94 if x < 0 then
95 begin
96 Width := Width + x;
97 x := 0;
98 end;
100 if Width < 0 then
101 Exit;
103 if y < 0 then
104 begin
105 Height := Height + y;
106 y := 0;
107 end;
109 if Height < 0 then
110 Exit;
112 if x > gMapInfo.Width then
113 Exit;
114 if y > gMapInfo.Height then
115 Exit;
117 y2 := y + Height - 1;
118 if y2 > gMapInfo.Height then
119 y2 := gMapInfo.Height;
121 x2 := x + Width - 1;
122 if x2 > gMapInfo.Width then
123 x2 := gMapInfo.Width;
125 if st then
126 begin // Óñòàíîâèòü ïðèçíàê
127 for yy := y to y2 do
128 for xx := x to x2 do
129 gCollideMap[yy][xx] := gCollideMap[yy][xx] or t;
130 end
131 else
132 begin // Óáðàòü ïðèçíàê
133 t := not t;
134 for yy := y to y2 do
135 for xx := x to x2 do
136 gCollideMap[yy][xx] := gCollideMap[yy][xx] and t;
137 end;
138 end;
140 procedure CreateCollideMap();
141 var
142 a: Integer;
143 begin
144 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
145 SetLength(gCollideMap, gMapInfo.Height+1);
146 for a := 0 to High(gCollideMap) do
147 SetLength(gCollideMap[a], gMapInfo.Width+1);
149 if gWater <> nil then
150 begin
151 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 2/6', 0, True);
152 for a := 0 to High(gWater) do
153 with gWater[a] do
154 g_Mark(X, Y, Width, Height, MARK_WATER, True);
155 end;
157 if gAcid1 <> nil then
158 begin
159 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 3/6', 0, True);
160 for a := 0 to High(gAcid1) do
161 with gAcid1[a] do
162 g_Mark(X, Y, Width, Height, MARK_ACID, True);
163 end;
165 if gAcid2 <> nil then
166 begin
167 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 4/6', 0, True);
168 for a := 0 to High(gAcid2) do
169 with gAcid2[a] do
170 g_Mark(X, Y, Width, Height, MARK_ACID, True);
171 end;
173 if gLifts <> nil then
174 begin
175 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 5/6', 0, True);
176 for a := 0 to High(gLifts) do
177 with gLifts[a] do
178 begin
179 g_Mark(X, Y, Width, Height, MARK_LIFT, False);
181 if LiftType = 0 then
182 g_Mark(X, Y, Width, Height, MARK_LIFTUP, True)
183 else if LiftType = 1 then
184 g_Mark(X, Y, Width, Height, MARK_LIFTDOWN, True)
185 else if LiftType = 2 then
186 g_Mark(X, Y, Width, Height, MARK_LIFTLEFT, True)
187 else if LiftType = 3 then
188 g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT, True)
189 end;
190 end;
192 if gWalls <> nil then
193 begin
194 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 6/6', 0, True);
195 for a := 0 to High(gWalls) do
196 begin
197 if gWalls[a].Door then
198 begin
199 // Çàêðûòàÿ äâåðü:
200 if gWalls[a].Enabled then
201 with gWalls[a] do
202 g_Mark(X, Y, Width, Height, MARK_DOOR, True)
203 else // Îòêðûòàÿ äâåðü:
204 if gWalls[a].Enabled then
205 with gWalls[a] do
206 g_Mark(X, Y, Width, Height, MARK_DOOR, False);
207 end
208 else // Ñòåíà
209 with gWalls[a] do
210 g_Mark(X, Y, Width, Height, MARK_WALL, True);
211 end;
212 end;
213 end;
215 procedure g_GFX_Init();
216 begin
217 CreateCollideMap();
218 end;
220 procedure g_GFX_Free();
221 var
222 a: Integer;
223 begin
224 Particles := nil;
225 SetLength(Particles, MaxParticles);
226 CurrentParticle := 0;
228 if OnceAnims <> nil then
229 begin
230 for a := 0 to High(OnceAnims) do
231 OnceAnims[a].Animation.Free();
233 OnceAnims := nil;
234 end;
236 gCollideMap := nil;
237 end;
239 procedure CorrectOffsets(id: Integer);
240 begin
241 with Particles[id] do
242 begin
243 if (X >= 0) and (Y > 0) and
244 (Y < Length(gCollideMap)) and (X < Length(gCollideMap[0])) and
245 (ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) then
246 offsetY := 1 // Ñòåíà ñâåðõó
247 else
248 offsetY := 0;
250 if (X > 0) and (Y >= 0) and
251 (Y < Length(gCollideMap)) and (X < Length(gCollideMap[0])) and
252 (ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)) then
253 offsetX := 1 // Ñòåíà ñëåâà
254 else
255 offsetX := 0;
256 end;
257 end;
259 procedure g_GFX_SparkVel(fX, fY: Integer; Count: Word; VX, VY: Integer; DevX, DevY: Byte);
260 var
261 a: Integer;
262 DevX1, DevX2,
263 DevY1, DevY2: Byte;
264 l: Integer;
265 begin
266 l := Length(Particles);
267 if l = 0 then
268 Exit;
269 if Count > l then
270 Count := l;
272 DevX1 := DevX div 2;
273 DevX2 := DevX + 1;
274 DevY1 := DevY div 2;
275 DevY2 := DevY + 1;
277 for a := 1 to Count do
278 begin
279 with Particles[CurrentParticle] do
280 begin
281 X := fX-DevX1+Random(DevX2);
282 Y := fY-DevY1+Random(DevY2);
284 VelX := VX + (Random-Random)*3;
285 VelY := VY + (Random-Random)*3;
287 if VelY > -4 then
288 if VelY-4 < -4 then
289 VelY := -4
290 else
291 VelY := VelY-4;
293 AccelX := -Sign(VelX)*Random/100;
294 AccelY := 0.8;
296 Red := 255;
297 Green := 100+Random(155);
298 Blue := 64;
299 Alpha := 255;
301 State := STATE_NORMAL;
302 Time := 0;
303 LiveTime := 30+Random(60);
304 ParticleType := PARTICLE_SPARK;
306 CorrectOffsets(CurrentParticle);
307 end;
309 if CurrentParticle+2 > MaxParticles then
310 CurrentParticle := 0
311 else
312 CurrentParticle := CurrentParticle+1;
313 end;
314 end;
316 procedure g_GFX_Blood(fX, fY: Integer; Count: Word; vx, vy: Integer;
317 DevX, DevY: Word; CR, CG, CB: Byte; Kind: Byte = BLOOD_NORMAL);
318 var
319 a: Integer;
320 DevX1, DevX2,
321 DevY1, DevY2: Word;
322 l: Integer;
323 CRnd: Byte;
324 CC: SmallInt;
325 begin
326 if Kind = BLOOD_SPARKS then
327 begin
328 g_GFX_SparkVel(fX, fY, 2 + Random(2), -VX div 2, -VY div 2, DevX, DevY);
329 Exit;
330 end;
331 l := Length(Particles);
332 if l = 0 then
333 Exit;
334 if Count > l then
335 Count := l;
337 DevX1 := DevX div 2;
338 DevX2 := DevX + 1;
339 DevY1 := DevY div 2;
340 DevY2 := DevY + 1;
342 for a := 1 to Count do
343 begin
344 with Particles[CurrentParticle] do
345 begin
346 X := fX - DevX1 + Random(DevX2);
347 Y := fY - DevY1 + Random(DevY2);
349 if (X < 0) or (X > gMapInfo.Width-1) or
350 (Y < 0) or (Y > gMapInfo.Height-1) or
351 ByteBool(gCollideMap[Y, X] and MARK_WALL) then
352 Continue;
354 VelX := vx + (Random-Random)*3;
355 VelY := vy + (Random-Random)*3;
357 if VelY > -4 then
358 if VelY-4 < -4 then
359 VelY := -4
360 else
361 VelY := VelY-4;
363 AccelX := -Sign(VelX)*Random/100;
364 AccelY := 0.8;
366 CRnd := 20*Random(6);
367 if CR > 0 then
368 begin
369 CC := CR + CRnd - 50;
370 if CC < 0 then CC := 0;
371 if CC > 255 then CC := 255;
372 Red := CC;
373 end else
374 Red := 0;
375 if CG > 0 then
376 begin
377 CC := CG + CRnd - 50;
378 if CC < 0 then CC := 0;
379 if CC > 255 then CC := 255;
380 Green := CC;
381 end else
382 Green := 0;
383 if CB > 0 then
384 begin
385 CC := CB + CRnd - 50;
386 if CC < 0 then CC := 0;
387 if CC > 255 then CC := 255;
388 Blue := CC;
389 end else
390 Blue := 0;
392 Alpha := 255;
394 State := STATE_NORMAL;
395 Time := 0;
396 LiveTime := 120+Random(40);
397 ParticleType := PARTICLE_BLOOD;
399 CorrectOffsets(CurrentParticle);
400 end;
402 if CurrentParticle >= MaxParticles-1 then
403 CurrentParticle := 0
404 else
405 CurrentParticle := CurrentParticle+1;
406 end;
407 end;
409 procedure g_GFX_Spark(fX, fY: Integer; Count: Word; Angle: SmallInt; DevX, DevY: Byte);
410 var
411 a: Integer;
412 b: Single;
413 DevX1, DevX2,
414 DevY1, DevY2: Byte;
415 BaseVelX, BaseVelY: Single;
416 l: Integer;
417 begin
418 l := Length(Particles);
419 if l = 0 then
420 Exit;
421 if Count > l then
422 Count := l;
424 Angle := 360 - Angle;
426 DevX1 := DevX div 2;
427 DevX2 := DevX + 1;
428 DevY1 := DevY div 2;
429 DevY2 := DevY + 1;
431 b := DegToRad(Angle);
432 BaseVelX := cos(b);
433 BaseVelY := 1.6*sin(b);
434 if Abs(BaseVelX) < 0.01 then
435 BaseVelX := 0.0;
436 if Abs(BaseVelY) < 0.01 then
437 BaseVelY := 0.0;
438 for a := 1 to Count do
439 begin
440 with Particles[CurrentParticle] do
441 begin
442 X := fX-DevX1+Random(DevX2);
443 Y := fY-DevY1+Random(DevY2);
445 VelX := BaseVelX*Random;
446 VelY := BaseVelY-Random;
447 AccelX := VelX/3.0;
448 AccelY := VelY/5.0;
450 Red := 255;
451 Green := 100+Random(155);
452 Blue := 64;
453 Alpha := 255;
455 State := STATE_NORMAL;
456 Time := 0;
457 LiveTime := 30+Random(60);
458 ParticleType := PARTICLE_SPARK;
460 CorrectOffsets(CurrentParticle);
461 end;
463 if CurrentParticle+2 > MaxParticles then
464 CurrentParticle := 0
465 else
466 CurrentParticle := CurrentParticle+1;
467 end;
468 end;
470 procedure g_GFX_Water(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DevX, DevY, Color: Byte);
471 var
472 a: Integer;
473 DevX1, DevX2,
474 DevY1, DevY2: Byte;
475 l: Integer;
476 begin
477 l := Length(Particles);
478 if l = 0 then
479 Exit;
480 if Count > l then
481 Count := l;
483 if Abs(fVelX) < 3.0 then
484 fVelX := 3.0 - 6.0*Random;
486 DevX1 := DevX div 2;
487 DevX2 := DevX + 1;
488 DevY1 := DevY div 2;
489 DevY2 := DevY + 1;
491 for a := 1 to Count do
492 begin
493 with Particles[CurrentParticle] do
494 begin
495 X := fX-DevX1+Random(DevX2);
496 Y := fY-DevY1+Random(DevY2);
498 if Abs(fVelX) < 0.5 then
499 VelX := 1.0 - 2.0*Random
500 else
501 VelX := fVelX*Random;
502 if Random(10) < 7 then
503 VelX := -VelX;
504 VelY := fVelY*Random;
505 AccelX := 0.0;
506 AccelY := 0.8;
508 case Color of
509 1: // Êðàñíûé
510 begin
511 Red := 155 + Random(9)*10;
512 Green := Trunc(150*Random);
513 Blue := Green;
514 end;
515 2: // Çåëåíûé
516 begin
517 Red := Trunc(150*Random);
518 Green := 175 + Random(9)*10;
519 Blue := Red;
520 end;
521 3: // Ñèíèé
522 begin
523 Red := Trunc(200*Random);
524 Green := Red;
525 Blue := 175 + Random(9)*10;
526 end;
527 else // Ñåðûé
528 begin
529 Red := 90 + Random(12)*10;
530 Green := Red;
531 Blue := Red;
532 end;
533 end;
535 Alpha := 255;
537 State := STATE_NORMAL;
538 Time := 0;
539 LiveTime := 60+Random(60);
540 ParticleType := PARTICLE_WATER;
542 CorrectOffsets(CurrentParticle);
543 end;
545 if CurrentParticle+2 > MaxParticles then
546 CurrentParticle := 0
547 else
548 CurrentParticle := CurrentParticle+1;
549 end;
550 end;
552 procedure g_GFX_SimpleWater(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DefColor, CR, CG, CB: Byte);
553 var
554 a: Integer;
555 l: Integer;
556 begin
557 l := Length(Particles);
558 if l = 0 then
559 Exit;
560 if Count > l then
561 Count := l;
563 for a := 1 to Count do
564 begin
565 with Particles[CurrentParticle] do
566 begin
567 X := fX;
568 Y := fY;
570 VelX := fVelX;
571 VelY := fVelY;
572 AccelX := 0.0;
573 AccelY := 0.8;
575 case DefColor of
576 1: // Êðàñíûé
577 begin
578 Red := 155 + Random(9)*10;
579 Green := Trunc(150*Random);
580 Blue := Green;
581 end;
582 2: // Çåëåíûé
583 begin
584 Red := Trunc(150*Random);
585 Green := 175 + Random(9)*10;
586 Blue := Red;
587 end;
588 3: // Ñèíèé
589 begin
590 Red := Trunc(200*Random);
591 Green := Red;
592 Blue := 175 + Random(9)*10;
593 end;
594 4: // Ñâîé öâåò, ñâåòëåå
595 begin
596 Red := 20 + Random(19)*10;
597 Green := Red;
598 Blue := Red;
599 Red := Min(Red + CR, 255);
600 Green := Min(Green + CG, 255);
601 Blue := Min(Blue + CB, 255);
602 end;
603 5: // Ñâîé öâåò, òåìíåå
604 begin
605 Red := 20 + Random(19)*10;
606 Green := Red;
607 Blue := Red;
608 Red := Max(CR - Red, 0);
609 Green := Max(CG - Green, 0);
610 Blue := Max(CB - Blue, 0);
611 end;
612 else // Ñåðûé
613 begin
614 Red := 90 + Random(12)*10;
615 Green := Red;
616 Blue := Red;
617 end;
618 end;
620 Alpha := 255;
622 State := STATE_NORMAL;
623 Time := 0;
624 LiveTime := 60+Random(60);
625 ParticleType := PARTICLE_WATER;
627 CorrectOffsets(CurrentParticle);
628 end;
630 if CurrentParticle+2 > MaxParticles then
631 CurrentParticle := 0
632 else
633 CurrentParticle := CurrentParticle+1;
634 end;
635 end;
637 procedure g_GFX_Bubbles(fX, fY: Integer; Count: Word; DevX, DevY: Byte);
638 var
639 a: Integer;
640 DevX1, DevX2,
641 DevY1, DevY2: Byte;
642 l: Integer;
643 begin
644 l := Length(Particles);
645 if l = 0 then
646 Exit;
647 if Count > l then
648 Count := l;
650 DevX1 := DevX div 2;
651 DevX2 := DevX + 1;
652 DevY1 := DevY div 2;
653 DevY2 := DevY + 1;
655 for a := 1 to Count do
656 begin
657 with Particles[CurrentParticle] do
658 begin
659 X := fX-DevX1+Random(DevX2);
660 Y := fY-DevY1+Random(DevY2);
662 if (X >= gMapInfo.Width) or (X <= 0) or
663 (Y >= gMapInfo.Height) or (Y <= 0) then
664 Continue;
666 if not ByteBool(gCollideMap[Y, X] and MARK_LIQUID) then
667 Continue;
669 VelX := 0;
670 VelY := -1-Random;
671 AccelX := 0;
672 AccelY := VelY/10;
674 Red := 255;
675 Green := 255;
676 Blue := 255;
677 Alpha := 255;
679 State := STATE_NORMAL;
680 Time := 0;
681 LiveTime := 65535;
682 ParticleType := PARTICLE_BUBBLES;
684 CorrectOffsets(CurrentParticle);
685 end;
687 if CurrentParticle+2 > MaxParticles then
688 CurrentParticle := 0
689 else
690 CurrentParticle := CurrentParticle+1;
691 end;
692 end;
694 procedure g_GFX_SetMax(Count: Integer);
695 begin
696 if Count > 50000 then
697 Count := 50000;
699 SetLength(Particles, Count);
700 MaxParticles := Count;
701 if CurrentParticle >= Count then
702 CurrentParticle := 0;
703 end;
705 function g_GFX_GetMax(): Integer;
706 begin
707 Result := MaxParticles;
708 end;
710 function FindOnceAnim: DWORD;
711 var
712 i: Integer;
713 begin
714 if OnceAnims <> nil then
715 for i := 0 to High(OnceAnims) do
716 if OnceAnims[i].Animation = nil then
717 begin
718 Result := i;
719 Exit;
720 end;
722 if OnceAnims = nil then
723 begin
724 SetLength(OnceAnims, 16);
725 Result := 0;
726 end
727 else
728 begin
729 Result := High(OnceAnims) + 1;
730 SetLength(OnceAnims, Length(OnceAnims) + 16);
731 end;
732 end;
734 procedure g_GFX_OnceAnim(X, Y: Integer; Anim: TAnimation; AnimType: Byte = 0);
735 var
736 find_id: DWORD;
737 begin
738 if Anim = nil then
739 Exit;
741 find_id := FindOnceAnim();
743 OnceAnims[find_id].AnimType := AnimType;
744 OnceAnims[find_id].Animation := TAnimation.Create(Anim.FramesID, Anim.Loop, Anim.Speed);
745 OnceAnims[find_id].Animation.Blending := Anim.Blending;
746 OnceAnims[find_id].Animation.Alpha := Anim.Alpha;
747 OnceAnims[find_id].X := X;
748 OnceAnims[find_id].Y := Y;
749 end;
751 procedure g_GFX_Update();
752 var
753 a: Integer;
754 w, h: Integer;
755 dX, dY: SmallInt;
756 b, len: Integer;
757 s: ShortInt;
758 c: Byte;
759 begin
760 if Particles <> nil then
761 begin
762 w := gMapInfo.Width;
763 h := gMapInfo.Height;
765 len := High(Particles);
767 for a := 0 to len do
768 if Particles[a].State <> 0 then
769 with Particles[a] do
770 begin
771 if Time = LiveTime then
772 State := STATE_FREE;
773 if (X+1 >= w) or (Y+1 >= h) or (X <= 0) or (Y <= 0) then
774 State := STATE_FREE;
775 if State = STATE_FREE then
776 Continue;
778 case ParticleType of
779 PARTICLE_BLOOD:
780 begin
781 if gAdvBlood then
782 begin
783 if (State = STATE_STICK) then
784 if (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
785 (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) and
786 (not ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)) and
787 (not ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED)) then
788 begin // Îòëèïëà - êàïàåò
789 VelY := 0.5;
790 AccelY := 0.15;
791 State := STATE_NORMAL;
792 end
793 else
794 if Random(200) = 100 then
795 begin // Ïðèëåïëåíà - íî âîçìîæíî ñòåêàåò
796 VelY := 0.5;
797 AccelY := 0.15;
798 Continue;
799 end;
801 if not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED) then
802 begin
803 if ByteBool(gCollideMap[Y, X] and MARK_LIFTUP) then
804 begin // Ëèôò ââåðõ
805 if VelY > -4-Random(3) then
806 VelY := VelY - 0.8;
807 if Abs(VelX) > 0.1 then
808 VelX := VelX - VelX/10.0;
809 VelX := VelX + (Random-Random)*0.2;
810 AccelY := 0.15;
811 end;
812 if ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT) then
813 begin // Ïîòîê âëåâî
814 if VelX > -8-Random(3) then
815 VelX := VelX - 0.8;
816 AccelY := 0.15;
817 end;
818 if ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT) then
819 begin // Ïîòîê âïðàâî
820 if VelX < 8+Random(3) then
821 VelX := VelX + 0.8;
822 AccelY := 0.15;
823 end;
824 end;
826 dX := Round(VelX);
827 dY := Round(VelY);
829 if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) then
830 if (State <> STATE_STICK) and
831 (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
832 (not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)) and
833 (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) then
834 begin // Âèñèò â âîçäóõå - êàïàåò
835 VelY := 0.8;
836 AccelY := 0.5;
837 State := STATE_NORMAL;
838 end;
840 if dX <> 0 then
841 begin
842 if dX > 0 then
843 s := 1
844 else
845 s := -1;
847 dX := Abs(dX);
849 for b := 1 to dX do
850 begin
851 if (X+s >= w) or (X+s <= 0) then
852 begin
853 State := STATE_FREE;
854 Break;
855 end;
857 c := gCollideMap[Y, X+s];
859 if ByteBool(c and MARK_BLOCKED) then
860 begin // Ñòåíà/äâåðü
861 VelX := 0;
862 VelY := 0;
863 AccelX := 0;
864 AccelY := 0;
865 State := STATE_STICK;
866 Break;
867 end;
869 X := X+s;
870 end;
871 end;
873 if dY <> 0 then
874 begin
875 if dY > 0 then
876 s := 1
877 else
878 s := -1;
880 dY := Abs(dY);
882 for b := 1 to dY do
883 begin
884 if (Y+s >= h) or (Y+s <= 0) then
885 begin
886 State := STATE_FREE;
887 Break;
888 end;
890 c := gCollideMap[Y+s, X];
892 if ByteBool(c and MARK_BLOCKED) then
893 begin // Ñòåíà/äâåðü
894 VelX := 0;
895 VelY := 0;
896 AccelX := 0;
897 AccelY := 0;
898 if (s > 0) and (State <> STATE_STICK) then
899 State := STATE_NORMAL
900 else
901 State := STATE_STICK;
902 Break;
903 end;
905 Y := Y+s;
906 end;
907 end;
908 end // if gAdvBlood
909 else
910 begin
911 dX := Round(VelX);
912 dY := Round(VelY);
914 if (X+dX >= w) or (Y+dY >= h) or
915 (X+dX <= 0) or (Y+dY <= 0) or
916 ByteBool(gCollideMap[Y+dY, X+dX] and MARK_BLOCKED) then
917 begin // Ñòåíà/äâåðü/ãðàíèöà
918 State := STATE_FREE;
919 VelX := 0;
920 VelY := 0;
921 end
922 else
923 begin
924 Y := Y + dY;
925 X := X + dX;
926 end;
927 end;
929 VelX := VelX + AccelX;
930 VelY := VelY + AccelY;
932 // Êðîâü ðàñòâîðÿåòñÿ â æèäêîñòè:
933 if ByteBool(gCollideMap[Y, X] and MARK_LIQUID) then
934 begin
935 Inc(Time);
937 Alpha := 255 - Trunc((255.0 * Time) / LiveTime);
938 end;
939 end;
941 PARTICLE_SPARK:
942 begin
943 dX := Round(VelX);
944 dY := Round(VelY);
946 if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) and
947 (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
948 (not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)) and
949 (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) then
950 begin // Âèñèò â âîçäóõå
951 VelY := 0.8;
952 AccelY := 0.5;
953 end;
955 if dX <> 0 then
956 begin
957 if dX > 0 then
958 s := 1
959 else
960 s := -1;
962 dX := Abs(dX);
964 for b := 1 to dX do
965 begin
966 if (X+s >= w) or (X+s <= 0) then
967 begin
968 State := STATE_FREE;
969 Break;
970 end;
972 c := gCollideMap[Y, X+s];
974 if ByteBool(c and MARK_BLOCKED) then
975 begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî
976 VelX := 0;
977 AccelX := 0;
978 Break;
979 end
980 else // Ïóñòî:
981 if c = MARK_FREE then
982 X := X + s
983 else // Îñòàëüíîå:
984 begin
985 State := STATE_FREE;
986 Break;
987 end;
988 end;
989 end;
991 if dY <> 0 then
992 begin
993 if dY > 0 then
994 s := 1
995 else
996 s := -1;
998 dY := Abs(dY);
1000 for b := 1 to dY do
1001 begin
1002 if (Y+s >= h) or (Y+s <= 0) then
1003 begin
1004 State := STATE_FREE;
1005 Break;
1006 end;
1008 c := gCollideMap[Y+s, X];
1010 if ByteBool(c and MARK_BLOCKED) then
1011 begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî
1012 if s < 0 then
1013 begin
1014 VelY := -VelY;
1015 AccelY := Abs(AccelY);
1016 end
1017 else // Èëè íå ïàäàåò
1018 begin
1019 VelX := 0;
1020 AccelX := 0;
1021 VelY := 0;
1022 AccelY := 0.8;
1023 end;
1025 Break;
1026 end
1027 else // Ïóñòî:
1028 if c = MARK_FREE then
1029 Y := Y + s
1030 else // Îñàëüíîå:
1031 begin
1032 State := STATE_FREE;
1033 Break;
1034 end;
1035 end;
1036 end;
1038 if VelX <> 0.0 then
1039 VelX := VelX + AccelX;
1040 if VelY <> 0.0 then
1041 begin
1042 if AccelY < 10 then
1043 AccelY := AccelY + 0.08;
1044 VelY := VelY + AccelY;
1045 end;
1047 Time := Time + 1;
1048 end;
1050 PARTICLE_WATER:
1051 begin
1052 if (State = STATE_STICK) and (Random(30) = 15) then
1053 begin // Ñòåêàåò/îòëèïàåò
1054 VelY := 0.5;
1055 AccelY := 0.15;
1056 if (not ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)) and
1057 (not ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED)) then
1058 State := STATE_NORMAL;
1059 Continue;
1060 end;
1062 if not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED) then
1063 begin
1064 if ByteBool(gCollideMap[Y, X] and MARK_LIFTUP) then
1065 begin // Ëèôò ââåðõ
1066 if VelY > -4-Random(3) then
1067 VelY := VelY - 0.8;
1068 if Abs(VelX) > 0.1 then
1069 VelX := VelX - VelX/10.0;
1070 VelX := VelX + (Random-Random)*0.2;
1071 AccelY := 0.15;
1072 end;
1073 if ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT) then
1074 begin // Ïîòîê âëåâî
1075 if VelX > -8-Random(3) then
1076 VelX := VelX - 0.8;
1077 AccelY := 0.15;
1078 end;
1079 if ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT) then
1080 begin // Ïîòîê âïðàâî
1081 if VelX < 8+Random(3) then
1082 VelX := VelX + 0.8;
1083 AccelY := 0.15;
1084 end;
1085 end;
1087 dX := Round(VelX);
1088 dY := Round(VelY);
1090 if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) then
1091 if (State <> STATE_STICK) and
1092 (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
1093 (not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)) and
1094 (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) then
1095 begin // Âèñèò â âîçäóõå - êàïàåò
1096 VelY := 0.8;
1097 AccelY := 0.5;
1098 State := STATE_NORMAL;
1099 end;
1101 if dX <> 0 then
1102 begin
1103 if dX > 0 then
1104 s := 1
1105 else
1106 s := -1;
1108 for b := 1 to Abs(dX) do
1109 begin
1110 if (X+s >= w) or (X+s <= 0) then
1111 begin // Ñáîêó ãðàíèöà
1112 State := STATE_FREE;
1113 Break;
1114 end;
1116 c := gCollideMap[Y, X+s];
1118 if ByteBool(c and MARK_LIQUID) and (dY > 0) then
1119 begin // Ñáîêó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
1120 State := STATE_FREE;
1121 Break;
1122 end;
1124 if ByteBool(c and MARK_BLOCKED) then
1125 begin // Ñòåíà/äâåðü
1126 VelX := 0;
1127 VelY := 0;
1128 AccelX := 0;
1129 AccelY := 0;
1130 State := STATE_STICK;
1131 Break;
1132 end;
1134 X := X+s;
1135 end;
1136 end;
1138 if dY <> 0 then
1139 begin
1140 if dY > 0 then
1141 s := 1
1142 else
1143 s := -1;
1145 for b := 1 to Abs(dY) do
1146 begin
1147 if (Y+s >= h) or (Y+s <= 0) then
1148 begin // Ñíèçó/ñâåðõó ãðàíèöà
1149 State := STATE_FREE;
1150 Break;
1151 end;
1153 c := gCollideMap[Y+s, X];
1155 if ByteBool(c and MARK_LIQUID) and (dY > 0) then
1156 begin // Ñíèçó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
1157 State := STATE_FREE;
1158 Break;
1159 end;
1161 if ByteBool(c and MARK_BLOCKED) then
1162 begin // Ñòåíà/äâåðü
1163 VelX := 0;
1164 VelY := 0;
1165 AccelX := 0;
1166 AccelY := 0;
1167 if (s > 0) and (State <> STATE_STICK) then
1168 State := STATE_NORMAL
1169 else
1170 State := STATE_STICK;
1171 Break;
1172 end;
1174 Y := Y+s;
1175 end;
1176 end;
1178 VelX := VelX + AccelX;
1179 VelY := VelY + AccelY;
1181 Time := Time + 1;
1182 end;
1184 PARTICLE_BUBBLES:
1185 begin
1186 dY := Round(VelY);
1188 if dY <> 0 then
1189 begin
1190 if dY > 0 then
1191 s := 1
1192 else
1193 s := -1;
1195 for b := 1 to Abs(dY) do
1196 begin
1197 if (Y+s >= h) or (Y+s <= 0) then
1198 begin
1199 State := STATE_FREE;
1200 Break;
1201 end;
1203 if not ByteBool(gCollideMap[Y+s, X] and MARK_LIQUID) then
1204 begin // Óæå íå æèäêîñòü
1205 State := STATE_FREE;
1206 Break;
1207 end;
1209 Y := Y+s;
1210 end;
1211 end;
1213 if VelY > -4 then
1214 VelY := VelY + AccelY;
1216 Time := Time + 1;
1217 end;
1218 end; // case
1220 CorrectOffsets(a);
1221 end;
1222 end; // Particles <> nil
1224 if OnceAnims <> nil then
1225 begin
1226 for a := 0 to High(OnceAnims) do
1227 if OnceAnims[a].Animation <> nil then
1228 begin
1229 case OnceAnims[a].AnimType of
1230 ONCEANIM_SMOKE:
1231 begin
1232 if Random(3) = 0 then
1233 OnceAnims[a].X := OnceAnims[a].X-1+Random(3);
1234 if Random(2) = 0 then
1235 OnceAnims[a].Y := OnceAnims[a].Y-Random(2);
1236 end;
1237 end;
1239 if OnceAnims[a].Animation.Played then
1240 begin
1241 OnceAnims[a].Animation.Free();
1242 OnceAnims[a].Animation := nil;
1243 end
1244 else
1245 OnceAnims[a].Animation.Update();
1246 end;
1247 end;
1248 end;
1250 procedure g_GFX_Draw();
1251 var
1252 a, len: Integer;
1253 begin
1254 if Particles <> nil then
1255 begin
1256 glDisable(GL_TEXTURE_2D);
1257 glPointSize(2);
1259 glEnable(GL_BLEND);
1260 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1262 glBegin(GL_POINTS);
1264 len := High(Particles);
1266 for a := 0 to len do
1267 with Particles[a] do
1268 if (State <> STATE_FREE) and (X >= sX) and (Y >= sY) and
1269 (X <= sX+sWidth) and (sY <= sY+sHeight) then
1270 begin
1271 glColor4ub(Red, Green, Blue, Alpha);
1272 glVertex2i(X + offsetX, Y + offsetY);
1273 end;
1275 glEnd();
1277 glDisable(GL_BLEND);
1278 end;
1280 if OnceAnims <> nil then
1281 for a := 0 to High(OnceAnims) do
1282 if OnceAnims[a].Animation <> nil then
1283 with OnceAnims[a] do
1284 Animation.Draw(X, Y, M_NONE);
1285 end;
1287 end.