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
871 else
879 end
880 else
881 begin
882 // water will disappear in any liquid
886 else
888 // dry water
898 // ////////////////////////////////////////////////////////////////////////// //
899 procedure g_GFX_SparkVel (fX, fY: Integer; count: Word; vx, vy: Integer; devX, devY: Byte); forward;
905 begin
907 begin
912 end
913 else
914 begin
919 var
925 begin
929 begin
931 exit;
932 end
934 begin
949 begin
951 begin
955 // check for level bounds
958 // in what environment we are starting in?
961 begin
962 // either in a wall, or in a liquid
965 end
966 else
967 begin
975 begin
1003 procedure g_GFX_Water (fX, fY: Integer; count: Word; fVelX, fVelY: Single; devX, devY, color: Byte;
1005 var
1010 begin
1027 begin
1029 begin
1031 begin
1040 end
1041 else
1042 begin
1052 // check for level bounds
1055 // this hack will allow water spawned in water to fly out
1056 // it can happen when player fell from a huge height (see "DOOM2D.WAD:\MAP03", for example)
1058 begin
1059 // in what environment we are starting in?
1061 end
1062 else
1063 begin
1069 // color
1072 begin
1078 begin
1084 begin
1090 begin
1099 begin
1108 begin
1130 procedure g_GFX_SimpleWater (fX, fY: Integer; count: Word; fVelX, fVelY: Single; defColor, cr, cg, cb: Byte);
1131 begin
1136 // ////////////////////////////////////////////////////////////////////////// //
1138 var
1140 begin
1144 begin
1147 begin
1149 end
1150 else
1151 begin
1161 else
1166 {.$DEFINE D2F_DEBUG_BUBBLES}
1168 var
1172 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1175 {$ENDIF}
1176 begin
1189 begin
1191 begin
1195 // check for level bounds
1198 (*
1199 // don't spawn bubbles outside of the liquid
1200 if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
1201 Continue;
1202 *)
1204 // trace liquid, so we'll know where it ends; do it in 8px steps for speed
1205 // tracer will return `false` if we started outside of the liquid
1207 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1209 ptr := mapGrid.traceOrthoRayWhileIn(liquidx, liquidTopY, x, y, x, 0, GridTagWater or GridTagAcid1 or GridTagAcid2);
1211 e_LogWritefln('traceOrthoRayWhileIn: time=%s (%s); liquidTopY=%s', [Integer(stt), ptr, liquidTopY]);
1212 //
1216 e_LogWritefln('g_Map_TraceLiquidNonPrecise: time=%s (%s); liquidTopY=%s', [Integer(stt), nptr, liquidTopY]);
1218 {$ELSE}
1221 {$ENDIF}
1245 // ////////////////////////////////////////////////////////////////////////// //
1247 label
1248 _done;
1249 var
1253 begin
1259 //writeln('spark0: pos=(', x, ',', y, '); delta=(', dx, ',', dy, '); state=', state, '; ceilingY=', ceilingY, '; floorY=', floorY);
1261 // apply gravity
1263 begin
1268 // flying
1270 begin
1271 // has some horizontal velocity
1277 begin
1279 // hit the wall; falling down vertically
1283 end
1285 begin
1286 // has some vertical velocity
1288 begin
1289 // flying up
1293 begin
1294 // oops, hit a ceiling
1299 // environment didn't changed
1300 end
1301 else
1302 begin
1303 // falling down
1307 begin
1308 // hit something except a floor?
1310 // otherwise, go to sleep
1313 // environment didn't changed
1318 _done:
1319 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
1324 begin
1329 //writeln('spark1: pos=(', x, ',', y, '); delta=(', velX:6:3, ',', velY:6:3, '); state=', state, '; ceilingY=', ceilingY, '; floorY=', floorY);
1333 else
1338 // ////////////////////////////////////////////////////////////////////////// //
1340 var
1345 begin
1358 begin
1360 begin
1364 // check for level bounds
1367 // in what environment we are starting in?
1370 begin
1371 // either in a wall, or in a liquid
1372 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1373 //env := TEnvType.ELiquid;
1374 continue;
1375 end
1376 else
1377 begin
1385 begin
1412 var
1419 begin
1440 begin
1442 begin
1446 // check for level bounds
1449 // in what environment we are starting in?
1452 begin
1453 // either in a wall, or in a liquid
1454 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1455 //env := TEnvType.ELiquid;
1456 continue;
1457 end
1458 else
1459 begin
1487 // ////////////////////////////////////////////////////////////////////////// //
1489 var
1491 begin
1502 begin
1508 var
1510 begin
1514 begin
1516 Exit;
1520 begin
1523 end
1524 else
1525 begin
1533 var
1535 begin
1551 // ////////////////////////////////////////////////////////////////////////// //
1553 begin
1554 //g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
1555 //SetLength(gCollideMap, gMapInfo.Height+1);
1556 //for a := 0 to High(gCollideMap) do SetLength(gCollideMap[a], gMapInfo.Width+1);
1558 {$IFDEF HEADLESS}
1560 {$ENDIF}
1565 var
1567 begin
1574 begin
1580 // why not?
1586 // ////////////////////////////////////////////////////////////////////////// //
1588 var
1592 begin
1596 begin
1603 begin
1605 begin
1607 begin
1616 // clear awake map
1620 begin
1623 begin
1625 ONCEANIM_SMOKE:
1626 begin
1635 begin
1638 end
1639 else
1647 var
1649 {$IFDEF USE_NANOGL}
1650 type
1655 var
1658 {$ENDIF}
1659 begin
1663 begin
1673 {$IFDEF USE_NANOGL}
1677 begin
1679 begin
1681 begin
1700 {$ELSE}
1705 begin
1707 begin
1710 begin
1718 {$ENDIF}
1724 begin
1727 begin
1729 begin