dm / commit
feat: skills_add in update_character tool + descriptor inabilities
public/index.html | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/public/index.html b/public/index.html index 65a516f..a9621bb 100644 --- a/public/index.html +++ b/public/index.html @@ -1858,8 +1858,8 @@ const TYPES = [ const DESCRIPTORS = [ { name: 'Appealing', icon: '๐', poolBonus: { speed: 2 }, note: 'Your presence puts others at ease. Trained in pleasant social interactions.', startingSkills: [{ name: 'Pleasant social interactions', rank: 'trained' }] }, - { name: 'Brash', icon: '๐ค', poolBonus: { speed: 2 }, note: 'Act first, think later. Trained in initiative; +2 Speed pool.', - startingSkills: [{ name: 'Initiative', rank: 'trained' }] }, + { name: 'Brash', icon: '๐ค', poolBonus: { speed: 2 }, note: 'Act first, think later. Trained in initiative; inability in patience tasks.', + startingSkills: [{ name: 'Initiative', rank: 'trained' }, { name: 'Tasks requiring patience', rank: 'inability' }] }, { name: 'Calm', icon: '๐ง', poolBonus: { intellect: 2 }, note: 'Unshakeable under pressure. Trained in resisting persuasion and panic.', startingSkills: [{ name: 'Resisting persuasion', rank: 'trained' }] }, { name: 'Charming', icon: '๐ซ', poolBonus: { intellect: 2 }, note: 'Hard to dislike and easy to trust. Trained in persuasion and performance.', @@ -1878,8 +1878,8 @@ const DESCRIPTORS = [ startingSkills: [] }, { name: 'Honorable', icon: '๐ก๏ธ', poolBonus: { might: 2 }, note: 'Trained in pleasant social interactions and detecting lies.', startingSkills: [{ name: 'Pleasant social interactions', rank: 'trained' }, { name: 'Detecting lies', rank: 'trained' }] }, - { name: 'Impulsive', icon: 'โก', poolBonus: { speed: 2 }, note: 'You go first and think later. Trained in initiative and Speed defense.', - startingSkills: [{ name: 'Initiative', rank: 'trained' }, { name: 'Speed defense', rank: 'trained' }] }, + { name: 'Impulsive', icon: 'โก', poolBonus: { speed: 2 }, note: 'You go first and think later. Trained in initiative and Speed defense; inability in careful deliberation.', + startingSkills: [{ name: 'Initiative', rank: 'trained' }, { name: 'Speed defense', rank: 'trained' }, { name: 'Careful deliberation', rank: 'inability' }] }, { name: 'Inquisitive', icon: '๐', poolBonus: { intellect: 4 }, note: 'Trained in learning, geography, and history.', startingSkills: [{ name: 'Learning', rank: 'trained' }, { name: 'Geography', rank: 'trained' }, { name: 'History', rank: 'trained' }] }, { name: 'Intelligent', icon: '๐', poolBonus: { intellect: 2 }, note: 'Trained in one knowledge area and memorization.', @@ -1918,8 +1918,8 @@ const DESCRIPTORS = [ startingSkills: [{ name: 'Running', rank: 'trained' }, { name: 'Escaping', rank: 'trained' }] }, { name: 'Tough', icon: '๐ฆพ', poolBonus: { might: 2 }, note: '+1 Armor; +1 to recovery rolls.', startingSkills: [] }, - { name: 'Vicious', icon: '๐ฉธ', poolBonus: { might: 2 }, note: 'You fight to hurt. Attacks deal 1 additional point of damage.', - startingSkills: [] }, + { name: 'Vicious', icon: '๐ฉธ', poolBonus: { might: 2 }, note: 'You fight to hurt. Attacks deal 1 additional point of damage; inability in pleasant social interactions.', + startingSkills: [{ name: 'Pleasant social interactions', rank: 'inability' }] }, { name: 'Virtuous', icon: 'โญ', poolBonus: { intellect: 2 }, note: 'Trained in resisting temptation and corruption; allies trust you deeply.', startingSkills: [{ name: 'Resisting temptation', rank: 'trained' }] }, { name: 'Weird', icon: '๐', poolBonus: { intellect: 2 }, note: 'Trained in supernatural knowledge; senses nearby strange phenomena.', @@ -2089,10 +2089,11 @@ const UPDATE_TOOL = { cyphers_remove: { type: 'array', items: { type: 'string' }, description: 'Names of cyphers used or lost.' }, equipment_add: { type: 'array', items: { type: 'string' }, description: 'Equipment gained.' }, equipment_remove: { type: 'array', items: { type: 'string' }, description: 'Equipment lost.' }, + skills_add: { type: 'array', items: { type: 'object', properties: { name: { type: 'string' }, rank: { type: 'string', enum: ['trained','specialized','inability'] } }, required: ['name','rank'] }, description: 'Skills to grant or upgrade. Use to reflect training earned during play. Rank: trained, specialized, or inability. Two trained in the same skill auto-promotes to specialized.' }, tier_advance: { type: 'boolean', description: 'True if character advances a Tier.' }, reason: { type: 'string', description: 'Brief reason for the change.' }, }, - required: ['might_damage','speed_damage','intellect_damage','might_restore','speed_restore','intellect_restore','xp_gain','shins_change','cyphers_add','cyphers_remove','equipment_add','equipment_remove','tier_advance','reason'], + required: ['might_damage','speed_damage','intellect_damage','might_restore','speed_restore','intellect_restore','xp_gain','shins_change','cyphers_add','cyphers_remove','equipment_add','equipment_remove','skills_add','tier_advance','reason'], }, }; @@ -2684,6 +2685,24 @@ function applyStatUpdate(update) { }); } + // Skills + if (update.skills_add?.length) { + const rankOrder = { inability: 0, trained: 1, specialized: 2 }; + update.skills_add.forEach(({ name, rank }) => { + if (!name || !rank) return; + const existing = (c.skills || []).find(s => s.name.toLowerCase() === name.toLowerCase()); + if (existing) { + if (existing.rank === 'trained' && rank === 'trained') { + existing.rank = 'specialized'; + } else if (rankOrder[rank] > rankOrder[existing.rank]) { + existing.rank = rank; + } + } else { + c.skills = [...(c.skills || []), { name, rank }]; + } + }); + } + // Equipment if (update.equipment_add?.length) c.equipment.push(...update.equipment_add); if (update.equipment_remove?.length) {