View Format: Multi-Page Single Page

Simple Skill Forge

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

Complete Documentation — All pages in a single file for offline reading and printing.

Build Your Skill System

Stop hand-coding skill databases and writing boilerplate ScriptableObject editors. Simple Skill Forge gives you 4 interconnected wizard tools that generate production-ready databases with custom editors, type-safe enums, runtime trackers, and AI-assisted content generation — all from a guided, step-by-step interface inside the Unity Editor.

Whether you are building an ARPG with hundreds of hand-crafted abilities, a MOBA with precise skill loadouts, or a soulslike with deep talent trees, Simple Skill Forge handles the infrastructure so you can focus on game design.

Why Simple Skill Forge?

Complete Package

All 4 forges, all runtime components, all 6 genre templates, and full documentation included. No hidden tiers, no premium upgrades, no paywalls. One purchase, everything included.

Two-Level Properties

The Skill Forge defines dynamic properties at both skill-level AND rank-level. Define Categories, Flags, Numerics, and Texts independently for skills and their individual ranks — giving you unmatched flexibility without touching code.

AI-First Design

Schema export in 3 formats (Full JSON, Light JSON, Markdown) with embedded AI instructions for bulk content generation. Export your schema, hand it to ChatGPT or Claude, and import hundreds of skills back into your database in seconds.

Deep Cross-Forge Integration

12 cross-forge reference fields connect skills to items (weapon requirements, reagent costs, crafted items), enemies (summons, trainers, faction effectiveness), quests (unlock conditions, rewards), and attributes (modifiers, class restrictions). All via safe reflection — zero hard dependencies.

Zero Dependencies

Works standalone out of the box. Optional companion integrations with Simple Attribute Forge, Simple Item Forge, Simple Enemy Forge, and Simple Quest Forge are detected and enabled automatically when installed.

6 Genre Templates

Start with pre-built property schemas for ARPG, MOBA, MMO, Turn-Based, Action, or Roguelike games. Each template provides genre-appropriate Categories, Flags, Numerics, and Texts — customize them freely or start from scratch.

The Four Forges

Skill Forge

The main forge. Define skills with two-level dynamic properties (skill-level + rank-level), multi-rank progression with upgrade costs, prerequisites, SAF modifier assets, and 12 cross-forge reference fields for items, enemies, quests, and factions.

Skill Forge Documentation →

Skill Tree Forge

Build talent trees with grid-based node layouts, parent-child connections, branch groups, point costs, level requirements, and single-level dynamic properties. Nodes reference skills from any Skill Forge database.

Skill Tree Documentation →

Skill Set Forge

Create loadout templates with typed slots, skill assignments, and threshold-based set bonuses (equip 3/5 for bonus effects). Supports SAF modifier assets on bonuses. Single-level properties.

Skill Set Documentation →

Skill Combo Forge

Define skill sequences with ordered steps (required/optional), alternate skill choices, timing windows, branch groups, and threshold rewards with modifier effects. Single-level properties.

Skill Combo Documentation →

Utility Windows

Database Export

Export any generated database as clean JSON with resolved property names. Supports all 4 database types. Ideal for AI workflows, data sharing, and backups.

Window > Living Failure > Simple Skill Forge > Export Database

Batch Icon Assignment

Scan a sprite folder and auto-match sprites to skill/tree/set/combo codes by normalized filename. Preview matches, manually override, and apply in one click.

Window > Living Failure > Simple Skill Forge > Batch Icon Assignment

What Gets Generated

Each forge generates 4 files per database:

File Description
{Prefix}Type.cs Type-safe enum of all entry codes (e.g., ARPGSkillsType.FIREBALL)
{Prefix}Database.cs ScriptableObject class implementing the forge's interface (e.g., ISimpleSkillDataSource)
{Prefix}DatabaseEditor.cs Custom inspector that mirrors the wizard's builder UI with search, sort, filter, and pagination
{Prefix}Database.asset The actual ScriptableObject instance with all your data baked in

Runtime Components

SimpleSkillHelper

Static utility class for prerequisite checking, cross-reference queries, skill lookups by item/enemy/quest code, and resource affordability checks.

SimpleSkillTreeTracker

Runtime state tracker for skill tree node unlocks. Tracks points spent, validates unlock requirements, supports cascade reset, and provides event callbacks and serializable snapshots.

SimpleSkillBarManager

Runtime manager for skill set loadouts. Handles equip/unequip to typed slots, tracks threshold-based set bonuses, and provides events and snapshots.

SimpleSkillComboTracker

Runtime tracker for active skill combos with timing windows. Tracks combo progress across all defined combos simultaneously, fires events on progression/completion/drops, and awards threshold rewards.

Plus SimpleSkillComboEvaluator — a static utility for evaluating combo progress, getting next valid skills, and checking timing windows without instantiating a tracker.

Getting Started

1 Install — Import from the Unity Asset Store or add via UPM. See Installation for details.
2 Open a ForgeWindow > Living Failure > Simple Skill Forge > Skill Forge (or Tree/Set/Combo Forge).
3 Choose a Template — Select a genre template (ARPG, MOBA, MMO, etc.) to pre-populate property definitions, or start with None for a blank slate.
4 Define Properties — Customize your Categories, Flags, Numerics, and Texts at both skill-level and rank-level (Skill Forge only — other forges use single-level).
5 Build Entries — Add skills, trees, sets, or combos using the split-panel builder with search, sort, filter, and pagination.
6 Generate — Click Generate to produce your enum, database, custom editor, and ScriptableObject asset. Assign the asset to your game systems.

See Quick Start for a complete walkthrough.

Interconnected Ecosystem

Simple Skill Forge is part of the Simple Forge Ecosystem — a family of Unity tools that work independently but become more powerful together:

Package What It Does How It Connects to SSF
Simple Attribute Forge Character stats, modifiers, and class templates Modifier assets on skills/ranks/bonuses, attribute prerequisites, character class restrictions
Simple Item Forge Items, loot tables, crafting, shops, item sets Skill books, weapon requirements, reagent costs, produced items
Simple Enemy Forge Enemies, factions, squads, spawns, waves Summon skills, NPC trainers, learned-from enemies, faction effectiveness
Simple Quest Forge Quests, quest chains, procedural quests Quest-gated skill unlocks, quest-rewarded skills

All integrations use safe reflection — no hard dependencies, no compile errors if companion packages are not installed. Install them when you need them.

See Integration for details on each cross-forge connection.

Package Manager (UPM)

The recommended way to install Simple Skill Forge is through Unity's Package Manager using a Git URL. This approach makes updates easy and keeps the package outside your Assets folder.

Option A — Git URL

1 Open Window > Package Manager in the Unity Editor.
2 Click the + button in the top-left corner and select Add package from git URL...
3 Enter the repository URL:
https://github.com/LivingFailure/com.livingfailure.simple-skill-forge.git
4 Click Add. Unity will download and import the package automatically.

Option B — manifest.json

You can also add the package directly to your project's Packages/manifest.json file:

{ "dependencies": { "com.livingfailure.simple-skill-forge": "https://github.com/LivingFailure/com.livingfailure.simple-skill-forge.git", ... } }

Save the file and return to Unity. The package will be resolved automatically.

Tip: To lock to a specific version, append #v1.0.0 (or any tag/branch) to the Git URL.

Asset Store

Simple Skill Forge is available on the Unity Asset Store.

1 Open the Unity Asset Store in your browser or the Unity Editor (Window > Asset Store).
2 Search for "Simple Skill Forge" by Living Failure.
3 Click Add to My Assets, then open Window > Package Manager, switch to My Assets, find Simple Skill Forge, and click Import.
4 In the Import dialog, ensure all files are selected and click Import.

The package will be placed under Assets/SimpleSkillForge/.

Manual Import

If you received Simple Skill Forge as a .unitypackage file:

1 In Unity, go to Assets > Import Package > Custom Package...
2 Navigate to the .unitypackage file and select it.
3 In the Import dialog, ensure all files are checked and click Import.
Important: Do not move or rename the assembly definition (.asmdef) files after import. They define the SimpleSkillForge.Runtime and SimpleSkillForge.Editor assemblies and must remain in their original locations for compilation to succeed.

Verifying Installation

After installation, verify that everything is working correctly:

1 Check the menu: Open Window > Living Failure > Simple Skill Forge. You should see 4 forge entries: Skill Forge, Skill Tree Forge, Skill Set Forge, and Skill Combo Forge, plus the utility windows.
2 Open a forge: Click Skill Forge. The wizard window should appear with Step 1 (Setup) displayed. If you see the database name field, template dropdown, and linked database sections, the installation is correct.
3 Check the console: Look for any compilation errors in the Unity Console (Window > General > Console). A clean installation produces zero errors.
Success: If all 4 forge windows open without errors, Simple Skill Forge is installed correctly.

If you encounter issues, see Troubleshooting.

Optional Companions

Simple Skill Forge works standalone with zero dependencies. However, it integrates with 4 companion packages from the Simple Forge Ecosystem. When a companion is detected, SSF automatically enables additional features via safe reflection — no configuration required.

Package UPM Name What It Unlocks in SSF
Simple Attribute Forge com.livingfailure.simple-attribute-forge Modifier assets on skills, ranks, and set bonuses. Attribute names for prerequisites. Character class restrictions via Character Template integration.
Simple Item Forge com.livingfailure.simple-item-forge Item-skill relationships: skill books (grantedByItemCode), weapon requirements (requiredEquipmentCode), crafted items (producesItemCode), and reagent costs (reagentCosts[]).
Simple Enemy Forge com.livingfailure.simple-enemy-forge Enemy-skill relationships: summon skills (summonEnemyCode), NPC trainers (taughtByNPCCode), learned-from enemies (learnedFromEnemyCode), faction effectiveness (effectiveAgainstFactions[]), and faction restrictions (restrictedToFactionCode).
Simple Quest Forge com.livingfailure.simple-quest-forge Quest-skill relationships: quest-gated unlocks (unlockedByQuestCode) and quest-rewarded skills (rewardedByQuestCodes[]).

Installing Companions

Install companion packages the same way you installed SSF (UPM, Asset Store, or manual import). Once imported, SSF detects them automatically on the next domain reload. No restart or manual configuration is needed.

Detection Mechanism

SSF uses two detection methods that work together:

  • UPM detection: The .asmdef files contain versionDefines entries that set scripting defines (e.g., SIMPLE_ATTRIBUTE_FORGE, SIMPLE_ITEM_FORGE) when companion packages are present in the Package Manager.
  • Reflection detection: Bridge classes (SAFBridge, SIFBridge, SEFBridge, SQFBridge) probe for companion types at runtime using Type.GetType(). This handles non-UPM installations (Asset Store, manual import).
Note: You can install and remove companions at any time. SSF gracefully disables features when a companion is removed — no compile errors, no data loss. Cross-forge reference fields simply become manual text entry instead of searchable dropdowns.

Assembly Definitions

Simple Skill Forge uses two assembly definitions to keep runtime and editor code properly separated:

Assembly Namespace Contents
SimpleSkillForge.Runtime SimpleSkillForge All runtime types: definitions (skill, tree, set, combo), interfaces (ISimpleSkillDataSource, etc.), helpers, trackers, evaluators, bridges
SimpleSkillForge.Editor SimpleSkillForge.Editor All editor types: wizard windows, wizard steps, wizard data, code generators, templates, schema export, utility windows

Referencing SSF in Your Code

If your project uses assembly definitions, add a reference to SimpleSkillForge.Runtime in your runtime .asmdef to access SSF types:

{ "name": "MyGame.Runtime", "references": [ "SimpleSkillForge.Runtime" ] }

For editor scripts that need SSF editor types, reference both assemblies:

{ "name": "MyGame.Editor", "references": [ "SimpleSkillForge.Runtime", "SimpleSkillForge.Editor" ] }

Version Defines

The runtime assembly's .asmdef includes versionDefines for all companion packages. When a companion is installed via UPM, Unity automatically sets the corresponding scripting define symbol:

Companion Package Define Symbol
com.livingfailure.simple-attribute-forge SIMPLE_ATTRIBUTE_FORGE
com.livingfailure.simple-item-forge SIMPLE_ITEM_FORGE
com.livingfailure.simple-enemy-forge SIMPLE_ENEMY_FORGE
com.livingfailure.simple-quest-forge SIMPLE_QUEST_FORGE

These defines gate #if blocks in SSF source code so that companion-specific features compile only when the companion is present.

Your First Skill Database

This guide walks you through creating a complete skill database using the Skill Forge — from opening the wizard to using the generated database in your game code. The entire process takes about 5 minutes.

By the end, you will have:

  • A type-safe enum of all your skill codes
  • A ScriptableObject database with a custom inspector
  • Runtime-ready data you can query from any script
Prerequisites: Simple Skill Forge must be installed. See Installation if you have not done this yet. Unity 2021.3 or later is required.

Step 1: Setup

Open the Skill Forge wizard:

Window > Living Failure > Simple Skill Forge > Skill Forge

The wizard opens to Step 1: Setup. Configure these fields:

Database Name

Enter a name for your database, e.g., RPGSkills. This determines the generated class names:

Field Example
Database Name RPGSkills
Generated Enum RPGSkillsType
Generated Database RPGSkillsDatabase
Generated Editor RPGSkillsDatabaseEditor

Namespace

Optionally set a namespace for the generated code. Leave blank if your project does not use namespaces.

Template

Select a genre template to pre-populate property definitions. For this walkthrough, choose ARPG — it provides a solid set of categories (Skill Type, Element, Target Type), flags (Is Passive, Is Ultimate), numerics (Mana Cost, Cooldown, Cast Time), and texts (Tooltip, Lore) at both skill-level and rank-level.

Tip: You can select None to start with a blank slate and define every property yourself. Templates are just a starting point — you can add, remove, or modify any property in Step 2.

Linked Databases

If you have companion packages installed (SAF, SIF, SEF, SQF), you can drag-and-drop their generated database assets here. This enables searchable dropdowns for cross-forge reference fields in Step 3 (e.g., selecting an item code from your SIF database instead of typing it manually).

For this walkthrough, you can skip linked databases. They are entirely optional.

Click Next to proceed to Step 2.

Step 2: Definitions

This is where you define the dynamic property schema for your skills. The Skill Forge uses a two-level property system:

  • Skill-Level Properties — apply to the skill as a whole (e.g., Skill Type, Element, Is Passive)
  • Rank-Level Properties — apply to each individual rank of a skill (e.g., Damage, Mana Cost, Area of Effect)

If you chose the ARPG template, you will see pre-populated definitions at both levels. You can customize them freely.

Property Types

There are 4 types of dynamic properties, available at both skill-level and rank-level:

Type What It Stores Example
Category Selection from a list of named entries Skill Type: [Attack, Buff, Debuff, Heal, Summon]
Flag Boolean (true/false) Is Passive, Is Ultimate, Requires Line of Sight
Numeric Float or integer value (optionally a range) Mana Cost, Cooldown, Cast Time, Base Damage
Text String value (single or multi-line) Tooltip, Lore Text, VFX Path

Adding a Property

To add a new property, expand the relevant section (e.g., Skill-Level Categories) and click the + button at the bottom of the list. Fill in the label/name and any additional settings (entries for categories, constraints for numerics, line count for texts).

Removing or Reordering

Use the - button to remove a property, or drag entries in the ReorderableList to reorder them. All existing skill entries are automatically synced when you add, remove, or reorder definitions.

JSON Schema Export

At the bottom of Step 2, you will find the JSON Schema section. This lets you export your property definitions in 3 formats (Full JSON, Light JSON, Markdown) for AI-assisted bulk content generation. You can also import skills from JSON. See AI Workflow for details.

Click Next to proceed to Step 3.

Step 3: Builder

The builder is a split-panel editor where you create and edit individual skill entries.

Left Panel — Skill List

The left panel shows all your skills in a scrollable list with:

  • Search bar — filter by name or code
  • Category filter — show only skills of a specific type
  • Sort — alphabetical, by code, or by category
  • Pagination — handles large lists efficiently
  • Bulk operations — select multiple skills for delete or duplicate
  • + / - buttons — add or remove skills

Click any skill in the list to select it and edit its details in the right panel.

Right Panel — Skill Editor

The right panel displays all editable fields for the selected skill, organized into foldout sections:

  • Identity — Code (SCREAMING_SNAKE_CASE), display name, description, icon
  • Categories — dropdown selectors for each skill-level category
  • Flags — toggle checkboxes for each skill-level flag
  • Numeric Properties — value fields for each skill-level numeric
  • Text Properties — text fields for each skill-level text
  • Ranks — a list of ranks, each with its own rank-level properties, upgrade costs (resource code + amount), and optional SAF modifier assets
  • Prerequisites — conditions that must be met to learn/use the skill (e.g., "FIREBALL at least rank 3")
  • Skill Modifiers — SAF modifier assets attached to the skill itself (requires Simple Attribute Forge)
  • Cross-Forge References — 12 fields linking to items, enemies, quests, and factions from companion forges

