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 //writeln('spark0: pos=(', x, ',', y, '); delta=(', dx, ',', dy, '); state=', state, '; ceilingY=', ceilingY, '; floorY=', floorY);
1241 // apply gravity
1243 begin
1248 // flying
1250 begin
1251 // has some horizontal velocity
1257 begin
1259 // hit the wall; falling down vertically
1263 end
1265 begin
1266 // has some vertical velocity
1268 begin
1269 // flying up
1273 begin
1274 // oops, hit a ceiling
1279 // environment didn't changed
1280 end
1281 else
1282 begin
1283 // falling down
1287 begin
1288 // hit something except a floor?
1290 // otherwise, go to sleep
1293 // environment didn't changed
1298 _done:
1299 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
1304 begin
1309 //writeln('spark1: pos=(', x, ',', y, '); delta=(', velX:6:3, ',', velY:6:3, '); state=', state, '; ceilingY=', ceilingY, '; floorY=', floorY);
1315 // ////////////////////////////////////////////////////////////////////////// //
1317 var
1322 begin
1335 begin
1337 begin
1341 // check for level bounds
1344 // in what environment we are starting in?
1347 begin
1348 // either in a wall, or in a liquid
1349 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1350 //env := TEnvType.ELiquid;
1351 continue;
1352 end
1353 else
1354 begin
1362 begin
1388 var
1395 begin
1416 begin
1418 begin
1422 // check for level bounds
1425 // in what environment we are starting in?
1428 begin
1429 // either in a wall, or in a liquid
1430 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1431 //env := TEnvType.ELiquid;
1432 continue;
1433 end
1434 else
1435 begin
1462 // ////////////////////////////////////////////////////////////////////////// //
1464 var
1466 begin
1477 begin
1483 var
1485 begin
1489 begin
1491 Exit;
1495 begin
1498 end
1499 else
1500 begin
1508 var
1510 begin
1526 // ////////////////////////////////////////////////////////////////////////// //
1528 begin
1529 //g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
1530 //SetLength(gCollideMap, gMapInfo.Height+1);
1531 //for a := 0 to High(gCollideMap) do SetLength(gCollideMap[a], gMapInfo.Width+1);
1533 {$IFDEF HEADLESS}
1535 {$ENDIF}
1540 var
1542 begin
1549 begin
1555 // why not?
1561 // ////////////////////////////////////////////////////////////////////////// //
1563 var
1567 begin
1571 begin
1578 begin
1580 begin
1582 begin
1591 // clear awake map
1595 begin
1598 begin
1600 ONCEANIM_SMOKE:
1601 begin
1610 begin
1613 end
1614 else
1622 var
1624 begin
1628 begin
1642 begin
1644 begin
1647 begin
1660 begin
1663 begin
1665 begin