DEADSOFTWARE

removed some unused code
[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 {$INCLUDE ../shared/a_modes.inc}
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();
62 implementation
64 uses
65 g_map, g_basic, Math, e_graphics, GL, GLExt,
66 g_options, g_console, SysUtils, g_triggers, MAPDEF,
67 g_game, g_language, g_net;
69 type
70 PParticle = ^TParticle;
71 TParticle = record
72 X, Y: Integer;
73 VelX, VelY: Single;
74 AccelX, AccelY: Single;
75 Red, Green, Blue: Byte;
76 Alpha: Byte;
77 Time, LiveTime: Word;
78 State: Byte;
79 ParticleType: Byte;
80 offsetX, offsetY: ShortInt;
81 end;
83 TOnceAnim = record
84 AnimType: Byte;
85 X, Y: Integer;
86 Animation: TAnimation;
87 end;
89 const
90 PARTICLE_BLOOD = 0;
91 PARTICLE_SPARK = 1;
92 PARTICLE_BUBBLES = 2;
93 PARTICLE_WATER = 3;
94 STATE_FREE = 0;
95 STATE_NORMAL = 1;
96 STATE_STICK = 2;
98 var
99 Particles: Array of TParticle;
100 OnceAnims: Array of TOnceAnim;
101 MaxParticles: Integer;
102 CurrentParticle: Integer;
105 function isBlockedAt (x, y: Integer; w: Integer=1; h: Integer=1): Boolean; inline;
106 begin
107 result := g_Map_CollidePanel(x, y, w, h, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
108 end;
111 // ???
112 function isWallAt (x, y: Integer; w: Integer=1; h: Integer=1): Boolean; inline;
113 begin
114 result := g_Map_CollidePanel(x, y, w, h, (PANEL_WALL or PANEL_STEP));
115 end;
118 function isLiftUpAt (x, y: Integer; w: Integer=1; h: Integer=1): Boolean; inline;
119 begin
120 result := g_Map_CollidePanel(x, y, w, h, PANEL_LIFTUP);
121 end;
123 function isLiftDownAt (x, y: Integer; w: Integer=1; h: Integer=1): Boolean; inline;
124 begin
125 result := g_Map_CollidePanel(x, y, w, h, PANEL_LIFTDOWN);
126 end;
128 function isLiftLeftAt (x, y: Integer; w: Integer=1; h: Integer=1): Boolean; inline;
129 begin
130 result := g_Map_CollidePanel(x, y, w, h, PANEL_LIFTLEFT);
131 end;
133 function isLiftRightAt (x, y: Integer; w: Integer=1; h: Integer=1): Boolean; inline;
134 begin
135 result := g_Map_CollidePanel(x, y, w, h, PANEL_LIFTRIGHT);
136 end;
139 function isLiquidAt (x, y: Integer; w: Integer=1; h: Integer=1): Boolean; inline;
140 begin
141 result := g_Map_CollidePanel(x, y, w, h, (PANEL_WATER or PANEL_ACID1 or PANEL_ACID2));
142 end;
145 function isAnythingAt (x, y: Integer; w: Integer=1; h: Integer=1): Boolean; inline;
146 begin
147 result := g_Map_CollidePanel(x, y, w, h, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_OPENDOOR or PANEL_WATER or PANEL_ACID1 or PANEL_ACID2 or PANEL_STEP or PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT));
148 end;
151 {$IF DEFINED(HAS_COLLIDE_BITMAP)}
152 procedure g_Mark(x, y, Width, Height: Integer; t: Byte; st: Boolean);
153 var
154 yy, y2, xx, x2: Integer;
155 begin
156 if x < 0 then
157 begin
158 Width := Width + x;
159 x := 0;
160 end;
162 if Width < 0 then
163 Exit;
165 if y < 0 then
166 begin
167 Height := Height + y;
168 y := 0;
169 end;
171 if Height < 0 then
172 Exit;
174 if x > gMapInfo.Width then
175 Exit;
176 if y > gMapInfo.Height then
177 Exit;
179 y2 := y + Height - 1;
180 if y2 > gMapInfo.Height then
181 y2 := gMapInfo.Height;
183 x2 := x + Width - 1;
184 if x2 > gMapInfo.Width then
185 x2 := gMapInfo.Width;
187 if st then
188 begin // Óñòàíîâèòü ïðèçíàê
189 for yy := y to y2 do
190 for xx := x to x2 do
191 gCollideMap[yy][xx] := gCollideMap[yy][xx] or t;
192 end
193 else
194 begin // Óáðàòü ïðèçíàê
195 t := not t;
196 for yy := y to y2 do
197 for xx := x to x2 do
198 gCollideMap[yy][xx] := gCollideMap[yy][xx] and t;
199 end;
200 end;
201 {$ENDIF}
204 {$IF DEFINED(HAS_COLLIDE_BITMAP)}
205 procedure CreateCollideMap();
206 var
207 a: Integer;
208 begin
209 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
210 SetLength(gCollideMap, gMapInfo.Height+1);
211 for a := 0 to High(gCollideMap) do
212 SetLength(gCollideMap[a], gMapInfo.Width+1);
214 if gWater <> nil then
215 begin
216 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 2/6', 0, True);
217 for a := 0 to High(gWater) do
218 with gWater[a] do
219 g_Mark(X, Y, Width, Height, MARK_WATER, True);
220 end;
222 if gAcid1 <> nil then
223 begin
224 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 3/6', 0, True);
225 for a := 0 to High(gAcid1) do
226 with gAcid1[a] do
227 g_Mark(X, Y, Width, Height, MARK_ACID, True);
228 end;
230 if gAcid2 <> nil then
231 begin
232 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 4/6', 0, True);
233 for a := 0 to High(gAcid2) do
234 with gAcid2[a] do
235 g_Mark(X, Y, Width, Height, MARK_ACID, True);
236 end;
238 if gLifts <> nil then
239 begin
240 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 5/6', 0, True);
241 for a := 0 to High(gLifts) do
242 with gLifts[a] do
243 begin
244 g_Mark(X, Y, Width, Height, MARK_LIFT, False);
246 if LiftType = 0 then
247 g_Mark(X, Y, Width, Height, MARK_LIFTUP, True)
248 else if LiftType = 1 then
249 g_Mark(X, Y, Width, Height, MARK_LIFTDOWN, True)
250 else if LiftType = 2 then
251 g_Mark(X, Y, Width, Height, MARK_LIFTLEFT, True)
252 else if LiftType = 3 then
253 g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT, True)
254 end;
255 end;
257 if gWalls <> nil then
258 begin
259 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 6/6', 0, True);
260 for a := 0 to High(gWalls) do
261 begin
262 if gWalls[a].Door then
263 begin
264 // Çàêðûòàÿ äâåðü:
265 if gWalls[a].Enabled then
266 with gWalls[a] do
267 g_Mark(X, Y, Width, Height, MARK_DOOR, True)
268 else // Îòêðûòàÿ äâåðü:
269 if gWalls[a].Enabled then
270 with gWalls[a] do
271 g_Mark(X, Y, Width, Height, MARK_DOOR, False);
272 end
273 else // Ñòåíà
274 with gWalls[a] do
275 g_Mark(X, Y, Width, Height, MARK_WALL, True);
276 end;
277 end;
278 end;
279 {$ENDIF}
282 procedure g_GFX_Init();
283 begin
284 //CreateCollideMap();
285 end;
288 procedure g_GFX_Free();
289 var
290 a: Integer;
291 begin
292 Particles := nil;
293 SetLength(Particles, MaxParticles);
294 CurrentParticle := 0;
296 if OnceAnims <> nil then
297 begin
298 for a := 0 to High(OnceAnims) do
299 OnceAnims[a].Animation.Free();
301 OnceAnims := nil;
302 end;
303 end;
306 procedure CorrectOffsets(id: Integer);
307 var
308 part: PParticle;
309 begin
310 part := @Particles[id];
311 part.offsetX := 0;
312 part.offsetY := 0;
313 // check for upper wall
314 if isBlockedAt(part.X, part.Y-1) then part.offsetY := 1;
315 // check for left wall
316 if isBlockedAt(part.X-1, part.Y) then part.offsetX := 1;
317 end;
320 procedure g_GFX_SparkVel (fX, fY: Integer; Count: Word; VX, VY: Integer; DevX, DevY: Byte);
321 var
322 a: Integer;
323 DevX1, DevX2,
324 DevY1, DevY2: Byte;
325 l: Integer;
326 begin
327 l := Length(Particles);
328 if l = 0 then exit;
329 if Count > l then Count := l;
331 DevX1 := DevX div 2;
332 DevX2 := DevX + 1;
333 DevY1 := DevY div 2;
334 DevY2 := DevY + 1;
336 for a := 1 to Count do
337 begin
338 with Particles[CurrentParticle] do
339 begin
340 X := fX-DevX1+Random(DevX2);
341 Y := fY-DevY1+Random(DevY2);
343 VelX := VX + (Random-Random)*3;
344 VelY := VY + (Random-Random)*3;
346 if VelY > -4 then
347 if VelY-4 < -4 then
348 VelY := -4
349 else
350 VelY := VelY-4;
352 AccelX := -Sign(VelX)*Random/100;
353 AccelY := 0.8;
355 Red := 255;
356 Green := 100+Random(155);
357 Blue := 64;
358 Alpha := 255;
360 State := STATE_NORMAL;
361 Time := 0;
362 LiveTime := 30+Random(60);
363 ParticleType := PARTICLE_SPARK;
365 CorrectOffsets(CurrentParticle);
366 end;
368 if CurrentParticle+2 > MaxParticles then
369 CurrentParticle := 0
370 else
371 CurrentParticle := CurrentParticle+1;
372 end;
373 end;
376 procedure g_GFX_Blood(fX, fY: Integer; Count: Word; vx, vy: Integer;
377 DevX, DevY: Word; CR, CG, CB: Byte; Kind: Byte = BLOOD_NORMAL);
378 var
379 a: Integer;
380 DevX1, DevX2,
381 DevY1, DevY2: Word;
382 l: Integer;
383 CRnd: Byte;
384 CC: SmallInt;
385 begin
386 if Kind = BLOOD_SPARKS then
387 begin
388 g_GFX_SparkVel(fX, fY, 2 + Random(2), -VX div 2, -VY div 2, DevX, DevY);
389 Exit;
390 end;
391 l := Length(Particles);
392 if l = 0 then
393 Exit;
394 if Count > l then
395 Count := l;
397 DevX1 := DevX div 2;
398 DevX2 := DevX + 1;
399 DevY1 := DevY div 2;
400 DevY2 := DevY + 1;
402 for a := 1 to Count do
403 begin
404 with Particles[CurrentParticle] do
405 begin
406 X := fX - DevX1 + Random(DevX2);
407 Y := fY - DevY1 + Random(DevY2);
410 if (X < 0) or (X > gMapInfo.Width-1) or
411 (Y < 0) or (Y > gMapInfo.Height-1) or
412 ByteBool(gCollideMap[Y, X] and MARK_WALL) then
413 Continue;
415 if isWallAt(X, Y) then continue;
417 VelX := vx + (Random-Random)*3;
418 VelY := vy + (Random-Random)*3;
420 if VelY > -4 then
421 if VelY-4 < -4 then
422 VelY := -4
423 else
424 VelY := VelY-4;
426 AccelX := -Sign(VelX)*Random/100;
427 AccelY := 0.8;
429 CRnd := 20*Random(6);
430 if CR > 0 then
431 begin
432 CC := CR + CRnd - 50;
433 if CC < 0 then CC := 0;
434 if CC > 255 then CC := 255;
435 Red := CC;
436 end else
437 Red := 0;
438 if CG > 0 then
439 begin
440 CC := CG + CRnd - 50;
441 if CC < 0 then CC := 0;
442 if CC > 255 then CC := 255;
443 Green := CC;
444 end else
445 Green := 0;
446 if CB > 0 then
447 begin
448 CC := CB + CRnd - 50;
449 if CC < 0 then CC := 0;
450 if CC > 255 then CC := 255;
451 Blue := CC;
452 end else
453 Blue := 0;
455 Alpha := 255;
457 State := STATE_NORMAL;
458 Time := 0;
459 LiveTime := 120+Random(40);
460 ParticleType := PARTICLE_BLOOD;
462 CorrectOffsets(CurrentParticle);
463 end;
465 if CurrentParticle >= MaxParticles-1 then
466 CurrentParticle := 0
467 else
468 CurrentParticle := CurrentParticle+1;
469 end;
470 end;
473 procedure g_GFX_Spark(fX, fY: Integer; Count: Word; Angle: SmallInt; DevX, DevY: Byte);
474 var
475 a: Integer;
476 b: Single;
477 DevX1, DevX2,
478 DevY1, DevY2: Byte;
479 BaseVelX, BaseVelY: Single;
480 l: Integer;
481 begin
482 l := Length(Particles);
483 if l = 0 then
484 Exit;
485 if Count > l then
486 Count := l;
488 Angle := 360 - Angle;
490 DevX1 := DevX div 2;
491 DevX2 := DevX + 1;
492 DevY1 := DevY div 2;
493 DevY2 := DevY + 1;
495 b := DegToRad(Angle);
496 BaseVelX := cos(b);
497 BaseVelY := 1.6*sin(b);
498 if Abs(BaseVelX) < 0.01 then
499 BaseVelX := 0.0;
500 if Abs(BaseVelY) < 0.01 then
501 BaseVelY := 0.0;
502 for a := 1 to Count do
503 begin
504 with Particles[CurrentParticle] do
505 begin
506 X := fX-DevX1+Random(DevX2);
507 Y := fY-DevY1+Random(DevY2);
509 VelX := BaseVelX*Random;
510 VelY := BaseVelY-Random;
511 AccelX := VelX/3.0;
512 AccelY := VelY/5.0;
514 Red := 255;
515 Green := 100+Random(155);
516 Blue := 64;
517 Alpha := 255;
519 State := STATE_NORMAL;
520 Time := 0;
521 LiveTime := 30+Random(60);
522 ParticleType := PARTICLE_SPARK;
524 CorrectOffsets(CurrentParticle);
525 end;
527 if CurrentParticle+2 > MaxParticles then
528 CurrentParticle := 0
529 else
530 CurrentParticle := CurrentParticle+1;
531 end;
532 end;
534 procedure g_GFX_Water(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DevX, DevY, Color: Byte);
535 var
536 a: Integer;
537 DevX1, DevX2,
538 DevY1, DevY2: Byte;
539 l: Integer;
540 begin
541 l := Length(Particles);
542 if l = 0 then
543 Exit;
544 if Count > l then
545 Count := l;
547 if Abs(fVelX) < 3.0 then
548 fVelX := 3.0 - 6.0*Random;
550 DevX1 := DevX div 2;
551 DevX2 := DevX + 1;
552 DevY1 := DevY div 2;
553 DevY2 := DevY + 1;
555 for a := 1 to Count do
556 begin
557 with Particles[CurrentParticle] do
558 begin
559 X := fX-DevX1+Random(DevX2);
560 Y := fY-DevY1+Random(DevY2);
562 if Abs(fVelX) < 0.5 then
563 VelX := 1.0 - 2.0*Random
564 else
565 VelX := fVelX*Random;
566 if Random(10) < 7 then
567 VelX := -VelX;
568 VelY := fVelY*Random;
569 AccelX := 0.0;
570 AccelY := 0.8;
572 case Color of
573 1: // Êðàñíûé
574 begin
575 Red := 155 + Random(9)*10;
576 Green := Trunc(150*Random);
577 Blue := Green;
578 end;
579 2: // Çåëåíûé
580 begin
581 Red := Trunc(150*Random);
582 Green := 175 + Random(9)*10;
583 Blue := Red;
584 end;
585 3: // Ñèíèé
586 begin
587 Red := Trunc(200*Random);
588 Green := Red;
589 Blue := 175 + Random(9)*10;
590 end;
591 else // Ñåðûé
592 begin
593 Red := 90 + Random(12)*10;
594 Green := Red;
595 Blue := Red;
596 end;
597 end;
599 Alpha := 255;
601 State := STATE_NORMAL;
602 Time := 0;
603 LiveTime := 60+Random(60);
604 ParticleType := PARTICLE_WATER;
606 CorrectOffsets(CurrentParticle);
607 end;
609 if CurrentParticle+2 > MaxParticles then
610 CurrentParticle := 0
611 else
612 CurrentParticle := CurrentParticle+1;
613 end;
614 end;
616 procedure g_GFX_SimpleWater(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DefColor, CR, CG, CB: Byte);
617 var
618 a: Integer;
619 l: Integer;
620 begin
621 l := Length(Particles);
622 if l = 0 then
623 Exit;
624 if Count > l then
625 Count := l;
627 for a := 1 to Count do
628 begin
629 with Particles[CurrentParticle] do
630 begin
631 X := fX;
632 Y := fY;
634 VelX := fVelX;
635 VelY := fVelY;
636 AccelX := 0.0;
637 AccelY := 0.8;
639 case DefColor of
640 1: // Êðàñíûé
641 begin
642 Red := 155 + Random(9)*10;
643 Green := Trunc(150*Random);
644 Blue := Green;
645 end;
646 2: // Çåëåíûé
647 begin
648 Red := Trunc(150*Random);
649 Green := 175 + Random(9)*10;
650 Blue := Red;
651 end;
652 3: // Ñèíèé
653 begin
654 Red := Trunc(200*Random);
655 Green := Red;
656 Blue := 175 + Random(9)*10;
657 end;
658 4: // Ñâîé öâåò, ñâåòëåå
659 begin
660 Red := 20 + Random(19)*10;
661 Green := Red;
662 Blue := Red;
663 Red := Min(Red + CR, 255);
664 Green := Min(Green + CG, 255);
665 Blue := Min(Blue + CB, 255);
666 end;
667 5: // Ñâîé öâåò, òåìíåå
668 begin
669 Red := 20 + Random(19)*10;
670 Green := Red;
671 Blue := Red;
672 Red := Max(CR - Red, 0);
673 Green := Max(CG - Green, 0);
674 Blue := Max(CB - Blue, 0);
675 end;
676 else // Ñåðûé
677 begin
678 Red := 90 + Random(12)*10;
679 Green := Red;
680 Blue := Red;
681 end;
682 end;
684 Alpha := 255;
686 State := STATE_NORMAL;
687 Time := 0;
688 LiveTime := 60+Random(60);
689 ParticleType := PARTICLE_WATER;
691 CorrectOffsets(CurrentParticle);
692 end;
694 if CurrentParticle+2 > MaxParticles then
695 CurrentParticle := 0
696 else
697 CurrentParticle := CurrentParticle+1;
698 end;
699 end;
701 procedure g_GFX_Bubbles(fX, fY: Integer; Count: Word; DevX, DevY: Byte);
702 var
703 a: Integer;
704 DevX1, DevX2,
705 DevY1, DevY2: Byte;
706 l: Integer;
707 begin
708 l := Length(Particles);
709 if l = 0 then
710 Exit;
711 if Count > l then
712 Count := l;
714 DevX1 := DevX div 2;
715 DevX2 := DevX + 1;
716 DevY1 := DevY div 2;
717 DevY2 := DevY + 1;
719 for a := 1 to Count do
720 begin
721 with Particles[CurrentParticle] do
722 begin
723 X := fX-DevX1+Random(DevX2);
724 Y := fY-DevY1+Random(DevY2);
726 if (X >= gMapInfo.Width) or (X <= 0) or
727 (Y >= gMapInfo.Height) or (Y <= 0) then
728 Continue;
730 if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
731 Continue;
733 VelX := 0;
734 VelY := -1-Random;
735 AccelX := 0;
736 AccelY := VelY/10;
738 Red := 255;
739 Green := 255;
740 Blue := 255;
741 Alpha := 255;
743 State := STATE_NORMAL;
744 Time := 0;
745 LiveTime := 65535;
746 ParticleType := PARTICLE_BUBBLES;
748 CorrectOffsets(CurrentParticle);
749 end;
751 if CurrentParticle+2 > MaxParticles then
752 CurrentParticle := 0
753 else
754 CurrentParticle := CurrentParticle+1;
755 end;
756 end;
758 procedure g_GFX_SetMax(Count: Integer);
759 begin
760 if Count > 50000 then
761 Count := 50000;
763 SetLength(Particles, Count);
764 MaxParticles := Count;
765 if CurrentParticle >= Count then
766 CurrentParticle := 0;
767 end;
769 function g_GFX_GetMax(): Integer;
770 begin
771 Result := MaxParticles;
772 end;
774 function FindOnceAnim: DWORD;
775 var
776 i: Integer;
777 begin
778 if OnceAnims <> nil then
779 for i := 0 to High(OnceAnims) do
780 if OnceAnims[i].Animation = nil then
781 begin
782 Result := i;
783 Exit;
784 end;
786 if OnceAnims = nil then
787 begin
788 SetLength(OnceAnims, 16);
789 Result := 0;
790 end
791 else
792 begin
793 Result := High(OnceAnims) + 1;
794 SetLength(OnceAnims, Length(OnceAnims) + 16);
795 end;
796 end;
798 procedure g_GFX_OnceAnim(X, Y: Integer; Anim: TAnimation; AnimType: Byte = 0);
799 var
800 find_id: DWORD;
801 begin
802 if Anim = nil then
803 Exit;
805 find_id := FindOnceAnim();
807 OnceAnims[find_id].AnimType := AnimType;
808 OnceAnims[find_id].Animation := TAnimation.Create(Anim.FramesID, Anim.Loop, Anim.Speed);
809 OnceAnims[find_id].Animation.Blending := Anim.Blending;
810 OnceAnims[find_id].Animation.Alpha := Anim.Alpha;
811 OnceAnims[find_id].X := X;
812 OnceAnims[find_id].Y := Y;
813 end;
815 procedure g_GFX_Update();
816 var
817 a: Integer;
818 w, h: Integer;
819 dX, dY: SmallInt;
820 b, len: Integer;
821 s: ShortInt;
822 //c: Byte;
823 begin
824 if Particles <> nil then
825 begin
826 w := gMapInfo.Width;
827 h := gMapInfo.Height;
829 len := High(Particles);
831 for a := 0 to len do
832 if Particles[a].State <> 0 then
833 with Particles[a] do
834 begin
835 if Time = LiveTime then
836 State := STATE_FREE;
837 if (X+1 >= w) or (Y+1 >= h) or (X <= 0) or (Y <= 0) then
838 State := STATE_FREE;
839 if State = STATE_FREE then
840 Continue;
842 case ParticleType of
843 PARTICLE_BLOOD:
844 begin
845 if gAdvBlood then
846 begin
847 if (State = STATE_STICK) then
849 if (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
850 (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) and
851 (not ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)) and
852 (not ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED))
853 then
855 if (not isBlockedAt(X, Y-1)) and
856 (not isBlockedAt(X, Y+1)) and
857 (not isBlockedAt(X-1, Y)) and
858 (not isBlockedAt(X+1, Y))
859 then
860 begin // Îòëèïëà - êàïàåò
861 VelY := 0.5;
862 AccelY := 0.15;
863 State := STATE_NORMAL;
864 end
865 else
866 if Random(200) = 100 then
867 begin // Ïðèëåïëåíà - íî âîçìîæíî ñòåêàåò
868 VelY := 0.5;
869 AccelY := 0.15;
870 Continue;
871 end;
873 if not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)} then
874 begin
875 if isLiftUpAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTUP)} then
876 begin // Ëèôò ââåðõ
877 if VelY > -4-Random(3) then
878 VelY := VelY - 0.8;
879 if Abs(VelX) > 0.1 then
880 VelX := VelX - VelX/10.0;
881 VelX := VelX + (Random-Random)*0.2;
882 AccelY := 0.15;
883 end;
884 if isLiftLeftAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT)} then
885 begin // Ïîòîê âëåâî
886 if VelX > -8-Random(3) then
887 VelX := VelX - 0.8;
888 AccelY := 0.15;
889 end;
890 if isLiftRightAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT)} then
891 begin // Ïîòîê âïðàâî
892 if VelX < 8+Random(3) then
893 VelX := VelX + 0.8;
894 AccelY := 0.15;
895 end;
896 end;
898 dX := Round(VelX);
899 dY := Round(VelY);
901 if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) then
902 if (State <> STATE_STICK) and
903 (not isBlockedAt(X, Y-1) {ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)}) and
904 (not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)}) and
905 (not isBlockedAt(X, Y+1) {ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)}) then
906 begin // Âèñèò â âîçäóõå - êàïàåò
907 VelY := 0.8;
908 AccelY := 0.5;
909 State := STATE_NORMAL;
910 end;
912 if dX <> 0 then
913 begin
914 if dX > 0 then
915 s := 1
916 else
917 s := -1;
919 dX := Abs(dX);
921 for b := 1 to dX do
922 begin
923 if (X+s >= w) or (X+s <= 0) then
924 begin
925 State := STATE_FREE;
926 Break;
927 end;
929 //c := gCollideMap[Y, X+s];
931 if isBlockedAt(X+s, Y) {ByteBool(c and MARK_BLOCKED)} then
932 begin // Ñòåíà/äâåðü
933 VelX := 0;
934 VelY := 0;
935 AccelX := 0;
936 AccelY := 0;
937 State := STATE_STICK;
938 Break;
939 end;
941 X := X+s;
942 end;
943 end;
945 if dY <> 0 then
946 begin
947 if dY > 0 then
948 s := 1
949 else
950 s := -1;
952 dY := Abs(dY);
954 for b := 1 to dY do
955 begin
956 if (Y+s >= h) or (Y+s <= 0) then
957 begin
958 State := STATE_FREE;
959 Break;
960 end;
962 //c := gCollideMap[Y+s, X];
964 if isBlockedAt(X, Y+s) {ByteBool(c and MARK_BLOCKED)} then
965 begin // Ñòåíà/äâåðü
966 VelX := 0;
967 VelY := 0;
968 AccelX := 0;
969 AccelY := 0;
970 if (s > 0) and (State <> STATE_STICK) then
971 State := STATE_NORMAL
972 else
973 State := STATE_STICK;
974 Break;
975 end;
977 Y := Y+s;
978 end;
979 end;
980 end // if gAdvBlood
981 else
982 begin
983 dX := Round(VelX);
984 dY := Round(VelY);
986 if (X+dX >= w) or (Y+dY >= h) or
987 (X+dX <= 0) or (Y+dY <= 0) or
988 isBlockedAt(X+dX, Y+dY) {ByteBool(gCollideMap[Y+dY, X+dX] and MARK_BLOCKED)} then
989 begin // Ñòåíà/äâåðü/ãðàíèöà
990 State := STATE_FREE;
991 VelX := 0;
992 VelY := 0;
993 end
994 else
995 begin
996 Y := Y + dY;
997 X := X + dX;
998 end;
999 end;
1001 VelX := VelX + AccelX;
1002 VelY := VelY + AccelY;
1004 // Êðîâü ðàñòâîðÿåòñÿ â æèäêîñòè:
1005 if isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
1006 begin
1007 Inc(Time);
1009 Alpha := 255 - Trunc((255.0 * Time) / LiveTime);
1010 end;
1011 end;
1013 PARTICLE_SPARK:
1014 begin
1015 dX := Round(VelX);
1016 dY := Round(VelY);
1018 if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) and
1019 (not isBlockedAt(X, Y-1) {ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)}) and
1020 (not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)}) and
1021 (not isBlockedAt(X, Y+1) {ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)}) then
1022 begin // Âèñèò â âîçäóõå
1023 VelY := 0.8;
1024 AccelY := 0.5;
1025 end;
1027 if dX <> 0 then
1028 begin
1029 if dX > 0 then
1030 s := 1
1031 else
1032 s := -1;
1034 dX := Abs(dX);
1036 for b := 1 to dX do
1037 begin
1038 if (X+s >= w) or (X+s <= 0) then
1039 begin
1040 State := STATE_FREE;
1041 Break;
1042 end;
1044 //c := gCollideMap[Y, X+s];
1046 if isBlockedAt(X+s, Y) {ByteBool(c and MARK_BLOCKED)} then
1047 begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî
1048 VelX := 0;
1049 AccelX := 0;
1050 Break;
1051 end
1052 else // Ïóñòî:
1053 if not isAnythingAt(X+s, Y) {c = MARK_FREE} then
1054 X := X + s
1055 else // Îñòàëüíîå:
1056 begin
1057 State := STATE_FREE;
1058 Break;
1059 end;
1060 end;
1061 end;
1063 if dY <> 0 then
1064 begin
1065 if dY > 0 then
1066 s := 1
1067 else
1068 s := -1;
1070 dY := Abs(dY);
1072 for b := 1 to dY do
1073 begin
1074 if (Y+s >= h) or (Y+s <= 0) then
1075 begin
1076 State := STATE_FREE;
1077 Break;
1078 end;
1080 //c := gCollideMap[Y+s, X];
1082 if isBlockedAt(X, Y+s) {ByteBool(c and MARK_BLOCKED)} then
1083 begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî
1084 if s < 0 then
1085 begin
1086 VelY := -VelY;
1087 AccelY := Abs(AccelY);
1088 end
1089 else // Èëè íå ïàäàåò
1090 begin
1091 VelX := 0;
1092 AccelX := 0;
1093 VelY := 0;
1094 AccelY := 0.8;
1095 end;
1097 Break;
1098 end
1099 else // Ïóñòî:
1100 if not isAnythingAt(X, Y+s) {c = MARK_FREE} then
1101 Y := Y + s
1102 else // Îñàëüíîå:
1103 begin
1104 State := STATE_FREE;
1105 Break;
1106 end;
1107 end;
1108 end;
1110 if VelX <> 0.0 then
1111 VelX := VelX + AccelX;
1112 if VelY <> 0.0 then
1113 begin
1114 if AccelY < 10 then
1115 AccelY := AccelY + 0.08;
1116 VelY := VelY + AccelY;
1117 end;
1119 Time := Time + 1;
1120 end;
1122 PARTICLE_WATER:
1123 begin
1124 if (State = STATE_STICK) and (Random(30) = 15) then
1125 begin // Ñòåêàåò/îòëèïàåò
1126 VelY := 0.5;
1127 AccelY := 0.15;
1128 if (not isBlockedAt(X-1, Y) {ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)}) and
1129 (not isBlockedAt(X+1, Y) {ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED)}) then
1130 State := STATE_NORMAL;
1131 Continue;
1132 end;
1134 if not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)} then
1135 begin
1136 if isLiftUpAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTUP)} then
1137 begin // Ëèôò ââåðõ
1138 if VelY > -4-Random(3) then
1139 VelY := VelY - 0.8;
1140 if Abs(VelX) > 0.1 then
1141 VelX := VelX - VelX/10.0;
1142 VelX := VelX + (Random-Random)*0.2;
1143 AccelY := 0.15;
1144 end;
1145 if isLiftLeftAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT)} then
1146 begin // Ïîòîê âëåâî
1147 if VelX > -8-Random(3) then
1148 VelX := VelX - 0.8;
1149 AccelY := 0.15;
1150 end;
1151 if isLiftRightAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT)} then
1152 begin // Ïîòîê âïðàâî
1153 if VelX < 8+Random(3) then
1154 VelX := VelX + 0.8;
1155 AccelY := 0.15;
1156 end;
1157 end;
1159 dX := Round(VelX);
1160 dY := Round(VelY);
1162 if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) then
1163 if (State <> STATE_STICK) and
1164 (not isBlockedAt(X, Y-1) {ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)}) and
1165 (not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)}) and
1166 (not isBlockedAt(X, Y+1) {ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)}) then
1167 begin // Âèñèò â âîçäóõå - êàïàåò
1168 VelY := 0.8;
1169 AccelY := 0.5;
1170 State := STATE_NORMAL;
1171 end;
1173 if dX <> 0 then
1174 begin
1175 if dX > 0 then
1176 s := 1
1177 else
1178 s := -1;
1180 for b := 1 to Abs(dX) do
1181 begin
1182 if (X+s >= w) or (X+s <= 0) then
1183 begin // Ñáîêó ãðàíèöà
1184 State := STATE_FREE;
1185 Break;
1186 end;
1188 //c := gCollideMap[Y, X+s];
1190 if isLiquidAt(X+s, Y) {ByteBool(c and MARK_LIQUID)} and (dY > 0) then
1191 begin // Ñáîêó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
1192 State := STATE_FREE;
1193 Break;
1194 end;
1196 if isBlockedAt(X+s, Y) {ByteBool(c and MARK_BLOCKED)} then
1197 begin // Ñòåíà/äâåðü
1198 VelX := 0;
1199 VelY := 0;
1200 AccelX := 0;
1201 AccelY := 0;
1202 State := STATE_STICK;
1203 Break;
1204 end;
1206 X := X+s;
1207 end;
1208 end;
1210 if dY <> 0 then
1211 begin
1212 if dY > 0 then
1213 s := 1
1214 else
1215 s := -1;
1217 for b := 1 to Abs(dY) do
1218 begin
1219 if (Y+s >= h) or (Y+s <= 0) then
1220 begin // Ñíèçó/ñâåðõó ãðàíèöà
1221 State := STATE_FREE;
1222 Break;
1223 end;
1225 //c := gCollideMap[Y+s, X];
1227 if isLiquidAt(X, Y+s) {ByteBool(c and MARK_LIQUID)} and (dY > 0) then
1228 begin // Ñíèçó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
1229 State := STATE_FREE;
1230 Break;
1231 end;
1233 if isBlockedAt(X, Y+s) {ByteBool(c and MARK_BLOCKED)} then
1234 begin // Ñòåíà/äâåðü
1235 VelX := 0;
1236 VelY := 0;
1237 AccelX := 0;
1238 AccelY := 0;
1239 if (s > 0) and (State <> STATE_STICK) then
1240 State := STATE_NORMAL
1241 else
1242 State := STATE_STICK;
1243 Break;
1244 end;
1246 Y := Y+s;
1247 end;
1248 end;
1250 VelX := VelX + AccelX;
1251 VelY := VelY + AccelY;
1253 Time := Time + 1;
1254 end;
1256 PARTICLE_BUBBLES:
1257 begin
1258 dY := Round(VelY);
1260 if dY <> 0 then
1261 begin
1262 if dY > 0 then
1263 s := 1
1264 else
1265 s := -1;
1267 for b := 1 to Abs(dY) do
1268 begin
1269 if (Y+s >= h) or (Y+s <= 0) then
1270 begin
1271 State := STATE_FREE;
1272 Break;
1273 end;
1275 if not isLiquidAt(X, Y+s) {ByteBool(gCollideMap[Y+s, X] and MARK_LIQUID)} then
1276 begin // Óæå íå æèäêîñòü
1277 State := STATE_FREE;
1278 Break;
1279 end;
1281 Y := Y+s;
1282 end;
1283 end;
1285 if VelY > -4 then
1286 VelY := VelY + AccelY;
1288 Time := Time + 1;
1289 end;
1290 end; // case
1292 CorrectOffsets(a);
1293 end;
1294 end; // Particles <> nil
1296 if OnceAnims <> nil then
1297 begin
1298 for a := 0 to High(OnceAnims) do
1299 if OnceAnims[a].Animation <> nil then
1300 begin
1301 case OnceAnims[a].AnimType of
1302 ONCEANIM_SMOKE:
1303 begin
1304 if Random(3) = 0 then
1305 OnceAnims[a].X := OnceAnims[a].X-1+Random(3);
1306 if Random(2) = 0 then
1307 OnceAnims[a].Y := OnceAnims[a].Y-Random(2);
1308 end;
1309 end;
1311 if OnceAnims[a].Animation.Played then
1312 begin
1313 OnceAnims[a].Animation.Free();
1314 OnceAnims[a].Animation := nil;
1315 end
1316 else
1317 OnceAnims[a].Animation.Update();
1318 end;
1319 end;
1320 end;
1322 procedure g_GFX_Draw();
1323 var
1324 a, len: Integer;
1325 begin
1326 if Particles <> nil then
1327 begin
1328 glDisable(GL_TEXTURE_2D);
1329 glPointSize(2);
1331 glEnable(GL_BLEND);
1332 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1334 glBegin(GL_POINTS);
1336 len := High(Particles);
1338 for a := 0 to len do
1339 with Particles[a] do
1340 if (State <> STATE_FREE) and (X >= sX) and (Y >= sY) and
1341 (X <= sX+sWidth) and (sY <= sY+sHeight) then
1342 begin
1343 glColor4ub(Red, Green, Blue, Alpha);
1344 glVertex2i(X + offsetX, Y + offsetY);
1345 end;
1347 glEnd();
1349 glDisable(GL_BLEND);
1350 end;
1352 if OnceAnims <> nil then
1353 for a := 0 to High(OnceAnims) do
1354 if OnceAnims[a].Animation <> nil then
1355 with OnceAnims[a] do
1356 Animation.Draw(X, Y, M_NONE);
1357 end;
1359 end.