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}
19 interface
21 uses
24 const
51 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)
93 // note: this MUST be record, so we can keep it in
94 // dynamic array and has sequential memory access pattern
113 //k8: sorry, i have to emulate virtual methods this way, 'cause i haet `Object`
138 var
143 // awakeMap has one bit for each map grid cell; on g_Mark,
144 // corresponding bits will be set, and in `think()` all particles
145 // in marked cells will be awaken
153 // ////////////////////////////////////////////////////////////////////////// //
154 // HACK! using mapgrid
156 begin
158 begin
166 begin
174 {$IF DEFINED(D2F_DEBUG)}
175 e_LogWritefln('particle awake map: %sx%s (for grid of size %sx%s)', [awakeMapW, awakeMapH, mapGrid.gridWidth, mapGrid.gridHeight]);
176 {$ENDIF}
183 begin
187 begin
188 {$IF DEFINED(D2F_DEBUG)}
190 {$ENDIF}
192 end
193 else
194 begin
201 var
203 begin
207 begin
208 {$IF DEFINED(D2F_DEBUG)}
210 {$ENDIF}
218 // ////////////////////////////////////////////////////////////////////////// //
222 // remove velocities and acceleration
224 begin
225 // stop right there, you criminal scum!
233 // `true`: affected by air stream
235 var
237 begin
241 begin
243 begin
248 end
250 begin
253 end
255 begin
258 end
259 else
260 begin
263 // awake
269 // switch to sleep mode
271 begin
273 begin
281 var
284 begin
286 // stuck in the wall? rescan, 'cause it can be mplat
288 begin
291 begin
292 // either in a wall, or in a liquid
294 begin
295 // we are in the wall, wtf?!
300 exit;
302 // we are in liquid, trace to liquid end
306 // are we in a liquid?
308 begin
309 // trace out of the liquid
310 //env := TEnvType.ELiquid;
312 //e_LogWritefln('tracing out of a liquid; floorY=%s; y=%s', [floorY, y]);
315 //e_LogWritefln(' traced out of a liquid; floorY=%s; y=%s', [floorY, y]);
316 end
317 else
318 begin
319 // in the air
321 //env := TEnvType.EAir;
322 pan := g_Map_traceToNearest(x, y, x, g_Map_MaxY, (GridTagObstacle or GridTagLiquid), @ex, @floorY);
324 begin
325 // wall or liquid
327 begin
328 // wall
330 end
331 else
332 begin
333 // liquid
337 end
338 else
339 begin
340 // out of the level; assume wall, but it doesn't really matter
349 var
351 begin
354 begin
361 begin
362 // awake sleeping particle, if necessary
364 begin
368 begin
385 // ////////////////////////////////////////////////////////////////////////// //
388 begin
396 var
398 begin
402 // find next floor transition
404 // find `wallEndY`
405 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
409 begin
416 // `true`: didn't, get outa thinker
418 begin
427 // switch to freefall mode
429 begin
436 begin
439 begin
442 end
443 else
444 begin
450 label
451 _done;
452 var
457 begin
461 begin
462 // still check for air streams when sleeping (no)
463 if (state = TPartState.Sleeping) then begin {checkAirStreams();} goto _done; end; // so blood will dissolve
465 // process stuck particles
467 begin
468 // stuck to a ceiling?
470 begin
471 // yeah, stuck to a ceiling
473 // dropped from a ceiling?
475 begin
476 // yep
480 end
481 else
482 begin
483 // otherwise, try to drip
486 end
487 else
488 begin
489 // stuck to a wall
491 // floor transition?
493 begin
497 begin
502 begin
503 // rescan, so we'll know when we'll exit the liquid
507 begin
508 // rescan, so we'll know when we'll enter something interesting
514 // wall transition?
516 begin
517 // just unstuck from the wall, switch to freefall mode
520 end
521 else
522 begin
523 // otherwise, try to drip
527 // nope, process as usual
530 // it is important to have it here
536 // gravity, if not stuck
538 begin
540 // floor transition?
542 begin
545 begin
546 // nothing to do
549 begin
550 // rescan, so we'll know when we'll exit the liquid
555 begin
556 // rescan, so we'll know when we'll enter something interesting
558 if (floorType <> TFloorType.Wall) or (floorY <> y) then applyGravity(floorType = TFloorType.LiquidIn);
561 end
562 else
563 begin
564 // looks like we're in the air
569 // trace movement
571 begin
572 // has some horizontal velocity
578 begin
579 // dunno yet
582 // check environment (air/liquid)
583 if (g_Map_PanelAtPoint(x, y, GridTagLiquid) <> nil) then env := TEnvType.ELiquid else env := TEnvType.EAir;
586 begin
587 // we stuck
588 // the only case when we can have both ceiling and wall is corner; stick to wall in this case
589 // check if we stuck to a wall
592 begin
593 // stuck to a wall
595 end
596 else
597 begin
598 // stuck to a ceiling
602 end
604 begin
605 // has only vertical velocity
607 begin
608 // flying up
612 // environment didn't changed
613 end
614 else
615 begin
617 begin
618 // falling down
622 //e_LogWritefln('floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
624 begin
625 // floor transition
628 //e_LogWritefln(' HIT FLOORY: floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
631 begin
632 // environment didn't changed
637 begin
638 // we're entered the liquid
640 // rescan, so we'll know when we'll exit the liquid
644 begin
645 // we're exited the liquid
647 // rescan, so we'll know when we'll enter something interesting
650 begin
656 end
657 else
658 begin
665 else
666 begin
667 // simple blood
675 _done:
676 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
681 // blood will dissolve in other liquids
683 begin
685 begin
693 end
694 else
695 begin
696 // water will disappear in any liquid
699 // dry water
709 // ////////////////////////////////////////////////////////////////////////// //
710 procedure g_GFX_SparkVel (fX, fY: Integer; count: Word; vx, vy: Integer; devX, devY: Byte); forward;
716 begin
718 begin
723 end
724 else
725 begin
730 var
736 begin
740 begin
742 exit;
755 begin
757 begin
761 // check for level bounds
764 // in what environment we are starting in?
767 begin
768 // either in a wall, or in a liquid
771 end
772 else
773 begin
781 begin
808 procedure g_GFX_Water (fX, fY: Integer; count: Word; fVelX, fVelY: Single; devX, devY, color: Byte;
810 var
815 begin
832 begin
834 begin
836 begin
845 end
846 else
847 begin
857 // check for level bounds
860 // this hack will allow water spawned in water to fly out
861 // it can happen when player fell from a huge height (see "DOOM2D.WAD:\MAP03", for example)
863 begin
864 // in what environment we are starting in?
866 end
867 else
868 begin
873 // color
876 begin
882 begin
888 begin
894 begin
903 begin
912 begin
933 procedure g_GFX_SimpleWater (fX, fY: Integer; count: Word; fVelX, fVelY: Single; defColor, cr, cg, cb: Byte);
934 begin
939 // ////////////////////////////////////////////////////////////////////////// //
941 var
943 begin
947 begin
950 begin
952 end
953 else
954 begin
966 {.$DEFINE D2F_DEBUG_BUBBLES}
968 var
972 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
975 {$ENDIF}
976 begin
989 begin
991 begin
995 // check for level bounds
998 (*
999 // don't spawn bubbles outside of the liquid
1000 if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
1001 Continue;
1002 *)
1004 // trace liquid, so we'll know where it ends; do it in 8px steps for speed
1005 // tracer will return `false` if we started outside of the liquid
1007 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1009 ptr := mapGrid.traceOrthoRayWhileIn(liquidx, liquidTopY, x, y, x, 0, GridTagWater or GridTagAcid1 or GridTagAcid2);
1011 e_LogWritefln('traceOrthoRayWhileIn: time=%s (%s); liquidTopY=%s', [Integer(stt), ptr, liquidTopY]);
1012 //
1016 e_LogWritefln('g_Map_TraceLiquidNonPrecise: time=%s (%s); liquidTopY=%s', [Integer(stt), nptr, liquidTopY]);
1018 {$ELSE}
1021 {$ENDIF}
1044 // ////////////////////////////////////////////////////////////////////////// //
1046 label
1047 _done;
1048 var
1052 begin
1058 // apply gravity
1060 begin
1065 // flying
1067 begin
1068 // has some horizontal velocity
1074 begin
1076 // hit the wall; falling down vertically
1080 end
1082 begin
1083 // has some vertical velocity
1085 begin
1086 // flying up
1090 begin
1091 // oops, hit a ceiling
1096 // environment didn't changed
1097 end
1098 else
1099 begin
1100 // falling down
1104 begin
1105 // hit something except a floor?
1107 // otherwise, go to sleep
1110 // environment didn't changed
1115 _done:
1116 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
1121 begin
1130 // ////////////////////////////////////////////////////////////////////////// //
1132 var
1137 begin
1150 begin
1152 begin
1156 // check for level bounds
1159 // in what environment we are starting in?
1162 begin
1163 // either in a wall, or in a liquid
1164 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1165 //env := TEnvType.ELiquid;
1166 continue;
1167 end
1168 else
1169 begin
1177 begin
1203 var
1210 begin
1231 begin
1233 begin
1237 // check for level bounds
1240 // in what environment we are starting in?
1243 begin
1244 // either in a wall, or in a liquid
1245 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1246 //env := TEnvType.ELiquid;
1247 continue;
1248 end
1249 else
1250 begin
1277 // ////////////////////////////////////////////////////////////////////////// //
1279 var
1281 begin
1292 begin
1298 var
1300 begin
1304 begin
1306 Exit;
1310 begin
1313 end
1314 else
1315 begin
1323 var
1325 begin
1341 // ////////////////////////////////////////////////////////////////////////// //
1342 // st: set mark
1343 // t: mark type
1344 // currently unused
1346 var
1349 begin
1353 // make some border, so we'll hit particles lying around the panel
1360 begin
1363 begin
1372 // ////////////////////////////////////////////////////////////////////////// //
1374 begin
1375 //g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
1376 //SetLength(gCollideMap, gMapInfo.Height+1);
1377 //for a := 0 to High(gCollideMap) do SetLength(gCollideMap[a], gMapInfo.Width+1);
1379 {$IFDEF HEADLESS}
1381 {$ENDIF}
1386 var
1388 begin
1395 begin
1401 // why not?
1407 // ////////////////////////////////////////////////////////////////////////// //
1409 var
1413 begin
1417 begin
1424 begin
1426 begin
1428 begin
1437 // clear awake map
1441 begin
1444 begin
1446 ONCEANIM_SMOKE:
1447 begin
1456 begin
1459 end
1460 else
1468 var
1470 begin
1474 begin
1485 begin
1487 begin
1489 begin
1502 begin
1505 begin
1507 begin