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
362 begin
371 begin
372 // awake sleeping particle, if necessary
374 begin
378 else
390 // ////////////////////////////////////////////////////////////////////////// //
393 begin
401 var
403 begin
407 // find next floor transition
409 // find `wallEndY`
410 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
414 begin
421 // `true`: didn't, get outa thinker
423 begin
430 begin
433 // if we're falling from ceiling, switch to normal mode
438 // switch to freefall mode
440 begin
447 begin
450 begin
453 end
454 else
455 begin
461 label
463 var
469 begin
473 begin
474 // still check for air streams when sleeping (no)
475 if (state = TPartState.Sleeping) then begin {checkAirStreams();} goto _done; end; // so blood will dissolve
477 // process stuck particles
479 begin
480 // stuck to a ceiling?
482 begin
483 // yeah, stuck to a ceiling
485 // dropped from a ceiling?
487 begin
488 // yep
492 end
493 else
494 begin
495 // otherwise, try to drip
498 end
499 else
500 begin
501 // stuck to a wall
503 begin
504 // this can happen if mplat was moved out; find new `wallEndY`
507 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
509 _stuckagain:
510 // floor transition?
512 begin
516 begin
517 // check if our ground wasn't moved since the last scan
520 begin
524 // otherwise, do it again
528 begin
529 // rescan, so we'll know when we'll exit the liquid
533 begin
534 // rescan, so we'll know when we'll enter something interesting
540 // wall transition?
542 begin
543 // just unstuck from the wall, switch to freefall mode
546 end
547 else
548 begin
549 // otherwise, try to drip
553 // nope, process as usual
556 // it is important to have it here
562 // gravity, if not stuck
564 begin
567 _gravityagain:
568 // floor transition?
570 begin
573 begin
574 // check if our ground wasn't moved since the last scan
576 begin
581 // otherwise, nothing to do
584 begin
585 // rescan, so we'll know when we'll exit the liquid
590 begin
591 // rescan, so we'll know when we'll enter something interesting
593 if (floorType <> TFloorType.Wall) or (floorY <> y) then applyGravity(floorType = TFloorType.LiquidIn);
596 end
597 else
598 begin
599 // looks like we're in the air
604 // trace movement
606 begin
607 // has some horizontal velocity
613 begin
614 // dunno yet
617 // check environment (air/liquid)
618 if (g_Map_PanelAtPoint(x, y, GridTagLiquid) <> nil) then env := TEnvType.ELiquid else env := TEnvType.EAir;
621 begin
622 // we stuck
623 // the only case when we can have both ceiling and wall is corner; stick to wall in this case
624 // check if we stuck to a wall
627 begin
628 // stuck to a wall
630 end
631 else
632 begin
633 // stuck to a ceiling
637 end
639 begin
640 // has only vertical velocity
642 begin
643 // flying up
647 // environment didn't changed
648 end
649 else
650 begin
652 begin
653 // falling down
658 //e_LogWritefln('floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
660 begin
661 // floor transition
664 //e_LogWritefln(' HIT FLOORY: floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
667 begin
668 // check if our ground wasn't moved since the last scan
670 begin
677 // environment didn't changed
682 begin
683 // we're entered the liquid
685 // rescan, so we'll know when we'll exit the liquid
689 begin
690 // we're exited the liquid
692 // rescan, so we'll know when we'll enter something interesting
695 begin
701 end
702 else
703 begin
710 else
711 begin
712 // simple blood
720 _done:
721 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
726 // blood will dissolve in other liquids
728 begin
730 begin
738 end
739 else
740 begin
741 // water will disappear in any liquid
744 // dry water
754 // ////////////////////////////////////////////////////////////////////////// //
755 procedure g_GFX_SparkVel (fX, fY: Integer; count: Word; vx, vy: Integer; devX, devY: Byte); forward;
761 begin
763 begin
768 end
769 else
770 begin
775 var
781 begin
785 begin
787 exit;
800 begin
802 begin
806 // check for level bounds
809 // in what environment we are starting in?
812 begin
813 // either in a wall, or in a liquid
816 end
817 else
818 begin
826 begin
853 procedure g_GFX_Water (fX, fY: Integer; count: Word; fVelX, fVelY: Single; devX, devY, color: Byte;
855 var
860 begin
877 begin
879 begin
881 begin
890 end
891 else
892 begin
902 // check for level bounds
905 // this hack will allow water spawned in water to fly out
906 // it can happen when player fell from a huge height (see "DOOM2D.WAD:\MAP03", for example)
908 begin
909 // in what environment we are starting in?
911 end
912 else
913 begin
919 // color
922 begin
928 begin
934 begin
940 begin
949 begin
958 begin
979 procedure g_GFX_SimpleWater (fX, fY: Integer; count: Word; fVelX, fVelY: Single; defColor, cr, cg, cb: Byte);
980 begin
985 // ////////////////////////////////////////////////////////////////////////// //
987 var
989 begin
993 begin
996 begin
998 end
999 else
1000 begin
1012 {.$DEFINE D2F_DEBUG_BUBBLES}
1014 var
1018 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1021 {$ENDIF}
1022 begin
1035 begin
1037 begin
1041 // check for level bounds
1044 (*
1045 // don't spawn bubbles outside of the liquid
1046 if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
1047 Continue;
1048 *)
1050 // trace liquid, so we'll know where it ends; do it in 8px steps for speed
1051 // tracer will return `false` if we started outside of the liquid
1053 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1055 ptr := mapGrid.traceOrthoRayWhileIn(liquidx, liquidTopY, x, y, x, 0, GridTagWater or GridTagAcid1 or GridTagAcid2);
1057 e_LogWritefln('traceOrthoRayWhileIn: time=%s (%s); liquidTopY=%s', [Integer(stt), ptr, liquidTopY]);
1058 //
1062 e_LogWritefln('g_Map_TraceLiquidNonPrecise: time=%s (%s); liquidTopY=%s', [Integer(stt), nptr, liquidTopY]);
1064 {$ELSE}
1067 {$ENDIF}
1090 // ////////////////////////////////////////////////////////////////////////// //
1092 label
1093 _done;
1094 var
1098 begin
1104 // apply gravity
1106 begin
1111 // flying
1113 begin
1114 // has some horizontal velocity
1120 begin
1122 // hit the wall; falling down vertically
1126 end
1128 begin
1129 // has some vertical velocity
1131 begin
1132 // flying up
1136 begin
1137 // oops, hit a ceiling
1142 // environment didn't changed
1143 end
1144 else
1145 begin
1146 // falling down
1150 begin
1151 // hit something except a floor?
1153 // otherwise, go to sleep
1156 // environment didn't changed
1161 _done:
1162 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
1167 begin
1176 // ////////////////////////////////////////////////////////////////////////// //
1178 var
1183 begin
1196 begin
1198 begin
1202 // check for level bounds
1205 // in what environment we are starting in?
1208 begin
1209 // either in a wall, or in a liquid
1210 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1211 //env := TEnvType.ELiquid;
1212 continue;
1213 end
1214 else
1215 begin
1223 begin
1249 var
1256 begin
1277 begin
1279 begin
1283 // check for level bounds
1286 // in what environment we are starting in?
1289 begin
1290 // either in a wall, or in a liquid
1291 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1292 //env := TEnvType.ELiquid;
1293 continue;
1294 end
1295 else
1296 begin
1323 // ////////////////////////////////////////////////////////////////////////// //
1325 var
1327 begin
1338 begin
1344 var
1346 begin
1350 begin
1352 Exit;
1356 begin
1359 end
1360 else
1361 begin
1369 var
1371 begin
1387 // ////////////////////////////////////////////////////////////////////////// //
1388 // st: set mark
1389 // t: mark type
1390 // currently unused
1392 var
1395 begin
1399 // make some border, so we'll hit particles lying around the panel
1406 begin
1409 begin
1418 // ////////////////////////////////////////////////////////////////////////// //
1420 begin
1421 //g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
1422 //SetLength(gCollideMap, gMapInfo.Height+1);
1423 //for a := 0 to High(gCollideMap) do SetLength(gCollideMap[a], gMapInfo.Width+1);
1425 {$IFDEF HEADLESS}
1427 {$ENDIF}
1432 var
1434 begin
1441 begin
1447 // why not?
1453 // ////////////////////////////////////////////////////////////////////////// //
1455 var
1459 begin
1463 begin
1470 begin
1472 begin
1474 begin
1483 // clear awake map
1487 begin
1490 begin
1492 ONCEANIM_SMOKE:
1493 begin
1502 begin
1505 end
1506 else
1514 var
1517 begin
1521 begin
1534 begin
1536 begin
1539 begin
1552 begin
1555 begin
1557 begin