View Format: Multi-Page Single Page

Simple Skill Forge

Generate Complete Skill Databases, Skill Trees, Loadouts, and Combos in Minutes.

Overview

The Skill Set Forge generates skill set databases — loadout templates that group skills into typed slots with threshold-based set bonuses that activate when enough skills from the set are equipped. Think item set bonuses from Diablo or gear sets from MMOs, but applied to skills.

Generated databases implement ISimpleSkillSetDataSource and produce the standard 4-file output with the suffix Set (e.g., ARPGSetType.cs, ARPGSetDatabase.cs).

Open the Skill Set Forge wizard from the Unity menu:

Window > Living Failure > Simple Skill Forge > Skill Set Forge

Key features:

  • Typed slots with required/optional designation
  • Skill code references from linked Skill Forge databases
  • Threshold-based set bonuses (e.g., "Equip 3/5 for bonus")
  • SAF modifier assets on bonuses
  • Single-level dynamic properties on each set
  • Runtime manager with equip/unequip, bonus tracking, and snapshots
  • Character class restrictions via SAF Character Templates

The 5-Step Wizard

The Skill Set Forge follows the same 5-step wizard pattern as all forges.

Step 1: Setup

Configure the database name, namespace, class prefix, and template. Link Skill Forge database assets for searchable skill code dropdowns in Step 3. Link SAF Character Template assets for class restriction support. Supports multiple linked databases with duplicate detection.

Step 2: Definitions

Define single-level dynamic properties for your sets (e.g., "Set Type", "Max Slots", "Is Starter Set"). JSON schema export/import is available for AI-assisted content generation with context-aware usage hints.

Step 3: Builder

Split-panel editor (280px left panel). The right panel shows foldout sections for:

  • Identity — code, display name, description, icon
  • Categories / Flags / Numerics / Texts — single-level properties
  • Slots — ReorderableList with 3 fields per slot (slotType, skillCode, isRequired)
  • Bonuses — ReorderableList with threshold count, description, and SAF modifier assets
  • Character Class Restrictions — allowed character classes

Step 4: Settings

Output paths, custom paths toggle, generation toggles, and file preview.

Step 5: Generate

Two-phase generation producing {Prefix}SetType.cs, {Prefix}SetDatabase.cs, {Prefix}SetDatabaseEditor.cs, and the .asset file with all slot, bonus, and modifier data baked in.

Slots

Each set contains an array of SimpleSkillSetSlot structs. A slot defines a position in the loadout with a type label, an assigned skill code, and a required flag.

Field Type Description
slotType string Slot type label (e.g., "Active1", "Active2", "Passive1", "Ultimate"). Used for categorizing and filtering slots. Free-form string — your game defines the slot type conventions.
skillCode string Skill code referencing a Skill Forge database entry. In the wizard, this is presented as a searchable dropdown when skill databases are linked.
isRequired bool Whether this slot must be filled for the set to be considered valid. Optional slots can be left empty at runtime.

Querying Slots

// Get all slots for a set SimpleSkillSetSlot[] slots = database.GetSlotsForSet("WARRIOR_KIT"); // Convenience accessors on the set struct int totalSlots = set.SlotCount; int requiredSlots = set.RequiredSlotCount; // Get all unique slot types string[] types = set.GetSlotTypes(); // e.g., ["Active", "Passive", "Ultimate"] // Get slots of a specific type SimpleSkillSetSlot[] activeSlots = set.GetSlotsByType("Active"); // Check if the set contains a specific skill bool hasSlash = set.ContainsSkill("SLASH"); // Get all skill codes in the set (non-empty) string[] skillCodes = set.GetSkillCodes(); // Find all sets containing a skill SimpleSkillSetDefinition[] setsWithSlash = database.FindSetsContainingSkill("SLASH");

Bonuses

Each set can have multiple SimpleSkillSetBonus entries that activate when enough skills from the set are equipped. This follows the same threshold pattern as item set bonuses.

Field Type Description
requiredCount int Number of equipped skills from this set required to activate the bonus
bonusDescription string Human-readable description of the bonus effect (e.g., "+20% fire damage")
modifiers[] ScriptableObject[] SAF modifier assets applied when this bonus is active. Requires Simple Attribute Forge to be installed for the modifier assets — the field still exists without SAF, but modifiers will be empty.

Querying Bonuses

// Get all bonuses for a set SimpleSkillSetBonus[] bonuses = database.GetBonusesForSet("FIRE_MAGE_KIT"); // Convenience accessors on the set struct int bonusCount = set.BonusCount; // Get the highest-tier bonus that is active for a given equipped count SimpleSkillSetBonus? best = set.GetBonusForCount(equippedCount: 3); // Get ALL bonuses active at a given count (stacking) SimpleSkillSetBonus[] active = set.GetActiveBonuses(equippedCount: 3);

Example: Tiered Bonuses

