---
name: set-calculations
description: Reference for the numbers the Set World API calculates about characters and items, with each formula, endpoint and response schema. Use when deriving the 23 attributes from stats, rating a character's power, computing how a trait name changes stats, scoring an item's rarity, or reading an item's power budget and theme channels, either by calling the API or by recomputing locally.
license: Free to use when obtained from set.world, commercially too (the API, what it returns, the skills and downloaded models). The source code of Set is © Jimmy Lee under CC BY-NC 4.0 and its commercial use needs a paid waiver.
metadata:
  version: "0.8.9"
  title: Calculations
---

# Calculations

Every number Set returns is a pure function of the tables and the inputs. Call the endpoint, or recompute it yourself from the formulas here; both give the same result. This skill owns five calculations. Prices in orbs (crafts, salvage, boosts, drops) are owned by [Crafting an item](https://set.world/skills/crafting-an-item).

| Calculation | Endpoint |
| --- | --- |
| Derived attributes | `/api/attributes?stats=`, `/api/attributes/spec` |
| Power rating | `/api/power?stats=&level=&skills=` |
| Trait impact | `/api/traits/impact?name=&kind=`, `/api/traits/impacts?kind=` |
| Rarity score | `/api/rarity?rolls=` or `indexes=`, `/api/rarity/tiers` |
| Item power budget and themes | `/api/modifiers?rolls=` or `indexes=`, `/api/modifiers/spec` |

`stats` is nine dash-joined integers from 8 to 24 in the canonical order ([Stats](https://set.world/skills/character-stats)). `rolls` and `indexes` are 19 dash-joined integers ([Item properties](https://set.world/skills/item-properties)).

The schemas below reuse `StatName` and `StatBlock` from [Stats](https://set.world/skills/character-stats), and `Grade` and `Material` from [Materials](https://set.world/skills/item-materials). `AttributeName` is one of the 23 names in the table below.

## Derived attributes

```text
attribute = base + primaryCoef × (primary − 8) + secondaryCoef × (secondary − 8)
```

Only the five primary stats appear. Each is clamped to 8 to 24 first; results keep four decimals.

```sh
curl 'https://set.world/api/attributes?stats=16-15-12-11-15-18-12-13-9'
curl 'https://set.world/api/attributes/spec?format=csv'
```

```ts
type AttributesResponse = { stats: StatBlock; attributes: Record<AttributeName, number> };
type AttributeSpec = Record<AttributeName, { primary: StatName; secondary: StatName; base: number; primaryCoef: number; secondaryCoef: number; unit: string; op: 'add' }>;
```

```json
{
  "stats": { "strength": 16, "dexterity": 15, "intelligence": 12, "wisdom": 11, "agility": 15, "vitality": 18, "perception": 12, "resolve": 13, "luck": 9 },
  "attributes": {
    "maxHealth": 184,
    "stamina": 96,
    "physicalDamage": 25.5,
    "magicalDamage": 19.5,
    "actionDamage": 23.2,
    "physicalDamageReduction": 0.152,
    "magicalDamageReduction": 0.088,
    "globalResistance": 0.092,
    "ailmentResistance": 0.116,
    "dodgeRate": 0.125,
    "walkSpeed": 1.155,
    "attackSpeed": 1.14,
    "castSpeed": 1.09,
    "chargeSpeedCast": 1.108,
    "chargeSpeedAction": 1.126,
    "carrySpeed": 1.15,
    "carryCapacity": 110,
    "jumpHeight": 1.11,
    "visionRange": 1.095,
    "criticalHitChance": 0.092,
    "clarity": 0.083,
    "initiative": 1.108,
    "reflexes": 0.119
  }
}
```

The formula table, as `/api/attributes/spec?format=csv` serves it:

```csv
attribute,primary,secondary,base,primaryCoef,secondaryCoef,unit
maxHealth,vitality,strength,80,8,3,hp
stamina,vitality,strength,40,4,2,sp
physicalDamage,strength,dexterity,10,1.5,0.5,dmg per swing
magicalDamage,intelligence,dexterity,10,1.5,0.5,dmg per cast
actionDamage,dexterity,strength,10,1.2,0.6,dmg per action
physicalDamageReduction,vitality,strength,0,0.012,0.004,% mitigated
magicalDamageReduction,intelligence,vitality,0,0.012,0.004,% mitigated
globalResistance,vitality,intelligence,0,0.008,0.003,% mitigated all
ailmentResistance,vitality,intelligence,0,0.01,0.004,% avoid status
dodgeRate,agility,dexterity,0.02,0.01,0.005,% avoid hits
walkSpeed,agility,vitality,1,0.015,0.005,% of base move
attackSpeed,dexterity,agility,1,0.015,0.005,% of base swing
castSpeed,intelligence,dexterity,1,0.012,0.006,% of base cast
chargeSpeedCast,intelligence,vitality,1,0.012,0.006,% of base wind-up
chargeSpeedAction,dexterity,agility,1,0.012,0.006,% of base wind-up
carrySpeed,strength,agility,1,0.01,0.01,% of base move
carryCapacity,strength,vitality,50,5,2,weight units
jumpHeight,agility,strength,1,0.01,0.005,% of base jump
visionRange,intelligence,agility,1,0.015,0.005,% of base sight
criticalHitChance,dexterity,intelligence,0.02,0.008,0.004,% crit
clarity,intelligence,dexterity,0,0.012,0.005,% chance to ignore enemy dodge
initiative,agility,intelligence,1,0.012,0.006,% of base cooldown rate
reflexes,agility,dexterity,0,0.012,0.005,% chance to counter surprise hits
```

The order of these 23 rows is the order of `AttributeName` and of the first 23 theme channels below. Percent channels are fractions: a `dodgeRate` of 0.125 is 12.5%. Units are advisory: a real-time game reads `attackSpeed` as swings per second, a turn-based game as turn-meter rate.

| Stat block | maxHealth | stamina | physicalDamage | attackSpeed | initiative |
| --- | ---: | ---: | ---: | ---: | ---: |
| All 8 | 80 | 40 | 10 | 1.00 | 1.000 |
| All 16 | 168 | 88 | 26 | 1.16 | 1.144 |
| All 24 | 256 | 136 | 42 | 1.32 | 1.288 |

## Power rating

```text
powerRating    = 100 × level + 10 × (strength + intelligence + dexterity + agility + vitality)
               + 5 × (wisdom + perception + resolve) + 2 × luck + 25 × skills
powerRatingMax = 100 × level + 1,708          every stat 24, 4 skills
```

```sh
curl 'https://set.world/api/power?stats=16-15-12-11-15-18-12-13-9&skills=2'
```

```ts
type PowerResponse = { level: number; skills: number; stats: StatBlock; powerRating: number; powerRatingMax: number };
```

```json
{
  "level": 1,
  "skills": 2,
  "stats": { "strength": 16, "dexterity": 15, "intelligence": 12, "wisdom": 11, "agility": 15, "vitality": 18, "perception": 12, "resolve": 13, "luck": 9 },
  "powerRating": 1108,
  "powerRatingMax": 1808
}
```

`level` defaults to 1 and `skills` to 0 (0 to 4). `level` is your number; Set never interprets it. Equal ratings do not mean equal strength in a fight.

## Trait impacts

An advantage or disadvantage is only a name. Its effect is a pinned hash of that name, so every consumer computes the same impact, and any string has one.

```text
h         = FNV-1a 32-bit (offset 0x811c9dc5, prime 0x01000193) over the UTF-8 bytes of the name in Unicode NFC
STATS     = [strength, dexterity, intelligence, wisdom, agility, vitality, perception, resolve, luck]
primary   = STATS[(h & 0xff) % 9]
b         = ((h >>> 8) & 0xff) % 100;   tier = b < 60 → 1, b < 85 → 2, b < 97 → 3, else 4
secondary = STATS[((h >>> 16) & 0xff) % 9], advanced by one on collision with the primary      tier 2 and above
```

| Tier | Advantage (primary / secondary) | Disadvantage (primary / secondary) |
| --- | --- | --- |
| 1 | +5% / none | −8% / none |
| 2 | +10% / +5% | −15% / −8% |
| 3 | +15% / +10% | −22% / −15% |
| 4 | +25% / +15% | −35% / −20% |

All of a character's deltas add per stat, then:

```text
modifiedStat = clamp(8, 24, round(base × (1 + Σ deltas)))
```

```sh
curl 'https://set.world/api/traits/impact?name=unyielding%20in%20the%20face%20of%20adversity&kind=advantage'
curl 'https://set.world/api/traits/impacts?kind=advantage'
```

```ts
type TraitImpact = {
  name: string;
  kind: 'advantage' | 'disadvantage';
  tier: 1 | 2 | 3 | 4;
  primary: StatName;
  primaryDelta: number;            // a signed fraction: 0.1 is +10%
  secondary?: StatName;            // tier 2 and above
  secondaryDelta?: number;
};
type TraitImpactsResponse = { kind: 'advantage' | 'disadvantage'; impacts: TraitImpact[] };
```

```json
{ "name": "unyielding in the face of adversity", "kind": "advantage", "tier": 2, "primary": "dexterity", "primaryDelta": 0.1, "secondary": "resolve", "secondaryDelta": 0.05 }
```

The tables of names are in [Advantages](https://set.world/skills/character-advantages) and [Disadvantages](https://set.world/skills/character-disadvantages).

## Rarity score

```text
P(item) = P(quality) × P(prefix) × P(slot) × P(material | slot) × P(gear | slot) × P(suffix)
score   = −log10 P(item)                          4 ≈ 1 in 10,000; 7 ≈ 1 in 10,000,000
```

Each probability is `weight / totalWeight` from the item tables. The grade is separate: it comes from the material alone ([Materials](https://set.world/skills/item-materials)).

```sh
curl 'https://set.world/api/rarity?rolls=119899-493-0-430998-9100-0-0-0-52-0-0-0-0-0-0-0-0-0-1108'
```

```ts
type RarityResponse = {
  indexes: number[];
  score: number;
  probability: number;             // 10^(−score)
  materialRank: number;
  tier: number;
  tierGrade: Grade;
  tierName: string;
  orbValue: number;
  material: Material;
  breakdown: Array<{ slot: 'quality' | 'prefix' | 'material' | 'slot' | 'gear' | 'suffix'; name: string; p: number; contribution: number }>;   // largest first
};
```

```json
{
  "indexes": [5, 5, 0, 10, 3, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
  "score": 10.7359,
  "probability": 1.8368537066135063e-11,
  "materialRank": 9,
  "tier": 4,
  "tierGrade": "C",
  "tierName": "Grade C",
  "orbValue": 125,
  "material": { "name": "steel", "materialRank": 9, "tier": 4, "tierGrade": "C", "tierName": "Grade C" },
  "breakdown": [
    { "slot": "suffix", "name": "dawn", "p": 0.0007733952049497294, "contribution": 3.111598524880394 },
    { "slot": "prefix", "name": "burning", "p": 0.0015337423312883436, "contribution": 2.81424759573192 },
    { "slot": "gear", "name": "sword", "p": 0.006896551724137931, "contribution": 2.161368002234975 },
    { "slot": "material", "name": "steel", "p": 0.06333189828470179, "contribution": 1.1983774944104577 },
    { "slot": "slot", "name": "tool", "p": 0.17926565874730022, "contribution": 0.7465028986418792 },
    { "slot": "quality", "name": "fine", "p": 0.19777394880915988, "contribution": 0.7038309151328761 }
  ]
}
```

`/api/rarity/tiers` returns the seven grade definitions: `{ tiers: [{ tier, grade, name, share }], note, rules, gradeRanges: { tools: 23, wearables: 31 } }`.

## Item power budget and themes

Items never ship resolved modifiers. Set grades a budget and names a theme; what a point buys is your game's tuning.

```text
budget(tier)  = 0 for F, else 2^(tier − 2)         F 0, E 1, D 2, C 4, B 8, A 16, S 32
channel(word) = CHANNELS[fnv1a32(word) % 31]       one per name factor; "-" is skipped
CHANNELS      = the 23 attributes in the order above, then fire, frost, lightning, poison, shadow, holy, arcane, nature
```

```sh
curl 'https://set.world/api/modifiers?rolls=119899-493-0-430998-9100-0-0-0-52-0-0-0-0-0-0-0-0-0-1108'
```

```ts
type ModifiersResponse = {
  indexes: number[];
  score: number;
  materialRank: number;
  tier: number;
  tierGrade: Grade;
  tierName: string;
  orbValue: number;
  material: Material;
  budget: number;
  themes: Array<{ factor: 'quality' | 'prefix' | 'material' | 'gear' | 'suffix'; name: string; channel: string }>;
};
```

```json
{
  "indexes": [5, 5, 0, 10, 3, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
  "score": 10.7359,
  "materialRank": 9,
  "tier": 4,
  "tierGrade": "C",
  "tierName": "Grade C",
  "orbValue": 125,
  "material": { "name": "steel", "materialRank": 9, "tier": 4, "tierGrade": "C", "tierName": "Grade C" },
  "budget": 4,
  "themes": [
    { "factor": "quality", "name": "fine", "channel": "frost" },
    { "factor": "prefix", "name": "burning", "channel": "magicalDamageReduction" },
    { "factor": "material", "name": "steel", "channel": "carrySpeed" },
    { "factor": "gear", "name": "sword", "channel": "carrySpeed" },
    { "factor": "suffix", "name": "dawn", "channel": "jumpHeight" }
  ]
}
```

A theme comes from the hash, not the word's meaning: `burning` gets the `magicalDamageReduction` channel, whatever the word suggests. `/api/modifiers/spec` returns the budget per grade, the 31 channels and the hash rule: `{ contract, budgets: [{ tier, tierGrade, tierName, budget, craftCost }], budgetRule, channels, elementalChannels, themeDerivation }`.

A hypothetical way to spend a budget in your game:

```ts
type ItemModifier = { channel: string; operation: 'add' | 'multiply'; value: number };
// One point per theme channel, in turn, until the budget is spent. The values are your tuning:
// { channel: 'carrySpeed', operation: 'multiply', value: 1.02 }, { channel: 'frost', operation: 'add', value: 3 }, …
```

## Beyond these

Prices in orbs: [Crafting an item](https://set.world/skills/crafting-an-item). One attack or one window of turn order: [Combat](https://set.world/skills/basic-lightweight-combat), optional and experimental. Weight, protection and real-time combat in Set's own game: [Derived stats](https://set.world/skills/anima-derived-stats) and [Derived combat](https://set.world/skills/anima-derived-combat). Full derivations: [Algorithms](https://set.world/skills/algorithms).
