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_NEW_SPARK_THINKER}
20 interface
22 uses
25 const
52 procedure g_GFX_Water (fX, fY: Integer; count: Word; fVelX, fVelY: Single; devX, devY, color: Byte;
54 procedure g_GFX_SimpleWater (fX, fY: Integer; count: Word; fVelX, fVelY: Single; defColor, cr, cg, cb: Byte);
68 var
73 implementation
75 uses
81 const
85 type
89 // Wall: floorY is just before floor
90 // LiquidIn: floorY is liquid *start* (i.e. just in a liquid)
91 // LiquidOut: floorY is liquid *end* (i.e. just out of a liquid)
94 // note: this MUST be record, so we can keep it in
95 // dynamic array and has sequential memory access pattern
107 // for water
115 // for all
120 //k8: sorry, i have to emulate virtual methods this way, 'cause i haet `Object`
146 var
151 // awakeMap has one bit for each map grid cell; on g_Mark,
152 // corresponding bits will be set, and in `think()` all particles
153 // in marked cells will be awaken
160 // ////////////////////////////////////////////////////////////////////////// //
161 // HACK! using mapgrid
163 begin
169 begin
177 {$IF DEFINED(D2F_DEBUG)}
178 e_LogWritefln('particle awake map: %sx%s (for grid of size %sx%s)', [awakeMapW, awakeMapH, mapGrid.gridWidth, mapGrid.gridHeight]);
179 {$ENDIF}
185 begin
189 begin
190 {$IF DEFINED(D2F_DEBUG)}
192 {$ENDIF}
194 end
195 else
196 begin
203 var
205 begin
209 begin
210 {$IF DEFINED(D2F_DEBUG)}
212 {$ENDIF}
219 // ////////////////////////////////////////////////////////////////////////// //
224 begin
229 begin
231 begin
232 // wakeup this particle
233 {
234 if (part.ParticleType = PARTICLE_SPARK) then
235 begin
236 e_LogWritefln('waking up particle of type %s; justSticked=%s; onGround=%s; VelY=%s; AccelY=%s', [part.ParticleType, part.justSticked, part.onGround, part.VelY, part.AccelY]);
237 end;
238 }
241 begin
251 // remove velocities and acceleration
253 begin
254 // stop right there, you criminal scum!
262 // switch to sleep mode
264 begin
271 var
274 begin
276 // stuck in the wall? rescan, 'cause it can be mplat
278 begin
281 begin
282 // either in a wall, or in a liquid
284 begin
285 // we are in the wall, wtf?!
290 exit;
292 // we are in liquid, trace to liquid end
296 // are we in a liquid?
298 begin
299 // trace out of the liquid
300 //env := TEnvType.ELiquid;
302 //e_LogWritefln('tracing out of a liquid; floorY=%s; y=%s', [floorY, y]);
305 //e_LogWritefln(' traced out of a liquid; floorY=%s; y=%s', [floorY, y]);
306 end
307 else
308 begin
309 // in the air
311 //env := TEnvType.EAir;
312 pan := g_Map_traceToNearest(x, y, x, g_Map_MaxY, (GridTagObstacle or GridTagLiquid), @ex, @floorY);
314 begin
315 // wall or liquid
317 begin
318 // wall
320 end
321 else
322 begin
323 // liquid
327 end
328 else
329 begin
330 // out of the level; assume wall, but it doesn't really matter
339 var
341 begin
344 begin
351 begin
352 // awake sleeping particle, if necessary
356 //TPartType.Spark: thinkerSpark();
362 // ////////////////////////////////////////////////////////////////////////// //
365 begin
373 var
375 begin
379 // find next floor transition
381 // find `wallEndY`
382 mapGrid.traceOrthoRayWhileIn(ex, wallEndY, x+stickDX, y, x+stickDX, floorY+1, (GridTagWall or GridTagDoor or GridTagStep));
383 //if (wallEndY > floorY) then wallEndY := floorY; // just in case
387 begin
394 // `true`: didn't, get outa thinker
396 begin
405 // `true`: affected by air stream
407 var
409 begin
413 begin
415 begin
420 end
422 begin
425 end
427 begin
430 end
431 else
432 begin
435 // awake
440 // switch to freefall mode
442 begin
449 begin
452 begin
455 end
456 else
457 begin
463 label
464 _done;
465 var
469 begin
471 begin
472 // still check for air streams when sleeping
473 if (state = TPartState.Sleeping) then begin checkAirStreams(); goto _done; end; // so blood will dissolve
475 // process stuck particles
477 begin
478 // stuck to a ceiling?
480 begin
481 // yeah, stuck to a ceiling
483 // dropped from a ceiling?
485 begin
486 // yep
490 end
491 else
492 begin
493 // otherwise, try to drip
496 end
497 else
498 begin
499 // stuck to a wall
501 // floor transition?
503 begin
506 begin
511 begin
512 // rescan, so we'll know when we'll exit the liquid
516 begin
517 // rescan, so we'll know when we'll enter something interesting
523 // wall transition?
525 begin
526 // just unstuck from the wall, switch to freefall mode
528 end
529 else
530 begin
531 // otherwise, try to drip
535 // nope, process as usual
538 // it is important to have it here
542 // gravity, if not stuck
544 begin
546 // floor transition?
548 begin
551 begin
552 // nothing to do
555 begin
556 // rescan, so we'll know when we'll exit the liquid
561 begin
562 // rescan, so we'll know when we'll enter something interesting
564 if (floorType <> TFloorType.Wall) or (floorY <> y) then applyGravity(floorType = TFloorType.LiquidIn);
567 end
568 else
569 begin
570 // looks like we're in the air
575 // trace movement
577 begin
578 // has some horizontal velocity
585 begin
586 // we stuck
587 // the only case when we can have both ceiling and wall is corner; stick to wall in this case
588 // check environment (air/liquid)
589 if (g_Map_PanelAtPoint(x, y, GridTagLiquid) <> nil) then env := TEnvType.ELiquid else env := TEnvType.EAir;
590 // check if we stuck to a wall
593 begin
594 // stuck to a wall
596 end
597 else
598 begin
599 // stuck to a ceiling
603 end
605 begin
606 // has only vertical velocity
608 begin
609 // flying up
613 // environmend didn't changed
614 end
615 else
616 begin
618 begin
619 // falling down
622 //e_LogWritefln('floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
624 begin
625 // floor transition
628 //e_LogWritefln(' HIT FLOORY: floorY=%s; newy=%s; dY=%s; floorType=%s', [floorY, y, dY, floorType]);
631 begin
632 // environmend didn't changed
637 begin
638 // we're entered the liquid
640 // rescan, so we'll know when we'll exit the liquid
644 begin
645 // we're exited the liquid
647 // rescan, so we'll know when we'll enter something interesting
650 begin
656 end
657 else
658 begin
665 else
666 begin
667 // simple blood
672 if (x > g_Map_MaxX) or (y > g_Map_MaxY) or (x < g_Map_MinX) or (y < g_Map_MinY) then begin die(); exit; end;
676 _done:
680 // blood will dissolve in other liquids
682 begin
684 begin
692 end
693 else
694 begin
695 // water will disappear in water (?)
702 // ////////////////////////////////////////////////////////////////////////// //
703 procedure g_GFX_SparkVel (fX, fY: Integer; count: Word; VX, VY: Integer; devX, devY: Byte); forward;
709 begin
711 begin
716 end
717 else
718 begin
723 var
729 begin
733 begin
735 exit;
748 begin
750 begin
754 // check for level bounds
757 // in what environment we are starting in?
760 begin
761 // either in a wall, or in a liquid
764 end
765 else
766 begin
774 begin
801 procedure g_GFX_Water (fX, fY: Integer; count: Word; fVelX, fVelY: Single; devX, devY, color: Byte;
803 var
808 begin
825 begin
827 begin
829 begin
838 end
839 else
840 begin
850 // check for level bounds
853 // in what environment we are starting in?
856 begin
857 // either in a wall, or in a liquid
858 //if ((pan.tag and GridTagObstacle) <> 0) then continue; // don't spawn in walls
859 //env := TEnvType.ELiquid;
860 continue;
861 end
862 else
863 begin
867 // color
870 begin
876 begin
882 begin
888 begin
897 begin
906 begin
927 procedure g_GFX_SimpleWater (fX, fY: Integer; count: Word; fVelX, fVelY: Single; defColor, cr, cg, cb: Byte);
928 begin
933 // ////////////////////////////////////////////////////////////////////////// //
935 var
937 begin
941 begin
944 begin
946 end
947 else
948 begin
960 {.$DEFINE D2F_DEBUG_BUBBLES}
962 var
966 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
969 {$ENDIF}
970 begin
983 begin
985 begin
989 // check for level bounds
992 (*
993 // don't spawn bubbles outside of the liquid
994 if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
995 Continue;
996 *)
998 // trace liquid, so we'll know where it ends; do it in 8px steps for speed
999 // tracer will return `false` if we started outside of the liquid
1001 {$IF DEFINED(D2F_DEBUG_BUBBLES)}
1003 ptr := mapGrid.traceOrthoRayWhileIn(liquidx, liquidTopY, x, y, x, 0, GridTagWater or GridTagAcid1 or GridTagAcid2);
1005 e_LogWritefln('traceOrthoRayWhileIn: time=%s (%s); liquidTopY=%s', [Integer(stt), ptr, liquidTopY]);
1006 //
1010 e_LogWritefln('g_Map_TraceLiquidNonPrecise: time=%s (%s); liquidTopY=%s', [Integer(stt), nptr, liquidTopY]);
1012 {$ELSE}
1015 {$ENDIF}
1038 // ////////////////////////////////////////////////////////////////////////// //
1040 begin
1042 result := g_Map_HasAnyPanelAtPoint(x, y, (PANEL_WALL or PANEL_OPENDOOR or PANEL_CLOSEDOOR or PANEL_STEP));
1045 // ???
1047 begin
1053 begin
1059 begin
1065 begin
1071 begin
1077 begin
1083 begin
1085 result := g_Map_HasAnyPanelAtPoint(x, y, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_OPENDOOR or PANEL_WATER or PANEL_ACID1 or PANEL_ACID2 or PANEL_STEP or PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT));
1089 // ////////////////////////////////////////////////////////////////////////// //
1091 var
1093 {$IF not DEFINED(D2F_NEW_SPARK_THINKER)}
1096 {$ELSE}
1099 {$ENDIF}
1100 begin
1104 {$IF DEFINED(D2F_NEW_SPARK_THINKER)}
1106 begin
1107 pan := g_Map_traceToNearest(x, y-1, x, y+1, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey);
1109 {$ELSE}
1118 {$ENDIF}
1121 begin
1122 {$IF DEFINED(D2F_NEW_SPARK_THINKER)}
1123 pan := g_Map_traceToNearest(x, y, x+dX, y, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey);
1124 //e_WriteLog(Format('spark h-trace: (%d,%d)-(%d,%d); dx=%d; end=(%d,%d); hit=%d', [X, Y, X+dX, Y, dX, ex, ey, Integer(pan <> nil)]), MSG_NOTIFY);
1127 // free to ride?
1129 begin
1130 // nope
1131 if ((pan.tag and (GridTagAcid1 or GridTagAcid2 or GridTagWater)) <> 0) then begin die(); exit; end;
1136 {$ELSE}
1140 begin
1142 //c := gCollideMap[Y, X+s];
1147 Break;
1148 end
1153 begin
1155 break;
1158 {$ENDIF}
1162 begin
1163 {$IF DEFINED(D2F_NEW_SPARK_THINKER)}
1165 begin
1166 pan := g_Map_traceToNearest(x, y, x, y+dY, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey);
1168 {
1169 if awaken then
1170 begin
1171 awaken := false;
1172 e_LogWritefln('AWAKEN particle of type %s; justSticked=%s; onGround=%s; VelY=%s; AccelY=%s; Y=%s; ey=%s', [ParticleType, justSticked, onGround, VelY, AccelY, Y, ey]);
1173 end;
1174 }
1175 // free to ride?
1177 begin
1178 // nope
1179 if ((pan.tag and (GridTagAcid1 or GridTagAcid2 or GridTagWater)) <> 0) then begin die(); exit; end;
1181 begin
1184 end
1185 else
1186 begin
1193 onGround := (velY >= 0) and g_Map_HasAnyPanelAtPoint(x, y+1, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
1196 {$ELSE}
1200 begin
1202 //c := gCollideMap[Y+s, X];
1206 begin
1209 end
1211 begin
1218 Break;
1219 end
1224 begin
1226 break;
1229 {$ENDIF}
1235 begin
1244 // ////////////////////////////////////////////////////////////////////////// //
1246 var
1251 begin
1252 exit;
1264 begin
1266 begin
1276 else
1292 onGround := (velY >= 0) and g_Map_HasAnyPanelAtPoint(x, y+1, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
1298 else
1305 var
1312 begin
1313 exit;
1317 Exit;
1336 begin
1338 begin
1357 onGround := (velY >= 0) and g_Map_HasAnyPanelAtPoint(x, y+1, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
1363 else
1369 // ////////////////////////////////////////////////////////////////////////// //
1371 var
1373 begin
1380 //if CurrentParticle >= Count then
1386 begin
1392 var
1394 begin
1398 begin
1400 Exit;
1404 begin
1407 end
1408 else
1409 begin
1417 var
1419 begin
1422 Exit;
1435 // ////////////////////////////////////////////////////////////////////////// //
1436 // st: set mark
1437 // t: mark type
1438 // currently unused
1440 var
1443 begin
1445 // make some border, so we'll hit particles lying around the panel
1452 begin
1455 begin
1464 // ////////////////////////////////////////////////////////////////////////// //
1465 {$IF DEFINED(HAS_COLLIDE_BITMAP)}
1467 var
1469 begin
1470 //g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False);
1471 //SetLength(gCollideMap, gMapInfo.Height+1);
1472 //for a := 0 to High(gCollideMap) do SetLength(gCollideMap[a], gMapInfo.Width+1);
1474 {$ENDIF}
1478 begin
1479 //CreateCollideMap();
1481 {$IFDEF HEADLESS}
1483 {$ENDIF}
1488 var
1490 begin
1497 begin
1503 // why not?
1509 // ////////////////////////////////////////////////////////////////////////// //
1511 var
1515 begin
1519 begin
1526 begin
1528 begin
1530 begin
1533 //if not alive then Continue;
1534 //e_WriteLog(Format('particle #%d: %d', [State, ParticleType]), MSG_NOTIFY);
1541 // clear awake map
1545 begin
1548 begin
1550 ONCEANIM_SMOKE:
1551 begin
1560 begin
1563 end
1564 else
1572 var
1574 begin
1576 begin
1590 begin