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
55 procedure g_GFX_Water (fX, fY: Integer; count: Word; fVelX, fVelY: Single; devX, devY, color: Byte;
57 procedure g_GFX_SimpleWater (fX, fY: Integer; count: Word; fVelX, fVelY: Single; defColor, cr, cg, cb: Byte);
71 var
76 //WARNING: only for Holmes!
80 implementation
82 uses
83 {$INCLUDE ../nogl/noGLuses.inc}
89 const
93 type
97 // Wall: floorY is just before floor
98 // LiquidIn: floorY is liquid *start* (i.e. just in a liquid)
99 // LiquidOut: floorY is liquid *end* (i.e. just out of a liquid)
102 // note: this MUST be record, so we can keep it in
103 // dynamic array and has sequential memory access pattern
122 //k8: sorry, i have to emulate virtual methods this way, 'cause i haet `Object`
147 var
152 // awakeMap has one bit for each map grid cell; on g_Mark,
153 // corresponding bits will be set, and in `think()` all particles
154 // in marked cells will be awaken
160 {$IF DEFINED(D2F_DEBUG_PART_AWAKE)}
162 {$ENDIF}
165 // ////////////////////////////////////////////////////////////////////////// //
167 begin
168 {$IF DEFINED(D2F_DEBUG_PART_AWAKE)}
173 begin
175 begin
177 end
178 else
179 begin
182 end
183 else
184 begin
187 {$ELSE}
189 {$ENDIF}
193 // ////////////////////////////////////////////////////////////////////////// //
194 // HACK! using mapgrid
196 begin
197 {$IF DEFINED(D2F_DEBUG_PART_AWAKE)}
199 begin
203 {$ENDIF}
205 begin
213 begin
221 {$IF DEFINED(D2F_DEBUG_PART_AWAKE)}
224 {$ENDIF}
225 //{$IF DEFINED(D2F_DEBUG)}
226 e_LogWritefln('particle awake map: %sx%s (for grid of size %sx%s)', [awakeMapW, awakeMapH, mapGrid.gridWidth, mapGrid.gridHeight]);
227 //{$ENDIF}
234 begin
238 begin
239 {$IF DEFINED(D2F_DEBUG)}
241 {$ENDIF}
243 end
244 else
245 begin
252 var
254 begin
258 begin
259 {$IF DEFINED(D2F_DEBUG)}
261 {$ENDIF}
269 // ////////////////////////////////////////////////////////////////////////// //
270 // st: set mark
271 // t: mark type
272 // currently unused
275 var
278 begin
284 // make some border, so we'll hit particles around the panel
295 // has something to do?
304 begin
306 begin
307 {$IF DEFINED(D2F_DEBUG)}
310 {$ENDIF}
318 // ////////////////////////////////////////////////////////////////////////// //
322 // remove velocities and acceleration
324 begin
325 // stop right there, you criminal scum!
333 // `true`: affected by air stream
335 var
337 begin
341 begin
343 begin
348 end
350 begin
353 end
355 begin
358 end
359 else
360 begin
363 // awake
369 // switch to sleep mode
371 begin
373 begin
381 var
384 begin
386 // stuck in the wall? rescan, 'cause it can be mplat
388 begin
391 begin
392 // either in a wall, or in a liquid
394 begin
395 // we are in the wall, wtf?!
400 exit;
402 // we are in liquid, trace to liquid end
406 // are we in a liquid?
408 begin
409 // trace out of the liquid
410 //env := TEnvType.ELiquid;
412 //e_LogWritefln('tracing out of a liquid; floorY=%s; y=%s', [floorY, y]);
415 //e_LogWritefln(' traced out of a liquid; floorY=%s; y=%s', [floorY, y]);
416 end
417 else
418 begin
419 // in the air
421 //env := TEnvType.EAir;
422 pan := g_Map_traceToNearest(x, y, x, g_Map_MaxY, (GridTagObstacle or GridTagLiquid), @ex, @floorY);
424 begin
425 // wall or liquid
427 begin
428 // wall
430 end
431 else
432 begin
433 // liquid
437 end
438 else
439 begin
440 // out of the level; assume wall, but it doesn't really matter
449 var
451 begin
454 begin
462 begin
464 begin
465 //writeln('awaking particle at (', x, ',', y, ')');
467 begin
469 end
470 else
471 begin
472 // stuck to a wall, check if wall is still there
474 begin
477 begin
478 // a wall was moved out, start falling
485 end
486 else
487 begin
496 begin
497 // awake sleeping particle, if necessary
499 begin
501 {
502 case state of
503 TPartState.Sleeping, TPartState.Stuck:
504 if awmIsSet(x, y) then awake();
505 else
506 if (env = TEnvType.EWall) and awmIsSet(x, y) then awake();
507 end;
508 }
518 // ////////////////////////////////////////////////////////////////////////// //
521 begin
529 var
531 begin
535 // find next floor transition
537 // find `wallEndY`
538 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
542 begin
549 // `true`: didn't, get outa thinker
551 begin
558 begin
561 // if we're falling from ceiling, switch to normal mode
566 // switch to freefall mode
568 begin
575 begin
578 begin
581 end
582 else
583 begin
589 label
591 var
597 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
599 {$ENDIF}
600 begin
604 begin
605 // still check for air streams when sleeping (no)
606 if (state = TPartState.Sleeping) then begin {checkAirStreams();} goto _done; end; // so blood will dissolve
608 // process stuck particles
610 begin
611 // stuck to a ceiling?
613 begin
614 // yeah, stuck to a ceiling
616 // dropped from a ceiling?
618 begin
619 // yep
623 end
624 else
625 begin
626 // otherwise, try to drip
629 end
630 else
631 begin
632 // stuck to a wall
634 begin
635 // this can happen if mplat was moved out; find new `wallEndY`
638 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
640 _stuckagain:
641 // floor transition?
643 begin
647 begin
648 // check if our ground wasn't moved since the last scan
651 begin
655 // otherwise, do it again
659 begin
660 // rescan, so we'll know when we'll exit the liquid
664 begin
665 // rescan, so we'll know when we'll enter something interesting
671 // wall transition?
673 begin
674 // just unstuck from the wall, switch to freefall mode
677 end
678 else
679 begin
680 // otherwise, try to drip
684 // nope, process as usual
687 // it is important to have it here
693 // gravity, if not stuck
695 begin
698 _gravityagain:
699 // floor transition?
701 begin
704 begin
705 // check if our ground wasn't moved since the last scan
707 begin
712 // otherwise, nothing to do
715 begin
716 // rescan, so we'll know when we'll exit the liquid
721 begin
722 // rescan, so we'll know when we'll enter something interesting
724 if (floorType <> TFloorType.Wall) or (floorY <> y) then applyGravity(floorType = TFloorType.LiquidIn);
727 end
728 else
729 begin
730 // looks like we're in the air
735 // trace movement
737 begin
738 // has some horizontal velocity
744 begin
745 // dunno yet
748 // check environment (air/liquid)
749 if (g_Map_PanelAtPoint(x, y, GridTagLiquid) <> nil) then env := TEnvType.ELiquid else env := TEnvType.EAir;
752 begin
753 // we stuck
754 // the only case when we can have both ceiling and wall is corner; stick to wall in this case
755 // check if we stuck to a wall
758 begin
759 // stuck to a wall
761 end
762 else
763 begin
764 // stuck to a ceiling
768 end
770 begin
771 // has only vertical velocity
773 begin
774 // flying up
778 // environment didn't changed
779 end
780 else
781 begin
783 begin
784 // falling down
789 //e_LogWritefln('floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
791 begin
792 // floor transition
795 //e_LogWritefln(' HIT FLOORY: floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
798 begin
799 // check if our ground wasn't moved since the last scan
801 begin
802 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
804 {$ENDIF}
806 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
808 begin
809 e_LogWritefln('force rescanning vpart at (%s,%s); oldFloorY=%s; floorY=%s', [x, y, oldFloorY, floorY]);
811 {$ENDIF}
815 // environment didn't changed
820 begin
821 // we're entered the liquid
823 // rescan, so we'll know when we'll exit the liquid
827 begin
828 // we're exited the liquid
830 // rescan, so we'll know when we'll enter something interesting
833 begin
839 end
840 else
841 begin
848 else
849 begin
850 // simple blood
858 _done:
859 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
864 // blood will dissolve in other liquids
866 begin
868 begin
876 end
877 else
878 begin
879 // water will disappear in any liquid
882 // dry water
892 // ////////////////////////////////////////////////////////////////////////// //
893 procedure g_GFX_SparkVel (fX, fY: Integer; count: Word; vx, vy: Integer; devX, devY: Byte); forward;
899 begin
901 begin
906 end
907 else
908 begin
913 var
919 begin
923 begin
925 exit;
926 end
928 begin
943 begin
945 begin
949 // check for level bounds
952 // in what environment we are starting in?
955 begin
956 // either in a wall, or in a liquid
959 end
960 else
961 begin
969 begin
996 procedure g_GFX_Water (fX, fY: Integer; count: Word; fVelX, fVelY: Single; devX, devY, color: Byte;
998 var
1003 begin
1020 begin
1022 begin
1024 begin
1033 end
1034 else
1035 begin
1045 // check for level bounds
1048 // this hack will allow water spawned in water to fly out
1049 // it can happen when player fell from a huge height (see "DOOM2D.WAD:\MAP03", for example)
1051 begin
1052 // in what environment we are starting in?
1054 end
1055 else
1056 begin
1062 // color
1065 begin
1071 begin
1077 begin
1083 begin
1092 begin
1101 begin
1122 procedure g_GFX_SimpleWater (fX, fY: Integer; count: Word; fVelX, fVelY: Single; defColor, cr, cg, cb: Byte);
1123 begin
1128 // ////////////////////////////////////////////////////////////////////////// //
1130 var
1132 begin
1136 begin
1139 begin
1141 end
1142 else
1143 begin
1155 {.$DEFINE D2F_DEBUG_BUBBLES}
1157 var
1161 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1164 {$ENDIF}
1165 begin
1178 begin
1180 begin
1184 // check for level bounds
1187 (*
1188 // don't spawn bubbles outside of the liquid
1189 if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
1190 Continue;
1191 *)
1193 // trace liquid, so we'll know where it ends; do it in 8px steps for speed
1194 // tracer will return `false` if we started outside of the liquid
1196 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1198 ptr := mapGrid.traceOrthoRayWhileIn(liquidx, liquidTopY, x, y, x, 0, GridTagWater or GridTagAcid1 or GridTagAcid2);
1200 e_LogWritefln('traceOrthoRayWhileIn: time=%s (%s); liquidTopY=%s', [Integer(stt), ptr, liquidTopY]);
1201 //
1205 e_LogWritefln('g_Map_TraceLiquidNonPrecise: time=%s (%s); liquidTopY=%s', [Integer(stt), nptr, liquidTopY]);
1207 {$ELSE}
1210 {$ENDIF}
1233 // ////////////////////////////////////////////////////////////////////////// //
1235 label
1236 _done;
1237 var
1241 begin
1247 //writeln('spark0: pos=(', x, ',', y, '); delta=(', dx, ',', dy, '); state=', state, '; ceilingY=', ceilingY, '; floorY=', floorY);
1249 // apply gravity
1251 begin
1256 // flying
1258 begin
1259 // has some horizontal velocity
1265 begin
1267 // hit the wall; falling down vertically
1271 end
1273 begin
1274 // has some vertical velocity
1276 begin
1277 // flying up
1281 begin
1282 // oops, hit a ceiling
1287 // environment didn't changed
1288 end
1289 else
1290 begin
1291 // falling down
1295 begin
1296 // hit something except a floor?
1298 // otherwise, go to sleep
1301 // environment didn't changed
1306 _done:
1307 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
1312 begin
1317 //writeln('spark1: pos=(', x, ',', y, '); delta=(', velX:6:3, ',', velY:6:3, '); state=', state, '; ceilingY=', ceilingY, '; floorY=', floorY);
1323 // ////////////////////////////////////////////////////////////////////////// //
1325 var
1330 begin
1343 begin
1345 begin
1349 // check for level bounds
1352 // in what environment we are starting in?
1355 begin
1356 // either in a wall, or in a liquid
1357 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1358 //env := TEnvType.ELiquid;
1359 continue;
1360 end
1361 else
1362 begin
1370 begin
1396 var
1403 begin
1424 begin
1426 begin
1430 // check for level bounds
1433 // in what environment we are starting in?
1436 begin
1437 // either in a wall, or in a liquid
1438 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1439 //env := TEnvType.ELiquid;
1440 continue;
1441 end
1442 else
1443 begin
1470 // ////////////////////////////////////////////////////////////////////////// //
1472 var
1474 begin
1485 begin
1491 var
1493 begin
1497 begin
1499 Exit;
1503 begin
1506 end
1507 else
1508 begin
1516 var
1518 begin
1534 // ////////////////////////////////////////////////////////////////////////// //
1536 begin
1537 //g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
1538 //SetLength(gCollideMap, gMapInfo.Height+1);
1539 //for a := 0 to High(gCollideMap) do SetLength(gCollideMap[a], gMapInfo.Width+1);
1541 {$IFDEF HEADLESS}
1543 {$ENDIF}
1548 var
1550 begin
1557 begin
1563 // why not?
1569 // ////////////////////////////////////////////////////////////////////////// //
1571 var
1575 begin
1579 begin
1586 begin
1588 begin
1590 begin
1599 // clear awake map
1603 begin
1606 begin
1608 ONCEANIM_SMOKE:
1609 begin
1618 begin
1621 end
1622 else
1630 var
1632 {$IFDEF USE_NANOGL}
1633 type
1638 var
1641 {$ENDIF}
1642 begin
1646 begin
1656 {$IFDEF USE_NANOGL}
1660 begin
1662 begin
1664 begin
1683 {$ELSE}
1688 begin
1690 begin
1693 begin
1701 {$ENDIF}
1707 begin
1710 begin
1712 begin