# Achievements

**URL:** https://heroiclabs.com/docs/hiro/concepts/achievements/
**Summary:** Achievements are a way to reward players for completing specific tasks in your game.
**Keywords:** achievement, player progression
**Categories:** hiro, achievements, concepts

---

<figure class="float-right" style="max-width: 35%; border: 20px solid transparent; text-align: center;">
  <img 
    src="{{< fingerprint_image "/images/pages/hiro/concepts/achievements/daily-goals-wordscapes.png" >}}" 
    style="width: 100%;"
  >
  <figcaption> Daily Goals in Wordscapes by PeopleFun </figcaption>
</figure>

# Achievements

The Achievement system is a great tool that game designers can use to create a sense of progression by unlocking new content and rewarding players for completing tasks.

An "achievement" represents a player task which can be completed and, on completion, can unlock a reward. The reward can be in-game currency, collectables, energy, energy modifiers, or consumables.

For increased player engagement and larger sense of progression, achievements can be configured to have a precondition. This means that the achievement cannot be completed until one or more other achievements have been completed.

Achievements can also be configured to have any number of [sub achievements](./sub-achievements/). Sub achievements are nested, hierarchical achievements that can be used for progressive rewards.

{{< note "outline" "" hide_icon>}}
Ready to try it yourself? Explore the [Achievements sample project](../../../sample-projects/unity/hiro-achievements/).
{{</ note>}}

## Use Cases

- Daily/weekly quests: Recurring goals that reset on a schedule.
- Battle pass tracks: A parent achievement with sub‑achievements for each tier; rewards per tier plus an optional completion reward.
- Limited‑time events: Achievements that are only active during an event window.
- Milestones: One‑off goals that don’t repeat.

## Key Terms

- Achievement: A top‑level goal that can award a reward and may contain **sub‑achievements**.
- Sub‑achievement: A child goal used for progressive tracks or stepwise rewards.
- Active phase: The time window during which progress counts for an achievement before it completes or resets.
- `is_active`: A read-only boolean on the returned achievement object. The server computes
  this field at response time to indicate whether the achievement's active phase is currently
  in effect. Use it to show or hide achievements in your UI without requiring client-side
  time math. It is `true` when all of the following hold:
    - The current time is at or after `start_time_sec` (if set).
    - The current time is before `end_time_sec` (if set).
    - The current time falls within the active phase window defined by `reset_cronexpr` and `duration_sec` (if set).
- ``reward`` vs ``total_reward``:
  - ``reward`` applies to the achievement (or a sub‑achievement) itself.
  - ``total_reward`` applies when a parent achievement with sub‑achievements is fully complete.
- Auto-claim:
  - ``auto_claim``: Automatically claims the reward defined on that achievement/sub‑achievement.
  - ``auto_claim_total``: Automatically claims the total_reward on the parent achievement when all sub‑achievements are complete.
- Preconditions (precondition_ids): Other achievement or sub‑achievement IDs that must be complete before this one becomes available.

## Achievement response fields

The following fields are returned on achievement objects but are not configuration parameters.
They are populated by the server when retrieving or updating achievements.

| Field | Type | Description |
|---|---|---|
| `is_active` | boolean | Whether the achievement's active phase is currently in effect. Computed at request time from scheduling fields. |
| `update_time_sec` | integer | Unix timestamp (seconds) of the last time this achievement's progress was updated in storage. Used internally to detect stale progress across scheduling windows. |


## Scheduling

Achievements can be configured to repeat on a schedule, or to repeat automatically when the player completes the task. They can also be one-off achievements which are only completed once. If an achievement has been completed, but hasn't been claimed yet, and the schedule causes it to reset, the player is still able claim their rewards. Alternatively, you could set the achievement to be auto claimed upon completion. If the achievement is set to reset upon completion, rather than using an interval, it will reset immediately, even if there are rewards to claim (they can still be claimed later).  

An achievement's active phase and reset schedule is calculated as soon as the configuration is loaded by the server, this means that you can't currently create an achievement to be available at a future point in time, instead, it would have to be created/added at that future point in time. An easy way to do this is to use [Satori Feature Flags](../../../satori/concepts/remote-configuration/) to add new achievements to the remote configuration when you want them to become available.

Achievements can be always‑available, time‑boxed, or recurring. Four fields govern timing:
- ``reset_cronexpr``: A cron expression that creates recurring active phases (for example, every day at 00:00).
- ``duration_sec``: The length of each active phase. When the duration elapses, the phase ends and the achievement resets if it is recurring.
- ``start_time_sec``: The first moment a phase is allowed to begin (Unix timestamp). If set, the initial phase won’t start before this time.
- ``end_time_sec``: A cutoff in the future (Unix timestamp). After this time, new phases don’t start. An in‑progress phase may still finish if it started before the cutoff.

### Scheduling configuration examples

