# Formulas

Formulas are the math engine behind Spark's number crunching. They are used for damage calculations, healing calculations, stat scaling, stat bonuses, and anywhere else a custom calculation is needed. Formulas are not limited to combat — any system that needs a calculated value can reference a formula.

Spark uses **nCalc**, a powerful open-source expression evaluator for .NET, as its formula engine. This means formulas support a full range of mathematical operations, conditional logic, and built-in functions.

## Creating a Formula

Open the Spark Editor, go to **Combat > Formulas** and click **Create New**.

Each formula entry has:

| Field              | Description                                                                           |
| ------------------ | ------------------------------------------------------------------------------------- |
| Formula Expression | The nCalc math expression (e.g., `BaseDamage + [AttackPower] * 2.5 - [Armor] * 0.5`). |
| Variable Mappings  | Maps variable names in the expression to stat values from the caster or target.       |

## Variable Mappings

Each variable mapping connects a name used in the formula to an actual stat value at runtime:

| Field         | Description                                                                                                           |
| ------------- | --------------------------------------------------------------------------------------------------------------------- |
| Variable Name | The name used in the expression (e.g., "AttackPower").                                                                |
| Stat          | Which stat entry to read the value from.                                                                              |
| Property ID   | Which property of the stat: `value` (for value stats), `current` or `maximum` (for resource stats). Default: `value`. |
| Source        | Whether to read from the **Caster** or the **Target** entity.                                                         |

## Built-in Variables

These variables are automatically available in every formula without needing a mapping:

| Variable          | Description                                                      |
| ----------------- | ---------------------------------------------------------------- |
| `BaseDamage`      | The base damage value from the damage effect.                    |
| `BaseHealing`     | The base healing value from the healing effect.                  |
| `StackMultiplier` | The current stack count of the status applying this effect.      |
| `Random`          | A random value between 0 and 1, generated fresh each evaluation. |

## nCalc Expression Reference

Spark's formula system supports the full nCalc expression language. Below is a reference of everything you can use in formula expressions.

### Arithmetic Operators

| Operator | Description         | Example                 |
| -------- | ------------------- | ----------------------- |
| `+`      | Addition            | `BaseDamage + 10`       |
| `-`      | Subtraction         | `[MaxHP] - [CurrentHP]` |
| `*`      | Multiplication      | `[AttackPower] * 2.5`   |
| `/`      | Division            | `[Damage] / 2`          |
| `%`      | Modulus (remainder) | `[Level] % 10`          |
| `**`     | Exponentiation      | `[Level] ** 2`          |

### Comparison Operators

| Operator     | Description           | Example             |
| ------------ | --------------------- | ------------------- |
| `=` or `==`  | Equal                 | `[Level] = 10`      |
| `!=` or `<>` | Not equal             | `[Class] != 0`      |
| `<`          | Less than             | `[CurrentHP] < 100` |
| `>`          | Greater than          | `[Armor] > 50`      |
| `<=`         | Less than or equal    | `[Mana] <= 0`       |
| `>=`         | Greater than or equal | `[Level] >= 5`      |

### Logical Operators

| Operator       | Description | Example                         |
| -------------- | ----------- | ------------------------------- |
| `and` or `&&`  | Logical AND | `[Level] > 5 and [HasBuff] = 1` |
| `or` or `\|\|` | Logical OR  | `[IsBoss] = 1 or [IsElite] = 1` |
| `not`          | Logical NOT | `not ([IsDead] = 1)`            |

### Conditional Functions

| Function                                    | Description                                                        | Example                                                         |
| ------------------------------------------- | ------------------------------------------------------------------ | --------------------------------------------------------------- |
| `if(condition, trueValue, falseValue)`      | Returns one of two values based on a condition.                    | `if([CurrentHP] < [MaxHP] * 0.3, BaseDamage * 1.5, BaseDamage)` |
| `switch(condition1, result1, ..., default)` | Returns a value from a list based on the first matching condition. | `switch([Element] = 1, 'Fire', [Element] = 2, 'Ice', 'Normal')` |
| `in(value, set...)`                         | Checks if a value is in a set.                                     | `in([DamageType], 1, 3, 5)`                                     |

