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
360 begin
363 end
364 else
365 begin
368 // awake
374 // switch to sleep mode
376 begin
378 begin
386 var
389 begin
391 // stuck in the wall? rescan, 'cause it can be mplat
393 begin
396 begin
397 // either in a wall, or in a liquid
399 begin
400 // we are in the wall, wtf?!
405 exit;
407 // we are in liquid, trace to liquid end
411 // are we in a liquid?
413 begin
414 // trace out of the liquid
415 //env := TEnvType.ELiquid;
417 //e_LogWritefln('tracing out of a liquid; floorY=%s; y=%s', [floorY, y]);
420 //e_LogWritefln(' traced out of a liquid; floorY=%s; y=%s', [floorY, y]);
421 end
422 else
423 begin
424 // in the air
426 //env := TEnvType.EAir;
427 pan := g_Map_traceToNearest(x, y, x, g_Map_MaxY, (GridTagObstacle or GridTagLiquid), @ex, @floorY);
429 begin
430 // wall or liquid
432 begin
433 // wall
435 end
436 else
437 begin
438 // liquid
442 end
443 else
444 begin
445 // out of the level; assume wall, but it doesn't really matter
454 var
456 begin
459 begin
467 begin
469 begin
470 //writeln('awaking particle at (', x, ',', y, ')');
472 begin
474 end
475 else
476 begin
477 // stuck to a wall, check if wall is still there
479 begin
482 begin
483 // a wall was moved out, start falling
490 end
491 else
492 begin
501 begin
502 // awake sleeping particle, if necessary
504 begin
506 {
507 case state of
508 TPartState.Sleeping, TPartState.Stuck:
509 if awmIsSet(x, y) then awake();
510 else
511 if (env = TEnvType.EWall) and awmIsSet(x, y) then awake();
512 end;
513 }
523 // ////////////////////////////////////////////////////////////////////////// //
526 begin
534 var
536 begin
540 // find next floor transition
542 // find `wallEndY`
543 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
547 begin
554 // `true`: didn't, get outa thinker
556 begin
563 begin
566 // if we're falling from ceiling, switch to normal mode
571 // switch to freefall mode
573 begin
580 begin
583 begin
586 end
587 else
588 begin
594 label
596 var
602 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
604 {$ENDIF}
605 begin
609 begin
610 // still check for air streams when sleeping (no)
611 if (state = TPartState.Sleeping) then begin {checkAirStreams();} goto _done; end; // so blood will dissolve
613 // process stuck particles
615 begin
616 // stuck to a ceiling?
618 begin
619 // yeah, stuck to a ceiling
621 // dropped from a ceiling?
623 begin
624 // yep
628 end
629 else
630 begin
631 // otherwise, try to drip
634 end
635 else
636 begin
637 // stuck to a wall
639 begin
640 // this can happen if mplat was moved out; find new `wallEndY`
643 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
645 _stuckagain:
646 // floor transition?
648 begin
652 begin
653 // check if our ground wasn't moved since the last scan
656 begin
660 // otherwise, do it again
664 begin
665 // rescan, so we'll know when we'll exit the liquid
669 begin
670 // rescan, so we'll know when we'll enter something interesting
676 // wall transition?
678 begin
679 // just unstuck from the wall, switch to freefall mode
682 end
683 else
684 begin
685 // otherwise, try to drip
689 // nope, process as usual
692 // it is important to have it here
698 // gravity, if not stuck
700 begin
703 _gravityagain:
704 // floor transition?
706 begin
709 begin
710 // check if our ground wasn't moved since the last scan
712 begin
717 // otherwise, nothing to do
720 begin
721 // rescan, so we'll know when we'll exit the liquid
726 begin
727 // rescan, so we'll know when we'll enter something interesting
729 if (floorType <> TFloorType.Wall) or (floorY <> y) then applyGravity(floorType = TFloorType.LiquidIn);
732 end
733 else
734 begin
735 // looks like we're in the air
740 // trace movement
742 begin
743 // has some horizontal velocity
749 begin
750 // dunno yet
753 // check environment (air/liquid)
754 if (g_Map_PanelAtPoint(x, y, GridTagLiquid) <> nil) then env := TEnvType.ELiquid else env := TEnvType.EAir;
757 begin
758 // we stuck
759 // the only case when we can have both ceiling and wall is corner; stick to wall in this case
760 // check if we stuck to a wall
763 begin
764 // stuck to a wall
766 end
767 else
768 begin
769 // stuck to a ceiling
773 end
775 begin
776 // has only vertical velocity
778 begin
779 // flying up
783 // environment didn't changed
784 end
785 else
786 begin
788 begin
789 // falling down
794 //e_LogWritefln('floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
796 begin
797 // floor transition
800 //e_LogWritefln(' HIT FLOORY: floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
803 begin
804 // check if our ground wasn't moved since the last scan
806 begin
807 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
809 {$ENDIF}
811 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
813 begin
814 e_LogWritefln('force rescanning vpart at (%s,%s); oldFloorY=%s; floorY=%s', [x, y, oldFloorY, floorY]);
816 {$ENDIF}
820 // environment didn't changed
825 begin
826 // we're entered the liquid
828 // rescan, so we'll know when we'll exit the liquid
832 begin
833 // we're exited the liquid
835 // rescan, so we'll know when we'll enter something interesting
838 begin
844 end
845 else
846 begin
853 else
854 begin
855 // simple blood
863 _done:
864 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
869 // blood will dissolve in other liquids
871 begin
873 begin
876 else
884 end
885 else
886 begin
887 // water will disappear in any liquid
891 else
893 // dry water
903 // ////////////////////////////////////////////////////////////////////////// //
904 procedure g_GFX_SparkVel (fX, fY: Integer; count: Word; vx, vy: Integer; devX, devY: Byte); forward;
910 begin
912 begin
917 end
918 else
919 begin
924 var
930 begin
934 begin
936 exit;
937 end
939 begin
954 begin
956 begin
960 // check for level bounds
963 // in what environment we are starting in?
966 begin
967 // either in a wall, or in a liquid
970 end
971 else
972 begin
980 begin
1008 procedure g_GFX_Water (fX, fY: Integer; count: Word; fVelX, fVelY: Single; devX, devY, color: Byte;
1010 var
1015 begin
1032 begin
1034 begin
1036 begin
1045 end
1046 else
1047 begin
1057 // check for level bounds
1060 // this hack will allow water spawned in water to fly out
1061 // it can happen when player fell from a huge height (see "DOOM2D.WAD:\MAP03", for example)
1063 begin
1064 // in what environment we are starting in?
1066 end
1067 else
1068 begin
1074 // color
1077 begin
1083 begin
1089 begin
1095 begin
1104 begin
1113 begin
1135 procedure g_GFX_SimpleWater (fX, fY: Integer; count: Word; fVelX, fVelY: Single; defColor, cr, cg, cb: Byte);
1136 begin
1141 // ////////////////////////////////////////////////////////////////////////// //
1143 var
1145 begin
1149 begin
1152 begin
1154 end
1155 else
1156 begin
1166 else
1171 {.$DEFINE D2F_DEBUG_BUBBLES}
1173 var
1177 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1180 {$ENDIF}
1181 begin
1194 begin
1196 begin
1200 // check for level bounds
1203 (*
1204 // don't spawn bubbles outside of the liquid
1205 if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
1206 Continue;
1207 *)
1209 // trace liquid, so we'll know where it ends; do it in 8px steps for speed
1210 // tracer will return `false` if we started outside of the liquid
1212 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1214 ptr := mapGrid.traceOrthoRayWhileIn(liquidx, liquidTopY, x, y, x, 0, GridTagWater or GridTagAcid1 or GridTagAcid2);
1216 e_LogWritefln('traceOrthoRayWhileIn: time=%s (%s); liquidTopY=%s', [Integer(stt), ptr, liquidTopY]);
1217 //
1221 e_LogWritefln('g_Map_TraceLiquidNonPrecise: time=%s (%s); liquidTopY=%s', [Integer(stt), nptr, liquidTopY]);
1223 {$ELSE}
1226 {$ENDIF}
1250 // ////////////////////////////////////////////////////////////////////////// //
1252 label
1253 _done;
1254 var
1258 begin
1264 //writeln('spark0: pos=(', x, ',', y, '); delta=(', dx, ',', dy, '); state=', state, '; ceilingY=', ceilingY, '; floorY=', floorY);
1266 // apply gravity
1268 begin
1273 // flying
1275 begin
1276 // has some horizontal velocity
1282 begin
1284 // hit the wall; falling down vertically
1288 end
1290 begin
1291 // has some vertical velocity
1293 begin
1294 // flying up
1298 begin
1299 // oops, hit a ceiling
1304 // environment didn't changed
1305 end
1306 else
1307 begin
1308 // falling down
1312 begin
1313 // hit something except a floor?
1315 // otherwise, go to sleep
1318 // environment didn't changed
1323 _done:
1324 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
1329 begin
1334 //writeln('spark1: pos=(', x, ',', y, '); delta=(', velX:6:3, ',', velY:6:3, '); state=', state, '; ceilingY=', ceilingY, '; floorY=', floorY);
1338 else
1343 // ////////////////////////////////////////////////////////////////////////// //
1345 var
1350 begin
1363 begin
1365 begin
1369 // check for level bounds
1372 // in what environment we are starting in?
1375 begin
1376 // either in a wall, or in a liquid
1377 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1378 //env := TEnvType.ELiquid;
1379 continue;
1380 end
1381 else
1382 begin
1390 begin
1417 var
1424 begin
1445 begin
1447 begin
1451 // check for level bounds
1454 // in what environment we are starting in?
1457 begin
1458 // either in a wall, or in a liquid
1459 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1460 //env := TEnvType.ELiquid;
1461 continue;
1462 end
1463 else
1464 begin
1492 // ////////////////////////////////////////////////////////////////////////// //
1494 var
1496 begin
1507 begin
1513 var
1515 begin
1519 begin
1521 Exit;
1525 begin
1528 end
1529 else
1530 begin
1538 var
1540 begin
1556 // ////////////////////////////////////////////////////////////////////////// //
1558 begin
1559 //g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
1560 //SetLength(gCollideMap, gMapInfo.Height+1);
1561 //for a := 0 to High(gCollideMap) do SetLength(gCollideMap[a], gMapInfo.Width+1);
1563 {$IFDEF HEADLESS}
1565 {$ENDIF}
1570 var
1572 begin
1579 begin
1585 // why not?
1591 // ////////////////////////////////////////////////////////////////////////// //
1593 var
1597 begin
1601 begin
1608 begin
1610 begin
1612 begin
1621 // clear awake map
1625 begin
1628 begin
1630 ONCEANIM_SMOKE:
1631 begin
1640 begin
1643 end
1644 else
1652 var
1654 {$IFDEF USE_NANOGL}
1655 type
1660 var
1663 {$ENDIF}
1664 begin
1668 begin
1678 {$IFDEF USE_NANOGL}
1682 begin
1684 begin
1686 begin
1705 {$ELSE}
1710 begin
1712 begin
1715 begin
1723 {$ENDIF}
1729 begin
1732 begin
1734 begin