Creating Your First Skill

1 Click the + button in the left panel to add a new skill.
2 In the Identity section, set the Code to FIREBALL and the Display Name to Fireball. Add a description like Hurls a ball of fire at the target.
3 Set category values (e.g., Skill Type: Attack, Element: Fire).
4 Set flag values (e.g., Is Passive: unchecked).
5 Set numeric values (e.g., Mana Cost: 25, Cooldown: 3.0).
6 Expand the Ranks section and add ranks. Each rank has its own rank-level property values (e.g., Rank 1: Damage 50, Rank 2: Damage 80, Rank 3: Damage 120).

Repeat to add more skills. Use Duplicate to clone an existing skill as a starting point.

Click Next to proceed to Step 4.

Step 4: Settings

Configure where and how the database is generated.

Output Path

Set the folder where generated files will be placed. The default is Assets/GeneratedSkillDatabases/. Click Browse to choose a different location.

Custom Paths

Enable Use Custom Paths to specify separate output folders for scripts (.cs files) and assets (.asset files). Useful if you want scripts in a Scripts/ folder and assets in a Data/ folder.

Generation Toggles

  • Generate Enum — produces the {Prefix}Type.cs enum file. Disable if you want to manage skill identifiers differently.
  • Generate Database — produces the {Prefix}Database.cs ScriptableObject and {Prefix}DatabaseEditor.cs custom inspector. Almost always left enabled.

File Preview

The bottom of Step 4 shows a preview of all files that will be generated, including their full paths. Review this before proceeding.

Click Next to proceed to Step 5.

Step 5: Generate

The final step shows a summary of your database and a Generate button.

Summary

Review the summary to confirm everything is correct: database name, number of skills, number of properties, output paths, and enabled generation options.

Generation Process

Click Generate to start the two-phase generation:

1 Phase 1 — Script Generation: The forge writes the .cs files (enum, database class, custom editor) to your output folder. Unity then triggers a domain reload to compile the new scripts.
2 Phase 2 — Asset Creation: After the domain reload completes, the forge automatically creates the .asset ScriptableObject and populates it with all your skill data. A log message confirms completion.
Do not close the wizard window or switch editor focus during generation. The two-phase process relies on an [InitializeOnLoad] handler that runs after the domain reload to complete Phase 2.

Generated Files

After generation completes, you will find these files in your output folder:

Assets/GeneratedSkillDatabases/ RPGSkillsType.cs ← enum: RPGSkillsType.FIREBALL, .ICE_BOLT, etc. RPGSkillsDatabase.cs ← ScriptableObject implementing ISimpleSkillDataSource RPGSkillsDatabaseEditor.cs ← custom inspector with search, sort, filter RPGSkillsDatabase.asset ← your data, ready to assign
Done! Select the .asset file in the Project window and inspect it. The custom editor displays your skills in the same split-panel layout as the wizard's builder.

Using Your Database at Runtime

The generated database implements ISimpleSkillDataSource, giving you a clean API to query skill data from any script.

Assigning the Database

Add a ScriptableObject field to your MonoBehaviour and drag the generated .asset file onto it in the Inspector:

using SimpleSkillForge; using UnityEngine; public class SkillManager : MonoBehaviour { [SerializeField] private ScriptableObject skillDatabase; private ISimpleSkillDataSource _skills; void Awake() { _skills = skillDatabase as ISimpleSkillDataSource; } }

Querying Skills

Use the interface methods to access your data:

// Get all skill definitions SimpleSkillDefinition[] allSkills = _skills.GetSkillDefinitions(); // Look up a skill by code SimpleSkillDefinition? fireball = _skills.GetSkillByCode("FIREBALL"); // Get all skill codes and names string[] codes = _skills.GetSkillCodes(); string[] names = _skills.GetSkillNames(); // Check if a skill exists bool exists = _skills.HasSkill("FIREBALL"); // Get the generated enum type for type-safe lookups Type enumType = _skills.GetSkillEnumType();

Reading Dynamic Properties

Access the dynamic properties you defined in Step 2 using index-based accessors. The index corresponds to the order you defined them (0-based):

SimpleSkillDefinition skill = allSkills[0]; // Skill-level properties int skillType = skill.GetCategoryValue(0); // first category (e.g., Skill Type) bool isPassive = skill.GetFlagValue(0); // first flag (e.g., Is Passive) float manaCost = skill.GetNumericValue(0); // first numeric (e.g., Mana Cost) string tooltip = skill.GetTextValue(0); // first text (e.g., Tooltip) // Rank-level properties (on each rank) SimpleSkillRank rank = skill.ranks[0]; float damage = rank.GetNumericValue(0); // first rank-level numeric (e.g., Damage)

Property Definition Labels

To get human-readable labels for your properties (useful for UI), query the data source:

// Skill-level property labels string[] categoryLabels = _skills.GetCategoryLabels(); // ["Skill Type", "Element", ...] string[] flagNames = _skills.GetFlagNames(); // ["Is Passive", "Is Ultimate", ...] string[] numericNames = _skills.GetNumericNames(); // ["Mana Cost", "Cooldown", ...] string[] textNames = _skills.GetTextNames(); // ["Tooltip", "Lore", ...] // Category entries (options for a specific category) string[] skillTypes = _skills.GetCategoryEntries(0); // ["Attack", "Buff", "Debuff", ...] // Rank-level property labels string[] rankCatLabels = _skills.GetRankCategoryLabels(); string[] rankFlagNames = _skills.GetRankFlagNames(); string[] rankNumericNames = _skills.GetRankNumericNames(); string[] rankTextNames = _skills.GetRankTextNames();

Filtering

Query skills by property values:

// All skills where category 0 (Skill Type) == entry 3 (Heal) SimpleSkillDefinition[] heals = _skills.GetSkillsByCategory(0, 3); // All skills where flag 0 (Is Passive) == true SimpleSkillDefinition[] passives = _skills.GetSkillsByFlag(0, true); // All skills where numeric 1 (Cooldown) is between 0 and 5 SimpleSkillDefinition[] quickSkills = _skills.GetSkillsByNumericRange(1, 0f, 5f); // All skills usable by a specific character class (requires SAF Character Templates) SimpleSkillDefinition[] mageSkills = _skills.GetSkillsUsableByClass("Mage");

Using SimpleSkillHelper

The static helper class provides utility functions without needing a tracker instance:

// Check if a skill's prerequisites are met // The valueProvider function returns the player's current value for each prerequisite code bool canLearn = SimpleSkillHelper.CheckAllPrerequisites( fireball.Value, (code) => GetPlayerSkillRank(code) // your function that returns current rank ); // Find all skills granted by a specific item SimpleSkillDefinition[] bookSkills = SimpleSkillHelper.FindSkillsGrantedByItem( _skills, "TOME_OF_FIRE" ); // Check if the player can afford the upgrade to the next rank bool canAfford = SimpleSkillHelper.CanAffordRankUp( fireball.Value, currentRank, (resourceCode) => GetPlayerResource(resourceCode) // your resource lookup );

Next Steps

You have created your first skill database. Here is where to go from here:

Skill Forge Deep Dive

Learn about all features: rank progression, prerequisites, cross-forge references, and the two-level property system in detail.

Skill Forge Documentation →

Build Skill Trees

Create talent trees with grid-based node layouts that reference your skills. Nodes have point costs, level requirements, and parent-child connections.

Skill Tree Forge →

Create Skill Sets

Design loadout templates with typed slots and threshold-based set bonuses. "Equip 3 fire skills for +20% fire damage."

Skill Set Forge →

Define Combos

Build skill sequences with timing windows and threshold rewards. "Fireball, Ice Bolt, Lightning within 2 seconds = Elemental Burst."

Skill Combo Forge →

AI-Assisted Content

Export your schema to JSON or Markdown, feed it to an AI assistant, and import hundreds of generated skills back into your database.

AI Workflow →

Cross-Forge Integration

Connect to Simple Attribute Forge, Simple Item Forge, Simple Enemy Forge, and Simple Quest Forge for deep cross-system references.

Integration →

Overview

The Skill Forge is the primary forge in Simple Skill Forge. It generates complete skill databases as ScriptableObjects with type-safe enums, custom inspectors, and a runtime interface (ISimpleSkillDataSource) for querying skill data from game code.

What makes the Skill Forge unique among the four forges is its two-level dynamic property system. You define properties at two independent levels:

  • Skill-Level Properties (Level 1) — apply to the skill as a whole. Examples: Skill Type, Element, Is Passive, Mana Cost, Tooltip.
  • Rank-Level Properties (Level 2) — apply to each individual rank within a skill. Examples: Damage, Healing Amount, Area of Effect, Duration.

On top of the two-level property system, each skill supports:

  • Multi-rank progression with per-rank upgrade costs and SAF modifier assets
  • Prerequisites for skill unlock conditions
  • 12 cross-forge reference fields linking skills to items (SIF), enemies (SEF), quests (SQF), and attributes/modifiers (SAF)
  • Character class restrictions via SAF Character Templates

Open the Skill Forge wizard from the Unity menu:

Window > Living Failure > Simple Skill Forge > Skill Forge

The 5-Step Wizard

The Skill Forge follows the standard 5-step wizard pattern shared across all Living Failure forges.

Step 1: Setup

Configure the foundational settings for your skill database:

Field Description
Database Name The name prefix for all generated files (e.g., ARPGSkills generates ARPGSkillsType.cs, ARPGSkillsDatabase.cs, etc.)
Namespace Optional C# namespace for generated code. Leave blank if your project does not use namespaces.
Class Prefix Optional prefix for generated class names. Defaults to the database name.
Template Genre template (ARPG, MOBA, MMO, TurnBased, Action, Roguelike, or None) to pre-populate property definitions at both skill-level and rank-level.
Linked Databases Drag-and-drop ScriptableObject database assets from companion forges (SAF, SIF, SEF, SQF) to enable searchable dropdowns for cross-forge reference fields in Step 3. Also supports SAF Character Template assets for class restrictions.
Template selection: When you choose a template, it populates Step 2 with genre-appropriate property definitions. Selecting None clears all existing definitions (with a confirmation dialog). You can always modify template-provided definitions freely.

Step 2: Definitions

Define the dynamic property schema for your skills. This is where the two-level system comes into play. You define properties separately for:

  • Skill-Level — Categories, Flags, Numerics, and Texts that apply to the skill as a whole
  • Rank-Level — Categories, Flags, Numerics, and Texts that apply to each individual rank

Each property type is managed via a ReorderableList. Add, remove, reorder, and configure properties with full control. All existing skill entries are automatically synced when definitions change.

Step 2 also includes a JSON Schema section for AI-assisted content generation. Export your schema in 3 formats (Full JSON, Light JSON, Markdown) and import skills from JSON. See AI Workflow for details.

Step 3: Builder

The builder is a split-panel editor for creating and editing individual skills.

Left Panel — a scrollable list of all skills with:

  • Search bar (filter by name or code)
  • Category filter dropdown
  • Sort options (alphabetical, by code, by category)
  • Pagination for large lists
  • Bulk select, delete, and duplicate
  • Category type indicator badge ([TypeName])
  • + / - buttons for adding and removing skills

Right Panel — detail editor for the selected skill, organized into foldout sections:

  • Identity — code (SCREAMING_SNAKE_CASE), display name, description, icon (Sprite)
  • Categories — dropdown selectors for each skill-level category
  • Flags — toggle checkboxes for each skill-level flag
  • Numeric Properties — value fields for each skill-level numeric
  • Text Properties — text fields for each skill-level text
  • Ranks — nested rank entries, each with rank-level properties, upgrade costs, and modifier assets
  • Prerequisites — unlock conditions (targetCode + comparison + value)
  • Skill Modifiers — SAF modifier assets on the skill itself
  • Cross-Forge References — 12 fields organized by companion forge
  • Character Class Restrictions — allowed character classes

Step 4: Settings

Configure output paths and generation toggles:

  • Output Path — folder for generated files (default: Assets/GeneratedSkillDatabases/)
  • Use Custom Paths — separate folders for scripts and assets
  • Generate Enum — toggle {Prefix}Type.cs generation
  • Generate Database — toggle database and editor generation
  • File Preview — shows all files that will be created

Step 5: Generate

Review the summary and click Generate to produce your database. The generation uses a two-phase process:

1 Phase 1 — Script Generation: Writes .cs files (enum, database class, custom editor). Unity triggers a domain reload to compile the new scripts.
2 Phase 2 — Asset Creation: After the domain reload, an [InitializeOnLoad] handler creates the .asset ScriptableObject and populates it with all your skill data. GUID-based persistence ensures ScriptableObject references survive the reload.
Do not close the wizard window or switch editor focus during generation. The two-phase process requires the [InitializeOnLoad] handler to run after the domain reload to complete Phase 2.

Property Types

Both skill-level and rank-level support 4 types of dynamic properties:

Categories

A selection from a named list of entries. Each category has a label and a list of string entries.

// Definition CategoryDefinition { string label; // e.g., "Skill Type" List<string> entries; // e.g., ["Attack", "Buff", "Debuff", "Heal", "Summon"] int defaultIndex; // default selection } // Access on a skill int skillTypeIndex = skill.GetCategoryValue(0); // Get the human-readable entry name string[] entries = database.GetCategoryEntries(0); // skill-level string skillTypeName = entries[skillTypeIndex]; // "Attack" // Rank-level categories string[] rankEntries = database.GetRankCategoryEntries(0); int rankCatValue = rank.GetCategoryValue(0);

Flags

Boolean properties. Each flag has a name and a default value.

// Access bool isPassive = skill.GetFlagValue(0); // Get the flag name string[] flagNames = database.GetFlagNames(); // skill-level string[] rankFlagNames = database.GetRankFlagNames(); // rank-level

Numerics

Float or integer values with optional min/max constraints.

// Access float manaCost = skill.GetNumericValue(0); // Get the numeric name string[] numericNames = database.GetNumericNames(); // skill-level string[] rankNumNames = database.GetRankNumericNames(); // rank-level // Rank-level numerics (values that change per rank) float damage = rank.GetNumericValue(0); // e.g., Rank 1: 50, Rank 2: 80

Texts

String values. Each text property has a name and a line count (1 = single line, >1 = multi-line TextArea).

// Access string tooltip = skill.GetTextValue(0); // Get the text name string[] textNames = database.GetTextNames(); // skill-level string[] rankTextNames = database.GetRankTextNames(); // rank-level

Filtering by Properties

The database interface provides filtering methods for all property types:

// All skills where category 0 == entry index 2 SimpleSkillDefinition[] debuffs = database.GetSkillsByCategory(0, 2); // All skills where flag 0 (Is Passive) == true SimpleSkillDefinition[] passives = database.GetSkillsByFlag(0, true); // All skills where numeric 1 (Cooldown) is between 0 and 5 SimpleSkillDefinition[] quickSkills = database.GetSkillsByNumericRange(1, 0f, 5f);

Ranks and Upgrade Costs

Each skill can have multiple ranks representing progression levels. Ranks are stored as SimpleSkillRank[] on the skill definition. Each rank has:

Field Type Description
rank int Rank number (starts at 1, not 0)
categoryValues int[] Rank-level category values
flagValues bool[] Rank-level flag values
numericValues float[] Rank-level numeric values (damage, healing, etc.)
textValues string[] Rank-level text values
upgradeCosts SimpleSkillUpgradeCost[] Resources required to reach this rank
modifiers ScriptableObject[] SAF modifier assets gained at this rank

Upgrade Costs

Each rank can have multiple upgrade costs. An upgrade cost pairs a resource code with an amount:

