> For the complete documentation index, see [llms.txt](https://docs.seismic.systems/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.seismic.systems/tutorials/understanding-the-clown-beatdown-contract/writing-the-contract/chapter-2-the-stamina-bar-and-robbing-secrets.md).

# Ch 2: Stamina and Robbing Secrets

In this chapter, you'll build the **stamina bar**, the protective layer that guards the clown's secrets. You'll initialize the clown's stamina and implement a `hit` function to reduce it. Additionally, you'll add a `rob()` function with a `requireDown` modifier to ensure secrets can only be stolen once the clown is knocked out. *Estimated Time: \~10 minutes.*

### Defining the stamina bar

The stamina bar determines the clown's resilience. It has an integer value (`clownStamina`), which represents how many hits the clown can withstand before going down. Let's define the stamina and initialize it in the constructor:

```solidity
    uint256 initialClownStamina; // Starting stamina restored on reset.
    uint256 clownStamina; // Remaining stamina before the clown is down.

    constructor(uint256 _clownStamina) {
        initialClownStamina = _clownStamina; // Set starting stamina.
        clownStamina = _clownStamina; // Initialize remaining stamina.
        round = 1; // Start with the first round.
    }
```

### Adding the hit function

Each time the clown is hit, its stamina decreases, bringing it one step closer to being knocked out. This is crucial for revealing secrets, **as the clown must be fully knocked out for secrets to be accessible:**

```solidity
    // Event to log hits.
    event Hit(uint256 indexed round, address indexed hitter, uint256 remaining);

    // Hit the clown to reduce stamina.
    function hit() public requireStanding {
        clownStamina--; // Decrease stamina.
        emit Hit(round, msg.sender, clownStamina); // Log the hit.
    }

    // Modifier to ensure the clown is still standing.
    modifier requireStanding() {
        require(clownStamina > 0, "CLOWN_ALREADY_DOWN");
        _;
    }
```

### What's happening here?

* **The `requireStanding` modifier**: Ensures that the function cannot be called if the clown is already knocked out (`clownStamina == 0`). This prevents unnecessary calls after the clown is down.
* **Decrementing stamina**: Each call to `hit` decreases the clown's stamina (`clownStamina`) by one.
* **Logging the action**: The `Hit` event records the round, the hitter's address (`msg.sender`), and the remaining stamina.

### Adding a stamina getter

Add a public view function so the current stamina can be checked:

```solidity
    // Get the current clown stamina.
    function getClownStamina() public view returns (uint256) {
        return clownStamina;
    }
```

### Robbing the clown

Now that we have implemented the stamina system and the ability to reduce it using the hit function, we can introduce the robbery mechanic: the clown's secret should only be revealed once it is fully knocked out.

* The secret **should remain hidden** while the **clown is standing**.
* The secret **can only be stolen** once the clown's stamina reaches **zero, i.e. when it is knocked out**.

To enforce this, we will create a function called `rob()`, which will return a randomly selected secret, but only if the clown has been fully knocked out.

Here's how we define `rob()` with a `requireDown` modifier:

```solidity
    // Reveal secret once the clown is down and the caller contributed.
    function rob() public view requireDown returns (bytes memory) {
        sbytes memory secret = secrets[uint256(secretIndex)];
        return bytes(secret); // Return the randomly selected secret.
    }

    // Modifier to ensure the clown is down.
    modifier requireDown() {
        require(clownStamina == 0, "CLOWN_STILL_STANDING");
        _;
    }
```

### What's happening here?

* **Restricting Access with a Condition**: The `requireDown` modifier ensures that `rob()` can only be called if `clownStamina == 0`, meaning the clown has been fully knocked out.
* **Revealing the Secret**: Once the condition is met, `rob()` reads the secret at the shielded `secretIndex` position. It converts the `sbytes` value to plain `bytes` for the caller.
* **Preventing Premature Access**: If `rob()` is called before the clown is knocked out, the function will revert with the error `"CLOWN_STILL_STANDING"`.

### Updated contract with hit and rob

```solidity
// SPDX-License-Identifier: MIT License
pragma solidity ^0.8.13;

contract ClownBeatdown {
    uint256 initialClownStamina; // Starting stamina restored on reset.
    uint256 clownStamina; // Remaining stamina before the clown is down.
    uint256 round; // The current round number.

    mapping(uint256 => sbytes) secrets; // Pool of possible secrets (shielded).
    uint256 secretsCount; // Number of secrets for modular arithmetic.
    suint256 secretIndex; // Shielded index into the secrets mapping.

    // Event to log hits.
    event Hit(uint256 indexed round, address indexed hitter, uint256 remaining);

    constructor(uint256 _clownStamina) {
        initialClownStamina = _clownStamina; // Set starting stamina.
        clownStamina = _clownStamina; // Initialize remaining stamina.
        round = 1; // Start with the first round.
    }

    // Get the current clown stamina.
    function getClownStamina() public view returns (uint256) {
        return clownStamina;
    }

    function addSecret(string memory _secret) public {
        secrets[secretsCount] = sbytes(_secret);
        secretsCount++;
        secretIndex = suint256(_randomIndex()); // Re-pick a random secret.
    }

    // Hit the clown to reduce stamina.
    function hit() public requireStanding {
        clownStamina--; // Decrease stamina.
        emit Hit(round, msg.sender, clownStamina); // Log the hit.
    }

    // Reveal secret once the clown is down.
    function rob() public view requireDown returns (bytes memory) {
        sbytes memory secret = secrets[uint256(secretIndex)];
        return bytes(secret); // Return the randomly selected secret.
    }

    // Generate a pseudo-random index into the secrets array.
    function _randomIndex() private view returns (uint256) {
        return uint256(keccak256(abi.encodePacked(block.prevrandao, block.timestamp, round))) % secretsCount;
    }

    // Modifier to ensure the clown is down.
    modifier requireDown() {
        require(clownStamina == 0, "CLOWN_STILL_STANDING");
        _;
    }

    // Modifier to ensure the clown is still standing.
    modifier requireStanding() {
        require(clownStamina > 0, "CLOWN_ALREADY_DOWN");
        _;
    }
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.seismic.systems/tutorials/understanding-the-clown-beatdown-contract/writing-the-contract/chapter-2-the-stamina-bar-and-robbing-secrets.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