### Built-in Math Functions

nCalc provides all standard math functions from .NET's `System.Math`:

| Function              | Description                       | Example                                |
| --------------------- | --------------------------------- | -------------------------------------- |
| `Abs(x)`              | Absolute value                    | `Abs([Armor] - [Penetration])`         |
| `Ceiling(x)`          | Round up to nearest integer       | `Ceiling(BaseDamage * 1.3)`            |
| `Floor(x)`            | Round down to nearest integer     | `Floor([CritMultiplier] * BaseDamage)` |
| `Round(x)`            | Round to nearest integer          | `Round([AttackPower] * 0.7)`           |
| `Round(x, decimals)`  | Round to specified decimal places | `Round([DPS], 2)`                      |
| `Truncate(x)`         | Remove decimal portion            | `Truncate([RawDamage])`                |
| `Max(x, y)`           | Return the larger value           | `Max(1, BaseDamage - [Armor])`         |
| `Min(x, y)`           | Return the smaller value          | `Min([CurrentHP], [MaxHP])`            |
| `Pow(x, y)`           | Raise x to the power of y         | `Pow([Level], 1.5) * 10`               |
| `Sqrt(x)`             | Square root                       | `Sqrt([Intelligence]) * 5`             |
| `Log(x)`              | Natural logarithm                 | `Log([Level] + 1) * 50`                |
| `Log10(x)`            | Base-10 logarithm                 | `Log10([Experience])`                  |
| `Log(x, base)`        | Logarithm with custom base        | `Log([Value], 2)`                      |
| `Exp(x)`              | e raised to the power of x        | `Exp(-0.1 * [Armor])`                  |
| `Sign(x)`             | Returns -1, 0, or 1               | `Sign([Direction])`                    |
| `Sin(x)`              | Sine (radians)                    | `Sin([Angle])`                         |
| `Cos(x)`              | Cosine (radians)                  | `Cos([Angle])`                         |
| `Tan(x)`              | Tangent (radians)                 | `Tan([Angle])`                         |
| `Asin(x)`             | Arc sine                          | `Asin([Value])`                        |
| `Acos(x)`             | Arc cosine                        | `Acos([Value])`                        |
| `Atan(x)`             | Arc tangent                       | `Atan([Value])`                        |
| `Atan2(y, x)`         | Arc tangent of y/x                | `Atan2([DeltaY], [DeltaX])`            |
| `IEEERemainder(x, y)` | IEEE remainder                    | `IEEERemainder([Value], 360)`          |

## Formula Examples

Here are some practical formula examples for common game mechanics:

**Simple damage with armor reduction:**

```
Max(1, BaseDamage + [AttackPower] * 2 - [TargetArmor] * 0.5)
```

**Critical hit with random chance:**

```
if(Random < [CritChance] / 100, BaseDamage * [CritMultiplier], BaseDamage)
```

**Percentage-based healing:**

```
[TargetMaxHP] * 0.15 + [HealingPower] * 0.5
```

**Level-scaled damage with diminishing returns:**

```
BaseDamage * (1 + Log([Level] + 1) * 0.5) + [AttackPower] * 1.2
```

**Conditional damage bonus (execute-style, bonus damage on low HP targets):**

```
if([TargetCurrentHP] < [TargetMaxHP] * 0.3, BaseDamage * 2.0, BaseDamage) + [AttackPower]
```

## Where Formulas Are Used

Formulas appear in several places throughout Spark:

* **Damage effects**: Custom damage calculation replacing the default BaseDamage.
* **Healing effects**: Custom healing calculation.
* **Stat scaling**: Stats can scale damage/healing types using a formula instead of flat/percentage.
* **Stat bonuses**: Stat-to-stat bonuses can use formulas for complex scaling relationships.

Because formulas are database entries, the same formula can be reused across multiple abilities, stats, and effects.

## Performance

Spark caches compiled formula expressions and uses version tracking to invalidate the cache only when a formula changes. This means formula evaluation is fast at runtime even with complex expressions. The result is always clamped to a minimum of 0 to prevent negative values.


---

# Agent Instructions: 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:

```
GET https://docs.sparkframework.dev/documentation/user-guide/plugins/combat/formulas.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