SimpleSkillUpgradeCost { string resourceCode; // e.g., "GOLD", "SKILL_POINT", "DRAGON_SCALE" float amount; // e.g., 500 }

The resourceCode is a free-form string. It can reference an item code from SIF, an attribute code from SAF, or any custom identifier your game uses. The forge does not validate the code — your game logic interprets it.

Querying Ranks

// Get all ranks for a skill SimpleSkillRank[] ranks = database.GetRanksForSkill("FIREBALL"); // Get max rank number int maxRank = database.GetMaxRank("FIREBALL"); // Get a specific rank from the skill struct SimpleSkillRank? rank2 = skill.GetRank(2); if (rank2.HasValue) { float damage = rank2.Value.GetNumericValue(0); SimpleSkillUpgradeCost[] costs = rank2.Value.upgradeCosts; } // Get the max rank from the skill struct int max = skill.GetMaxRank();

Reagent Costs vs. Upgrade Costs

Important distinction: SimpleSkillUpgradeCost (on each rank) represents the cost to level up a skill to that rank. SimpleSkillReagentCost (on the skill definition) represents items consumed each time the skill is cast. They are different systems.

Prerequisites

Skills can have prerequisites — conditions that must be met before the skill can be learned or used. Each prerequisite is a SimpleSkillPrerequisite:

SimpleSkillPrerequisite { string targetCode; // e.g., "FIREBALL", "PLAYER_LEVEL" SimpleSkillComparison comparison; // Equals, NotEquals, GreaterThan, LessThan, // GreaterOrEqual, LessOrEqual float value; // e.g., 3.0 (meaning "rank 3") }

Prerequisites are evaluated using a Func<string, float> value provider — a function you supply that returns the current value for any target code. This keeps the system completely game-agnostic:

// Check if prerequisites are met bool canLearn = SimpleSkillHelper.CheckAllPrerequisites( skill, (code) => { // Return current rank for skill codes if (playerSkillRanks.ContainsKey(code)) return playerSkillRanks[code]; // Return player level for "PLAYER_LEVEL" if (code == "PLAYER_LEVEL") return playerLevel; return 0f; } ); // Query skills with a specific prerequisite SimpleSkillDefinition[] advancedFire = database.GetSkillsWithPrerequisite("FIREBALL");

Common prerequisite patterns:

  • FIREBALL GreaterOrEqual 3 — "Fireball must be at least rank 3"
  • PLAYER_LEVEL GreaterOrEqual 10 — "Character level 10 required"
  • ICE_BOLT Equals 0 — "Must not have learned Ice Bolt" (mutual exclusion)

Cross-Forge References

Each skill has 12 cross-forge reference fields that link skills to data from companion forges. All references are stored as string codes (no hard dependencies). The companion forge does not need to be installed for the data to be stored — it is just strings.

SIF (Simple Item Forge) — 4 Fields

Field Type Description Use Cases
grantedByItemCode string Item that teaches/grants this skill Skill books, scrolls, equipment passives, gem sockets
requiredEquipmentCode string Item that must be equipped to use this skill Bow for arrow skills, staff for magic, specific weapon types
producesItemCode string Item created when the skill is used Conjure food, crafting skills, transmutation, gathering yields
reagentCosts[] SimpleSkillReagentCost[] Items consumed per cast Arrows, soul shards, catalysts, reagents

SEF (Simple Enemy Forge) — 5 Fields

Field Type Description Use Cases
summonEnemyCode string Enemy summoned by this skill Necromancer minions, pet classes, conjured creatures
learnedFromEnemyCode string Enemy that teaches this skill Blue Mage / FF, Enemy Skill materia, monster absorption
taughtByNPCCode string NPC trainer that teaches this skill Class trainers, skill masters, weapon trainers, move tutors
effectiveAgainstFactions[] string[] Factions this skill is strong against Holy vs Undead, Dragon Slayer vs Dragon, type advantages
restrictedToFactionCode string Only characters of this faction can use the skill Racial abilities, covenant skills, guild techniques

SQF (Simple Quest Forge) — 2 Fields

Field Type Description Use Cases
unlockedByQuestCode string Quest that must be completed to learn this skill Class quests, weapon art quests, mastery trials
rewardedByQuestCodes[] string[] Quests that award this skill as a reward Reverse lookup for UI: "Learned from: The Archmage's Trial"

SAF (Simple Attribute Forge) — 1 Field

Field Type Description Use Cases
modifiers[] ScriptableObject[] SAF modifier assets attached to the skill itself Passive effects, auras, stat modifications

Additionally, each rank has its own modifiers[] array for effects gained at specific ranks.

Convenience Accessors

The SimpleSkillDefinition struct provides boolean convenience properties for checking whether cross-forge references are set:

skill.IsItemGranted // grantedByItemCode is set skill.HasEquipmentRequirement // requiredEquipmentCode is set skill.ProducesItem // producesItemCode is set skill.HasReagentCosts // reagentCosts is non-empty skill.IsSummonSkill // summonEnemyCode is set skill.IsEnemyLearned // learnedFromEnemyCode is set skill.HasTrainer // taughtByNPCCode is set skill.HasFactionEffectiveness // effectiveAgainstFactions is non-empty skill.IsFactionRestricted // restrictedToFactionCode is set skill.IsQuestUnlocked // unlockedByQuestCode is set skill.IsQuestRewarded // rewardedByQuestCodes is non-empty skill.HasClassRestriction // allowedCharacterClasses is non-empty

Cross-Forge Queries

The ISimpleSkillDataSource interface provides reverse-lookup queries for all cross-forge fields:

// SIF queries database.GetSkillsGrantedByItem("TOME_OF_FIRE"); database.GetSkillsRequiringEquipment("IRON_BOW"); database.GetSkillsProducingItem("CONJURED_BREAD"); database.GetSkillsConsumingReagent("SOUL_SHARD"); // SEF queries database.GetSkillsSummoningEnemy("SKELETON_WARRIOR"); database.GetSkillsLearnedFromEnemy("BLUE_DRAGON"); database.GetSkillsTaughtByNPC("ARCHMAGE_THERON"); database.GetSkillsEffectiveAgainstFaction("UNDEAD"); database.GetSkillsRestrictedToFaction("ELF"); // SQF queries database.GetSkillsUnlockedByQuest("CLASS_TRIAL_MAGE"); database.GetSkillsRewardedByQuest("THE_ARCHMAGES_TRIAL");

Character Class Restrictions

Skills can be restricted to specific character classes using the allowedCharacterClasses field. This integrates with SAF Character Templates — if you have character template assets linked in Step 1, the wizard displays a checkbox list of available class names in Step 3. You can also add class names manually.

An empty allowedCharacterClasses array means the skill is usable by all classes.

// Check class restriction bool hasRestriction = skill.HasClassRestriction; // Check if a specific class can use the skill bool canUse = skill.IsUsableByClass("Mage"); // true if unrestricted or "Mage" is in the list // Database-level queries SimpleSkillDefinition[] mageOnly = database.GetSkillsForClass("Mage"); // restricted TO Mage SimpleSkillDefinition[] mageUsable = database.GetSkillsUsableByClass("Mage"); // restricted TO Mage + unrestricted
Distinction: GetSkillsForClass("Mage") returns only skills that are explicitly restricted to the Mage class. GetSkillsUsableByClass("Mage") returns those plus all unrestricted skills (skills with an empty allowedCharacterClasses array).

Overview

The Skill Tree Forge generates skill tree databases — grid-based talent trees where nodes reference skills from Skill Forge databases and are connected by directed parent-child edges. Each tree supports branch groups for specialization paths, point costs, level requirements, and single-level dynamic properties.

Generated databases implement ISimpleSkillTreeDataSource and produce the same 4-file output as the Skill Forge (enum, database, editor, asset), with the suffix Tree (e.g., ARPGTreeType.cs, ARPGTreeDatabase.cs).

Open the Skill Tree Forge wizard from the Unity menu:

Window > Living Failure > Simple Skill Forge > Skill Tree Forge

Key features:

  • Grid-based node layout with row/column positioning
  • Parent-child connections enforcing unlock order
  • Branch groups for specialization paths (e.g., "Fire", "Ice", "Lightning")
  • Per-node point cost, required level, and required points in tree
  • Nodes reference skill codes from any linked Skill Forge database
  • Single-level dynamic properties on each tree
  • Runtime tracker with unlock/reset/snapshot support
  • Character class restrictions via SAF Character Templates

The 5-Step Wizard

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

Step 1: Setup

Configure the database name, namespace, class prefix, and template. The Skill Tree Forge adds a Linked Skill Databases section where you drag-and-drop Skill Forge database assets. Linking a skill database enables searchable dropdown menus for node skillCode fields in Step 3. You can link multiple skill databases.

You can also link SAF Character Template assets for class restriction support.

Auto-naming: The Skill Tree Forge offers auto-naming based on your database name. For example, entering ARPG generates ARPGTreeType, ARPGTreeDatabase, etc.

Step 2: Definitions

Define single-level dynamic properties for your trees. Unlike the Skill Forge, there is no rank-level — properties apply to the tree definition itself (e.g., "Tree Type", "Total Point Cap", "Is Starter Tree"). The JSON schema export/import section is available for AI-assisted content generation.

Step 3: Builder

Split-panel editor (280px left panel). The left panel lists all tree definitions with search, filter, sort, bulk operations, and pagination. The right panel shows foldout sections for:

  • Identity — code, display name, description, icon
  • Categories / Flags / Numerics / Texts — single-level properties
  • Nodes — ReorderableList of tree nodes (9 editable fields per node)
  • Connections — ReorderableList of directed edges (from/to node dropdowns)
  • 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}TreeType.cs, {Prefix}TreeDatabase.cs, {Prefix}TreeDatabaseEditor.cs, and the .asset file.

Nodes

Each tree contains an array of SimpleSkillTreeNode structs. A node represents a single unlockable entry in the tree, referencing a skill from a linked Skill Forge database.

Field Type Description
nodeId int Unique identifier within this tree (auto-assigned)
skillCode string Skill code referencing a Skill Forge database entry
row int Row position in the tree grid (for visual layout)
column int Column position in the tree grid (for visual layout)
pointCost int Skill points required to unlock this node
requiredLevel int Minimum character level required to unlock this node
requiredPointsInTree int Minimum total points already spent in this tree to unlock
branchGroup string Specialization path identifier (e.g., "Fire", "Ice"). Nodes with the same branchGroup form a specialization track. Empty = no specific branch.
isRequired bool Whether this node must be unlocked to proceed further down its branch

Querying Nodes

// Get all nodes for a tree SimpleSkillTreeNode[] nodes = database.GetNodesForTree("WARRIOR_COMBAT"); // Get a node by ID from the tree struct SimpleSkillTreeNode? node = tree.GetNodeById(5); // Get root nodes (no parent connections) SimpleSkillTreeNode[] roots = tree.GetRootNodes(); // Get nodes in a specific branch SimpleSkillTreeNode[] fireNodes = tree.GetNodesInBranch("Fire"); // Get all unique branch groups string[] branches = tree.GetBranchGroups(); // Also available at the database level: string[] dbBranches = database.GetBranchGroups("WARRIOR_COMBAT"); // Check if a tree contains a specific skill bool hasFireball = tree.ContainsSkill("FIREBALL"); // Find all trees containing a skill SimpleSkillTreeDefinition[] treesWithFireball = database.FindTreesContainingSkill("FIREBALL");

Connections

Connections are directed edges (SimpleSkillTreeConnection) that define parent-child unlock dependencies between nodes. A child node cannot be unlocked until all parent nodes are unlocked.

Field Type Description
fromNodeId int Parent node ID (must be unlocked first)
toNodeId int Child node ID (unlockable after parent)

Querying Connections

// Get all connections for a tree SimpleSkillTreeConnection[] connections = database.GetConnectionsForTree("WARRIOR_COMBAT"); // Get connections from/to a specific node SimpleSkillTreeConnection[] children = tree.GetConnectionsFrom(nodeId); SimpleSkillTreeConnection[] parents = tree.GetConnectionsTo(nodeId); // Get parent/child node IDs directly int[] parentIds = tree.GetParentNodeIds(nodeId); int[] childIds = tree.GetChildNodeIds(nodeId);

Single-Level Properties

Skill trees use single-level dynamic properties (Categories, Flags, Numerics, Texts) on the tree definition itself. There is no child-level like the Skill Forge's rank-level properties.

// Access tree-level properties int treeType = tree.GetCategoryValue(0); bool isStarterTree = tree.GetFlagValue(0); float pointCap = tree.GetNumericValue(0); string lore = tree.GetTextValue(0); // Get property definition labels string[] catLabels = database.GetCategoryLabels(); // e.g., ["Tree Type", "Specialization"] string[] catEntries = database.GetCategoryEntries(0); // e.g., ["Class", "Subclass", "Universal"] string[] flagNames = database.GetFlagNames(); // e.g., ["Is Starter Tree", "Requires Mastery"] string[] numNames = database.GetNumericNames(); // e.g., ["Total Point Cap", "Required Level"] string[] textNames = database.GetTextNames(); // e.g., ["Tree Description", "Lore"] // Filter trees by property values SimpleSkillTreeDefinition[] classTrees = database.GetTreesByCategory(0, 0); SimpleSkillTreeDefinition[] starterTrees = database.GetTreesByFlag(0, true); SimpleSkillTreeDefinition[] bigTrees = database.GetTreesByNumericRange(0, 20f, 100f);

Runtime: SimpleSkillTreeTracker

SimpleSkillTreeTracker is a runtime state tracker that manages skill tree node unlocks, point spending, prerequisite validation, cascade resets, and serializable snapshots.

Setup

// Create a tracker from your tree database var tracker = new SimpleSkillTreeTracker(treeDatabase); // Initialize trees for tracking (must be called before unlock/query) tracker.InitializeTree("WARRIOR_COMBAT"); tracker.InitializeTree("MAGE_ARCANE");

Unlocking Nodes

// Check if a node can be unlocked (validates all prerequisites) bool canUnlock = tracker.CanUnlockNode( "WARRIOR_COMBAT", nodeId: 3, playerLevel: 10, availablePoints: 5 // pass -1 to skip point check ); // Unlock a node (does NOT deduct points -- your game manages point balance) bool unlocked = tracker.UnlockNode("WARRIOR_COMBAT", nodeId: 3, playerLevel: 10); // Check if a node is unlocked bool isUnlocked = tracker.IsNodeUnlocked("WARRIOR_COMBAT", nodeId: 3); // Check if a skill is unlocked in ANY initialized tree bool hasFireball = tracker.IsSkillUnlocked("FIREBALL");
Point management: UnlockNode tracks points spent internally (for requiredPointsInTree validation) but does not deduct from a player point balance. Your game code is responsible for checking and deducting available points before calling UnlockNode.

Queries

// Get total points spent in a tree int spent = tracker.GetPointsSpent("WARRIOR_COMBAT"); // Get points spent in a specific branch int fireSpent = tracker.GetPointsSpentInBranch("WARRIOR_COMBAT", "Fire"); // Get all unlocked node IDs int[] unlockedIds = tracker.GetUnlockedNodeIds("WARRIOR_COMBAT"); // Get all nodes that can currently be unlocked int[] available = tracker.GetAvailableNodeIds("WARRIOR_COMBAT", playerLevel: 10, availablePoints: 5); // Get all unlocked skill codes across ALL initialized trees string[] allUnlocked = tracker.GetAllUnlockedSkillCodes();

Reset

// Reset a single node (cascades to dependent child nodes) int refunded = tracker.ResetNode("WARRIOR_COMBAT", nodeId: 3); // Reset an entire tree int totalRefunded = tracker.ResetTree("WARRIOR_COMBAT"); // Clear all tracked state tracker.ClearAll();
Cascade reset: When you reset a node, all child nodes that depend on it (directly or transitively) are also reset. The returned value is the total points refunded across all reset nodes.

Events

tracker.OnNodeUnlocked += (treeCode, nodeId) => Debug.Log($"Unlocked node {nodeId} in {treeCode}"); tracker.OnNodeReset += (treeCode, nodeId) => Debug.Log($"Reset node {nodeId} in {treeCode}"); tracker.OnTreeReset += (treeCode) => Debug.Log($"Tree {treeCode} fully reset"); tracker.OnPointsChanged += (treeCode, newTotal) => Debug.Log($"Points spent in {treeCode}: {newTotal}");

Snapshots (Save/Load)

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

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);

Overview

The Skill Combo Forge generates skill combo databases — sequential skill chains where players execute skills in a specific order to earn threshold-based rewards. Each combo defines ordered steps with timing windows, alternate skill choices, and branch groups, plus rewards that trigger at step count thresholds.

Generated databases implement ISimpleSkillComboDataSource and produce the standard 4-file output with the suffix Combo (e.g., ARPGComboType.cs, ARPGComboDatabase.cs).

Open the Skill Combo Forge wizard from the Unity menu:

Window > Living Failure > Simple Skill Forge > Skill Combo Forge

Key features:

  • Ordered steps with sortOrder sequencing
  • Required and optional steps
  • Alternate skill choices per step (alternateSkillCodes[])
  • Branch groups for OR-alternative step paths
  • Per-step timing windows (maxDelay in seconds)
  • Threshold-based rewards with SAF modifier assets
  • Single-level dynamic properties on each combo
  • Runtime tracker for automatic combo detection and progression
  • Static evaluator for stateless combo analysis
  • Character class restrictions via SAF Character Templates

The 5-Step Wizard

The Skill Combo 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.

Step 2: Definitions

