> ## Documentation Index
> Fetch the complete documentation index at: https://docs.game-services.work/llms.txt
> Use this file to discover all available pages before exploring further.

# Jackpot Values Generator

> Preview STANDARD jackpot values and READ_ONLY jackpot growth.

export const JackpotValuesCalculator = () => {
  const jackpots = [{
    name: "CLOVER_7",
    indexes: ["MAJOR", "GRAND"]
  }, {
    name: "CLOVER_BURNING",
    indexes: ["MAJOR", "GRAND"]
  }, {
    name: "CASH_CONNECTION",
    indexes: ["MAJOR", "GRAND"]
  }, {
    name: "EGT_CARDS",
    indexes: ["CLUBS", "DIAMONDS", "HEARTS", "SPADES"]
  }, {
    name: "BELL-LINK",
    indexes: ["MAJOR", "GRAND"]
  }, {
    name: "DIVINE_FORTUNE",
    indexes: ["DIVINE"]
  }, {
    name: "CLOVER_CHANCE",
    indexes: ["MINI", "MINOR", "MAJOR", "GRAND"]
  }, {
    name: "3x7",
    indexes: ["MAJOR", "GRAND"]
  }];
  const [jackpotName, setJackpotName] = useState("");
  const [indexName, setIndexName] = useState("");
  const [groupType, setGroupType] = useState("");
  const [copyStatus, setCopyStatus] = useState("");
  const [startBalance, setStartBalance] = useState("1000");
  const [betsToWin, setBetsToWin] = useState("100000");
  const [contributionPercentage, setContributionPercentage] = useState("1");
  const [tickIncrement, setTickIncrement] = useState("1");
  const [endBalance, setEndBalance] = useState("13100");
  const balance = Number(startBalance);
  const bets = Number(betsToWin);
  const contribution = Number(contributionPercentage);
  const tick = Number(tickIncrement);
  const end = Number(endBalance);
  const jackpot = jackpots.find(entry => entry.name === jackpotName);
  const indexes = jackpot?.indexes || [];
  const validSettings = startBalance !== "" && Number.isInteger(balance) && balance >= 0 && (groupType === "STANDARD" ? betsToWin !== "" && contributionPercentage !== "" && Number.isInteger(bets) && bets > 0 && Number.isFinite(contribution) && contribution > 0 : tickIncrement !== "" && endBalance !== "" && Number.isInteger(tick) && tick > 0 && Number.isInteger(end) && end > balance);
  const settings = groupType === "STANDARD" ? {
    startBalance: balance,
    winProbability: bets,
    contributionPercentage: contribution
  } : {
    startBalance: balance,
    tickIncrement: tick,
    endBalance: end
  };
  const jsonText = JSON.stringify({
    jackpotName,
    indexName,
    jackpotGroupType: groupType,
    ...settings
  }, null, 2);
  const copyJson = async () => {
    try {
      await navigator.clipboard.writeText(jsonText);
      setCopyStatus("JSON copied");
    } catch {
      setCopyStatus("Could not copy JSON. Check clipboard permissions.");
    }
  };
  let averageWin = null;
  let jackpotRtp = null;
  if (groupType === "STANDARD") {
    if (betsToWin === "" || contributionPercentage === "" || bets === 0 || contribution === 0) {
      averageWin = "0.00";
      jackpotRtp = "0.00";
    } else if (Number.isFinite(balance) && balance >= 0 && Number.isFinite(bets) && bets > 0 && Number.isFinite(contribution) && contribution > 0) {
      const betsInCents = bets * 100;
      const startInCents = balance * 100;
      const contributionFraction = contribution / 100;
      const averageWinInCents = jackpotName === "CLOVER_7" ? 1 / (100 / betsInCents) * contributionFraction + startInCents : startInCents + betsInCents * contributionFraction;
      averageWin = (averageWinInCents / 100).toFixed(2);
      jackpotRtp = (jackpotName === "CLOVER_7" ? averageWinInCents * 100 / bets : averageWinInCents / bets).toFixed(2);
    }
  }
  let incrementRange = null;
  let tickRange = null;
  if (groupType === "READ_ONLY" && Number.isFinite(balance) && balance >= 0 && Number.isFinite(end) && end > balance && Number.isFinite(tick) && tick > 0) {
    const slowTick = tick * 0.9;
    const fastTick = tick * 1.1;
    incrementRange = `${slowTick.toFixed(2)}–${fastTick.toFixed(2)}`;
    tickRange = `${Math.ceil((end - balance) / fastTick).toLocaleString()}–${Math.ceil((end - balance) / slowTick).toLocaleString()}`;
  }
  const fieldClass = "mt-1 block w-full rounded-md border border-gray-300 bg-white px-3 py-2 text-gray-900 dark:border-gray-600 dark:bg-gray-900 dark:text-white";
  const labelClass = "block text-sm font-medium text-gray-700 dark:text-gray-200";
  return <div className="not-prose rounded-lg border border-gray-200 p-5 dark:border-gray-700">
      <div className="grid gap-4 sm:grid-cols-2">
        <label className={labelClass}>
          Jackpot
          <select className={fieldClass} value={jackpotName} onChange={event => {
    setJackpotName(event.target.value);
    setIndexName("");
    setGroupType("");
    setCopyStatus("");
  }}>
            <option value="">Select a jackpot</option>
            {jackpots.map(jackpot => <option key={jackpot.name} value={jackpot.name}>{jackpot.name}</option>)}
          </select>
        </label>
        {jackpot ? <label className={labelClass}>
          Index
          <select className={fieldClass} value={indexName} onChange={event => {
    setIndexName(event.target.value);
    setGroupType("");
    setCopyStatus("");
  }}>
            <option value="">Select an index</option>
            {indexes.map(name => <option key={name} value={name}>{name}</option>)}
          </select>
        </label> : null}
        {indexName ? <label className={labelClass}>
          Type
          <select className={fieldClass} value={groupType} onChange={event => {
    setGroupType(event.target.value);
    setCopyStatus("");
  }}>
            <option value="">Select a type</option>
            <option value="STANDARD">STANDARD</option>
            <option value="READ_ONLY">READ_ONLY</option>
          </select>
        </label> : null}
        {groupType ? <>
        <label className={labelClass}>
          Start balance (currency units)
          <input className={fieldClass} type="number" min="0" step="1" value={startBalance} onChange={event => {
    setStartBalance(event.target.value);
    setCopyStatus("");
  }} />
        </label>
        {groupType === "STANDARD" ? <>
            <label className={labelClass}>
              Bets to win
              <input className={fieldClass} type="number" min="1" step="1" value={betsToWin} onChange={event => {
    setBetsToWin(event.target.value);
    setCopyStatus("");
  }} />
            </label>
            <label className={labelClass}>
              Contribution percentage (%)
              <input className={fieldClass} type="number" min="0.01" step="0.01" value={contributionPercentage} onChange={event => {
    setContributionPercentage(event.target.value);
    setCopyStatus("");
  }} />
            </label>
          </> : <>
            <label className={labelClass}>
              Tick increment (currency units per 10 seconds)
              <input className={fieldClass} type="number" min="0" step="1" value={tickIncrement} onChange={event => {
    setTickIncrement(event.target.value);
    setCopyStatus("");
  }} />
            </label>
            <label className={labelClass}>
              End balance (currency units)
              <input className={fieldClass} type="number" min="0" step="1" value={endBalance} onChange={event => {
    setEndBalance(event.target.value);
    setCopyStatus("");
  }} />
            </label>
          </>}
        </> : null}
      </div>
      {groupType ? <>
      <div className="mt-5 grid gap-3 sm:grid-cols-2" aria-live="polite">
        {groupType === "STANDARD" ? <>
            <div className="rounded-md bg-gray-100 p-4 dark:bg-gray-800">
              <div className="text-sm text-gray-600 dark:text-gray-300">Average Jackpot Win</div>
              <div className="mt-1 text-xl font-semibold">{averageWin === null ? "—" : averageWin}</div>
              <div className="text-xs text-gray-500 dark:text-gray-400">In the jackpot currency</div>
            </div>
            <div className="rounded-md bg-gray-100 p-4 dark:bg-gray-800">
              <div className="text-sm text-gray-600 dark:text-gray-300">Jackpot RTP</div>
              <div className="mt-1 text-xl font-semibold">{jackpotRtp === null ? "—" : `${jackpotRtp}%`}</div>
            </div>
          </> : <>
            <div className="rounded-md bg-gray-100 p-4 dark:bg-gray-800">
              <div className="text-sm text-gray-600 dark:text-gray-300">Increase per tick</div>
              <div className="mt-1 text-xl font-semibold">{incrementRange === null ? "—" : incrementRange}</div>
              <div className="text-xs text-gray-500 dark:text-gray-400">Before the cap at End Balance</div>
            </div>
            <div className="rounded-md bg-gray-100 p-4 dark:bg-gray-800">
              <div className="text-sm text-gray-600 dark:text-gray-300">Theoretical ticks to End Balance</div>
              <div className="mt-1 text-xl font-semibold">{tickRange === null ? "—" : tickRange}</div>
              <div className="text-xs text-gray-500 dark:text-gray-400">From Start Balance; 10 seconds per scheduled tick</div>
            </div>
          </>}
      </div>
      {validSettings ? <pre className="mt-4 overflow-x-auto rounded-md bg-gray-100 p-4 text-xs text-gray-900 dark:bg-gray-800 dark:text-gray-100">{jsonText}</pre> : null}
      <div className="mt-4 flex items-center gap-3">
        <button className="rounded-md bg-blue-600 px-3 py-2 text-sm font-medium text-white disabled:cursor-not-allowed disabled:opacity-50" type="button" onClick={copyJson} disabled={!validSettings}>Copy JSON</button>
        <span className="text-sm text-gray-600 dark:text-gray-300" role="status">{copyStatus}</span>
      </div>
      <p className="mt-3 text-sm text-gray-600 dark:text-gray-300">This calculator previews values; it does not save jackpot settings.</p>
      </> : null}
    </div>;
};

