Skip to content

Drain

namespace Griff.Modules.PhysicsGames;
public sealed class Drain : Component, IPlaytestReport

The drain at the bottom of a pinball table, with no code: a ball that falls into it is lost, and the next of its Balls is served onto the Plunger``ServeDelay seconds later, until there are none left and the game’s over. A ball lost within BallSave seconds of being shot is given back instead, and shot again by itself (once: shot again, it has no ball save of its own).

Put it on a trigger below the flippers. A ball is any body that falls into it (or one on its Layers); with other balls still on the table (multiball) a ball that drains just goes, and no ball is lost. Its Ball, Balls Left and Game Over outputs are for a Counter (“Ball {0}”) or a panel; its GameOverMessage opens a game-over panel. Its Extra Ball action adds a ball (a target or a Counter’s Reach can award one), and Save Ball starts a ball save. A Tilt covering it is put right as each ball drains.

This is a component: its saved properties are on its component page.

public int Ball { get; set; }

Which ball is being played: 1 for the first.

public float BallSave { get; set; }

Seconds after each ball is shot from the plunger that losing it gives it back (served and shot again by itself, with no save of its own this time): a ball save. 0 saves none.

public int Balls { get; set; }

How many balls a game has.

public int BallsLeft { get; }

How many balls are left, the one being played too: 0 once the game’s over.

public string? DrainMessage { get; set; }

A message sent as a ball is lost, with the balls left as its data, e.g. “BallLost”.

public bool GameOver { get; set; }

True once the last ball has drained.

public string? GameOverMessage { get; set; }

A message sent as the last ball drains, e.g. “GameOver”: a panel that says so opens on it.

public string? Layers { get; set; }

The collision layers it drains, e.g. “Ball”. Empty drains any body that falls into it (but flippers).

public string? Plunger { get; set; }

The plunger each new ball is served onto, by name. Empty: the nearest plunger.

public float SaveLeft { get; set; }

Seconds the ball save still has; 0 when it’s off. Set by the game.

public string? SaveMessage { get; set; }

A message sent as a lost ball is given back by the ball save, e.g. “BallSaved”.

public bool SaveReady { get; set; }

True from a ball being served until it’s shot, which starts its ball save (not for a saved ball). Set by the game.

public string? SaveSound { get; set; }

A sound played as a lost ball is saved.

public bool Saved { get; set; }

True if the ball being served was saved, so it’s shot again by itself. Set by the game.

public bool Saving { get; }

True while losing the ball would give it back.

public float ServeDelay { get; set; }

Seconds after a ball drains before the next is served onto the plunger.

public float ServeIn { get; set; }

Seconds until it’s served. Set by the game.

public string? Serving { get; set; }

The ball waiting to be served, by its entity’s id. Set by the game.

public string? Sound { get; set; }

A sound played as a ball drains, e.g. “Sounds/drain.wav”.

public string? Within { get; set; }

The table it counts balls on, by an entity’s name: the balls inside it or standing in its area. Empty counts every ball in the scene.

public void ExtraBall()

Adds a ball to the game.

public void SaveBall()

Starts a ball save of its Ball Save’s seconds (5 if that’s 0): losing the ball soon gives it back.

public override bool Uses(string property)
public event Action<Drain, Entity, bool>? Drained

Raised as a ball drains, with the ball and whether it was saved.