Define single-level dynamic properties for your combos (e.g., "Combo Type", "Element", "Damage Multiplier", "Is Finisher"). JSON schema export/import with context-aware usage hints and 5 combo design patterns (Chain Combo, Rotation, Reaction Chain, Hit String, Synergy Set).

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
  • Steps — ReorderableList with 6 fields per step (skillCode, isRequired, alternateSkillCodes mini-list, branchGroup, maxDelay, sortOrder)
  • Rewards — ReorderableList with threshold count, description, effect code, 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}ComboType.cs, {Prefix}ComboDatabase.cs, {Prefix}ComboDatabaseEditor.cs, and the .asset file with all step, reward, and modifier data baked in.

Steps

Each combo contains an array of SimpleSkillComboStep structs, sorted by sortOrder at runtime. A step defines a single position in the combo sequence.

Field Type Description
skillCode string Primary skill code that satisfies this step
isRequired bool Whether this step must be hit or can be skipped. Optional steps are automatically skipped if the player uses a skill matching a later required step.
alternateSkillCodes[] string[] Additional skill codes that also satisfy this step. Any of these (or the primary skillCode) will advance the combo.
branchGroup string Steps in the same branch group are OR alternatives — only one needs to be completed. Empty = no branch group.
maxDelay float Maximum seconds allowed before the next step must be hit. If the player waits longer, the combo drops. 0 = no time limit.
sortOrder int Determines the execution order of steps within the combo. Lower values go first. Steps are sorted by this field at runtime.

Querying Steps

// Get all steps for a combo SimpleSkillComboStep[] steps = database.GetStepsForCombo("ELEMENTAL_BURST"); // Convenience accessors on the combo struct int stepCount = combo.StepCount; SimpleSkillComboStep? step = combo.GetStepByIndex(0); // Check if the combo contains a specific skill (primary or alternates) bool hasFireball = combo.ContainsSkill("FIREBALL"); // Get all unique skill codes from all steps string[] allSkills = combo.GetAllSkillCodes(); // Find steps that match a specific skill code SimpleSkillComboStep[] matching = combo.FindStepsBySkillCode("FIREBALL"); // Find all combos containing a skill SimpleSkillComboDefinition[] combosWithFireball = database.FindCombosContainingSkill("FIREBALL"); // Find combos whose first step matches a skill SimpleSkillComboDefinition[] combosStarting = database.FindCombosStartingWith("SLASH");

Example: Elemental Burst Combo

Sort Order Skill Code Required Alternates Max Delay
0 FIREBALL Yes 0 (no limit)
1 ICE_BOLT Yes FROST_NOVA 2.0 sec
2 LIGHTNING_STRIKE Yes 2.0 sec
3 ARCANE_BLAST No (optional) 3.0 sec

The player must cast Fireball, then Ice Bolt (or Frost Nova) within 2 seconds, then Lightning Strike within 2 more seconds. The optional Arcane Blast at the end earns a bonus reward if hit within 3 seconds but is not required for combo completion.

Rewards

Each combo can have multiple SimpleSkillComboReward entries that trigger when enough steps are completed. This follows the same threshold pattern as set bonuses.

Field Type Description
requiredSteps int Number of completed steps required to earn this reward
rewardDescription string Human-readable description (e.g., "Elemental Overload: +50% elemental damage for 5s")
effectCode string Game-specific effect identifier for your code to interpret
modifiers[] ScriptableObject[] SAF modifier assets applied when this reward triggers

Querying Rewards

// Get all rewards for a combo SimpleSkillComboReward[] rewards = database.GetRewardsForCombo("ELEMENTAL_BURST"); // Convenience accessors on the combo struct int rewardCount = combo.RewardCount; // Get all rewards active at a given step count (stacking) SimpleSkillComboReward[] active = combo.GetActiveRewards(completedStepCount: 3);

Example: Tiered Rewards

Required Steps Reward Effect Code
2 Elemental Resonance: +20% elemental damage for 3s ELEM_RESONANCE
3 Elemental Overload: +50% elemental damage for 5s, AoE explosion ELEM_OVERLOAD
4 Elemental Mastery: Full elemental damage for 8s, reset all cooldowns ELEM_MASTERY

Each tier stacks — completing 3 steps earns both the 2-step and 3-step rewards.

Single-Level Properties

Skill combos use single-level dynamic properties on the combo definition itself.

// Access combo-level properties int comboType = combo.GetCategoryValue(0); bool isFinisher = combo.GetFlagValue(0); float damageMultiplier = combo.GetNumericValue(0); string description = combo.GetTextValue(0); // Get property definition labels string[] catLabels = database.GetCategoryLabels(); // e.g., ["Combo Type", "Element"] string[] catEntries = database.GetCategoryEntries(0); // e.g., ["Chain", "Rotation", "Reaction"] string[] flagNames = database.GetFlagNames(); // e.g., ["Is Finisher", "Requires Airborne"] string[] numNames = database.GetNumericNames(); // e.g., ["Damage Multiplier", "Cooldown Reduction"] string[] textNames = database.GetTextNames(); // e.g., ["Combo Description", "Flavor Text"] // Filter combos by property values SimpleSkillComboDefinition[] chains = database.GetCombosByCategory(0, 0); SimpleSkillComboDefinition[] finishers = database.GetCombosByFlag(0, true); SimpleSkillComboDefinition[] highDamage = database.GetCombosByNumericRange(0, 1.5f, 10f);

Runtime: SimpleSkillComboTracker

SimpleSkillComboTracker tracks active skill combos at runtime. Feed skill usage into the tracker and it automatically evaluates all defined combos simultaneously — starting new combos when a matching first step is detected, progressing active combos on subsequent matches, dropping combos when timing windows expire, and triggering rewards at thresholds.

Setup

// Create a tracker from your combo database var tracker = new SimpleSkillComboTracker(comboDatabase);

Feeding Skill Usage

// Call OnSkillUsed whenever the player casts a skill // The tracker evaluates ALL combos simultaneously tracker.OnSkillUsed("SLASH", Time.time); tracker.OnSkillUsed("UPPERCUT", Time.time); tracker.OnSkillUsed("SLAM", Time.time);

Each call to OnSkillUsed does the following:

  • Checks timing windows on all active combos (drops expired ones)
  • Advances active combos if the skill matches their next step
  • Skips optional steps when the skill matches a later required step
  • Triggers rewards when step thresholds are reached
  • Completes combos when all steps are matched
  • Starts new combos if the skill matches any inactive combo's first step

Queries

// Get all active combo states SimpleActiveComboState[] active = tracker.GetActiveComboStates(); // Get the number of active combos int count = tracker.GetActiveComboCount(); // Check if a specific combo is active bool isActive = tracker.IsComboActive("ELEMENTAL_BURST"); // Get completion progress (0 to 1) float progress = tracker.GetComboProgress("ELEMENTAL_BURST"); // Manually drop a combo tracker.DropCombo("ELEMENTAL_BURST"); // Drop all active combos tracker.DropAllCombos();

Events

tracker.OnComboStarted += (comboCode) => Debug.Log($"Combo started: {comboCode}"); tracker.OnComboProgressed += (comboCode, currentStep, totalSteps) => Debug.Log($"Combo {comboCode}: {currentStep}/{totalSteps}"); tracker.OnComboCompleted += (comboCode) => Debug.Log($"Combo complete: {comboCode}"); tracker.OnComboDropped += (comboCode, reason) => Debug.Log($"Combo dropped: {comboCode} ({reason})"); tracker.OnRewardTriggered += (comboCode, rewardIndex) => Debug.Log($"Reward {rewardIndex} triggered in {comboCode}");

Snapshots (Save/Load)

// Save current state (including mid-combo progress) SimpleComboTrackerSnapshot snapshot = tracker.CreateSnapshot(); string json = JsonUtility.ToJson(snapshot); // Load state var loaded = JsonUtility.FromJson<SimpleComboTrackerSnapshot>(json); tracker.RestoreFromSnapshot(loaded);

Runtime: SimpleSkillComboEvaluator

SimpleSkillComboEvaluator is a static utility class for evaluating combos without instantiating a tracker. All methods are stateless pure functions — useful for UI previews, combo planning, AI decision-making, and tooltip generation.

Evaluating a Combo

// Evaluate how well a sequence of skills matches a combo string[] usedSkills = { "FIREBALL", "ICE_BOLT", "LIGHTNING_STRIKE" }; ComboEvalResult result = SimpleSkillComboEvaluator.EvaluateCombo(combo, usedSkills); // Result fields: result.matchedStepCount; // 3 result.totalStepCount; // 4 result.completionPercentage; // 0.75 result.isComplete; // false result.nextValidSkillCodes; // ["ARCANE_BLAST"] (what to cast next)

Getting Next Valid Skills

// Get skills that would advance the combo from a given position string[] nextSkills = SimpleSkillComboEvaluator.GetNextValidSkills(combo, completedStepCount: 2); // Returns the primary skillCode + all alternateSkillCodes for step at index 2

This is especially useful for UI hints ("Cast one of these skills to continue the combo") and AI skill selection.

Finding Matching Combos

// Find all combos that partially or fully match a recent skill sequence string[] recentSkills = { "SLASH", "UPPERCUT" }; ComboMatch[] matches = SimpleSkillComboEvaluator.FindMatchingCombos(comboDatabase, recentSkills); foreach (var match in matches) { Debug.Log($"{match.comboCode}: {match.matchedSteps}/{match.totalSteps}" + (match.isComplete ? " COMPLETE" : "")); }

Quick Checks

// Check if a combo is fully complete bool complete = SimpleSkillComboEvaluator.IsComboComplete(combo, usedSkills); // Get completion progress (0 to 1) float progress = SimpleSkillComboEvaluator.GetComboProgress(combo, usedSkills); // Get active rewards for a step count SimpleSkillComboReward[] rewards = SimpleSkillComboEvaluator.GetActiveRewards(combo, completedStepCount: 3);

Tracker vs. Evaluator

Feature SimpleSkillComboTracker SimpleSkillComboEvaluator
Type Instance class (stateful) Static class (stateless)
Tracks multiple combos simultaneously Yes No (one-at-a-time evaluation)
Timing windows Yes (automatic drop on expiry) No
Events Yes (started, progressed, completed, dropped, reward) No
Snapshots Yes (save/load) No
Use case Live gameplay combo tracking UI previews, tooltips, AI planning

AI-Assisted Content Generation

All 4 forges support schema export in Step 2 (Definitions). Export your property schema with embedded AI instructions, hand it to ChatGPT, Claude, or any LLM, and import the generated content back into your database — all without writing code.

This workflow lets you:

  • Generate hundreds of skills/trees/sets/combos from a single prompt
  • Maintain consistency with your property schema (AI can only use your defined properties)
  • Iterate rapidly on content design before committing to implementation
  • Use AI as a creative partner for brainstorming skill concepts

Export Formats

Each forge offers 3 export formats:

FormatBest ForContent
Full JSON Structured AI input, programmatic processing Complete schema + definitions + existing entries + AI instructions as JSON
Light JSON Quick AI prompts, smaller context windows Schema + definitions + AI instructions (no existing entries)
Markdown Human-readable, documentation, wiki Schema + definitions formatted as Markdown tables + AI instructions

Export Workflow

1 Define your property schema in Step 2 of any wizard (or use a genre template).
2 Open the Schema Export section at the bottom of Step 2. Click "Export Full JSON", "Export Light JSON", or "Export Markdown".
3 Choose a save location for the exported file.
4 Send the file to an AI with a prompt like:
Generate 20 ARPG skills following the schema in this file. Include a mix of attack, spell, buff, and passive skills. Each skill should have 3 ranks with increasing damage and decreasing cooldown.
5 Copy the AI's JSON response and import it back in Step 2 (see Import below).

Embedded AI Instructions

The exported file includes a BuildInstructions section (600+ lines for the Skill Forge) that teaches the AI everything it needs to know:

  • Property system explanation — how Categories, Flags, Numerics, and Texts work at both skill-level and rank-level
  • Ecosystem description — all 7 forge systems and how they connect
  • User questions — 7-step questionnaire for the AI to ask the user about their game
  • Per-property guidance — context-aware usage hints for each defined property
  • Skill archetype patterns — 8 common skill types with design guidance
  • Rank progression patterns — how to design meaningful rank upgrades
  • Format examples — exact JSON structure using your actual definitions
  • 5-phase workflow — structured process for the AI to follow
  • Cross-forge awareness — what data is available from companion packages

Import Workflow

1 Copy the AI's JSON response to your clipboard or save it as a file.
2 In Step 2, click "Import JSON" in the Schema Export section.
3 Choose how to handle existing entries:
  • Replace — delete all existing entries and import only the new ones
  • Keep — keep existing entries and add new ones (skip duplicates by code)
  • Cancel — abort the import
4 Review the import results popup showing assigned/skipped/error counts.

The import validates each entry: codes must be unique C# identifiers, property arrays must match your defined schema length, and required fields (code, displayName) must be present.

Tips for AI Generation

Be Specific About Your Game

Tell the AI what kind of game you're making. "Generate ARPG skills" produces generic results. "Generate skills for a dark fantasy ARPG where the player is a fallen angel regaining divine powers" produces much more interesting content.

Use the Full JSON Format

The Full JSON export includes your existing entries as examples. This gives the AI concrete patterns to follow, resulting in more consistent output.

Generate in Batches

Ask for 10–20 entries at a time rather than 100+. Smaller batches give the AI more room to be creative and reduce the chance of repetitive content.

Iterate on Definitions First

Before generating content, make sure your property definitions are finalized. Changing definitions after importing 200 skills means all those skills need to be re-synced.

Review and Edit

AI-generated content is a starting point. Use the builder in Step 3 to review, edit, and refine each entry. The split-panel editor with search, sort, and filter makes this efficient.

Genre Templates

All 4 forges ship with 6 genre templates that pre-populate property definitions with genre-appropriate Categories, Flags, Numerics, and Texts. Templates are a starting point — you can modify, add, or remove any property after applying a template.

Select a template in Step 1 (Setup) of any wizard. Choosing "None" starts with a blank slate. Changing templates after defining entries will prompt for confirmation, since it replaces all property definitions.

Templates only set property definitions (the schema). They do not create any skill/tree/set/combo entries. Use the AI schema export or the builder in Step 3 to create content.

ARPG Template

Designed for action RPGs (Diablo, Path of Exile, Last Epoch). Emphasizes damage types, resource management, and scaling per rank.

Skill-Level Properties (Skill Forge)

TypeNameDetails
CategorySkill TypeAttack, Spell, Buff, Debuff, Passive, Movement, Summon, Aura
CategoryElementPhysical, Fire, Ice, Lightning, Poison, Holy, Dark, Arcane
CategoryTarget TypeSelf, Single Target, AoE, Cone, Line, Chain, Global
FlagIs PassiveDefault: false
FlagIs UltimateDefault: false
NumericBase CooldownSeconds
NumericMana CostBase resource cost
TextLoreFlavor text

Rank-Level Properties (Skill Forge)

TypeNameDetails
NumericDamagePer-rank damage value
NumericDurationEffect duration in seconds
NumericCooldown ReductionPercentage reduction per rank

MOBA Template

Designed for MOBAs (League of Legends, Dota 2). Focuses on ability scaling, lane impact, and team synergy.

Skill-level categories include Lane Phase (Early, Mid, Late), Role Fit (Carry, Support, Tank, Assassin, Mage, Bruiser), and Crowd Control type. Rank-level numerics emphasize per-level scaling values and cooldown reduction.

MMO Template

Designed for MMOs (World of Warcraft, Final Fantasy XIV). Emphasizes class identity, raid roles, and resource management.

Skill-level categories include Skill Category (Core, Talent, Racial, Profession), Resource Type (Mana, Energy, Rage, Focus, Combo Points), and Cast Type (Instant, Channeled, Cast Time, Toggle). Rank-level properties track per-rank GCD modifications and resource cost scaling.

Turn-Based Template

Designed for turn-based RPGs (Final Fantasy, Persona, Fire Emblem). Focuses on action economy, turn order, and elemental weakness systems.

Skill-level categories include Action Cost (Free, Half Turn, Full Turn, Multi-Turn), Element, and Range. Flags include "Consumes Turn" and "Can Counter". Rank numerics track hit rate, critical rate, and accuracy bonuses.

Action Template

Designed for action games (Devil May Cry, Bayonetta, God of War). Emphasizes combo potential, input complexity, and style scoring.

Skill-level categories include Input Type (Press, Hold, Charge, Direction+Press), Attack Type (Light, Heavy, Launcher, Slam, Projectile), and Cancel Window. Flags include "Can Air Cancel" and "Has Super Armor". Rank numerics include "Hit Count" and "Style Points".