Select a **Jackpot**, then one of its **Indexes**, then a **Type** (`STANDARD` or `READ_ONLY`). The settings fields and calculation preview appear after you select a type.

* **STANDARD:** Wins occur randomly, so individual payouts vary. Across a large number of wins, the system is designed to keep the average close to the intended value. The jackpot balance grows from accumulated contributions; after a win, it resets to the start balance. The calculator previews average win and jackpot RTP from the entered settings.
* **READ\_ONLY:** The service increases the balance on scheduled ticks, with a small random variation. At the end balance, it records the completed win and resets to the start balance. The calculator previews the tick increase and estimated number of ticks.

<JackpotValuesCalculator />

## Index names

After selecting a jackpot, **Index** shows only its associated indexes:

| Software | Jackpot | Index names |
| - | - | - |
| `NOVOMATIC` | `CLOVER_7` | `MAJOR`, `GRAND` |
| `NOVOMATIC` | `CLOVER_BURNING` | `MAJOR`, `GRAND` |
| `NOVOMATIC` | `CASH_CONNECTION` | `MAJOR`, `GRAND` |
| `EGT` | `EGT_CARDS` | `CLUBS`, `DIAMONDS`, `HEARTS`, `SPADES` |
| `EGT_DIGITAL` | `BELL-LINK` | `MAJOR`, `GRAND` |
| `NETENT` | `DIVINE_FORTUNE` | `DIVINE` |
| `EGT_DIGITAL` | `CLOVER_CHANCE` | `MINI`, `MINOR`, `MAJOR`, `GRAND` |
| `TRIPLE_SEVEN` | `3x7` | `MAJOR`, `GRAND` |

