Advanced skills can no longer be unlocked through proficiency picks

Advanced skills must be unlocked with the pool cost. Only a profession's
own proficiency still unlocks its skill for free. Proficiency picks need
an unlocked skill, locking a skill returns its picks, old characters that
used picks to unlock a skill get it unlocked automatically.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJhXuLD2Z6hv3Wqeq9UL9K
This commit is contained in:
Claude
2026-10-20 20:48:45 +00:00
parent 4c0d7906cd
commit a2e719afd0
6 changed files with 21 additions and 19 deletions
+7 -6
View File
@@ -134,6 +134,7 @@ export default function Creator({ rules: baseRules, user, loadRequest, clearLoad
// Click on pip k (1 = Proficient, 2 = Expertise) of a skill: sets the skill's total pips to k, or one lower if already there.
const clickPip = (s, k) => {
if (!s.usable) return flash('Unlock this advanced skill first.')
const target = s.pips >= k ? k - 1 : k
const wantFree = Math.max(0, target - s.profPip)
if (wantFree - s.freePips > c.profLeft) return flash('No proficiency picks left.')
@@ -263,7 +264,7 @@ export default function Creator({ rules: baseRules, user, loadRequest, clearLoad
<h2>Skills</h2>
<p className="muted">
At most half the attribute per skill. Advanced skills must be unlocked first for {c.unlockCost} points from the pool
(free if your profession grants them). The pool size comes from the rules preset.
(free if your profession grants proficiency in them). The pool size comes from the rules preset.
</p>
<div className="pools">
<div className={`pool ${c.skillLeft < 0 ? 'over' : ''}`}>
@@ -275,7 +276,7 @@ export default function Creator({ rules: baseRules, user, loadRequest, clearLoad
</div>
<p className="small muted">
Proficiency adds +{cr.proficiency_bonus}. Two picks on the same skill make it Expertise (+{cr.expertise_bonus}); a profession proficiency counts as one of them.
Proficiency in an advanced skill unlocks it for free. The talent "Versatile Training" grants 2 more picks.
Proficiency picks only work on skills you can use, so unlock an advanced skill first. The talent "Versatile Training" grants 2 more picks.
</p>
{rules.skill_groups.map((g) => (
<div key={g.id}>
@@ -295,8 +296,8 @@ export default function Creator({ rules: baseRules, user, loadRequest, clearLoad
<span className="small muted">Training</span>
{[1, 2].map((k) => (
<button key={k} className={`pip ${s.pips >= k ? 'on' : ''} ${s.profPip >= k ? 'from-prof' : ''}`}
disabled={s.profPip >= k} onClick={() => clickPip(s, k)}
title={s.profPip >= k ? 'From your profession' : k === 2 ? 'Expertise (uses 2 picks in total)' : 'Proficiency'}
disabled={s.profPip >= k || !s.usable} onClick={() => clickPip(s, k)}
title={!s.usable ? 'Unlock the skill first' : s.profPip >= k ? 'From your profession' : k === 2 ? 'Expertise (uses 2 picks in total)' : 'Proficiency'}
aria-label={`${s.name} proficiency ${k}`}>{s.pips >= k ? '◆' : '◇'}</button>
))}
</div>
@@ -309,8 +310,8 @@ export default function Creator({ rules: baseRules, user, loadRequest, clearLoad
) : (
<div className="stepper">
{s.type === 'advanced' && !s.free && (
<button className="ghost small-btn" title={`Lock again and get ${c.unlockCost} points back`}
onClick={() => setCh((x) => ({ ...x, unlocked: x.unlocked.filter((id) => id !== s.id), skill_points: { ...x.skill_points, [s.id]: 0 } }))}>Lock</button>
<button className="ghost small-btn" title={`Lock again: you get ${c.unlockCost} points back, its points and proficiency picks are returned`}
onClick={() => setCh((x) => ({ ...x, unlocked: x.unlocked.filter((id) => id !== s.id), skill_points: { ...x.skill_points, [s.id]: 0 }, proficiency_picks: { ...x.proficiency_picks, [s.id]: 0 } }))}>Lock</button>
)}
<button onClick={() => setPts(s.points - 1)} aria-label={`${s.name} minus`}>−</button>
<span className="val">{s.points}</span>