SK

skills-and-advancement

Handles skill tree structures, attribute calculations, and advancement systems in the Oxidus LPC codebase.

Install

mkdir -p .claude/skills/skills-and-advancement && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/18133" && unzip -o skill.zip -d .claude/skills/skills-and-advancement && rm skill.zip

Installs to .claude/skills/skills-and-advancement

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Understand and work with the skill tree and advancement systems in Oxidus. Covers the nested skill tree, dot-path addressing, use-based improvement, the query_skill / query_raw_skill / query_skill_level / query_raw_skill_level API grid, has_skill existence checks, boon integration, XP, TNL formula, leveling, attributes, and how skills interact with combat and NPCs.
367 charsno explicit “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Advanced

Key capabilities

  • Navigate a nested skill tree using dot notation
  • Query raw skill levels without boons
  • Query effective skill levels with boon modifiers
  • Check for skill existence using has_skill()
  • Improve skills transparently through use-based progression

How it works

The skill system uses a nested tree structure for skills, allowing dot-path addressing. Players improve skills through use, with a chance to increase their level, and boons can modify effective skill levels.

Inputs & outputs

You give it
Skill dot-path (e.g., 'combat.melee.slashing'), optional level for adding/setting skills, mixed mod_adjust for use_skill
You get back
Skill level (float or integer), existence status of a skill, updated skill progress

When to use skills-and-advancement

  • Querying skill levels
  • Implementing new advancement logic
  • Debugging skill tree attributes

About this skill

Skills and Advancement Skill

You are helping work with the Oxidus skill and advancement systems. Follow the lpc-coding-style skill for all LPC formatting.

Architecture Overview

skills.lpc (std/living/skills.lpc)           — nested skill tree, use-based improvement
advancement.lpc (std/living/advancement.lpc) — per-living XP/level state
advance.lpc (adm/daemons/advance.lpc)        — TNL formula, kill_xp, earn_xp
attributes.lpc (std/living/attributes.lpc)   — STR/DEX/CON/INT/WIS/CHA
boon.lpc (std/living/boon.lpc)               — buff/debuff modifiers on skills and vitals

All of these are inherited by STD_BODY and apply to both players and NPCs.

Skill System — std/living/skills.lpc

Storage Structure

Skills are a nested tree, not a flat mapping:

skills = ([
    "combat": ([
        "level": 3.47,
        "subskills": ([
            "melee": ([
                "level": 2.15,
                "subskills": ([
                    "slashing": ([ "level": 4.82, "subskills": ([]) ]),
                    "piercing": ([ "level": 1.03, "subskills": ([]) ]),
                    "bludgeoning": ([ "level": 2.60, "subskills": ([]) ]),
                    "unarmed": ([ "level": 1.55, "subskills": ([]) ]),
                ]),
            ]),
            "defense": ([
                "level": 1.90,
                "subskills": ([
                    "dodge": ([ "level": 3.21, "subskills": ([]) ]),
                    "parry": ([ "level": 1.10, "subskills": ([]) ]),
                ]),
            ]),
        ]),
    ]),
])

Dot notation addresses nodes: "combat.melee.slashing" navigates the tree.

The integer part of the level is the effective skill level. The fractional part is progress toward the next level (0-99%).

A private find_skill_node(string skill) helper walks the dot-path and returns the live node mapping (or 0). Every read/leaf-mutate function delegates to it — add_skill and remove_skill keep their own walks because they need creation / parent-ref semantics.

Default Skill Tree (from config)

combat
  defense: dodge, parry
  melee: attack, bludgeoning, piercing, slashing, unarmed
social: barter, charm, intimidate, persuade
general: appraise, hide, jump, listen, search, spot, swim

Full dot-path examples: "combat.melee.slashing", "combat.defense.dodge", "social.barter", "general.swim".

Key Functions

FunctionSignatureDescription
add_skillint (string skill, float level)Creates skill at dot-path. Intermediates created at level 1.0. Does not overwrite existing nodes. Returns 1 on success
remove_skillint (string skill)Removes leaf node
has_skillint (string skill)Returns 1 if the node exists, 0 otherwise. Use this for existence checks instead of nullp(query_raw_skill(...))
query_raw_skillfloat (string skill)Raw float level — no flooring, no boon
query_skillfloat (string skill)Raw float level + boon modifier
query_raw_skill_levelfloat (string skill)floor(level) — no boon
query_skill_levelfloat (string skill)floor(level) + query_effective_boon("skill", skill). The function combat math uses
set_skill_levelint (string skill, float level)Sets exact float level. Requires intermediates to already exist; will not create them
query_skillsmapping ()Returns a copy of the entire tree
set_skillsvoid (mapping s)Replaces the tree wholesale (no-op if s is not a mapping)
use_skillint (string skill, mixed mod_adjust)20% chance per call to call improve_skill(skill, mod_adjust). mod_adjust raises the per-call progress cap for low-frequency callers. Auto-creates the skill if missing
improve_skillfloat (string skill, mixed potential_progress)Default cap 0.01 via (: 0.01 :) syntax. See improvement algorithm below
query_skill_progressint (string skill)Fractional part of the level as a 0-99 integer
modify_skill_levelint (string skill, int level)Replace level with an int. Like set_skill_level but accepts int and doesn't enforce a minimum
assure_skillint (string skill)Creates at level 1.0 if missing, tells the player they gained a new skill
wipe_skillsvoid ()Resets to empty mapping
initialize_missing_skillsvoid (mapping, string)Creates any missing skills from a config-shaped tree
adjust_skills_by_npc_levelint (float level)NPC-only: seeds every skill in the tree to level * 3.0 so query_skill_level() is honest for combat math. Errors if called on a user