Changing the jackpot clears the selected index and type. The index identifies the jackpot settings being edited; it does not alter the calculations below.

## Copy the entered values

After entering valid settings, click **Copy JSON** to copy the JSON shown beneath the calculation. It includes the selected jackpot, index, type, and entered settings. The JSON is a summary of these values; copying it does not save any settings.

## STANDARD calculations

For a `STANDARD` group, enter **Start Balance**, **Bets to Win**, and **Contribution Percentage**. Let `B` be Start Balance in the jackpot currency, `N` be Bets to Win, and `C` be the entered Contribution Percentage. Enter `1` for 1%. The calculator converts balances and bet counts to cents before calculating, then displays Average Jackpot Win in currency units and Jackpot RTP as a percentage. Both displayed values are rounded to two decimal places.

| Jackpot name | Average Jackpot Win, in currency units | Jackpot RTP, in percent |
| - | - | - |
| Any name except `CLOVER_7` | `B + (N × C / 100)` | `(100 × B / N) + C` |
| `CLOVER_7` | `B + (N × C / 10000)` | `(10000 × B / N) + C` |

The `CLOVER_7` branch uses a fixed contribution value of `100` and fixed bet value of `1`. When Bets to Win or Contribution Percentage is empty or zero, the calculator displays zero for both values.

## READ\_ONLY calculations

For a `READ_ONLY` group, enter **Start Balance**, **Tick Increment**, and **End Balance**. The jackpot service attempts a tick every 10 seconds. On each tick it varies Tick Increment by a random positive or negative 5–10%, then caps the increase at the remaining distance to End Balance:

```text theme={null}
next balance = min(end balance, current balance + tick increment × multiplier)
multiplier = 1 ± a random value from 0.05 to 0.10
```

The calculator shows the possible per-tick increase from `0.9 × Tick Increment` to `1.1 × Tick Increment`, before the End Balance cap. Its tick-count range is a theoretical estimate from Start Balance: divide the remaining balance by `1.1 × Tick Increment` for the fastest case and by `0.9 × Tick Increment` for the slowest case, rounding each result up. Actual timing depends on which scheduled ticks run and the random variation. When the jackpot reaches End Balance, the service records that win and resets the current balance to Start Balance. Tick Increment of zero or less does not advance the jackpot.

For `READ_ONLY`, the calculator shows tick growth instead of Average Jackpot Win and Jackpot RTP. Its preview is calculated in your browser and does not change jackpot settings.