Roguelike Template

Designed for roguelikes (Hades, Slay the Spire, Dead Cells). Emphasizes run synergies, randomized upgrades, and resource efficiency.

Skill-level categories include Rarity (Common, Uncommon, Rare, Epic, Legendary), Synergy Tag (multiple synergy groups), and Acquisition (Starter, Shop, Drop, Boss Reward, Secret). Flags include "Stackable" and "Removable". Rank numerics track "Stack Multiplier" and "Trigger Chance".

Customizing Templates

After applying a template, you can freely:

  • Add new categories, flags, numerics, or texts
  • Remove any property you don't need
  • Rename labels and entries
  • Reorder properties (drag handles in the ReorderableList)
  • Add category entries to existing categories

All changes in Step 2 automatically sync to existing entries in Step 3. New properties get default values; removed properties are cleaned up.

The template system tracks modifications. If you've customized a template and switch to a different one, you'll see a confirmation dialog showing what will change.

Data Structures

All runtime data structures live in the SimpleSkillForge namespace and are [Serializable] structs. The Skill Forge uses a two-level property system (skill-level + rank-level), while the Tree, Set, and Combo forges use single-level properties.

SimpleSkillDefinition

The main skill entry. Contains identity, two-level dynamic properties, nested ranks, prerequisites, modifier references, and 12 cross-forge reference fields.

Identity Fields

FieldTypeDescription
codestringUnique identifier (SCREAMING_SNAKE_CASE)
displayNamestringHuman-readable name
descriptionstringSkill description text
iconSpriteSkill icon

Skill-Level Dynamic Properties (Level 1)

FieldTypeDescription
categoryValuesint[]Category indices (one per category definition)
flagValuesbool[]Boolean flags (one per flag definition)
numericValuesfloat[]Numeric values (one per numeric definition)
textValuesstring[]Text values (one per text definition)

Nested Data

FieldTypeDescription
ranksSimpleSkillRank[]Per-rank data with Level 2 properties
prerequisitesSimpleSkillPrerequisite[]Unlock conditions
modifiersScriptableObject[]SAF modifier assets (passive effects)

Cross-Forge References: SIF (Item Forge)

FieldTypeDescription
grantedByItemCodestringItem that teaches/grants this skill (skill books, scrolls, equipment passives)
requiredEquipmentCodestringItem that must be equipped to use this skill (weapon requirements)
producesItemCodestringItem created when this skill is used (conjure food, crafting skills)
reagentCostsSimpleSkillReagentCost[]Items consumed per cast (arrows, soul shards, catalysts)

Cross-Forge References: SEF (Enemy Forge)

FieldTypeDescription
summonEnemyCodestringEnemy summoned by this skill (necromancer minions, pet classes)
learnedFromEnemyCodestringEnemy that teaches this skill (Blue Mage, monster absorption)
taughtByNPCCodestringNPC trainer that teaches this skill (class trainers, skill masters)
effectiveAgainstFactionsstring[]Factions this skill is strong against (Holy vs Undead, type advantages)
restrictedToFactionCodestringOnly characters of this faction can use this skill

Cross-Forge References: SQF (Quest Forge)

FieldTypeDescription
unlockedByQuestCodestringQuest that must be completed to learn this skill
rewardedByQuestCodesstring[]Quests that award this skill as a reward

Cross-Forge References: SAF Character Templates

FieldTypeDescription
allowedCharacterClassesstring[]Character class names this skill is restricted to. Empty = usable by all classes.

Accessor Methods

MethodReturnsDescription
GetCategoryValue(int index)intSafe category access (returns 0 if out of range)
GetFlagValue(int index)boolSafe flag access (returns false if out of range)
GetNumericValue(int index)floatSafe numeric access (returns 0f if out of range)
GetTextValue(int index)stringSafe text access (returns "" if out of range)
GetMaxRank()intReturns the maximum rank number defined for this skill
GetRank(int rankNumber)SimpleSkillRank?Returns rank data for a specific rank number, or null

Convenience Properties

PropertyTypeDescription
IsItemGrantedboolTrue if grantedByItemCode is set
HasEquipmentRequirementboolTrue if requiredEquipmentCode is set
ProducesItemboolTrue if producesItemCode is set
HasReagentCostsboolTrue if reagentCosts has entries
IsSummonSkillboolTrue if summonEnemyCode is set
IsEnemyLearnedboolTrue if learnedFromEnemyCode is set
HasTrainerboolTrue if taughtByNPCCode is set
HasFactionEffectivenessboolTrue if effectiveAgainstFactions has entries
IsFactionRestrictedboolTrue if restrictedToFactionCode is set
IsQuestUnlockedboolTrue if unlockedByQuestCode is set
IsQuestRewardedboolTrue if rewardedByQuestCodes has entries
HasClassRestrictionboolTrue if allowedCharacterClasses has entries

Query Methods

MethodReturnsDescription
IsUsableByClass(string className)boolTrue if unrestricted or className is in allowedCharacterClasses
IsEffectiveAgainst(string factionCode)boolTrue if factionCode is in effectiveAgainstFactions
IsRewardedByQuest(string questCode)boolTrue if questCode is in rewardedByQuestCodes

SimpleSkillRank

A single rank of a skill. Each rank has its own rank-level dynamic properties (Level 2), upgrade costs, and optional SAF modifier references.

FieldTypeDescription
rankintRank number (starts at 1, not an index)
categoryValuesint[]Rank-level category indices
flagValuesbool[]Rank-level boolean flags
numericValuesfloat[]Rank-level numeric values
textValuesstring[]Rank-level text values
upgradeCostsSimpleSkillUpgradeCost[]Resources required to reach this rank
modifiersScriptableObject[]SAF modifier assets gained at this rank

Accessor Methods

MethodReturnsDescription
GetCategoryValue(int index)intSafe category access (returns 0 if out of range)
GetFlagValue(int index)boolSafe flag access (returns false if out of range)
GetNumericValue(int index)floatSafe numeric access (returns 0f if out of range)
GetTextValue(int index)stringSafe text access (returns "" if out of range)

SimpleSkillUpgradeCost

A resource cost for upgrading a skill to a specific rank. The resourceCode can reference an item code (SIF), attribute code (SAF), or any custom string.

FieldTypeDescription
resourceCodestringIdentifier of the required resource
amountfloatQuantity required

SimpleSkillReagentCost

An item consumed each time the skill is used. Different from SimpleSkillUpgradeCost which is for leveling/ranking up.

FieldTypeDescription
itemCodestringItem code consumed per cast
amountintQuantity consumed per cast

SimpleSkillPrerequisite

A prerequisite condition for unlocking a skill. Evaluated as: valueProvider(targetCode) [comparison] value

FieldTypeDescription
targetCodestringCode to evaluate (skill code, attribute code, quest code, or custom)
comparisonSimpleSkillComparisonComparison operator
valuefloatThreshold value to compare against

SimpleSkillComparison (enum)

Comparison operators for prerequisite evaluation.

ValueMeaning
EqualsCurrent value equals target (using Mathf.Approximately)
NotEqualsCurrent value does not equal target
GreaterThanCurrent value is greater than target
LessThanCurrent value is less than target
GreaterOrEqualCurrent value is greater than or equal to target
LessOrEqualCurrent value is less than or equal to target

SimpleSkillTreeDefinition

A complete skill tree with identity, nodes, connections, and single-level dynamic properties.

Fields

FieldTypeDescription
codestringUnique identifier
displayNamestringHuman-readable name
descriptionstringTree description text
iconSpriteTree icon
nodesSimpleSkillTreeNode[]All nodes in this tree
connectionsSimpleSkillTreeConnection[]Directed edges between nodes
categoryValuesint[]Category indices
flagValuesbool[]Boolean flags
numericValuesfloat[]Numeric values
textValuesstring[]Text values
allowedCharacterClassesstring[]Class restrictions (empty = unrestricted)

Accessor Methods

MethodReturnsDescription
GetCategoryValue(int index)intSafe category access (returns -1 if out of range)
GetFlagValue(int index)boolSafe flag access (returns false if out of range)
GetNumericValue(int index)floatSafe numeric access (returns 0f if out of range)
GetTextValue(int index)stringSafe text access (returns "" if out of range)
GetNodeById(int nodeId)SimpleSkillTreeNode?Find a node by its ID, or null
GetNodesInBranch(string branchGroup)SimpleSkillTreeNode[]Get all nodes in a branch group
GetBranchGroups()string[]Get all unique branch group names
GetConnectionsFrom(int nodeId)SimpleSkillTreeConnection[]Get connections from a node (children)
GetConnectionsTo(int nodeId)SimpleSkillTreeConnection[]Get connections to a node (parents)
GetParentNodeIds(int nodeId)int[]Get parent node IDs
GetChildNodeIds(int nodeId)int[]Get child node IDs
GetRootNodes()SimpleSkillTreeNode[]Get nodes with no parent connections
ContainsSkill(string skillCode)boolCheck if any node references this skill code
IsAvailableToClass(string className)boolTrue if unrestricted or className is allowed

Convenience Properties

PropertyTypeDescription
NodeCountintNumber of nodes
ConnectionCountintNumber of connections
HasClassRestrictionboolTrue if allowedCharacterClasses has entries

SimpleSkillTreeNode

A single node in a skill tree. References a skill code and defines grid position, unlock requirements, and branch membership.

FieldTypeDescription
nodeIdintUnique identifier within this tree
skillCodestringSkill code from a linked Skill Forge database
rowintRow position in the tree grid (visual layout)
columnintColumn position in the tree grid (visual layout)
pointCostintSkill points required to unlock this node
requiredLevelintMinimum character level required
requiredPointsInTreeintMinimum total points spent in this tree to unlock
branchGroupstringSpecialization path identifier (e.g., "Fire", "Ice"). Empty = no branch.
isRequiredboolMust this node be unlocked to proceed down the branch?

SimpleSkillTreeConnection

A directed edge in a skill tree: parent to child unlock dependency. The child node cannot be unlocked until the parent is unlocked.

FieldTypeDescription
fromNodeIdintSource node ID (must be unlocked first)
toNodeIdintTarget node ID (unlockable after parent)

SimpleSkillSetDefinition

A complete skill set with identity, slots, threshold-based bonuses, and single-level dynamic properties.

Fields

FieldTypeDescription
codestringUnique identifier
displayNamestringHuman-readable name
descriptionstringSet description text
iconSpriteSet icon
slotsSimpleSkillSetSlot[]Typed skill slots
bonusesSimpleSkillSetBonus[]Threshold-based set bonuses
categoryValuesint[]Category indices
flagValuesbool[]Boolean flags
numericValuesfloat[]Numeric values
textValuesstring[]Text values
allowedCharacterClassesstring[]Class restrictions (empty = unrestricted)

Accessor Methods

MethodReturnsDescription
GetCategoryValue(int index)intSafe category access (returns -1 if out of range)
GetFlagValue(int index)boolSafe flag access
GetNumericValue(int index)floatSafe numeric access
GetTextValue(int index)stringSafe text access
GetSlotTypes()string[]Get all unique slot type labels
GetSlotsByType(string slotType)SimpleSkillSetSlot[]Get all slots of a specific type
ContainsSkill(string skillCode)boolCheck if any slot references this skill code
GetSkillCodes()string[]Get all non-empty skill codes from slots
GetBonusForCount(int equippedCount)SimpleSkillSetBonus?Get the highest-threshold bonus for a given count
GetActiveBonuses(int equippedCount)SimpleSkillSetBonus[]Get all bonuses active for a given count
IsAvailableToClass(string className)boolTrue if unrestricted or className is allowed

Convenience Properties

PropertyTypeDescription
SlotCountintNumber of slots
BonusCountintNumber of bonuses
RequiredSlotCountintNumber of required slots
HasClassRestrictionboolTrue if allowedCharacterClasses has entries

SimpleSkillSetSlot

A single slot in a skill set, with a type label, skill reference, and required flag.

FieldTypeDescription
slotTypestringSlot type label (e.g., "Active1", "Passive1", "Ultimate")
skillCodestringSkill code from a linked Skill Forge database
isRequiredboolWhether this slot must be filled for the set to be valid

SimpleSkillSetBonus

A threshold-based bonus that activates when enough skills from the set are equipped.

FieldTypeDescription
requiredCountintNumber of equipped skills required to activate
bonusDescriptionstringHuman-readable description of the bonus effect
modifiersScriptableObject[]SAF modifier assets applied when this bonus activates

SimpleSkillComboDefinition

A complete skill combo with identity, ordered steps, threshold-based rewards, and single-level dynamic properties.

Fields

FieldTypeDescription
codestringUnique identifier
displayNamestringHuman-readable name
descriptionstringCombo description text
iconSpriteCombo icon
stepsSimpleSkillComboStep[]Ordered steps in the combo sequence
rewardsSimpleSkillComboReward[]Threshold-based rewards
categoryValuesint[]Category indices
flagValuesbool[]Boolean flags
numericValuesfloat[]Numeric values
textValuesstring[]Text values
allowedCharacterClassesstring[]Class restrictions (empty = unrestricted)

Accessor Methods

MethodReturnsDescription
GetCategoryValue(int index)intSafe category access (returns -1 if out of range)
GetFlagValue(int index)boolSafe flag access
GetNumericValue(int index)floatSafe numeric access
GetTextValue(int index)stringSafe text access
GetStepByIndex(int index)SimpleSkillComboStep?Get step by index, or null if out of range
ContainsSkill(string skillCode)boolCheck if any step references this skill (primary or alternates)
GetAllSkillCodes()string[]Get all unique skill codes from all steps
GetActiveRewards(int completedStepCount)SimpleSkillComboReward[]Get rewards active for a given step count
FindStepsBySkillCode(string skillCode)SimpleSkillComboStep[]Find all steps matching a skill code (primary or alternates)
IsAvailableToClass(string className)boolTrue if unrestricted or className is allowed

Convenience Properties

PropertyTypeDescription
StepCountintNumber of steps
RewardCountintNumber of rewards
HasClassRestrictionboolTrue if allowedCharacterClasses has entries

SimpleSkillComboStep

A single step in a combo chain, with a primary skill, alternates, branch grouping, and timing.

FieldTypeDescription
skillCodestringPrimary skill code for this step
isRequiredboolMust this step be hit, or can it be skipped?
alternateSkillCodesstring[]Alternative skill codes that also satisfy this step
branchGroupstringSteps in the same branch group are OR alternatives
maxDelayfloatMax seconds before the combo drops (0 = no limit)
sortOrderintSort order for step sequencing

SimpleSkillComboReward

A threshold-based reward that activates when enough combo steps are completed.

FieldTypeDescription
requiredStepsintNumber of completed steps required to earn this reward
rewardDescriptionstringHuman-readable description of the reward effect
effectCodestringGame-specific effect identifier
modifiersScriptableObject[]SAF modifier assets applied when this reward triggers

Interfaces

Each forge generates a ScriptableObject database class that implements one of these interfaces. Cast your generated database asset to the interface for type-safe access.

// Cast a ScriptableObject to the interface var db = skillDatabaseAsset as ISimpleSkillDataSource; var fireball = db.GetSkillByCode("FIREBALL");

ISimpleSkillDataSource

Interface for generated skill databases. Supports two-level dynamic properties (skill-level + rank-level).

Skill Access

MemberReturnsDescription
SkillCountintTotal number of skills
GetSkillDefinitions()SimpleSkillDefinition[]All skill definitions
GetSkillByCode(string code)SimpleSkillDefinition?Skill by code, or null
GetSkillCodes()string[]All skill codes
GetSkillNames()string[]All skill display names
HasSkill(string code)boolCheck if a skill exists
GetSkillEnumType()TypeThe generated enum type for skill codes

Rank Access

MethodReturnsDescription
GetRanksForSkill(string skillCode)SimpleSkillRank[]All ranks for a skill
GetMaxRank(string skillCode)intMax rank number for a skill

Skill-Level Property Definitions (Level 1)

MethodReturnsDescription
GetCategoryLabels()string[]Labels for skill-level categories
GetCategoryEntries(int index)string[]Entries for a skill-level category
GetFlagNames()string[]Names of skill-level flags
GetNumericNames()string[]Names of skill-level numerics
GetTextNames()string[]Names of skill-level texts

Rank-Level Property Definitions (Level 2)

MethodReturnsDescription
GetRankCategoryLabels()string[]Labels for rank-level categories
GetRankCategoryEntries(int index)string[]Entries for a rank-level category
GetRankFlagNames()string[]Names of rank-level flags
GetRankNumericNames()string[]Names of rank-level numerics
GetRankTextNames()string[]Names of rank-level texts

Dynamic Filtering