Use-Based Improvement

Players improve skills transparently by using them — no skill points or manual allocation.

varargs int use_skill(string skill, mixed mod_adjust) {
    if(has_skill(skill)) {
        if(random_float(100.0) < 20.0)          // 20% chance per use
            improve_skill(skill, mod_adjust);
    } else {
        assure_skill(skill);                     // auto-create at level 1.0
    }
}

use_skill() is called throughout the codebase:

  • Combat: attacker trains weapon skill after each swing, defender trains defense skill on every hit attempt.
  • Any system can call use_skill("general.swim") etc. to trigger organic improvement.

mod_adjust raises the per-call progress cap above the 0.01 default. Use it for low-frequency call sites (specific spells, niche abilities) where the default would feel painfully slow. Pattern: tp->use_skill("combat.spell.light", 0.15);. Hot paths (combat swings, defense checks) should omit it. All nodes on the path share the same cap — the bubble-up doesn't tighten it, so pick mod_adjust values that are reasonable for parents too.

Improvement Algorithm

improve_skill(string skill, mixed potential_progress):

  1. Coerces potential_progress to a float — accepts omitted/null (defaults to 0.01 via FluffOS's (: 0.01 :) default-closure syntax, resolved at the call boundary), float (as-is), int (promoted), or a closure (evaluated against this_object()).
  2. Builds the dot-path's chances mapping: each node's weight is (depth+1)*3. For a 3-segment path: leaf 50%, middle 33%, root 17%.
  3. Picks one node via element_of_weighted(chances).
  4. Applies random_float(progress) to that node's level.
  5. If the floored level rises, notifies the player: "You have improved your X skill."

This means using "combat.melee.slashing" can also improve "combat.melee" or "combat" — but with lower probability. Parent skills grow organically as their children are used, but more slowly because they are picked less often. Every node on the path uses the same cap; bubble-up balance lives entirely in the pick weights — that's the lever to tune if balance ever feels off.

Query API Grid

Four query functions form an orthogonal grid over two axes: floored vs raw float, and with-boon vs without-boon.

Raw floatFloored (combat math)
No boonquery_raw_skill(s) → 3.47query_raw_skill_level(s) → 3.0
+ boonquery_skill(s) → 3.47 + boonquery_skill_level(s) → 3.0 + boon

Pick by what the call site actually wants:

  • Hit/damage formulasquery_skill_level(). Combat math.
  • Proc rolls / scaling on fractional progressquery_raw_skill() (e.g. multi-strike in swing()) or query_skill() if buffs should help.
  • Existence checkhas_skill(s) — returns 1 or 0. Do not use nullp(query_raw_skill(...)) for this.

All four functions return null if the skill is not found. NPCs and players read the same storage — there is no NPC shortcut. NPCs are seeded at level * 3.0 at setup time so the storage is honest for both through the same code path.

Boon Integration

The query_skill and query_skill_level variants add the effective boon modifier:

// query_skill_level
return floor(level) + query_effective_boon("skill", skill);
// query_skill
return level + query_effective_boon("skill", skill);

Where query_effective_boon("skill", "combat.melee.slashing") = sum of boons minus sum of curses for that skill class+type. See the buff-system skill for details on applying boons. Use the query_raw_* variants when you explicitly want to bypass boons (e.g. introspection commands, raw progression UI).

Skills Used by the Combat System

SkillWhere Used
"combat.melee"Multi-strike chance in swing() (uses query_skill_level — floored level + boons)
"combat.melee.<type>"Hit chance and damage formulas
"combat.melee.unarmed"Unarmed combat fallback
"combat.defense.dodge"Melee defense in hit chance
"combat.defense.evade"Spell defense in hit chance
"combat.defense"Generic defense reduction in damage formula

XP and Advancement

Per-Living State — std/living/advancement.lpc

VariableTypeDefaultDescription
__levelfloat1.0Current level
__level_modfloat0.0Temporary level modifier (boons / curses)
__xpint0Accumulated experience points

Functions

FunctionSignatureDescription
query_xpint ()Returns __xp
query_levelfloat ()Returns __level
query_effective_levelfloat ()Returns __level + __level_mod. Used throughout combat math
query_tnlfloat ()Returns ADVANCE_D->to_next_level(__level)
set_levelfloat (float l)Sets __level. Sends GMCP Char.Status if user
adjust_levelfloat (float l)Adds delta to __level. Sends GMCP if user
query_level_modfloat ()Returns the temporary modifier
set_level_modfloat (float l)Sets the temporary modifier (routes through `adjust_level_

Content truncated.

When not to use it

  • When working with flat skill systems
  • When skill points or manual allocation are required for progression
  • When attributes are directly modifying skill checks

Limitations

  • Skills are a nested tree, not a flat mapping
  • Attributes are currently independent of skills
  • Progress is tiny by default, requiring mod_adjust for low-frequency callers

How it compares

This skill system features a nested, use-based progression model where skills improve transparently through actions, differing from systems that require manual skill point allocation or flat skill lists.

Compared to similar skills

skills-and-advancement side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
skills-and-advancement (this skill)017dNo flagsAdvanced
azure-eventhub-py12moReviewIntermediate
benchling-integration17moNo flagsAdvanced
latchbio-integration17moReviewAdvanced

Try saying

Example prompts that trigger this skill in your AI assistant.

Search skills

Search the agent skills registry