- Nothing configured -> Always available until completed.
- ``reset_cronexpr`` only -> Recurring achievement that resets on schedule.
- ``duration_sec`` only -> A one‑time achievement with a limited active window from creation time.
- ``reset_cronexpr`` + ``duration_sec`` -> Recurring windows (for example, weekly challenges open for 72 hours).
- Add ``start_time_sec``-> Delay the first eligible phase until the start time.
- Add ``end_time_sec`` -> Stop scheduling new phases after the end time.

**Example:**
With ``reset_cronexpr`` set to weekly and duration_sec set to 3 days, phases open every Monday and last 72 hours. If ``start_time_sec`` is next Monday 00:00, nothing opens before then. If ``end_time_sec`` is one month later, weeks after that date won’t create new phases.

{{< note "note" "Reset behavior and unclaimed rewards" >}}
- When a phase ends (by duration or cron reset), the achievement’s count/progress resets for the next phase.
- If the player completed a phase but didn’t claim rewards before a reset, those rewards remain claimable.
- If an achievement is configured to reset on completion, it immediately resets into the next phase. Rewards from the completed phase remain claimable.
{{< / note >}}

## Rewards model and claiming

- Use ``reward`` for per‑step or per‑achievement payouts.
- Use ``total_reward`` to grant an additional payout when a parent achievement with sub‑achievements is fully complete.
- You may define both on the same parent. This supports battle passes that grant a reward for the final step and a completion bonus.
- Auto‑claim controls are scoped:
  - ``auto_claim`` applies only to the reward on that achievement (or sub‑achievement).
  - ``auto_claim_total`` applies only to the parent’s total_reward.

## Preconditions

Use ``precondition_ids`` to gate availability or sequence content. You can reference **achievement IDs** and **sub‑achievement IDs**. Typical patterns include:
- Linear track: Each sub‑achievement requires the previous one.
- Branching: A parent unlocks multiple children after completion.
- Event gating: A limited‑time parent requires a permanent milestone first.

## Sub‑achievements

Sub‑achievements let you build progressive tracks:
- Define as many steps as you need.
- Attach reward to each step for granular payouts.
- Optionally add a parent total_reward for finishing the whole track.
- Combine with preconditions to enforce order.

## Deleting and resetting achievements

Achievement storage can be deleted server-side, which removes all stored progress for the specified achievement IDs and lets them restart from scratch. This is an administrative operation, for example, to correct data errors or support a game update that invalidates existing
progress.

This operation is only available server-side. See [server-side achievements](../../server-framework/achievements/) for the implementation.

## Customization Parameters

The following JSON represents the customization parameters you can use to configure the default user experience for the achievements system.

```json
{
  "achievements": {
    "achievementId1": {
      "auto_claim": false,
      "auto_reset": false,
      "category": "category1",
      "count": 0,
      "reset_cronexpr": "* * * * *",
      "duration_sec": 86400,
      "max_count": 10,
      "name": "name1",
      "reward": {
        "guaranteed": {
          "currencies": {
            "gold": {
              "min": 100
            }
          },
          "items": {
            "hero_card": {
              "min": 1,
              "max": 5
            }
          }
        }
      },
      "additional_properties": {
        "propertyName": "value"
      },
      "sub_achievements": {}
    },
    "achievementId2": {
      "auto_claim": false,
      "auto_claim_total": false,
      "auto_reset": false,
      "category": "category2",
      "count": 0,
      "reset_cronexpr": "* * * * *",
      "duration_sec": 86400,
      "max_count": 10,
      "name": "name2",
      "reward": {
        "guaranteed": {
          "currencies": {
            "gold": {
              "min": 100
            }
          },
          "items": {
            "hero_card": {
              "min": 1,
              "max": 5
            }
          }
        }
      },
      "total_reward": {
        "guaranteed": {
          "currencies": {
            "gold": {
              "min": 100
            }
          },
          "items": {
            "hero_card": {
              "min": 1,
              "max": 5
            }
          }
        }
      },
      "precondition_ids": [
        "achievementId1"
      ],
      "additional_properties": {
        "propertyName": "value"
      },
      "sub_achievements": {}
    }
  }
}
```

The JSON schema defines an `achievements` object which _must contain an individual object for each achievement_ you wish to define in the system. You can configure as few or as many achievements and sub-achievements as needed for your desired gameplay.

{{< table name="gdk.concepts.achievements.achievements-system" >}}

Each individual achievement is keyed by id and may define the following:

### Achievement

{{< table name="gdk.concepts.achievements.achievement" >}}

## Additional Information

**Sample Projects**
- [Hiro Achievements sample project](../../../sample-projects/unity/hiro-achievements)
- [Mage Mayhem sample project](../../../sample-projects/games/mage-mayhem)

**How-to Guides**

- [How to implement a Battle Pass](../../guides/gameplay-mechanics/battle-pass/)
- [How to implement Quests](../../guides/gameplay-mechanics/quests/)

**Reference Docs**

- [Server-side implementation of achievements](../../server-framework/achievements/)
- [Achievements in Unity](../../unity/achievements/)
- [Achievements in Unreal](../../unreal/achievements/)

