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
53 procedure g_GFX_Water (fX, fY: Integer; count: Word; fVelX, fVelY: Single; devX, devY, color: Byte;
55 procedure g_GFX_SimpleWater (fX, fY: Integer; count: Word; fVelX, fVelY: Single; defColor, cr, cg, cb: Byte);
69 var
74 //WARNING: only for Holmes!
78 implementation
80 uses
81 {$INCLUDE ../nogl/noGLuses.inc}
87 const
91 type
95 // Wall: floorY is just before floor
96 // LiquidIn: floorY is liquid *start* (i.e. just in a liquid)
97 // LiquidOut: floorY is liquid *end* (i.e. just out of a liquid)
100 // note: this MUST be record, so we can keep it in
101 // dynamic array and has sequential memory access pattern
120 //k8: sorry, i have to emulate virtual methods this way, 'cause i haet `Object`
145 var
150 // awakeMap has one bit for each map grid cell; on g_Mark,
151 // corresponding bits will be set, and in `think()` all particles
152 // in marked cells will be awaken
158 {$IF DEFINED(D2F_DEBUG_PART_AWAKE)}
160 {$ENDIF}
163 // ////////////////////////////////////////////////////////////////////////// //
165 begin
166 {$IF DEFINED(D2F_DEBUG_PART_AWAKE)}
171 begin
173 begin
175 end
176 else
177 begin
180 end
181 else
182 begin
185 {$ELSE}
187 {$ENDIF}
191 // ////////////////////////////////////////////////////////////////////////// //
192 // HACK! using mapgrid
194 begin
195 {$IF DEFINED(D2F_DEBUG_PART_AWAKE)}
197 begin
201 {$ENDIF}
203 begin
211 begin
219 {$IF DEFINED(D2F_DEBUG_PART_AWAKE)}
222 {$ENDIF}
223 //{$IF DEFINED(D2F_DEBUG)}
224 e_LogWritefln('particle awake map: %sx%s (for grid of size %sx%s)', [awakeMapW, awakeMapH, mapGrid.gridWidth, mapGrid.gridHeight]);
225 //{$ENDIF}
232 begin
236 begin
237 {$IF DEFINED(D2F_DEBUG)}
239 {$ENDIF}
241 end
242 else
243 begin
250 var
252 begin
256 begin
257 {$IF DEFINED(D2F_DEBUG)}
259 {$ENDIF}
267 // ////////////////////////////////////////////////////////////////////////// //
268 // st: set mark
269 // t: mark type
270 // currently unused
273 var
276 begin
282 // make some border, so we'll hit particles around the panel
293 // has something to do?
302 begin
304 begin
305 {$IF DEFINED(D2F_DEBUG)}
308 {$ENDIF}
316 // ////////////////////////////////////////////////////////////////////////// //
320 // remove velocities and acceleration
322 begin
323 // stop right there, you criminal scum!
331 // `true`: affected by air stream
333 var
335 begin
339 begin
341 begin
346 end
348 begin
351 end
353 begin
356 end
357 else
358 begin
361 // awake
367 // switch to sleep mode
369 begin
371 begin
379 var
382 begin
384 // stuck in the wall? rescan, 'cause it can be mplat
386 begin
389 begin
390 // either in a wall, or in a liquid
392 begin
393 // we are in the wall, wtf?!
398 exit;
400 // we are in liquid, trace to liquid end
404 // are we in a liquid?
406 begin
407 // trace out of the liquid
408 //env := TEnvType.ELiquid;
410 //e_LogWritefln('tracing out of a liquid; floorY=%s; y=%s', [floorY, y]);
413 //e_LogWritefln(' traced out of a liquid; floorY=%s; y=%s', [floorY, y]);
414 end
415 else
416 begin
417 // in the air
419 //env := TEnvType.EAir;
420 pan := g_Map_traceToNearest(x, y, x, g_Map_MaxY, (GridTagObstacle or GridTagLiquid), @ex, @floorY);
422 begin
423 // wall or liquid
425 begin
426 // wall
428 end
429 else
430 begin
431 // liquid
435 end
436 else
437 begin
438 // out of the level; assume wall, but it doesn't really matter
447 var
449 begin
452 begin
460 begin
462 begin
463 //writeln('awaking particle at (', x, ',', y, ')');
465 begin
467 end
468 else
469 begin
470 // stuck to a wall, check if wall is still there
472 begin
475 begin
476 // a wall was moved out, start falling
483 end
484 else
485 begin
494 begin
495 // awake sleeping particle, if necessary
497 begin
499 {
500 case state of
501 TPartState.Sleeping, TPartState.Stuck:
502 if awmIsSet(x, y) then awake();
503 else
504 if (env = TEnvType.EWall) and awmIsSet(x, y) then awake();
505 end;
506 }
516 // ////////////////////////////////////////////////////////////////////////// //
519 begin
527 var
529 begin
533 // find next floor transition
535 // find `wallEndY`
536 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
540 begin
547 // `true`: didn't, get outa thinker
549 begin
556 begin
559 // if we're falling from ceiling, switch to normal mode
564 // switch to freefall mode
566 begin
573 begin
576 begin
579 end
580 else
581 begin
587 label
589 var
595 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
597 {$ENDIF}
598 begin
602 begin
603 // still check for air streams when sleeping (no)
604 if (state = TPartState.Sleeping) then begin {checkAirStreams();} goto _done; end; // so blood will dissolve
606 // process stuck particles
608 begin
609 // stuck to a ceiling?
611 begin
612 // yeah, stuck to a ceiling
614 // dropped from a ceiling?
616 begin
617 // yep
621 end
622 else
623 begin
624 // otherwise, try to drip
627 end
628 else
629 begin
630 // stuck to a wall
632 begin
633 // this can happen if mplat was moved out; find new `wallEndY`
636 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
638 _stuckagain:
639 // floor transition?
641 begin
645 begin
646 // check if our ground wasn't moved since the last scan
649 begin
653 // otherwise, do it again
657 begin
658 // rescan, so we'll know when we'll exit the liquid
662 begin
663 // rescan, so we'll know when we'll enter something interesting
669 // wall transition?
671 begin
672 // just unstuck from the wall, switch to freefall mode
675 end
676 else
677 begin
678 // otherwise, try to drip
682 // nope, process as usual
685 // it is important to have it here
691 // gravity, if not stuck
693 begin
696 _gravityagain:
697 // floor transition?
699 begin
702 begin
703 // check if our ground wasn't moved since the last scan
705 begin
710 // otherwise, nothing to do
713 begin
714 // rescan, so we'll know when we'll exit the liquid
719 begin
720 // rescan, so we'll know when we'll enter something interesting
722 if (floorType <> TFloorType.Wall) or (floorY <> y) then applyGravity(floorType = TFloorType.LiquidIn);
725 end
726 else
727 begin
728 // looks like we're in the air
733 // trace movement
735 begin
736 // has some horizontal velocity
742 begin
743 // dunno yet
746 // check environment (air/liquid)
747 if (g_Map_PanelAtPoint(x, y, GridTagLiquid) <> nil) then env := TEnvType.ELiquid else env := TEnvType.EAir;
750 begin
751 // we stuck
752 // the only case when we can have both ceiling and wall is corner; stick to wall in this case
753 // check if we stuck to a wall
756 begin
757 // stuck to a wall
759 end
760 else
761 begin
762 // stuck to a ceiling
766 end
768 begin
769 // has only vertical velocity
771 begin
772 // flying up
776 // environment didn't changed
777 end
778 else
779 begin
781 begin
782 // falling down
787 //e_LogWritefln('floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
789 begin
790 // floor transition
793 //e_LogWritefln(' HIT FLOORY: floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
796 begin
797 // check if our ground wasn't moved since the last scan
799 begin
800 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
802 {$ENDIF}
804 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
806 begin
807 e_LogWritefln('force rescanning vpart at (%s,%s); oldFloorY=%s; floorY=%s', [x, y, oldFloorY, floorY]);
809 {$ENDIF}
813 // environment didn't changed
818 begin
819 // we're entered the liquid
821 // rescan, so we'll know when we'll exit the liquid
825 begin
826 // we're exited the liquid
828 // rescan, so we'll know when we'll enter something interesting
831 begin
837 end
838 else
839 begin
846 else
847 begin
848 // simple blood
856 _done:
857 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
862 // blood will dissolve in other liquids
864 begin
866 begin
874 end
875 else
876 begin
877 // water will disappear in any liquid
880 // dry water
890 // ////////////////////////////////////////////////////////////////////////// //
891 procedure g_GFX_SparkVel (fX, fY: Integer; count: Word; vx, vy: Integer; devX, devY: Byte); forward;
897 begin
899 begin
904 end
905 else
906 begin
911 var
917 begin
921 begin
923 exit;
936 begin
938 begin
942 // check for level bounds
945 // in what environment we are starting in?
948 begin
949 // either in a wall, or in a liquid
952 end
953 else
954 begin
962 begin
989 procedure g_GFX_Water (fX, fY: Integer; count: Word; fVelX, fVelY: Single; devX, devY, color: Byte;
991 var
996 begin
1013 begin
1015 begin
1017 begin
1026 end
1027 else
1028 begin
1038 // check for level bounds
1041 // this hack will allow water spawned in water to fly out
1042 // it can happen when player fell from a huge height (see "DOOM2D.WAD:\MAP03", for example)
1044 begin
1045 // in what environment we are starting in?
1047 end
1048 else
1049 begin
1055 // color
1058 begin
1064 begin
1070 begin
1076 begin
1085 begin
1094 begin
1115 procedure g_GFX_SimpleWater (fX, fY: Integer; count: Word; fVelX, fVelY: Single; defColor, cr, cg, cb: Byte);
1116 begin
1121 // ////////////////////////////////////////////////////////////////////////// //
1123 var
1125 begin
1129 begin
1132 begin
1134 end
1135 else
1136 begin
1148 {.$DEFINE D2F_DEBUG_BUBBLES}
1150 var
1154 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1157 {$ENDIF}
1158 begin
1171 begin
1173 begin
1177 // check for level bounds
1180 (*
1181 // don't spawn bubbles outside of the liquid
1182 if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
1183 Continue;
1184 *)
1186 // trace liquid, so we'll know where it ends; do it in 8px steps for speed
1187 // tracer will return `false` if we started outside of the liquid
1189 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1191 ptr := mapGrid.traceOrthoRayWhileIn(liquidx, liquidTopY, x, y, x, 0, GridTagWater or GridTagAcid1 or GridTagAcid2);
1193 e_LogWritefln('traceOrthoRayWhileIn: time=%s (%s); liquidTopY=%s', [Integer(stt), ptr, liquidTopY]);
1194 //
1198 e_LogWritefln('g_Map_TraceLiquidNonPrecise: time=%s (%s); liquidTopY=%s', [Integer(stt), nptr, liquidTopY]);
1200 {$ELSE}
1203 {$ENDIF}
1226 // ////////////////////////////////////////////////////////////////////////// //
1228 label
1229 _done;
1230 var
1234 begin
1240 //writeln('spark0: pos=(', x, ',', y, '); delta=(', dx, ',', dy, '); state=', state, '; ceilingY=', ceilingY, '; floorY=', floorY);
1242 // apply gravity
1244 begin
1249 // flying
1251 begin
1252 // has some horizontal velocity
1258 begin
1260 // hit the wall; falling down vertically
1264 end
1266 begin
1267 // has some vertical velocity
1269 begin
1270 // flying up
1274 begin
1275 // oops, hit a ceiling
1280 // environment didn't changed
1281 end
1282 else
1283 begin
1284 // falling down
1288 begin
1289 // hit something except a floor?
1291 // otherwise, go to sleep
1294 // environment didn't changed
1299 _done:
1300 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
1305 begin
1310 //writeln('spark1: pos=(', x, ',', y, '); delta=(', velX:6:3, ',', velY:6:3, '); state=', state, '; ceilingY=', ceilingY, '; floorY=', floorY);
1316 // ////////////////////////////////////////////////////////////////////////// //
1318 var
1323 begin
1336 begin
1338 begin
1342 // check for level bounds
1345 // in what environment we are starting in?
1348 begin
1349 // either in a wall, or in a liquid
1350 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1351 //env := TEnvType.ELiquid;
1352 continue;
1353 end
1354 else
1355 begin
1363 begin
1389 var
1396 begin
1417 begin
1419 begin
1423 // check for level bounds
1426 // in what environment we are starting in?
1429 begin
1430 // either in a wall, or in a liquid
1431 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1432 //env := TEnvType.ELiquid;
1433 continue;
1434 end
1435 else
1436 begin
1463 // ////////////////////////////////////////////////////////////////////////// //
1465 var
1467 begin
1478 begin
1484 var
1486 begin
1490 begin
1492 Exit;
1496 begin
1499 end
1500 else
1501 begin
1509 var
1511 begin
1527 // ////////////////////////////////////////////////////////////////////////// //
1529 begin
1530 //g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
1531 //SetLength(gCollideMap, gMapInfo.Height+1);
1532 //for a := 0 to High(gCollideMap) do SetLength(gCollideMap[a], gMapInfo.Width+1);
1534 {$IFDEF HEADLESS}
1536 {$ENDIF}
1541 var
1543 begin
1550 begin
1556 // why not?
1562 // ////////////////////////////////////////////////////////////////////////// //
1564 var
1568 begin
1572 begin
1579 begin
1581 begin
1583 begin
1592 // clear awake map
1596 begin
1599 begin
1601 ONCEANIM_SMOKE:
1602 begin
1611 begin
1614 end
1615 else
1623 var
1625 {$IFDEF USE_NANOGL}
1626 type
1631 var
1634 {$ENDIF}
1635 begin
1639 begin
1649 {$IFDEF USE_NANOGL}
1653 begin
1655 begin
1657 begin
1676 {$ELSE}
1681 begin
1683 begin
1686 begin
1694 {$ENDIF}
1700 begin
1703 begin
1705 begin