Use when building or auditing core ARPG systems (Diablo / PoE / Last Epoch style). Covers stat formulas, damage calculation, loot tables, item affixes, character progression, save system shape, inventory mechanics. Each section flags common design pitfalls that ruin late-game balance or save migration. Use when designing a system from scratch, or auditing an existing one before public playtest.
How this skill is triggered — by the user, by Claude, or both
Slash command
/gamedev-toolkit-claude:arpg-systems-checklistThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Action RPGs (Diablo, Path of Exile, Last Epoch, Grim Dawn) share a common core: stats × items × skills × monsters. The math of how they multiply together makes or breaks the genre.
Action RPGs (Diablo, Path of Exile, Last Epoch, Grim Dawn) share a common core: stats × items × skills × monsters. The math of how they multiply together makes or breaks the genre.
This skill is the design + implementation checklist for each system, plus the common pitfalls that surface 6 months in when "endgame doesn't feel right".
The biggest architectural decision in ARPG combat is how multipliers stack. Three common approaches:
| Approach | Formula | Pros | Cons |
|---|---|---|---|
| Additive ("Diablo 2") | dmg * (1 + sum_increases - sum_reductions) | Predictable, easy to balance | Late-game scaling flatlines |
| Multiplicative ("PoE") | dmg * prod(1 + each_mod) | Encourages build diversity | Easy to make broken combos |
| Hybrid (most modern) | Categorize mods into "increased" (additive) and "more" (multiplicative) | Best of both | Players need to understand the difference |
Decision early: write down which approach, document the rule in CLAUDE.md, never deviate.
ARPGs typically have 5-8 damage types (Physical, Fire, Cold, Lightning, Poison, Chaos, etc.). Each needs:
Test grid: 20+ scenarios covering edge cases (immune monster, full conversion, max resistance cap).
// Cap resistance to prevent invincibility builds
const float MAX_RESISTANCE = 0.75f; // 75%
const float MAX_RESISTANCE_OVERCAP_BENEFIT = 0.5f; // overcap helps vs penetration
Without caps, late-game builds reach 100% resistance and become unkillable. With caps, you maintain a damage gradient.
public int CalculateHit(int baseDamage, IRng rng, AttackStats attacker, DefenseStats defender) {
var critChance = attacker.CritChance + defender.CritChanceBonus; // some defenders give crit
var isCrit = rng.Value < critChance;
var critMult = isCrit ? attacker.CritDamage : 1.0f;
return Mathf.RoundToInt(baseDamage * critMult * /* resists, damage mods... */);
}
Document: floor or ceiling for rounding? Affects feel ("Why does my 99 damage hit do 99 sometimes and 100 sometimes?").
Items roll from a pool of affixes weighted by item level + monster level + rarity tier.
[CreateAssetMenu]
public class AffixDefinition : ScriptableObject {
public string Id;
public AffixType Type; // Prefix / Suffix
public AffixCategory Category; // PhysDmg, FireDmg, Life, Resistance, etc.
public int MinItemLevel;
public AffixTier[] Tiers; // each tier: weight, min/max range, label
}
Pitfall: not separating affixes by Prefix/Suffix slots. Result: items can roll 6 damage affixes and nothing else useful. Standard pattern: max 3 prefixes + 3 suffixes per item.
Normal: 1.0 weight (60% of drops)
Magic: 0.5 weight (~25%)
Rare: 0.15 weight (~12%)
Set: 0.01 weight (rare set drops)
Unique: 0.005 weight (very rare)
These weights compound with MagicFind stat and MonsterLevel. Test with 10000 simulated drops and verify the distribution matches design intent.
[CreateAssetMenu]
public class ItemBaseType : ScriptableObject {
public string Id;
public ItemSlot Slot; // Head / Body / Weapon / Ring / etc.
public WeaponClass? WeaponClass;
public int BaseArmor;
public int BaseDamage;
public AffixCategory[] AllowedAffixes; // which affixes CAN roll on this base
}
Allowed affixes per base prevents nonsense like "fire damage on a ring" if your design says rings don't roll weapon affixes.
| Type | Examples | Pros | Cons |
|---|---|---|---|
| Slot-based | Diablo 3, Last Epoch | Simple, no spatial puzzle | Less inventory tension |
| Grid-based | Diablo 2, Path of Exile | Inventory tetris is part of gameplay | UI complex, many edge cases |
If grid-based, every operation (pickup, move, sell, equip) has 4-6 edge cases. Test grid:
public class ItemStack {
public ItemDefinition Definition;
public int Count;
public int MaxStackSize => Definition.MaxStackSize;
public bool CanMergeWith(ItemStack other) =>
Definition == other.Definition
&& Count + other.Count <= MaxStackSize
&& /* affixes match (for non-unique stackables like potions) */;
}
Crafting materials and currencies stack high (~100-1000). Equipment never stacks (each instance has unique rolled affixes).
public class LevelTable {
// Geometric or polynomial?
public static int XpForLevel(int level) => Mathf.RoundToInt(100 * Mathf.Pow(level, 2.2f));
}
Document the curve. Too flat = no late-game grind feel. Too steep = late levels take 10+ hours each.
Common pattern: exponential up to mid-game, polynomial in late-game so each level is roughly equally valuable.
Two approaches:
For solo-dev or small-team: class-locked is usually right. Save shared-graph for projects with 6+ months of dedicated balance work post-launch.
Decide early:
Each has its place. Document it. Players need to know before they invest 20 hours.
[Serializable]
public class SaveDataV3 {
public int SchemaVersion = 3;
public string CharacterName;
public int Level;
public PlayerStatsSave PlayerStats;
public InventorySaveData Inventory;
public WorldSaveData World;
public QuestStateSave Quests;
public AchievementSave Achievements;
public PlayTimeSave PlayTime;
public string GameVersion; // for crash-report correlation
public long SavedAtUnixTime;
}
Every save change bumps SchemaVersion. Migration code lives in SaveSystem.MigrateXToY(...).
For single-player ARPG, save tampering by players is fine in offline mode. But if there's a Steam leaderboard or online-vs-mode, sign saves with a HMAC:
public string Sign(string saveJson, string steamId) {
// HMAC-SHA256(saveJson + steamId, secret)
// Reject loads where signature doesn't match
}
Stops casual editing. Determined cheaters will always win — don't waste time on full anti-cheat for a single-player game.
// Always keep last 3 saves. If current corrupts, fall back.
saves/
├── slot_1_current.save
├── slot_1_backup_1.save
├── slot_1_backup_2.save
└── slot_1_backup_3.save
Players will report "I lost my character." Without backups: it's gone, ticket closed, refund issued. With backups: rollback, ticket closed, retention saved.
| Approach | Examples | Notes |
|---|---|---|
| Static zones (level X) | Diablo 1-3 | Players can outlevel zones; trivializes content |
| Player-scaled | Diablo 3 endgame, Last Epoch | Always challenging; harder to balance feel |
| Hybrid (zone tier + player level) | Diablo 4, PoE maps | Zone has min level, monsters scale up to player |
Hybrid is the modern default. Pick early.
Rare monsters in ARPGs roll 1-3 dangerous affixes (Fire Enchanted, Vampiric, Mortar). Player notices these as "elite mob with name". Pool of affixes balanced by danger level — each affix should change how the player engages (run/dodge/burst/los).
ARPG SYSTEMS AUDIT
==================
[Done/Partial/Missing] Damage formula documented & tested
[Done/Partial/Missing] Damage type matrix (5+ types, resists with caps)
[Done/Partial/Missing] Crit formula + rounding policy documented
[Done/Partial/Missing] Affix tier table + prefix/suffix slots
[Done/Partial/Missing] Rarity weights tested with 10k drops
[Done/Partial/Missing] Item base type → allowed affixes map
[Done/Partial/Missing] Inventory operations: 6 edge cases tested
[Done/Partial/Missing] XP curve documented
[Done/Partial/Missing] Skill tree shape (class-locked or shared) chosen
[Done/Partial/Missing] Respec policy documented & implemented
[Done/Partial/Missing] Save format versioned + migration tested
[Done/Partial/Missing] Save backup rotation (3 slots)
[Done/Partial/Missing] Difficulty scaling approach chosen
[Done/Partial/Missing] Monster affix pool exists
GAPS TO ADDRESS BEFORE PUBLIC PLAYTEST: <list>
npx claudepluginhub marcin-elj/gamedev-toolkit-claude --plugin gamedev-toolkit-claudeGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.