ff7089b46f31177abfc89971a3f66a28b8838e36
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}
18 {/$DEFINE D2F_DEBUG_PART_AWAKE}
21 interface
23 uses
26 const
53 procedure g_GFX_Water (fX, fY: Integer; count: Word; fVelX, fVelY: Single; devX, devY, color: Byte;
55 procedure g_GFX_SimpleWater (fX, fY: Integer; count: Word; fVelX, fVelY: Single; defColor, cr, cg, cb: Byte);
69 var
74 //WARNING: only for Holmes!
78 implementation
80 uses
86 const
90 type
94 // Wall: floorY is just before floor
95 // LiquidIn: floorY is liquid *start* (i.e. just in a liquid)
96 // LiquidOut: floorY is liquid *end* (i.e. just out of a liquid)
99 // note: this MUST be record, so we can keep it in
100 // dynamic array and has sequential memory access pattern
119 //k8: sorry, i have to emulate virtual methods this way, 'cause i haet `Object`
144 var
149 // awakeMap has one bit for each map grid cell; on g_Mark,
150 // corresponding bits will be set, and in `think()` all particles
151 // in marked cells will be awaken
157 {$IF DEFINED(D2F_DEBUG_PART_AWAKE)}
159 {$ENDIF}
162 // ////////////////////////////////////////////////////////////////////////// //
164 begin
165 {$IF DEFINED(D2F_DEBUG_PART_AWAKE)}
170 begin
172 begin
174 end
175 else
176 begin
179 end
180 else
181 begin
184 {$ELSE}
186 {$ENDIF}
190 // ////////////////////////////////////////////////////////////////////////// //
191 // HACK! using mapgrid
193 begin
194 {$IF DEFINED(D2F_DEBUG_PART_AWAKE)}
196 begin
200 {$ENDIF}
202 begin
210 begin
218 {$IF DEFINED(D2F_DEBUG_PART_AWAKE)}
221 {$ENDIF}
222 //{$IF DEFINED(D2F_DEBUG)}
223 e_LogWritefln('particle awake map: %sx%s (for grid of size %sx%s)', [awakeMapW, awakeMapH, mapGrid.gridWidth, mapGrid.gridHeight]);
224 //{$ENDIF}
231 begin
235 begin
236 {$IF DEFINED(D2F_DEBUG)}
238 {$ENDIF}
240 end
241 else
242 begin
249 var
251 begin
255 begin
256 {$IF DEFINED(D2F_DEBUG)}
258 {$ENDIF}
266 // ////////////////////////////////////////////////////////////////////////// //
267 // st: set mark
268 // t: mark type
269 // currently unused
272 var
275 begin
281 // make some border, so we'll hit particles around the panel
292 // has something to do?
301 begin
303 begin
304 {$IF DEFINED(D2F_DEBUG)}
307 {$ENDIF}
315 // ////////////////////////////////////////////////////////////////////////// //
319 // remove velocities and acceleration
321 begin
322 // stop right there, you criminal scum!
330 // `true`: affected by air stream
332 var
334 begin
338 begin
340 begin
345 end
347 begin
350 end
352 begin
355 end
356 else
357 begin
360 // awake
366 // switch to sleep mode
368 begin
370 begin
378 var
381 begin
383 // stuck in the wall? rescan, 'cause it can be mplat
385 begin
388 begin
389 // either in a wall, or in a liquid
391 begin
392 // we are in the wall, wtf?!
397 exit;
399 // we are in liquid, trace to liquid end
403 // are we in a liquid?
405 begin
406 // trace out of the liquid
407 //env := TEnvType.ELiquid;
409 //e_LogWritefln('tracing out of a liquid; floorY=%s; y=%s', [floorY, y]);
412 //e_LogWritefln(' traced out of a liquid; floorY=%s; y=%s', [floorY, y]);
413 end
414 else
415 begin
416 // in the air
418 //env := TEnvType.EAir;
419 pan := g_Map_traceToNearest(x, y, x, g_Map_MaxY, (GridTagObstacle or GridTagLiquid), @ex, @floorY);
421 begin
422 // wall or liquid
424 begin
425 // wall
427 end
428 else
429 begin
430 // liquid
434 end
435 else
436 begin
437 // out of the level; assume wall, but it doesn't really matter
446 var
448 begin
451 begin
459 begin
461 begin
462 //writeln('awaking particle at (', x, ',', y, ')');
464 begin
466 end
467 else
468 begin
469 // stuck to a wall, check if wall is still there
471 begin
474 begin
475 // a wall was moved out, start falling
482 end
483 else
484 begin
493 begin
494 // awake sleeping particle, if necessary
496 begin
498 {
499 case state of
500 TPartState.Sleeping, TPartState.Stuck:
501 if awmIsSet(x, y) then awake();
502 else
503 if (env = TEnvType.EWall) and awmIsSet(x, y) then awake();
504 end;
505 }
515 // ////////////////////////////////////////////////////////////////////////// //
518 begin
526 var
528 begin
532 // find next floor transition
534 // find `wallEndY`
535 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
539 begin
546 // `true`: didn't, get outa thinker
548 begin
555 begin
558 // if we're falling from ceiling, switch to normal mode
563 // switch to freefall mode
565 begin
572 begin
575 begin
578 end
579 else
580 begin
586 label
588 var
594 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
596 {$ENDIF}
597 begin
601 begin
602 // still check for air streams when sleeping (no)
603 if (state = TPartState.Sleeping) then begin {checkAirStreams();} goto _done; end; // so blood will dissolve
605 // process stuck particles
607 begin
608 // stuck to a ceiling?
610 begin
611 // yeah, stuck to a ceiling
613 // dropped from a ceiling?
615 begin
616 // yep
620 end
621 else
622 begin
623 // otherwise, try to drip
626 end
627 else
628 begin
629 // stuck to a wall
631 begin
632 // this can happen if mplat was moved out; find new `wallEndY`
635 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
637 _stuckagain:
638 // floor transition?
640 begin
644 begin
645 // check if our ground wasn't moved since the last scan
648 begin
652 // otherwise, do it again
656 begin
657 // rescan, so we'll know when we'll exit the liquid
661 begin
662 // rescan, so we'll know when we'll enter something interesting
668 // wall transition?
670 begin
671 // just unstuck from the wall, switch to freefall mode
674 end
675 else
676 begin
677 // otherwise, try to drip
681 // nope, process as usual
684 // it is important to have it here
690 // gravity, if not stuck
692 begin
695 _gravityagain:
696 // floor transition?
698 begin
701 begin
702 // check if our ground wasn't moved since the last scan
704 begin
709 // otherwise, nothing to do
712 begin
713 // rescan, so we'll know when we'll exit the liquid
718 begin
719 // rescan, so we'll know when we'll enter something interesting
721 if (floorType <> TFloorType.Wall) or (floorY <> y) then applyGravity(floorType = TFloorType.LiquidIn);
724 end
725 else
726 begin
727 // looks like we're in the air
732 // trace movement
734 begin
735 // has some horizontal velocity
741 begin
742 // dunno yet
745 // check environment (air/liquid)
746 if (g_Map_PanelAtPoint(x, y, GridTagLiquid) <> nil) then env := TEnvType.ELiquid else env := TEnvType.EAir;
749 begin
750 // we stuck
751 // the only case when we can have both ceiling and wall is corner; stick to wall in this case
752 // check if we stuck to a wall
755 begin
756 // stuck to a wall
758 end
759 else
760 begin
761 // stuck to a ceiling
765 end
767 begin
768 // has only vertical velocity
770 begin
771 // flying up
775 // environment didn't changed
776 end
777 else
778 begin
780 begin
781 // falling down
786 //e_LogWritefln('floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
788 begin
789 // floor transition
792 //e_LogWritefln(' HIT FLOORY: floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
795 begin
796 // check if our ground wasn't moved since the last scan
798 begin
799 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
801 {$ENDIF}
803 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
805 begin
806 e_LogWritefln('force rescanning vpart at (%s,%s); oldFloorY=%s; floorY=%s', [x, y, oldFloorY, floorY]);
808 {$ENDIF}
812 // environment didn't changed
817 begin
818 // we're entered the liquid
820 // rescan, so we'll know when we'll exit the liquid
824 begin
825 // we're exited the liquid
827 // rescan, so we'll know when we'll enter something interesting
830 begin
836 end
837 else
838 begin
845 else
846 begin
847 // simple blood
855 _done:
856 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
861 // blood will dissolve in other liquids
863 begin
865 begin
873 end
874 else
875 begin
876 // water will disappear in any liquid
879 // dry water
889 // ////////////////////////////////////////////////////////////////////////// //
890 procedure g_GFX_SparkVel (fX, fY: Integer; count: Word; vx, vy: Integer; devX, devY: Byte); forward;
896 begin
898 begin
903 end
904 else
905 begin
910 var
916 begin
920 begin
922 exit;
935 begin
937 begin
941 // check for level bounds
944 // in what environment we are starting in?
947 begin
948 // either in a wall, or in a liquid
951 end
952 else
953 begin
961 begin
988 procedure g_GFX_Water (fX, fY: Integer; count: Word; fVelX, fVelY: Single; devX, devY, color: Byte;
990 var
995 begin
1012 begin
1014 begin
1016 begin
1025 end
1026 else
1027 begin
1037 // check for level bounds
1040 // this hack will allow water spawned in water to fly out
1041 // it can happen when player fell from a huge height (see "DOOM2D.WAD:\MAP03", for example)
1043 begin
1044 // in what environment we are starting in?
1046 end
1047 else
1048 begin
1054 // color
1057 begin
1063 begin
1069 begin
1075 begin
1084 begin
1093 begin
1114 procedure g_GFX_SimpleWater (fX, fY: Integer; count: Word; fVelX, fVelY: Single; defColor, cr, cg, cb: Byte);
1115 begin
1120 // ////////////////////////////////////////////////////////////////////////// //
1122 var
1124 begin
1128 begin
1131 begin
1133 end
1134 else
1135 begin
1147 {.$DEFINE D2F_DEBUG_BUBBLES}
1149 var
1153 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1156 {$ENDIF}
1157 begin
1170 begin
1172 begin
1176 // check for level bounds
1179 (*
1180 // don't spawn bubbles outside of the liquid
1181 if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
1182 Continue;
1183 *)
1185 // trace liquid, so we'll know where it ends; do it in 8px steps for speed
1186 // tracer will return `false` if we started outside of the liquid
1188 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1190 ptr := mapGrid.traceOrthoRayWhileIn(liquidx, liquidTopY, x, y, x, 0, GridTagWater or GridTagAcid1 or GridTagAcid2);
1192 e_LogWritefln('traceOrthoRayWhileIn: time=%s (%s); liquidTopY=%s', [Integer(stt), ptr, liquidTopY]);
1193 //
1197 e_LogWritefln('g_Map_TraceLiquidNonPrecise: time=%s (%s); liquidTopY=%s', [Integer(stt), nptr, liquidTopY]);
1199 {$ELSE}
1202 {$ENDIF}
1225 // ////////////////////////////////////////////////////////////////////////// //
1227 label
1228 _done;
1229 var
1233 begin
1239 // apply gravity
1241 begin
1246 // flying
1248 begin
1249 // has some horizontal velocity
1255 begin
1257 // hit the wall; falling down vertically
1261 end
1263 begin
1264 // has some vertical velocity
1266 begin
1267 // flying up
1271 begin
1272 // oops, hit a ceiling
1277 // environment didn't changed
1278 end
1279 else
1280 begin
1281 // falling down
1285 begin
1286 // hit something except a floor?
1288 // otherwise, go to sleep
1291 // environment didn't changed
1296 _done:
1297 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
1302 begin
1311 // ////////////////////////////////////////////////////////////////////////// //
1313 var
1318 begin
1331 begin
1333 begin
1337 // check for level bounds
1340 // in what environment we are starting in?
1343 begin
1344 // either in a wall, or in a liquid
1345 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1346 //env := TEnvType.ELiquid;
1347 continue;
1348 end
1349 else
1350 begin
1358 begin
1384 var
1391 begin
1412 begin
1414 begin
1418 // check for level bounds
1421 // in what environment we are starting in?
1424 begin
1425 // either in a wall, or in a liquid
1426 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1427 //env := TEnvType.ELiquid;
1428 continue;
1429 end
1430 else
1431 begin
1458 // ////////////////////////////////////////////////////////////////////////// //
1460 var
1462 begin
1473 begin
1479 var
1481 begin
1485 begin
1487 Exit;
1491 begin
1494 end
1495 else
1496 begin
1504 var
1506 begin
1522 // ////////////////////////////////////////////////////////////////////////// //
1524 begin
1525 //g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
1526 //SetLength(gCollideMap, gMapInfo.Height+1);
1527 //for a := 0 to High(gCollideMap) do SetLength(gCollideMap[a], gMapInfo.Width+1);
1529 {$IFDEF HEADLESS}
1531 {$ENDIF}
1536 var
1538 begin
1545 begin
1551 // why not?
1557 // ////////////////////////////////////////////////////////////////////////// //
1559 var
1563 begin
1567 begin
1574 begin
1576 begin
1578 begin
1587 // clear awake map
1591 begin
1594 begin
1596 ONCEANIM_SMOKE:
1597 begin
1606 begin
1609 end
1610 else
1618 var
1621 begin
1625 begin
1638 begin
1640 begin
1643 begin
1656 begin
1659 begin
1661 begin