MethodReturnsDescription
GetSkillsByCategory(int categoryIndex, int entryIndex)SimpleSkillDefinition[]Skills matching a category value
GetSkillsByFlag(int flagIndex, bool value)SimpleSkillDefinition[]Skills matching a flag value
GetSkillsByNumericRange(int numericIndex, float min, float max)SimpleSkillDefinition[]Skills with a numeric in the given range

Cross-Reference Queries

MethodReturnsDescription
GetSkillsWithPrerequisite(string targetCode)SimpleSkillDefinition[]Skills requiring a specific target code
GetSkillsWithUpgradeCost(string resourceCode)SimpleSkillDefinition[]Skills using a resource in any rank's upgrade costs

Cross-Forge Queries: SIF

MethodReturnsDescription
GetSkillsGrantedByItem(string itemCode)SimpleSkillDefinition[]Skills granted by a specific item
GetSkillsRequiringEquipment(string itemCode)SimpleSkillDefinition[]Skills requiring a specific item equipped
GetSkillsProducingItem(string itemCode)SimpleSkillDefinition[]Skills that produce a specific item
GetSkillsConsumingReagent(string itemCode)SimpleSkillDefinition[]Skills consuming a specific reagent item

Cross-Forge Queries: SEF

MethodReturnsDescription
GetSkillsSummoningEnemy(string enemyCode)SimpleSkillDefinition[]Skills that summon a specific enemy
GetSkillsLearnedFromEnemy(string enemyCode)SimpleSkillDefinition[]Skills learned from a specific enemy
GetSkillsTaughtByNPC(string npcCode)SimpleSkillDefinition[]Skills taught by a specific NPC trainer
GetSkillsEffectiveAgainstFaction(string factionCode)SimpleSkillDefinition[]Skills effective against a specific faction
GetSkillsRestrictedToFaction(string factionCode)SimpleSkillDefinition[]Skills restricted to a specific faction

Cross-Forge Queries: SQF

MethodReturnsDescription
GetSkillsUnlockedByQuest(string questCode)SimpleSkillDefinition[]Skills unlocked by completing a specific quest
GetSkillsRewardedByQuest(string questCode)SimpleSkillDefinition[]Skills rewarded by a specific quest

Cross-Forge Queries: SAF Character Templates

MethodReturnsDescription
GetSkillsForClass(string className)SimpleSkillDefinition[]Skills restricted to a specific class
GetSkillsUsableByClass(string className)SimpleSkillDefinition[]Skills usable by a class (restricted to that class + unrestricted)

ISimpleSkillTreeDataSource

Interface for generated skill tree databases. Supports single-level dynamic properties on trees.

Tree Access

MemberReturnsDescription
TreeCountintNumber of trees
GetAllTrees()SimpleSkillTreeDefinition[]All tree definitions
GetTreeByCode(string code)SimpleSkillTreeDefinition?Tree by code, or null
GetTreeCodes()string[]All tree codes
GetTreeNames()string[]All tree display names
HasTree(string code)boolCheck if a tree exists
GetTreeEnumType()TypeThe generated enum type for tree codes

Node and Connection Access

MethodReturnsDescription
GetNodesForTree(string treeCode)SimpleSkillTreeNode[]All nodes for a tree
GetConnectionsForTree(string treeCode)SimpleSkillTreeConnection[]All connections for a tree
GetBranchGroups(string treeCode)string[]Unique branch group names in a tree

Property Definitions (Single-Level)

MethodReturnsDescription
GetCategoryLabels()string[]Category labels
GetCategoryEntries(int categoryIndex)string[]Entries for a category
GetFlagNames()string[]Flag names
GetNumericNames()string[]Numeric property names
GetTextNames()string[]Text property names

Dynamic Filtering

MethodReturnsDescription
GetTreesByCategory(int categoryIndex, int entryIndex)SimpleSkillTreeDefinition[]Trees matching a category value
GetTreesByFlag(int flagIndex, bool value)SimpleSkillTreeDefinition[]Trees matching a flag value
GetTreesByNumericRange(int numericIndex, float min, float max)SimpleSkillTreeDefinition[]Trees with a numeric in the given range

Cross-Reference and Class Queries

MethodReturnsDescription
FindTreesContainingSkill(string skillCode)SimpleSkillTreeDefinition[]Trees containing a node with the given skill code
GetTreesForClass(string className)SimpleSkillTreeDefinition[]Trees restricted to a specific class
GetTreesAvailableToClass(string className)SimpleSkillTreeDefinition[]Trees available to a class (restricted + unrestricted)

ISimpleSkillSetDataSource

Interface for generated skill set databases. Supports single-level dynamic properties on sets.

Set Access

MemberReturnsDescription
SetCountintNumber of sets
GetAllSets()SimpleSkillSetDefinition[]All set definitions
GetSetByCode(string code)SimpleSkillSetDefinition?Set by code, or null
GetSetCodes()string[]All set codes
GetSetNames()string[]All set display names
HasSet(string code)boolCheck if a set exists
GetSetEnumType()TypeThe generated enum type for set codes

Slot and Bonus Access

MethodReturnsDescription
GetSlotsForSet(string setCode)SimpleSkillSetSlot[]All slots for a set
GetBonusesForSet(string setCode)SimpleSkillSetBonus[]All bonuses for a set

Property Definitions (Single-Level)

MethodReturnsDescription
GetCategoryLabels()string[]Category labels
GetCategoryEntries(int categoryIndex)string[]Entries for a category
GetFlagNames()string[]Flag names
GetNumericNames()string[]Numeric property names
GetTextNames()string[]Text property names

Dynamic Filtering

MethodReturnsDescription
GetSetsByCategory(int categoryIndex, int entryIndex)SimpleSkillSetDefinition[]Sets matching a category value
GetSetsByFlag(int flagIndex, bool value)SimpleSkillSetDefinition[]Sets matching a flag value
GetSetsByNumericRange(int numericIndex, float min, float max)SimpleSkillSetDefinition[]Sets with a numeric in the given range

Cross-Reference and Class Queries

MethodReturnsDescription
FindSetsContainingSkill(string skillCode)SimpleSkillSetDefinition[]Sets containing a slot with the given skill code
GetSetsForClass(string className)SimpleSkillSetDefinition[]Sets restricted to a specific class
GetSetsAvailableToClass(string className)SimpleSkillSetDefinition[]Sets available to a class (restricted + unrestricted)

ISimpleSkillComboDataSource

Interface for generated skill combo databases. Supports single-level dynamic properties on combos.

Combo Access

MemberReturnsDescription
ComboCountintNumber of combos
GetAllCombos()SimpleSkillComboDefinition[]All combo definitions
GetComboByCode(string code)SimpleSkillComboDefinition?Combo by code, or null
GetComboCodes()string[]All combo codes
GetComboNames()string[]All combo display names
HasCombo(string code)boolCheck if a combo exists
GetComboEnumType()TypeThe generated enum type for combo codes

Step and Reward Access

MethodReturnsDescription
GetStepsForCombo(string comboCode)SimpleSkillComboStep[]All steps for a combo
GetRewardsForCombo(string comboCode)SimpleSkillComboReward[]All rewards for a combo

Cross-Reference and Class Queries

MethodReturnsDescription
FindCombosContainingSkill(string skillCode)SimpleSkillComboDefinition[]Combos containing a step with the given skill (primary or alternates)
FindCombosStartingWith(string skillCode)SimpleSkillComboDefinition[]Combos whose first step matches the given skill code
GetCombosForClass(string className)SimpleSkillComboDefinition[]Combos restricted to a specific class
GetCombosAvailableToClass(string className)SimpleSkillComboDefinition[]Combos available to a class (restricted + unrestricted)

Property Definitions (Single-Level)

MethodReturnsDescription
GetCategoryLabels()string[]Category labels
GetCategoryEntries(int categoryIndex)string[]Entries for a category
GetFlagNames()string[]Flag names
GetNumericNames()string[]Numeric property names
GetTextNames()string[]Text property names

Dynamic Filtering

MethodReturnsDescription
GetCombosByCategory(int categoryIndex, int entryIndex)SimpleSkillComboDefinition[]Combos matching a category value
GetCombosByFlag(int flagIndex, bool value)SimpleSkillComboDefinition[]Combos matching a flag value
GetCombosByNumericRange(int numericIndex, float min, float max)SimpleSkillComboDefinition[]Combos with a numeric in the given range

Static Helpers

Stateless utility classes with pure functions. No instantiation needed — call methods directly on the static class.

SimpleSkillHelper

Static utility class for prerequisite evaluation, upgrade cost queries, cross-reference lookups, and rank-up affordability checks. All methods are pure functions.

Prerequisite Evaluation

MethodReturnsDescription
CheckPrerequisite(SimpleSkillPrerequisite, Func<string, float>)boolEvaluate a single prerequisite condition
CheckAllPrerequisites(SimpleSkillDefinition, Func<string, float>)boolEvaluate all prerequisites for a skill (ALL must pass)
EvaluatePrerequisites(SimpleSkillDefinition, Func<string, float>)PrerequisiteResult[]Evaluate all prerequisites with detailed results (currentValue, passed)

Upgrade Cost Queries

MethodReturnsDescription
GetTotalUpgradeCost(SimpleSkillDefinition, string resourceCode, int fromRank, int toRank)floatTotal cost of a resource to upgrade between ranks
GetAllResourceCodes(SimpleSkillDefinition)string[]All unique resource codes used across all ranks
GetUpgradeCostsForRank(SimpleSkillDefinition, int rankNumber)SimpleSkillUpgradeCost[]Upgrade costs for a specific rank
CanAffordRankUp(SimpleSkillDefinition, int currentRank, Func<string, float>)boolCheck if player can afford upgrading to the next rank

Cross-Reference Queries

MethodReturnsDescription
FindSkillsByCategory(ISimpleSkillDataSource, int categoryIndex, int entryIndex)SimpleSkillDefinition[]Skills matching a category value
FindSkillsRequiring(ISimpleSkillDataSource, string targetCode)SimpleSkillDefinition[]Skills with a specific prerequisite target code
FindUnlockedSkills(ISimpleSkillDataSource, Func<string, float>)List<SimpleSkillDefinition>All skills whose prerequisites are met
GetPrerequisiteChain(ISimpleSkillDataSource, string skillCode)List<string>Recursive prerequisite chain (all skills needed before target)

Cross-Forge Queries: SIF (Item Forge)

MethodReturnsDescription
FindSkillsGrantedByItem(ISimpleSkillDataSource, string itemCode)SimpleSkillDefinition[]Skills granted by a specific item
FindSkillsRequiringEquipment(ISimpleSkillDataSource, string itemCode)SimpleSkillDefinition[]Skills requiring a specific item equipped
FindSkillsProducingItem(ISimpleSkillDataSource, string itemCode)SimpleSkillDefinition[]Skills that produce a specific item
FindSkillsConsumingReagent(ISimpleSkillDataSource, string itemCode)SimpleSkillDefinition[]Skills consuming a specific reagent item
GetAllReagentItemCodes(ISimpleSkillDataSource)string[]All unique reagent item codes across all skills

Cross-Forge Queries: SEF (Enemy Forge)

MethodReturnsDescription
FindSkillsSummoningEnemy(ISimpleSkillDataSource, string enemyCode)SimpleSkillDefinition[]Skills summoning a specific enemy
FindSkillsLearnedFromEnemy(ISimpleSkillDataSource, string enemyCode)SimpleSkillDefinition[]Skills learned from a specific enemy
FindSkillsTaughtByNPC(ISimpleSkillDataSource, string npcCode)SimpleSkillDefinition[]Skills taught by a specific NPC trainer
FindSkillsEffectiveAgainstFaction(ISimpleSkillDataSource, string factionCode)SimpleSkillDefinition[]Skills effective against a faction
FindSkillsRestrictedToFaction(ISimpleSkillDataSource, string factionCode)SimpleSkillDefinition[]Skills restricted to a faction

Cross-Forge Queries: SQF (Quest Forge)

MethodReturnsDescription
FindSkillsUnlockedByQuest(ISimpleSkillDataSource, string questCode)SimpleSkillDefinition[]Skills unlocked by a quest
FindSkillsRewardedByQuest(ISimpleSkillDataSource, string questCode)SimpleSkillDefinition[]Skills rewarded by a quest

Cross-Forge Queries: SAF Character Templates

MethodReturnsDescription
FindSkillsForClass(ISimpleSkillDataSource, string className)SimpleSkillDefinition[]Skills restricted to a specific class
FindSkillsUsableByClass(ISimpleSkillDataSource, string className)SimpleSkillDefinition[]Skills usable by a class (restricted + unrestricted)

Tree Node Lookup

MethodReturnsDescription
GetSkillForTreeNode(ISimpleSkillDataSource, ISimpleSkillTreeDataSource, string treeCode, int nodeId)SimpleSkillDefinition?Convenience: get the skill definition for a tree node

Usage Example

// Check if a player can learn a skill Func<string, float> valueProvider = (code) => GetPlayerValue(code); bool canLearn = SimpleSkillHelper.CheckAllPrerequisites(fireball, valueProvider); // Get detailed results for UI display var results = SimpleSkillHelper.EvaluatePrerequisites(fireball, valueProvider); foreach (var r in results) Debug.Log($"{r.prerequisite.targetCode}: {r.currentValue} - {(r.passed ? "MET" : "NOT MET")}"); // Check if player can afford rank-up bool canAfford = SimpleSkillHelper.CanAffordRankUp(fireball, currentRank, resourceProvider); // Get the full prerequisite chain var chain = SimpleSkillHelper.GetPrerequisiteChain(db, "METEOR_STORM"); Debug.Log($"Must learn first: {string.Join(" > ", chain)}");

SimpleSkillComboEvaluator

Static utility class for evaluating combo progress, finding matching combos, and computing next valid skills. Stateless — all methods are pure functions. Use this when you need combo evaluation without instantiating a tracker.

Methods

MethodReturnsDescription
EvaluateCombo(SimpleSkillComboDefinition, string[] usedSkillCodes)ComboEvalResultEvaluate a combo against a sequence of used skills
FindMatchingCombos(ISimpleSkillComboDataSource, string[] recentSkillCodes)ComboMatch[]Find all combos that partially or fully match recent skills
GetActiveRewards(SimpleSkillComboDefinition, int completedStepCount)SimpleSkillComboReward[]Get rewards active for a given step count
GetNextValidSkills(SimpleSkillComboDefinition, int completedStepCount)string[]Get skill codes that would advance the combo from current position
IsComboComplete(SimpleSkillComboDefinition, string[] usedSkillCodes)boolCheck if a combo is fully complete
GetComboProgress(SimpleSkillComboDefinition, string[] usedSkillCodes)floatGet completion progress (0 to 1)

Result Types

ComboEvalResult

FieldTypeDescription
matchedStepCountintNumber of steps matched
totalStepCountintTotal steps in the combo
completionPercentagefloatCompletion percentage (0 to 1)
isCompleteboolWhether all steps have been matched
nextValidSkillCodesstring[]Skills that would advance the combo

ComboMatch

FieldTypeDescription
comboCodestringThe combo code
matchedStepsintNumber of steps matched
totalStepsintTotal steps in the combo
isCompleteboolWhether the combo is fully complete

Usage Example

// Evaluate a specific combo against recent skills var result = SimpleSkillComboEvaluator.EvaluateCombo(combo, new[] { "SLASH", "UPPERCUT" }); Debug.Log($"Progress: {result.completionPercentage:P0}"); Debug.Log($"Next valid: {string.Join(", ", result.nextValidSkillCodes)}"); // Find all matching combos in a database var matches = SimpleSkillComboEvaluator.FindMatchingCombos(comboDb, new[] { "SLASH", "UPPERCUT" }); foreach (var m in matches) Debug.Log($"{m.comboCode}: {m.matchedSteps}/{m.totalSteps}");

State Trackers

Mutable runtime state managers. Instantiate them with a database reference, use methods to modify state, subscribe to events for reactive updates, and create/restore snapshots for save/load.

SimpleSkillTreeTracker

Tracks skill tree progression at runtime. Manages node unlocks, point spending, prerequisite validation, cascade resets, and serializable snapshots.

Constructor

var tracker = new SimpleSkillTreeTracker(treeDatabase);

Events

EventSignatureDescription
OnNodeUnlockedAction<string, int>Fired when a node is unlocked (treeCode, nodeId)
OnNodeResetAction<string, int>Fired when a node is reset/locked (treeCode, nodeId)
OnTreeResetAction<string>Fired when an entire tree is reset (treeCode)
OnPointsChangedAction<string, int>Fired when points spent changes (treeCode, newTotal)

Properties

