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_DEBUG_FALL_MPLAT}
20 interface
22 uses
25 const
52 procedure g_GFX_Water (fX, fY: Integer; count: Word; fVelX, fVelY: Single; devX, devY, color: Byte;
54 procedure g_GFX_SimpleWater (fX, fY: Integer; count: Word; fVelX, fVelY: Single; defColor, cr, cg, cb: Byte);
68 var
73 implementation
75 uses
81 const
85 type
89 // Wall: floorY is just before floor
90 // LiquidIn: floorY is liquid *start* (i.e. just in a liquid)
91 // LiquidOut: floorY is liquid *end* (i.e. just out of a liquid)
94 // note: this MUST be record, so we can keep it in
95 // dynamic array and has sequential memory access pattern
114 //k8: sorry, i have to emulate virtual methods this way, 'cause i haet `Object`
139 var
144 // awakeMap has one bit for each map grid cell; on g_Mark,
145 // corresponding bits will be set, and in `think()` all particles
146 // in marked cells will be awaken
154 // ////////////////////////////////////////////////////////////////////////// //
155 // HACK! using mapgrid
157 begin
159 begin
167 begin
175 //{$IF DEFINED(D2F_DEBUG)}
176 e_LogWritefln('particle awake map: %sx%s (for grid of size %sx%s)', [awakeMapW, awakeMapH, mapGrid.gridWidth, mapGrid.gridHeight]);
177 //{$ENDIF}
184 begin
188 begin
189 {$IF DEFINED(D2F_DEBUG)}
191 {$ENDIF}
193 end
194 else
195 begin
202 var
204 begin
208 begin
209 {$IF DEFINED(D2F_DEBUG)}
211 {$ENDIF}
219 // ////////////////////////////////////////////////////////////////////////// //
223 // remove velocities and acceleration
225 begin
226 // stop right there, you criminal scum!
234 // `true`: affected by air stream
236 var
238 begin
242 begin
244 begin
249 end
251 begin
254 end
256 begin
259 end
260 else
261 begin
264 // awake
270 // switch to sleep mode
272 begin
274 begin
282 var
285 begin
287 // stuck in the wall? rescan, 'cause it can be mplat
289 begin
292 begin
293 // either in a wall, or in a liquid
295 begin
296 // we are in the wall, wtf?!
301 exit;
303 // we are in liquid, trace to liquid end
307 // are we in a liquid?
309 begin
310 // trace out of the liquid
311 //env := TEnvType.ELiquid;
313 //e_LogWritefln('tracing out of a liquid; floorY=%s; y=%s', [floorY, y]);
316 //e_LogWritefln(' traced out of a liquid; floorY=%s; y=%s', [floorY, y]);
317 end
318 else
319 begin
320 // in the air
322 //env := TEnvType.EAir;
323 pan := g_Map_traceToNearest(x, y, x, g_Map_MaxY, (GridTagObstacle or GridTagLiquid), @ex, @floorY);
325 begin
326 // wall or liquid
328 begin
329 // wall
331 end
332 else
333 begin
334 // liquid
338 end
339 else
340 begin
341 // out of the level; assume wall, but it doesn't really matter
350 var
352 begin
355 begin
363 begin
372 begin
373 // awake sleeping particle, if necessary
375 begin
379 else
391 // ////////////////////////////////////////////////////////////////////////// //
394 begin
402 var
404 begin
408 // find next floor transition
410 // find `wallEndY`
411 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
415 begin
422 // `true`: didn't, get outa thinker
424 begin
431 begin
434 // if we're falling from ceiling, switch to normal mode
439 // switch to freefall mode
441 begin
448 begin
451 begin
454 end
455 else
456 begin
462 label
464 var
470 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
472 {$ENDIF}
473 begin
477 begin
478 // still check for air streams when sleeping (no)
479 if (state = TPartState.Sleeping) then begin {checkAirStreams();} goto _done; end; // so blood will dissolve
481 // process stuck particles
483 begin
484 // stuck to a ceiling?
486 begin
487 // yeah, stuck to a ceiling
489 // dropped from a ceiling?
491 begin
492 // yep
496 end
497 else
498 begin
499 // otherwise, try to drip
502 end
503 else
504 begin
505 // stuck to a wall
507 begin
508 // this can happen if mplat was moved out; find new `wallEndY`
511 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
513 _stuckagain:
514 // floor transition?
516 begin
520 begin
521 // check if our ground wasn't moved since the last scan
524 begin
528 // otherwise, do it again
532 begin
533 // rescan, so we'll know when we'll exit the liquid
537 begin
538 // rescan, so we'll know when we'll enter something interesting
544 // wall transition?
546 begin
547 // just unstuck from the wall, switch to freefall mode
550 end
551 else
552 begin
553 // otherwise, try to drip
557 // nope, process as usual
560 // it is important to have it here
566 // gravity, if not stuck
568 begin
571 _gravityagain:
572 // floor transition?
574 begin
577 begin
578 // check if our ground wasn't moved since the last scan
580 begin
585 // otherwise, nothing to do
588 begin
589 // rescan, so we'll know when we'll exit the liquid
594 begin
595 // rescan, so we'll know when we'll enter something interesting
597 if (floorType <> TFloorType.Wall) or (floorY <> y) then applyGravity(floorType = TFloorType.LiquidIn);
600 end
601 else
602 begin
603 // looks like we're in the air
608 // trace movement
610 begin
611 // has some horizontal velocity
617 begin
618 // dunno yet
621 // check environment (air/liquid)
622 if (g_Map_PanelAtPoint(x, y, GridTagLiquid) <> nil) then env := TEnvType.ELiquid else env := TEnvType.EAir;
625 begin
626 // we stuck
627 // the only case when we can have both ceiling and wall is corner; stick to wall in this case
628 // check if we stuck to a wall
631 begin
632 // stuck to a wall
634 end
635 else
636 begin
637 // stuck to a ceiling
641 end
643 begin
644 // has only vertical velocity
646 begin
647 // flying up
651 // environment didn't changed
652 end
653 else
654 begin
656 begin
657 // falling down
662 //e_LogWritefln('floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
664 begin
665 // floor transition
668 //e_LogWritefln(' HIT FLOORY: floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
671 begin
672 // check if our ground wasn't moved since the last scan
674 begin
675 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
677 {$ENDIF}
679 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
681 begin
682 e_LogWritefln('force rescanning vpart at (%s,%s); oldFloorY=%s; floorY=%s', [x, y, oldFloorY, floorY]);
684 {$ENDIF}
688 // environment didn't changed
693 begin
694 // we're entered the liquid
696 // rescan, so we'll know when we'll exit the liquid
700 begin
701 // we're exited the liquid
703 // rescan, so we'll know when we'll enter something interesting
706 begin
712 end
713 else
714 begin
721 else
722 begin
723 // simple blood
731 _done:
732 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
737 // blood will dissolve in other liquids
739 begin
741 begin
749 end
750 else
751 begin
752 // water will disappear in any liquid
755 // dry water
765 // ////////////////////////////////////////////////////////////////////////// //
766 procedure g_GFX_SparkVel (fX, fY: Integer; count: Word; vx, vy: Integer; devX, devY: Byte); forward;
772 begin
774 begin
779 end
780 else
781 begin
786 var
792 begin
796 begin
798 exit;
811 begin
813 begin
817 // check for level bounds
820 // in what environment we are starting in?
823 begin
824 // either in a wall, or in a liquid
827 end
828 else
829 begin
837 begin
864 procedure g_GFX_Water (fX, fY: Integer; count: Word; fVelX, fVelY: Single; devX, devY, color: Byte;
866 var
871 begin
888 begin
890 begin
892 begin
901 end
902 else
903 begin
913 // check for level bounds
916 // this hack will allow water spawned in water to fly out
917 // it can happen when player fell from a huge height (see "DOOM2D.WAD:\MAP03", for example)
919 begin
920 // in what environment we are starting in?
922 end
923 else
924 begin
930 // color
933 begin
939 begin
945 begin
951 begin
960 begin
969 begin
990 procedure g_GFX_SimpleWater (fX, fY: Integer; count: Word; fVelX, fVelY: Single; defColor, cr, cg, cb: Byte);
991 begin
996 // ////////////////////////////////////////////////////////////////////////// //
998 var
1000 begin
1004 begin
1007 begin
1009 end
1010 else
1011 begin
1023 {.$DEFINE D2F_DEBUG_BUBBLES}
1025 var
1029 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1032 {$ENDIF}
1033 begin
1046 begin
1048 begin
1052 // check for level bounds
1055 (*
1056 // don't spawn bubbles outside of the liquid
1057 if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
1058 Continue;
1059 *)
1061 // trace liquid, so we'll know where it ends; do it in 8px steps for speed
1062 // tracer will return `false` if we started outside of the liquid
1064 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1066 ptr := mapGrid.traceOrthoRayWhileIn(liquidx, liquidTopY, x, y, x, 0, GridTagWater or GridTagAcid1 or GridTagAcid2);
1068 e_LogWritefln('traceOrthoRayWhileIn: time=%s (%s); liquidTopY=%s', [Integer(stt), ptr, liquidTopY]);
1069 //
1073 e_LogWritefln('g_Map_TraceLiquidNonPrecise: time=%s (%s); liquidTopY=%s', [Integer(stt), nptr, liquidTopY]);
1075 {$ELSE}
1078 {$ENDIF}
1101 // ////////////////////////////////////////////////////////////////////////// //
1103 label
1104 _done;
1105 var
1109 begin
1115 // apply gravity
1117 begin
1122 // flying
1124 begin
1125 // has some horizontal velocity
1131 begin
1133 // hit the wall; falling down vertically
1137 end
1139 begin
1140 // has some vertical velocity
1142 begin
1143 // flying up
1147 begin
1148 // oops, hit a ceiling
1153 // environment didn't changed
1154 end
1155 else
1156 begin
1157 // falling down
1161 begin
1162 // hit something except a floor?
1164 // otherwise, go to sleep
1167 // environment didn't changed
1172 _done:
1173 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
1178 begin
1187 // ////////////////////////////////////////////////////////////////////////// //
1189 var
1194 begin
1207 begin
1209 begin
1213 // check for level bounds
1216 // in what environment we are starting in?
1219 begin
1220 // either in a wall, or in a liquid
1221 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1222 //env := TEnvType.ELiquid;
1223 continue;
1224 end
1225 else
1226 begin
1234 begin
1260 var
1267 begin
1288 begin
1290 begin
1294 // check for level bounds
1297 // in what environment we are starting in?
1300 begin
1301 // either in a wall, or in a liquid
1302 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1303 //env := TEnvType.ELiquid;
1304 continue;
1305 end
1306 else
1307 begin
1334 // ////////////////////////////////////////////////////////////////////////// //
1336 var
1338 begin
1349 begin
1355 var
1357 begin
1361 begin
1363 Exit;
1367 begin
1370 end
1371 else
1372 begin
1380 var
1382 begin
1398 // ////////////////////////////////////////////////////////////////////////// //
1399 // st: set mark
1400 // t: mark type
1401 // currently unused
1403 var
1406 begin
1410 // make some border, so we'll hit particles lying around the panel
1417 begin
1420 begin
1429 // ////////////////////////////////////////////////////////////////////////// //
1431 begin
1432 //g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
1433 //SetLength(gCollideMap, gMapInfo.Height+1);
1434 //for a := 0 to High(gCollideMap) do SetLength(gCollideMap[a], gMapInfo.Width+1);
1436 {$IFDEF HEADLESS}
1438 {$ENDIF}
1443 var
1445 begin
1452 begin
1458 // why not?
1464 // ////////////////////////////////////////////////////////////////////////// //
1466 var
1470 begin
1474 begin
1481 begin
1483 begin
1485 begin
1494 // clear awake map
1498 begin
1501 begin
1503 ONCEANIM_SMOKE:
1504 begin
1513 begin
1516 end
1517 else
1525 var
1528 begin
1532 begin
1545 begin
1547 begin
1550 begin
1563 begin
1566 begin
1568 begin