+function TParticle.alive (): Boolean; inline; begin result := (state <> TPartState.Free); end;
+procedure TParticle.die (); inline; begin state := TPartState.Free; end;
+
+function TParticle.isSleeping (): Boolean; inline;
+begin
+ result := alive and (onGround or (not justSticked and (state = TPartState.Stuck)));
+end;
+
+procedure TParticle.awake (); inline;
+begin
+ if {alive and} (onGround or (not justSticked and (state = TPartState.Stuck))) then
+ begin
+ // wakeup this particle
+ {
+ if (part.ParticleType = PARTICLE_SPARK) then
+ begin
+ 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]);
+ end;
+ }
+ justSticked := true; // so sticked state will be re-evaluated
+ if onGround then
+ begin
+ if (velY = 0) then velY := 0.1;
+ if (accelY = 0) then accelY := 0.5;
+ end;
+ onGround := false; // so onground state will be re-evaluated
+ awaken := true;
+ end;
+end;
+
+
+procedure TParticle.findFloor (force: Boolean=false);
+var
+ ex: Integer;
+ pan: TPanel;
+begin
+ if (not force) and (floorY <> Unknown) then exit;
+ // are we in a liquid?
+ pan := g_Map_PanelAtPoint(x, y, (GridTagObstacle or GridTagLiquid));
+ if (pan <> nil) then
+ begin
+ // either in a wall, or in a liquid
+ if ((pan.tag and GridTagObstacle) <> 0) then
+ begin
+ // we are in the wall, wtf?!
+ floorY := y;
+ floorType := TFloorType.Wall;
+ state := TPartState.Sleeping; // anyway
+ exit;
+ end;
+ // we are in liquid, trace to liquid end
+ floorType := TFloorType.LiquidOut; // exiting liquid
+ //e_LogWritefln('tracing out of a liquid; floorY=%s; y=%s', [floorY, y]);
+ mapGrid.traceOrthoRayWhileIn(ex, floorY, x, y, x, g_Map_MaxY, GridTagLiquid);
+ floorY += 1; // so `floorY` is just out of a liquid
+ //e_LogWritefln(' traced out of a liquid; floorY=%s; y=%s', [floorY, y]);
+ end
+ else
+ begin
+ // not in a wall
+ pan := g_Map_traceToNearest(x, y, x, g_Map_MaxY, (GridTagObstacle or GridTagLiquid), @ex, @floorY);
+ if (pan <> nil) then
+ begin
+ // wall or liquid
+ if ((pan.tag and GridTagObstacle) <> 0) then
+ begin
+ // wall
+ floorType := TFloorType.Wall;
+ end
+ else
+ begin
+ // liquid
+ floorType := TFloorType.LiquidIn; // entering liquid
+ floorY += 1; // so `floorY` is just in a liquid
+ end;
+ end
+ else
+ begin
+ // out of the level; assume wall, but it doesn't really matter
+ floorType := TFloorType.Wall;
+ floorY := g_Map_MaxY+2;
+ end;
+ end;
+end;
+
+
+procedure TParticle.findCeiling (force: Boolean=false);
+var
+ ex: Integer;
+begin
+ if (not force) and (ceilingY <> Unknown) then exit;
+ if (nil = g_Map_traceToNearest(x, y, x, g_Map_MinY, GridTagObstacle, @ex, @ceilingY)) then
+ begin
+ ceilingY := g_Map_MinY-2;
+ end;
+end;
+