PropertyTypeDescription
DatabaseISimpleSkillTreeDataSourceThe tree database this tracker uses
InitializedTreeCodesstring[]All initialized tree codes

Lifecycle Methods

MethodReturnsDescription
InitializeTree(string treeCode)boolInitialize a tree for tracking. Required before unlock/query operations.
IsTreeInitialized(string treeCode)boolCheck if a tree has been initialized
GetTreeState(string treeCode)SimpleSkillTreeStateGet the runtime state object, or null

Node Unlock Methods

MethodReturnsDescription
CanUnlockNode(string treeCode, int nodeId, int playerLevel, int availablePoints)boolCheck all prerequisites: parent nodes, level, points in tree, point cost
UnlockNode(string treeCode, int nodeId, int playerLevel)boolUnlock a node (caller manages point deduction)
IsNodeUnlocked(string treeCode, int nodeId)boolCheck if a specific node is unlocked

Query Methods

MethodReturnsDescription
GetPointsSpent(string treeCode)intTotal skill points spent in a tree
GetPointsSpentInBranch(string treeCode, string branchGroup)intPoints spent in a specific branch
GetUnlockedNodeIds(string treeCode)int[]All unlocked node IDs for a tree
GetAvailableNodeIds(string treeCode, int playerLevel, int availablePoints)int[]All node IDs that can currently be unlocked
GetAllUnlockedSkillCodes()string[]All unlocked skill codes across all initialized trees
IsSkillUnlocked(string skillCode)boolCheck if a skill code is unlocked in any tree

Reset Methods

MethodReturnsDescription
ResetNode(string treeCode, int nodeId)intReset a node and cascade to dependents. Returns points refunded.
ResetTree(string treeCode)intReset an entire tree. Returns points refunded.
ClearAll()voidClear all tracked state

Serialization

MethodReturnsDescription
CreateSnapshot()SimpleSkillTreeTrackerSnapshotExport current state as a serializable snapshot
RestoreFromSnapshot(SimpleSkillTreeTrackerSnapshot)voidRestore state from a snapshot

Usage Example

var tracker = new SimpleSkillTreeTracker(treeDatabase); tracker.InitializeTree("WARRIOR_COMBAT"); tracker.OnNodeUnlocked += (tree, node) => Debug.Log($"Unlocked node {node} in {tree}"); // Check and unlock if (tracker.CanUnlockNode("WARRIOR_COMBAT", 3, playerLevel: 10)) { tracker.UnlockNode("WARRIOR_COMBAT", 3, playerLevel: 10); int spent = tracker.GetPointsSpent("WARRIOR_COMBAT"); } // Save/load var snapshot = tracker.CreateSnapshot(); string json = JsonUtility.ToJson(snapshot); // ... later ... tracker.RestoreFromSnapshot(JsonUtility.FromJson<SimpleSkillTreeTrackerSnapshot>(json));

SimpleSkillBarManager

Manages skill set loadouts at runtime. Handles equipping/unequipping skills to set slots, tracks active set bonuses based on equipped count thresholds, and supports snapshot serialization.

Constructor

var manager = new SimpleSkillBarManager(setDatabase);

Events

EventSignatureDescription
OnSkillEquippedAction<string, int, string>Fired when a skill is equipped (setCode, slotIndex, skillCode)
OnSkillUnequippedAction<string, int, string>Fired when a skill is unequipped (setCode, slotIndex, previousSkillCode)
OnSetBonusActivatedAction<string, int>Fired when a set bonus activates (setCode, bonusIndex)
OnSetBonusDeactivatedAction<string, int>Fired when a set bonus deactivates (setCode, bonusIndex)
OnLoadoutChangedAction<string>Fired on any equip/unequip (setCode)

Properties

PropertyTypeDescription
DatabaseISimpleSkillSetDataSourceThe set database this manager uses
InitializedSetCodesstring[]All initialized set codes

Lifecycle Methods

MethodReturnsDescription
InitializeSet(string setCode)boolInitialize a set for loadout tracking. Required before equip/query operations.
IsSetInitialized(string setCode)boolCheck if a set has been initialized
GetLoadoutState(string setCode)SimpleSkillSetLoadoutStateGet the runtime loadout state, or null

Equip / Unequip Methods

MethodReturnsDescription
EquipSkill(string setCode, int slotIndex, string skillCode)boolEquip a skill to a slot (auto-unequips previous)
UnequipSkill(string setCode, int slotIndex)boolUnequip a skill from a slot
ClearLoadout(string setCode)intClear all equipped skills. Returns number of slots cleared.

Query Methods

MethodReturnsDescription
GetEquippedSkill(string setCode, int slotIndex)stringGet the skill code in a slot, or empty string
GetEquippedCount(string setCode)intNumber of non-empty slots
AreRequiredSlotsFilled(string setCode)boolCheck if all required slots are filled
GetActiveBonuses(string setCode)SimpleSkillSetBonus[]Get currently active bonuses
IsBonusActive(string setCode, int bonusIndex)boolCheck if a specific bonus is active
IsSkillEquipped(string skillCode)boolCheck if a skill is equipped in any set
GetAllEquippedSkillCodes()string[]All equipped skill codes across all sets
FindEquippedSkill(string skillCode, out string setCode, out int slotIndex)boolFind which set and slot a skill is equipped in

Serialization

MethodReturnsDescription
CreateSnapshot()SimpleSkillBarSnapshotExport current state as a serializable snapshot
RestoreFromSnapshot(SimpleSkillBarSnapshot)voidRestore state from a snapshot
ClearAll()voidClear all tracked state

Usage Example

var manager = new SimpleSkillBarManager(setDatabase); manager.InitializeSet("WARRIOR_KIT"); manager.OnSetBonusActivated += (set, idx) => Debug.Log($"Bonus {idx} activated on {set}!"); manager.EquipSkill("WARRIOR_KIT", 0, "SLASH"); manager.EquipSkill("WARRIOR_KIT", 1, "SHIELD_BASH"); manager.EquipSkill("WARRIOR_KIT", 2, "CHARGE"); // Check bonuses var bonuses = manager.GetActiveBonuses("WARRIOR_KIT"); foreach (var b in bonuses) Debug.Log($"Active bonus ({b.requiredCount} equipped): {b.bonusDescription}"); // Save/load var snapshot = manager.CreateSnapshot(); string json = JsonUtility.ToJson(snapshot); // ... later ... manager.RestoreFromSnapshot(JsonUtility.FromJson<SimpleSkillBarSnapshot>(json));

SimpleSkillComboTracker

Tracks active skill combos at runtime. Feed skill usage to auto-evaluate all defined combos simultaneously, handles timing windows, triggers threshold rewards, and supports snapshot serialization.

Constructor

var tracker = new SimpleSkillComboTracker(comboDatabase);

Events

EventSignatureDescription
OnComboStartedAction<string>Fired when a combo starts (first step matched). Parameter: comboCode.
OnComboProgressedAction<string, int, int>Fired when a combo progresses (comboCode, currentStep, totalSteps)
OnComboCompletedAction<string>Fired when a combo is fully completed (comboCode)
OnComboDroppedAction<string, string>Fired when a combo is dropped (comboCode, reason)
OnRewardTriggeredAction<string, int>Fired when a combo reward triggers (comboCode, rewardIndex)

Properties

PropertyTypeDescription
DatabaseISimpleSkillComboDataSourceThe combo database this tracker uses

Skill Usage

MethodReturnsDescription
OnSkillUsed(string skillCode, float currentTime)voidFeed a skill usage. Evaluates all combos and starts new ones.

Query Methods

MethodReturnsDescription
GetActiveComboStates()SimpleActiveComboState[]Get all active combo states
GetActiveComboCount()intNumber of active combos
IsComboActive(string comboCode)boolCheck if a specific combo is active
GetComboProgress(string comboCode)floatCompletion progress of an active combo (0 to 1)

Control Methods

MethodReturnsDescription
DropCombo(string comboCode)voidManually drop an active combo
DropAllCombos()voidDrop all active combos

Serialization

MethodReturnsDescription
CreateSnapshot()SimpleComboTrackerSnapshotExport current state as a serializable snapshot
RestoreFromSnapshot(SimpleComboTrackerSnapshot)voidRestore state from a snapshot
ClearAll()voidClear all tracked state

Usage Example

var tracker = new SimpleSkillComboTracker(comboDatabase); tracker.OnComboStarted += (code) => Debug.Log($"Combo started: {code}"); tracker.OnComboCompleted += (code) => Debug.Log($"Combo complete: {code}!"); tracker.OnRewardTriggered += (code, idx) => Debug.Log($"Reward earned in {code}!"); // Feed skill usage as the player casts skills tracker.OnSkillUsed("SLASH", Time.time); tracker.OnSkillUsed("UPPERCUT", Time.time + 0.5f); tracker.OnSkillUsed("SLAM", Time.time + 1.0f); // Check progress foreach (var state in tracker.GetActiveComboStates()) Debug.Log($"{state.comboCode}: {state.completedStepCount}/{state.definition.StepCount}"); // Save/load var snapshot = tracker.CreateSnapshot(); string json = JsonUtility.ToJson(snapshot); // ... later ... tracker.RestoreFromSnapshot(JsonUtility.FromJson<SimpleComboTrackerSnapshot>(json));

Supporting Types

These types are used internally by the static helpers and state trackers.

PrerequisiteResult

Returned by SimpleSkillHelper.EvaluatePrerequisites().

FieldTypeDescription
prerequisiteSimpleSkillPrerequisiteThe prerequisite that was evaluated
currentValuefloatThe current value from the value provider
passedboolWhether the prerequisite was met

SimpleIntArray

Wrapper for int[] to allow serialization of nested arrays. Used for multi-select category values.

FieldTypeDescription
valuesint[]The wrapped integer array

Snapshot Types

All snapshot types are [Serializable] classes compatible with JsonUtility.

TypeUsed ByContains
SimpleSkillTreeTrackerSnapshotSimpleSkillTreeTrackerList of tree state snapshots (treeCode, totalPointsSpent, unlockedNodeIds)
SimpleSkillBarSnapshotSimpleSkillBarManagerList of loadout snapshots (setCode, equippedSkills)
SimpleComboTrackerSnapshotSimpleSkillComboTrackerList of active combo snapshots (comboCode, completedStepCount, usedSkillCodes, lastStepTime)

Cross-Forge Integration

Simple Skill Forge integrates with 4 companion packages from the Living Failure ecosystem. All integrations use safe reflection — no hard dependencies, no compile errors, no #if preprocessor directives. Install companion packages when you need them; SSF adapts automatically.

PackagePackage IDWhat SSF Gets
Simple Attribute Forge com.livingfailure.simple-attribute-forge Modifier assets on skills/ranks/bonuses, character class restrictions
Simple Item Forge com.livingfailure.simple-item-forge 4 skill-item reference fields + reagent costs
Simple Enemy Forge com.livingfailure.simple-enemy-forge 5 skill-enemy/faction reference fields
Simple Quest Forge com.livingfailure.simple-quest-forge 2 skill-quest reference fields

How Bridges Work

SSF uses two detection paths:

1. UPM Detection (Automatic)

The .asmdef files contain versionDefines that detect companion packages by their UPM package name and set scripting defines automatically:

"versionDefines": [ { "name": "com.livingfailure.simple-attribute-forge", "expression": "", "define": "SIMPLE_ATTRIBUTE_FORGE" }, { "name": "com.livingfailure.simple-item-forge", "expression": "", "define": "SIMPLE_ITEM_FORGE" }, { "name": "com.livingfailure.simple-enemy-forge", "expression": "", "define": "SIMPLE_ENEMY_FORGE" }, { "name": "com.livingfailure.simple-quest-forge", "expression": "", "define": "SIMPLE_QUEST_FORGE" } ]

2. Reflection Detection (Fallback)

For non-UPM installs (Asset Store, .unitypackage), bridge classes use Type.GetType() to probe for companion types at editor time. Each bridge is a static class that caches type references and builds delegate-based accessors:

// Example: SIFBridge probes for item data source var type = Type.GetType("SimpleItemForge.ISimpleItemDataSource, SimpleItemForge.Runtime"); if (type != null) { IsAvailable = true; GetItemCodes = (db) => (string[])type.GetMethod("GetItemCodes").Invoke(db, null); }

At runtime, the demo scenes use FindType() (scanning all loaded assemblies) instead of Type.GetType() with assembly-qualified names, since assembly names may vary between UPM and Asset Store installs.

Simple Attribute Forge (SAF)

When SAF is detected, the following features become available:

Modifier Assets

The Skill Forge builder (Step 3) shows a Skill Modifiers section where you can assign SimpleModifierAssetBase ScriptableObjects to skills. Each rank can also have its own modifier assets. The Skill Set Forge allows modifiers on set bonuses.

Character Class Restrictions

When SAF Character Templates are detected, all 4 forges show an Allowed Character Classes section. You can assign character template assets in Step 1, and the builder provides checkbox toggles for each detected class name plus a manual entry list.

At runtime, each definition struct has allowedCharacterClasses (string[]) with HasClassRestriction and IsUsableByClass() / IsAvailableToClass() accessors. The interfaces provide GetSkillsForClass() and GetSkillsUsableByClass() query methods.

Simple Item Forge (SIF)

When SIF is detected, the Skill Forge builder shows 4 cross-forge reference fields plus reagent costs:

FieldTypePurposeExample
grantedByItemCodestring Item that teaches/grants this skill Skill books, scrolls, equipment passives, gem sockets
requiredEquipmentCodestring Item that must be equipped to use this skill Bow for arrow skills, staff for magic, specific weapon types
producesItemCodestring Item created when skill is used Conjure food, crafting skills, transmutation, gathering yields
reagentCosts[]SimpleSkillReagentCost[] Items consumed per cast Arrows, soul shards, catalysts, reagents
Note: Reagent costs are different from SimpleSkillUpgradeCost (which defines costs to level up a skill rank). Reagents are consumed every time the skill is cast.

Runtime Queries

// Find all skills that require a specific item equipped var bowSkills = db.GetSkillsRequiringEquipment("LONGBOW"); // Find all skills that consume a specific reagent var arrowSkills = db.GetSkillsConsumingReagent("IRON_ARROW");

Simple Enemy Forge (SEF)

When SEF is detected, the Skill Forge builder shows 5 cross-forge reference fields:

FieldTypePurposeExample
summonEnemyCodestring Enemy summoned by this skill Necromancer minions, pet classes, conjured creatures
learnedFromEnemyCodestring Enemy that teaches this skill Blue Mage skills, Enemy Skill materia, monster absorption
taughtByNPCCodestring NPC trainer that teaches this skill Class trainers, weapon masters, move tutors
effectiveAgainstFactions[]string[] Factions this skill is strong against Holy vs Undead, Dragon Slayer vs Dragons, type advantages
restrictedToFactionCodestring Only characters of this faction can use the skill Racial abilities, covenant skills, guild techniques
In SEF, NPCs are represented as enemy definitions. The taughtByNPCCode field references an enemy code from the SEF database.

Runtime Queries

// Find all skills learned from a specific enemy var blueSkills = db.GetSkillsLearnedFromEnemy("FIRE_DRAGON"); // Find all skills effective against a faction var antiUndead = db.GetSkillsEffectiveAgainstFaction("UNDEAD");

Simple Quest Forge (SQF)

When SQF is detected, the Skill Forge builder shows 2 cross-forge reference fields:

FieldTypePurposeExample
unlockedByQuestCodestring Quest that must be completed to learn this skill Class quests, weapon art quests, mastery trials
rewardedByQuestCodes[]string[] Quests that award this skill as a reward Reverse lookup: "Learned from: The Archmage's Trial"

Runtime Queries

// Find all skills unlocked by completing a quest var questSkills = db.GetSkillsUnlockedByQuest("ARCHMAGE_TRIAL"); // Find all skills rewarded by a quest var rewards = db.GetSkillsRewardedByQuest("DRAGON_SLAYER_QUEST");

Character Class System

All 4 forge types (Skill, Tree, Set, Combo) support allowedCharacterClasses on their definition structs. This feature is enabled when SAF Character Templates are detected, but can also be used manually by typing class names directly.

How It Works

  • In Step 1, assign Character Template assets to populate available class names
  • In Step 3 (builder), toggle classes on/off per entry or type custom names
  • An empty allowedCharacterClasses array means the entry is unrestricted (usable by all classes)
  • A non-empty array means the entry is restricted to listed classes only

Runtime API

