6a994723c44807e0f329321e8c95daf5c820e8a8
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
52 procedure g_GFX_Water (fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DevX, DevY, Color: Byte);
53 procedure g_GFX_SimpleWater (fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DefColor, CR, CG, CB: Byte);
67 var
72 implementation
74 uses
80 const
84 type
88 // Wall: floorY is just before floor
89 // LiquidIn: floorY is liquid *start* (i.e. just in a liquid)
90 // LiquidOut: floorY is liquid *end* (i.e. just out of a liquid)
103 // for bubbles
105 // for water
112 // for all
117 //k8: sorry, i have to emulate virtual methods this way, 'cause i haet `Object`
141 var
146 // awakeMap has one bit for each map grid cell; on g_Mark,
147 // corresponding bits will be set, and in `think()` all particles
148 // in marked cells will be awaken
155 // ////////////////////////////////////////////////////////////////////////// //
156 // HACK! using mapgrid
158 begin
164 begin
172 {$IF DEFINED(D2F_DEBUG)}
173 e_LogWritefln('particle awake map: %sx%s (for grid of size %sx%s)', [awakeMapW, awakeMapH, mapGrid.gridWidth, mapGrid.gridHeight]);
174 {$ENDIF}
180 begin
184 begin
185 {$IF DEFINED(D2F_DEBUG)}
187 {$ENDIF}
189 end
190 else
191 begin
198 var
200 begin
204 begin
205 {$IF DEFINED(D2F_DEBUG)}
207 {$ENDIF}
214 // ////////////////////////////////////////////////////////////////////////// //
219 begin
224 begin
226 begin
227 // wakeup this particle
228 {
229 if (part.ParticleType = PARTICLE_SPARK) then
230 begin
231 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]);
232 end;
233 }
236 begin
247 var
250 begin
252 // are we in a liquid?
255 begin
256 // either in a wall, or in a liquid
258 begin
259 // we are in the wall, wtf?!
263 exit;
265 // we are in liquid, trace to liquid end
267 //e_LogWritefln('tracing out of a liquid; floorY=%s; y=%s', [floorY, y]);
270 //e_LogWritefln(' traced out of a liquid; floorY=%s; y=%s', [floorY, y]);
271 end
272 else
273 begin
274 // not in a wall
275 pan := g_Map_traceToNearest(x, y, x, g_Map_MaxY, (GridTagObstacle or GridTagLiquid), @ex, @floorY);
277 begin
278 // wall or liquid
280 begin
281 // wall
283 end
284 else
285 begin
286 // liquid
290 end
291 else
292 begin
293 // out of the level; assume wall, but it doesn't really matter
302 var
304 begin
307 begin
314 begin
315 // awake sleeping particle, if necessary
319 //TPartType.Spark: thinkerSpark();
320 //TPartType.Bubbles: thinkerBubble();
321 //TPartType.Water: thinkerWater();
326 // ////////////////////////////////////////////////////////////////////////// //
328 begin
330 result := g_Map_HasAnyPanelAtPoint(x, y, (PANEL_WALL or PANEL_OPENDOOR or PANEL_CLOSEDOOR or PANEL_STEP));
333 // ???
335 begin
341 begin
347 begin
353 begin
359 begin
365 begin
371 begin
373 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));
377 // ////////////////////////////////////////////////////////////////////////// //
378 // st: set mark
379 // t: mark type
380 // currently unused
382 var
385 begin
387 // make some border, so we'll hit particles lying around the panel
394 begin
397 begin
406 // ////////////////////////////////////////////////////////////////////////// //
407 {$IF DEFINED(HAS_COLLIDE_BITMAP)}
409 var
411 begin
412 //g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
413 //SetLength(gCollideMap, gMapInfo.Height+1);
414 //for a := 0 to High(gCollideMap) do SetLength(gCollideMap[a], gMapInfo.Width+1);
416 {$ENDIF}
420 begin
421 //CreateCollideMap();
423 {$IFDEF HEADLESS}
425 {$ENDIF}
430 var
432 begin
439 begin
445 // why not?
451 // ////////////////////////////////////////////////////////////////////////// //
454 begin
457 // stop right there, you criminal scum!
466 var
468 begin
471 // stop right there, you criminal scum!
476 // find next floor transition
478 // find `wallEndY`
479 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
480 //if (wallEndY > floorY) then wallEndY := floorY; // just in case
484 begin
486 // stop right there, you criminal scum!
495 // `true`: didn't, get outa thinker
497 begin
502 // `true`: affected by air stream
504 var
506 begin
510 begin
512 begin
517 end
519 begin
522 end
524 begin
527 end
528 else
529 begin
532 // awake
537 // switch to sleep mode
539 begin
541 // stop right there, you criminal scum!
548 // switch to freefall mode
550 begin
557 begin
560 begin
563 end
564 else
565 begin
571 label
572 _done;
573 var
577 begin
579 begin
580 // still check for air streams when sleeping
583 // process stuck particles
585 begin
586 // stuck to a ceiling?
588 begin
590 // dropped from a ceiling?
592 begin
593 // yep
597 end
598 else
599 begin
600 // otherwise, try to drip
603 end
604 else
605 begin
606 // stuck to a wall
608 // floor transition?
610 begin
613 begin
618 begin
619 // rescan, so we'll know when we'll exit the liquid
623 begin
624 // rescan, so we'll know when we'll enter something interesting
630 // wall transition?
632 begin
633 // just unstuck from the wall, switch to freefall mode
635 end
636 else
637 begin
638 // otherwise, try to drip
642 // nope, process as usual
645 // it is important to have it here
649 // gravity, if not stuck
651 begin
653 // floor transition?
655 begin
658 begin
659 // nothing to do
662 begin
663 // rescan, so we'll know when we'll exit the liquid
668 begin
669 // rescan, so we'll know when we'll enter something interesting
671 if (floorType <> TFloorType.Wall) or (floorY <> y) then applyGravity(floorType = TFloorType.LiquidIn);
674 end
675 else
676 begin
677 // looks like we're in the air
682 // horizontal movement
684 begin
685 pan := g_Map_traceToNearest(x, y, x+dX, y, (GridTagWall or GridTagDoor or GridTagStep), @ex, @ey);
692 // vertical movement
694 begin
695 // flying up
699 end
700 else
701 begin
703 begin
704 // falling down
707 //e_LogWritefln('floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
709 begin
710 // floor transition
713 //e_LogWritefln(' HIT FLOORY: floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
716 begin
721 begin
722 // rescan, so we'll know when we'll exit the liquid
726 begin
727 // rescan, so we'll know when we'll enter something interesting
730 begin
736 end
737 else
738 begin
745 else
746 begin
747 // simple blood
750 if (x+dX > g_Map_MaxX) or (y+dY > g_Map_MaxY) or (x+dX < g_Map_MinX) or (y+dY < g_Map_MinY) or isBlockedAt(x+dX, y+dY) then
751 begin
752 // Ñòåíà/äâåðü/ãðàíèöà
754 exit;
755 end
756 else
757 begin
763 _done:
767 // blood will dissolve in other liquids
769 begin
773 (*
774 // Êðîâü ðàñòâîðÿåòñÿ â æèäêîñòè
775 if isLiquidAt(x, y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
776 begin
777 time += 1;
778 alpha := 255-trunc((255.0*time)/liveTime);
779 end;
780 *)
784 procedure g_GFX_SparkVel (fX, fY: Integer; Count: Word; VX, VY: Integer; DevX, DevY: Byte); forward;
788 var
794 begin
798 begin
800 exit;
813 begin
815 begin
819 {
820 if (X < 0) or (X > gMapInfo.Width-1) or
821 (Y < 0) or (Y > gMapInfo.Height-1) or
822 ByteBool(gCollideMap[Y, X] and MARK_WALL) then
823 Continue;
824 }
831 begin
840 begin
845 end
846 else
847 begin
851 begin
856 end
857 else
858 begin
862 begin
867 end
868 else
869 begin
879 //justSticked := false;
880 //onGround := (velY >= 0) and g_Map_HasAnyPanelAtPoint(x, y+1, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
881 //awaken := false;
882 //stickEY := 0;
889 else
895 // ////////////////////////////////////////////////////////////////////////// //
897 var
899 {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
903 {$ELSE}
906 {$ENDIF}
907 begin
908 {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
911 {$ENDIF}
913 //TODO: trace wall end when water becomes stick
918 {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
922 {$ELSE}
924 begin
925 // no walls around, drop
927 end
928 else
929 begin
931 begin
932 if not mapGrid.traceOrthoRayWhileIn(ex, ey, x+stickDX, y, x+stickDX, mapGrid.gridY0+mapGrid.gridHeight, GridTagWall or GridTagDoor or GridTagStep) then
933 begin
934 // îòëèïëà
936 //e_LogWritefln('juststicked unsticked: X=%s; X+stickDX=%s; stickDX=%s; Y=%s', [X, X+stickDX, stickDX, Y]);
937 end
938 else
939 begin
942 if (nil <> g_Map_traceToNearest(x, y, x, stickEY, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey)) then
943 begin
946 //e_LogWritefln('juststicked: X=%s; X+stickDX=%s; stickDX=%s; Y=%s; stickEY=%s', [X, X+stickDX, stickDX, Y, stickEY]);
948 end
949 else
950 begin
953 //if not g_Map_CollidePanel(X-1, Y-1, 3, 3, (PANEL_STEP or PANEL_WALL or PANEL_OPENDOOR or PANEL_CLOSEDOOR))
955 {$ENDIF}
956 exit;
959 {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
961 begin
984 {$ELSE}
987 begin
988 if ((pan.tag and (GridTagAcid1 or GridTagAcid2 or GridTagWater)) <> 0) then begin die(); exit; end;
990 begin
997 begin
1002 begin
1007 {$ENDIF}
1012 {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
1014 begin
1025 {$ELSE}
1027 begin
1028 // Âèñèò â âîçäóõå - êàïàåò
1029 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
1030 begin
1036 {$ENDIF}
1038 {$IF DEFINED(D2F_NEW_SPARK_THINKER)}
1039 // horizontal
1041 begin
1042 pan := g_Map_traceToNearest(x, y, x+dX, y, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey);
1045 // free to ride?
1047 begin
1048 // nope
1049 if (dY > 0) and ((pan.tag and (GridTagAcid1 or GridTagAcid2 or GridTagWater)) <> 0) then begin die(); exit; end;
1050 // Ñòåíà/äâåðü?
1052 begin
1064 // vertical
1066 begin
1068 begin
1069 pan := g_Map_traceToNearest(x, y, x, y+dY, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey);
1071 // free to ride?
1073 begin
1074 // nope
1075 if (dY > 0) and ((pan.tag and (GridTagAcid1 or GridTagAcid2 or GridTagWater)) <> 0) then begin die(); exit; end;
1076 // Ñòåíà/äâåðü?
1078 begin
1084 begin
1086 end
1087 else
1088 begin
1090 if (g_Map_PanelAtPoint(x-1, y, (GridTagWall or GridTagDoor or GridTagStep)) <> nil) then stickDX := -1
1091 else if (g_Map_PanelAtPoint(x+1, y, (GridTagWall or GridTagDoor or GridTagStep)) <> nil) then stickDX := 1
1097 onGround := (velY >= 0) and g_Map_HasAnyPanelAtPoint(x, y+1, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
1101 {$ELSE}
1102 // horizontal
1104 begin
1107 begin
1108 // Ñáîêó ãðàíèöà?
1110 //c := gCollideMap[Y, X+s];
1111 // Ñáîêó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò?
1121 Break;
1126 // vertical
1128 begin
1131 begin
1132 // Ñíèçó/ñâåðõó ãðàíèöà
1134 //c := gCollideMap[Y+s, X];
1135 // Ñíèçó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
1143 if (s > 0) and (state <> TPartState.Stuck) then state := TPartState.Normal else state := TPartState.Stuck;
1145 break;
1150 {$ENDIF}
1159 // ////////////////////////////////////////////////////////////////////////// //
1161 var
1163 {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
1166 {$ELSE}
1169 {$ENDIF}
1170 begin
1174 {$IF DEFINED(D2F_NEW_SPARK_THINKER)}
1176 begin
1177 pan := g_Map_traceToNearest(x, y-1, x, y+1, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey);
1179 {$ELSE}
1188 {$ENDIF}
1191 begin
1192 {$IF DEFINED(D2F_NEW_SPARK_THINKER)}
1193 pan := g_Map_traceToNearest(x, y, x+dX, y, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey);
1194 //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);
1197 // free to ride?
1199 begin
1200 // nope
1201 if ((pan.tag and (GridTagAcid1 or GridTagAcid2 or GridTagWater)) <> 0) then begin die(); exit; end;
1206 {$ELSE}
1210 begin
1212 //c := gCollideMap[Y, X+s];
1217 Break;
1218 end
1223 begin
1225 break;
1228 {$ENDIF}
1232 begin
1233 {$IF DEFINED(D2F_NEW_SPARK_THINKER)}
1235 begin
1236 pan := g_Map_traceToNearest(x, y, x, y+dY, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey);
1238 {
1239 if awaken then
1240 begin
1241 awaken := false;
1242 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]);
1243 end;
1244 }
1245 // free to ride?
1247 begin
1248 // nope
1249 if ((pan.tag and (GridTagAcid1 or GridTagAcid2 or GridTagWater)) <> 0) then begin die(); exit; end;
1251 begin
1254 end
1255 else
1256 begin
1263 onGround := (velY >= 0) and g_Map_HasAnyPanelAtPoint(x, y+1, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
1266 {$ELSE}
1270 begin
1272 //c := gCollideMap[Y+s, X];
1276 begin
1279 end
1281 begin
1288 Break;
1289 end
1294 begin
1296 break;
1299 {$ENDIF}
1305 begin
1313 // ////////////////////////////////////////////////////////////////////////// //
1315 var
1320 begin
1326 begin
1329 else
1333 begin
1336 (*
1337 if not isLiquidAt(X, Y+s) {ByteBool(gCollideMap[Y+s, X] and MARK_LIQUID)} then
1338 begin // Óæå íå æèäêîñòü
1339 State := STATE_FREE;
1340 Break;
1341 end;
1342 *)
1343 // we traced liquid before, so don't bother checking
1357 // ////////////////////////////////////////////////////////////////////////// //
1359 var
1364 begin
1365 exit;
1377 begin
1379 begin
1389 else
1405 onGround := (velY >= 0) and g_Map_HasAnyPanelAtPoint(x, y+1, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
1411 else
1418 var
1425 begin
1426 exit;
1430 Exit;
1449 begin
1451 begin
1470 onGround := (velY >= 0) and g_Map_HasAnyPanelAtPoint(x, y+1, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
1476 else
1482 procedure g_GFX_Water(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DevX, DevY, Color: Byte);
1483 var
1488 begin
1489 exit;
1493 Exit;
1506 begin
1508 begin
1514 else
1524 begin
1530 begin
1536 begin
1542 begin
1556 onGround := (velY >= 0) and g_Map_HasAnyPanelAtPoint(x, y+1, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
1562 else
1568 procedure g_GFX_SimpleWater(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DefColor, CR, CG, CB: Byte);
1569 var
1572 begin
1573 exit;
1577 Exit;
1582 begin
1584 begin
1595 begin
1601 begin
1607 begin
1613 begin
1622 begin
1631 begin
1645 onGround := (velY >= 0) and g_Map_HasAnyPanelAtPoint(x, y+1, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
1651 else
1657 {.$DEFINE D2F_DEBUG_BUBBLES}
1659 var
1664 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1667 {$ENDIF}
1668 begin
1669 exit;
1673 Exit;
1683 begin
1685 begin
1691 Continue;
1693 (*
1694 // don't spawn bubbles outside of the liquid
1695 if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
1696 Continue;
1697 *)
1699 // trace liquid, so we'll know where it ends; do it in 8px steps for speed
1700 // tracer will return `false` if we started outside of the liquid
1702 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1704 ptr := mapGrid.traceOrthoRayWhileIn(liquidx, liquidTopY, x, y, x, 0, GridTagWater or GridTagAcid1 or GridTagAcid2);
1706 e_LogWritefln('traceOrthoRayWhileIn: time=%s (%s); liquidTopY=%s', [Integer(stt), ptr, liquidTopY]);
1707 //
1711 e_LogWritefln('g_Map_TraceLiquidNonPrecise: time=%s (%s); liquidTopY=%s', [Integer(stt), nptr, liquidTopY]);
1713 {$ELSE}
1715 {$ENDIF}
1732 onGround := (velY >= 0) and g_Map_HasAnyPanelAtPoint(x, y+1, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
1738 else
1744 // ////////////////////////////////////////////////////////////////////////// //
1746 var
1748 begin
1755 //if CurrentParticle >= Count then
1761 begin
1767 var
1769 begin
1773 begin
1775 Exit;
1779 begin
1782 end
1783 else
1784 begin
1792 var
1794 begin
1797 Exit;
1811 var
1815 begin
1819 begin
1826 begin
1828 begin
1830 begin
1833 //if not alive then Continue;
1834 //e_WriteLog(Format('particle #%d: %d', [State, ParticleType]), MSG_NOTIFY);
1841 // clear awake map
1845 begin
1848 begin
1850 ONCEANIM_SMOKE:
1851 begin
1860 begin
1863 end
1864 else
1872 var
1874 begin
1876 begin
1890 begin