e92f369d78fd66ce8b8cfd57298003928bb0ef42
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
338 begin
343 begin
345 begin
350 end
352 begin
355 end
357 begin
360 end
362 begin
365 end
366 else
367 begin
370 // awake
376 // switch to sleep mode
378 begin
380 begin
388 var
391 begin
393 // stuck in the wall? rescan, 'cause it can be mplat
395 begin
398 begin
399 // either in a wall, or in a liquid
401 begin
402 // we are in the wall, wtf?!
407 exit;
409 // we are in liquid, trace to liquid end
413 // are we in a liquid?
415 begin
416 // trace out of the liquid
417 //env := TEnvType.ELiquid;
419 //e_LogWritefln('tracing out of a liquid; floorY=%s; y=%s', [floorY, y]);
422 //e_LogWritefln(' traced out of a liquid; floorY=%s; y=%s', [floorY, y]);
423 end
424 else
425 begin
426 // in the air
428 //env := TEnvType.EAir;
429 pan := g_Map_traceToNearest(x, y, x, g_Map_MaxY, (GridTagObstacle or GridTagLiquid), @ex, @floorY);
431 begin
432 // wall or liquid
434 begin
435 // wall
437 end
438 else
439 begin
440 // liquid
444 end
445 else
446 begin
447 // out of the level; assume wall, but it doesn't really matter
456 var
458 begin
461 begin
469 begin
471 begin
472 //writeln('awaking particle at (', x, ',', y, ')');
474 begin
476 end
477 else
478 begin
479 // stuck to a wall, check if wall is still there
481 begin
484 begin
485 // a wall was moved out, start falling
492 end
493 else
494 begin
503 begin
504 // awake sleeping particle, if necessary
506 begin
508 {
509 case state of
510 TPartState.Sleeping, TPartState.Stuck:
511 if awmIsSet(x, y) then awake();
512 else
513 if (env = TEnvType.EWall) and awmIsSet(x, y) then awake();
514 end;
515 }
525 // ////////////////////////////////////////////////////////////////////////// //
528 begin
536 var
538 begin
542 // find next floor transition
544 // find `wallEndY`
545 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
549 begin
556 // `true`: didn't, get outa thinker
558 begin
565 begin
568 // if we're falling from ceiling, switch to normal mode
573 // switch to freefall mode
575 begin
582 begin
585 begin
588 end
589 else
590 begin
596 label
598 var
604 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
606 {$ENDIF}
607 begin
611 begin
612 // still check for air streams when sleeping (no)
613 if (state = TPartState.Sleeping) then begin {checkAirStreams();} goto _done; end; // so blood will dissolve
615 // process stuck particles
617 begin
618 // stuck to a ceiling?
620 begin
621 // yeah, stuck to a ceiling
623 // dropped from a ceiling?
625 begin
626 // yep
630 end
631 else
632 begin
633 // otherwise, try to drip
636 end
637 else
638 begin
639 // stuck to a wall
641 begin
642 // this can happen if mplat was moved out; find new `wallEndY`
645 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
647 _stuckagain:
648 // floor transition?
650 begin
654 begin
655 // check if our ground wasn't moved since the last scan
658 begin
662 // otherwise, do it again
666 begin
667 // rescan, so we'll know when we'll exit the liquid
671 begin
672 // rescan, so we'll know when we'll enter something interesting
678 // wall transition?
680 begin
681 // just unstuck from the wall, switch to freefall mode
684 end
685 else
686 begin
687 // otherwise, try to drip
691 // nope, process as usual
694 // it is important to have it here
700 // gravity, if not stuck
702 begin
705 _gravityagain:
706 // floor transition?
708 begin
711 begin
712 // check if our ground wasn't moved since the last scan
714 begin
719 // otherwise, nothing to do
722 begin
723 // rescan, so we'll know when we'll exit the liquid
728 begin
729 // rescan, so we'll know when we'll enter something interesting
731 if (floorType <> TFloorType.Wall) or (floorY <> y) then applyGravity(floorType = TFloorType.LiquidIn);
734 end
735 else
736 begin
737 // looks like we're in the air
742 // trace movement
744 begin
745 // has some horizontal velocity
751 begin
752 // dunno yet
755 // check environment (air/liquid)
756 if (g_Map_PanelAtPoint(x, y, GridTagLiquid) <> nil) then env := TEnvType.ELiquid else env := TEnvType.EAir;
759 begin
760 // we stuck
761 // the only case when we can have both ceiling and wall is corner; stick to wall in this case
762 // check if we stuck to a wall
765 begin
766 // stuck to a wall
768 end
769 else
770 begin
771 // stuck to a ceiling
775 end
777 begin
778 // has only vertical velocity
780 begin
781 // flying up
785 // environment didn't changed
786 end
787 else
788 begin
790 begin
791 // falling down
796 //e_LogWritefln('floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
798 begin
799 // floor transition
802 //e_LogWritefln(' HIT FLOORY: floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
805 begin
806 // check if our ground wasn't moved since the last scan
808 begin
809 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
811 {$ENDIF}
813 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
815 begin
816 e_LogWritefln('force rescanning vpart at (%s,%s); oldFloorY=%s; floorY=%s', [x, y, oldFloorY, floorY]);
818 {$ENDIF}
822 // environment didn't changed
827 begin
828 // we're entered the liquid
830 // rescan, so we'll know when we'll exit the liquid
834 begin
835 // we're exited the liquid
837 // rescan, so we'll know when we'll enter something interesting
840 begin
846 end
847 else
848 begin
855 else
856 begin
857 // simple blood
865 _done:
866 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
871 // blood will dissolve in other liquids
873 begin
875 begin
878 else
886 end
887 else
888 begin
889 // water will disappear in any liquid
893 else
895 // dry water
905 // ////////////////////////////////////////////////////////////////////////// //
906 procedure g_GFX_SparkVel (fX, fY: Integer; count: Word; vx, vy: Integer; devX, devY: Byte); forward;
912 begin
914 begin
919 end
920 else
921 begin
926 var
932 begin
936 begin
938 exit;
939 end
941 begin
956 begin
958 begin
962 // check for level bounds
965 // in what environment we are starting in?
968 begin
969 // either in a wall, or in a liquid
972 end
973 else
974 begin
982 begin
1010 procedure g_GFX_Water (fX, fY: Integer; count: Word; fVelX, fVelY: Single; devX, devY, color: Byte;
1012 var
1017 begin
1034 begin
1036 begin
1038 begin
1047 end
1048 else
1049 begin
1059 // check for level bounds
1062 // this hack will allow water spawned in water to fly out
1063 // it can happen when player fell from a huge height (see "DOOM2D.WAD:\MAP03", for example)
1065 begin
1066 // in what environment we are starting in?
1068 end
1069 else
1070 begin
1076 // color
1079 begin
1085 begin
1091 begin
1097 begin
1106 begin
1115 begin
1137 procedure g_GFX_SimpleWater (fX, fY: Integer; count: Word; fVelX, fVelY: Single; defColor, cr, cg, cb: Byte);
1138 begin
1143 // ////////////////////////////////////////////////////////////////////////// //
1145 var
1147 begin
1151 begin
1154 begin
1156 end
1157 else
1158 begin
1168 else
1173 {.$DEFINE D2F_DEBUG_BUBBLES}
1175 var
1179 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1182 {$ENDIF}
1183 begin
1196 begin
1198 begin
1202 // check for level bounds
1205 (*
1206 // don't spawn bubbles outside of the liquid
1207 if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
1208 Continue;
1209 *)
1211 // trace liquid, so we'll know where it ends; do it in 8px steps for speed
1212 // tracer will return `false` if we started outside of the liquid
1214 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1216 ptr := mapGrid.traceOrthoRayWhileIn(liquidx, liquidTopY, x, y, x, 0, GridTagWater or GridTagAcid1 or GridTagAcid2);
1218 e_LogWritefln('traceOrthoRayWhileIn: time=%s (%s); liquidTopY=%s', [Integer(stt), ptr, liquidTopY]);
1219 //
1223 e_LogWritefln('g_Map_TraceLiquidNonPrecise: time=%s (%s); liquidTopY=%s', [Integer(stt), nptr, liquidTopY]);
1225 {$ELSE}
1228 {$ENDIF}
1252 // ////////////////////////////////////////////////////////////////////////// //
1254 label
1255 _done;
1256 var
1260 begin
1266 //writeln('spark0: pos=(', x, ',', y, '); delta=(', dx, ',', dy, '); state=', state, '; ceilingY=', ceilingY, '; floorY=', floorY);
1268 // apply gravity
1270 begin
1275 // flying
1277 begin
1278 // has some horizontal velocity
1284 begin
1286 // hit the wall; falling down vertically
1290 end
1292 begin
1293 // has some vertical velocity
1295 begin
1296 // flying up
1300 begin
1301 // oops, hit a ceiling
1306 // environment didn't changed
1307 end
1308 else
1309 begin
1310 // falling down
1314 begin
1315 // hit something except a floor?
1317 // otherwise, go to sleep
1320 // environment didn't changed
1325 _done:
1326 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
1331 begin
1336 //writeln('spark1: pos=(', x, ',', y, '); delta=(', velX:6:3, ',', velY:6:3, '); state=', state, '; ceilingY=', ceilingY, '; floorY=', floorY);
1340 else
1345 // ////////////////////////////////////////////////////////////////////////// //
1347 var
1352 begin
1365 begin
1367 begin
1371 // check for level bounds
1374 // in what environment we are starting in?
1377 begin
1378 // either in a wall, or in a liquid
1379 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1380 //env := TEnvType.ELiquid;
1381 continue;
1382 end
1383 else
1384 begin
1392 begin
1419 var
1426 begin
1447 begin
1449 begin
1453 // check for level bounds
1456 // in what environment we are starting in?
1459 begin
1460 // either in a wall, or in a liquid
1461 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1462 //env := TEnvType.ELiquid;
1463 continue;
1464 end
1465 else
1466 begin
1494 // ////////////////////////////////////////////////////////////////////////// //
1496 var
1498 begin
1509 begin
1515 var
1517 begin
1521 begin
1523 Exit;
1527 begin
1530 end
1531 else
1532 begin
1540 var
1542 begin
1558 // ////////////////////////////////////////////////////////////////////////// //
1560 begin
1561 //g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
1562 //SetLength(gCollideMap, gMapInfo.Height+1);
1563 //for a := 0 to High(gCollideMap) do SetLength(gCollideMap[a], gMapInfo.Width+1);
1565 {$IFDEF HEADLESS}
1567 {$ENDIF}
1572 var
1574 begin
1581 begin
1587 // why not?
1593 // ////////////////////////////////////////////////////////////////////////// //
1595 var
1599 begin
1603 begin
1610 begin
1612 begin
1614 begin
1623 // clear awake map
1627 begin
1630 begin
1632 ONCEANIM_SMOKE:
1633 begin
1642 begin
1645 end
1646 else
1654 var
1656 {$IFDEF USE_NANOGL}
1657 type
1662 var
1665 {$ENDIF}
1666 begin
1670 begin
1680 {$IFDEF USE_NANOGL}
1684 begin
1686 begin
1688 begin
1707 {$ELSE}
1712 begin
1714 begin
1717 begin
1725 {$ENDIF}
1731 begin
1734 begin
1736 begin