> For the complete documentation index, see [llms.txt](https://docs.overtime.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.overtime.io/overtime-casino/games/quick-games/penalty-shootout.md).

# Penalty Shootout

Pick your spot, beat the keeper, bank the win streak. Every goal compounds your multiplier, every dive is a fresh Chainlink VRF draw, and you decide when to walk away. Fully onchain.

#### How it works

Overtime Penalty Shootout is a streak game: one stake, as many kicks as you dare.

1. You pick a difficulty (**Amateur**, **Pro** or **World Class**), choose where to aim, and take the first kick. Placing the bet and taking the first kick happen in one transaction
2. The contract requests a random word from Chainlink VRF. The keeper's dive is derived from it: `randomWord % zones`, one zone out of the difficulty's total
3. If the keeper dives anywhere other than where you aimed, it's a **goal** and your running multiplier grows by the difficulty's factor. If the keeper dives to your zone, it's a **save**: the run ends and the stake is lost
4. After every goal you choose again: take another kick (at any difficulty) or **cash out** to take `stake × current multiplier`
5. The run continues until you cash out, the keeper saves, or no difficulty fits under the multiplier cap

Where you aim does not change your odds. The keeper covers exactly one zone, chosen uniformly at random, so your chance of scoring is simply the open zones over the total. Your aim is written to the contract in the same transaction that requests the randomness, before the random word exists, so neither your shot nor the keeper's dive can react to the other.

***

#### Difficulty levels

Each difficulty narrows the goal. The keeper always covers one zone.

| Difficulty  | Goal zones | Open zones | Chance to score | Multiplier per goal (2% edge) |
| ----------- | ---------- | ---------- | --------------- | ----------------------------- |
| Amateur     | 5          | 4          | 80% (4 in 5)    | 1.225×                        |
| Pro         | 3          | 2          | 66.7% (2 in 3)  | 1.47×                         |
| World Class | 2          | 1          | 50% (1 in 2)    | 1.96×                         |

You can switch difficulty between kicks. Bank a few Amateur goals and finish at World Class, or open big and play it safe once the multiplier is worth protecting. The game is fixed for the whole run; only the difficulty and your aim change from kick to kick.

***

#### The multiplier

Every goal multiplies your running total by the difficulty's factor:

```
factor = zones × (1 − houseEdge) / openZones
```

That's the entire pricing model. It makes `chance to score × factor = 1 − houseEdge` for every difficulty, so each kick carries exactly the same house edge whichever one you pick. At the default 2% edge that's **1.225×**, **1.47×** and **1.96×**. Players never supply odds: a kick is a difficulty and an aim, and the contract looks the odds up and derives the factor itself.

Goals compound:

| Goals in a row  | Amateur          | Pro              | World Class     |
| --------------- | ---------------- | ---------------- | --------------- |
| 1               | 1.225×           | 1.47×            | 1.96×           |
| 2               | 1.50×            | 2.16×            | 3.84×           |
| 3               | 1.84×            | 3.18×            | 7.53×           |
| 4               | 2.25×            | 4.67×            | 14.76×          |
| 5               | 2.76×            | 6.86×            | 28.93×          |
| 6               | 3.38×            | 10.09×           | 56.69×          |
| Most before cap | 22 goals, 86.89× | 11 goals, 69.26× | 6 goals, 56.69× |

Mixing difficulties gets closer to the cap: the highest reachable multiplier is about **99×**.

Because the edge applies to every kick, it compounds across a run. A run you cash out after `n` goals returns `0.98ⁿ` of the stake on average at the 2% edge (about 90.4% after 5 goals, whatever the difficulty). The harder difficulties reach a given multiplier in fewer kicks, so they pay less total edge getting there, in exchange for a much bigger chance of an early save.

**The cap.** The default multiplier cap is **100×**. A kick whose factor would push the multiplier past the cap is rejected, not trimmed: payouts are never silently truncated. Near the cap only the difficulties that still fit are playable (`playableTiers`), and once none fit, the only move left is to cash out. The house edge and the cap are both snapshotted when you place the bet, so a later parameter change can never alter a run that's already live.

***

#### Cashing out

This is the whole game. After any goal your multiplier is locked in as long as you stop. The moment you kick again, you're risking the entire accumulated amount on the next dive.

* **Cash out** → you receive `stake × current multiplier`, the run resolves, done
* **Kick again** → a goal grows the multiplier; a save loses everything

There is no partial cash out and no insurance. Reaching the cap does not cash out for you either: winnings are paid only in the cash out transaction, never inside the VRF callback.

Before each kick, the contract checks that the treasury can cover what that kick would owe if you score. If it can't, the kick is rejected before any randomness is requested, and your run stays exactly where it was, cashable at its current multiplier.

Runs don't expire. If a run sits idle after a goal for longer than the core's `cancelTimeout`, the resolver can settle it for you with `adminCashout`, which pays exactly what a cash out would: `stake × current multiplier`. It cannot pay less.

***

#### Limits

<table data-search="false"><thead><tr><th>Parameter</th><th>Value</th></tr></thead><tbody><tr><td>Minimum bet</td><td>3 USD (configurable per game via core)</td></tr><tr><td>Maximum bet</td><td>Bounded by max profit: <code>stake × (cap − 1) ≤ maxProfitUsd</code>. At a 2,000 USD max profit and the 100× cap, about ~ 20 USD</td></tr><tr><td>House edge</td><td>2% per kick</td></tr><tr><td>Multiplier per goal</td><td>1.225× / 1.47× / 1.96× at 2% edge</td></tr><tr><td>Multiplier cap</td><td>100× default, snapshotted per bet</td></tr><tr><td>Max kicks per run</td><td>200</td></tr><tr><td>Push</td><td>None: every kick is a goal or a save</td></tr><tr><td>Idle run</td><td>Resolver may settle it after <code>cancelTimeout</code> at the full <code>stake × current multiplier</code></td></tr><tr><td>Cancellation</td><td>Admin/resolver only, intended for a stalled VRF request; refunds original stake, forfeits accumulated multiplier</td></tr></tbody></table>

If the game is paused while you're mid-run, Cash Out is available again as soon as it's unpaused. The resolver's `adminCashout` is not pause-gated and still pays the full multiplier.

Supported collaterals: **USDC**, **WETH**, **$OVER**. Free bets supported via the `isFreeBet` flag on `placeBet`. On a lost real-money run, the referrer's share is paid automatically in the transaction that settles the save.

***

#### User guide

**1. Open Penalty Shootout**

Select **Penalty Shootout** from the casino lobby. Set your stake and collateral.

**2. Pick a difficulty**

Choose **Amateur**, **Pro** or **World Class**. The panel shows the payout on a first goal.

**3. Aim and shoot**

Pick your spot and hit **Take the Kick**. This places the bet and takes the first kick in a single transaction.

**4. Goal or save**

When the VRF callback arrives, the keeper dives. Goal: your multiplier ticks up and it's your turn again. Save: the run is over.

**5. Shoot again or cash out**

Keep the difficulty or change it, and kick again to push the multiplier higher. Or hit **Cash Out** to bank `stake × multiplier`.

**6. Resolution**

Cashing out, or a save, resolves the bet. Your full run is stored onchain and shown in your history: the difficulty of every kick, its factor, where the keeper dived, the result, and your multiplier after each one.

***

#### Onchain reference

Penalty Shootout runs on `StreakGame`, a streak engine on the shared `CasinoCoreV2` treasury. Games on the engine are registered modes, each with a fixed set of difficulty tiers validated when they're published. Read `getModes()` for the live list.

| Action                         | Call                                                                         |
| ------------------------------ | ---------------------------------------------------------------------------- |
| Start a run (bet + first kick) | `placeBet(collateral, amount, referrer, modeId, tierIdx, choice, isFreeBet)` |
| Next kick                      | `playRound(betId, tierIdx, choice)`                                          |
| Cash out                       | `cashout(betId)`                                                             |
| Difficulties still playable    | `playableTiers(betId)`                                                       |
| Kick-by-kick history           | `getBetRounds(betId)`                                                        |
| Factor for a difficulty        | `factorForTierE18(modeId, tierIdx)`                                          |

Penalty Shootout is `modeId = 1`. `tierIdx`: `0` Amateur, `1` Pro, `2` World Class. `choice` is the zone you aim at, from `0` to `zones − 1`.

***

#### Why this matters

A streak game is the easiest game in a casino to rig. The whole product is the question of whether to shoot one more time, and on a centralized site nothing stops the server from making the keeper a little better at reading you exactly when your multiplier gets big. You'd never see it happen.

On Overtime, the keeper can't read you. Each dive comes from a fresh Chainlink VRF request that doesn't exist until your aim is committed onchain. The odds are zones you can count, the factor is a published formula, the house edge is a public variable locked into your bet when you place it, and every kick of every run is reconstructable from the chain. The only thing deciding whether you score is the dive. Which is the entire point.