// Check if a skill has class restrictions if (skill.HasClassRestriction) Debug.Log($"Restricted to: {string.Join(", ", skill.allowedCharacterClasses)}"); // Check if a specific class can use a skill bool canUse = skill.IsUsableByClass("Warrior"); // Query: get all skills usable by a class (restricted to that class + unrestricted) var warriorSkills = db.GetSkillsUsableByClass("Warrior"); // Same pattern works for trees, sets, and combos var warriorTrees = treeDb.GetTreesAvailableToClass("Warrior"); var warriorSets = setDb.GetSetsAvailableToClass("Warrior"); var warriorCombos = comboDb.GetCombosAvailableToClass("Warrior");

Demo Scenes

Simple Skill Forge ships with two interactive demo scenes that showcase all 4 forges and their runtime components. Both demos are generated procedurally via editor menu commands — no manual scene setup required.

DemoPurposeRequirements
ARPG Demo Proves the SSF runtime API works: browse skills, rank up, unlock tree nodes, equip loadouts, cast combos SSF only (standalone)
Soulslike Demo Showcases cross-forge integration: browse items/enemies/quests and see how they connect to skills SSF + SAF + SIF + SEF + SQF (all installed)

ARPG Demo

A 4-tab interactive skill system with Royal Orange theme (1920x1080).

Tab 1: Skills

Left panel: searchable skill list with rank badges. Right panel: skill detail with identity, properties, rank stats (per-rank costs, UNLOCKED/LOCKED status), prerequisites (MET/NOT MET), and cross-forge connections. RANK UP button deducts resources. EQUIP TO BAR adds the skill to the bottom bar.

Tab 2: Skill Trees

Left panel: tree list. Right panel: node list showing skill name, SP cost, level requirement, and UNLOCK/UNLOCKED/LOCKED status. Click a node to unlock it (deducts skill points). RESET TREE refunds all points.

Tab 3: Loadout

Left panel: set list with equipped count. Right panel: dropdown per slot for skill assignment, X button to unequip, and set bonus progress (3/5 threshold bonuses with OK/[ ] indicators).

Tab 4: Combos

Left panel: combo list with step count. Right panel: step sequence with skill names, required/optional flags, timing windows, alternate skills, reward thresholds. Live tracker shows combo progress bars and next valid skills.

Bottom Bar

6 skill slots with CAST buttons. Casting updates combo tracking, shows combo progress, set status, and cast log. Cyclic assignment — equipping when full wraps to slot 0.

Top Bar

Class dropdown (filters all tabs by character class). Cheat buttons: +LVL, +SP, +Souls for testing.

Soulslike Demo

A 7-tab cross-forge showcase with upsell panel. Same Royal Orange theme.

Upsell Panel

Shown when any companion package (SAF/SIF/SEF/SQF) is not installed. Displays a checklist of INSTALLED/MISSING packages with descriptions of what each provides. A forceShowUpsell debug toggle on the component lets you test this panel even with all packages installed.

Tabs 1–4: Skills, Trees, Loadout, Combos

Same functionality as the ARPG demo. Uses "Souls" instead of "Gold" for the Soulslike theme.

Tab 5: Items

Browses all items from assigned SIF databases. Shows item name, code, description, properties (categories, flags, numerics, texts reflected from the item database), and skill connections — which skills grant, require, produce, or consume this item.

Tab 6: Enemies

Browses all enemies from assigned SEF databases. Shows enemy name, code, description, info (properties reflected from the enemy database), and skill connections — which skills are taught by, trained by, or summoned by this enemy.

Tab 7: Quests

Browses all quests from assigned SQF databases. Shows quest name, code, description, and skill connections — which skills this quest unlocks or rewards.

Cross-Forge Reflection

The Soulslike demo uses FindType() to scan all loaded assemblies for SIF/SEF/SQF interfaces. It builds lookup dictionaries (code → name, code → description) and reverse lookups (item → skills that reference it) via reflection at startup. No hard dependencies on any companion package.

Generating Demo Scenes

ARPG Demo

1 Generate databases using the 4 forge wizards with the ARPG template.
2 Generate the demo canvas: Window > Living Failure > Simple Skill Forge > Generate Skill Demo
3 Assign databases to the SkillDemo component (see below).
4 Press Play and interact with the skill system.

Soulslike Demo

1 Install SAF, SIF, SEF, and SQF from the Asset Store.
2 Generate databases using all forge wizards with Soulslike templates.
3 Generate the demo canvas: Window > Living Failure > Simple Skill Forge > Generate Soulslike Demo
4 Assign all databases (SSF + SAF + SIF + SEF + SQF) to the SoulslikeSkillDemo component.
5 Press Play and browse across all forges.

Assigning Databases

After generating a demo canvas, select the root canvas GameObject in the Hierarchy. The demo component will be attached with empty database array fields:

ARPG Demo (SkillDemo component)

FieldWhat to Assign
skillDatabasesYour generated Skill database .asset(s)
treeDatabasesYour generated Skill Tree database .asset(s)
setDatabasesYour generated Skill Set database .asset(s)
comboDatabasesYour generated Skill Combo database .asset(s)

Soulslike Demo (SoulslikeSkillDemo component)

FieldWhat to Assign
skillDatabasesSSF Skill database(s)
treeDatabasesSSF Skill Tree database(s)
setDatabasesSSF Skill Set database(s)
comboDatabasesSSF Skill Combo database(s)
attributeDatabasesSAF Attribute database(s)
modifierAssetsSAF Modifier assets
itemDatabasesSIF Item database(s)
enemyDatabasesSEF Enemy database(s)
factionDatabasesSEF Faction database(s)
questDatabasesSQF Quest database(s)
characterTemplatesSAF Character Template assets
All database arrays accept multiple assets. If you generated separate ARPG and Soulslike databases, you can assign both to the same array — the demo will merge and deduplicate entries.

Troubleshooting

Common issues and their solutions when working with Simple Skill Forge.

Generation Issues

"Generation seems stuck" / Nothing happens after clicking Generate

Simple Skill Forge uses two-phase generation. Phase 1 generates C# scripts, which triggers a Unity domain reload (recompilation). Phase 2 runs automatically after the reload to create the ScriptableObject asset. This process can take 5–30 seconds depending on your project size.

If the wizard window closes during domain reload, reopen it from the menu. The generation will resume automatically via [InitializeOnLoad].

"The generated .asset file is empty"

This typically means Phase 2 failed. Check the Console for errors. Common causes:

  • A compile error in your project prevented the domain reload from completing.
  • The SessionState keys were lost (rare, usually caused by a Unity crash during generation).

Fix: Delete the generated Scripts/ folder, fix any compile errors, and re-run the wizard.

"Duplicate code" validation error

Every entry code must be unique within a database and must be a valid C# identifier (letters, digits, underscores; cannot start with a digit). Use SCREAMING_SNAKE_CASE for consistency: FIREBALL, DARK_SLASH, HEAL_OVER_TIME.

"Output path does not exist"

The output folder must exist before generation. Create it manually in your Assets folder, or use the Browse button in Step 4 to select an existing folder.

Editor Issues

The generated custom inspector shows "Element 0, Element 1" instead of property names

This can happen if the database was generated with an older version of the editor generator. Re-run the wizard to regenerate the editor script.

Cross-forge sections (SIF/SEF/SQF) appear in the inspector even without companion packages

The generated editor uses Type.GetType() bridge checks to gate cross-forge sections. If sections appear without the companion package installed, regenerate the database — the editor generator has been updated to include proper bridge detection.

Property definitions changed but entries are out of sync

When you add/remove/reorder property definitions in Step 2, the wizard automatically syncs all entries. However, if you modify the generated database asset manually, the sync won't apply. Use the wizard for all structural changes.

Runtime Issues

SimpleSkillTreeTracker throws "Tree not initialized"

Call InitializeTree(treeCode) for each tree before attempting to unlock nodes or query state. The tracker does not auto-initialize — this is intentional so you can control which trees are active.

SimpleSkillBarManager set bonuses not activating

Set bonuses require the correct number of distinct skills equipped. Equipping the same skill in multiple slots does not count multiple times. Check GetEquippedCount(setCode) to verify.

SimpleSkillComboTracker drops combos unexpectedly

Combos have timing windows defined by maxDelay on each step. If you cast skills too slowly, the combo will drop. Set maxDelay to 0 to disable timing for a step. Also ensure you're passing consistent Time.time values to OnSkillUsed().

Prerequisite checks always return false

SimpleSkillHelper.CheckPrerequisite() requires a Func<string, float> value provider that returns the current value for any prerequisite target code. Common mistake: the provider returns 0 for all codes because it doesn't check the right dictionary.

// Example value provider for skill ranks bool met = SimpleSkillHelper.CheckPrerequisite(prereq, code => { if (skillRanks.ContainsKey(code)) return skillRanks[code]; if (code == "Level") return playerLevel; return 0f; });

Integration Issues

SAF/SIF/SEF/SQF bridge not detecting installed package

Bridge detection uses two paths:

  1. UPM path: versionDefines in .asmdef files detect packages by com.livingfailure.* package name and set scripting defines automatically.
  2. Non-UPM path: [InitializeOnLoad] detector classes use Type.GetType() to probe for companion types and set scripting defines manually.

If detection fails, check that the companion package's .asmdef files are present and correctly named. For Asset Store imports, ensure the folder structure matches the expected layout.

Character class restrictions not showing in the wizard

Class names come from SAF Character Template assets assigned in Step 1. If you don't have SAF installed or haven't assigned any character template assets, the class restriction section will be empty. You can still manually type class names in the builder.

Cross-forge reference dropdowns are empty

Cross-forge dropdowns in Step 3 are populated from linked databases assigned in Step 1. If you haven't assigned any SIF/SEF/SQF databases, the dropdowns will only show manual code entry fields.

Demo Scene Issues

ARPG Demo: "Assign all databases to SkillDemo component"

After running Window > Living Failure > Simple Skill Forge > Generate Skill Demo, you need to manually assign your generated database ScriptableObjects to the SkillDemo component in the Inspector. Drag your Skill, Tree, Set, and Combo database assets into the corresponding array fields.

Soulslike Demo: Shows upsell panel instead of main UI

The Soulslike demo requires all 4 companion packages (SAF, SIF, SEF, SQF) to be installed. If any are missing, it shows an upsell panel explaining what's needed. Install the missing packages and re-enter Play mode.

Soulslike Demo: "forceShowUpsell" is checked

The SoulslikeSkillDemo component has a debug toggle forceShowUpsell. Uncheck it in the Inspector to show the main UI even when all bridges are detected.

Demo scroll views don't scroll

Ensure the EventSystem exists in the scene. The generator creates one automatically, but if you deleted it, scrolling won't work. Add GameObject > UI > Event System.

FAQ

Can I have multiple skill databases in one project?

Yes. Run the wizard multiple times with different database names. Each run generates its own enum, database class, and editor. At runtime, cast each ScriptableObject to ISimpleSkillDataSource and merge or query them independently.

Can I modify the generated database asset in the Inspector?

Yes. The generated custom editor provides a full split-panel builder with search, sort, filter, and pagination — identical to the wizard's Step 3. You can add, remove, edit, and duplicate entries directly in the Inspector without reopening the wizard.

Does SSF support multiplayer / networking?

SSF generates data assets and provides runtime state trackers. The trackers (SimpleSkillTreeTracker, SimpleSkillBarManager, SimpleSkillComboTracker) are pure C# classes with snapshot serialization. You can serialize their state via CreateSnapshot() / RestoreFromSnapshot() for network sync, save/load, or undo/redo.

What's the performance impact?

Generated databases are standard Unity ScriptableObjects with struct arrays. All runtime lookups use linear scans over small arrays (typical game databases have 50–500 entries). The trackers use dictionaries for O(1) state lookups. There are no per-frame allocations in normal usage.

Can I use SSF with Addressables / Asset Bundles?

Yes. The generated database is a standard ScriptableObject and works with any Unity asset loading system. Cast the loaded asset to the appropriate interface at runtime.

About Simple Skill Forge

Simple Skill Forge is a Unity Editor tool for creating ScriptableObject-based skill databases using a wizard-driven workflow. It follows the same proven architecture as Simple Enemy Forge, Simple Item Forge, and Simple Quest Forge — dynamic property systems, two-phase code generation, schema export/import for AI-assisted content creation, and optional integration bridges via safe reflection.

Whether you're building a small indie RPG or a large-scale MMO, Simple Skill Forge adapts to your game's needs. You define the properties that matter to your game (there are no hardcoded "Mana Cost" or "Cooldown" fields), and the tool generates production-ready code and data assets from your design.

Design Philosophy

Two-Level Properties

The Skill Forge defines dynamic properties at both skill-level AND rank-level. A skill can have "Element" and "Skill Type" while each of its ranks independently tracks "Damage Multiplier" and "Cast Time". The other three forges (Tree, Set, Combo) use single-level properties.

Dynamic, Not Hardcoded

There are no built-in "Mana Cost" or "Cooldown" fields. You define your own property schema using four property types: Categories (dropdowns), Flags (booleans), Numerics (numbers), and Texts (strings). A MOBA might need "Lane Phase" and "Team Fight Impact". A roguelike might need "Synergy Tag" and "Stack Limit". Your game, your properties, your rules.

Four Tools, One Ecosystem

Skill Forge defines individual skills with ranks and cross-forge references. Skill Tree Forge organizes them into unlockable talent grids. Skill Set Forge groups them into loadouts with set bonuses. Skill Combo Forge chains them into timed sequences with rewards. Together they cover every aspect of a skill system.

AI-First Content Pipeline

All four wizards support schema export in 3 formats (Full JSON, Light JSON, Markdown) with detailed AI instructions embedded in the export. Define your schema once, let AI generate hundreds of skills, then import the results — all without writing a line of code.

The Forge Ecosystem

Simple Skill Forge is part of the Simple Forge Ecosystem, a family of Unity Editor tools that share a common architecture:

PackageForgesRuntime Components
Simple Attribute Forge Attribute Forge, Modifier System, Character Templates Runtime attributes, modifier tracker, formula calculator
Simple Item Forge Item Forge, Loot Forge, Crafting Forge, Shop Forge Loot roller, crafting evaluator, shop manager
Simple Enemy Forge Enemy, Squad, Spawn, Scaling, Wave, Behavior, Faction Forges Spawn roller, wave runner, scaling helper, faction helper
Simple Quest Forge Quest Forge, Quest Chain Forge, Procedural Quest Forge Quest tracker, chain tracker, procedural generator
Simple Skill Forge Skill Forge, Skill Tree Forge, Skill Set Forge, Skill Combo Forge Tree tracker, bar manager, combo tracker, combo evaluator

Every package in the ecosystem follows the same 5-step wizard pattern, uses the same dynamic property system, generates the same output structure (enum + database + editor + asset), and supports the same AI schema export/import workflow.

What Gets Generated

Each forge generates 4 files per database run:

Generated/ ARPG/ Skills/ Scripts/ ARPGSkillsType.cs ← Enum of all skill codes ARPGSkillsDatabase.cs ← ScriptableObject implementing ISimpleSkillDataSource Editor/ ARPGSkillsDatabaseEditor.cs ← Custom inspector with split-panel builder ARPGSkillsDatabase.asset ← The actual data asset

The generated database implements the corresponding interface (ISimpleSkillDataSource, ISimpleSkillTreeDataSource, ISimpleSkillSetDataSource, or ISimpleSkillComboDataSource), so your game code only depends on the interface — never on the generated class name.

Companion Products

Simple Skill Forge optionally integrates with these companion packages via safe reflection. No hard dependencies — install them only when you need them:

Simple Attribute Forge (SAF)

Enables modifier asset references on skills, ranks, and set bonuses. Provides attribute names for prerequisites and character class templates for class restrictions on all 4 forge types.

Simple Item Forge (SIF)

Enables skill-item relationships: skill books (grantedByItemCode), weapon requirements (requiredEquipmentCode), produced items (producesItemCode), and reagent costs per cast.

Simple Enemy Forge (SEF)

Enables skill-enemy relationships: summon skills (summonEnemyCode), NPC trainers (taughtByNPCCode), learned-from enemies (learnedFromEnemyCode), faction effectiveness, and faction restrictions.

Simple Quest Forge (SQF)

Enables skill-quest relationships: quest-gated unlocks (unlockedByQuestCode) and quest-rewarded skills (rewardedByQuestCodes).

Version History

VersionDateChanges
1.0.0 2025 Initial release. 4 forges, 6 genre templates, 4 runtime trackers, cross-forge integration (SAF/SIF/SEF/SQF), AI schema export/import, character class restrictions, 2 demo scenes (ARPG + Soulslike), database export window, batch icon assignment.

Support

Simple Skill Forge is developed and maintained by Living Failure.

PublisherLiving Failure on Unity Asset Store
Emaillivingfailuregames@gmail.com
Unity Version2021.3+
Package Namecom.livingfailure.simple-skill-forge

Found a bug? Have a feature request? Email us or leave a review on the Asset Store page.