A set with 5 slots might define bonuses like this:

Required Count Bonus Description
2 +10% fire damage
3 +20% fire damage, fire skills cost 15% less mana
5 +50% fire damage, all fire skills gain area of effect

With 3 skills equipped, both the "2-piece" and "3-piece" bonuses are active. GetActiveBonuses(3) returns both.

Single-Level Properties

Skill sets use single-level dynamic properties on the set definition itself.

// Access set-level properties int setType = set.GetCategoryValue(0); bool isStarterSet = set.GetFlagValue(0); float maxSlots = set.GetNumericValue(0); string flavor = set.GetTextValue(0); // Get property definition labels string[] catLabels = database.GetCategoryLabels(); // e.g., ["Set Type", "Class Association"] string[] catEntries = database.GetCategoryEntries(0); // e.g., ["Class", "Build", "Loadout"] string[] flagNames = database.GetFlagNames(); // e.g., ["Is Starter Set", "Allows Custom Slots"] string[] numNames = database.GetNumericNames(); // e.g., ["Max Slots", "Difficulty Rating"] string[] textNames = database.GetTextNames(); // e.g., ["Set Description", "Flavor Text"] // Filter sets by property values SimpleSkillSetDefinition[] classSets = database.GetSetsByCategory(0, 0); SimpleSkillSetDefinition[] starterSets = database.GetSetsByFlag(0, true); SimpleSkillSetDefinition[] bigSets = database.GetSetsByNumericRange(0, 4f, 10f);

Runtime: SimpleSkillBarManager

SimpleSkillBarManager is a runtime manager that handles equipping/unequipping skills to set slots, tracks threshold-based set bonuses, fires events on changes, and supports serializable snapshots for save/load.

Setup

// Create a manager from your set database var manager = new SimpleSkillBarManager(setDatabase); // Initialize sets for tracking (must be called before equip/query) manager.InitializeSet("WARRIOR_KIT"); manager.InitializeSet("FIRE_MAGE_KIT");

Equip and Unequip

// Equip a skill to a specific slot index manager.EquipSkill("WARRIOR_KIT", slotIndex: 0, "SLASH"); manager.EquipSkill("WARRIOR_KIT", slotIndex: 1, "SHIELD_BASH"); manager.EquipSkill("WARRIOR_KIT", slotIndex: 2, "CHARGE"); // Unequip a specific slot manager.UnequipSkill("WARRIOR_KIT", slotIndex: 1); // Clear all slots in a set int cleared = manager.ClearLoadout("WARRIOR_KIT");
Auto-swap: If you equip a skill to a slot that already has a skill, the previous skill is automatically unequipped first. Both OnSkillUnequipped and OnSkillEquipped events fire.

Queries

// Get what is equipped in a specific slot string skill = manager.GetEquippedSkill("WARRIOR_KIT", slotIndex: 0); // "SLASH" // Get the number of filled slots int equipped = manager.GetEquippedCount("WARRIOR_KIT"); // Check if all required slots are filled bool valid = manager.AreRequiredSlotsFilled("WARRIOR_KIT"); // Get currently active bonuses SimpleSkillSetBonus[] bonuses = manager.GetActiveBonuses("WARRIOR_KIT"); // Check if a specific bonus (by index) is active bool has3Piece = manager.IsBonusActive("WARRIOR_KIT", bonusIndex: 1); // Check if a skill is equipped in ANY initialized set bool equipped = manager.IsSkillEquipped("SLASH"); // Get all equipped skill codes across all sets string[] allEquipped = manager.GetAllEquippedSkillCodes(); // Find which set and slot a skill is in string setCode; int slotIndex; if (manager.FindEquippedSkill("SLASH", out setCode, out slotIndex)) Debug.Log($"SLASH is in {setCode}, slot {slotIndex}");

Events

manager.OnSkillEquipped += (setCode, slotIndex, skillCode) => Debug.Log($"Equipped {skillCode} to {setCode} slot {slotIndex}"); manager.OnSkillUnequipped += (setCode, slotIndex, previousSkillCode) => Debug.Log($"Unequipped {previousSkillCode} from {setCode} slot {slotIndex}"); manager.OnSetBonusActivated += (setCode, bonusIndex) => Debug.Log($"Bonus {bonusIndex} activated in {setCode}"); manager.OnSetBonusDeactivated += (setCode, bonusIndex) => Debug.Log($"Bonus {bonusIndex} deactivated in {setCode}"); manager.OnLoadoutChanged += (setCode) => Debug.Log($"Loadout changed in {setCode}");

Snapshots (Save/Load)

// Save current state SimpleSkillBarSnapshot snapshot = manager.CreateSnapshot(); string json = JsonUtility.ToJson(snapshot); // Load state var loaded = JsonUtility.FromJson<SimpleSkillBarSnapshot>(json); manager.RestoreFromSnapshot(loaded);