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 {$DEFINE D2F_NEW_SPARK_THINKER}
20 interface
22 uses
25 const
49 procedure g_GFX_Water(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DevX, DevY, Color: Byte);
50 procedure g_GFX_SimpleWater(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DefColor, CR, CG, CB: Byte);
63 var
68 implementation
70 uses
75 type
88 // for bubbles
90 // for water
92 // for blood
95 // for all
99 //k8: sorry, i have to emulate virtual methods this way, 'cause i haet `Object`
120 const
129 var
134 // awakeMap has one bit for each map grid cell; on g_Mark,
135 // corresponding bits will be set, and in `think()` all particles
136 // in marked cells will be awaken
143 // ////////////////////////////////////////////////////////////////////////// //
144 // HACK! using mapgrid
146 begin
152 begin
160 {$IF DEFINED(D2F_DEBUG)}
161 e_LogWritefln('particle awake map: %sx%s (for grid of size %sx%s)', [awakeMapW, awakeMapH, mapGrid.gridWidth, mapGrid.gridHeight]);
162 {$ENDIF}
168 begin
172 begin
173 {$IF DEFINED(D2F_DEBUG)}
175 {$ENDIF}
177 end
178 else
179 begin
186 var
188 begin
192 begin
193 {$IF DEFINED(D2F_DEBUG)}
195 {$ENDIF}
202 // ////////////////////////////////////////////////////////////////////////// //
207 begin
212 begin
214 begin
215 // wakeup this particle
216 {
217 if (part.ParticleType = PARTICLE_SPARK) then
218 begin
219 e_LogWritefln('waking up particle of type %s; justSticked=%s; onGround=%s; VelY=%s; AccelY=%s', [part.ParticleType, part.justSticked, part.onGround, part.VelY, part.AccelY]);
220 end;
221 }
224 begin
235 begin
236 // awake sleeping particle, if necessary
238 begin
250 // ////////////////////////////////////////////////////////////////////////// //
252 begin
257 // ???
259 begin
265 begin
271 begin
277 begin
283 begin
289 begin
295 begin
297 result := g_Map_HasAnyPanelAtPoint(x, y, (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));
301 // st: set mark
302 // t: mark type
303 // currently unused
305 var
308 begin
310 // make some border, so we'll hit particles lying around the panel
317 begin
320 begin
329 {$IF DEFINED(HAS_COLLIDE_BITMAP)}
331 var
333 begin
334 //g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
335 //SetLength(gCollideMap, gMapInfo.Height+1);
336 //for a := 0 to High(gCollideMap) do SetLength(gCollideMap[a], gMapInfo.Width+1);
338 {$ENDIF}
342 begin
343 //CreateCollideMap();
345 {$IFDEF HEADLESS}
347 {$ENDIF}
352 var
354 begin
361 begin
367 // why not?
373 // ////////////////////////////////////////////////////////////////////////// //
375 var
378 {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
381 {$ELSE}
384 {$ENDIF}
385 begin
390 begin
392 begin
393 {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
394 {
395 if (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
396 (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) and
397 (not ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)) and
398 (not ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED))
399 then
400 }
405 {$ELSE}
407 begin
408 if not mapGrid.traceOrthoRayWhileIn(ex, ey, X+stickDX, Y, X+stickDX, mapGrid.gridY0+mapGrid.gridHeight, GridTagWall or GridTagDoor or GridTagStep) then
409 begin
410 // îòëèïëà
412 //e_LogWritefln('juststicked unsticked: X=%s; X+stickDX=%s; stickDX=%s; Y=%s', [X, X+stickDX, stickDX, Y]);
413 end
414 else
415 begin
417 if (nil <> g_Map_traceToNearest(X, Y, X, stickEY, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey)) then
418 begin
422 //e_LogWritefln('juststicked: X=%s; X+stickDX=%s; stickDX=%s; Y=%s; stickEY=%s', [X, X+stickDX, stickDX, Y, stickEY]);
426 //if not g_Map_CollidePanel(X-1, Y-1, 3, 3, (PANEL_STEP or PANEL_WALL or PANEL_OPENDOOR or PANEL_CLOSEDOOR))
427 {$ENDIF}
428 then
433 end
438 exit;
442 {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
444 begin
463 {$ELSE}
466 begin
468 begin
475 begin
480 begin
485 {$ENDIF}
490 {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
492 begin
503 {$ELSE}
505 begin
506 // Âèñèò â âîçäóõå - êàïàåò
507 if (nil = g_Map_traceToNearest(X, Y-1, X, Y+1, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey)) then
508 begin
514 {$ENDIF}
516 {$IF DEFINED(D2F_NEW_SPARK_THINKER)}
517 // horizontal
519 begin
520 pan := g_Map_traceToNearest(X, Y, X+dX, Y, (GridTagWall or GridTagDoor or GridTagStep), @ex, @ey);
522 // free to ride?
524 begin
525 // Ñòåíà/äâåðü
536 // vertical
538 begin
540 begin
541 pan := g_Map_traceToNearest(X, Y, X, Y+dY, (GridTagWall or GridTagDoor or GridTagStep), @ex, @ey);
543 // free to ride?
545 begin
546 // Ñòåíà/äâåðü
552 begin
554 end
555 else
556 begin
558 if (g_Map_PanelAtPoint(X-1, Y, (GridTagWall or GridTagDoor or GridTagStep)) <> nil) then stickDX := -1
559 else if (g_Map_PanelAtPoint(X+1, Y, (GridTagWall or GridTagDoor or GridTagStep)) <> nil) then stickDX := 1
564 onGround := (VelY >= 0) and g_Map_HasAnyPanelAtPoint(X, Y+1, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
568 {$ELSE}
569 // horizontal
571 begin
575 begin
577 //c := gCollideMap[Y, X+s];
586 break;
591 // vertical
593 begin
597 begin
599 //c := gCollideMap[Y+s, X];
608 break;
613 {$ENDIF}
615 else
616 begin
619 if (X+dX >= w) or (Y+dY >= h) or (X+dX <= 0) or (Y+dY <= 0) or isBlockedAt(X+dX, Y+dY) {ByteBool(gCollideMap[Y+dY, X+dX] and MARK_BLOCKED)} then
622 exit;
623 //VelX := 0;
624 //VelY := 0;
625 end
626 else
627 begin
636 // Êðîâü ðàñòâîðÿåòñÿ â æèäêîñòè:
638 begin
646 // ////////////////////////////////////////////////////////////////////////// //
648 var
650 {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
654 {$ELSE}
657 {$ENDIF}
658 begin
659 {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
662 {$ENDIF}
664 //TODO: trace wall end when water becomes stick
669 {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
673 {$ELSE}
675 begin
676 // no walls around, drop
678 end
679 else
680 begin
682 begin
683 if not mapGrid.traceOrthoRayWhileIn(ex, ey, X+stickDX, Y, X+stickDX, mapGrid.gridY0+mapGrid.gridHeight, GridTagWall or GridTagDoor or GridTagStep) then
684 begin
685 // îòëèïëà
687 //e_LogWritefln('juststicked unsticked: X=%s; X+stickDX=%s; stickDX=%s; Y=%s', [X, X+stickDX, stickDX, Y]);
688 end
689 else
690 begin
693 if (nil <> g_Map_traceToNearest(X, Y, X, stickEY, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey)) then
694 begin
697 //e_LogWritefln('juststicked: X=%s; X+stickDX=%s; stickDX=%s; Y=%s; stickEY=%s', [X, X+stickDX, stickDX, Y, stickEY]);
699 end
700 else
701 begin
704 //if not g_Map_CollidePanel(X-1, Y-1, 3, 3, (PANEL_STEP or PANEL_WALL or PANEL_OPENDOOR or PANEL_CLOSEDOOR))
706 {$ENDIF}
707 exit;
710 {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
712 begin
735 {$ELSE}
738 begin
739 if ((pan.tag and (GridTagAcid1 or GridTagAcid2 or GridTagWater)) <> 0) then begin die(); exit; end;
741 begin
748 begin
753 begin
758 {$ENDIF}
763 {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
765 begin
776 {$ELSE}
778 begin
779 // Âèñèò â âîçäóõå - êàïàåò
780 if (nil = g_Map_traceToNearest(X, Y-1, X, Y+1, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey)) then
781 begin
787 {$ENDIF}
789 {$IF DEFINED(D2F_NEW_SPARK_THINKER)}
790 // horizontal
792 begin
793 pan := g_Map_traceToNearest(X, Y, X+dX, Y, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey);
795 // free to ride?
797 begin
798 // nope
799 if (dY > 0) and ((pan.tag and (GridTagAcid1 or GridTagAcid2 or GridTagWater)) <> 0) then begin die(); exit; end;
800 // Ñòåíà/äâåðü?
802 begin
814 // vertical
816 begin
818 begin
819 pan := g_Map_traceToNearest(X, Y, X, Y+dY, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey);
821 // free to ride?
823 begin
824 // nope
825 if (dY > 0) and ((pan.tag and (GridTagAcid1 or GridTagAcid2 or GridTagWater)) <> 0) then begin die(); exit; end;
826 // Ñòåíà/äâåðü?
828 begin
834 begin
836 end
837 else
838 begin
840 if (g_Map_PanelAtPoint(X-1, Y, (GridTagWall or GridTagDoor or GridTagStep)) <> nil) then stickDX := -1
841 else if (g_Map_PanelAtPoint(X+1, Y, (GridTagWall or GridTagDoor or GridTagStep)) <> nil) then stickDX := 1
847 onGround := (VelY >= 0) and g_Map_HasAnyPanelAtPoint(X, Y+1, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
851 {$ELSE}
852 // horizontal
854 begin
857 begin
858 // Ñáîêó ãðàíèöà?
860 //c := gCollideMap[Y, X+s];
861 // Ñáîêó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò?
871 Break;
876 // vertical
878 begin
881 begin
882 // Ñíèçó/ñâåðõó ãðàíèöà
884 //c := gCollideMap[Y+s, X];
885 // Ñíèçó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
895 break;
900 {$ENDIF}
909 // ////////////////////////////////////////////////////////////////////////// //
911 var
913 {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
916 {$ELSE}
919 {$ENDIF}
920 begin
924 {$IF DEFINED(D2F_NEW_SPARK_THINKER)}
926 begin
927 pan := g_Map_traceToNearest(X, Y-1, X, Y+1, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey);
929 {$ELSE}
938 {$ENDIF}
941 begin
942 {$IF DEFINED(D2F_NEW_SPARK_THINKER)}
943 pan := g_Map_traceToNearest(X, Y, X+dX, Y, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey);
944 //e_WriteLog(Format('spark h-trace: (%d,%d)-(%d,%d); dx=%d; end=(%d,%d); hit=%d', [X, Y, X+dX, Y, dX, ex, ey, Integer(pan <> nil)]), MSG_NOTIFY);
946 // free to ride?
948 begin
949 // nope
950 if ((pan.tag and (GridTagAcid1 or GridTagAcid2 or GridTagWater)) <> 0) then begin die(); exit; end;
955 {$ELSE}
959 begin
961 //c := gCollideMap[Y, X+s];
966 Break;
967 end
972 begin
974 break;
977 {$ENDIF}
981 begin
982 {$IF DEFINED(D2F_NEW_SPARK_THINKER)}
984 begin
985 pan := g_Map_traceToNearest(X, Y, X, Y+dY, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey);
987 {
988 if awaken then
989 begin
990 awaken := false;
991 e_LogWritefln('AWAKEN particle of type %s; justSticked=%s; onGround=%s; VelY=%s; AccelY=%s; Y=%s; ey=%s', [ParticleType, justSticked, onGround, VelY, AccelY, Y, ey]);
992 end;
993 }
994 // free to ride?
996 begin
997 // nope
998 if ((pan.tag and (GridTagAcid1 or GridTagAcid2 or GridTagWater)) <> 0) then begin die(); exit; end;
1000 begin
1003 end
1004 else
1005 begin
1012 onGround := (VelY >= 0) and g_Map_HasAnyPanelAtPoint(X, Y+1, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
1015 {$ELSE}
1019 begin
1021 //c := gCollideMap[Y+s, X];
1025 begin
1028 end
1030 begin
1037 Break;
1038 end
1043 begin
1045 break;
1048 {$ENDIF}
1054 begin
1062 // ////////////////////////////////////////////////////////////////////////// //
1064 var
1069 begin
1075 begin
1078 else
1082 begin
1085 (*
1086 if not isLiquidAt(X, Y+s) {ByteBool(gCollideMap[Y+s, X] and MARK_LIQUID)} then
1087 begin // Óæå íå æèäêîñòü
1088 State := STATE_FREE;
1089 Break;
1090 end;
1091 *)
1092 // we traced liquid before, so don't bother checking
1106 // ////////////////////////////////////////////////////////////////////////// //
1108 var
1113 begin
1125 begin
1127 begin
1137 else
1153 onGround := (VelY >= 0) and g_Map_HasAnyPanelAtPoint(X, Y+1, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
1159 else
1167 var
1174 begin
1177 begin
1179 Exit;
1183 Exit;
1193 begin
1195 begin
1199 {
1200 if (X < 0) or (X > gMapInfo.Width-1) or
1201 (Y < 0) or (Y > gMapInfo.Height-1) or
1202 ByteBool(gCollideMap[Y, X] and MARK_WALL) then
1203 Continue;
1204 }
1213 else
1221 begin
1226 end else
1229 begin
1234 end else
1237 begin
1242 end else
1252 onGround := (VelY >= 0) and g_Map_HasAnyPanelAtPoint(X, Y+1, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
1254 //stickEY := 0;
1259 else
1266 var
1273 begin
1277 Exit;
1296 begin
1298 begin
1317 onGround := (VelY >= 0) and g_Map_HasAnyPanelAtPoint(X, Y+1, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
1323 else
1328 procedure g_GFX_Water(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DevX, DevY, Color: Byte);
1329 var
1334 begin
1338 Exit;
1351 begin
1353 begin
1359 else
1369 begin
1375 begin
1381 begin
1387 begin
1401 onGround := (VelY >= 0) and g_Map_HasAnyPanelAtPoint(X, Y+1, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
1407 else
1412 procedure g_GFX_SimpleWater(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DefColor, CR, CG, CB: Byte);
1413 var
1416 begin
1420 Exit;
1425 begin
1427 begin
1438 begin
1444 begin
1450 begin
1456 begin
1465 begin
1474 begin
1488 onGround := (VelY >= 0) and g_Map_HasAnyPanelAtPoint(X, Y+1, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
1494 else
1500 {.$DEFINE D2F_DEBUG_BUBBLES}
1502 var
1507 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1510 {$ENDIF}
1511 begin
1515 Exit;
1525 begin
1527 begin
1533 Continue;
1535 (*
1536 // don't spawn bubbles outside of the liquid
1537 if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
1538 Continue;
1539 *)
1541 // trace liquid, so we'll know where it ends; do it in 8px steps for speed
1542 // tracer will return `false` if we started outside of the liquid
1544 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1546 ptr := mapGrid.traceOrthoRayWhileIn(liquidx, liquidTopY, X, Y, X, 0, GridTagWater or GridTagAcid1 or GridTagAcid2);
1548 e_LogWritefln('traceOrthoRayWhileIn: time=%s (%s); liquidTopY=%s', [Integer(stt), ptr, liquidTopY]);
1549 //
1553 e_LogWritefln('g_Map_TraceLiquidNonPrecise: time=%s (%s); liquidTopY=%s', [Integer(stt), nptr, liquidTopY]);
1555 {$ELSE}
1557 {$ENDIF}
1574 onGround := (VelY >= 0) and g_Map_HasAnyPanelAtPoint(X, Y+1, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
1580 else
1586 var
1588 begin
1595 //if CurrentParticle >= Count then
1600 begin
1605 var
1607 begin
1611 begin
1613 Exit;
1617 begin
1620 end
1621 else
1622 begin
1629 var
1631 begin
1634 Exit;
1647 var
1651 begin
1655 begin
1662 begin
1664 begin
1666 begin
1669 //if not alive then Continue;
1670 //e_WriteLog(Format('particle #%d: %d', [State, ParticleType]), MSG_NOTIFY);
1677 // clear awake map
1681 begin
1684 begin
1686 ONCEANIM_SMOKE:
1687 begin
1696 begin
1699 end
1700 else
1707 var
1709 begin
1711 begin
1725 begin