8bdbf88400547702ff9f29aff9e964f1e15d2276
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
370 begin
371 // awake sleeping particle, if necessary
373 begin
377 else
389 // ////////////////////////////////////////////////////////////////////////// //
392 begin
400 var
402 begin
406 // find next floor transition
408 // find `wallEndY`
409 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
413 begin
420 // `true`: didn't, get outa thinker
422 begin
431 // switch to freefall mode
433 begin
440 begin
443 begin
446 end
447 else
448 begin
454 label
455 _done;
456 var
461 begin
465 begin
466 // still check for air streams when sleeping (no)
467 if (state = TPartState.Sleeping) then begin {checkAirStreams();} goto _done; end; // so blood will dissolve
469 // process stuck particles
471 begin
472 // stuck to a ceiling?
474 begin
475 // yeah, stuck to a ceiling
477 // dropped from a ceiling?
479 begin
480 // yep
484 end
485 else
486 begin
487 // otherwise, try to drip
490 end
491 else
492 begin
493 // stuck to a wall
495 // floor transition?
497 begin
501 begin
506 begin
507 // rescan, so we'll know when we'll exit the liquid
511 begin
512 // rescan, so we'll know when we'll enter something interesting
518 // wall transition?
520 begin
521 // just unstuck from the wall, switch to freefall mode
524 end
525 else
526 begin
527 // otherwise, try to drip
531 // nope, process as usual
534 // it is important to have it here
540 // gravity, if not stuck
542 begin
544 // floor transition?
546 begin
549 begin
550 // nothing to do
553 begin
554 // rescan, so we'll know when we'll exit the liquid
559 begin
560 // rescan, so we'll know when we'll enter something interesting
562 if (floorType <> TFloorType.Wall) or (floorY <> y) then applyGravity(floorType = TFloorType.LiquidIn);
565 end
566 else
567 begin
568 // looks like we're in the air
573 // trace movement
575 begin
576 // has some horizontal velocity
582 begin
583 // dunno yet
586 // check environment (air/liquid)
587 if (g_Map_PanelAtPoint(x, y, GridTagLiquid) <> nil) then env := TEnvType.ELiquid else env := TEnvType.EAir;
590 begin
591 // we stuck
592 // the only case when we can have both ceiling and wall is corner; stick to wall in this case
593 // check if we stuck to a wall
596 begin
597 // stuck to a wall
599 end
600 else
601 begin
602 // stuck to a ceiling
606 end
608 begin
609 // has only vertical velocity
611 begin
612 // flying up
616 // environment didn't changed
617 end
618 else
619 begin
621 begin
622 // falling down
626 //e_LogWritefln('floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
628 begin
629 // floor transition
632 //e_LogWritefln(' HIT FLOORY: floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
635 begin
636 // environment didn't changed
641 begin
642 // we're entered the liquid
644 // rescan, so we'll know when we'll exit the liquid
648 begin
649 // we're exited the liquid
651 // rescan, so we'll know when we'll enter something interesting
654 begin
660 end
661 else
662 begin
669 else
670 begin
671 // simple blood
679 _done:
680 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
685 // blood will dissolve in other liquids
687 begin
689 begin
697 end
698 else
699 begin
700 // water will disappear in any liquid
703 // dry water
713 // ////////////////////////////////////////////////////////////////////////// //
714 procedure g_GFX_SparkVel (fX, fY: Integer; count: Word; vx, vy: Integer; devX, devY: Byte); forward;
720 begin
722 begin
727 end
728 else
729 begin
734 var
740 begin
744 begin
746 exit;
759 begin
761 begin
765 // check for level bounds
768 // in what environment we are starting in?
771 begin
772 // either in a wall, or in a liquid
775 end
776 else
777 begin
785 begin
812 procedure g_GFX_Water (fX, fY: Integer; count: Word; fVelX, fVelY: Single; devX, devY, color: Byte;
814 var
819 begin
836 begin
838 begin
840 begin
849 end
850 else
851 begin
861 // check for level bounds
864 // this hack will allow water spawned in water to fly out
865 // it can happen when player fell from a huge height (see "DOOM2D.WAD:\MAP03", for example)
867 begin
868 // in what environment we are starting in?
870 end
871 else
872 begin
878 // color
881 begin
887 begin
893 begin
899 begin
908 begin
917 begin
938 procedure g_GFX_SimpleWater (fX, fY: Integer; count: Word; fVelX, fVelY: Single; defColor, cr, cg, cb: Byte);
939 begin
944 // ////////////////////////////////////////////////////////////////////////// //
946 var
948 begin
952 begin
955 begin
957 end
958 else
959 begin
971 {.$DEFINE D2F_DEBUG_BUBBLES}
973 var
977 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
980 {$ENDIF}
981 begin
994 begin
996 begin
1000 // check for level bounds
1003 (*
1004 // don't spawn bubbles outside of the liquid
1005 if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
1006 Continue;
1007 *)
1009 // trace liquid, so we'll know where it ends; do it in 8px steps for speed
1010 // tracer will return `false` if we started outside of the liquid
1012 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1014 ptr := mapGrid.traceOrthoRayWhileIn(liquidx, liquidTopY, x, y, x, 0, GridTagWater or GridTagAcid1 or GridTagAcid2);
1016 e_LogWritefln('traceOrthoRayWhileIn: time=%s (%s); liquidTopY=%s', [Integer(stt), ptr, liquidTopY]);
1017 //
1021 e_LogWritefln('g_Map_TraceLiquidNonPrecise: time=%s (%s); liquidTopY=%s', [Integer(stt), nptr, liquidTopY]);
1023 {$ELSE}
1026 {$ENDIF}
1049 // ////////////////////////////////////////////////////////////////////////// //
1051 label
1052 _done;
1053 var
1057 begin
1063 // apply gravity
1065 begin
1070 // flying
1072 begin
1073 // has some horizontal velocity
1079 begin
1081 // hit the wall; falling down vertically
1085 end
1087 begin
1088 // has some vertical velocity
1090 begin
1091 // flying up
1095 begin
1096 // oops, hit a ceiling
1101 // environment didn't changed
1102 end
1103 else
1104 begin
1105 // falling down
1109 begin
1110 // hit something except a floor?
1112 // otherwise, go to sleep
1115 // environment didn't changed
1120 _done:
1121 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
1126 begin
1135 // ////////////////////////////////////////////////////////////////////////// //
1137 var
1142 begin
1155 begin
1157 begin
1161 // check for level bounds
1164 // in what environment we are starting in?
1167 begin
1168 // either in a wall, or in a liquid
1169 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1170 //env := TEnvType.ELiquid;
1171 continue;
1172 end
1173 else
1174 begin
1182 begin
1208 var
1215 begin
1236 begin
1238 begin
1242 // check for level bounds
1245 // in what environment we are starting in?
1248 begin
1249 // either in a wall, or in a liquid
1250 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1251 //env := TEnvType.ELiquid;
1252 continue;
1253 end
1254 else
1255 begin
1282 // ////////////////////////////////////////////////////////////////////////// //
1284 var
1286 begin
1297 begin
1303 var
1305 begin
1309 begin
1311 Exit;
1315 begin
1318 end
1319 else
1320 begin
1328 var
1330 begin
1346 // ////////////////////////////////////////////////////////////////////////// //
1347 // st: set mark
1348 // t: mark type
1349 // currently unused
1351 var
1354 begin
1358 // make some border, so we'll hit particles lying around the panel
1365 begin
1368 begin
1377 // ////////////////////////////////////////////////////////////////////////// //
1379 begin
1380 //g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
1381 //SetLength(gCollideMap, gMapInfo.Height+1);
1382 //for a := 0 to High(gCollideMap) do SetLength(gCollideMap[a], gMapInfo.Width+1);
1384 {$IFDEF HEADLESS}
1386 {$ENDIF}
1391 var
1393 begin
1400 begin
1406 // why not?
1412 // ////////////////////////////////////////////////////////////////////////// //
1414 var
1418 begin
1422 begin
1429 begin
1431 begin
1433 begin
1442 // clear awake map
1446 begin
1449 begin
1451 ONCEANIM_SMOKE:
1452 begin
1461 begin
1464 end
1465 else
1473 var
1475 begin
1479 begin
1490 begin
1492 begin
1494 begin
1507 begin
1510 begin
1512 begin