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

# forge-gameplay-rules

> Read and override HELIX's native gameplay rules (downed, auto-respawn, ...) from server Lua.

`forge-gameplay-rules` is a thin, testable wrapper over HELIX's native gameplay-rules system
(`HGameplayRulesetComponent`, which lives on the GameState). Rules are **tag-based** (`GameplayRule.*`
tags), either **toggle** (bool) or **scalar** (number). Base values are authored per-experience;
this package exposes **server-authoritative runtime overrides** behind FORGE's `Result` convention.

Its first consumer is [forge-health](/packages/forge-health), which toggles the downed state and
auto-respawn at boot.

## Concepts

* **Toggle vs scalar.** A rule is a boolean flag or a number. Read with a default; override at runtime.
* **Overrides are server-only and reversible.** `Override*` sets a value; `ClearOverride` / `ClearAll`
  restores the experience's base value.
* **Reads are always safe.** If the ruleset component isn't up yet (no GameState), a read returns the
  supplied default with `source = "default"` rather than failing.

## Exports

| Export           | Signature                     | Returns                               |
| ---------------- | ----------------------------- | ------------------------------------- |
| `GetToggle`      | `GetToggle(tag, default)`     | `Result{ data = { value, source? } }` |
| `GetScalar`      | `GetScalar(tag, default)`     | `Result{ data = { value, source? } }` |
| `OverrideToggle` | `OverrideToggle(tag, bool)`   | `Result`                              |
| `OverrideScalar` | `OverrideScalar(tag, number)` | `Result`                              |
| `ClearOverride`  | `ClearOverride(tag)`          | `Result`                              |
| `ClearAll`       | `ClearAll()`                  | `Result`                              |

```lua theme={null}
local gr = exports["forge-gameplay-rules"]

gr:OverrideToggle("GameplayRule.Health.DownedState.Enable", true)     -- bleed-out instead of instant death
gr:OverrideToggle("GameplayRule.Health.DownedState.ShowDefaultUI", false)  -- hide native downed widget
gr:OverrideScalar("GameplayRule.Health.DownedState.Duration", 300)   -- seconds of bleed-out
```

### Well-known tags

| Tag                                                 | Kind             |
| --------------------------------------------------- | ---------------- |
| `GameplayRule.Health.DownedState.Enable`            | toggle           |
| `GameplayRule.Health.DownedState.Duration`          | scalar (seconds) |
| `GameplayRule.Health.DownedState.ReviveHealthRatio` | scalar (0..1)    |
| `GameplayRule.Health.DownedState.ShowDefaultUI`     | toggle           |
| `GameplayRule.Health.DownedState.AllowGiveUp`       | toggle           |
| `GameplayRule.Health.AutoRespawn.Enable`            | toggle           |

Creators may read or override any `GameplayRule.*` tag, not just these.

## Result codes

| Code                             | Meaning                                                 |
| -------------------------------- | ------------------------------------------------------- |
| `core:invalid_args`              | tag wasn't a string (or a scalar value wasn't a number) |
| `gameplay_rules:no_component`    | ruleset component unavailable (no GameState yet)        |
| `gameplay_rules:override_failed` | the native override call raised                         |

<Warning>
  Three UnLua traps this package handles for you, worth knowing if you call the native component
  directly:

  1. **World context must be a live player controller.** `GetGameState(HWorld)` returns nil from
     server Lua; the component is resolved via an active controller's world context instead.
  2. **Class is `UE.UHGameplayRulesetComponent`** (the `U` prefix matters).
  3. **A tag must be a real `FGameplayTag`**, built as `local t = UE.FGameplayTag(); t.TagName = name`.
     Passing a raw string silently no-ops ("userdata needed but got string").
</Warning>

## Configuration

```lua theme={null}
Config = { Enabled = true, SchemaVersion = 1 }
```

Set `Enabled = false` to register the service inert (all overrides then reject). Ships no content.
