hand-fistCh 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:

    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:

    // 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:

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:

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

Last updated