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 procedure g_Mark(x, y, Width, Height: Integer; t: Byte; st: Boolean);
152 {$IF DEFINED(HAS_COLLIDE_BITMAP)}
153 var
154 yy, y2, xx, x2: Integer;
155 {$ENDIF}
156 begin
157 {$IF DEFINED(HAS_COLLIDE_BITMAP)}
158 if x < 0 then
159 begin
160 Width := Width + x;
161 x := 0;
162 end;
164 if Width < 0 then
165 Exit;
167 if y < 0 then
168 begin
169 Height := Height + y;
170 y := 0;
171 end;
173 if Height < 0 then
174 Exit;
176 if x > gMapInfo.Width then
177 Exit;
178 if y > gMapInfo.Height then
179 Exit;
181 y2 := y + Height - 1;
182 if y2 > gMapInfo.Height then
183 y2 := gMapInfo.Height;
185 x2 := x + Width - 1;
186 if x2 > gMapInfo.Width then
187 x2 := gMapInfo.Width;
189 if st then
190 begin // Óñòàíîâèòü ïðèçíàê
191 for yy := y to y2 do
192 for xx := x to x2 do
193 gCollideMap[yy][xx] := gCollideMap[yy][xx] or t;
194 end
195 else
196 begin // Óáðàòü ïðèçíàê
197 t := not t;
198 for yy := y to y2 do
199 for xx := x to x2 do
200 gCollideMap[yy][xx] := gCollideMap[yy][xx] and t;
201 end;
202 {$ENDIF}
203 end;
205 procedure CreateCollideMap();
206 {$IF DEFINED(HAS_COLLIDE_BITMAP)}
207 var
208 a: Integer;
209 {$ENDIF}
210 begin
211 {$IF DEFINED(HAS_COLLIDE_BITMAP)}
212 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
213 SetLength(gCollideMap, gMapInfo.Height+1);
214 for a := 0 to High(gCollideMap) do
215 SetLength(gCollideMap[a], gMapInfo.Width+1);
217 if gWater <> nil then
218 begin
219 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 2/6', 0, True);
220 for a := 0 to High(gWater) do
221 with gWater[a] do
222 g_Mark(X, Y, Width, Height, MARK_WATER, True);
223 end;
225 if gAcid1 <> nil then
226 begin
227 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 3/6', 0, True);
228 for a := 0 to High(gAcid1) do
229 with gAcid1[a] do
230 g_Mark(X, Y, Width, Height, MARK_ACID, True);
231 end;
233 if gAcid2 <> nil then
234 begin
235 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 4/6', 0, True);
236 for a := 0 to High(gAcid2) do
237 with gAcid2[a] do
238 g_Mark(X, Y, Width, Height, MARK_ACID, True);
239 end;
241 if gLifts <> nil then
242 begin
243 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 5/6', 0, True);
244 for a := 0 to High(gLifts) do
245 with gLifts[a] do
246 begin
247 g_Mark(X, Y, Width, Height, MARK_LIFT, False);
249 if LiftType = 0 then
250 g_Mark(X, Y, Width, Height, MARK_LIFTUP, True)
251 else if LiftType = 1 then
252 g_Mark(X, Y, Width, Height, MARK_LIFTDOWN, True)
253 else if LiftType = 2 then
254 g_Mark(X, Y, Width, Height, MARK_LIFTLEFT, True)
255 else if LiftType = 3 then
256 g_Mark(X, Y, Width, Height, MARK_LIFTRIGHT, True)
257 end;
258 end;
260 if gWalls <> nil then
261 begin
262 g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 6/6', 0, True);
263 for a := 0 to High(gWalls) do
264 begin
265 if gWalls[a].Door then
266 begin
267 // Çàêðûòàÿ äâåðü:
268 if gWalls[a].Enabled then
269 with gWalls[a] do
270 g_Mark(X, Y, Width, Height, MARK_DOOR, True)
271 else // Îòêðûòàÿ äâåðü:
272 if gWalls[a].Enabled then
273 with gWalls[a] do
274 g_Mark(X, Y, Width, Height, MARK_DOOR, False);
275 end
276 else // Ñòåíà
277 with gWalls[a] do
278 g_Mark(X, Y, Width, Height, MARK_WALL, True);
279 end;
280 end;
281 {$ENDIF}
282 end;
284 procedure g_GFX_Init();
285 begin
286 CreateCollideMap();
287 end;
289 procedure g_GFX_Free();
290 var
291 a: Integer;
292 begin
293 Particles := nil;
294 SetLength(Particles, MaxParticles);
295 CurrentParticle := 0;
297 if OnceAnims <> nil then
298 begin
299 for a := 0 to High(OnceAnims) do
300 OnceAnims[a].Animation.Free();
302 OnceAnims := nil;
303 end;
304 end;
307 procedure CorrectOffsets(id: Integer);
308 var
309 part: PParticle;
310 begin
311 part := @Particles[id];
312 part.offsetX := 0;
313 part.offsetY := 0;
314 // check for upper wall
315 if isBlockedAt(part.X, part.Y-1) then part.offsetY := 1;
316 // check for left wall
317 if isBlockedAt(part.X-1, part.Y) then part.offsetX := 1;
318 end;
321 procedure g_GFX_SparkVel (fX, fY: Integer; Count: Word; VX, VY: Integer; DevX, DevY: Byte);
322 var
323 a: Integer;
324 DevX1, DevX2,
325 DevY1, DevY2: Byte;
326 l: Integer;
327 begin
328 l := Length(Particles);
329 if l = 0 then exit;
330 if Count > l then Count := l;
332 DevX1 := DevX div 2;
333 DevX2 := DevX + 1;
334 DevY1 := DevY div 2;
335 DevY2 := DevY + 1;
337 for a := 1 to Count do
338 begin
339 with Particles[CurrentParticle] do
340 begin
341 X := fX-DevX1+Random(DevX2);
342 Y := fY-DevY1+Random(DevY2);
344 VelX := VX + (Random-Random)*3;
345 VelY := VY + (Random-Random)*3;
347 if VelY > -4 then
348 if VelY-4 < -4 then
349 VelY := -4
350 else
351 VelY := VelY-4;
353 AccelX := -Sign(VelX)*Random/100;
354 AccelY := 0.8;
356 Red := 255;
357 Green := 100+Random(155);
358 Blue := 64;
359 Alpha := 255;
361 State := STATE_NORMAL;
362 Time := 0;
363 LiveTime := 30+Random(60);
364 ParticleType := PARTICLE_SPARK;
366 CorrectOffsets(CurrentParticle);
367 end;
369 if CurrentParticle+2 > MaxParticles then
370 CurrentParticle := 0
371 else
372 CurrentParticle := CurrentParticle+1;
373 end;
374 end;
377 procedure g_GFX_Blood(fX, fY: Integer; Count: Word; vx, vy: Integer;
378 DevX, DevY: Word; CR, CG, CB: Byte; Kind: Byte = BLOOD_NORMAL);
379 var
380 a: Integer;
381 DevX1, DevX2,
382 DevY1, DevY2: Word;
383 l: Integer;
384 CRnd: Byte;
385 CC: SmallInt;
386 begin
387 if Kind = BLOOD_SPARKS then
388 begin
389 g_GFX_SparkVel(fX, fY, 2 + Random(2), -VX div 2, -VY div 2, DevX, DevY);
390 Exit;
391 end;
392 l := Length(Particles);
393 if l = 0 then
394 Exit;
395 if Count > l then
396 Count := l;
398 DevX1 := DevX div 2;
399 DevX2 := DevX + 1;
400 DevY1 := DevY div 2;
401 DevY2 := DevY + 1;
403 for a := 1 to Count do
404 begin
405 with Particles[CurrentParticle] do
406 begin
407 X := fX - DevX1 + Random(DevX2);
408 Y := fY - DevY1 + Random(DevY2);
411 if (X < 0) or (X > gMapInfo.Width-1) or
412 (Y < 0) or (Y > gMapInfo.Height-1) or
413 ByteBool(gCollideMap[Y, X] and MARK_WALL) then
414 Continue;
416 if isWallAt(X, Y) then continue;
418 VelX := vx + (Random-Random)*3;
419 VelY := vy + (Random-Random)*3;
421 if VelY > -4 then
422 if VelY-4 < -4 then
423 VelY := -4
424 else
425 VelY := VelY-4;
427 AccelX := -Sign(VelX)*Random/100;
428 AccelY := 0.8;
430 CRnd := 20*Random(6);
431 if CR > 0 then
432 begin
433 CC := CR + CRnd - 50;
434 if CC < 0 then CC := 0;
435 if CC > 255 then CC := 255;
436 Red := CC;
437 end else
438 Red := 0;
439 if CG > 0 then
440 begin
441 CC := CG + CRnd - 50;
442 if CC < 0 then CC := 0;
443 if CC > 255 then CC := 255;
444 Green := CC;
445 end else
446 Green := 0;
447 if CB > 0 then
448 begin
449 CC := CB + CRnd - 50;
450 if CC < 0 then CC := 0;
451 if CC > 255 then CC := 255;
452 Blue := CC;
453 end else
454 Blue := 0;
456 Alpha := 255;
458 State := STATE_NORMAL;
459 Time := 0;
460 LiveTime := 120+Random(40);
461 ParticleType := PARTICLE_BLOOD;
463 CorrectOffsets(CurrentParticle);
464 end;
466 if CurrentParticle >= MaxParticles-1 then
467 CurrentParticle := 0
468 else
469 CurrentParticle := CurrentParticle+1;
470 end;
471 end;
474 procedure g_GFX_Spark(fX, fY: Integer; Count: Word; Angle: SmallInt; DevX, DevY: Byte);
475 var
476 a: Integer;
477 b: Single;
478 DevX1, DevX2,
479 DevY1, DevY2: Byte;
480 BaseVelX, BaseVelY: Single;
481 l: Integer;
482 begin
483 l := Length(Particles);
484 if l = 0 then
485 Exit;
486 if Count > l then
487 Count := l;
489 Angle := 360 - Angle;
491 DevX1 := DevX div 2;
492 DevX2 := DevX + 1;
493 DevY1 := DevY div 2;
494 DevY2 := DevY + 1;
496 b := DegToRad(Angle);
497 BaseVelX := cos(b);
498 BaseVelY := 1.6*sin(b);
499 if Abs(BaseVelX) < 0.01 then
500 BaseVelX := 0.0;
501 if Abs(BaseVelY) < 0.01 then
502 BaseVelY := 0.0;
503 for a := 1 to Count do
504 begin
505 with Particles[CurrentParticle] do
506 begin
507 X := fX-DevX1+Random(DevX2);
508 Y := fY-DevY1+Random(DevY2);
510 VelX := BaseVelX*Random;
511 VelY := BaseVelY-Random;
512 AccelX := VelX/3.0;
513 AccelY := VelY/5.0;
515 Red := 255;
516 Green := 100+Random(155);
517 Blue := 64;
518 Alpha := 255;
520 State := STATE_NORMAL;
521 Time := 0;
522 LiveTime := 30+Random(60);
523 ParticleType := PARTICLE_SPARK;
525 CorrectOffsets(CurrentParticle);
526 end;
528 if CurrentParticle+2 > MaxParticles then
529 CurrentParticle := 0
530 else
531 CurrentParticle := CurrentParticle+1;
532 end;
533 end;
535 procedure g_GFX_Water(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DevX, DevY, Color: Byte);
536 var
537 a: Integer;
538 DevX1, DevX2,
539 DevY1, DevY2: Byte;
540 l: Integer;
541 begin
542 l := Length(Particles);
543 if l = 0 then
544 Exit;
545 if Count > l then
546 Count := l;
548 if Abs(fVelX) < 3.0 then
549 fVelX := 3.0 - 6.0*Random;
551 DevX1 := DevX div 2;
552 DevX2 := DevX + 1;
553 DevY1 := DevY div 2;
554 DevY2 := DevY + 1;
556 for a := 1 to Count do
557 begin
558 with Particles[CurrentParticle] do
559 begin
560 X := fX-DevX1+Random(DevX2);
561 Y := fY-DevY1+Random(DevY2);
563 if Abs(fVelX) < 0.5 then
564 VelX := 1.0 - 2.0*Random
565 else
566 VelX := fVelX*Random;
567 if Random(10) < 7 then
568 VelX := -VelX;
569 VelY := fVelY*Random;
570 AccelX := 0.0;
571 AccelY := 0.8;
573 case Color of
574 1: // Êðàñíûé
575 begin
576 Red := 155 + Random(9)*10;
577 Green := Trunc(150*Random);
578 Blue := Green;
579 end;
580 2: // Çåëåíûé
581 begin
582 Red := Trunc(150*Random);
583 Green := 175 + Random(9)*10;
584 Blue := Red;
585 end;
586 3: // Ñèíèé
587 begin
588 Red := Trunc(200*Random);
589 Green := Red;
590 Blue := 175 + Random(9)*10;
591 end;
592 else // Ñåðûé
593 begin
594 Red := 90 + Random(12)*10;
595 Green := Red;
596 Blue := Red;
597 end;
598 end;
600 Alpha := 255;
602 State := STATE_NORMAL;
603 Time := 0;
604 LiveTime := 60+Random(60);
605 ParticleType := PARTICLE_WATER;
607 CorrectOffsets(CurrentParticle);
608 end;
610 if CurrentParticle+2 > MaxParticles then
611 CurrentParticle := 0
612 else
613 CurrentParticle := CurrentParticle+1;
614 end;
615 end;
617 procedure g_GFX_SimpleWater(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DefColor, CR, CG, CB: Byte);
618 var
619 a: Integer;
620 l: Integer;
621 begin
622 l := Length(Particles);
623 if l = 0 then
624 Exit;
625 if Count > l then
626 Count := l;
628 for a := 1 to Count do
629 begin
630 with Particles[CurrentParticle] do
631 begin
632 X := fX;
633 Y := fY;
635 VelX := fVelX;
636 VelY := fVelY;
637 AccelX := 0.0;
638 AccelY := 0.8;
640 case DefColor of
641 1: // Êðàñíûé
642 begin
643 Red := 155 + Random(9)*10;
644 Green := Trunc(150*Random);
645 Blue := Green;
646 end;
647 2: // Çåëåíûé
648 begin
649 Red := Trunc(150*Random);
650 Green := 175 + Random(9)*10;
651 Blue := Red;
652 end;
653 3: // Ñèíèé
654 begin
655 Red := Trunc(200*Random);
656 Green := Red;
657 Blue := 175 + Random(9)*10;
658 end;
659 4: // Ñâîé öâåò, ñâåòëåå
660 begin
661 Red := 20 + Random(19)*10;
662 Green := Red;
663 Blue := Red;
664 Red := Min(Red + CR, 255);
665 Green := Min(Green + CG, 255);
666 Blue := Min(Blue + CB, 255);
667 end;
668 5: // Ñâîé öâåò, òåìíåå
669 begin
670 Red := 20 + Random(19)*10;
671 Green := Red;
672 Blue := Red;
673 Red := Max(CR - Red, 0);
674 Green := Max(CG - Green, 0);
675 Blue := Max(CB - Blue, 0);
676 end;
677 else // Ñåðûé
678 begin
679 Red := 90 + Random(12)*10;
680 Green := Red;
681 Blue := Red;
682 end;
683 end;
685 Alpha := 255;
687 State := STATE_NORMAL;
688 Time := 0;
689 LiveTime := 60+Random(60);
690 ParticleType := PARTICLE_WATER;
692 CorrectOffsets(CurrentParticle);
693 end;
695 if CurrentParticle+2 > MaxParticles then
696 CurrentParticle := 0
697 else
698 CurrentParticle := CurrentParticle+1;
699 end;
700 end;
702 procedure g_GFX_Bubbles(fX, fY: Integer; Count: Word; DevX, DevY: Byte);
703 var
704 a: Integer;
705 DevX1, DevX2,
706 DevY1, DevY2: Byte;
707 l: Integer;
708 begin
709 l := Length(Particles);
710 if l = 0 then
711 Exit;
712 if Count > l then
713 Count := l;
715 DevX1 := DevX div 2;
716 DevX2 := DevX + 1;
717 DevY1 := DevY div 2;
718 DevY2 := DevY + 1;
720 for a := 1 to Count do
721 begin
722 with Particles[CurrentParticle] do
723 begin
724 X := fX-DevX1+Random(DevX2);
725 Y := fY-DevY1+Random(DevY2);
727 if (X >= gMapInfo.Width) or (X <= 0) or
728 (Y >= gMapInfo.Height) or (Y <= 0) then
729 Continue;
731 if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
732 Continue;
734 VelX := 0;
735 VelY := -1-Random;
736 AccelX := 0;
737 AccelY := VelY/10;
739 Red := 255;
740 Green := 255;
741 Blue := 255;
742 Alpha := 255;
744 State := STATE_NORMAL;
745 Time := 0;
746 LiveTime := 65535;
747 ParticleType := PARTICLE_BUBBLES;
749 CorrectOffsets(CurrentParticle);
750 end;
752 if CurrentParticle+2 > MaxParticles then
753 CurrentParticle := 0
754 else
755 CurrentParticle := CurrentParticle+1;
756 end;
757 end;
759 procedure g_GFX_SetMax(Count: Integer);
760 begin
761 if Count > 50000 then
762 Count := 50000;
764 SetLength(Particles, Count);
765 MaxParticles := Count;
766 if CurrentParticle >= Count then
767 CurrentParticle := 0;
768 end;
770 function g_GFX_GetMax(): Integer;
771 begin
772 Result := MaxParticles;
773 end;
775 function FindOnceAnim: DWORD;
776 var
777 i: Integer;
778 begin
779 if OnceAnims <> nil then
780 for i := 0 to High(OnceAnims) do
781 if OnceAnims[i].Animation = nil then
782 begin
783 Result := i;
784 Exit;
785 end;
787 if OnceAnims = nil then
788 begin
789 SetLength(OnceAnims, 16);
790 Result := 0;
791 end
792 else
793 begin
794 Result := High(OnceAnims) + 1;
795 SetLength(OnceAnims, Length(OnceAnims) + 16);
796 end;
797 end;
799 procedure g_GFX_OnceAnim(X, Y: Integer; Anim: TAnimation; AnimType: Byte = 0);
800 var
801 find_id: DWORD;
802 begin
803 if Anim = nil then
804 Exit;
806 find_id := FindOnceAnim();
808 OnceAnims[find_id].AnimType := AnimType;
809 OnceAnims[find_id].Animation := TAnimation.Create(Anim.FramesID, Anim.Loop, Anim.Speed);
810 OnceAnims[find_id].Animation.Blending := Anim.Blending;
811 OnceAnims[find_id].Animation.Alpha := Anim.Alpha;
812 OnceAnims[find_id].X := X;
813 OnceAnims[find_id].Y := Y;
814 end;
816 procedure g_GFX_Update();
817 var
818 a: Integer;
819 w, h: Integer;
820 dX, dY: SmallInt;
821 b, len: Integer;
822 s: ShortInt;
823 //c: Byte;
824 begin
825 if Particles <> nil then
826 begin
827 w := gMapInfo.Width;
828 h := gMapInfo.Height;
830 len := High(Particles);
832 for a := 0 to len do
833 if Particles[a].State <> 0 then
834 with Particles[a] do
835 begin
836 if Time = LiveTime then
837 State := STATE_FREE;
838 if (X+1 >= w) or (Y+1 >= h) or (X <= 0) or (Y <= 0) then
839 State := STATE_FREE;
840 if State = STATE_FREE then
841 Continue;
843 case ParticleType of
844 PARTICLE_BLOOD:
845 begin
846 if gAdvBlood then
847 begin
848 if (State = STATE_STICK) then
850 if (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
851 (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) and
852 (not ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)) and
853 (not ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED))
854 then
856 if (not isBlockedAt(X, Y-1)) and
857 (not isBlockedAt(X, Y+1)) and
858 (not isBlockedAt(X-1, Y)) and
859 (not isBlockedAt(X+1, Y))
860 then
861 begin // Îòëèïëà - êàïàåò
862 VelY := 0.5;
863 AccelY := 0.15;
864 State := STATE_NORMAL;
865 end
866 else
867 if Random(200) = 100 then
868 begin // Ïðèëåïëåíà - íî âîçìîæíî ñòåêàåò
869 VelY := 0.5;
870 AccelY := 0.15;
871 Continue;
872 end;
874 if not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)} then
875 begin
876 if isLiftUpAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTUP)} then
877 begin // Ëèôò ââåðõ
878 if VelY > -4-Random(3) then
879 VelY := VelY - 0.8;
880 if Abs(VelX) > 0.1 then
881 VelX := VelX - VelX/10.0;
882 VelX := VelX + (Random-Random)*0.2;
883 AccelY := 0.15;
884 end;
885 if isLiftLeftAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT)} then
886 begin // Ïîòîê âëåâî
887 if VelX > -8-Random(3) then
888 VelX := VelX - 0.8;
889 AccelY := 0.15;
890 end;
891 if isLiftRightAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT)} then
892 begin // Ïîòîê âïðàâî
893 if VelX < 8+Random(3) then
894 VelX := VelX + 0.8;
895 AccelY := 0.15;
896 end;
897 end;
899 dX := Round(VelX);
900 dY := Round(VelY);
902 if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) then
903 if (State <> STATE_STICK) and
904 (not isBlockedAt(X, Y-1) {ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)}) and
905 (not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)}) and
906 (not isBlockedAt(X, Y+1) {ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)}) then
907 begin // Âèñèò â âîçäóõå - êàïàåò
908 VelY := 0.8;
909 AccelY := 0.5;
910 State := STATE_NORMAL;
911 end;
913 if dX <> 0 then
914 begin
915 if dX > 0 then
916 s := 1
917 else
918 s := -1;
920 dX := Abs(dX);
922 for b := 1 to dX do
923 begin
924 if (X+s >= w) or (X+s <= 0) then
925 begin
926 State := STATE_FREE;
927 Break;
928 end;
930 //c := gCollideMap[Y, X+s];
932 if isBlockedAt(X+s, Y) {ByteBool(c and MARK_BLOCKED)} then
933 begin // Ñòåíà/äâåðü
934 VelX := 0;
935 VelY := 0;
936 AccelX := 0;
937 AccelY := 0;
938 State := STATE_STICK;
939 Break;
940 end;
942 X := X+s;
943 end;
944 end;
946 if dY <> 0 then
947 begin
948 if dY > 0 then
949 s := 1
950 else
951 s := -1;
953 dY := Abs(dY);
955 for b := 1 to dY do
956 begin
957 if (Y+s >= h) or (Y+s <= 0) then
958 begin
959 State := STATE_FREE;
960 Break;
961 end;
963 //c := gCollideMap[Y+s, X];
965 if isBlockedAt(X, Y+s) {ByteBool(c and MARK_BLOCKED)} then
966 begin // Ñòåíà/äâåðü
967 VelX := 0;
968 VelY := 0;
969 AccelX := 0;
970 AccelY := 0;
971 if (s > 0) and (State <> STATE_STICK) then
972 State := STATE_NORMAL
973 else
974 State := STATE_STICK;
975 Break;
976 end;
978 Y := Y+s;
979 end;
980 end;
981 end // if gAdvBlood
982 else
983 begin
984 dX := Round(VelX);
985 dY := Round(VelY);
987 if (X+dX >= w) or (Y+dY >= h) or
988 (X+dX <= 0) or (Y+dY <= 0) or
989 isBlockedAt(X+dX, Y+dY) {ByteBool(gCollideMap[Y+dY, X+dX] and MARK_BLOCKED)} then
990 begin // Ñòåíà/äâåðü/ãðàíèöà
991 State := STATE_FREE;
992 VelX := 0;
993 VelY := 0;
994 end
995 else
996 begin
997 Y := Y + dY;
998 X := X + dX;
999 end;
1000 end;
1002 VelX := VelX + AccelX;
1003 VelY := VelY + AccelY;
1005 // Êðîâü ðàñòâîðÿåòñÿ â æèäêîñòè:
1006 if isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
1007 begin
1008 Inc(Time);
1010 Alpha := 255 - Trunc((255.0 * Time) / LiveTime);
1011 end;
1012 end;
1014 PARTICLE_SPARK:
1015 begin
1016 dX := Round(VelX);
1017 dY := Round(VelY);
1019 if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) and
1020 (not isBlockedAt(X, Y-1) {ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)}) and
1021 (not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)}) and
1022 (not isBlockedAt(X, Y+1) {ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)}) then
1023 begin // Âèñèò â âîçäóõå
1024 VelY := 0.8;
1025 AccelY := 0.5;
1026 end;
1028 if dX <> 0 then
1029 begin
1030 if dX > 0 then
1031 s := 1
1032 else
1033 s := -1;
1035 dX := Abs(dX);
1037 for b := 1 to dX do
1038 begin
1039 if (X+s >= w) or (X+s <= 0) then
1040 begin
1041 State := STATE_FREE;
1042 Break;
1043 end;
1045 //c := gCollideMap[Y, X+s];
1047 if isBlockedAt(X+s, Y) {ByteBool(c and MARK_BLOCKED)} then
1048 begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî
1049 VelX := 0;
1050 AccelX := 0;
1051 Break;
1052 end
1053 else // Ïóñòî:
1054 if not isAnythingAt(X+s, Y) {c = MARK_FREE} then
1055 X := X + s
1056 else // Îñòàëüíîå:
1057 begin
1058 State := STATE_FREE;
1059 Break;
1060 end;
1061 end;
1062 end;
1064 if dY <> 0 then
1065 begin
1066 if dY > 0 then
1067 s := 1
1068 else
1069 s := -1;
1071 dY := Abs(dY);
1073 for b := 1 to dY do
1074 begin
1075 if (Y+s >= h) or (Y+s <= 0) then
1076 begin
1077 State := STATE_FREE;
1078 Break;
1079 end;
1081 //c := gCollideMap[Y+s, X];
1083 if isBlockedAt(X, Y+s) {ByteBool(c and MARK_BLOCKED)} then
1084 begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî
1085 if s < 0 then
1086 begin
1087 VelY := -VelY;
1088 AccelY := Abs(AccelY);
1089 end
1090 else // Èëè íå ïàäàåò
1091 begin
1092 VelX := 0;
1093 AccelX := 0;
1094 VelY := 0;
1095 AccelY := 0.8;
1096 end;
1098 Break;
1099 end
1100 else // Ïóñòî:
1101 if not isAnythingAt(X, Y+s) {c = MARK_FREE} then
1102 Y := Y + s
1103 else // Îñàëüíîå:
1104 begin
1105 State := STATE_FREE;
1106 Break;
1107 end;
1108 end;
1109 end;
1111 if VelX <> 0.0 then
1112 VelX := VelX + AccelX;
1113 if VelY <> 0.0 then
1114 begin
1115 if AccelY < 10 then
1116 AccelY := AccelY + 0.08;
1117 VelY := VelY + AccelY;
1118 end;
1120 Time := Time + 1;
1121 end;
1123 PARTICLE_WATER:
1124 begin
1125 if (State = STATE_STICK) and (Random(30) = 15) then
1126 begin // Ñòåêàåò/îòëèïàåò
1127 VelY := 0.5;
1128 AccelY := 0.15;
1129 if (not isBlockedAt(X-1, Y) {ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)}) and
1130 (not isBlockedAt(X+1, Y) {ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED)}) then
1131 State := STATE_NORMAL;
1132 Continue;
1133 end;
1135 if not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)} then
1136 begin
1137 if isLiftUpAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTUP)} then
1138 begin // Ëèôò ââåðõ
1139 if VelY > -4-Random(3) then
1140 VelY := VelY - 0.8;
1141 if Abs(VelX) > 0.1 then
1142 VelX := VelX - VelX/10.0;
1143 VelX := VelX + (Random-Random)*0.2;
1144 AccelY := 0.15;
1145 end;
1146 if isLiftLeftAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT)} then
1147 begin // Ïîòîê âëåâî
1148 if VelX > -8-Random(3) then
1149 VelX := VelX - 0.8;
1150 AccelY := 0.15;
1151 end;
1152 if isLiftRightAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT)} then
1153 begin // Ïîòîê âïðàâî
1154 if VelX < 8+Random(3) then
1155 VelX := VelX + 0.8;
1156 AccelY := 0.15;
1157 end;
1158 end;
1160 dX := Round(VelX);
1161 dY := Round(VelY);
1163 if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) then
1164 if (State <> STATE_STICK) and
1165 (not isBlockedAt(X, Y-1) {ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)}) and
1166 (not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)}) and
1167 (not isBlockedAt(X, Y+1) {ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)}) then
1168 begin // Âèñèò â âîçäóõå - êàïàåò
1169 VelY := 0.8;
1170 AccelY := 0.5;
1171 State := STATE_NORMAL;
1172 end;
1174 if dX <> 0 then
1175 begin
1176 if dX > 0 then
1177 s := 1
1178 else
1179 s := -1;
1181 for b := 1 to Abs(dX) do
1182 begin
1183 if (X+s >= w) or (X+s <= 0) then
1184 begin // Ñáîêó ãðàíèöà
1185 State := STATE_FREE;
1186 Break;
1187 end;
1189 //c := gCollideMap[Y, X+s];
1191 if isLiquidAt(X+s, Y) {ByteBool(c and MARK_LIQUID)} and (dY > 0) then
1192 begin // Ñáîêó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
1193 State := STATE_FREE;
1194 Break;
1195 end;
1197 if isBlockedAt(X+s, Y) {ByteBool(c and MARK_BLOCKED)} then
1198 begin // Ñòåíà/äâåðü
1199 VelX := 0;
1200 VelY := 0;
1201 AccelX := 0;
1202 AccelY := 0;
1203 State := STATE_STICK;
1204 Break;
1205 end;
1207 X := X+s;
1208 end;
1209 end;
1211 if dY <> 0 then
1212 begin
1213 if dY > 0 then
1214 s := 1
1215 else
1216 s := -1;
1218 for b := 1 to Abs(dY) do
1219 begin
1220 if (Y+s >= h) or (Y+s <= 0) then
1221 begin // Ñíèçó/ñâåðõó ãðàíèöà
1222 State := STATE_FREE;
1223 Break;
1224 end;
1226 //c := gCollideMap[Y+s, X];
1228 if isLiquidAt(X, Y+s) {ByteBool(c and MARK_LIQUID)} and (dY > 0) then
1229 begin // Ñíèçó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
1230 State := STATE_FREE;
1231 Break;
1232 end;
1234 if isBlockedAt(X, Y+s) {ByteBool(c and MARK_BLOCKED)} then
1235 begin // Ñòåíà/äâåðü
1236 VelX := 0;
1237 VelY := 0;
1238 AccelX := 0;
1239 AccelY := 0;
1240 if (s > 0) and (State <> STATE_STICK) then
1241 State := STATE_NORMAL
1242 else
1243 State := STATE_STICK;
1244 Break;
1245 end;
1247 Y := Y+s;
1248 end;
1249 end;
1251 VelX := VelX + AccelX;
1252 VelY := VelY + AccelY;
1254 Time := Time + 1;
1255 end;
1257 PARTICLE_BUBBLES:
1258 begin
1259 dY := Round(VelY);
1261 if dY <> 0 then
1262 begin
1263 if dY > 0 then
1264 s := 1
1265 else
1266 s := -1;
1268 for b := 1 to Abs(dY) do
1269 begin
1270 if (Y+s >= h) or (Y+s <= 0) then
1271 begin
1272 State := STATE_FREE;
1273 Break;
1274 end;
1276 if not isLiquidAt(X, Y+s) {ByteBool(gCollideMap[Y+s, X] and MARK_LIQUID)} then
1277 begin // Óæå íå æèäêîñòü
1278 State := STATE_FREE;
1279 Break;
1280 end;
1282 Y := Y+s;
1283 end;
1284 end;
1286 if VelY > -4 then
1287 VelY := VelY + AccelY;
1289 Time := Time + 1;
1290 end;
1291 end; // case
1293 CorrectOffsets(a);
1294 end;
1295 end; // Particles <> nil
1297 if OnceAnims <> nil then
1298 begin
1299 for a := 0 to High(OnceAnims) do
1300 if OnceAnims[a].Animation <> nil then
1301 begin
1302 case OnceAnims[a].AnimType of
1303 ONCEANIM_SMOKE:
1304 begin
1305 if Random(3) = 0 then
1306 OnceAnims[a].X := OnceAnims[a].X-1+Random(3);
1307 if Random(2) = 0 then
1308 OnceAnims[a].Y := OnceAnims[a].Y-Random(2);
1309 end;
1310 end;
1312 if OnceAnims[a].Animation.Played then
1313 begin
1314 OnceAnims[a].Animation.Free();
1315 OnceAnims[a].Animation := nil;
1316 end
1317 else
1318 OnceAnims[a].Animation.Update();
1319 end;
1320 end;
1321 end;
1323 procedure g_GFX_Draw();
1324 var
1325 a, len: Integer;
1326 begin
1327 if Particles <> nil then
1328 begin
1329 glDisable(GL_TEXTURE_2D);
1330 glPointSize(2);
1332 glEnable(GL_BLEND);
1333 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1335 glBegin(GL_POINTS);
1337 len := High(Particles);
1339 for a := 0 to len do
1340 with Particles[a] do
1341 if (State <> STATE_FREE) and (X >= sX) and (Y >= sY) and
1342 (X <= sX+sWidth) and (sY <= sY+sHeight) then
1343 begin
1344 glColor4ub(Red, Green, Blue, Alpha);
1345 glVertex2i(X + offsetX, Y + offsetY);
1346 end;
1348 glEnd();
1350 glDisable(GL_BLEND);
1351 end;
1353 if OnceAnims <> nil then
1354 for a := 0 to High(OnceAnims) do
1355 if OnceAnims[a].Animation <> nil then
1356 with OnceAnims[a] do
1357 Animation.Draw(X, Y, M_NONE);
1358 end;
1360 end.