0f26212b29ce8f21c066bb80299f4c395011bfbe
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 {$IFDEF USE_NANOGL}
82 nanoGL,
83 {$ELSE}
85 {$ENDIF}
91 const
95 type
99 // Wall: floorY is just before floor
100 // LiquidIn: floorY is liquid *start* (i.e. just in a liquid)
101 // LiquidOut: floorY is liquid *end* (i.e. just out of a liquid)
104 // note: this MUST be record, so we can keep it in
105 // dynamic array and has sequential memory access pattern
124 //k8: sorry, i have to emulate virtual methods this way, 'cause i haet `Object`
149 var
154 // awakeMap has one bit for each map grid cell; on g_Mark,
155 // corresponding bits will be set, and in `think()` all particles
156 // in marked cells will be awaken
162 {$IF DEFINED(D2F_DEBUG_PART_AWAKE)}
164 {$ENDIF}
167 // ////////////////////////////////////////////////////////////////////////// //
169 begin
170 {$IF DEFINED(D2F_DEBUG_PART_AWAKE)}
175 begin
177 begin
179 end
180 else
181 begin
184 end
185 else
186 begin
189 {$ELSE}
191 {$ENDIF}
195 // ////////////////////////////////////////////////////////////////////////// //
196 // HACK! using mapgrid
198 begin
199 {$IF DEFINED(D2F_DEBUG_PART_AWAKE)}
201 begin
205 {$ENDIF}
207 begin
215 begin
223 {$IF DEFINED(D2F_DEBUG_PART_AWAKE)}
226 {$ENDIF}
227 //{$IF DEFINED(D2F_DEBUG)}
228 e_LogWritefln('particle awake map: %sx%s (for grid of size %sx%s)', [awakeMapW, awakeMapH, mapGrid.gridWidth, mapGrid.gridHeight]);
229 //{$ENDIF}
236 begin
240 begin
241 {$IF DEFINED(D2F_DEBUG)}
243 {$ENDIF}
245 end
246 else
247 begin
254 var
256 begin
260 begin
261 {$IF DEFINED(D2F_DEBUG)}
263 {$ENDIF}
271 // ////////////////////////////////////////////////////////////////////////// //
272 // st: set mark
273 // t: mark type
274 // currently unused
277 var
280 begin
286 // make some border, so we'll hit particles around the panel
297 // has something to do?
306 begin
308 begin
309 {$IF DEFINED(D2F_DEBUG)}
312 {$ENDIF}
320 // ////////////////////////////////////////////////////////////////////////// //
324 // remove velocities and acceleration
326 begin
327 // stop right there, you criminal scum!
335 // `true`: affected by air stream
337 var
339 begin
343 begin
345 begin
350 end
352 begin
355 end
357 begin
360 end
361 else
362 begin
365 // awake
371 // switch to sleep mode
373 begin
375 begin
383 var
386 begin
388 // stuck in the wall? rescan, 'cause it can be mplat
390 begin
393 begin
394 // either in a wall, or in a liquid
396 begin
397 // we are in the wall, wtf?!
402 exit;
404 // we are in liquid, trace to liquid end
408 // are we in a liquid?
410 begin
411 // trace out of the liquid
412 //env := TEnvType.ELiquid;
414 //e_LogWritefln('tracing out of a liquid; floorY=%s; y=%s', [floorY, y]);
417 //e_LogWritefln(' traced out of a liquid; floorY=%s; y=%s', [floorY, y]);
418 end
419 else
420 begin
421 // in the air
423 //env := TEnvType.EAir;
424 pan := g_Map_traceToNearest(x, y, x, g_Map_MaxY, (GridTagObstacle or GridTagLiquid), @ex, @floorY);
426 begin
427 // wall or liquid
429 begin
430 // wall
432 end
433 else
434 begin
435 // liquid
439 end
440 else
441 begin
442 // out of the level; assume wall, but it doesn't really matter
451 var
453 begin
456 begin
464 begin
466 begin
467 //writeln('awaking particle at (', x, ',', y, ')');
469 begin
471 end
472 else
473 begin
474 // stuck to a wall, check if wall is still there
476 begin
479 begin
480 // a wall was moved out, start falling
487 end
488 else
489 begin
498 begin
499 // awake sleeping particle, if necessary
501 begin
503 {
504 case state of
505 TPartState.Sleeping, TPartState.Stuck:
506 if awmIsSet(x, y) then awake();
507 else
508 if (env = TEnvType.EWall) and awmIsSet(x, y) then awake();
509 end;
510 }
520 // ////////////////////////////////////////////////////////////////////////// //
523 begin
531 var
533 begin
537 // find next floor transition
539 // find `wallEndY`
540 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
544 begin
551 // `true`: didn't, get outa thinker
553 begin
560 begin
563 // if we're falling from ceiling, switch to normal mode
568 // switch to freefall mode
570 begin
577 begin
580 begin
583 end
584 else
585 begin
591 label
593 var
599 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
601 {$ENDIF}
602 begin
606 begin
607 // still check for air streams when sleeping (no)
608 if (state = TPartState.Sleeping) then begin {checkAirStreams();} goto _done; end; // so blood will dissolve
610 // process stuck particles
612 begin
613 // stuck to a ceiling?
615 begin
616 // yeah, stuck to a ceiling
618 // dropped from a ceiling?
620 begin
621 // yep
625 end
626 else
627 begin
628 // otherwise, try to drip
631 end
632 else
633 begin
634 // stuck to a wall
636 begin
637 // this can happen if mplat was moved out; find new `wallEndY`
640 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
642 _stuckagain:
643 // floor transition?
645 begin
649 begin
650 // check if our ground wasn't moved since the last scan
653 begin
657 // otherwise, do it again
661 begin
662 // rescan, so we'll know when we'll exit the liquid
666 begin
667 // rescan, so we'll know when we'll enter something interesting
673 // wall transition?
675 begin
676 // just unstuck from the wall, switch to freefall mode
679 end
680 else
681 begin
682 // otherwise, try to drip
686 // nope, process as usual
689 // it is important to have it here
695 // gravity, if not stuck
697 begin
700 _gravityagain:
701 // floor transition?
703 begin
706 begin
707 // check if our ground wasn't moved since the last scan
709 begin
714 // otherwise, nothing to do
717 begin
718 // rescan, so we'll know when we'll exit the liquid
723 begin
724 // rescan, so we'll know when we'll enter something interesting
726 if (floorType <> TFloorType.Wall) or (floorY <> y) then applyGravity(floorType = TFloorType.LiquidIn);
729 end
730 else
731 begin
732 // looks like we're in the air
737 // trace movement
739 begin
740 // has some horizontal velocity
746 begin
747 // dunno yet
750 // check environment (air/liquid)
751 if (g_Map_PanelAtPoint(x, y, GridTagLiquid) <> nil) then env := TEnvType.ELiquid else env := TEnvType.EAir;
754 begin
755 // we stuck
756 // the only case when we can have both ceiling and wall is corner; stick to wall in this case
757 // check if we stuck to a wall
760 begin
761 // stuck to a wall
763 end
764 else
765 begin
766 // stuck to a ceiling
770 end
772 begin
773 // has only vertical velocity
775 begin
776 // flying up
780 // environment didn't changed
781 end
782 else
783 begin
785 begin
786 // falling down
791 //e_LogWritefln('floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
793 begin
794 // floor transition
797 //e_LogWritefln(' HIT FLOORY: floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
800 begin
801 // check if our ground wasn't moved since the last scan
803 begin
804 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
806 {$ENDIF}
808 {$IF DEFINED(D2F_DEBUG_FALL_MPLAT)}
810 begin
811 e_LogWritefln('force rescanning vpart at (%s,%s); oldFloorY=%s; floorY=%s', [x, y, oldFloorY, floorY]);
813 {$ENDIF}
817 // environment didn't changed
822 begin
823 // we're entered the liquid
825 // rescan, so we'll know when we'll exit the liquid
829 begin
830 // we're exited the liquid
832 // rescan, so we'll know when we'll enter something interesting
835 begin
841 end
842 else
843 begin
850 else
851 begin
852 // simple blood
860 _done:
861 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
866 // blood will dissolve in other liquids
868 begin
870 begin
878 end
879 else
880 begin
881 // water will disappear in any liquid
884 // dry water
894 // ////////////////////////////////////////////////////////////////////////// //
895 procedure g_GFX_SparkVel (fX, fY: Integer; count: Word; vx, vy: Integer; devX, devY: Byte); forward;
901 begin
903 begin
908 end
909 else
910 begin
915 var
921 begin
925 begin
927 exit;
940 begin
942 begin
946 // check for level bounds
949 // in what environment we are starting in?
952 begin
953 // either in a wall, or in a liquid
956 end
957 else
958 begin
966 begin
993 procedure g_GFX_Water (fX, fY: Integer; count: Word; fVelX, fVelY: Single; devX, devY, color: Byte;
995 var
1000 begin
1017 begin
1019 begin
1021 begin
1030 end
1031 else
1032 begin
1042 // check for level bounds
1045 // this hack will allow water spawned in water to fly out
1046 // it can happen when player fell from a huge height (see "DOOM2D.WAD:\MAP03", for example)
1048 begin
1049 // in what environment we are starting in?
1051 end
1052 else
1053 begin
1059 // color
1062 begin
1068 begin
1074 begin
1080 begin
1089 begin
1098 begin
1119 procedure g_GFX_SimpleWater (fX, fY: Integer; count: Word; fVelX, fVelY: Single; defColor, cr, cg, cb: Byte);
1120 begin
1125 // ////////////////////////////////////////////////////////////////////////// //
1127 var
1129 begin
1133 begin
1136 begin
1138 end
1139 else
1140 begin
1152 {.$DEFINE D2F_DEBUG_BUBBLES}
1154 var
1158 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1161 {$ENDIF}
1162 begin
1175 begin
1177 begin
1181 // check for level bounds
1184 (*
1185 // don't spawn bubbles outside of the liquid
1186 if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
1187 Continue;
1188 *)
1190 // trace liquid, so we'll know where it ends; do it in 8px steps for speed
1191 // tracer will return `false` if we started outside of the liquid
1193 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1195 ptr := mapGrid.traceOrthoRayWhileIn(liquidx, liquidTopY, x, y, x, 0, GridTagWater or GridTagAcid1 or GridTagAcid2);
1197 e_LogWritefln('traceOrthoRayWhileIn: time=%s (%s); liquidTopY=%s', [Integer(stt), ptr, liquidTopY]);
1198 //
1202 e_LogWritefln('g_Map_TraceLiquidNonPrecise: time=%s (%s); liquidTopY=%s', [Integer(stt), nptr, liquidTopY]);
1204 {$ELSE}
1207 {$ENDIF}
1230 // ////////////////////////////////////////////////////////////////////////// //
1232 label
1233 _done;
1234 var
1238 begin
1244 //writeln('spark0: pos=(', x, ',', y, '); delta=(', dx, ',', dy, '); state=', state, '; ceilingY=', ceilingY, '; floorY=', floorY);
1246 // apply gravity
1248 begin
1253 // flying
1255 begin
1256 // has some horizontal velocity
1262 begin
1264 // hit the wall; falling down vertically
1268 end
1270 begin
1271 // has some vertical velocity
1273 begin
1274 // flying up
1278 begin
1279 // oops, hit a ceiling
1284 // environment didn't changed
1285 end
1286 else
1287 begin
1288 // falling down
1292 begin
1293 // hit something except a floor?
1295 // otherwise, go to sleep
1298 // environment didn't changed
1303 _done:
1304 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
1309 begin
1314 //writeln('spark1: pos=(', x, ',', y, '); delta=(', velX:6:3, ',', velY:6:3, '); state=', state, '; ceilingY=', ceilingY, '; floorY=', floorY);
1320 // ////////////////////////////////////////////////////////////////////////// //
1322 var
1327 begin
1340 begin
1342 begin
1346 // check for level bounds
1349 // in what environment we are starting in?
1352 begin
1353 // either in a wall, or in a liquid
1354 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1355 //env := TEnvType.ELiquid;
1356 continue;
1357 end
1358 else
1359 begin
1367 begin
1393 var
1400 begin
1421 begin
1423 begin
1427 // check for level bounds
1430 // in what environment we are starting in?
1433 begin
1434 // either in a wall, or in a liquid
1435 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1436 //env := TEnvType.ELiquid;
1437 continue;
1438 end
1439 else
1440 begin
1467 // ////////////////////////////////////////////////////////////////////////// //
1469 var
1471 begin
1474 {$ENDIF}
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 begin
1636 begin
1650 begin
1652 begin
1655 begin
1668 begin
1671 begin
1673 begin