0ec78f65b68a6a44be558efeda92d61685a565d3
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}
19 interface
21 uses
24 const
51 procedure g_GFX_Water (fX, fY: Integer; count: Word; fVelX, fVelY: Single; devX, devY, color: Byte;
53 procedure g_GFX_SimpleWater (fX, fY: Integer; count: Word; fVelX, fVelY: Single; defColor, cr, cg, cb: Byte);
67 var
72 implementation
74 uses
80 const
84 type
88 // Wall: floorY is just before floor
89 // LiquidIn: floorY is liquid *start* (i.e. just in a liquid)
90 // LiquidOut: floorY is liquid *end* (i.e. just out of a liquid)
93 // note: this MUST be record, so we can keep it in
94 // dynamic array and has sequential memory access pattern
113 //k8: sorry, i have to emulate virtual methods this way, 'cause i haet `Object`
136 var
141 // awakeMap has one bit for each map grid cell; on g_Mark,
142 // corresponding bits will be set, and in `think()` all particles
143 // in marked cells will be awaken
151 // ////////////////////////////////////////////////////////////////////////// //
152 // HACK! using mapgrid
154 begin
156 begin
164 begin
172 {$IF DEFINED(D2F_DEBUG)}
173 e_LogWritefln('particle awake map: %sx%s (for grid of size %sx%s)', [awakeMapW, awakeMapH, mapGrid.gridWidth, mapGrid.gridHeight]);
174 {$ENDIF}
181 begin
185 begin
186 {$IF DEFINED(D2F_DEBUG)}
188 {$ENDIF}
190 end
191 else
192 begin
199 var
201 begin
205 begin
206 {$IF DEFINED(D2F_DEBUG)}
208 {$ENDIF}
216 // ////////////////////////////////////////////////////////////////////////// //
220 // remove velocities and acceleration
222 begin
223 // stop right there, you criminal scum!
231 // switch to sleep mode
233 begin
240 var
243 begin
245 // stuck in the wall? rescan, 'cause it can be mplat
247 begin
250 begin
251 // either in a wall, or in a liquid
253 begin
254 // we are in the wall, wtf?!
259 exit;
261 // we are in liquid, trace to liquid end
265 // are we in a liquid?
267 begin
268 // trace out of the liquid
269 //env := TEnvType.ELiquid;
271 //e_LogWritefln('tracing out of a liquid; floorY=%s; y=%s', [floorY, y]);
274 //e_LogWritefln(' traced out of a liquid; floorY=%s; y=%s', [floorY, y]);
275 end
276 else
277 begin
278 // in the air
280 //env := TEnvType.EAir;
281 pan := g_Map_traceToNearest(x, y, x, g_Map_MaxY, (GridTagObstacle or GridTagLiquid), @ex, @floorY);
283 begin
284 // wall or liquid
286 begin
287 // wall
289 end
290 else
291 begin
292 // liquid
296 end
297 else
298 begin
299 // out of the level; assume wall, but it doesn't really matter
308 var
310 begin
313 begin
320 begin
321 // awake sleeping particle, if necessary
323 begin
327 begin
344 // ////////////////////////////////////////////////////////////////////////// //
347 begin
355 var
357 begin
361 // find next floor transition
363 // find `wallEndY`
364 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
368 begin
375 // `true`: didn't, get outa thinker
377 begin
386 // `true`: affected by air stream
388 var
390 begin
394 begin
396 begin
401 end
403 begin
406 end
408 begin
411 end
412 else
413 begin
416 // awake
421 // switch to freefall mode
423 begin
430 begin
433 begin
436 end
437 else
438 begin
444 label
445 _done;
446 var
451 begin
455 begin
456 // still check for air streams when sleeping
457 if (state = TPartState.Sleeping) then begin checkAirStreams(); goto _done; end; // so blood will dissolve
459 // process stuck particles
461 begin
462 // stuck to a ceiling?
464 begin
465 // yeah, stuck to a ceiling
467 // dropped from a ceiling?
469 begin
470 // yep
474 end
475 else
476 begin
477 // otherwise, try to drip
480 end
481 else
482 begin
483 // stuck to a wall
485 // floor transition?
487 begin
491 begin
496 begin
497 // rescan, so we'll know when we'll exit the liquid
501 begin
502 // rescan, so we'll know when we'll enter something interesting
508 // wall transition?
510 begin
511 // just unstuck from the wall, switch to freefall mode
514 end
515 else
516 begin
517 // otherwise, try to drip
521 // nope, process as usual
524 // it is important to have it here
528 // gravity, if not stuck
530 begin
532 // floor transition?
534 begin
537 begin
538 // nothing to do
541 begin
542 // rescan, so we'll know when we'll exit the liquid
547 begin
548 // rescan, so we'll know when we'll enter something interesting
550 if (floorType <> TFloorType.Wall) or (floorY <> y) then applyGravity(floorType = TFloorType.LiquidIn);
553 end
554 else
555 begin
556 // looks like we're in the air
561 // trace movement
563 begin
564 // has some horizontal velocity
570 begin
571 // dunno yet
574 // check environment (air/liquid)
575 if (g_Map_PanelAtPoint(x, y, GridTagLiquid) <> nil) then env := TEnvType.ELiquid else env := TEnvType.EAir;
578 begin
579 // we stuck
580 // the only case when we can have both ceiling and wall is corner; stick to wall in this case
581 // check if we stuck to a wall
584 begin
585 // stuck to a wall
587 end
588 else
589 begin
590 // stuck to a ceiling
594 end
596 begin
597 // has only vertical velocity
599 begin
600 // flying up
604 // environment didn't changed
605 end
606 else
607 begin
609 begin
610 // falling down
614 //e_LogWritefln('floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
616 begin
617 // floor transition
620 //e_LogWritefln(' HIT FLOORY: floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
623 begin
624 // environment didn't changed
629 begin
630 // we're entered the liquid
632 // rescan, so we'll know when we'll exit the liquid
636 begin
637 // we're exited the liquid
639 // rescan, so we'll know when we'll enter something interesting
642 begin
648 end
649 else
650 begin
657 else
658 begin
659 // simple blood
667 _done:
668 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
673 // blood will dissolve in other liquids
675 begin
677 begin
685 end
686 else
687 begin
688 // water will disappear in any liquid
691 // dry water
701 // ////////////////////////////////////////////////////////////////////////// //
702 procedure g_GFX_SparkVel (fX, fY: Integer; count: Word; vx, vy: Integer; devX, devY: Byte); forward;
708 begin
710 begin
715 end
716 else
717 begin
722 var
728 begin
732 begin
734 exit;
747 begin
749 begin
753 // check for level bounds
756 // in what environment we are starting in?
759 begin
760 // either in a wall, or in a liquid
763 end
764 else
765 begin
773 begin
800 procedure g_GFX_Water (fX, fY: Integer; count: Word; fVelX, fVelY: Single; devX, devY, color: Byte;
802 var
807 begin
824 begin
826 begin
828 begin
837 end
838 else
839 begin
849 // check for level bounds
852 // in what environment we are starting in?
855 begin
856 // either in a wall, or in a liquid
857 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
858 //env := TEnvType.ELiquid;
859 continue;
860 end
861 else
862 begin
866 // color
869 begin
875 begin
881 begin
887 begin
896 begin
905 begin
926 procedure g_GFX_SimpleWater (fX, fY: Integer; count: Word; fVelX, fVelY: Single; defColor, cr, cg, cb: Byte);
927 begin
932 // ////////////////////////////////////////////////////////////////////////// //
934 var
936 begin
940 begin
943 begin
945 end
946 else
947 begin
959 {.$DEFINE D2F_DEBUG_BUBBLES}
961 var
965 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
968 {$ENDIF}
969 begin
982 begin
984 begin
988 // check for level bounds
991 (*
992 // don't spawn bubbles outside of the liquid
993 if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
994 Continue;
995 *)
997 // trace liquid, so we'll know where it ends; do it in 8px steps for speed
998 // tracer will return `false` if we started outside of the liquid
1000 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1002 ptr := mapGrid.traceOrthoRayWhileIn(liquidx, liquidTopY, x, y, x, 0, GridTagWater or GridTagAcid1 or GridTagAcid2);
1004 e_LogWritefln('traceOrthoRayWhileIn: time=%s (%s); liquidTopY=%s', [Integer(stt), ptr, liquidTopY]);
1005 //
1009 e_LogWritefln('g_Map_TraceLiquidNonPrecise: time=%s (%s); liquidTopY=%s', [Integer(stt), nptr, liquidTopY]);
1011 {$ELSE}
1014 {$ENDIF}
1037 // ////////////////////////////////////////////////////////////////////////// //
1039 label
1040 _done;
1041 var
1045 begin
1051 // apply gravity
1053 begin
1058 // flying
1060 begin
1061 // has some horizontal velocity
1067 begin
1068 // hit the wall; falling down vertically
1072 end
1074 begin
1075 // has some vertical velocity
1077 begin
1078 // flying up
1082 begin
1083 // oops, hit a ceiling
1088 // environment didn't changed
1089 end
1090 else
1091 begin
1092 // falling down
1096 begin
1097 // hit something except a floor?
1099 // otherwise, go to sleep
1102 // environment didn't changed
1107 _done:
1108 if (x < g_Map_MinX) or (y < g_Map_MinY) or (x > g_Map_MaxX) or (y > g_Map_MaxY) then begin die(); end;
1113 begin
1122 // ////////////////////////////////////////////////////////////////////////// //
1124 var
1129 begin
1142 begin
1144 begin
1148 // check for level bounds
1151 // in what environment we are starting in?
1154 begin
1155 // either in a wall, or in a liquid
1156 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1157 //env := TEnvType.ELiquid;
1158 continue;
1159 end
1160 else
1161 begin
1169 begin
1195 var
1202 begin
1223 begin
1225 begin
1229 // check for level bounds
1232 // in what environment we are starting in?
1235 begin
1236 // either in a wall, or in a liquid
1237 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
1238 //env := TEnvType.ELiquid;
1239 continue;
1240 end
1241 else
1242 begin
1269 // ////////////////////////////////////////////////////////////////////////// //
1271 var
1273 begin
1284 begin
1290 var
1292 begin
1296 begin
1298 Exit;
1302 begin
1305 end
1306 else
1307 begin
1315 var
1317 begin
1333 // ////////////////////////////////////////////////////////////////////////// //
1334 // st: set mark
1335 // t: mark type
1336 // currently unused
1338 var
1341 begin
1345 // make some border, so we'll hit particles lying around the panel
1352 begin
1355 begin
1364 // ////////////////////////////////////////////////////////////////////////// //
1366 begin
1367 //g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
1368 //SetLength(gCollideMap, gMapInfo.Height+1);
1369 //for a := 0 to High(gCollideMap) do SetLength(gCollideMap[a], gMapInfo.Width+1);
1371 {$IFDEF HEADLESS}
1373 {$ENDIF}
1378 var
1380 begin
1387 begin
1393 // why not?
1399 // ////////////////////////////////////////////////////////////////////////// //
1401 var
1405 begin
1409 begin
1416 begin
1418 begin
1420 begin
1429 // clear awake map
1433 begin
1436 begin
1438 ONCEANIM_SMOKE:
1439 begin
1448 begin
1451 end
1452 else
1460 var
1462 begin
1466 begin
1477 begin
1479 begin
1481 begin
1494 begin
1497 begin
1499 begin