@archivist-gg/dnd5e 0.3.28 → 0.3.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/dist/background/background.codec.js +1 -1
  2. package/dist/background/background.parser.js +1 -1
  3. package/dist/background/background.schema.js +1 -1
  4. package/dist/{chunk-WXL7ABDO.js → chunk-3CHDDX6S.js} +1 -1
  5. package/dist/chunk-4F5F5A3X.js +1 -0
  6. package/dist/chunk-4N2UVV4P.js +1 -0
  7. package/dist/{chunk-OV4FG4KO.js → chunk-5NGQM3TO.js} +1 -1
  8. package/dist/{chunk-ADX7435T.js → chunk-655UY3MP.js} +1 -1
  9. package/dist/{chunk-IR5BA2DZ.js → chunk-65VM2BAA.js} +1 -1
  10. package/dist/{chunk-5QDSAZG6.js → chunk-6GFBSYE3.js} +1 -1
  11. package/dist/{chunk-J27N3KUE.js → chunk-6WRU5I75.js} +1 -1
  12. package/dist/{chunk-E4E6YEN6.js → chunk-7S4VMK3R.js} +1 -1
  13. package/dist/{chunk-EON7T2SN.js → chunk-7TH4WPSU.js} +1 -1
  14. package/dist/{chunk-EBFLUJIW.js → chunk-A25HLCQ7.js} +1 -1
  15. package/dist/{chunk-M2UA2FAK.js → chunk-FC4OPNZM.js} +1 -1
  16. package/dist/{chunk-7HOOPNF5.js → chunk-FDWQ6P7Z.js} +1 -1
  17. package/dist/{chunk-RR26E7LH.js → chunk-HI2BXTGB.js} +1 -1
  18. package/dist/{chunk-J6FIBUI4.js → chunk-HPBEMAM6.js} +1 -1
  19. package/dist/{chunk-NB4QWMF5.js → chunk-I6J6ZGZB.js} +1 -1
  20. package/dist/{chunk-GKNOCYDT.js → chunk-IK7XM6BW.js} +1 -1
  21. package/dist/{chunk-XFFFTR6O.js → chunk-IOFGBEGA.js} +1 -1
  22. package/dist/{chunk-U7BPRRY5.js → chunk-JLW7XFFL.js} +1 -1
  23. package/dist/{chunk-XCF5R5XX.js → chunk-JOLGJYDS.js} +1 -1
  24. package/dist/{chunk-NU6WP4P5.js → chunk-KGRRQ4US.js} +1 -1
  25. package/dist/chunk-LXISMSPG.js +1 -0
  26. package/dist/{chunk-2OVDSMPY.js → chunk-MJJQQI44.js} +1 -1
  27. package/dist/chunk-NTJPBLI5.js +1 -0
  28. package/dist/{chunk-D2BXAFOL.js → chunk-Q2U7MWMC.js} +1 -1
  29. package/dist/{chunk-AFEWQFQZ.js → chunk-QCCA46KM.js} +1 -1
  30. package/dist/{chunk-C4T6BUSP.js → chunk-RI4YYU75.js} +1 -1
  31. package/dist/{chunk-R2YRQM7G.js → chunk-TGZ6WQUX.js} +1 -1
  32. package/dist/{chunk-KZFTTAFN.js → chunk-XB6ACICG.js} +1 -1
  33. package/dist/{chunk-PFQPP77Q.js → chunk-YDN6GD2B.js} +1 -1
  34. package/dist/{chunk-VY5ZEOLG.js → chunk-Z362RQTB.js} +1 -1
  35. package/dist/{chunk-VHIE2KYQ.js → chunk-ZK3P4RSE.js} +1 -1
  36. package/dist/{chunk-CCFIINBA.js → chunk-ZKDHCDJ2.js} +1 -1
  37. package/dist/chunk-ZYMWQ7PG.js +1 -0
  38. package/dist/{chunk-KGZXAAFN.js → chunk-ZZ6QHLWX.js} +1 -1
  39. package/dist/class/class.codec.js +1 -1
  40. package/dist/class/class.parser.js +1 -1
  41. package/dist/class/class.schema.js +1 -1
  42. package/dist/class/class.slug.d.ts +1 -0
  43. package/dist/class/class.slug.js +1 -1
  44. package/dist/feat/feat.codec.js +1 -1
  45. package/dist/feat/feat.parser.js +1 -1
  46. package/dist/feat/feat.schema.d.ts +12 -0
  47. package/dist/feat/feat.schema.js +1 -1
  48. package/dist/index.js +6 -6
  49. package/dist/monster/monster.parser.js +1 -1
  50. package/dist/monster/monster.schema.js +1 -1
  51. package/dist/optional-feature/optional-feature.codec.js +1 -1
  52. package/dist/optional-feature/optional-feature.parser.js +1 -1
  53. package/dist/optional-feature/optional-feature.schema.d.ts +13 -0
  54. package/dist/optional-feature/optional-feature.schema.js +1 -1
  55. package/dist/pc/pc.additional-spells.js +1 -1
  56. package/dist/pc/pc.amount-bindings.d.ts +1 -0
  57. package/dist/pc/pc.amount-bindings.js +1 -1
  58. package/dist/pc/pc.decision-engine.js +1 -1
  59. package/dist/pc/pc.entry-overrides.js +1 -1
  60. package/dist/pc/pc.equipment.js +1 -1
  61. package/dist/pc/pc.feature-effects.d.ts +21 -1
  62. package/dist/pc/pc.feature-effects.js +1 -1
  63. package/dist/pc/pc.granted-spends.d.ts +2 -0
  64. package/dist/pc/pc.infusions.js +1 -1
  65. package/dist/pc/pc.item-effects.d.ts +1 -0
  66. package/dist/pc/pc.item-effects.js +1 -1
  67. package/dist/pc/pc.member-choices.js +1 -1
  68. package/dist/pc/pc.pools.js +1 -1
  69. package/dist/pc/pc.proficiencies.js +1 -1
  70. package/dist/pc/pc.recalc.js +1 -1
  71. package/dist/pc/pc.resolver.js +1 -1
  72. package/dist/pc/pc.resource-seed.js +1 -1
  73. package/dist/pc/pc.resources.js +1 -1
  74. package/dist/pc/pc.rest.js +1 -1
  75. package/dist/pc/pc.schema.d.ts +1 -1
  76. package/dist/pc/pc.spellcasting.js +1 -1
  77. package/dist/pc/pc.types.d.ts +36 -0
  78. package/dist/race/race.codec.js +1 -1
  79. package/dist/race/race.parser.js +1 -1
  80. package/dist/race/race.schema.js +1 -1
  81. package/dist/schemas/choice-schema.js +1 -1
  82. package/dist/schemas/feature-effect-schema.d.ts +12 -0
  83. package/dist/schemas/feature-effect-schema.js +1 -1
  84. package/dist/schemas/feature-schema.js +1 -1
  85. package/dist/schemas/resource-schema.d.ts +1 -0
  86. package/dist/schemas/resource-schema.js +1 -1
  87. package/dist/spell/spell.access.js +1 -1
  88. package/dist/subclass/subclass.codec.js +1 -1
  89. package/dist/subclass/subclass.parser.js +1 -1
  90. package/dist/subclass/subclass.schema.js +1 -1
  91. package/dist/types/feature-effect.d.ts +10 -0
  92. package/dist/types/resource.d.ts +1 -0
  93. package/package.json +1 -1
  94. package/dist/chunk-2GZM7FCD.js +0 -1
  95. package/dist/chunk-4FTTUZXM.js +0 -1
  96. package/dist/chunk-53SHSS4M.js +0 -1
  97. package/dist/chunk-CAPYNIGK.js +0 -1
  98. package/dist/chunk-MMDUUEFA.js +0 -1
@@ -1 +1 @@
1
- import{backgroundCodec}from"../chunk-WXL7ABDO.js";import"../chunk-IR5BA2DZ.js";import"../chunk-XFFFTR6O.js";import"../chunk-TKIEPC6F.js";import"../chunk-VHIE2KYQ.js";import"../chunk-EON7T2SN.js";import"../chunk-I26FHSI6.js";export{backgroundCodec};
1
+ import{backgroundCodec}from"../chunk-3CHDDX6S.js";import"../chunk-65VM2BAA.js";import"../chunk-IOFGBEGA.js";import"../chunk-TKIEPC6F.js";import"../chunk-ZK3P4RSE.js";import"../chunk-7TH4WPSU.js";import"../chunk-I26FHSI6.js";export{backgroundCodec};
@@ -1 +1 @@
1
- import{parseBackground}from"../chunk-IR5BA2DZ.js";import"../chunk-XFFFTR6O.js";import"../chunk-TKIEPC6F.js";import"../chunk-VHIE2KYQ.js";import"../chunk-EON7T2SN.js";import"../chunk-I26FHSI6.js";export{parseBackground};
1
+ import{parseBackground}from"../chunk-65VM2BAA.js";import"../chunk-IOFGBEGA.js";import"../chunk-TKIEPC6F.js";import"../chunk-ZK3P4RSE.js";import"../chunk-7TH4WPSU.js";import"../chunk-I26FHSI6.js";export{parseBackground};
@@ -1 +1 @@
1
- import{backgroundEntitySchema,langProfSchema}from"../chunk-XFFFTR6O.js";import"../chunk-TKIEPC6F.js";import"../chunk-VHIE2KYQ.js";import"../chunk-EON7T2SN.js";import"../chunk-I26FHSI6.js";export{backgroundEntitySchema,langProfSchema};
1
+ import{backgroundEntitySchema,langProfSchema}from"../chunk-IOFGBEGA.js";import"../chunk-TKIEPC6F.js";import"../chunk-ZK3P4RSE.js";import"../chunk-7TH4WPSU.js";import"../chunk-I26FHSI6.js";export{backgroundEntitySchema,langProfSchema};
@@ -1 +1 @@
1
- import{parseBackground}from"./chunk-IR5BA2DZ.js";import yaml from"js-yaml";var backgroundCodec={parse(doc){return parseBackground(doc.body)},serialize(entity){return yaml.dump(entity,{lineWidth:-1,sortKeys:false})}};export{backgroundCodec};
1
+ import{parseBackground}from"./chunk-65VM2BAA.js";import yaml from"js-yaml";var backgroundCodec={parse(doc){return parseBackground(doc.body)},serialize(entity){return yaml.dump(entity,{lineWidth:-1,sortKeys:false})}};export{backgroundCodec};
@@ -0,0 +1 @@
1
+ function bareSlug(ref){if(typeof ref!=="string")return"";const m=ref.match(/^\[\[(.+?)\]\]$/);return(m?m[1]:ref).toLowerCase()}function baseClassName(ref){const bare=bareSlug(ref);const p=bare.split("_");return p.length>=3?p.slice(2).join("_"):p[p.length-1]}function matchesSpellClass(word,classSlug){if(word===void 0)return true;const w=word.trim().toLowerCase().replace(/\s+/g,"-");if(w==="any")return true;if(!classSlug)return false;return baseClassName(w)===baseClassName(classSlug)}export{bareSlug,baseClassName,matchesSpellClass};
@@ -0,0 +1 @@
1
+ import{normalizeRollScope}from"./chunk-FOLHTMSC.js";import{toProfSlug}from"./chunk-VTQ4RWEG.js";import{memberSpellTargets}from"./chunk-6WRU5I75.js";import{heldPicks}from"./chunk-7S4VMK3R.js";import{CONDITION_SLUGS}from"./chunk-KM75CC6Q.js";import{warnOnce}from"./chunk-DZITM5AG.js";import{bareEntitySlug}from"./chunk-63YJPWTM.js";import{normalizeAbility}from"./chunk-EVT7MGAC.js";function emptyFeatureEffectTotals(){return{initiative_bonus:0,initiative_terms:[],initiative_amount_terms:[],skill_bonus_terms:[],save_bonus_terms:[],half_proficiency_terms:[],hp_per_level_bonus:0,hp_per_level_terms:[],speed_walk_bonus:0,speed_walk_terms:[],speed_terms:[],ignore_armor_strength:[],speed_walk_set:0,attunement_set:0,ability_bonus:{},ability_bonus_terms:[],senses:{darkvision:0,blindsight:0,tremorsense:0,truesight:0},ac_terms:[],resistances:[],immunities:[],vulnerabilities:[],condition_immunities:[],proficiencies:{skills:[],skillExpertise:[],tools:[],languages:[],saves:[],armor:[],weapons:[]},weaponAbilities:[],rollModifiers:[],saveOutcomes:[],critRange:20,conditionalCrits:[],extraAttack:0,scopedExtraAttacks:[],attackNotes:[],damageBonuses:[],spellDamageBonuses:[],damageRollOptions:[],spell_bonus_terms:[],cantrip_bonus_terms:[],applied_conditions:[]}}function pushUnique(list,value){const key=value.trim().toLowerCase();if(!key)return;if(!list.some(v=>v.trim().toLowerCase()===key))list.push(value.trim())}function pushDefenseGrant(list,value,source,condition,item){var _a;const key=value.trim().toLowerCase();if(!key)return;const existing=list.find(g=>g.value.trim().toLowerCase()===key);if(existing){if(!existing.sources.includes(source))existing.sources.push(source);if(!existing.condition&&condition)existing.condition=condition;if(item)mergeDefenseItems((_a=existing.items)!=null?_a:existing.items=[],[item]);return}list.push({value:value.trim(),sources:[source],...condition?{condition}:{},...item?{items:[item]}:{}})}function mergeDefenseItems(into,from){for(const it of from)if(!into.some(x=>x.index===it.index))into.push({...it})}function ownerItem(owner,label){return(owner==null?void 0:owner.kind)==="item"?{index:owner.index,name:label}:void 0}var NAMED_COLUMN=/^column\(\s*'([^']+)'\s*\)$/;function foldsNow(rf,activeBuffs){if(rf.feature.activatable!==true)return true;const id=rf.feature.id;return!!id&&activeBuffs.has(id)}function assembleEffectFeatures(resolved){var _a,_b,_c,_d,_e,_f,_g,_h,_i,_j;const activeBuffs=new Set((_b=(_a=resolved.state)==null?void 0:_a.active_buffs)!=null?_b:[]);const featureIds=new Set(((_c=resolved.features)!=null?_c:[]).map(f=>f.feature.id).filter(id=>!!id));const aliases=[];for(const pool of(_d=resolved.pools)!=null?_d:[]){for(const entry of[...(_e=pool.selected)!=null?_e:[],...(_f=pool.grants)!=null?_f:[]]){if(activeBuffs.has(entry.slug))continue;const bare=bareEntitySlug(entry.slug);for(const stored of activeBuffs){if(featureIds.has(stored))continue;if(bareEntitySlug(stored)===bare){aliases.push(entry.slug);break}}}}for(const a of aliases)activeBuffs.add(a);const buffFeatures=[];const pushBoon=(item,pool)=>{var _a2,_b2,_c2,_d2,_e2,_f2,_g2,_h2,_i2,_j2,_k;const e=item.entity;if(!e||item.itemBound===true||((_b2=(_a2=e.effects)==null?void 0:_a2.length)!=null?_b2:0)===0)return;const block=(_f2=(_e2=(_d2=(_c2=resolved.classes)==null?void 0:_c2[pool.classIndex])==null?void 0:_d2.choices)==null?void 0:_e2[pool.anchorLevel])!=null?_f2:{};const spellTargets=memberSpellTargets(e,id=>{var _a3;return block[`${pool.id}:${(_a3=item.key)!=null?_a3:item.slug}:${id}`]});buffFeatures.push({feature:{id:item.slug,name:e.name,activatable:(_g2=e.activatable)!=null?_g2:false,effects:e.effects},source:{kind:"class",slug:(_k=(_j2=(_i2=(_h2=resolved.classes)==null?void 0:_h2[pool.classIndex])==null?void 0:_i2.entity)==null?void 0:_j2.slug)!=null?_k:pool.id,level:pool.anchorLevel},...spellTargets?{spellTargets}:{},poolMember:true})};for(const pool of(_g=resolved.pools)!=null?_g:[]){for(const sel of heldPicks(pool))pushBoon(sel,pool);for(const g of(_h=pool.grants)!=null?_h:[])pushBoon(g,pool)}return{features:[...(_i=resolved.features)!=null?_i:[],...buffFeatures,...(_j=resolved.itemFeatures)!=null?_j:[]],activeBuffs}}function foldsOnSelf(eff){if(eff.subject===void 0||eff.subject==="self")return true;warnOnce(eff.subject,`archivist: unrecognised effect subject "${eff.subject}" (only "self" folds)`);return false}function selfEffectsOf(f){var _a;return((_a=f.effects)!=null?_a:[]).filter(foldsOnSelf)}function computeFeatureEffects(features,opts){var _a,_b,_c;const out=emptyFeatureEffectTotals();for(const rf of features){if(!foldsNow(rf,(_a=opts==null?void 0:opts.activeBuffs)!=null?_a:new Set))continue;const level=(_b=opts==null?void 0:opts.levelFor)==null?void 0:_b.call(opts,rf.source);for(const eff of selfEffectsOf(rf.feature)){const effect=columnScaledRider(eff,rf,level,opts==null?void 0:opts.tableDiceFor,opts==null?void 0:opts.tableCellFor);if(effect)applyEffect(out,effect,(_c=rf.feature.name)!=null?_c:"Feature",level,rf.source,rf.spellTargets,rf)}}return out}function classifyProficiencyEffect(eff){if(eff.kind!=="proficiency")return null;const raw=eff.value;const expertise=eff.expertise===true;switch(eff.proficiency_type){case"skill":return{bucket:"skills",value:toProfSlug(raw),raw,expertise};case"tool":return{bucket:"tools",value:toProfSlug(raw),raw,expertise};case"language":return{bucket:"languages",value:toProfSlug(raw),raw,expertise};case"armor":return{bucket:"armor",value:raw.toLowerCase(),raw,expertise};case"weapon":return{bucket:"weapons",value:raw.toLowerCase(),raw,expertise};default:{const ab=normalizeAbility(raw);return ab?{bucket:"saves",value:ab,raw,expertise}:null}}}function collectProficiencyEffectGrants(features,activeBuffs){const out={skills:[],tools:[],languages:[],saves:[],armor:[],weapons:[]};for(const rf of features){if(!foldsNow(rf,activeBuffs))continue;for(const eff of selfEffectsOf(rf.feature)){const c=classifyProficiencyEffect(eff);if(!c)continue;out[c.bucket].push({value:c.value,raw:c.raw,sourceKind:rf.source.kind,sourceSlug:rf.source.slug,...c.expertise?{expertise:true}:{}})}}return out}function scaled(base,key,scalesAt,level){if(level===void 0||!(scalesAt==null?void 0:scalesAt.length))return base;let best=base;let bestLevel=-1;for(const step of scalesAt){if(step.level>level||step.level<=bestLevel)continue;const v=step[key];if(typeof v!=="number")continue;best=v;bestLevel=step.level}return best}function columnScaledRider(eff,rf,level,tableDiceFor,tableCellFor){var _a;if(eff.kind!=="damage-bonus")return eff;const named=NAMED_COLUMN.exec(eff.amount.trim());if(named){const cell=(_a=tableCellFor==null?void 0:tableCellFor(rf.source,named[1]))!=null?_a:null;return cell?{...eff,amount:cell}:null}if(level===void 0||!tableDiceFor)return eff;const src=rf.source;const column=rf.feature.name;if(src.kind!=="class"&&src.kind!=="subclass"||!column)return eff;const atGain=tableDiceFor(src,column,src.level);if(!atGain||atGain.toLowerCase()!==eff.amount.trim().toLowerCase())return eff;const now=tableDiceFor(src,column,level);return now?{...eff,amount:now}:eff}function conditionSlugOf(name){const key=name.trim().toLowerCase();return CONDITION_SLUGS.includes(key)?key:null}function riderScope(appliesTo){if(appliesTo===void 0||appliesTo==="all"||appliesTo==="spell")return void 0;return Array.isArray(appliesTo)?[...appliesTo]:[appliesTo]}function extraAttackSourceOf(rf,label,level,owner,scope){const source=owner!=null?owner:rf==null?void 0:rf.source;if(!source)return void 0;return{name:label,source,...level!==void 0?{level}:{},...(rf==null?void 0:rf.poolMember)?{poolMember:true}:{},...(rf==null?void 0:rf.feature.activatable)===true?{switched:true}:{},...scope?{scope}:{}}}function applyEffect(out,eff,label,level,owner,targets,rf){var _a,_b,_c,_d,_e,_f,_g,_h,_i,_j,_k,_l,_m,_n,_o,_p,_q,_r,_s,_t,_u,_v;switch(eff.kind){case"initiative-bonus":if(typeof eff.value==="number"){out.initiative_bonus+=eff.value;out.initiative_terms.push({label,value:eff.value})}else if(typeof eff.amount==="string"){out.initiative_amount_terms.push({label,amount:eff.amount,...owner?{owner}:{}})}break;case"skill-bonus":out.skill_bonus_terms.push({skills:eff.skills.map(toProfSlug),ability:eff.ability,minimum:(_a=eff.minimum)!=null?_a:0,label});break;case"save-bonus":out.save_bonus_terms.push({saves:[...(_b=eff.saves)!=null?_b:[]],ability:eff.ability,minimum:(_c=eff.minimum)!=null?_c:0,...eff.inactive_while?{inactiveWhile:eff.inactive_while}:{},label});break;case"half-proficiency":out.half_proficiency_terms.push({skills:((_d=eff.skills)!=null?_d:[]).map(toProfSlug),round:(_e=eff.round)!=null?_e:"down",label});break;case"hp-per-level-bonus":out.hp_per_level_bonus+=eff.value;out.hp_per_level_terms.push({label,value:eff.value});break;case"speed-bonus":{const gate=eff.inactive_while===void 0?void 0:[].concat(eff.inactive_while);const qualifiers={...eff.condition?{condition:eff.condition}:{},...gate?{inactiveWhile:gate}:{}};if(eff.equal_to==="walk"){out.speed_terms.push({mode:eff.mode,label,value:0,set:false,equalsWalk:true,...qualifiers});break}const value=scaled((_f=eff.value)!=null?_f:0,"value",eff.scales_at,level);out.speed_terms.push({mode:eff.mode,label,value,set:eff.set===true,...qualifiers});if(eff.mode==="walk"&&!gate){if(eff.set)out.speed_walk_set=Math.max(out.speed_walk_set,value);else{out.speed_walk_bonus+=value;out.speed_walk_terms.push({label,value})}}break}case"speed-rule":if(eff.flag==="ignore-armor-strength")out.ignore_armor_strength.push(label);break;case"attunement-limit":{out.attunement_set=Math.max(out.attunement_set,scaled(eff.value,"value",eff.scales_at,level));break}case"sense":out.senses[eff.type]=Math.max(out.senses[eff.type],eff.range);break;case"resistance":pushDefenseGrant(out.resistances,eff.damage_type,label,eff.condition,ownerItem(owner,label));break;case"immunity":pushDefenseGrant(out.immunities,eff.damage_type,label,eff.condition,ownerItem(owner,label));break;case"vulnerability":pushDefenseGrant(out.vulnerabilities,eff.damage_type,label,eff.condition,ownerItem(owner,label));break;case"immune-condition":if(!eff.while)pushDefenseGrant(out.condition_immunities,eff.condition,label,void 0,ownerItem(owner,label));else if((owner==null?void 0:owner.kind)==="item")pushDefenseGrant(out.condition_immunities,eff.condition,label,eff.while,ownerItem(owner,label));break;case"proficiency":{const c=classifyProficiencyEffect(eff);if(!c)break;if(c.bucket==="saves"){pushUnique(out.proficiencies.saves,c.value)}else{pushUnique(out.proficiencies[c.bucket],c.value)}if(c.expertise&&c.bucket==="skills")pushUnique(out.proficiencies.skillExpertise,c.value);break}case"ac-bonus":out.ac_terms.push({value:eff.value,requires_armor:eff.requires_armor===true,label,condition:eff.condition});break;case"weapon-ability":{if(eff.ability!=="spellcasting"){const w=eff.weapons;if(w==="pact-weapon"){out.weaponAbilities.push({ability:eff.ability,pactWeapon:true});break}const weaponSlugs=!w||w==="chosen"?void 0:Array.isArray(w)?w.map(bareEntitySlug):[bareEntitySlug(w)];out.weaponAbilities.push({ability:eff.ability,weaponSlugs})}break}case"roll-modifier":{const rolls=eff.roll==="any"?["ability-check","saving-throw","attack"]:[eff.roll];const scopes=(_g=normalizeRollScope(eff.scope,rolls[0]))!=null?_g:[eff.scope];const spellClass=eff.roll==="attack"?((_h=eff.spell_class)==null?void 0:_h.trim())||void 0:void 0;for(const roll of rolls)for(const scope of scopes)out.rollModifiers.push({mode:eff.mode,roll,scope,condition:eff.condition,label,...spellClass?{spellClass}:{}});break}case"spell-bonus":out.spell_bonus_terms.push({label,saveDC:(_i=eff.save_dc)!=null?_i:0,attack:(_j=eff.attack)!=null?_j:0,...((_k=eff.spell_class)==null?void 0:_k.trim())?{spellClass:eff.spell_class.trim()}:{}});break;case"extra-cantrips":out.cantrip_bonus_terms.push({label,count:eff.count,...((_l=eff.class)==null?void 0:_l.trim())?{class:eff.class.trim()}:{},...owner?{owner}:{}});break;case"apply-condition":{if((rf==null?void 0:rf.feature.activatable)!==true||!rf.feature.id||rf.source.kind==="item")break;const condition=conditionSlugOf(eff.condition);if(!condition){warnOnce(`apply-condition:${eff.condition}`,`archivist: "${label}" gives "${eff.condition}", which is not one of the 14 conditions; nothing applied`);break}out.applied_conditions.push({condition,label,buffKey:rf.feature.id});break}case"save-outcome":out.saveOutcomes.push({ability:eff.ability==="any"?void 0:eff.ability,on_success:eff.on_success,on_failure:eff.on_failure,appliesTo:(_m=eff.applies_to)!=null?_m:void 0,condition:eff.condition,label});break;case"crit-range":if(((_n=eff.applies_to)!=null?_n:"weapon")==="spell")break;if((_o=eff.condition)==null?void 0:_o.trim())out.conditionalCrits.push({minRoll:eff.min_roll,condition:eff.condition.trim(),source:label});else out.critRange=Math.min(out.critRange,eff.min_roll);break;case"extra-attack":{const count=scaled(eff.count,"count",eff.scales_at,level);const scope=riderScope(eff.applies_to);const source=extraAttackSourceOf(rf,label,level,owner,scope);if(scope)out.scopedExtraAttacks.push({count,scope,...source?{source}:{}});else if(count>out.extraAttack){out.extraAttack=count;if(source)out.extraAttackSource=source}}break;case"reroll-damage":{const qualifiers=[eff.once_per_die?"once/die":"",(_q=(_p=eff.condition)==null?void 0:_p.trim())!=null?_q:""].filter(q=>q!=="");out.attackNotes.push(`Reroll ${eff.max_reroll}s${qualifiers.length?` (${qualifiers.join(", ")})`:""}`)}break;case"attack-rule":if(eff.flag==="no-ranged-in-melee-disadvantage")out.attackNotes.push("No disadvantage firing in melee");break;case"damage-roll-option":{const scope=eff.applies_to===void 0?void 0:[].concat(eff.applies_to);out.damageRollOptions.push({mode:eff.mode,...eff.value!==void 0?{value:eff.value}:{},...eff.two_handed?{twoHanded:true}:{},...eff.once_per_turn?{oncePerTurn:true}:{},...((_r=eff.condition)==null?void 0:_r.trim())?{condition:eff.condition.trim()}:{},source:label,...scope?{scope}:{}});break}case"damage-bonus":if(((_s=eff.applies_to)!=null?_s:"weapon")!=="spell"){const scope=riderScope(eff.applies_to);out.damageBonuses.push({amount:eff.amount,damage_type:eff.damage_type,source:label,...eff.condition?{condition:eff.condition}:{},...scope?{scope}:{},...owner?{owner}:{}})}if(eff.applies_to==="spell"||eff.applies_to==="all"){const spellScope=(_t=eff.spell_scope)!=null?_t:eff.applies_to==="all"?{}:void 0;out.spellDamageBonuses.push({amount:eff.amount,damage_type:eff.damage_type,source:label,...eff.condition?{condition:eff.condition}:{},...owner?{owner}:{},...targets?{targets}:{},...spellScope?{scope:spellScope}:{}})}break;case"ability-score-increase":if(eff.abilities==="chosen")break;for(const ab of eff.abilities){out.ability_bonus[ab]=((_u=out.ability_bonus[ab])!=null?_u:0)+eff.amount;((_v=out.ability_bonus_terms)!=null?_v:out.ability_bonus_terms=[]).push({ability:ab,source:label,amount:eff.amount})}break;default:break}}export{emptyFeatureEffectTotals,pushDefenseGrant,mergeDefenseItems,foldsNow,assembleEffectFeatures,foldsOnSelf,selfEffectsOf,computeFeatureEffects,classifyProficiencyEffect,collectProficiencyEffectGrants};
@@ -1 +1 @@
1
- import{optionalFeatureEntitySchema}from"./chunk-U7BPRRY5.js";import{parseYaml}from"@archivist-gg/core";function parseOptionalFeature(source){const raw=parseYaml(source,["name","slug","feature_type"]);if(!raw.success)return raw;const result=optionalFeatureEntitySchema.safeParse({edition:"2014",...raw.data});if(!result.success){return{success:false,error:`optional-feature schema validation failed: ${result.error.message}`}}return{success:true,data:result.data}}export{parseOptionalFeature};
1
+ import{optionalFeatureEntitySchema}from"./chunk-JLW7XFFL.js";import{parseYaml}from"@archivist-gg/core";function parseOptionalFeature(source){const raw=parseYaml(source,["name","slug","feature_type"]);if(!raw.success)return raw;const result=optionalFeatureEntitySchema.safeParse({edition:"2014",...raw.data});if(!result.success){return{success:false,error:`optional-feature schema validation failed: ${result.error.message}`}}return{success:true,data:result.data}}export{parseOptionalFeature};
@@ -1 +1 @@
1
- import{poolGrantSchema,selectionPoolSchema,tabDeclSchema}from"./chunk-GCYUCIDN.js";import{casterTypeEnum}from"./chunk-X22SISGM.js";import{featureSchema}from"./chunk-M2UA2FAK.js";import{resourceSchema}from"./chunk-CCFIINBA.js";import{startingEquipmentEntrySchema,startingGoldSchema}from"./chunk-TKIEPC6F.js";import{choiceSchema}from"./chunk-VHIE2KYQ.js";import{additionalSpellsEntrySchema,imageField,progressionSchema}from"./chunk-I26FHSI6.js";import{z}from"zod";var abilityEnum=z.enum(["str","dex","con","int","wis","cha"]);var skillEnum=z.enum(["acrobatics","animal-handling","arcana","athletics","deception","history","insight","intimidation","investigation","medicine","nature","perception","performance","persuasion","religion","sleight-of-hand","stealth","survival"]);var armorCategoryEnum=z.enum(["light","medium","heavy","shield"]);var weaponCategoryEnum=z.enum(["simple","martial"]);var hitDieEnum=z.enum(["d6","d8","d10","d12"]);var editionEnum=z.enum(["2014","2024"]);var weaponProficiencySchema=z.object({fixed:z.array(z.string()).optional(),categories:z.array(weaponCategoryEnum).optional(),conditional:z.array(z.object({category:weaponCategoryEnum,where_property:z.array(z.string()).nonempty()})).optional()}).refine(w=>{var _a,_b,_c,_d,_e,_f;return((_b=(_a=w.fixed)==null?void 0:_a.length)!=null?_b:0)+((_d=(_c=w.categories)==null?void 0:_c.length)!=null?_d:0)+((_f=(_e=w.conditional)==null?void 0:_e.length)!=null?_f:0)>0},{message:"weapon proficiency must declare at least one of fixed/categories/conditional"});var toolProficiencySchema=z.object({fixed:z.array(z.string()).optional(),choice:z.object({count:z.number().int().positive(),from:z.array(z.string()).nonempty()}).optional()}).refine(t=>{var _a,_b;return((_b=(_a=t.fixed)==null?void 0:_a.length)!=null?_b:0)>0||t.choice!==void 0},{message:"tool proficiency must declare fixed or choice"});var spellcastingSchema=z.object({caster_type:casterTypeEnum,ability:abilityEnum,preparation:z.enum(["known","prepared"]),spell_list:z.string().min(1)});var weaponMasterySchema=z.object({starting_count:z.number().int().nonnegative().optional(),scaling:z.record(z.string(),z.number().int().nonnegative()).optional()});var classTableRowSchema=z.object({prof_bonus:z.number().int().positive(),columns:z.record(z.string(),z.union([z.string(),z.number()])).optional(),feature_ids:z.array(z.string())});var classEntitySchema=z.object({slug:z.string().min(1),name:z.string().min(1),edition:editionEnum,source:z.string().min(1),description:z.string(),hit_die:hitDieEnum,primary_abilities:z.array(abilityEnum).nonempty(),standard_array:z.strictObject({str:z.number().int(),dex:z.number().int(),con:z.number().int(),int:z.number().int(),wis:z.number().int(),cha:z.number().int()}).optional(),saving_throws:z.array(abilityEnum).length(2),proficiencies:z.object({armor:z.array(armorCategoryEnum),weapons:weaponProficiencySchema,tools:toolProficiencySchema.optional()}),skill_choices:z.object({count:z.number().int().positive(),from:z.array(skillEnum).nonempty()}),choices:z.array(choiceSchema).optional(),starting_equipment:z.array(startingEquipmentEntrySchema),starting_gold:startingGoldSchema.optional(),spellcasting:spellcastingSchema.nullable(),subclass_level:z.number().int().positive(),subclass_feature_name:z.string().min(1),weapon_mastery:weaponMasterySchema.nullable(),epic_boon_level:z.number().int().positive().nullable(),table:z.record(z.string(),classTableRowSchema),features_by_level:z.record(z.string(),z.array(featureSchema)),resources:z.array(resourceSchema),selection_pools:z.array(selectionPoolSchema).optional(),pool_grants:z.array(poolGrantSchema).optional(),tabs:z.array(tabDeclSchema).optional(),rendering_hint:z.string().optional(),has_fluff:z.boolean().optional(),has_fluff_images:z.boolean().optional(),table_col_labels:z.array(z.string().min(1)).optional(),starting_equipment_additional_from_background:z.boolean().optional(),multiclassing:z.unknown().optional(),cantrip_progression:z.array(z.number()).optional(),prepared_spells:z.string().min(1).optional(),prepared_spells_change:z.string().min(1).optional(),prepared_spells_progression:z.array(z.number()).optional(),spells_known_progression:z.array(z.number()).optional(),spells_known_progression_fixed:z.array(z.number()).optional(),spells_known_progression_fixed_allow_lower_level:z.boolean().optional(),spells_known_progression_fixed_by_level:z.record(z.string(),z.record(z.string(),z.number())).optional(),feat_progression:z.array(progressionSchema).optional(),optionalfeature_progression:z.array(progressionSchema).optional(),additional_spells:z.array(additionalSpellsEntrySchema).optional(),image:imageField});export{classEntitySchema};
1
+ import{poolGrantSchema,selectionPoolSchema,tabDeclSchema}from"./chunk-GCYUCIDN.js";import{casterTypeEnum}from"./chunk-X22SISGM.js";import{featureSchema}from"./chunk-FC4OPNZM.js";import{resourceSchema}from"./chunk-ZKDHCDJ2.js";import{startingEquipmentEntrySchema,startingGoldSchema}from"./chunk-TKIEPC6F.js";import{choiceSchema}from"./chunk-ZK3P4RSE.js";import{additionalSpellsEntrySchema,imageField,progressionSchema}from"./chunk-I26FHSI6.js";import{z}from"zod";var abilityEnum=z.enum(["str","dex","con","int","wis","cha"]);var skillEnum=z.enum(["acrobatics","animal-handling","arcana","athletics","deception","history","insight","intimidation","investigation","medicine","nature","perception","performance","persuasion","religion","sleight-of-hand","stealth","survival"]);var armorCategoryEnum=z.enum(["light","medium","heavy","shield"]);var weaponCategoryEnum=z.enum(["simple","martial"]);var hitDieEnum=z.enum(["d6","d8","d10","d12"]);var editionEnum=z.enum(["2014","2024"]);var weaponProficiencySchema=z.object({fixed:z.array(z.string()).optional(),categories:z.array(weaponCategoryEnum).optional(),conditional:z.array(z.object({category:weaponCategoryEnum,where_property:z.array(z.string()).nonempty()})).optional()}).refine(w=>{var _a,_b,_c,_d,_e,_f;return((_b=(_a=w.fixed)==null?void 0:_a.length)!=null?_b:0)+((_d=(_c=w.categories)==null?void 0:_c.length)!=null?_d:0)+((_f=(_e=w.conditional)==null?void 0:_e.length)!=null?_f:0)>0},{message:"weapon proficiency must declare at least one of fixed/categories/conditional"});var toolProficiencySchema=z.object({fixed:z.array(z.string()).optional(),choice:z.object({count:z.number().int().positive(),from:z.array(z.string()).nonempty()}).optional()}).refine(t=>{var _a,_b;return((_b=(_a=t.fixed)==null?void 0:_a.length)!=null?_b:0)>0||t.choice!==void 0},{message:"tool proficiency must declare fixed or choice"});var spellcastingSchema=z.object({caster_type:casterTypeEnum,ability:abilityEnum,preparation:z.enum(["known","prepared"]),spell_list:z.string().min(1)});var weaponMasterySchema=z.object({starting_count:z.number().int().nonnegative().optional(),scaling:z.record(z.string(),z.number().int().nonnegative()).optional()});var classTableRowSchema=z.object({prof_bonus:z.number().int().positive(),columns:z.record(z.string(),z.union([z.string(),z.number()])).optional(),feature_ids:z.array(z.string())});var classEntitySchema=z.object({slug:z.string().min(1),name:z.string().min(1),edition:editionEnum,source:z.string().min(1),description:z.string(),hit_die:hitDieEnum,primary_abilities:z.array(abilityEnum).nonempty(),standard_array:z.strictObject({str:z.number().int(),dex:z.number().int(),con:z.number().int(),int:z.number().int(),wis:z.number().int(),cha:z.number().int()}).optional(),saving_throws:z.array(abilityEnum).length(2),proficiencies:z.object({armor:z.array(armorCategoryEnum),weapons:weaponProficiencySchema,tools:toolProficiencySchema.optional()}),skill_choices:z.object({count:z.number().int().positive(),from:z.array(skillEnum).nonempty()}),choices:z.array(choiceSchema).optional(),starting_equipment:z.array(startingEquipmentEntrySchema),starting_gold:startingGoldSchema.optional(),spellcasting:spellcastingSchema.nullable(),subclass_level:z.number().int().positive(),subclass_feature_name:z.string().min(1),weapon_mastery:weaponMasterySchema.nullable(),epic_boon_level:z.number().int().positive().nullable(),table:z.record(z.string(),classTableRowSchema),features_by_level:z.record(z.string(),z.array(featureSchema)),resources:z.array(resourceSchema),selection_pools:z.array(selectionPoolSchema).optional(),pool_grants:z.array(poolGrantSchema).optional(),tabs:z.array(tabDeclSchema).optional(),rendering_hint:z.string().optional(),has_fluff:z.boolean().optional(),has_fluff_images:z.boolean().optional(),table_col_labels:z.array(z.string().min(1)).optional(),starting_equipment_additional_from_background:z.boolean().optional(),multiclassing:z.unknown().optional(),cantrip_progression:z.array(z.number()).optional(),prepared_spells:z.string().min(1).optional(),prepared_spells_change:z.string().min(1).optional(),prepared_spells_progression:z.array(z.number()).optional(),spells_known_progression:z.array(z.number()).optional(),spells_known_progression_fixed:z.array(z.number()).optional(),spells_known_progression_fixed_allow_lower_level:z.boolean().optional(),spells_known_progression_fixed_by_level:z.record(z.string(),z.record(z.string(),z.number())).optional(),feat_progression:z.array(progressionSchema).optional(),optionalfeature_progression:z.array(progressionSchema).optional(),additional_spells:z.array(additionalSpellsEntrySchema).optional(),image:imageField});export{classEntitySchema};
@@ -1 +1 @@
1
- import{backgroundEntitySchema}from"./chunk-XFFFTR6O.js";import{parseYaml}from"@archivist-gg/core";function parseBackground(source){const raw=parseYaml(source,["name","slug"]);if(!raw.success)return raw;const result=backgroundEntitySchema.safeParse({edition:"2014",...raw.data});if(!result.success){return{success:false,error:`background schema validation failed: ${result.error.message}`}}return{success:true,data:result.data}}export{parseBackground};
1
+ import{backgroundEntitySchema}from"./chunk-IOFGBEGA.js";import{parseYaml}from"@archivist-gg/core";function parseBackground(source){const raw=parseYaml(source,["name","slug"]);if(!raw.success)return raw;const result=backgroundEntitySchema.safeParse({edition:"2014",...raw.data});if(!result.success){return{success:false,error:`background schema validation failed: ${result.error.message}`}}return{success:true,data:result.data}}export{parseBackground};
@@ -1 +1 @@
1
- import{featureObjectSchema}from"./chunk-M2UA2FAK.js";import{imageField}from"./chunk-I26FHSI6.js";import{z}from"zod";var str=z.string();var num=z.number();var bool=z.boolean();var strArr=z.array(z.string());var damageQualifierSchema=z.object({get types(){return z.array(z.union([str,damageQualifierSchema])).optional()},note:str.optional(),pre_note:str.optional(),cond:bool.optional(),special:str.optional()});var qualifierList=z.array(z.union([str,damageQualifierSchema])).optional();var speedValue=z.union([num,z.object({number:num,condition:str.optional()})]);var monsterSpeedSchema=z.object({walk:speedValue.optional(),fly:speedValue.optional(),swim:speedValue.optional(),climb:speedValue.optional(),burrow:speedValue.optional(),hover:bool.optional(),can_hover:bool.optional(),alternate:z.record(str,z.array(z.object({number:num,condition:str.optional()}))).optional(),choose:z.object({from:strArr,amount:num,note:str.optional()}).optional()});var monsterTypeSchema=z.object({type:z.union([str,z.object({choose:strArr})]),tags:z.array(z.union([str,z.object({tag:str,prefix:str,prefix_hidden:bool.optional()})])).optional(),sidekick_type:str.optional(),sidekick_tags:strArr.optional(),swarm_size:str.optional(),sidekick_hidden:bool.optional()});var monsterCRSchema=z.object({cr:str,lair:str.optional(),coven:str.optional(),xp:num.optional(),xp_lair:num.optional()});var monsterACSchema=z.object({ac:num.optional(),from:strArr.optional(),condition:str.optional(),braces:bool.optional(),special:str.optional()});var monsterHPSchema=z.object({average:num.optional(),formula:str.optional(),special:str.optional()});var alignmentEntrySchema=z.object({alignment:strArr.optional(),chance:num.optional(),note:str.optional(),special:str.optional()});var spellEntry=z.union([str,z.object({entry:str,hidden:bool.optional()})]);var spellList=z.array(spellEntry);var spellLevel=z.object({slots:num.optional(),lower:num.optional(),spells:strArr});var monsterSpellcastingSchema=z.object({name:str.optional(),type:str.optional(),headerEntries:strArr.optional(),footerEntries:strArr.optional(),ability:str.optional(),displayAs:str.optional(),hidden:strArr.optional(),spells:z.record(str,spellLevel).optional(),will:spellList.optional(),ritual:spellList.optional(),daily:z.record(str,spellList).optional(),rest:z.record(str,spellList).optional(),restLong:z.record(str,spellList).optional(),recharge:z.record(str,spellList).optional(),legendary:z.record(str,spellList).optional(),charges:z.record(str,spellList).optional(),chargesItem:str.optional()});var initiativeSchema=z.union([num,z.object({proficiency:num.optional(),advantage_mode:str.optional()})]);var gearEntrySchema=z.union([str,z.object({item:str,quantity:num.optional(),displayName:str.optional()})]);var featureArr=z.array(featureObjectSchema).optional();var monsterSchema=z.object({name:str.min(1),size:z.union([str,strArr]).optional(),size_note:str.optional(),type:z.union([str,monsterTypeSchema]).optional(),subtype:str.optional(),alignment:z.union([str,z.array(z.union([str,alignmentEntrySchema]))]).optional(),alignment_prefix:str.optional(),cr:z.union([str,monsterCRSchema]).optional(),pb_note:str.optional(),ac:z.array(monsterACSchema).optional(),hp:monsterHPSchema.optional(),speed:monsterSpeedSchema.optional(),abilities:z.object({str:num,dex:num,con:num,int:num,wis:num,cha:num}).optional(),saves:z.record(str,num).optional(),skills:z.record(str,num).optional(),skills_other:z.array(z.unknown()).optional(),senses:strArr.nullable().optional(),passive_perception:num.optional(),languages:strArr.nullable().optional(),damage_vulnerabilities:qualifierList,damage_resistances:qualifierList,damage_immunities:qualifierList,condition_immunities:qualifierList,traits:featureArr,actions:featureArr,bonus_actions:featureArr,reactions:featureArr,legendary_actions:featureArr,mythic:featureArr,mythic_header:strArr.optional(),legendary_action_uses:num.optional(),legendary_resistance:num.optional(),legendary_actions_lair_count:num.optional(),section_headers:z.array(z.object({section:str,header:strArr})).optional(),action_note:str.optional(),reaction_note:str.optional(),spellcasting:z.array(monsterSpellcastingSchema).optional(),legendary_group:z.object({name:str,source:str}).optional(),lair_actions:z.array(z.unknown()).optional(),regional_actions:z.array(z.unknown()).optional(),variant:z.array(z.unknown()).optional(),initiative:initiativeSchema.optional(),gear:z.array(gearEntrySchema).optional(),is_named_creature:bool.optional(),is_npc:bool.optional(),familiar:bool.optional(),short_name:z.union([str,bool]).optional(),level:num.optional(),dragon_age:str.optional(),dragon_casting_color:str.optional(),environment:strArr.optional(),treasure:strArr.optional(),attached_items:strArr.optional(),group:strArr.nullable().optional(),summoned_by_spell:str.optional(),summoned_by_spell_level:num.optional(),summoned_by_class:str.optional(),trait_tags:strArr.optional(),action_tags:strArr.optional(),sense_tags:strArr.optional(),language_tags:strArr.optional(),spellcasting_tags:strArr.optional(),misc_tags:strArr.optional(),damage_tags:strArr.optional(),damage_tags_spell:strArr.optional(),damage_tags_legendary:strArr.optional(),condition_inflict:strArr.optional(),condition_inflict_spell:strArr.optional(),condition_inflict_legendary:strArr.optional(),saving_throw_forced:strArr.optional(),saving_throw_forced_spell:strArr.optional(),saving_throw_forced_legendary:strArr.optional(),has_fluff:bool.optional(),has_fluff_images:bool.optional(),has_token:bool.optional(),token_credit:str.optional(),token_custom:bool.optional(),sound_clip:z.object({type:str,path:str}).optional(),alt_art:z.array(z.object({name:str,source:str.optional(),page:num.optional()})).optional(),image:imageField,thumbnail:imageField,rendering_hint:str.optional(),columns:num.optional(),slug:str.optional(),edition:str.optional(),source:str.optional(),raw:z.record(str,z.unknown()).optional()});var MONSTER_KNOWN_KEYS=new Set(Object.keys(monsterSchema.shape));export{damageQualifierSchema,monsterSpeedSchema,monsterTypeSchema,monsterCRSchema,monsterACSchema,monsterHPSchema,alignmentEntrySchema,monsterSpellcastingSchema,initiativeSchema,gearEntrySchema,monsterSchema,MONSTER_KNOWN_KEYS};
1
+ import{featureObjectSchema}from"./chunk-FC4OPNZM.js";import{imageField}from"./chunk-I26FHSI6.js";import{z}from"zod";var str=z.string();var num=z.number();var bool=z.boolean();var strArr=z.array(z.string());var damageQualifierSchema=z.object({get types(){return z.array(z.union([str,damageQualifierSchema])).optional()},note:str.optional(),pre_note:str.optional(),cond:bool.optional(),special:str.optional()});var qualifierList=z.array(z.union([str,damageQualifierSchema])).optional();var speedValue=z.union([num,z.object({number:num,condition:str.optional()})]);var monsterSpeedSchema=z.object({walk:speedValue.optional(),fly:speedValue.optional(),swim:speedValue.optional(),climb:speedValue.optional(),burrow:speedValue.optional(),hover:bool.optional(),can_hover:bool.optional(),alternate:z.record(str,z.array(z.object({number:num,condition:str.optional()}))).optional(),choose:z.object({from:strArr,amount:num,note:str.optional()}).optional()});var monsterTypeSchema=z.object({type:z.union([str,z.object({choose:strArr})]),tags:z.array(z.union([str,z.object({tag:str,prefix:str,prefix_hidden:bool.optional()})])).optional(),sidekick_type:str.optional(),sidekick_tags:strArr.optional(),swarm_size:str.optional(),sidekick_hidden:bool.optional()});var monsterCRSchema=z.object({cr:str,lair:str.optional(),coven:str.optional(),xp:num.optional(),xp_lair:num.optional()});var monsterACSchema=z.object({ac:num.optional(),from:strArr.optional(),condition:str.optional(),braces:bool.optional(),special:str.optional()});var monsterHPSchema=z.object({average:num.optional(),formula:str.optional(),special:str.optional()});var alignmentEntrySchema=z.object({alignment:strArr.optional(),chance:num.optional(),note:str.optional(),special:str.optional()});var spellEntry=z.union([str,z.object({entry:str,hidden:bool.optional()})]);var spellList=z.array(spellEntry);var spellLevel=z.object({slots:num.optional(),lower:num.optional(),spells:strArr});var monsterSpellcastingSchema=z.object({name:str.optional(),type:str.optional(),headerEntries:strArr.optional(),footerEntries:strArr.optional(),ability:str.optional(),displayAs:str.optional(),hidden:strArr.optional(),spells:z.record(str,spellLevel).optional(),will:spellList.optional(),ritual:spellList.optional(),daily:z.record(str,spellList).optional(),rest:z.record(str,spellList).optional(),restLong:z.record(str,spellList).optional(),recharge:z.record(str,spellList).optional(),legendary:z.record(str,spellList).optional(),charges:z.record(str,spellList).optional(),chargesItem:str.optional()});var initiativeSchema=z.union([num,z.object({proficiency:num.optional(),advantage_mode:str.optional()})]);var gearEntrySchema=z.union([str,z.object({item:str,quantity:num.optional(),displayName:str.optional()})]);var featureArr=z.array(featureObjectSchema).optional();var monsterSchema=z.object({name:str.min(1),size:z.union([str,strArr]).optional(),size_note:str.optional(),type:z.union([str,monsterTypeSchema]).optional(),subtype:str.optional(),alignment:z.union([str,z.array(z.union([str,alignmentEntrySchema]))]).optional(),alignment_prefix:str.optional(),cr:z.union([str,monsterCRSchema]).optional(),pb_note:str.optional(),ac:z.array(monsterACSchema).optional(),hp:monsterHPSchema.optional(),speed:monsterSpeedSchema.optional(),abilities:z.object({str:num,dex:num,con:num,int:num,wis:num,cha:num}).optional(),saves:z.record(str,num).optional(),skills:z.record(str,num).optional(),skills_other:z.array(z.unknown()).optional(),senses:strArr.nullable().optional(),passive_perception:num.optional(),languages:strArr.nullable().optional(),damage_vulnerabilities:qualifierList,damage_resistances:qualifierList,damage_immunities:qualifierList,condition_immunities:qualifierList,traits:featureArr,actions:featureArr,bonus_actions:featureArr,reactions:featureArr,legendary_actions:featureArr,mythic:featureArr,mythic_header:strArr.optional(),legendary_action_uses:num.optional(),legendary_resistance:num.optional(),legendary_actions_lair_count:num.optional(),section_headers:z.array(z.object({section:str,header:strArr})).optional(),action_note:str.optional(),reaction_note:str.optional(),spellcasting:z.array(monsterSpellcastingSchema).optional(),legendary_group:z.object({name:str,source:str}).optional(),lair_actions:z.array(z.unknown()).optional(),regional_actions:z.array(z.unknown()).optional(),variant:z.array(z.unknown()).optional(),initiative:initiativeSchema.optional(),gear:z.array(gearEntrySchema).optional(),is_named_creature:bool.optional(),is_npc:bool.optional(),familiar:bool.optional(),short_name:z.union([str,bool]).optional(),level:num.optional(),dragon_age:str.optional(),dragon_casting_color:str.optional(),environment:strArr.optional(),treasure:strArr.optional(),attached_items:strArr.optional(),group:strArr.nullable().optional(),summoned_by_spell:str.optional(),summoned_by_spell_level:num.optional(),summoned_by_class:str.optional(),trait_tags:strArr.optional(),action_tags:strArr.optional(),sense_tags:strArr.optional(),language_tags:strArr.optional(),spellcasting_tags:strArr.optional(),misc_tags:strArr.optional(),damage_tags:strArr.optional(),damage_tags_spell:strArr.optional(),damage_tags_legendary:strArr.optional(),condition_inflict:strArr.optional(),condition_inflict_spell:strArr.optional(),condition_inflict_legendary:strArr.optional(),saving_throw_forced:strArr.optional(),saving_throw_forced_spell:strArr.optional(),saving_throw_forced_legendary:strArr.optional(),has_fluff:bool.optional(),has_fluff_images:bool.optional(),has_token:bool.optional(),token_credit:str.optional(),token_custom:bool.optional(),sound_clip:z.object({type:str,path:str}).optional(),alt_art:z.array(z.object({name:str,source:str.optional(),page:num.optional()})).optional(),image:imageField,thumbnail:imageField,rendering_hint:str.optional(),columns:num.optional(),slug:str.optional(),edition:str.optional(),source:str.optional(),raw:z.record(str,z.unknown()).optional()});var MONSTER_KNOWN_KEYS=new Set(Object.keys(monsterSchema.shape));export{damageQualifierSchema,monsterSpeedSchema,monsterTypeSchema,monsterCRSchema,monsterACSchema,monsterHPSchema,alignmentEntrySchema,monsterSpellcastingSchema,initiativeSchema,gearEntrySchema,monsterSchema,MONSTER_KNOWN_KEYS};
@@ -1 +1 @@
1
- import{heldPicks,parsePickKey,poolAnchorLevel}from"./chunk-E4E6YEN6.js";import{featProgressionCategory}from"./chunk-3QQOATV3.js";import{warnOnce}from"./chunk-DZITM5AG.js";import{bucketOf}from"./chunk-QMEKQTUT.js";import{bareEntitySlug,twinKey,wikilinkTailSlug}from"./chunk-63YJPWTM.js";var OPTIONAL_FEATURE_TYPE_CODE={"MV:B":"maneuver",MV:"maneuver",EI:"invocation",MM:"metamagic","FS:F":"fighting_style"};function spellFilter(choose,edition){const where={edition};for(const part of choose.split("|")){const[rawKey,rawValue=""]=part.split("=");const key=rawKey.trim().toLowerCase();const value=rawValue.trim();if(key==="level"){const n=Number(value.split(";")[0]);if(!Number.isInteger(n))return null;where.level=n}else if(key==="class")where.list=value.toLowerCase();else if(key==="components & miscellaneous"&&/ritual/i.test(value))where.ritual=true}return where}function isTargetChoice(ch){return ch.kind==="select-entity"&&ch.target===true}var PACT_WEAPON_CHOICE_ID="pact-weapon";function pactWeaponPick(sites){for(const site of sites){for(const ch of site.choices){if(ch.kind!=="select-entity"||ch.id!==PACT_WEAPON_CHOICE_ID)continue;const v=site.read(ch.id);const first=Array.isArray(v)?v.find(x=>typeof x==="string"&&x.trim()!==""):v;if(typeof first!=="string"||!first.trim())continue;return first.trim().replace(/^\[\[/,"").replace(/\]\]$/,"").split("|")[0].trim()}}return void 0}function classPactWeaponPick(character,classes){var _a,_b,_c,_d,_e,_f,_g;const inBlock=(choices,block)=>{for(const ch of choices!=null?choices:[]){if(ch.kind==="select-inline"){const sel=block[ch.id];const branch=typeof sel==="string"?ch.options.find(o=>o.value===sel):void 0;const hit=inBlock(branch==null?void 0:branch.choices,block);if(hit)return hit}else if(ch.kind==="select-entity"&&ch.id===PACT_WEAPON_CHOICE_ID){const hit=pactWeaponPick([{choices:[ch],read:id=>block[id]}]);if(hit)return hit}}return void 0};for(let i=0;i<classes.length;i++){const entity=(_a=classes[i])==null?void 0:_a.entity;const entry=character.class[i];if(!entity||!entry)continue;for(const[lvl,raw]of Object.entries((_b=entry.choices)!=null?_b:{})){const block=raw!=null?raw:{};const features=[...(_d=((_c=entity.features_by_level)!=null?_c:{})[Number(lvl)])!=null?_d:[],...(_g=((_f=(_e=classes[i].subclass)==null?void 0:_e.features_by_level)!=null?_f:{})[Number(lvl)])!=null?_g:[]];for(const f of features){const hit=inBlock(f.choices,block);if(hit)return hit}}}return void 0}function progressionCount(p){var _a;if(Array.isArray(p))return 0;return(_a=p["*"])!=null?_a:Math.max(0,...Object.values(p))}function spellChoices(entity,used){var _a,_b;const out=[];for(const block of(_a=entity.additional_spells)!=null?_a:[]){for(const bucket of["known","prepared"]){const byLevel=block[bucket];if(!byLevel||typeof byLevel!=="object")continue;for(const rows of Object.values(byLevel)){for(const row of Array.isArray(rows)?rows:[]){const r=row;if(typeof r.choose!=="string")continue;const where=spellFilter(r.choose,entity.edition);if(!where)continue;const base=where.ritual?"rituals":where.level===0?"cantrips":`spells-${(_b=where.level)!=null?_b:"any"}`;const label=where.ritual?"Rituals":where.level===0?"Cantrips":`Level ${where.level} spells`;let id=base;for(let i=2;used.has(id);i++)id=`${base}-${i}`;used.add(id);out.push({kind:"select-entity",id,label,count:typeof r.count==="number"?r.count:1,entity_type:"spell",where})}}}}return out}function memberChoices(entity){var _a,_b,_c,_d,_e,_f;if(!entity)return[];if((_a=entity.choices)==null?void 0:_a.length)return entity.choices;const out=[];const used=new Set;for(const fp of(_b=entity.feat_progression)!=null?_b:[]){const category=featProgressionCategory(fp.category);const count=progressionCount(fp.progression);if(!category||count<1)continue;const id=used.has("feat")?`feat-${used.size}`:"feat";used.add(id);out.push({kind:"select-entity",id,label:fp.name,count,entity_type:"feat",where:{category,edition:entity.edition}})}for(const op of(_c=entity.optionalfeature_progression)!=null?_c:[]){const codes=(_e=(_d=op.feature_type)!=null?_d:op.featureType)!=null?_e:[];const featureType=codes.map(c=>OPTIONAL_FEATURE_TYPE_CODE[c]).find(t=>!!t);const count=progressionCount(op.progression);if(!featureType||count<1){if(!featureType)warnOnce(`member-of-code:${entity.slug}`,`Archivist: "${entity.slug}" asks for optional features of type ${codes.join(", ")}, which this engine does not map; no pick is offered`);continue}const id=op.name.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")||"option";used.add(id);out.push({kind:"select-entity",id,label:op.name,count,entity_type:"optional-feature",where:{feature_type:featureType,edition:entity.edition}})}out.push(...spellChoices(entity,used));for(const pre of(_f=entity.prerequisites)!=null?_f:[]){if(pre.kind!=="spell-choose")continue;const where=spellFilter(pre.choose,entity.edition);if(!where||used.has("cantrip"))continue;used.add("cantrip");out.push({kind:"select-entity",id:"cantrip",label:where.level===0?"Cantrip":"Spell",count:1,entity_type:"spell",where,target:true})}return out}function memberSpellTargets(member,read){var _a;const refs=[];const open=[];for(const ch of memberChoices(member)){if(ch.kind!=="select-entity"||!isTargetChoice(ch)||ch.entity_type!=="spell")continue;const v=read(ch.id);const picked=(Array.isArray(v)?v:[v]).filter(x=>typeof x==="string"&&x.trim()!=="");if(picked.length)refs.push(...picked);else if(ch.where)open.push(ch.where)}for(const pre of(_a=member.prerequisites)!=null?_a:[])if(pre.kind==="spell-known")refs.push(pre.spell);return refs.length||open.length?{refs,open}:null}function spellMatchesFilter(d,where){var _a,_b;if(where.list&&!((_a=d.classes)!=null?_a:[]).includes(where.list))return false;if(where.level!==void 0&&((_b=d.level)!=null?_b:0)!==where.level)return false;if(where.edition&&d.edition!==where.edition)return false;if(where.ritual&&d.ritual!==true)return false;return true}function spellsReached(targets,spells){if(!targets)return[];const hit=new Set;for(const ref of targets.refs){const full=stripRef(ref);const exact=spells.filter(s=>s.slug===full);const bare=wikilinkTailSlug(ref);for(const s of exact.length?exact:spells.filter(s2=>bareEntitySlug(s2.slug)===bare))hit.add(s.slug)}for(const where of targets.open){const legal=new Set(spells.filter(s=>{var _a;return spellMatchesFilter(s.entity,where)&&!!((_a=s.entity.damage_roll)==null?void 0:_a.trim())}).map(s=>s.slug));if(legal.size===1)hit.add([...legal][0])}return[...new Set(spells.map(s=>s.slug))].filter(slug=>hit.has(slug))}function siteOf(classIndex,level,poolId,pickKey,member,memberSlug,block){const choices=memberChoices(member);if(!choices.length)return null;const prefix=`${poolId}:${pickKey}:`;return{classIndex,level,poolId,pickKey,member,memberSlug,choices,prefix,block,read:id=>block[`${prefix}${id}`]}}function poolMemberSites(classes,registry){const out=[];let byBare=null;let all=null;const lookup=(s,ownerPrefix)=>{all!=null?all:all=bucketOf(registry,"optional-feature");const bare=bareEntitySlug(s);const twin=twinKey(s);const owned=all.find(e=>twinKey(e.slug)===twin&&e.slug.split("_")[0]===ownerPrefix);if(owned)return owned;const direct=registry.getByTypeAndSlug("optional-feature",s);if(direct)return direct;byBare!=null?byBare:byBare=new Map(all.map(e=>[bareEntitySlug(e.slug),e]));return byBare.get(bare)};classes.forEach((rc,classIndex)=>{var _a,_b,_c,_d,_e;if(!rc.entity)return;const seen=new Set;for(const pool of[...(_a=rc.entity.selection_pools)!=null?_a:[],...(_c=(_b=rc.subclass)==null?void 0:_b.selection_pools)!=null?_c:[]]){if(seen.has(pool.id))continue;seen.add(pool.id);const{anchorLevel}=poolAnchorLevel(rc.entity,pool);const block=(_e=(_d=rc.choices)==null?void 0:_d[anchorLevel])!=null?_e:{};const raw=block[pool.id];const picks=Array.isArray(raw)?raw:typeof raw==="string"?[raw]:[];for(const s of picks){if(typeof s!=="string")continue;const{slugPart,param}=parsePickKey(s);const reg=lookup(slugPart,rc.entity.slug.split("_")[0]);if(!reg)continue;const member=reg.data;const key=member.repeatable===true||param!==null?s:reg.slug;const site=siteOf(classIndex,anchorLevel,pool.id,key,member,reg.slug,block);if(site)out.push(site)}}});return out}function poolMemberSitesOf(resolved){var _a,_b,_c,_d,_e;const out=[];for(const pool of(_a=resolved.pools)!=null?_a:[]){const block=(_e=(_d=(_c=(_b=resolved.classes)==null?void 0:_b[pool.classIndex])==null?void 0:_c.choices)==null?void 0:_d[pool.anchorLevel])!=null?_e:{};for(const e of heldPicks(pool)){const site=siteOf(pool.classIndex,pool.anchorLevel,pool.id,e.key,e.entity,e.slug,block);if(site)out.push(site)}}return out}var stripRef=ref=>ref.replace(/^\[\[/,"").replace(/\]\]$/,"");function featPickSites(classEntries,memberSites,classSlugOf){const out=[];(classEntries!=null?classEntries:[]).forEach((c,classIndex)=>{var _a;for(const[lvl,choiceBlock]of Object.entries((_a=c.choices)!=null?_a:{})){const block=choiceBlock;const feat=block==null?void 0:block.feat;if(!block||typeof feat!=="string")continue;const slug=stripRef(feat);if(!slug)continue;const level=/^\d+$/.test(lvl)?Number(lvl):null;const cls=classSlugOf(classIndex);out.push({slug,classIndex,level,via:cls&&level!==null?{kind:"class",slug:cls,level}:null,read:id=>block[`feat:${id}`]})}});for(const site of memberSites){for(const ch of site.choices){if(ch.kind!=="select-entity"||ch.entity_type!=="feat"||ch.target===true)continue;const v=site.read(ch.id);for(const ref of Array.isArray(v)?v:typeof v==="string"?[v]:[]){if(typeof ref!=="string")continue;const slug=stripRef(ref);if(!slug)continue;const cls=classSlugOf(site.classIndex);out.push({slug,classIndex:site.classIndex,level:site.level,via:cls?{kind:"pool",slug:site.memberSlug,name:site.member.name,classSlug:cls,level:site.level}:null,read:id=>site.block[`${site.prefix}feat:${id}`]})}}}return out}function raceFeatSites(race,originChoices){var _a;if(!race)return[];const oc=originChoices!=null?originChoices:{};const out=[];for(const list of[race.choices,...((_a=race.traits)!=null?_a:[]).map(t=>t==null?void 0:t.choices)]){for(const ch of Array.isArray(list)?list:[]){if((ch==null?void 0:ch.kind)!=="select-entity"||ch.entity_type!=="feat")continue;const v=oc[`race:${ch.id}`];for(const ref of Array.isArray(v)?v:typeof v==="string"?[v]:[]){const slug=typeof ref==="string"?stripRef(ref):"";if(slug)out.push({slug,via:{kind:"race",slug:race.slug},read:id=>oc[`race:feat:${id}`]})}}}return out}function featOfSite(site,feats){var _a;return(_a=feats.find(f=>f.slug===site.slug))!=null?_a:feats.find(f=>bareEntitySlug(f.slug)===bareEntitySlug(site.slug))}function nestedPickKeysToPrune(block,key,next){const prev=block==null?void 0:block[key];if(!block||!Array.isArray(prev))return[];const keep=new Set(next);const gone=prev.filter(k=>typeof k==="string"&&!keep.has(k));if(!gone.length)return[];return Object.keys(block).filter(k=>gone.some(g=>k.startsWith(`${key}:${g}:`)))}export{isTargetChoice,PACT_WEAPON_CHOICE_ID,pactWeaponPick,classPactWeaponPick,memberChoices,memberSpellTargets,spellsReached,poolMemberSites,poolMemberSitesOf,featPickSites,raceFeatSites,featOfSite,nestedPickKeysToPrune};
1
+ import{heldPicks,parsePickKey,poolAnchorLevel}from"./chunk-7S4VMK3R.js";import{featProgressionCategory}from"./chunk-3QQOATV3.js";import{warnOnce}from"./chunk-DZITM5AG.js";import{bucketOf}from"./chunk-QMEKQTUT.js";import{bareEntitySlug,twinKey,wikilinkTailSlug}from"./chunk-63YJPWTM.js";var OPTIONAL_FEATURE_TYPE_CODE={"MV:B":"maneuver",MV:"maneuver",EI:"invocation",MM:"metamagic","FS:F":"fighting_style"};function spellFilter(choose,edition){const where={edition};for(const part of choose.split("|")){const[rawKey,rawValue=""]=part.split("=");const key=rawKey.trim().toLowerCase();const value=rawValue.trim();if(key==="level"){const n=Number(value.split(";")[0]);if(!Number.isInteger(n))return null;where.level=n}else if(key==="class")where.list=value.toLowerCase();else if(key==="components & miscellaneous"&&/ritual/i.test(value))where.ritual=true}return where}function isTargetChoice(ch){return ch.kind==="select-entity"&&ch.target===true}var PACT_WEAPON_CHOICE_ID="pact-weapon";function pactWeaponPick(sites){for(const site of sites){for(const ch of site.choices){if(ch.kind!=="select-entity"||ch.id!==PACT_WEAPON_CHOICE_ID)continue;const v=site.read(ch.id);const first=Array.isArray(v)?v.find(x=>typeof x==="string"&&x.trim()!==""):v;if(typeof first!=="string"||!first.trim())continue;return first.trim().replace(/^\[\[/,"").replace(/\]\]$/,"").split("|")[0].trim()}}return void 0}function classPactWeaponPick(character,classes){var _a,_b,_c,_d,_e,_f,_g;const inBlock=(choices,block)=>{for(const ch of choices!=null?choices:[]){if(ch.kind==="select-inline"){const sel=block[ch.id];const branch=typeof sel==="string"?ch.options.find(o=>o.value===sel):void 0;const hit=inBlock(branch==null?void 0:branch.choices,block);if(hit)return hit}else if(ch.kind==="select-entity"&&ch.id===PACT_WEAPON_CHOICE_ID){const hit=pactWeaponPick([{choices:[ch],read:id=>block[id]}]);if(hit)return hit}}return void 0};for(let i=0;i<classes.length;i++){const entity=(_a=classes[i])==null?void 0:_a.entity;const entry=character.class[i];if(!entity||!entry)continue;for(const[lvl,raw]of Object.entries((_b=entry.choices)!=null?_b:{})){const block=raw!=null?raw:{};const features=[...(_d=((_c=entity.features_by_level)!=null?_c:{})[Number(lvl)])!=null?_d:[],...(_g=((_f=(_e=classes[i].subclass)==null?void 0:_e.features_by_level)!=null?_f:{})[Number(lvl)])!=null?_g:[]];for(const f of features){const hit=inBlock(f.choices,block);if(hit)return hit}}}return void 0}function progressionCount(p){var _a;if(Array.isArray(p))return 0;return(_a=p["*"])!=null?_a:Math.max(0,...Object.values(p))}function spellChoices(entity,used){var _a,_b;const out=[];for(const block of(_a=entity.additional_spells)!=null?_a:[]){for(const bucket of["known","prepared"]){const byLevel=block[bucket];if(!byLevel||typeof byLevel!=="object")continue;for(const rows of Object.values(byLevel)){for(const row of Array.isArray(rows)?rows:[]){const r=row;if(typeof r.choose!=="string")continue;const where=spellFilter(r.choose,entity.edition);if(!where)continue;const base=where.ritual?"rituals":where.level===0?"cantrips":`spells-${(_b=where.level)!=null?_b:"any"}`;const label=where.ritual?"Rituals":where.level===0?"Cantrips":`Level ${where.level} spells`;let id=base;for(let i=2;used.has(id);i++)id=`${base}-${i}`;used.add(id);out.push({kind:"select-entity",id,label,count:typeof r.count==="number"?r.count:1,entity_type:"spell",where})}}}}return out}function memberChoices(entity){var _a,_b,_c,_d,_e,_f;if(!entity)return[];if((_a=entity.choices)==null?void 0:_a.length)return entity.choices;const out=[];const used=new Set;for(const fp of(_b=entity.feat_progression)!=null?_b:[]){const category=featProgressionCategory(fp.category);const count=progressionCount(fp.progression);if(!category||count<1)continue;const id=used.has("feat")?`feat-${used.size}`:"feat";used.add(id);out.push({kind:"select-entity",id,label:fp.name,count,entity_type:"feat",where:{category,edition:entity.edition}})}for(const op of(_c=entity.optionalfeature_progression)!=null?_c:[]){const codes=(_e=(_d=op.feature_type)!=null?_d:op.featureType)!=null?_e:[];const featureType=codes.map(c=>OPTIONAL_FEATURE_TYPE_CODE[c]).find(t=>!!t);const count=progressionCount(op.progression);if(!featureType||count<1){if(!featureType)warnOnce(`member-of-code:${entity.slug}`,`Archivist: "${entity.slug}" asks for optional features of type ${codes.join(", ")}, which this engine does not map; no pick is offered`);continue}const id=op.name.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")||"option";used.add(id);out.push({kind:"select-entity",id,label:op.name,count,entity_type:"optional-feature",where:{feature_type:featureType,edition:entity.edition}})}out.push(...spellChoices(entity,used));for(const pre of(_f=entity.prerequisites)!=null?_f:[]){if(pre.kind!=="spell-choose")continue;const where=spellFilter(pre.choose,entity.edition);if(!where||used.has("cantrip"))continue;used.add("cantrip");out.push({kind:"select-entity",id:"cantrip",label:where.level===0?"Cantrip":"Spell",count:1,entity_type:"spell",where,target:true})}return out}function memberSpellTargets(member,read){var _a;const refs=[];const open=[];for(const ch of memberChoices(member)){if(ch.kind!=="select-entity"||!isTargetChoice(ch)||ch.entity_type!=="spell")continue;const v=read(ch.id);const picked=(Array.isArray(v)?v:[v]).filter(x=>typeof x==="string"&&x.trim()!=="");if(picked.length)refs.push(...picked);else if(ch.where)open.push(ch.where)}for(const pre of(_a=member.prerequisites)!=null?_a:[])if(pre.kind==="spell-known")refs.push(pre.spell);return refs.length||open.length?{refs,open}:null}function spellMatchesFilter(d,where){var _a,_b;if(where.list&&!((_a=d.classes)!=null?_a:[]).includes(where.list))return false;if(where.level!==void 0&&((_b=d.level)!=null?_b:0)!==where.level)return false;if(where.edition&&d.edition!==where.edition)return false;if(where.ritual&&d.ritual!==true)return false;return true}function spellsReached(targets,spells){if(!targets)return[];const hit=new Set;for(const ref of targets.refs){const full=stripRef(ref);const exact=spells.filter(s=>s.slug===full);const bare=wikilinkTailSlug(ref);for(const s of exact.length?exact:spells.filter(s2=>bareEntitySlug(s2.slug)===bare))hit.add(s.slug)}for(const where of targets.open){const legal=new Set(spells.filter(s=>{var _a;return spellMatchesFilter(s.entity,where)&&!!((_a=s.entity.damage_roll)==null?void 0:_a.trim())}).map(s=>s.slug));if(legal.size===1)hit.add([...legal][0])}return[...new Set(spells.map(s=>s.slug))].filter(slug=>hit.has(slug))}function siteOf(classIndex,level,poolId,pickKey,member,memberSlug,block){const choices=memberChoices(member);if(!choices.length)return null;const prefix=`${poolId}:${pickKey}:`;return{classIndex,level,poolId,pickKey,member,memberSlug,choices,prefix,block,read:id=>block[`${prefix}${id}`]}}function poolMemberSites(classes,registry){const out=[];let byBare=null;let all=null;const lookup=(s,ownerPrefix)=>{all!=null?all:all=bucketOf(registry,"optional-feature");const bare=bareEntitySlug(s);const twin=twinKey(s);const owned=all.find(e=>twinKey(e.slug)===twin&&e.slug.split("_")[0]===ownerPrefix);if(owned)return owned;const direct=registry.getByTypeAndSlug("optional-feature",s);if(direct)return direct;byBare!=null?byBare:byBare=new Map(all.map(e=>[bareEntitySlug(e.slug),e]));return byBare.get(bare)};classes.forEach((rc,classIndex)=>{var _a,_b,_c,_d,_e;if(!rc.entity)return;const seen=new Set;for(const pool of[...(_a=rc.entity.selection_pools)!=null?_a:[],...(_c=(_b=rc.subclass)==null?void 0:_b.selection_pools)!=null?_c:[]]){if(seen.has(pool.id))continue;seen.add(pool.id);const{anchorLevel}=poolAnchorLevel(rc.entity,pool);const block=(_e=(_d=rc.choices)==null?void 0:_d[anchorLevel])!=null?_e:{};const raw=block[pool.id];const picks=Array.isArray(raw)?raw:typeof raw==="string"?[raw]:[];for(const s of picks){if(typeof s!=="string")continue;const{slugPart,param}=parsePickKey(s);const reg=lookup(slugPart,rc.entity.slug.split("_")[0]);if(!reg)continue;const member=reg.data;const key=member.repeatable===true||param!==null?s:reg.slug;const site=siteOf(classIndex,anchorLevel,pool.id,key,member,reg.slug,block);if(site)out.push(site)}}});return out}function poolMemberSitesOf(resolved){var _a,_b,_c,_d,_e;const out=[];for(const pool of(_a=resolved.pools)!=null?_a:[]){const block=(_e=(_d=(_c=(_b=resolved.classes)==null?void 0:_b[pool.classIndex])==null?void 0:_c.choices)==null?void 0:_d[pool.anchorLevel])!=null?_e:{};for(const e of heldPicks(pool)){const site=siteOf(pool.classIndex,pool.anchorLevel,pool.id,e.key,e.entity,e.slug,block);if(site)out.push(site)}}return out}var stripRef=ref=>ref.replace(/^\[\[/,"").replace(/\]\]$/,"");function featPickSites(classEntries,memberSites,classSlugOf){const out=[];(classEntries!=null?classEntries:[]).forEach((c,classIndex)=>{var _a;for(const[lvl,choiceBlock]of Object.entries((_a=c.choices)!=null?_a:{})){const block=choiceBlock;const feat=block==null?void 0:block.feat;if(!block||typeof feat!=="string")continue;const slug=stripRef(feat);if(!slug)continue;const level=/^\d+$/.test(lvl)?Number(lvl):null;const cls=classSlugOf(classIndex);out.push({slug,classIndex,level,via:cls&&level!==null?{kind:"class",slug:cls,level}:null,read:id=>block[`feat:${id}`]})}});for(const site of memberSites){for(const ch of site.choices){if(ch.kind!=="select-entity"||ch.entity_type!=="feat"||ch.target===true)continue;const v=site.read(ch.id);for(const ref of Array.isArray(v)?v:typeof v==="string"?[v]:[]){if(typeof ref!=="string")continue;const slug=stripRef(ref);if(!slug)continue;const cls=classSlugOf(site.classIndex);out.push({slug,classIndex:site.classIndex,level:site.level,via:cls?{kind:"pool",slug:site.memberSlug,name:site.member.name,classSlug:cls,level:site.level}:null,read:id=>site.block[`${site.prefix}feat:${id}`]})}}}return out}function raceFeatSites(race,originChoices){var _a;if(!race)return[];const oc=originChoices!=null?originChoices:{};const out=[];for(const list of[race.choices,...((_a=race.traits)!=null?_a:[]).map(t=>t==null?void 0:t.choices)]){for(const ch of Array.isArray(list)?list:[]){if((ch==null?void 0:ch.kind)!=="select-entity"||ch.entity_type!=="feat")continue;const v=oc[`race:${ch.id}`];for(const ref of Array.isArray(v)?v:typeof v==="string"?[v]:[]){const slug=typeof ref==="string"?stripRef(ref):"";if(slug)out.push({slug,via:{kind:"race",slug:race.slug},read:id=>oc[`race:feat:${id}`]})}}}return out}function featOfSite(site,feats){var _a;return(_a=feats.find(f=>f.slug===site.slug))!=null?_a:feats.find(f=>bareEntitySlug(f.slug)===bareEntitySlug(site.slug))}function nestedPickKeysToPrune(block,key,next){const prev=block==null?void 0:block[key];if(!block||!Array.isArray(prev))return[];const keep=new Set(next);const gone=prev.filter(k=>typeof k==="string"&&!keep.has(k));if(!gone.length)return[];return Object.keys(block).filter(k=>gone.some(g=>k.startsWith(`${key}:${g}:`)))}export{isTargetChoice,PACT_WEAPON_CHOICE_ID,pactWeaponPick,classPactWeaponPick,memberChoices,memberSpellTargets,spellsReached,poolMemberSites,poolMemberSitesOf,featPickSites,raceFeatSites,featOfSite,nestedPickKeysToPrune};
@@ -1 +1 @@
1
- import{parseCastingTime}from"./chunk-CMIEZQL4.js";import{derivePoolLayout}from"./chunk-O776WL7O.js";import{readTableColumn}from"./chunk-CSTAQQGX.js";import{findItemAction,isReadOnceItem,resolveItemAction}from"./chunk-DVUXUIPV.js";import{requiresAttunement}from"./chunk-YGH7S5ZF.js";import{defaultSlotForType,effectiveArmor,isItemEntity,isShieldArmor,resolveEntityForEntry,slotAcTerms}from"./chunk-4IAMSRHD.js";import{warnOnce}from"./chunk-DZITM5AG.js";import{keptSlugFor,resolveBaseItem}from"./chunk-PZ4L2EEG.js";import{bucketOf,memoByRevision}from"./chunk-QMEKQTUT.js";import{bareEntitySlug,slugify,twinKey,wikilinkTailSlug}from"./chunk-63YJPWTM.js";import{parseInlineTag}from"./chunk-BREHZNTL.js";import{isCanonicalDamageType}from"./chunk-7FPQJDFD.js";function equivalentResourceIds(id,index){var _a,_b,_c;const out=[];const add=other=>{if(other!==id&&index.has(other)&&!out.includes(other))out.push(other)};for(const other of(_b=(_a=index.get(id))==null?void 0:_a.equivalentIds)!=null?_b:[])add(other);for(const res of index.values())if((_c=res.equivalentIds)==null?void 0:_c.includes(id))add(res.id);return out}function ownedByClass(res,rc){var _a,_b;const s=(_a=res==null?void 0:res.owner)==null?void 0:_a.source;if(!s)return false;if(s.kind==="class")return s.slug===((_b=rc.entity)==null?void 0:_b.slug);if(s.kind==="subclass")return!!rc.subclass&&s.slug===rc.subclass.slug;return false}function payingResourceId(id,index,owner){const candidates=[id,...equivalentResourceIds(id,index)].filter(c=>index.has(c));if(candidates.length===0)return void 0;if(owner){const own=candidates.find(c=>ownedByClass(index.get(c),owner));if(own)return own}return candidates[0]}function classOfSource(source,classes){var _a,_b;if(source.kind==="class")return(_a=classes.find(c=>{var _a2;return((_a2=c.entity)==null?void 0:_a2.slug)===source.slug}))!=null?_a:null;if(source.kind==="subclass")return(_b=classes.find(c=>{var _a2;return((_a2=c.subclass)==null?void 0:_a2.slug)===source.slug}))!=null?_b:null;return null}function bindFeatureConsumers(features,index,classes){return features.map(rf=>{const consumes=rf.feature.consumes;const id=consumes==null?void 0:consumes.resource;if(!consumes||typeof id!=="string"||id.length===0)return rf;const payer=payingResourceId(id,index,classOfSource(rf.source,classes));if(payer===void 0||payer===id)return rf;return{...rf,feature:{...rf.feature,consumes:{...consumes,resource:payer}}}})}var SORTED_OPTIONAL_FEATURES=new WeakMap;function sortedOptionalFeatures(registry){return memoByRevision(SORTED_OPTIONAL_FEATURES,registry,()=>bucketOf(registry,"optional-feature").slice().sort((a,b)=>a.name.localeCompare(b.name)||a.slug.localeCompare(b.slug)))}var SRD_OWNER_PREFIXES=new Set(["srd-5e","srd-2024"]);function levelPrereqMax(d){var _a;return((_a=d.prerequisites)!=null?_a:[]).filter(p=>p.kind==="level").reduce((m,p)=>Math.max(m,p.min),0)}function namedRefKey(name){return name?slugify(name.replace(/\s*\([^)]*\)\s*$/,"")):""}function levelPrereqRefsMet(d,rc){var _a,_b;for(const p of(_a=d.prerequisites)!=null?_a:[]){if(p.kind!=="level")continue;if(p.class&&namedRefKey(p.class.name)!==namedRefKey((_b=rc.entity)==null?void 0:_b.name))return false;if(p.subclass){const sub=rc.subclass;const own=[sub==null?void 0:sub.short_name,sub==null?void 0:sub.name].map(namedRefKey).filter(k=>k!=="");if(!own.includes(namedRefKey(p.subclass.name)))return false}}return true}function optionalFeaturePrereqKeys(d){var _a;return((_a=d.prerequisites)!=null?_a:[]).filter(p=>p.kind==="optionalfeature").map(p=>twinKey(wikilinkTailSlug(p.optionalfeature)))}function withOptionalFeaturePrereqsMet(offered,selected,grants){let open=offered;for(;;){const openSlugs=new Set(open.map(e=>e.slug));const held=new Set([...grants,...selected.filter(e=>openSlugs.has(e.slug))].map(e=>twinKey(e.slug)));const next=open.filter(e=>optionalFeaturePrereqKeys(e.entity).every(k=>held.has(k)));if(next.length===open.length)return next;open=next}}function poolAnchorLevel(entity,pool){let anchorLevel=1;let columnSeen=false;for(let l=1;l<=20;l++){const c=readTableColumn(entity.table,l,[pool.count.column]);if(c!=null)columnSeen=true;if(c!=null&&c>=1){anchorLevel=l;break}}return{anchorLevel,columnSeen}}function resolvePool(rc,classIndex,pool,registry,index,edition){var _a,_b,_c,_d,_e,_f,_g,_h,_i;const entity=rc.entity;const level=rc.level;const ownerBare=bareEntitySlug(entity.slug);const ownerPrefix=entity.slug.split("_")[0];const ownEdition=SRD_OWNER_PREFIXES.has(ownerPrefix)?entity.edition:void 0;const col=pool.count.column;const count=(_a=readTableColumn(entity.table,level,[col]))!=null?_a:0;const{anchorLevel,columnSeen}=poolAnchorLevel(entity,pool);if(!columnSeen){warnOnce(`pool-column:${pool.id}`,`Archivist: pool "${pool.id}" declares count column "${col}", which "${entity.slug}"'s class table carries at no level; the pool resolves count 0 at anchor level 1`)}const ft=pool.source.where.feature_type;const all=sortedOptionalFeatures(registry);const entryOf=(slug,entity2,compendium)=>({slug,entity:entity2,...compendium?{compendium}:{},key:slug,param:null,itemBound:isItemBound(entity2)});const byBare=new Map;const candidates=new Map;for(const e of all){const d=e.data;const entry=entryOf(e.slug,d,e.compendium);const bare=bareEntitySlug(e.slug);byBare.set(bare,entry);if(d.feature_type!==ft)continue;if(!((_b=d.available_to)!=null?_b:[]).some(l=>wikilinkTailSlug(l)===ownerBare))continue;if(levelPrereqMax(d)>level)continue;if(!levelPrereqRefsMet(d,rc))continue;if(ownEdition&&d.edition&&d.edition!==ownEdition)continue;const key=twinKey(e.slug);const group=candidates.get(key);if(group)group.push(entry);else candidates.set(key,[entry])}const collapsed=[];for(const group of candidates.values()){if(group.length===1){collapsed.push(group[0]);continue}const bare=bareEntitySlug(group[0].slug);const owned=group.find(e=>e.slug.split("_")[0]===ownerPrefix);if(!owned){warnOnce(`pool-collapse:${bare}`,`Archivist: pool "${pool.id}" holds ${group.length} cross-edition entries for "${bare}" and none shares the owner's compendium prefix "${ownerPrefix}"; keeping "${group[0].slug}"`)}collapsed.push(owned!=null?owned:group[0])}const grantDecls=[...(_d=(_c=rc.entity)==null?void 0:_c.pool_grants)!=null?_d:[],...(_f=(_e=rc.subclass)==null?void 0:_e.pool_grants)!=null?_f:[]];const grantsRaw=grantDecls.filter(g=>g.pool===pool.id).flatMap(g=>g.grants).filter(g=>g.at_level<=level).map(g=>byBare.get(wikilinkTailSlug(g.feature))).filter(e=>e!=null);const grantedBare=new Set;const grants=grantsRaw.filter(e=>{const key=bareEntitySlug(e.slug);if(grantedBare.has(key))return false;grantedBare.add(key);return true});const offered=collapsed.filter(e=>!grantedBare.has(bareEntitySlug(e.slug)));const bySlugAvailable=new Map(offered.map(e=>[e.slug,e]));const byTwinAvailable=new Map(offered.map(e=>[twinKey(e.slug),e]));const resolveStored=s=>{const exact=bySlugAvailable.get(s);if(exact)return exact;const survivor=byTwinAvailable.get(twinKey(s));if(survivor)return survivor;const full=registry.getByTypeAndSlug("optional-feature",s);if(full)return entryOf(full.slug,full.data,full.compendium);return byBare.get(bareEntitySlug(s))};const raw=(_g=rc.choices[anchorLevel])==null?void 0:_g[pool.id];const selectedSlugs=Array.isArray(raw)?raw:typeof raw==="string"?[raw]:[];const selected=[];const seenKeys=new Set;for(const s of selectedSlugs){const{slugPart,param}=parsePickKey(s);const entry=resolveStored(slugPart);if(!entry)continue;const repeatable=entry.entity.repeatable===true;if(!repeatable&&param!==null){warnOnce(`pick-param:${pool.id}:${s}`,`Archivist: pool "${pool.id}" pick "${s}" names a parameter, but "${entry.slug}" is not repeatable; the parameter is ignored`)}const nkey=repeatable?normalizedPickKey(s,true):twinKey(entry.slug);if(grantedBare.has(bareEntitySlug(entry.slug))||seenKeys.has(nkey))continue;seenKeys.add(nkey);selected.push({...entry,key:repeatable||param!==null?s:entry.slug,param:repeatable?param:null,...repeatable?{option:resolveCopyOption(entry.entity,param,{classLevel:level,registry,edition})}:{}})}const available=withOptionalFeaturePrereqsMet(offered,selected,grants);const members=[...available,...grants];const layout=derivePoolLayout(members);const votes=new Map;for(const e of members){const id=(_h=e.entity.consumes)==null?void 0:_h.resource;const payer=id?payingResourceId(id,index,rc):void 0;if(!payer)continue;votes.set(payer,((_i=votes.get(payer))!=null?_i:0)+1)}let resource;let bestN=0;for(const[id,n]of votes)if(n>bestN){resource=id;bestN=n}const bind=poolRebinder(rc,pool.id,resource,index);return{id:pool.id,label:pool.label,classIndex,count,anchorLevel,selected:selected.map(bind),available:available.map(bind),grants:grants.map(bind),...layout?{layout}:{},...resource?{resource}:{},...pool.count.label?{countLabel:pool.count.label}:{},...pool.active?{active:pool.active}:{},...pool.head_resource?{headResource:pool.head_resource}:{}}}function poolRebinder(rc,poolId,vote,index){const declared=declaredResourceIds(rc);const copies=new Map;return e=>{const consumes=e.entity.consumes;const id=consumes==null?void 0:consumes.resource;if(!consumes||typeof id!=="string"||id.length===0)return e;const payer=payingResourceId(id,index,rc);if(payer===id)return e;const target=payer!=null?payer:vote!==void 0&&!declared.has(id)?vote:void 0;if(target===void 0)return e;const done=copies.get(e.key);if(done)return done;if(payer===void 0){warnOnce(`pool-rebind:${poolId}:${id}`,`Archivist: pool "${poolId}" members consume "${id}", which this character does not own; bound to the pool's resource "${target}"`)}const copy={...e,entity:{...e.entity,consumes:{...consumes,resource:target}}};copies.set(e.key,copy);return copy}}function declaredResourceIds(rc){var _a;const out=new Set;const add=list=>{for(const r of list!=null?list:[])if(typeof(r==null?void 0:r.id)==="string")out.add(r.id)};for(const owner of[rc.entity,rc.subclass]){if(!owner)continue;add(owner.resources);for(const features of Object.values((_a=owner.features_by_level)!=null?_a:{}))for(const f of features!=null?features:[])add(f.resources)}return out}function resolveAllPools(resolved,registry,index){const out=[];resolved.classes.forEach((rc,classIndex)=>{var _a,_b,_c,_d;if(!rc.entity)return;const decls=[...(_a=rc.entity.selection_pools)!=null?_a:[],...(_c=(_b=rc.subclass)==null?void 0:_b.selection_pools)!=null?_c:[]];const seen=new Set;for(const pool of decls){if(seen.has(pool.id))continue;seen.add(pool.id);out.push(resolvePool(rc,classIndex,pool,registry,index,(_d=resolved.definition)==null?void 0:_d.edition))}});return out}function strandedPicks(pool){const inAvailable=new Set(pool.available.map(e=>e.slug));return pool.selected.filter(e=>!inAvailable.has(e.slug))}function heldPicks(pool){var _a;const selected=(_a=pool.selected)!=null?_a:[];if(!pool.available)return[...selected];const inAvailable=new Set(pool.available.map(e=>e.slug));return selected.filter(e=>inAvailable.has(e.slug))}function withoutStrandedSites(sites,classes,registry,edition){if(sites.length===0)return sites;const strandedKeys=new Map;const keysOf=(classIndex,poolId)=>{var _a,_b,_c;const at=`${classIndex}:${poolId}`;let keys=strandedKeys.get(at);if(keys)return keys;const rc=classes[classIndex];const decl=(rc==null?void 0:rc.entity)?[...(_a=rc.entity.selection_pools)!=null?_a:[],...(_c=(_b=rc.subclass)==null?void 0:_b.selection_pools)!=null?_c:[]].find(p=>p.id===poolId):void 0;keys=new Set(rc&&decl?strandedPicks(resolvePool(rc,classIndex,decl,registry,new Map,edition)).map(e=>twinKey(e.slug)):[]);strandedKeys.set(at,keys);return keys};return sites.filter(site=>!keysOf(site.classIndex,site.poolId).has(twinKey(site.memberSlug)))}function poolCountLabel(pool){var _a;return(_a=pool.countLabel)!=null?_a:"Known"}function poolActiveWords(pool){var _a,_b,_c;const a=pool.active;if(!a)return null;return{column:a.column,label:a.label,verb:a.verb,counterLabel:(_a=a.counter_label)!=null?_a:a.label,createLabel:(_b=a.create_label)!=null?_b:"Created",createVerb:(_c=a.create_verb)!=null?_c:"Create"}}function parsePickKey(stored){const i=stored.indexOf("#");return i===-1?{slugPart:stored,param:null}:{slugPart:stored.slice(0,i),param:stored.slice(i+1)}}function normalizedPickKey(stored,repeatable){const{slugPart,param}=parsePickKey(stored);return repeatable?`${bareEntitySlug(slugPart)}#${param!=null?param:""}`:bareEntitySlug(slugPart)}function markerKey(by){const{slugPart,param}=parsePickKey(by);return param===null?bareEntitySlug(slugPart):`${bareEntitySlug(slugPart)}#${param}`}function isItemBound(note){var _a;return!!note.infuse||note.repeatable===true&&!!((_a=note.options)==null?void 0:_a.some(r=>!!r.creates))}var SRD_BOOKS=new Set(["SRD 2024","SRD 5e"]);var lc=v=>String(v!=null?v:"").trim().toLowerCase();var linkSlug=link=>link.replace(/^\[\[/,"").replace(/\]\]$/,"").split("|")[0];var itemsOf=registry=>registry.search("","item",Number.POSITIVE_INFINITY);function matchesFilter(data,f){var _a;const type=lc(data.type);if(!f.rarity.map(lc).includes(lc(data.rarity)))return false;if(f.types&&!f.types.map(lc).includes(type))return false;if((_a=f.exclude_types)==null?void 0:_a.map(lc).includes(type))return false;return!(f.cursed===false&&data.cursed===true)}function rowMatches(row,it){const c=row.creates;if(c.item)return lc(it.name)===lc(row.name)||it.slug===linkSlug(c.item);if(c.variant)return c.variant.candidates.some(l=>bareEntitySlug(linkSlug(l))===bareEntitySlug(it.slug));return!!c.filter&&matchesFilter(it.data,c.filter)}function buildItemIndex(items){const lcType=[],lcRarity=[];const byLcName=new Map,bySlug=new Map,byBare=new Map;const push=(m,k,i)=>{const l=m.get(k);if(l)l.push(i);else m.set(k,[i])};items.forEach((it,i)=>{const data=it.data;lcType.push(lc(data.type));lcRarity.push(lc(data.rarity));push(byLcName,lc(it.name),i);if(!bySlug.has(it.slug))bySlug.set(it.slug,i);push(byBare,bareEntitySlug(it.slug),i)});return{items,lcType,lcRarity,byLcName,bySlug,byBare}}var ITEM_INDEX=new WeakMap;var itemIndexOf=registry=>memoByRevision(ITEM_INDEX,registry,()=>buildItemIndex(itemsOf(registry)));var inBucketOrder=(ix,hits)=>[...hits].sort((a,b)=>a-b).map(i=>ix.items[i]);function rowInstalledIn(row,ix){var _a,_b,_c;const c=row.creates;if(c.item){const hits=new Set((_a=ix.byLcName.get(lc(row.name)))!=null?_a:[]);const own=ix.bySlug.get(linkSlug(c.item));if(own!==void 0)hits.add(own);return inBucketOrder(ix,hits)}if(c.variant){const hits=new Set;for(const l of c.variant.candidates)for(const i of(_b=ix.byBare.get(bareEntitySlug(linkSlug(l))))!=null?_b:[])hits.add(i);return inBucketOrder(ix,hits)}const f=c.filter;if(!f)return[];const rarities=new Set(f.rarity.map(lc));const types=f.types?new Set(f.types.map(lc)):null;const excluded=new Set(((_c=f.exclude_types)!=null?_c:[]).map(lc));return ix.items.filter((it,i)=>rarities.has(ix.lcRarity[i])&&(!types||types.has(ix.lcType[i]))&&!excluded.has(ix.lcType[i])&&!(f.cursed===false&&it.data.cursed===true))}var rowInstalled=(row,registry)=>rowInstalledIn(row,itemIndexOf(registry));function candidateOrder(edition){return(a,b)=>{const ea=edition&&lc(a.data.edition)===edition?0:1;const eb=edition&&lc(b.data.edition)===edition?0:1;if(ea!==eb)return ea-eb;const sa=SRD_BOOKS.has(a.compendium)?0:1,sb=SRD_BOOKS.has(b.compendium)?0:1;if(sa!==sb)return sa-sb;return a.slug<b.slug?-1:a.slug>b.slug?1:0}}function optionCandidates(row,registry,opts={}){return candidatesFrom(rowInstalled(row,registry),registry,opts)}function candidatesFrom(installed,registry,opts){var _a,_b;const visible=(_a=opts.isEntityVisible)!=null?_a:(()=>true);const excluded=((_b=opts.exclude)!=null?_b:[]).map(s=>{var _a2;return registry.getByTypeAndSlug("item",(_a2=keptSlugFor(s))!=null?_a2:s)}).filter(e=>!!e);const exNames=new Set(excluded.map(e=>lc(e.name))),exBares=new Set(excluded.map(e=>bareEntitySlug(e.slug)));const seen=new Set,out=[];for(const e of installed.filter(visible).sort(candidateOrder(opts.edition))){const bare=bareEntitySlug(e.slug);if(seen.has(bare))continue;seen.add(bare);if(exNames.has(lc(e.name))||exBares.has(bare))continue;out.push(e.slug)}return out}function resolveOptionRows(note,registry,opts={}){var _a;const ix=itemIndexOf(registry);return((_a=note.options)!=null?_a:[]).map(row=>{var _a2;const rowItems=rowInstalledIn(row,ix);const candidates=candidatesFrom(rowItems,registry,opts);const anyVisible=candidates.length>0||candidatesFrom(rowItems,registry,{...opts,exclude:[]}).length>0;const installed=rowItems.length>0;return{key:row.key,name:row.name,minLevel:row.min_level,...row.attunement!==void 0?{attunement:row.attunement}:{},arm:row.creates.item?"item":row.creates.variant?"variant":"filter",candidates,availability:anyVisible?"installed":installed?"hidden-only":"not-installed",...rowItemWords(row,candidates[0]?ix.items[(_a2=ix.bySlug.get(candidates[0]))!=null?_a2:-1]:rowItems[0])}})}function rowItemWords(row,item){var _a,_b,_c,_d;const f=row.creates.filter;if(f)return{type:((_a=f.types)==null?void 0:_a[0])?lc(f.types[0]):null,rarity:f.rarity[0]?lc(f.rarity[0]):null,charges:null};const data=(_b=item==null?void 0:item.data)!=null?_b:{};const max=(_c=data.charges)==null?void 0:_c.max;return{type:lc(data.type)||null,rarity:lc(data.rarity)||null,charges:typeof max==="number"&&max>0?{max,...typeof((_d=data.charges)==null?void 0:_d.recharge)==="string"?{recharge:data.charges.recharge}:{}}:null}}function resolveCopyOption(note,param,ctx){var _a,_b,_c;const rows=(_a=note.options)!=null?_a:[];if(param===null||param==="")return{row:null,status:"needs-choice"};if(note.item_choice==="create"){const row=rows.find(r=>r.key===param);if(!row)return{row:null,status:"invalid"};const installed=rowInstalled(row,ctx.registry).sort(candidateOrder(ctx.edition));if(installed.length===0)return{row,status:"not-installed"};const own=row.creates.item?linkSlug(row.creates.item):void 0;const item=row.creates.item?((_b=installed.find(e=>e.slug===own))!=null?_b:installed[0]).slug:void 0;return{row,...item?{item}:{},status:row.min_level<=ctx.classLevel?"ok":"level"}}const slug=(_c=keptSlugFor(param))!=null?_c:param;const it=ctx.registry.getByTypeAndSlug("item",slug);if(!it)return{row:null,item:slug,status:"not-installed"};const matching=rows.filter(r=>rowMatches(r,it)).sort((a,b)=>a.min_level-b.min_level);if(matching.length===0)return{row:null,item:slug,status:"invalid"};return{row:matching[0],item:slug,status:matching[0].min_level<=ctx.classLevel?"ok":"level"}}var MUNDANE=new Set(["","none","mundane"]);var isMagic=data=>{const r=data==null?void 0:data.rarity;return typeof r==="string"&&!MUNDANE.has(r.trim().toLowerCase())};var plainText=item=>item.replace(/^\[\[/,"").replace(/\]\]$/,"").split("|").pop().split("/").pop();function scaledInfuseItem(infuse,classLevel){var _a,_b;let item={...(_a=infuse.item)!=null?_a:{}};const rows=[...(_b=infuse.scales_at)!=null?_b:[]].sort((a,b)=>a.level-b.level);for(const row of rows)if(row.level<=classLevel)item={...item,...row.item};return item}function wrapInfused(entry,note,classLevel,registry){var _a,_b,_c,_d,_e,_f,_g,_h,_i,_j,_k;const infuse=note.infuse;const item=scaledInfuseItem(infuse,classLevel);const resist=[...(_a=item.resist)!=null?_a:[],...((_b=infuse.choice)==null?void 0:_b.kind)==="damage-type"&&((_c=entry.infusion)==null?void 0:_c.choice)?[entry.infusion.choice]:[]];const overlay={...item.bonuses?{bonuses:item.bonuses}:{},resist,...item.charges?{charges:item.charges}:{},...item.action?{action:item.action}:{},...item.range?{range:item.range}:{},...infuse.attunement?{attunement:{required:true}}:{}};const base=resolveBaseItem(entry.item,registry);const data=(_d=base==null?void 0:base.data)!=null?_d:null;if(base&&isMagic(data)){const b=data;const bonuses={...(_e=b.bonuses)!=null?_e:{}};for(const[k,v]of Object.entries((_f=item.bonuses)!=null?_f:{}))if(typeof v==="number")bonuses[k]=(typeof bonuses[k]==="number"?bonuses[k]:0)+v;return{entity:{...b,bonuses,resist:[...new Set([...(_g=b.resist)!=null?_g:[],...resist])],attunement:{required:requiresAttunement(b)||!!infuse.attunement}},magicBase:true}}const rarity=(_h=infuse.rarity)!=null?_h:"unknown";if(!base){const text=plainText(entry.item);return{entity:{slug:`infused:${slugify(text)}`,name:text,type:"wondrous item",rarity,...overlay,description:""},magicBase:false}}const name=String((_i=data==null?void 0:data.name)!=null?_i:base.name),description=String((_j=data==null?void 0:data.description)!=null?_j:"");const slotted=base.entityType==="armor"||base.entityType==="weapon"?base:typeof(data==null?void 0:data.base_item)==="string"?resolveBaseItem(data.base_item,registry):null;if(slotted&&(slotted.entityType==="armor"||slotted.entityType==="weapon")){const type=slotted.entityType==="weapon"?"weapon":isShieldArmor(slotted.data)?"shield":"armor";return{entity:{slug:base.slug,name,type,rarity,base_item:`[[${slotted.slug}]]`,...overlay,description},magicBase:false}}return{entity:{slug:base.slug,name,type:String((_k=data==null?void 0:data.type)!=null?_k:"adventuring gear"),rarity,...overlay,description},magicBase:false}}function resolveEntryEntity(entry,index,registry,infusions){const view=!infusions?void 0:"views"in infusions?infusions.views.get(index):infusions.index===index?infusions:void 0;if(view)return{entity:view.entity,entityType:view.entityType};return resolveEntityForEntry(entry.item,registry)}function buildInfusionContext(character,resolved,registry){var _a,_b,_c,_d,_e;const equipment=(_a=character.equipment)!=null?_a:[];const pools=((_b=resolved.pools)!=null?_b:[]).filter(p=>!!p.active||p.selected.some(e=>e.itemBound));if(pools.length===0&&!equipment.some(e=>!!e.infusion))return void 0;const owners=new Map;for(const pool of pools)for(const entry of pool.selected)if(entry.itemBound)owners.set(normalizedPickKey(entry.key,entry.entity.repeatable===true),{pool,entry});const views=new Map,flags=[];const newest=new Map;equipment.forEach((e,i)=>{if(!e.infusion)return;const k=markerKey(e.infusion.by);const j=newest.get(k);if(j===void 0||equipment[j].infusion.seq<e.infusion.seq)newest.set(k,i)});equipment.forEach((e,i)=>{var _a2,_b2,_c2;const m=e.infusion;if(!m)return;const owner=owners.get(markerKey(m.by));const nullView=()=>{var _a3,_b3,_c3,_d2,_e2;return{index:i,kind:m.kind,entity:null,entityType:null,key:m.by,seq:m.seq,poolId:(_a3=owner==null?void 0:owner.pool.id)!=null?_a3:"",classIndex:(_b3=owner==null?void 0:owner.pool.classIndex)!=null?_b3:-1,noteSlug:(_c3=owner==null?void 0:owner.entry.slug)!=null?_c3:"",noteName:(_d2=owner==null?void 0:owner.entry.entity.name)!=null?_d2:"",sourceLabel:(_e2=owner==null?void 0:owner.entry.entity.name)!=null?_e2:""}};if(!owner){flags.push({index:i,reason:"orphan"});if(m.kind==="created")views.set(i,nullView());return}if(newest.get(markerKey(m.by))!==i){flags.push({index:i,reason:"duplicate"});if(m.kind==="created")views.set(i,nullView());return}if(((_a2=e.qty)!=null?_a2:1)>1)flags.push({index:i,reason:"stack"});const classLevel=(_c2=(_b2=resolved.classes[owner.pool.classIndex])==null?void 0:_b2.level)!=null?_c2:0;const base={index:i,kind:m.kind,key:m.by,seq:m.seq,poolId:owner.pool.id,classIndex:owner.pool.classIndex,noteSlug:owner.entry.slug,noteName:owner.entry.entity.name,sourceLabel:owner.entry.entity.name};if(m.kind==="created"){const own=resolveEntityForEntry(e.item,registry);const it=resolveBaseItem(e.item,registry);const opt=owner.entry.option;const fits=!!it&&!!(opt==null?void 0:opt.row)&&(opt.item===it.slug||rowMatches(opt.row,it));if(!fits)flags.push({index:i,reason:"mismatch"});views.set(i,{...base,entity:own.entity,entityType:own.entityType});return}if(!owner.entry.entity.infuse){flags.push({index:i,reason:"orphan"});return}const w=wrapInfused(e,owner.entry.entity,classLevel,registry);if(w.magicBase)flags.push({index:i,reason:"magic-base"});views.set(i,{...base,entity:w.entity,entityType:"item"})});const counters=new Map;for(const pool of pools){const words=poolActiveWords(pool);if(!words)continue;const rc=resolved.classes[pool.classIndex];const max=(_e=readTableColumn((_c=rc==null?void 0:rc.entity)==null?void 0:_c.table,(_d=rc==null?void 0:rc.level)!=null?_d:0,[words.column]))!=null?_e:0;const used=[...views.values()].filter(v=>v.poolId===pool.id&&v.entity!==null).length;counters.set(pool.id,{label:words.counterLabel,used,max,over:used>max})}return{views,counters,flags}}function entryCharges(entry,view,registry){return effectiveItemCharges(entry,registry,view)}function withEntryCharges(entry,view,current,registry){var _a,_b,_c,_d,_e,_f;const overlayMax=(view==null?void 0:view.kind)==="infused"?itemChargesMax(view.entity):void 0;if(overlayMax!==void 0&&entry.infusion)return{...entry,infusion:{...entry.infusion,charges:{current:Math.max(0,Math.min(current,overlayMax))}}};const max=(_e=(_d=(_b=(_a=entry.state)==null?void 0:_a.charges)==null?void 0:_b.max)!=null?_d:(_c=effectiveItemCharges(entry,registry,view))==null?void 0:_c.max)!=null?_e:Math.max(0,current);return{...entry,state:{...(_f=entry.state)!=null?_f:{},charges:{current:Math.max(0,Math.min(current,max)),max}}}}function isMarkedEntry(entry){return!!entry.infusion}function splitOne(equipment,index){var _a,_b;const src=equipment[index];if(!src||((_a=src.qty)!=null?_a:1)<=1)return[...equipment];const one={item:src.item,qty:1,...src.in!==void 0?{in:src.in}:{},...src.overrides?{overrides:src.overrides}:{}};return[...equipment.slice(0,index),{...src,qty:((_b=src.qty)!=null?_b:1)-1},one,...equipment.slice(index+1)]}var refuse=reason=>({ok:false,reason});function endInfusion(equipment,index,registry){const entry=equipment[index];if(!(entry==null?void 0:entry.infusion))return{equipment:[...equipment],ended:[]};const{kind,by}=entry.infusion;if(kind==="infused"){const{infusion:_m,...rest}=entry;const keep=requiresAttunement(resolveEntryEntity(rest,index,registry).entity);const next=keep?rest:(({attuned:_a,...r})=>r)(rest);return{equipment:equipment.map((e,i)=>i===index?next:e),ended:[{index,key:by,kind,item:entry.item}]}}const moved=equipment.map((e,i)=>{if(i===index||entry.id===void 0||e.in!==entry.id)return e;if(entry.in===void 0){const{in:_in,...r}=e;return r}return{...e,in:entry.in}});return{equipment:moved.filter((_,i)=>i!==index),ended:[{index:-1,key:by,kind,item:entry.item}]}}var pickKeyOf=e=>normalizedPickKey(e.key,e.entity.repeatable===true);var nextSeq=equipment=>equipment.reduce((m,e)=>{var _a,_b;return Math.max(m,(_b=(_a=e.infusion)==null?void 0:_a.seq)!=null?_b:0)},0)+1;function ownedPick(resolved,key){var _a,_b;const k=markerKey(key);for(const pool of(_a=resolved.pools)!=null?_a:[]){const entry=pool.selected.find(e=>e.itemBound&&pickKeyOf(e)===k);if(entry)return{pool,entry,stranded:strandedPicks(pool).includes(entry)||((_b=entry.option)==null?void 0:_b.status)==="level"}}return null}var wordsOf=(...texts)=>texts.map(lc).join(" ").split(/[^a-z]+/).filter(w=>w!=="");function shapeOf(found,text,registry){var _a,_b,_c;if(!found)return{kind:"gear",words:wordsOf(text)};const data=(_a=found.data)!=null?_a:{};const words=wordsOf((_b=data.name)!=null?_b:text,data.type);const slotted=found.entityType==="armor"||found.entityType==="weapon"?found:typeof data.base_item==="string"?resolveBaseItem(data.base_item,registry):null;if((slotted==null?void 0:slotted.entityType)==="armor"){const armor=slotted.data;return{kind:isShieldArmor(armor)?"shield":"armor",words,category:lc(armor.category)}}if((slotted==null?void 0:slotted.entityType)==="weapon"){const w=slotted.data;return{kind:"weapon",words,category:lc(w.category),properties:((_c=w.properties)!=null?_c:[]).filter(p=>typeof p==="string").map(lc)}}return{kind:"gear",words}}function admits(t,s){var _a,_b,_c,_d;if(t.kind!==s.kind)return false;if(((_a=t.category)==null?void 0:_a.length)&&!t.category.map(lc).includes(((_b=s.category)!=null?_b:"").split("-")[0]))return false;if(t.property&&!((_c=s.properties)!=null?_c:[]).includes(lc(t.property)))return false;if(((_d=t.name_any)==null?void 0:_d.length)&&!t.name_any.some(n=>{const w=wordsOf(n);return w.length>0&&w.every(x=>s.words.includes(x))}))return false;return true}function targetVerdict(entry,infuse,registry){const found=resolveBaseItem(entry.item,registry);if(!infuse.targets.some(t=>admits(t,shapeOf(found,plainText(entry.item),registry))))return"target-kind";return found&&isMagic(found.data)?"magic-base":"ok"}function newObjectEntry(name,infuse,registry,visible){const want=lc(name);const found=[];for(const type of["armor","weapon","item"]){for(const e of registry.search(name,type,Number.POSITIVE_INFINITY)){if(lc(e.name)===want&&!isMagic(e.data)&&visible(e)&&infuse.targets.some(t=>admits(t,shapeOf(e,e.name,registry))))found.push(e)}}const first=found.sort(candidateOrder(void 0))[0];return first?{item:`[[${first.slug}]]`,qty:1}:{item:name,qty:1}}function endBySeqs(equipment,seqs,registry){let eq=[...equipment];let slots=eq.map((_,i)=>i);const rows=[];for(const{seq,by}of seqs){const i=eq.findIndex(e=>{var _a;return((_a=e.infusion)==null?void 0:_a.seq)===seq&&e.infusion.by===by});if(i===-1)continue;const w=endInfusion(eq,i,registry);for(const row of w.ended)rows.push({row,slot:slots[i]});if(eq[i].infusion.kind==="created")slots=slots.filter((_,j)=>j!==i);eq=w.equipment}return{equipment:eq,ended:rows.map(({row,slot})=>row.kind==="infused"?{...row,index:slots.indexOf(slot)}:row)}}function displaced(equipment,resolved,pool,key){var _a;const k=markerKey(key);const out=equipment.filter(e=>!!e.infusion&&markerKey(e.infusion.by)===k).map(e=>({seq:e.infusion.seq,by:e.infusion.by}));const counter=(_a=resolved.infusions)==null?void 0:_a.counters.get(pool.id);if(!counter)return out;const live=[...resolved.infusions.views.values()].filter(v=>v.poolId===pool.id&&v.classIndex===pool.classIndex&&v.entity!==null&&markerKey(v.key)!==k).sort((a,b)=>a.seq-b.seq);let used=live.length;for(const v of live){if(used+1<=counter.max)break;out.push({seq:v.seq,by:v.key});used--}return out}function infuseEntry(character,resolved,registry,req){var _a,_b,_c,_d,_e,_f,_g;const owned=ownedPick(resolved,req.key);if(!owned)return refuse("not-owned");const infuse=owned.entry.entity.infuse;if(!infuse)return refuse("not-infusing");if(owned.stranded)return refuse("stranded");const wantsChoice=((_a=infuse.choice)==null?void 0:_a.kind)==="damage-type";const choice=lc(req.choice);if(wantsChoice&&choice==="")return refuse("choice-required");if(wantsChoice&&!isCanonicalDamageType(choice))return refuse("bad-choice");if(wantsChoice&&((_b=infuse.choice)==null?void 0:_b.options)&&!infuse.choice.options.some(o=>lc(o)===choice))return refuse("bad-choice");const equipment=(_c=character.equipment)!=null?_c:[];const charges=scaledInfuseItem(infuse,(_e=(_d=resolved.classes[owned.pool.classIndex])==null?void 0:_d.level)!=null?_e:0).charges;const marker={kind:"infused",by:owned.entry.key,seq:nextSeq(equipment),...wantsChoice?{choice}:{},...charges?{charges:{current:charges.max}}:{}};let placed;if(typeof req.target==="number"){const target=equipment[req.target];if(!target)return refuse("no-target");if(target.infusion)return refuse("marked");const verdict=targetVerdict(target,infuse,registry);if(verdict!=="ok")return refuse(verdict);const split=((_f=target.qty)!=null?_f:1)>1;placed=split?splitOne(equipment,req.target):[...equipment];const i=split?req.target+1:req.target;placed[i]={...placed[i],infusion:marker}}else{const name=req.target.newObject.trim();if(name==="")return refuse("no-target");placed=[...equipment,{...newObjectEntry(name,infuse,registry,(_g=req.isEntityVisible)!=null?_g:(()=>true)),infusion:marker}]}return{ok:true,...endBySeqs(placed,displaced(equipment,resolved,owned.pool,owned.entry.key),registry)}}function createEntry(character,resolved,registry,req){var _a,_b;const owned=ownedPick(resolved,req.key);if(!owned)return refuse("not-owned");const note=owned.entry.entity;if(!(note.repeatable===true&&!!((_a=note.options)==null?void 0:_a.some(r=>!!r.creates))))return refuse("not-creating");if(owned.stranded)return refuse("stranded");const opt=owned.entry.option;if(!(opt==null?void 0:opt.row)||opt.status!=="ok")return refuse("invalid-item");const it=registry.getByTypeAndSlug("item",linkSlug(req.item.trim()));if(!it||!(opt.item===it.slug||rowMatches(opt.row,it)))return refuse("invalid-item");const equipment=(_b=character.equipment)!=null?_b:[];const placed=[...equipment,{item:`[[${it.slug}]]`,qty:1,infusion:{kind:"created",by:owned.entry.key,seq:nextSeq(equipment)}}];return{ok:true,...endBySeqs(placed,displaced(equipment,resolved,owned.pool,owned.entry.key),registry)}}function markersWhere(equipment,pick){const out=[];equipment.forEach((e,index)=>{const m=e.infusion;if(m&&pick(m))out.push({index,key:m.by,kind:m.kind,item:e.item,seq:m.seq,by:m.by})});return out}var asRows=list=>list.map(({index,key,kind,item})=>({index,key,kind,item}));var storedKeys=v=>typeof v==="string"?[v]:Array.isArray(v)?v:[];function choiceEnds(character,resolved,req){var _a,_b,_c,_d,_e,_f;const pool=((_a=resolved.pools)!=null?_a:[]).find(p=>p.classIndex===req.classIndex&&p.id===req.choiceKey);if(!pool||!(pool.active||pool.selected.some(e=>e.itemBound)))return[];const choices=(_c=(_b=character.class[req.classIndex])==null?void 0:_b.choices)!=null?_c:{};const kept=new Set(req.next.map(markerKey));for(const lvl of Object.keys(choices))if(Number(lvl)!==req.level)for(const s of storedKeys((_d=choices[Number(lvl)])==null?void 0:_d[req.choiceKey]))kept.add(markerKey(s));const removed=new Set(storedKeys((_e=choices[req.level])==null?void 0:_e[req.choiceKey]).map(markerKey).filter(k=>!kept.has(k)));return markersWhere((_f=character.equipment)!=null?_f:[],m=>removed.has(markerKey(m.by)))}function infusionsEndedByChoice(character,resolved,_registry,req){return asRows(choiceEnds(character,resolved,req))}function reconcileChoiceEdit(character,resolved,registry,req){var _a;const list=choiceEnds(character,resolved,req);return list.length===0?null:endBySeqs((_a=character.equipment)!=null?_a:[],list,registry)}function classEnds(character,resolved,req){var _a,_b,_c,_d,_e;let pools=((_a=resolved.pools)!=null?_a:[]).filter(p=>p.classIndex===req.classIndex);if(!("remove"in req)){const old=(_c=(_b=resolved.classes[req.classIndex])==null?void 0:_b.subclass)!=null?_c:null;if(!old||req.subclass!==null&&bareEntitySlug(linkSlug(req.subclass.trim()))===bareEntitySlug(old.slug))return[];const ids=new Set(((_d=old.selection_pools)!=null?_d:[]).map(p=>p.id));pools=pools.filter(p=>ids.has(p.id))}const owned=new Set;for(const pool of pools)for(const e of pool.selected)if(e.itemBound)owned.add(pickKeyOf(e));return markersWhere((_e=character.equipment)!=null?_e:[],m=>owned.has(markerKey(m.by)))}function infusionsEndedByClassEdit(character,resolved,_registry,req){return asRows(classEnds(character,resolved,req))}function reconcileClassEdit(character,resolved,registry,req){var _a;const list=classEnds(character,resolved,req);return list.length===0?null:endBySeqs((_a=character.equipment)!=null?_a:[],list,registry)}function eligibleTargets(character,resolved,registry,key){var _a,_b;const infuse=(_a=ownedPick(resolved,key))==null?void 0:_a.entry.entity.infuse;if(!infuse)return[];const out=[];((_b=character.equipment)!=null?_b:[]).forEach((e,index)=>{var _a2;if(!e.infusion&&targetVerdict(e,infuse,registry)==="ok")out.push({index,stack:((_a2=e.qty)!=null?_a2:1)>1})});return out}var WEAPON_DEFAULT_ACTION_COST="action";var linkOf=item=>{var _a,_b;return(_b=(_a=item.match(/^\[\[(.+)\]\]$/))==null?void 0:_a[1])!=null?_b:null};var ruleOf=(entry,registry,view)=>resolveEntryEntity(entry,view?view.index:-1,registry,view!=null?view:null);function isWeaponLikeEntry(entry,registry,view){if(!registry)return false;const r=ruleOf(entry,registry,view);return defaultSlotForType(r.entityType,r.entity,registry)==="mainhand"}function itemsRowBranch(entry,registry,view){var _a,_b;const link=linkOf(entry.item);if(!link||!registry)return false;const t=view?view.entityType:(_b=(_a=registry.getBySlug(link))==null?void 0:_a.entityType)!=null?_b:null;return t!=="weapon"&&t!=="armor"&&!isWeaponLikeEntry(entry,registry,view)}function customizableOverrideKeys(entry,registry){const consumed=isConsumedOnUse(entry,registry);const keys=new Set(consumed?["name"]:["name","charges","recovery"]);if(!registry)return keys;const r=ruleOf(entry,registry);const slot=defaultSlotForType(r.entityType,r.entity,registry);const weaponLike=slot==="mainhand";const itemsRow=itemsRowBranch(entry,registry);if(weaponLike){keys.add("bonus");keys.add("damage_bonus");keys.add("extra_damage")}if(slot==="armor"||slot==="shield")keys.add("ac_bonus");if(weaponLike||itemsRow)keys.add("action");if(itemsRow)keys.add("range");const link=linkOf(entry.item);if(r.entityType==="item"&&!consumed&&!(link&&isReadOnceItem(link)))keys.add("resist");return keys}function defaultActionCost(entry,registry,view){var _a,_b,_c,_d,_e;if(isWeaponLikeEntry(entry,registry,view))return WEAPON_DEFAULT_ACTION_COST;const link=linkOf(entry.item);if(!link||!registry||!itemsRowBranch(entry,registry,view))return null;const withoutOverrides={...entry,overrides:void 0};const type=view?(_a=view.entity)==null?void 0:_a.type:(_c=(_b=registry.getBySlug(link))==null?void 0:_b.data)==null?void 0:_c.type;return(_e=(_d=resolveItemAction(link,withoutOverrides,type,{view,spellCost:scrollSpellCost(entry,registry)}))==null?void 0:_d.cost)!=null?_e:null}var SPELL_COST={action:"action",bonus:"bonus-action",reaction:"reaction"};function scrollSpellCost(entry,registry){var _a,_b,_c,_d,_e;const ref=(_a=entry.overrides)==null?void 0:_a.spell;if(!ref||!registry)return void 0;const castingTime=(_d=(_c=registry.getByTypeAndSlug("spell",(_b=linkOf(ref))!=null?_b:ref))==null?void 0:_c.data)==null?void 0:_d.casting_time;const kind=typeof castingTime==="string"?(_e=parseCastingTime(castingTime))==null?void 0:_e.kind:void 0;return kind?SPELL_COST[kind]:void 0}var chargesOf=e=>e==null?void 0:e.charges;function itemChargesMax(entity){const c=chargesOf(entity);if(typeof c==="number")return c>0?c:void 0;const m=c==null?void 0:c.max;return typeof m==="number"&&m>0?m:void 0}var RESET_OF=r=>{const s=String(r!=null?r:"").toLowerCase();return s.includes("dawn")?"dawn":s.includes("short")?"short":s.includes("long")?"long":"special"};function rechargeAmount(c){var _a,_b;const raw=[c.recharge_amount,c.dice].find(v=>typeof v==="string"&&v.trim()!=="");if(!raw)return"1";const bare=raw.trim().replace(/^`+|`+$/g,"");return((_b=(_a=parseInlineTag(bare))==null?void 0:_a.content)!=null?_b:bare).replace(/\s+/g,"")}var recoveryOf=(c,needRecharge)=>!c||typeof c==="number"||needRecharge&&(typeof c.recharge!=="string"||c.recharge.trim()==="")?void 0:{amount:rechargeAmount(c),reset:RESET_OF(c.recharge)};function effectiveItemRecovery(entry,registry,view){var _a,_b;if(isConsumedOnUse(entry,registry,view))return void 0;if(view&&view.entity===null)return void 0;if((view==null?void 0:view.kind)==="infused"&&itemChargesMax(view.entity)!==void 0)return recoveryOf(chargesOf(view.entity),false);if((_a=entry.state)==null?void 0:_a.recovery)return entry.state.recovery;const own=registry?recoveryOf(chargesOf(ruleOf(entry,registry,view).entity),true):void 0;if(own)return own;const link=linkOf(entry.item);return link?(_b=findItemAction(link))==null?void 0:_b.recovery:void 0}function isConsumedOnUse(entry,registry,view){var _a;const link=linkOf(entry.item);if(!link)return false;if((_a=findItemAction(link))==null?void 0:_a.consumed)return true;const entity=entityOf(entry,registry,view);return(entity==null?void 0:entity.type)==="potion"||isScrollEntity(entity)}function isScrollEntity(entity){if(!entity||typeof entity!=="object")return false;return entity.type==="scroll"||isCastableScroll(entity)}function isCastableScroll(entity){return settableSpellLevel(entity)!==null&&!storesSpell(entity)}function settableSpellLevel(entity){if(!entity||typeof entity!=="object")return null;const level=entity.scroll_level;return typeof level==="number"?level:null}function storesSpell(entity){if(settableSpellLevel(entity)===null)return false;const e=entity;if(e.type==="scroll")return false;return itemChargesMax(entity)!==void 0||typeof e.spell_charge_cost==="number"}function storedSpellNumbers(entity){if(!storesSpell(entity))return null;const e=entity;const text=[e.description,...Array.isArray(e.entries)?e.entries:[]].filter(t=>typeof t==="string").join("\n");const fromText=re=>{const m=re.exec(text);return m?parseInt(m[1],10):void 0};const saveDC=typeof e.spell_save_dc==="number"?e.spell_save_dc:fromText(/\bsav(?:e|ing throw) DC (?:is|of) (\d+)/i);const attackBonus=typeof e.spell_attack_bonus==="number"?e.spell_attack_bonus:fromText(/\battack bonus (?:is|of) \+?(-?\d+)/i);if(saveDC===void 0&&attackBonus===void 0)return null;return{...saveDC!==void 0?{saveDC}:{},...attackBonus!==void 0?{attackBonus}:{}}}function itemSpellUse(entry,registry,view){const entity=entityOf(entry,registry,view);if(settableSpellLevel(entity)===null)return null;if(isConsumedOnUse(entry,registry,view))return{kind:"consume"};const declared=entity.spell_charge_cost;const cost=typeof declared==="number"&&Number.isInteger(declared)&&declared>=0?declared:1;const charges=effectiveItemCharges(entry,registry,view);if(cost===0||!charges)return{kind:"at-will"};return{kind:"charges",cost,charges:{current:charges.current,max:charges.max}}}function entityOf(entry,registry,view){if(!registry||!linkOf(entry.item))return null;return ruleOf(entry,registry,view).entity}function effectiveItemCharges(entry,registry,view){var _a,_b,_c,_d,_e,_f;if(isConsumedOnUse(entry,registry,view))return void 0;if(view&&view.entity===null)return void 0;const infused=(view==null?void 0:view.kind)==="infused"?itemChargesMax(view.entity):void 0;if(infused!==void 0)return{current:Math.max(0,Math.min((_c=(_b=(_a=entry.infusion)==null?void 0:_a.charges)==null?void 0:_b.current)!=null?_c:infused,infused)),max:infused};const stored=(_d=entry.state)==null?void 0:_d.charges;if(stored)return stored;const own=registry?itemChargesMax(ruleOf(entry,registry,view).entity):void 0;if(own!==void 0)return{current:own,max:own};const link=linkOf(entry.item);const max=link?(_f=(_e=findItemAction(link))==null?void 0:_e.max_charges)!=null?_f:0:0;return max>0?{current:max,max}:void 0}function effectiveItemArmorClass(entry,registry,view){var _a;if(!registry)return null;const{entity}=ruleOf(entry,registry,view);const armor=effectiveArmor(entity,registry);if(!armor)return null;const shield=isShieldArmor(armor);const bonus=isItemEntity(entity)&&typeof((_a=entity.bonuses)==null?void 0:_a.ac)==="number"?entity.bonuses.ac:0;const terms=slotAcTerms(armor,entry);return{value:terms.armor+terms.override+bonus,shield,addDex:!shield&&armor.ac.add_dex===true}}export{WEAPON_DEFAULT_ACTION_COST,isWeaponLikeEntry,customizableOverrideKeys,defaultActionCost,scrollSpellCost,itemChargesMax,effectiveItemRecovery,isConsumedOnUse,isScrollEntity,isCastableScroll,settableSpellLevel,storesSpell,storedSpellNumbers,itemSpellUse,effectiveItemCharges,effectiveItemArmorClass,poolCountLabel,poolActiveWords,parsePickKey,normalizedPickKey,markerKey,isItemBound,optionCandidates,resolveOptionRows,resolveCopyOption,scaledInfuseItem,resolveEntryEntity,buildInfusionContext,entryCharges,withEntryCharges,isMarkedEntry,splitOne,endInfusion,infuseEntry,createEntry,infusionsEndedByChoice,reconcileChoiceEdit,infusionsEndedByClassEdit,reconcileClassEdit,eligibleTargets,bindFeatureConsumers,levelPrereqMax,levelPrereqRefsMet,poolAnchorLevel,resolvePool,resolveAllPools,strandedPicks,heldPicks,withoutStrandedSites};
1
+ import{parseCastingTime}from"./chunk-CMIEZQL4.js";import{derivePoolLayout}from"./chunk-O776WL7O.js";import{readTableColumn}from"./chunk-CSTAQQGX.js";import{findItemAction,isReadOnceItem,resolveItemAction}from"./chunk-DVUXUIPV.js";import{requiresAttunement}from"./chunk-YGH7S5ZF.js";import{defaultSlotForType,effectiveArmor,isItemEntity,isShieldArmor,resolveEntityForEntry,slotAcTerms}from"./chunk-4IAMSRHD.js";import{warnOnce}from"./chunk-DZITM5AG.js";import{keptSlugFor,resolveBaseItem}from"./chunk-PZ4L2EEG.js";import{bucketOf,memoByRevision}from"./chunk-QMEKQTUT.js";import{bareEntitySlug,slugify,twinKey,wikilinkTailSlug}from"./chunk-63YJPWTM.js";import{parseInlineTag}from"./chunk-BREHZNTL.js";import{isCanonicalDamageType}from"./chunk-7FPQJDFD.js";function equivalentResourceIds(id,index){var _a,_b,_c;const out=[];const add=other=>{if(other!==id&&index.has(other)&&!out.includes(other))out.push(other)};for(const other of(_b=(_a=index.get(id))==null?void 0:_a.equivalentIds)!=null?_b:[])add(other);for(const res of index.values())if((_c=res.equivalentIds)==null?void 0:_c.includes(id))add(res.id);return out}function ownedByClass(res,rc){var _a,_b;const s=(_a=res==null?void 0:res.owner)==null?void 0:_a.source;if(!s)return false;if(s.kind==="class")return s.slug===((_b=rc.entity)==null?void 0:_b.slug);if(s.kind==="subclass")return!!rc.subclass&&s.slug===rc.subclass.slug;return false}function payingResourceId(id,index,owner){const candidates=[id,...equivalentResourceIds(id,index)].filter(c=>index.has(c));if(candidates.length===0)return void 0;if(owner){const own=candidates.find(c=>ownedByClass(index.get(c),owner));if(own)return own}return candidates[0]}function classOfSource(source,classes){var _a,_b;if(source.kind==="class")return(_a=classes.find(c=>{var _a2;return((_a2=c.entity)==null?void 0:_a2.slug)===source.slug}))!=null?_a:null;if(source.kind==="subclass")return(_b=classes.find(c=>{var _a2;return((_a2=c.subclass)==null?void 0:_a2.slug)===source.slug}))!=null?_b:null;return null}function bindFeatureConsumers(features,index,classes){return features.map(rf=>{const consumes=rf.feature.consumes;const id=consumes==null?void 0:consumes.resource;if(!consumes||typeof id!=="string"||id.length===0)return rf;const payer=payingResourceId(id,index,classOfSource(rf.source,classes));if(payer===void 0||payer===id)return rf;return{...rf,feature:{...rf.feature,consumes:{...consumes,resource:payer}}}})}var SORTED_OPTIONAL_FEATURES=new WeakMap;function sortedOptionalFeatures(registry){return memoByRevision(SORTED_OPTIONAL_FEATURES,registry,()=>bucketOf(registry,"optional-feature").slice().sort((a,b)=>a.name.localeCompare(b.name)||a.slug.localeCompare(b.slug)))}var SRD_OWNER_PREFIXES=new Set(["srd-5e","srd-2024"]);function levelPrereqMax(d){var _a;return((_a=d.prerequisites)!=null?_a:[]).filter(p=>p.kind==="level").reduce((m,p)=>Math.max(m,p.min),0)}function namedRefKey(name){return name?slugify(name.replace(/\s*\([^)]*\)\s*$/,"")):""}function levelPrereqRefsMet(d,rc){var _a,_b;for(const p of(_a=d.prerequisites)!=null?_a:[]){if(p.kind!=="level")continue;if(p.class&&namedRefKey(p.class.name)!==namedRefKey((_b=rc.entity)==null?void 0:_b.name))return false;if(p.subclass){const sub=rc.subclass;const own=[sub==null?void 0:sub.short_name,sub==null?void 0:sub.name].map(namedRefKey).filter(k=>k!=="");if(!own.includes(namedRefKey(p.subclass.name)))return false}}return true}function optionalFeaturePrereqKeys(d){var _a;return((_a=d.prerequisites)!=null?_a:[]).filter(p=>p.kind==="optionalfeature").map(p=>twinKey(wikilinkTailSlug(p.optionalfeature)))}function withOptionalFeaturePrereqsMet(offered,selected,grants){let open=offered;for(;;){const openSlugs=new Set(open.map(e=>e.slug));const held=new Set([...grants,...selected.filter(e=>openSlugs.has(e.slug))].map(e=>twinKey(e.slug)));const next=open.filter(e=>optionalFeaturePrereqKeys(e.entity).every(k=>held.has(k)));if(next.length===open.length)return next;open=next}}function poolAnchorLevel(entity,pool){let anchorLevel=1;let columnSeen=false;for(let l=1;l<=20;l++){const c=readTableColumn(entity.table,l,[pool.count.column]);if(c!=null)columnSeen=true;if(c!=null&&c>=1){anchorLevel=l;break}}return{anchorLevel,columnSeen}}function resolvePool(rc,classIndex,pool,registry,index,edition){var _a,_b,_c,_d,_e,_f,_g,_h,_i;const entity=rc.entity;const level=rc.level;const ownerBare=bareEntitySlug(entity.slug);const ownerPrefix=entity.slug.split("_")[0];const ownEdition=SRD_OWNER_PREFIXES.has(ownerPrefix)?entity.edition:void 0;const col=pool.count.column;const count=(_a=readTableColumn(entity.table,level,[col]))!=null?_a:0;const{anchorLevel,columnSeen}=poolAnchorLevel(entity,pool);if(!columnSeen){warnOnce(`pool-column:${pool.id}`,`Archivist: pool "${pool.id}" declares count column "${col}", which "${entity.slug}"'s class table carries at no level; the pool resolves count 0 at anchor level 1`)}const ft=pool.source.where.feature_type;const all=sortedOptionalFeatures(registry);const entryOf=(slug,entity2,compendium)=>({slug,entity:entity2,...compendium?{compendium}:{},key:slug,param:null,itemBound:isItemBound(entity2)});const byBare=new Map;const candidates=new Map;for(const e of all){const d=e.data;const entry=entryOf(e.slug,d,e.compendium);const bare=bareEntitySlug(e.slug);byBare.set(bare,entry);if(d.feature_type!==ft)continue;if(!((_b=d.available_to)!=null?_b:[]).some(l=>wikilinkTailSlug(l)===ownerBare))continue;if(levelPrereqMax(d)>level)continue;if(!levelPrereqRefsMet(d,rc))continue;if(ownEdition&&d.edition&&d.edition!==ownEdition)continue;const key=twinKey(e.slug);const group=candidates.get(key);if(group)group.push(entry);else candidates.set(key,[entry])}const collapsed=[];for(const group of candidates.values()){if(group.length===1){collapsed.push(group[0]);continue}const bare=bareEntitySlug(group[0].slug);const owned=group.find(e=>e.slug.split("_")[0]===ownerPrefix);if(!owned){warnOnce(`pool-collapse:${bare}`,`Archivist: pool "${pool.id}" holds ${group.length} cross-edition entries for "${bare}" and none shares the owner's compendium prefix "${ownerPrefix}"; keeping "${group[0].slug}"`)}collapsed.push(owned!=null?owned:group[0])}const grantDecls=[...(_d=(_c=rc.entity)==null?void 0:_c.pool_grants)!=null?_d:[],...(_f=(_e=rc.subclass)==null?void 0:_e.pool_grants)!=null?_f:[]];const grantsRaw=grantDecls.filter(g=>g.pool===pool.id).flatMap(g=>g.grants).filter(g=>g.at_level<=level).map(g=>byBare.get(wikilinkTailSlug(g.feature))).filter(e=>e!=null);const grantedBare=new Set;const grants=grantsRaw.filter(e=>{const key=bareEntitySlug(e.slug);if(grantedBare.has(key))return false;grantedBare.add(key);return true});const offered=collapsed.filter(e=>!grantedBare.has(bareEntitySlug(e.slug)));const bySlugAvailable=new Map(offered.map(e=>[e.slug,e]));const byTwinAvailable=new Map(offered.map(e=>[twinKey(e.slug),e]));const resolveStored=s=>{const exact=bySlugAvailable.get(s);if(exact)return exact;const survivor=byTwinAvailable.get(twinKey(s));if(survivor)return survivor;const full=registry.getByTypeAndSlug("optional-feature",s);if(full)return entryOf(full.slug,full.data,full.compendium);return byBare.get(bareEntitySlug(s))};const raw=(_g=rc.choices[anchorLevel])==null?void 0:_g[pool.id];const selectedSlugs=Array.isArray(raw)?raw:typeof raw==="string"?[raw]:[];const selected=[];const seenKeys=new Set;for(const s of selectedSlugs){const{slugPart,param}=parsePickKey(s);const entry=resolveStored(slugPart);if(!entry)continue;const repeatable=entry.entity.repeatable===true;if(!repeatable&&param!==null){warnOnce(`pick-param:${pool.id}:${s}`,`Archivist: pool "${pool.id}" pick "${s}" names a parameter, but "${entry.slug}" is not repeatable; the parameter is ignored`)}const nkey=repeatable?normalizedPickKey(s,true):twinKey(entry.slug);if(grantedBare.has(bareEntitySlug(entry.slug))||seenKeys.has(nkey))continue;seenKeys.add(nkey);selected.push({...entry,key:repeatable||param!==null?s:entry.slug,param:repeatable?param:null,...repeatable?{option:resolveCopyOption(entry.entity,param,{classLevel:level,registry,edition})}:{}})}const available=withOptionalFeaturePrereqsMet(offered,selected,grants);const members=[...available,...grants];const layout=derivePoolLayout(members);const votes=new Map;for(const e of members){const id=(_h=e.entity.consumes)==null?void 0:_h.resource;const payer=id?payingResourceId(id,index,rc):void 0;if(!payer)continue;votes.set(payer,((_i=votes.get(payer))!=null?_i:0)+1)}let resource;let bestN=0;for(const[id,n]of votes)if(n>bestN){resource=id;bestN=n}const bind=poolRebinder(rc,pool.id,resource,index);return{id:pool.id,label:pool.label,classIndex,count,anchorLevel,selected:selected.map(bind),available:available.map(bind),grants:grants.map(bind),...layout?{layout}:{},...resource?{resource}:{},...pool.count.label?{countLabel:pool.count.label}:{},...pool.active?{active:pool.active}:{},...pool.head_resource?{headResource:pool.head_resource}:{}}}function poolRebinder(rc,poolId,vote,index){const declared=declaredResourceIds(rc);const copies=new Map;return e=>{const consumes=e.entity.consumes;const id=consumes==null?void 0:consumes.resource;if(!consumes||typeof id!=="string"||id.length===0)return e;const payer=payingResourceId(id,index,rc);if(payer===id)return e;const target=payer!=null?payer:vote!==void 0&&!declared.has(id)?vote:void 0;if(target===void 0)return e;const done=copies.get(e.key);if(done)return done;if(payer===void 0){warnOnce(`pool-rebind:${poolId}:${id}`,`Archivist: pool "${poolId}" members consume "${id}", which this character does not own; bound to the pool's resource "${target}"`)}const copy={...e,entity:{...e.entity,consumes:{...consumes,resource:target}}};copies.set(e.key,copy);return copy}}function declaredResourceIds(rc){var _a;const out=new Set;const add=list=>{for(const r of list!=null?list:[])if(typeof(r==null?void 0:r.id)==="string")out.add(r.id)};for(const owner of[rc.entity,rc.subclass]){if(!owner)continue;add(owner.resources);for(const features of Object.values((_a=owner.features_by_level)!=null?_a:{}))for(const f of features!=null?features:[])add(f.resources)}return out}function resolveAllPools(resolved,registry,index){const out=[];resolved.classes.forEach((rc,classIndex)=>{var _a,_b,_c,_d;if(!rc.entity)return;const decls=[...(_a=rc.entity.selection_pools)!=null?_a:[],...(_c=(_b=rc.subclass)==null?void 0:_b.selection_pools)!=null?_c:[]];const seen=new Set;for(const pool of decls){if(seen.has(pool.id))continue;seen.add(pool.id);out.push(resolvePool(rc,classIndex,pool,registry,index,(_d=resolved.definition)==null?void 0:_d.edition))}});return out}function strandedPicks(pool){const inAvailable=new Set(pool.available.map(e=>e.slug));return pool.selected.filter(e=>!inAvailable.has(e.slug))}function heldPicks(pool){var _a;const selected=(_a=pool.selected)!=null?_a:[];if(!pool.available)return[...selected];const inAvailable=new Set(pool.available.map(e=>e.slug));return selected.filter(e=>inAvailable.has(e.slug))}function withoutStrandedSites(sites,classes,registry,edition){if(sites.length===0)return sites;const strandedKeys=new Map;const keysOf=(classIndex,poolId)=>{var _a,_b,_c;const at=`${classIndex}:${poolId}`;let keys=strandedKeys.get(at);if(keys)return keys;const rc=classes[classIndex];const decl=(rc==null?void 0:rc.entity)?[...(_a=rc.entity.selection_pools)!=null?_a:[],...(_c=(_b=rc.subclass)==null?void 0:_b.selection_pools)!=null?_c:[]].find(p=>p.id===poolId):void 0;keys=new Set(rc&&decl?strandedPicks(resolvePool(rc,classIndex,decl,registry,new Map,edition)).map(e=>twinKey(e.slug)):[]);strandedKeys.set(at,keys);return keys};return sites.filter(site=>!keysOf(site.classIndex,site.poolId).has(twinKey(site.memberSlug)))}function poolCountLabel(pool){var _a;return(_a=pool.countLabel)!=null?_a:"Known"}function poolActiveWords(pool){var _a,_b,_c;const a=pool.active;if(!a)return null;return{column:a.column,label:a.label,verb:a.verb,counterLabel:(_a=a.counter_label)!=null?_a:a.label,createLabel:(_b=a.create_label)!=null?_b:"Created",createVerb:(_c=a.create_verb)!=null?_c:"Create"}}function parsePickKey(stored){const i=stored.indexOf("#");return i===-1?{slugPart:stored,param:null}:{slugPart:stored.slice(0,i),param:stored.slice(i+1)}}function normalizedPickKey(stored,repeatable){const{slugPart,param}=parsePickKey(stored);return repeatable?`${bareEntitySlug(slugPart)}#${param!=null?param:""}`:bareEntitySlug(slugPart)}function markerKey(by){const{slugPart,param}=parsePickKey(by);return param===null?bareEntitySlug(slugPart):`${bareEntitySlug(slugPart)}#${param}`}function isItemBound(note){var _a;return!!note.infuse||note.repeatable===true&&!!((_a=note.options)==null?void 0:_a.some(r=>!!r.creates))}var SRD_BOOKS=new Set(["SRD 2024","SRD 5e"]);var lc=v=>String(v!=null?v:"").trim().toLowerCase();var linkSlug=link=>link.replace(/^\[\[/,"").replace(/\]\]$/,"").split("|")[0];var itemsOf=registry=>registry.search("","item",Number.POSITIVE_INFINITY);function matchesFilter(data,f){var _a;const type=lc(data.type);if(!f.rarity.map(lc).includes(lc(data.rarity)))return false;if(f.types&&!f.types.map(lc).includes(type))return false;if((_a=f.exclude_types)==null?void 0:_a.map(lc).includes(type))return false;return!(f.cursed===false&&data.cursed===true)}function rowMatches(row,it){const c=row.creates;if(c.item)return lc(it.name)===lc(row.name)||it.slug===linkSlug(c.item);if(c.variant)return c.variant.candidates.some(l=>bareEntitySlug(linkSlug(l))===bareEntitySlug(it.slug));return!!c.filter&&matchesFilter(it.data,c.filter)}function buildItemIndex(items){const lcType=[],lcRarity=[];const byLcName=new Map,bySlug=new Map,byBare=new Map;const push=(m,k,i)=>{const l=m.get(k);if(l)l.push(i);else m.set(k,[i])};items.forEach((it,i)=>{const data=it.data;lcType.push(lc(data.type));lcRarity.push(lc(data.rarity));push(byLcName,lc(it.name),i);if(!bySlug.has(it.slug))bySlug.set(it.slug,i);push(byBare,bareEntitySlug(it.slug),i)});return{items,lcType,lcRarity,byLcName,bySlug,byBare}}var ITEM_INDEX=new WeakMap;var itemIndexOf=registry=>memoByRevision(ITEM_INDEX,registry,()=>buildItemIndex(itemsOf(registry)));var inBucketOrder=(ix,hits)=>[...hits].sort((a,b)=>a-b).map(i=>ix.items[i]);function rowInstalledIn(row,ix){var _a,_b,_c;const c=row.creates;if(c.item){const hits=new Set((_a=ix.byLcName.get(lc(row.name)))!=null?_a:[]);const own=ix.bySlug.get(linkSlug(c.item));if(own!==void 0)hits.add(own);return inBucketOrder(ix,hits)}if(c.variant){const hits=new Set;for(const l of c.variant.candidates)for(const i of(_b=ix.byBare.get(bareEntitySlug(linkSlug(l))))!=null?_b:[])hits.add(i);return inBucketOrder(ix,hits)}const f=c.filter;if(!f)return[];const rarities=new Set(f.rarity.map(lc));const types=f.types?new Set(f.types.map(lc)):null;const excluded=new Set(((_c=f.exclude_types)!=null?_c:[]).map(lc));return ix.items.filter((it,i)=>rarities.has(ix.lcRarity[i])&&(!types||types.has(ix.lcType[i]))&&!excluded.has(ix.lcType[i])&&!(f.cursed===false&&it.data.cursed===true))}var rowInstalled=(row,registry)=>rowInstalledIn(row,itemIndexOf(registry));function candidateOrder(edition){return(a,b)=>{const ea=edition&&lc(a.data.edition)===edition?0:1;const eb=edition&&lc(b.data.edition)===edition?0:1;if(ea!==eb)return ea-eb;const sa=SRD_BOOKS.has(a.compendium)?0:1,sb=SRD_BOOKS.has(b.compendium)?0:1;if(sa!==sb)return sa-sb;return a.slug<b.slug?-1:a.slug>b.slug?1:0}}function optionCandidates(row,registry,opts={}){return candidatesFrom(rowInstalled(row,registry),registry,opts)}function candidatesFrom(installed,registry,opts){var _a,_b;const visible=(_a=opts.isEntityVisible)!=null?_a:(()=>true);const excluded=((_b=opts.exclude)!=null?_b:[]).map(s=>{var _a2;return registry.getByTypeAndSlug("item",(_a2=keptSlugFor(s))!=null?_a2:s)}).filter(e=>!!e);const exNames=new Set(excluded.map(e=>lc(e.name))),exBares=new Set(excluded.map(e=>bareEntitySlug(e.slug)));const seen=new Set,out=[];for(const e of installed.filter(visible).sort(candidateOrder(opts.edition))){const bare=bareEntitySlug(e.slug);if(seen.has(bare))continue;seen.add(bare);if(exNames.has(lc(e.name))||exBares.has(bare))continue;out.push(e.slug)}return out}function resolveOptionRows(note,registry,opts={}){var _a;const ix=itemIndexOf(registry);return((_a=note.options)!=null?_a:[]).map(row=>{var _a2;const rowItems=rowInstalledIn(row,ix);const candidates=candidatesFrom(rowItems,registry,opts);const anyVisible=candidates.length>0||candidatesFrom(rowItems,registry,{...opts,exclude:[]}).length>0;const installed=rowItems.length>0;return{key:row.key,name:row.name,minLevel:row.min_level,...row.attunement!==void 0?{attunement:row.attunement}:{},arm:row.creates.item?"item":row.creates.variant?"variant":"filter",candidates,availability:anyVisible?"installed":installed?"hidden-only":"not-installed",...rowItemWords(row,candidates[0]?ix.items[(_a2=ix.bySlug.get(candidates[0]))!=null?_a2:-1]:rowItems[0])}})}function rowItemWords(row,item){var _a,_b,_c,_d;const f=row.creates.filter;if(f)return{type:((_a=f.types)==null?void 0:_a[0])?lc(f.types[0]):null,rarity:f.rarity[0]?lc(f.rarity[0]):null,charges:null};const data=(_b=item==null?void 0:item.data)!=null?_b:{};const max=(_c=data.charges)==null?void 0:_c.max;return{type:lc(data.type)||null,rarity:lc(data.rarity)||null,charges:typeof max==="number"&&max>0?{max,...typeof((_d=data.charges)==null?void 0:_d.recharge)==="string"?{recharge:data.charges.recharge}:{}}:null}}function resolveCopyOption(note,param,ctx){var _a,_b,_c;const rows=(_a=note.options)!=null?_a:[];if(param===null||param==="")return{row:null,status:"needs-choice"};if(note.item_choice==="create"){const row=rows.find(r=>r.key===param);if(!row)return{row:null,status:"invalid"};const installed=rowInstalled(row,ctx.registry).sort(candidateOrder(ctx.edition));if(installed.length===0)return{row,status:"not-installed"};const own=row.creates.item?linkSlug(row.creates.item):void 0;const item=row.creates.item?((_b=installed.find(e=>e.slug===own))!=null?_b:installed[0]).slug:void 0;return{row,...item?{item}:{},status:row.min_level<=ctx.classLevel?"ok":"level"}}const slug=(_c=keptSlugFor(param))!=null?_c:param;const it=ctx.registry.getByTypeAndSlug("item",slug);if(!it)return{row:null,item:slug,status:"not-installed"};const matching=rows.filter(r=>rowMatches(r,it)).sort((a,b)=>a.min_level-b.min_level);if(matching.length===0)return{row:null,item:slug,status:"invalid"};return{row:matching[0],item:slug,status:matching[0].min_level<=ctx.classLevel?"ok":"level"}}var MUNDANE=new Set(["","none","mundane"]);var isMagic=data=>{const r=data==null?void 0:data.rarity;return typeof r==="string"&&!MUNDANE.has(r.trim().toLowerCase())};var plainText=item=>item.replace(/^\[\[/,"").replace(/\]\]$/,"").split("|").pop().split("/").pop();function scaledInfuseItem(infuse,classLevel){var _a,_b;let item={...(_a=infuse.item)!=null?_a:{}};const rows=[...(_b=infuse.scales_at)!=null?_b:[]].sort((a,b)=>a.level-b.level);for(const row of rows)if(row.level<=classLevel)item={...item,...row.item};return item}function wrapInfused(entry,note,classLevel,registry){var _a,_b,_c,_d,_e,_f,_g,_h,_i,_j,_k;const infuse=note.infuse;const item=scaledInfuseItem(infuse,classLevel);const resist=[...(_a=item.resist)!=null?_a:[],...((_b=infuse.choice)==null?void 0:_b.kind)==="damage-type"&&((_c=entry.infusion)==null?void 0:_c.choice)?[entry.infusion.choice]:[]];const overlay={...item.bonuses?{bonuses:item.bonuses}:{},resist,...item.charges?{charges:item.charges}:{},...item.action?{action:item.action}:{},...item.range?{range:item.range}:{},...infuse.attunement?{attunement:{required:true}}:{}};const base=resolveBaseItem(entry.item,registry);const data=(_d=base==null?void 0:base.data)!=null?_d:null;if(base&&isMagic(data)){const b=data;const bonuses={...(_e=b.bonuses)!=null?_e:{}};for(const[k,v]of Object.entries((_f=item.bonuses)!=null?_f:{}))if(typeof v==="number")bonuses[k]=(typeof bonuses[k]==="number"?bonuses[k]:0)+v;return{entity:{...b,bonuses,resist:[...new Set([...(_g=b.resist)!=null?_g:[],...resist])],attunement:{required:requiresAttunement(b)||!!infuse.attunement}},magicBase:true}}const rarity=(_h=infuse.rarity)!=null?_h:"unknown";if(!base){const text=plainText(entry.item);return{entity:{slug:`infused:${slugify(text)}`,name:text,type:"wondrous item",rarity,...overlay,description:""},magicBase:false}}const name=String((_i=data==null?void 0:data.name)!=null?_i:base.name),description=String((_j=data==null?void 0:data.description)!=null?_j:"");const slotted=base.entityType==="armor"||base.entityType==="weapon"?base:typeof(data==null?void 0:data.base_item)==="string"?resolveBaseItem(data.base_item,registry):null;if(slotted&&(slotted.entityType==="armor"||slotted.entityType==="weapon")){const type=slotted.entityType==="weapon"?"weapon":isShieldArmor(slotted.data)?"shield":"armor";return{entity:{slug:base.slug,name,type,rarity,base_item:`[[${slotted.slug}]]`,...overlay,description},magicBase:false}}return{entity:{slug:base.slug,name,type:String((_k=data==null?void 0:data.type)!=null?_k:"adventuring gear"),rarity,...overlay,description},magicBase:false}}function resolveEntryEntity(entry,index,registry,infusions){const view=!infusions?void 0:"views"in infusions?infusions.views.get(index):infusions.index===index?infusions:void 0;if(view)return{entity:view.entity,entityType:view.entityType};return resolveEntityForEntry(entry.item,registry)}function buildInfusionContext(character,resolved,registry){var _a,_b,_c,_d,_e;const equipment=(_a=character.equipment)!=null?_a:[];const pools=((_b=resolved.pools)!=null?_b:[]).filter(p=>!!p.active||p.selected.some(e=>e.itemBound));if(pools.length===0&&!equipment.some(e=>!!e.infusion))return void 0;const owners=new Map;for(const pool of pools)for(const entry of pool.selected)if(entry.itemBound)owners.set(normalizedPickKey(entry.key,entry.entity.repeatable===true),{pool,entry});const views=new Map,flags=[];const newest=new Map;equipment.forEach((e,i)=>{if(!e.infusion)return;const k=markerKey(e.infusion.by);const j=newest.get(k);if(j===void 0||equipment[j].infusion.seq<e.infusion.seq)newest.set(k,i)});equipment.forEach((e,i)=>{var _a2,_b2,_c2;const m=e.infusion;if(!m)return;const owner=owners.get(markerKey(m.by));const nullView=()=>{var _a3,_b3,_c3,_d2,_e2;return{index:i,kind:m.kind,entity:null,entityType:null,key:m.by,seq:m.seq,poolId:(_a3=owner==null?void 0:owner.pool.id)!=null?_a3:"",classIndex:(_b3=owner==null?void 0:owner.pool.classIndex)!=null?_b3:-1,noteSlug:(_c3=owner==null?void 0:owner.entry.slug)!=null?_c3:"",noteName:(_d2=owner==null?void 0:owner.entry.entity.name)!=null?_d2:"",sourceLabel:(_e2=owner==null?void 0:owner.entry.entity.name)!=null?_e2:""}};if(!owner){flags.push({index:i,reason:"orphan"});if(m.kind==="created")views.set(i,nullView());return}if(newest.get(markerKey(m.by))!==i){flags.push({index:i,reason:"duplicate"});if(m.kind==="created")views.set(i,nullView());return}if(((_a2=e.qty)!=null?_a2:1)>1)flags.push({index:i,reason:"stack"});const classLevel=(_c2=(_b2=resolved.classes[owner.pool.classIndex])==null?void 0:_b2.level)!=null?_c2:0;const base={index:i,kind:m.kind,key:m.by,seq:m.seq,poolId:owner.pool.id,classIndex:owner.pool.classIndex,noteSlug:owner.entry.slug,noteName:owner.entry.entity.name,sourceLabel:owner.entry.entity.name};if(m.kind==="created"){const own=resolveEntityForEntry(e.item,registry);const it=resolveBaseItem(e.item,registry);const opt=owner.entry.option;const fits=!!it&&!!(opt==null?void 0:opt.row)&&(opt.item===it.slug||rowMatches(opt.row,it));if(!fits)flags.push({index:i,reason:"mismatch"});views.set(i,{...base,entity:own.entity,entityType:own.entityType});return}if(!owner.entry.entity.infuse){flags.push({index:i,reason:"orphan"});return}const w=wrapInfused(e,owner.entry.entity,classLevel,registry);if(w.magicBase)flags.push({index:i,reason:"magic-base"});views.set(i,{...base,entity:w.entity,entityType:"item"})});const counters=new Map;for(const pool of pools){const words=poolActiveWords(pool);if(!words)continue;const rc=resolved.classes[pool.classIndex];const max=(_e=readTableColumn((_c=rc==null?void 0:rc.entity)==null?void 0:_c.table,(_d=rc==null?void 0:rc.level)!=null?_d:0,[words.column]))!=null?_e:0;const used=[...views.values()].filter(v=>v.poolId===pool.id&&v.entity!==null).length;counters.set(pool.id,{label:words.counterLabel,used,max,over:used>max})}return{views,counters,flags}}function entryCharges(entry,view,registry){return effectiveItemCharges(entry,registry,view)}function withEntryCharges(entry,view,current,registry){var _a,_b,_c,_d,_e,_f;const overlayMax=(view==null?void 0:view.kind)==="infused"?itemChargesMax(view.entity):void 0;if(overlayMax!==void 0&&entry.infusion)return{...entry,infusion:{...entry.infusion,charges:{current:Math.max(0,Math.min(current,overlayMax))}}};const max=(_e=(_d=(_b=(_a=entry.state)==null?void 0:_a.charges)==null?void 0:_b.max)!=null?_d:(_c=effectiveItemCharges(entry,registry,view))==null?void 0:_c.max)!=null?_e:Math.max(0,current);return{...entry,state:{...(_f=entry.state)!=null?_f:{},charges:{current:Math.max(0,Math.min(current,max)),max}}}}function isMarkedEntry(entry){return!!entry.infusion}function splitOne(equipment,index){var _a,_b;const src=equipment[index];if(!src||((_a=src.qty)!=null?_a:1)<=1)return[...equipment];const one={item:src.item,qty:1,...src.in!==void 0?{in:src.in}:{},...src.overrides?{overrides:src.overrides}:{}};return[...equipment.slice(0,index),{...src,qty:((_b=src.qty)!=null?_b:1)-1},one,...equipment.slice(index+1)]}var refuse=reason=>({ok:false,reason});function endInfusion(equipment,index,registry){const entry=equipment[index];if(!(entry==null?void 0:entry.infusion))return{equipment:[...equipment],ended:[]};const{kind,by}=entry.infusion;if(kind==="infused"){const{infusion:_m,...rest}=entry;const keep=requiresAttunement(resolveEntryEntity(rest,index,registry).entity);const next=keep?rest:(({attuned:_a,...r})=>r)(rest);return{equipment:equipment.map((e,i)=>i===index?next:e),ended:[{index,key:by,kind,item:entry.item}]}}const moved=equipment.map((e,i)=>{if(i===index||entry.id===void 0||e.in!==entry.id)return e;if(entry.in===void 0){const{in:_in,...r}=e;return r}return{...e,in:entry.in}});return{equipment:moved.filter((_,i)=>i!==index),ended:[{index:-1,key:by,kind,item:entry.item}]}}var pickKeyOf=e=>normalizedPickKey(e.key,e.entity.repeatable===true);var nextSeq=equipment=>equipment.reduce((m,e)=>{var _a,_b;return Math.max(m,(_b=(_a=e.infusion)==null?void 0:_a.seq)!=null?_b:0)},0)+1;function ownedPick(resolved,key){var _a,_b;const k=markerKey(key);for(const pool of(_a=resolved.pools)!=null?_a:[]){const entry=pool.selected.find(e=>e.itemBound&&pickKeyOf(e)===k);if(entry)return{pool,entry,stranded:strandedPicks(pool).includes(entry)||((_b=entry.option)==null?void 0:_b.status)==="level"}}return null}var wordsOf=(...texts)=>texts.map(lc).join(" ").split(/[^a-z]+/).filter(w=>w!=="");function shapeOf(found,text,registry){var _a,_b,_c;if(!found)return{kind:"gear",words:wordsOf(text)};const data=(_a=found.data)!=null?_a:{};const words=wordsOf((_b=data.name)!=null?_b:text,data.type);const slotted=found.entityType==="armor"||found.entityType==="weapon"?found:typeof data.base_item==="string"?resolveBaseItem(data.base_item,registry):null;if((slotted==null?void 0:slotted.entityType)==="armor"){const armor=slotted.data;return{kind:isShieldArmor(armor)?"shield":"armor",words,category:lc(armor.category)}}if((slotted==null?void 0:slotted.entityType)==="weapon"){const w=slotted.data;return{kind:"weapon",words,category:lc(w.category),properties:((_c=w.properties)!=null?_c:[]).filter(p=>typeof p==="string").map(lc)}}return{kind:"gear",words}}function admits(t,s){var _a,_b,_c,_d;if(t.kind!==s.kind)return false;if(((_a=t.category)==null?void 0:_a.length)&&!t.category.map(lc).includes(((_b=s.category)!=null?_b:"").split("-")[0]))return false;if(t.property&&!((_c=s.properties)!=null?_c:[]).includes(lc(t.property)))return false;if(((_d=t.name_any)==null?void 0:_d.length)&&!t.name_any.some(n=>{const w=wordsOf(n);return w.length>0&&w.every(x=>s.words.includes(x))}))return false;return true}function targetVerdict(entry,infuse,registry){const found=resolveBaseItem(entry.item,registry);if(!infuse.targets.some(t=>admits(t,shapeOf(found,plainText(entry.item),registry))))return"target-kind";return found&&isMagic(found.data)?"magic-base":"ok"}function newObjectEntry(name,infuse,registry,visible){const want=lc(name);const found=[];for(const type of["armor","weapon","item"]){for(const e of registry.search(name,type,Number.POSITIVE_INFINITY)){if(lc(e.name)===want&&!isMagic(e.data)&&visible(e)&&infuse.targets.some(t=>admits(t,shapeOf(e,e.name,registry))))found.push(e)}}const first=found.sort(candidateOrder(void 0))[0];return first?{item:`[[${first.slug}]]`,qty:1}:{item:name,qty:1}}function endBySeqs(equipment,seqs,registry){let eq=[...equipment];let slots=eq.map((_,i)=>i);const rows=[];for(const{seq,by}of seqs){const i=eq.findIndex(e=>{var _a;return((_a=e.infusion)==null?void 0:_a.seq)===seq&&e.infusion.by===by});if(i===-1)continue;const w=endInfusion(eq,i,registry);for(const row of w.ended)rows.push({row,slot:slots[i]});if(eq[i].infusion.kind==="created")slots=slots.filter((_,j)=>j!==i);eq=w.equipment}return{equipment:eq,ended:rows.map(({row,slot})=>row.kind==="infused"?{...row,index:slots.indexOf(slot)}:row)}}function displaced(equipment,resolved,pool,key){var _a;const k=markerKey(key);const out=equipment.filter(e=>!!e.infusion&&markerKey(e.infusion.by)===k).map(e=>({seq:e.infusion.seq,by:e.infusion.by}));const counter=(_a=resolved.infusions)==null?void 0:_a.counters.get(pool.id);if(!counter)return out;const live=[...resolved.infusions.views.values()].filter(v=>v.poolId===pool.id&&v.classIndex===pool.classIndex&&v.entity!==null&&markerKey(v.key)!==k).sort((a,b)=>a.seq-b.seq);let used=live.length;for(const v of live){if(used+1<=counter.max)break;out.push({seq:v.seq,by:v.key});used--}return out}function infuseEntry(character,resolved,registry,req){var _a,_b,_c,_d,_e,_f,_g;const owned=ownedPick(resolved,req.key);if(!owned)return refuse("not-owned");const infuse=owned.entry.entity.infuse;if(!infuse)return refuse("not-infusing");if(owned.stranded)return refuse("stranded");const wantsChoice=((_a=infuse.choice)==null?void 0:_a.kind)==="damage-type";const choice=lc(req.choice);if(wantsChoice&&choice==="")return refuse("choice-required");if(wantsChoice&&!isCanonicalDamageType(choice))return refuse("bad-choice");if(wantsChoice&&((_b=infuse.choice)==null?void 0:_b.options)&&!infuse.choice.options.some(o=>lc(o)===choice))return refuse("bad-choice");const equipment=(_c=character.equipment)!=null?_c:[];const charges=scaledInfuseItem(infuse,(_e=(_d=resolved.classes[owned.pool.classIndex])==null?void 0:_d.level)!=null?_e:0).charges;const marker={kind:"infused",by:owned.entry.key,seq:nextSeq(equipment),...wantsChoice?{choice}:{},...charges?{charges:{current:charges.max}}:{}};let placed;if(typeof req.target==="number"){const target=equipment[req.target];if(!target)return refuse("no-target");if(target.infusion)return refuse("marked");const verdict=targetVerdict(target,infuse,registry);if(verdict!=="ok")return refuse(verdict);const split=((_f=target.qty)!=null?_f:1)>1;placed=split?splitOne(equipment,req.target):[...equipment];const i=split?req.target+1:req.target;placed[i]={...placed[i],infusion:marker}}else{const name=req.target.newObject.trim();if(name==="")return refuse("no-target");placed=[...equipment,{...newObjectEntry(name,infuse,registry,(_g=req.isEntityVisible)!=null?_g:(()=>true)),infusion:marker}]}return{ok:true,...endBySeqs(placed,displaced(equipment,resolved,owned.pool,owned.entry.key),registry)}}function createEntry(character,resolved,registry,req){var _a,_b;const owned=ownedPick(resolved,req.key);if(!owned)return refuse("not-owned");const note=owned.entry.entity;if(!(note.repeatable===true&&!!((_a=note.options)==null?void 0:_a.some(r=>!!r.creates))))return refuse("not-creating");if(owned.stranded)return refuse("stranded");const opt=owned.entry.option;if(!(opt==null?void 0:opt.row)||opt.status!=="ok")return refuse("invalid-item");const it=registry.getByTypeAndSlug("item",linkSlug(req.item.trim()));if(!it||!(opt.item===it.slug||rowMatches(opt.row,it)))return refuse("invalid-item");const equipment=(_b=character.equipment)!=null?_b:[];const placed=[...equipment,{item:`[[${it.slug}]]`,qty:1,infusion:{kind:"created",by:owned.entry.key,seq:nextSeq(equipment)}}];return{ok:true,...endBySeqs(placed,displaced(equipment,resolved,owned.pool,owned.entry.key),registry)}}function markersWhere(equipment,pick){const out=[];equipment.forEach((e,index)=>{const m=e.infusion;if(m&&pick(m))out.push({index,key:m.by,kind:m.kind,item:e.item,seq:m.seq,by:m.by})});return out}var asRows=list=>list.map(({index,key,kind,item})=>({index,key,kind,item}));var storedKeys=v=>typeof v==="string"?[v]:Array.isArray(v)?v:[];function choiceEnds(character,resolved,req){var _a,_b,_c,_d,_e,_f;const pool=((_a=resolved.pools)!=null?_a:[]).find(p=>p.classIndex===req.classIndex&&p.id===req.choiceKey);if(!pool||!(pool.active||pool.selected.some(e=>e.itemBound)))return[];const choices=(_c=(_b=character.class[req.classIndex])==null?void 0:_b.choices)!=null?_c:{};const kept=new Set(req.next.map(markerKey));for(const lvl of Object.keys(choices))if(Number(lvl)!==req.level)for(const s of storedKeys((_d=choices[Number(lvl)])==null?void 0:_d[req.choiceKey]))kept.add(markerKey(s));const removed=new Set(storedKeys((_e=choices[req.level])==null?void 0:_e[req.choiceKey]).map(markerKey).filter(k=>!kept.has(k)));return markersWhere((_f=character.equipment)!=null?_f:[],m=>removed.has(markerKey(m.by)))}function infusionsEndedByChoice(character,resolved,_registry,req){return asRows(choiceEnds(character,resolved,req))}function reconcileChoiceEdit(character,resolved,registry,req){var _a;const list=choiceEnds(character,resolved,req);return list.length===0?null:endBySeqs((_a=character.equipment)!=null?_a:[],list,registry)}function classEnds(character,resolved,req){var _a,_b,_c,_d,_e;let pools=((_a=resolved.pools)!=null?_a:[]).filter(p=>p.classIndex===req.classIndex);if(!("remove"in req)){const old=(_c=(_b=resolved.classes[req.classIndex])==null?void 0:_b.subclass)!=null?_c:null;if(!old||req.subclass!==null&&bareEntitySlug(linkSlug(req.subclass.trim()))===bareEntitySlug(old.slug))return[];const ids=new Set(((_d=old.selection_pools)!=null?_d:[]).map(p=>p.id));pools=pools.filter(p=>ids.has(p.id))}const owned=new Set;for(const pool of pools)for(const e of pool.selected)if(e.itemBound)owned.add(pickKeyOf(e));return markersWhere((_e=character.equipment)!=null?_e:[],m=>owned.has(markerKey(m.by)))}function infusionsEndedByClassEdit(character,resolved,_registry,req){return asRows(classEnds(character,resolved,req))}function reconcileClassEdit(character,resolved,registry,req){var _a;const list=classEnds(character,resolved,req);return list.length===0?null:endBySeqs((_a=character.equipment)!=null?_a:[],list,registry)}function eligibleTargets(character,resolved,registry,key){var _a,_b;const infuse=(_a=ownedPick(resolved,key))==null?void 0:_a.entry.entity.infuse;if(!infuse)return[];const out=[];((_b=character.equipment)!=null?_b:[]).forEach((e,index)=>{var _a2;if(!e.infusion&&targetVerdict(e,infuse,registry)==="ok")out.push({index,stack:((_a2=e.qty)!=null?_a2:1)>1})});return out}var WEAPON_DEFAULT_ACTION_COST="action";var linkOf=item=>{var _a,_b;return(_b=(_a=item.match(/^\[\[(.+)\]\]$/))==null?void 0:_a[1])!=null?_b:null};var ruleOf=(entry,registry,view)=>resolveEntryEntity(entry,view?view.index:-1,registry,view!=null?view:null);function isWeaponLikeEntry(entry,registry,view){if(!registry)return false;const r=ruleOf(entry,registry,view);return defaultSlotForType(r.entityType,r.entity,registry)==="mainhand"}function itemsRowBranch(entry,registry,view){var _a,_b;const link=linkOf(entry.item);if(!link||!registry)return false;const t=view?view.entityType:(_b=(_a=registry.getBySlug(link))==null?void 0:_a.entityType)!=null?_b:null;return t!=="weapon"&&t!=="armor"&&!isWeaponLikeEntry(entry,registry,view)}function customizableOverrideKeys(entry,registry){const consumed=isConsumedOnUse(entry,registry);const keys=new Set(consumed?["name"]:["name","charges","recovery"]);if(!registry)return keys;const r=ruleOf(entry,registry);const slot=defaultSlotForType(r.entityType,r.entity,registry);const weaponLike=slot==="mainhand";const itemsRow=itemsRowBranch(entry,registry);if(weaponLike){keys.add("bonus");keys.add("damage_bonus");keys.add("extra_damage")}if(slot==="armor"||slot==="shield")keys.add("ac_bonus");if(weaponLike||itemsRow)keys.add("action");if(itemsRow)keys.add("range");const link=linkOf(entry.item);if(r.entityType==="item"&&!consumed&&!(link&&isReadOnceItem(link)))keys.add("resist");return keys}function defaultActionCost(entry,registry,view){var _a,_b,_c,_d,_e;if(isWeaponLikeEntry(entry,registry,view))return WEAPON_DEFAULT_ACTION_COST;const link=linkOf(entry.item);if(!link||!registry||!itemsRowBranch(entry,registry,view))return null;const withoutOverrides={...entry,overrides:void 0};const type=view?(_a=view.entity)==null?void 0:_a.type:(_c=(_b=registry.getBySlug(link))==null?void 0:_b.data)==null?void 0:_c.type;return(_e=(_d=resolveItemAction(link,withoutOverrides,type,{view,spellCost:scrollSpellCost(entry,registry)}))==null?void 0:_d.cost)!=null?_e:null}var SPELL_COST={action:"action",bonus:"bonus-action",reaction:"reaction"};function scrollSpellCost(entry,registry){var _a,_b,_c,_d,_e;const ref=(_a=entry.overrides)==null?void 0:_a.spell;if(!ref||!registry)return void 0;const castingTime=(_d=(_c=registry.getByTypeAndSlug("spell",(_b=linkOf(ref))!=null?_b:ref))==null?void 0:_c.data)==null?void 0:_d.casting_time;const kind=typeof castingTime==="string"?(_e=parseCastingTime(castingTime))==null?void 0:_e.kind:void 0;return kind?SPELL_COST[kind]:void 0}var chargesOf=e=>e==null?void 0:e.charges;function itemChargesMax(entity){const c=chargesOf(entity);if(typeof c==="number")return c>0?c:void 0;const m=c==null?void 0:c.max;return typeof m==="number"&&m>0?m:void 0}var RESET_OF=r=>{const s=String(r!=null?r:"").toLowerCase();return s.includes("dawn")?"dawn":s.includes("short")?"short":s.includes("long")?"long":"special"};function rechargeAmount(c){var _a,_b;const raw=[c.recharge_amount,c.dice].find(v=>typeof v==="string"&&v.trim()!=="");if(!raw)return"1";const bare=raw.trim().replace(/^`+|`+$/g,"");return((_b=(_a=parseInlineTag(bare))==null?void 0:_a.content)!=null?_b:bare).replace(/\s+/g,"")}var recoveryOf=(c,needRecharge)=>!c||typeof c==="number"||needRecharge&&(typeof c.recharge!=="string"||c.recharge.trim()==="")?void 0:{amount:rechargeAmount(c),reset:RESET_OF(c.recharge)};function effectiveItemRecovery(entry,registry,view){var _a,_b;if(isConsumedOnUse(entry,registry,view))return void 0;if(view&&view.entity===null)return void 0;if((view==null?void 0:view.kind)==="infused"&&itemChargesMax(view.entity)!==void 0)return recoveryOf(chargesOf(view.entity),false);if((_a=entry.state)==null?void 0:_a.recovery)return entry.state.recovery;const own=registry?recoveryOf(chargesOf(ruleOf(entry,registry,view).entity),true):void 0;if(own)return own;const link=linkOf(entry.item);return link?(_b=findItemAction(link))==null?void 0:_b.recovery:void 0}function isConsumedOnUse(entry,registry,view){var _a;const link=linkOf(entry.item);if(!link)return false;if((_a=findItemAction(link))==null?void 0:_a.consumed)return true;const entity=entityOf(entry,registry,view);return(entity==null?void 0:entity.type)==="potion"||isScrollEntity(entity)}function isScrollEntity(entity){if(!entity||typeof entity!=="object")return false;return entity.type==="scroll"||isCastableScroll(entity)}function isCastableScroll(entity){return settableSpellLevel(entity)!==null&&!storesSpell(entity)}function settableSpellLevel(entity){if(!entity||typeof entity!=="object")return null;const level=entity.scroll_level;return typeof level==="number"?level:null}function storesSpell(entity){if(settableSpellLevel(entity)===null)return false;const e=entity;if(e.type==="scroll")return false;return itemChargesMax(entity)!==void 0||typeof e.spell_charge_cost==="number"}function storedSpellNumbers(entity){if(!storesSpell(entity))return null;const e=entity;const text=[e.description,...Array.isArray(e.entries)?e.entries:[]].filter(t=>typeof t==="string").join("\n");const fromText=re=>{const m=re.exec(text);return m?parseInt(m[1],10):void 0};const saveDC=typeof e.spell_save_dc==="number"?e.spell_save_dc:fromText(/\bsav(?:e|ing throw) DC (?:is|of) (\d+)/i);const attackBonus=typeof e.spell_attack_bonus==="number"?e.spell_attack_bonus:fromText(/\battack bonus (?:is|of) \+?(-?\d+)/i);if(saveDC===void 0&&attackBonus===void 0)return null;return{...saveDC!==void 0?{saveDC}:{},...attackBonus!==void 0?{attackBonus}:{}}}function itemSpellUse(entry,registry,view){const entity=entityOf(entry,registry,view);if(settableSpellLevel(entity)===null)return null;if(isConsumedOnUse(entry,registry,view))return{kind:"consume"};const declared=entity.spell_charge_cost;const cost=typeof declared==="number"&&Number.isInteger(declared)&&declared>=0?declared:1;const charges=effectiveItemCharges(entry,registry,view);if(cost===0||!charges)return{kind:"at-will"};return{kind:"charges",cost,charges:{current:charges.current,max:charges.max}}}function entityOf(entry,registry,view){if(!registry||!linkOf(entry.item))return null;return ruleOf(entry,registry,view).entity}function effectiveItemCharges(entry,registry,view){var _a,_b,_c,_d,_e,_f;if(isConsumedOnUse(entry,registry,view))return void 0;if(view&&view.entity===null)return void 0;const infused=(view==null?void 0:view.kind)==="infused"?itemChargesMax(view.entity):void 0;if(infused!==void 0)return{current:Math.max(0,Math.min((_c=(_b=(_a=entry.infusion)==null?void 0:_a.charges)==null?void 0:_b.current)!=null?_c:infused,infused)),max:infused};const stored=(_d=entry.state)==null?void 0:_d.charges;if(stored)return stored;const own=registry?itemChargesMax(ruleOf(entry,registry,view).entity):void 0;if(own!==void 0)return{current:own,max:own};const link=linkOf(entry.item);const max=link?(_f=(_e=findItemAction(link))==null?void 0:_e.max_charges)!=null?_f:0:0;return max>0?{current:max,max}:void 0}function effectiveItemArmorClass(entry,registry,view){var _a;if(!registry)return null;const{entity}=ruleOf(entry,registry,view);const armor=effectiveArmor(entity,registry);if(!armor)return null;const shield=isShieldArmor(armor);const bonus=isItemEntity(entity)&&typeof((_a=entity.bonuses)==null?void 0:_a.ac)==="number"?entity.bonuses.ac:0;const terms=slotAcTerms(armor,entry);return{value:terms.armor+terms.override+bonus,shield,addDex:!shield&&armor.ac.add_dex===true}}export{WEAPON_DEFAULT_ACTION_COST,isWeaponLikeEntry,customizableOverrideKeys,defaultActionCost,scrollSpellCost,itemChargesMax,effectiveItemRecovery,isConsumedOnUse,isScrollEntity,isCastableScroll,settableSpellLevel,storesSpell,storedSpellNumbers,itemSpellUse,effectiveItemCharges,effectiveItemArmorClass,poolCountLabel,poolActiveWords,parsePickKey,normalizedPickKey,markerKey,isItemBound,optionCandidates,resolveOptionRows,resolveCopyOption,scaledInfuseItem,resolveEntryEntity,buildInfusionContext,entryCharges,withEntryCharges,isMarkedEntry,splitOne,endInfusion,infuseEntry,createEntry,infusionsEndedByChoice,reconcileChoiceEdit,infusionsEndedByClassEdit,reconcileClassEdit,eligibleTargets,classOfSource,bindFeatureConsumers,levelPrereqMax,levelPrereqRefsMet,poolAnchorLevel,resolvePool,resolveAllPools,strandedPicks,heldPicks,withoutStrandedSites};
@@ -1 +1 @@
1
- import{z}from"zod";var abilityEnum=z.enum(["str","dex","con","int","wis","cha"]);var subjectField=z.string().min(1).optional();var conditionField=z.string().optional();var weaponScopeEnum=z.enum(["weapon","melee","ranged","unarmed","finesse","thrown","heavy","pact-weapon"]);var speedGateEnum=z.enum(["heavy-armor","armor","shield"]);var spellScopeSchema=z.object({list:z.string().min(1).optional(),level:z.number().int().min(0).max(9).optional(),school:z.string().min(1).optional(),damage_types:z.array(z.string().min(1)).min(1).optional(),damage_type_pick:z.string().min(1).optional(),spells:z.array(z.string().min(1)).min(1).optional(),once:z.boolean().optional()}).strict();var featureEffectSchema=z.discriminatedUnion("kind",[z.object({kind:z.literal("initiative-bonus"),value:z.number().int().optional(),amount:z.string().min(1).optional(),condition:conditionField,subject:subjectField}).refine(e=>e.value===void 0!==(e.amount===void 0),{path:["value"],message:"initiative-bonus takes exactly one of `value` (a number) or `amount` (a formula)"}),z.object({kind:z.literal("skill-bonus"),skills:z.array(z.string().min(1)).nonempty(),ability:abilityEnum,minimum:z.number().int().optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("save-bonus"),ability:abilityEnum,minimum:z.number().int().optional(),saves:z.array(abilityEnum).nonempty().optional(),inactive_while:z.enum(["incapacitated","unconscious"]).optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("half-proficiency"),skills:z.array(z.string().min(1)).nonempty().optional(),round:z.enum(["down","up"]).optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("immune-condition"),condition:z.string().min(1),while:z.string().optional(),subject:subjectField}),z.object({kind:z.literal("resistance"),damage_type:z.string().min(1),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("hp-per-level-bonus"),value:z.number().int(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("speed-bonus"),mode:z.enum(["walk","fly","swim","climb","burrow"]),value:z.number().int().optional(),equal_to:z.literal("walk").optional(),set:z.boolean().optional(),scales_at:z.array(z.object({level:z.number().int().min(1).max(20),value:z.number().int()})).optional(),inactive_while:z.union([speedGateEnum,z.array(speedGateEnum).nonempty()]).optional(),condition:conditionField,subject:subjectField}).refine(e=>e.value===void 0!==(e.equal_to===void 0),{path:["value"],message:"speed-bonus takes exactly one of `value` (feet) or `equal_to: walk`"}).refine(e=>e.equal_to===void 0||e.mode!=="walk"&&e.set===void 0&&e.scales_at===void 0,{path:["equal_to"],message:"`equal_to: walk` grants a mode other than walk, never with `set` or `scales_at`"}),z.object({kind:z.literal("speed-rule"),flag:z.enum(["ignore-armor-strength"]),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("attunement-limit"),value:z.number().int().positive(),scales_at:z.array(z.object({level:z.number().int().min(1).max(20),value:z.number().int().positive()})).optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("sense"),type:z.enum(["darkvision","blindsight","tremorsense","truesight"]),range:z.number().int().nonnegative(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("apply-condition"),condition:z.string().min(1),duration:z.string().optional(),ends_on:z.array(z.string()).optional(),save_repeat:z.object({ability:z.string().min(1),timing:z.string().min(1)}).optional(),subject:subjectField}),z.object({kind:z.literal("damage-bonus"),damage_type:z.string().min(1),amount:z.string().min(1),applies_to:z.union([z.enum(["spell","all"]),weaponScopeEnum,z.array(weaponScopeEnum).min(1)]).optional(),spell_scope:spellScopeSchema.optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("proficiency"),proficiency_type:z.enum(["skill","tool","language","saving-throw","armor","weapon"]),value:z.string().min(1),expertise:z.boolean().optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("ac-bonus"),value:z.number().int(),requires_armor:z.boolean().optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("unarmored-ac"),abilities:z.array(abilityEnum),base:z.number().int().optional(),allow_shield:z.boolean().optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("unarmed-strike"),dice:z.union([z.string().regex(/^\d+d\d+$/i),z.object({column:z.string().min(1)})]).optional(),abilities:z.array(abilityEnum).nonempty().optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("weapon-ability"),ability:z.union([abilityEnum,z.literal("spellcasting")]),weapons:z.union([z.literal("chosen"),z.string(),z.array(z.string())]).optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("roll-modifier"),mode:z.enum(["advantage","disadvantage","reroll","add-d4"]),roll:z.enum(["ability-check","saving-throw","attack","any"]),scope:z.string().optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("extra-attack"),count:z.number().int().positive(),scales_at:z.array(z.object({level:z.number().int().min(1).max(20),count:z.number().int().positive()})).optional(),applies_to:z.union([weaponScopeEnum,z.array(weaponScopeEnum).min(1)]).optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("crit-range"),min_roll:z.number().int().min(2).max(20),applies_to:z.enum(["weapon","spell","all"]).optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("reroll-damage"),max_reroll:z.number().int().positive(),applies_to:z.enum(["weapon","spell","all"]).optional(),once_per_die:z.boolean().optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("attack-rule"),flag:z.enum(["no-ranged-in-melee-disadvantage"]),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("damage-roll-option"),mode:z.enum(["reroll-weapon-dice-keep-higher","min-die-face","reroll-below"]),value:z.number().int().min(2).optional(),applies_to:z.union([weaponScopeEnum,z.array(weaponScopeEnum).min(1)]).optional(),two_handed:z.boolean().optional(),once_per_turn:z.boolean().optional(),condition:conditionField,subject:subjectField}).refine(e=>e.mode==="reroll-weapon-dice-keep-higher"===(e.value===void 0),{path:["value"],message:"damage-roll-option: `min-die-face` and `reroll-below` take a `value` (the face); keep-higher takes none"}),z.object({kind:z.literal("immunity"),damage_type:z.string().min(1),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("vulnerability"),damage_type:z.string().min(1),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("temp-hp"),amount:z.string().min(1),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("heal"),amount:z.string().min(1),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("ability-score-increase"),abilities:z.union([z.literal("chosen"),z.array(abilityEnum).min(1)]),amount:z.number().int().positive(),choose:z.number().int().positive().nullable(),max:z.number().int().positive().nullable(),condition:conditionField,subject:subjectField}).refine(e=>e.abilities==="chosen"===(e.choose!==null),{path:["choose"],message:'choose is required IFF abilities is "chosen": a fixed LIST is its own count'}),z.object({kind:z.literal("extra-action"),count:z.number().int().positive(),action_type:z.enum(["action","bonus-action","reaction"]),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("save-outcome"),ability:z.union([abilityEnum,z.literal("any")]),on_success:z.enum(["none","half","full"]),on_failure:z.enum(["none","half","full"]),applies_to:z.string().nullable(),condition:conditionField,subject:subjectField})]);export{featureEffectSchema};
1
+ import{z}from"zod";var abilityEnum=z.enum(["str","dex","con","int","wis","cha"]);var subjectField=z.string().min(1).optional();var conditionField=z.string().optional();var weaponScopeEnum=z.enum(["weapon","melee","ranged","unarmed","finesse","thrown","heavy","pact-weapon"]);var speedGateEnum=z.enum(["heavy-armor","armor","shield"]);var spellScopeSchema=z.object({list:z.string().min(1).optional(),level:z.number().int().min(0).max(9).optional(),school:z.string().min(1).optional(),damage_types:z.array(z.string().min(1)).min(1).optional(),damage_type_pick:z.string().min(1).optional(),spells:z.array(z.string().min(1)).min(1).optional(),once:z.boolean().optional()}).strict();var featureEffectSchema=z.discriminatedUnion("kind",[z.object({kind:z.literal("initiative-bonus"),value:z.number().int().optional(),amount:z.string().min(1).optional(),condition:conditionField,subject:subjectField}).refine(e=>e.value===void 0!==(e.amount===void 0),{path:["value"],message:"initiative-bonus takes exactly one of `value` (a number) or `amount` (a formula)"}),z.object({kind:z.literal("skill-bonus"),skills:z.array(z.string().min(1)).nonempty(),ability:abilityEnum,minimum:z.number().int().optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("save-bonus"),ability:abilityEnum,minimum:z.number().int().optional(),saves:z.array(abilityEnum).nonempty().optional(),inactive_while:z.enum(["incapacitated","unconscious"]).optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("half-proficiency"),skills:z.array(z.string().min(1)).nonempty().optional(),round:z.enum(["down","up"]).optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("immune-condition"),condition:z.string().min(1),while:z.string().optional(),subject:subjectField}),z.object({kind:z.literal("resistance"),damage_type:z.string().min(1),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("hp-per-level-bonus"),value:z.number().int(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("speed-bonus"),mode:z.enum(["walk","fly","swim","climb","burrow"]),value:z.number().int().optional(),equal_to:z.literal("walk").optional(),set:z.boolean().optional(),scales_at:z.array(z.object({level:z.number().int().min(1).max(20),value:z.number().int()})).optional(),inactive_while:z.union([speedGateEnum,z.array(speedGateEnum).nonempty()]).optional(),condition:conditionField,subject:subjectField}).refine(e=>e.value===void 0!==(e.equal_to===void 0),{path:["value"],message:"speed-bonus takes exactly one of `value` (feet) or `equal_to: walk`"}).refine(e=>e.equal_to===void 0||e.mode!=="walk"&&e.set===void 0&&e.scales_at===void 0,{path:["equal_to"],message:"`equal_to: walk` grants a mode other than walk, never with `set` or `scales_at`"}),z.object({kind:z.literal("speed-rule"),flag:z.enum(["ignore-armor-strength"]),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("attunement-limit"),value:z.number().int().positive(),scales_at:z.array(z.object({level:z.number().int().min(1).max(20),value:z.number().int().positive()})).optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("sense"),type:z.enum(["darkvision","blindsight","tremorsense","truesight"]),range:z.number().int().nonnegative(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("apply-condition"),condition:z.string().min(1),duration:z.string().optional(),ends_on:z.array(z.string()).optional(),save_repeat:z.object({ability:z.string().min(1),timing:z.string().min(1)}).optional(),subject:subjectField}),z.object({kind:z.literal("damage-bonus"),damage_type:z.string().min(1),amount:z.string().min(1),applies_to:z.union([z.enum(["spell","all"]),weaponScopeEnum,z.array(weaponScopeEnum).min(1)]).optional(),spell_scope:spellScopeSchema.optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("proficiency"),proficiency_type:z.enum(["skill","tool","language","saving-throw","armor","weapon"]),value:z.string().min(1),expertise:z.boolean().optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("ac-bonus"),value:z.number().int(),requires_armor:z.boolean().optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("unarmored-ac"),abilities:z.array(abilityEnum),base:z.number().int().optional(),allow_shield:z.boolean().optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("unarmed-strike"),dice:z.union([z.string().regex(/^\d+d\d+$/i),z.object({column:z.string().min(1)})]).optional(),abilities:z.array(abilityEnum).nonempty().optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("weapon-ability"),ability:z.union([abilityEnum,z.literal("spellcasting")]),weapons:z.union([z.literal("chosen"),z.string(),z.array(z.string())]).optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("roll-modifier"),mode:z.enum(["advantage","disadvantage","reroll","add-d4"]),roll:z.enum(["ability-check","saving-throw","attack","any"]),scope:z.string().optional(),spell_class:z.string().min(1).optional(),condition:conditionField,subject:subjectField}).refine(e=>e.spell_class===void 0||e.roll==="attack",{path:["spell_class"],message:"roll-modifier: `spell_class` is read only with `roll: attack`"}),z.object({kind:z.literal("extra-attack"),count:z.number().int().positive(),scales_at:z.array(z.object({level:z.number().int().min(1).max(20),count:z.number().int().positive()})).optional(),applies_to:z.union([weaponScopeEnum,z.array(weaponScopeEnum).min(1)]).optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("crit-range"),min_roll:z.number().int().min(2).max(20),applies_to:z.enum(["weapon","spell","all"]).optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("reroll-damage"),max_reroll:z.number().int().positive(),applies_to:z.enum(["weapon","spell","all"]).optional(),once_per_die:z.boolean().optional(),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("attack-rule"),flag:z.enum(["no-ranged-in-melee-disadvantage"]),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("spell-bonus"),save_dc:z.number().int().optional(),attack:z.number().int().optional(),spell_class:z.string().min(1).optional(),subject:subjectField}).refine(e=>e.save_dc!==void 0||e.attack!==void 0,{path:["save_dc"],message:"spell-bonus takes at least one of `save_dc` or `attack`"}),z.object({kind:z.literal("extra-cantrips"),count:z.number().int().positive(),class:z.string().min(1).optional(),subject:subjectField}),z.object({kind:z.literal("damage-roll-option"),mode:z.enum(["reroll-weapon-dice-keep-higher","min-die-face","reroll-below"]),value:z.number().int().min(2).optional(),applies_to:z.union([weaponScopeEnum,z.array(weaponScopeEnum).min(1)]).optional(),two_handed:z.boolean().optional(),once_per_turn:z.boolean().optional(),condition:conditionField,subject:subjectField}).refine(e=>e.mode==="reroll-weapon-dice-keep-higher"===(e.value===void 0),{path:["value"],message:"damage-roll-option: `min-die-face` and `reroll-below` take a `value` (the face); keep-higher takes none"}),z.object({kind:z.literal("immunity"),damage_type:z.string().min(1),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("vulnerability"),damage_type:z.string().min(1),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("temp-hp"),amount:z.string().min(1),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("heal"),amount:z.string().min(1),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("ability-score-increase"),abilities:z.union([z.literal("chosen"),z.array(abilityEnum).min(1)]),amount:z.number().int().positive(),choose:z.number().int().positive().nullable(),max:z.number().int().positive().nullable(),condition:conditionField,subject:subjectField}).refine(e=>e.abilities==="chosen"===(e.choose!==null),{path:["choose"],message:'choose is required IFF abilities is "chosen": a fixed LIST is its own count'}),z.object({kind:z.literal("extra-action"),count:z.number().int().positive(),action_type:z.enum(["action","bonus-action","reaction"]),condition:conditionField,subject:subjectField}),z.object({kind:z.literal("save-outcome"),ability:z.union([abilityEnum,z.literal("any")]),on_success:z.enum(["none","half","full"]),on_failure:z.enum(["none","half","full"]),applies_to:z.string().nullable(),condition:conditionField,subject:subjectField})]);export{featureEffectSchema};
@@ -1 +1 @@
1
- import{featEntitySchema}from"./chunk-AFEWQFQZ.js";import{parseYaml}from"@archivist-gg/core";function parseFeat(source){const raw=parseYaml(source,["name","slug"]);if(!raw.success)return raw;const result=featEntitySchema.safeParse({edition:"2014",...raw.data});if(!result.success){return{success:false,error:`feat schema validation failed: ${result.error.message}`}}return{success:true,data:result.data}}export{parseFeat};
1
+ import{featEntitySchema}from"./chunk-QCCA46KM.js";import{parseYaml}from"@archivist-gg/core";function parseFeat(source){const raw=parseYaml(source,["name","slug"]);if(!raw.success)return raw;const result=featEntitySchema.safeParse({edition:"2014",...raw.data});if(!result.success){return{success:false,error:`feat schema validation failed: ${result.error.message}`}}return{success:true,data:result.data}}export{parseFeat};
@@ -1 +1 @@
1
- import{durationSchema}from"./chunk-ZE46ADXS.js";import{actionCostEnum,resourceConsumptionSchema,resourceSchema}from"./chunk-CCFIINBA.js";import{choiceSchema}from"./chunk-VHIE2KYQ.js";import{featureEffectSchema}from"./chunk-EON7T2SN.js";import{z as z2}from"zod";import{z}from"zod";var abilityEnum=z.enum(["str","dex","con","int","wis","cha"]);var attackSchema=z.object({name:z.string().min(1),type:z.enum(["melee","ranged","spell"]),ability:z.union([abilityEnum,z.array(abilityEnum).nonempty()]).optional(),damage:z.string().optional(),damage_type:z.string().optional(),action:z.enum(["action","bonus-action","reaction"]).optional(),properties:z.array(z.string()).optional(),range:z.object({normal:z.number().int().nonnegative().optional(),long:z.number().int().nonnegative().optional(),reach:z.number().int().nonnegative().optional()}).optional(),condition:z.string().optional(),bonus:z.number().optional(),extra_damage:z.object({dice:z.string(),type:z.string()}).optional(),weapon_category:z.enum(["simple","martial"]).optional(),mastery:z.string().min(1).optional(),unarmed:z.boolean().optional()});var companionSchema=z2.object({statblock:z2.string().optional(),statblock_wikilink:z2.string().nullable().optional(),count:z2.string().optional(),count_scaling:z2.array(z2.object({level:z2.number().optional(),count:z2.string().optional(),source_quote:z2.string().optional()})).optional(),shares_action_economy:z2.boolean().optional(),turn_order:z2.string().optional(),turn_order_source_quote:z2.string().nullable().optional(),proficiency_bonus_scaled:z2.array(z2.object({stat:z2.string().optional(),formula:z2.string().optional(),source_quote:z2.string().optional()})).optional(),lifecycle:z2.object({created_by:z2.string().optional(),recreate_on:z2.string().nullable().optional(),previous_instance_perishes:z2.boolean().nullable().optional(),vanishes_if_owner_dies:z2.boolean().nullable().optional(),vanishes_after:z2.string().nullable().optional(),source_quote:z2.string().optional()}).nullable().optional(),autonomy:z2.object({when:z2.string().optional(),behaviour:z2.string().optional(),source_quote:z2.string().optional()}).nullable().optional(),variants:z2.array(z2.object({axis:z2.string().optional(),choices:z2.array(z2.string()).optional(),chosen_at:z2.string().optional(),source_quote:z2.string().optional()})).optional(),base_statblock:z2.string().nullable().optional(),overrides:z2.array(z2.object({field:z2.string().optional(),value:z2.string().optional(),source_quote:z2.string().optional()})).optional(),source_quote:z2.string().optional()});var featureObjectSchema=z2.lazy(()=>z2.object({id:z2.string().min(1).optional(),name:z2.string().min(1),description:z2.string().optional(),entries:z2.array(z2.string()).optional(),choices:z2.array(choiceSchema).optional(),grants_resource:z2.string().optional(),consumes:resourceConsumptionSchema.optional(),attacks:z2.array(attackSchema).optional(),action:z2.enum(["action","bonus-action","reaction","free","special"]).optional(),trigger:z2.string().optional(),dc_formula:z2.string().optional(),effects:z2.array(featureEffectSchema).optional(),sub_features:z2.array(featureSchemaTyped).optional(),resources:z2.array(resourceSchema).optional(),activatable:z2.boolean().optional(),passive:z2.boolean().optional(),duration:durationSchema.optional(),class_source:z2.string().min(1).optional(),rendering_hint:z2.string().optional(),subclass_short_name:z2.string().min(1).optional(),subclass_source:z2.string().min(1).optional(),header:z2.number().optional(),is_class_feature_variant:z2.boolean().optional(),gain_subclass_feature:z2.boolean().optional(),gain_subclass_feature_has_content:z2.boolean().optional(),type:z2.string().min(1).optional(),recharge:z2.object({type:z2.enum(["recharge_on_roll","per_day","per_short_rest","per_long_rest"]),param:z2.number()}).optional(),action_cost:actionCostEnum.optional(),save:z2.object({ability:z2.string().min(1),dc_formula:z2.string().min(1)}).optional(),companion:companionSchema.optional()}));var featureSchemaTyped=featureObjectSchema.refine(f=>f.description!==void 0||f.entries!==void 0&&f.entries.length>0,{message:"feature requires either description or non-empty entries"});var featureSchema=featureSchemaTyped;export{featureObjectSchema,featureSchema};
1
+ import{durationSchema}from"./chunk-ZE46ADXS.js";import{actionCostEnum,resourceConsumptionSchema,resourceSchema}from"./chunk-ZKDHCDJ2.js";import{choiceSchema}from"./chunk-ZK3P4RSE.js";import{featureEffectSchema}from"./chunk-7TH4WPSU.js";import{z as z2}from"zod";import{z}from"zod";var abilityEnum=z.enum(["str","dex","con","int","wis","cha"]);var attackSchema=z.object({name:z.string().min(1),type:z.enum(["melee","ranged","spell"]),ability:z.union([abilityEnum,z.array(abilityEnum).nonempty()]).optional(),damage:z.string().optional(),damage_type:z.string().optional(),action:z.enum(["action","bonus-action","reaction"]).optional(),properties:z.array(z.string()).optional(),range:z.object({normal:z.number().int().nonnegative().optional(),long:z.number().int().nonnegative().optional(),reach:z.number().int().nonnegative().optional()}).optional(),condition:z.string().optional(),bonus:z.number().optional(),extra_damage:z.object({dice:z.string(),type:z.string()}).optional(),weapon_category:z.enum(["simple","martial"]).optional(),mastery:z.string().min(1).optional(),unarmed:z.boolean().optional()});var companionSchema=z2.object({statblock:z2.string().optional(),statblock_wikilink:z2.string().nullable().optional(),count:z2.string().optional(),count_scaling:z2.array(z2.object({level:z2.number().optional(),count:z2.string().optional(),source_quote:z2.string().optional()})).optional(),shares_action_economy:z2.boolean().optional(),turn_order:z2.string().optional(),turn_order_source_quote:z2.string().nullable().optional(),proficiency_bonus_scaled:z2.array(z2.object({stat:z2.string().optional(),formula:z2.string().optional(),source_quote:z2.string().optional()})).optional(),lifecycle:z2.object({created_by:z2.string().optional(),recreate_on:z2.string().nullable().optional(),previous_instance_perishes:z2.boolean().nullable().optional(),vanishes_if_owner_dies:z2.boolean().nullable().optional(),vanishes_after:z2.string().nullable().optional(),source_quote:z2.string().optional()}).nullable().optional(),autonomy:z2.object({when:z2.string().optional(),behaviour:z2.string().optional(),source_quote:z2.string().optional()}).nullable().optional(),variants:z2.array(z2.object({axis:z2.string().optional(),choices:z2.array(z2.string()).optional(),chosen_at:z2.string().optional(),source_quote:z2.string().optional()})).optional(),base_statblock:z2.string().nullable().optional(),overrides:z2.array(z2.object({field:z2.string().optional(),value:z2.string().optional(),source_quote:z2.string().optional()})).optional(),source_quote:z2.string().optional()});var featureObjectSchema=z2.lazy(()=>z2.object({id:z2.string().min(1).optional(),name:z2.string().min(1),description:z2.string().optional(),entries:z2.array(z2.string()).optional(),choices:z2.array(choiceSchema).optional(),grants_resource:z2.string().optional(),consumes:resourceConsumptionSchema.optional(),attacks:z2.array(attackSchema).optional(),action:z2.enum(["action","bonus-action","reaction","free","special"]).optional(),trigger:z2.string().optional(),dc_formula:z2.string().optional(),effects:z2.array(featureEffectSchema).optional(),sub_features:z2.array(featureSchemaTyped).optional(),resources:z2.array(resourceSchema).optional(),activatable:z2.boolean().optional(),passive:z2.boolean().optional(),duration:durationSchema.optional(),class_source:z2.string().min(1).optional(),rendering_hint:z2.string().optional(),subclass_short_name:z2.string().min(1).optional(),subclass_source:z2.string().min(1).optional(),header:z2.number().optional(),is_class_feature_variant:z2.boolean().optional(),gain_subclass_feature:z2.boolean().optional(),gain_subclass_feature_has_content:z2.boolean().optional(),type:z2.string().min(1).optional(),recharge:z2.object({type:z2.enum(["recharge_on_roll","per_day","per_short_rest","per_long_rest"]),param:z2.number()}).optional(),action_cost:actionCostEnum.optional(),save:z2.object({ability:z2.string().min(1),dc_formula:z2.string().min(1)}).optional(),companion:companionSchema.optional()}));var featureSchemaTyped=featureObjectSchema.refine(f=>f.description!==void 0||f.entries!==void 0&&f.entries.length>0,{message:"feature requires either description or non-empty entries"});var featureSchema=featureSchemaTyped;export{featureObjectSchema,featureSchema};
@@ -1 +1 @@
1
- import{aliasFeaturesByLevelActionCost}from"./chunk-S5UCI27C.js";import{classEntitySchema}from"./chunk-ADX7435T.js";import{parseYaml}from"@archivist-gg/core";function parseClass(source){const raw=parseYaml(source,["name","slug"]);if(!raw.success)return raw;aliasFeaturesByLevelActionCost(raw.data.features_by_level);const result=classEntitySchema.safeParse({edition:"2014",...raw.data});if(!result.success){return{success:false,error:`class schema validation failed: ${result.error.message}`}}return{success:true,data:result.data}}export{parseClass};
1
+ import{aliasFeaturesByLevelActionCost}from"./chunk-S5UCI27C.js";import{classEntitySchema}from"./chunk-655UY3MP.js";import{parseYaml}from"@archivist-gg/core";function parseClass(source){const raw=parseYaml(source,["name","slug"]);if(!raw.success)return raw;aliasFeaturesByLevelActionCost(raw.data.features_by_level);const result=classEntitySchema.safeParse({edition:"2014",...raw.data});if(!result.success){return{success:false,error:`class schema validation failed: ${result.error.message}`}}return{success:true,data:result.data}}export{parseClass};
@@ -1 +1 @@
1
- import{RACE_STRUCTURAL_PSEUDO}from"./chunk-UBUKCRZ3.js";import{heldPicks}from"./chunk-E4E6YEN6.js";import{warnOnce}from"./chunk-DZITM5AG.js";import{memoByRevision}from"./chunk-QMEKQTUT.js";import{slugify}from"./chunk-63YJPWTM.js";import{mirrorSpellShapes}from"./chunk-4KVVAENP.js";import{ABILITY_KEYS}from"./chunk-EVT7MGAC.js";var entriesOf=a=>Array.isArray(a)?a:a&&typeof a==="object"?[a]:[];var editionOf=x=>{const e=x==null?void 0:x.edition;return typeof e==="string"?e:void 0};var prefixOf=slug=>{var _a;return(_a=slug.split("_")[0])!=null?_a:slug};function normalizeSpellRef(ref){var _a,_b,_c;if(typeof ref!=="string")return null;let s=ref.trim();const wl=/^\[\[(.+)\]\]$/.exec(s);if(wl){const target=(_a=wl[1].split("|")[0])!=null?_a:"";const tail=(_b=target.split("/").pop())!=null?_b:target;const w=slugify(tail.replace(/#.*$/,"").trim());return w.length>0?w:null}s=s.replace(/#.*$/,"");s=(_c=s.split("|")[0])!=null?_c:"";const out=slugify(s.trim());return out.length>0?out:null}function buildSpellNameIndex(entities){return memoByRevision(SPELL_NAME_INDEX,entities,()=>spellNameIndexOf(entities))}var SPELL_NAME_INDEX=new WeakMap;function spellNameIndexOf(entities){var _a;const byName=new Map;for(const e of entities.search("","spell",Number.POSITIVE_INFINITY)){const raw=e.data.name;const key=slugify(typeof raw==="string"?raw:e.name);const list=(_a=byName.get(key))!=null?_a:[];list.push(e);byName.set(key,list)}return{byName}}function resolveSpellByName(opts){var _a;const{entities,index,nameSlug,carrierSlug,carrierEdition,alreadyCollected}=opts;const own=alreadyCollected.find(s=>{var _a2;return slugify(String((_a2=s.entity.name)!=null?_a2:""))===nameSlug});if(own)return{entity:own.entity,slug:own.slug};const exact=entities.getByTypeAndSlug("spell",`${prefixOf(carrierSlug)}_spell_${nameSlug}`);if(exact)return{entity:mirrorSpellShapes(exact.data),slug:exact.slug};const cands=(_a=index.byName.get(nameSlug))!=null?_a:[];if(cands.length===0){warnOnce(`addspells:miss:${nameSlug}`,`archivist: additional_spells ref "${nameSlug}" matches no spell in the compendium`);return null}const prefix=prefixOf(carrierSlug);let pool=cands.filter(e=>prefixOf(e.slug)===prefix);if(pool.length===0)pool=cands;if(carrierEdition!==void 0){const same=pool.filter(e=>editionOf(e.data)===carrierEdition);if(same.length>0)pool=same}pool=[...pool].sort((a,b)=>a.slug<b.slug?-1:a.slug>b.slug?1:0);if(pool.length>1)warnOnce(`addspells:multi:${nameSlug}`,`archivist: additional_spells ref "${nameSlug}" matches ${cands.length} spells; using "${pool[0].slug}"`);return{entity:mirrorSpellShapes(pool[0].data),slug:pool[0].slug}}var hasContentSelectInline=choices=>Array.isArray(choices)&&choices.some(c=>(c==null?void 0:c.kind)==="select-inline"&&typeof c.id==="string"&&!RACE_STRUCTURAL_PSEUDO.has(c.id)||Array.isArray(c==null?void 0:c.options)&&c.options.some(o=>hasContentSelectInline(o==null?void 0:o.choices)));function raceIsUngated(race){var _a;const r=race;if(hasContentSelectInline(r.choices))return false;return!((_a=r.traits)!=null?_a:[]).some(t=>hasContentSelectInline(t==null?void 0:t.choices))}var readAbility=(v,own)=>{if(v&&typeof v==="object"&&"choose"in v)return"choose";if(typeof v!=="string")return void 0;if(v==="inherit")return own!=null?own:void 0;return ABILITY_KEYS.includes(v)?v:void 0};var entryHasInSliceLeaf=(e,comparand,own)=>readAbility(e.ability,own)!=="choose"&&["known","prepared"].some(b=>{const lv=e[b];return!!lv&&typeof lv==="object"&&!Array.isArray(lv)&&Object.entries(lv).some(([k,v])=>(k==="_"||Number(k)<=comparand)&&Array.isArray(v)&&v.some(x=>typeof x==="string"))});function chosenRaceOptionKeys(race,read){var _a;const out=new Set;const r=race;const lists=[r.choices,...((_a=r.traits)!=null?_a:[]).map(t=>t==null?void 0:t.choices)];for(const list of lists){for(const c of Array.isArray(list)?list:[]){if((c==null?void 0:c.kind)!=="select-inline"||typeof c.id!=="string"||RACE_STRUCTURAL_PSEUDO.has(c.id))continue;const v=read(c.id);for(const value of Array.isArray(v)?v:typeof v==="string"?[v]:[]){if(typeof value!=="string")continue;out.add(slugify(value));const opt=(Array.isArray(c.options)?c.options:[]).find(o=>(o==null?void 0:o.value)===value);if(typeof(opt==null?void 0:opt.label)==="string")out.add(slugify(opt.label))}}}return out}function innateLeaves(innate,comparand){if(!innate||typeof innate!=="object"||Array.isArray(innate))return[];const strings=v=>Array.isArray(v)?v.filter(x=>typeof x==="string"):v&&typeof v==="object"?Object.values(v).flatMap(strings):[];return Object.entries(innate).filter(([k])=>k==="_"||Number(k)<=comparand).flatMap(([,v])=>strings(v))}function memberAtWillLeaves(innate,comparand,slug){if(!innate||typeof innate!=="object"||Array.isArray(innate))return[];const out=[];for(const[k,v]of Object.entries(innate)){if(!(k==="_"||Number(k)<=comparand))continue;if(Array.isArray(v)){out.push(...v);continue}for(const[usage,list]of v&&typeof v==="object"?Object.entries(v):[]){if(usage==="will"&&Array.isArray(list))out.push(...list);else warnOnce(`addspells:usage:${slug}:innate:${k}:${usage}`,`archivist: additional_spells on "${slug}" innate.${k}.${usage} is a usage economy (skipped; G8)`)}}return out}function collectAdditionalSpells(args){var _a,_b;const{race,feats,classes,totalLevel,ownAbility,alreadyCollected,entities,warnings}=args;const raceChoice=(_a=args.raceChoice)!=null?_a:(()=>void 0);let index=null;const indexOf=()=>index!=null?index:index=buildSpellNameIndex(entities);const out=[];const carriers=[];const asRaw=x=>x==null?void 0:x.additional_spells;if(race&&raceIsUngated(race))carriers.push({root:"race",slug:race.slug,edition:editionOf(race),entries:entriesOf(asRaw(race)),comparand:totalLevel,classSlug:null});else if(race){const chosen=chosenRaceOptionKeys(race,raceChoice);for(const e of entriesOf(asRaw(race))){if(typeof e.name==="string"&&chosen.has(slugify(e.name))){carriers.push({root:"race",slug:race.slug,edition:editionOf(race),entries:[e],comparand:totalLevel,classSlug:null})}}}for(const f of feats)carriers.push({root:"feat",slug:f.slug,edition:editionOf(f),entries:entriesOf(asRaw(f)),comparand:totalLevel,classSlug:null});for(const c of classes){if(!c.entity)continue;carriers.push({root:"class",slug:c.entity.slug,edition:editionOf(c.entity),entries:entriesOf(asRaw(c.entity)),comparand:c.level,classSlug:c.entity.slug});if(c.subclass)carriers.push({root:"subclass",slug:c.subclass.slug,edition:editionOf(c.subclass),entries:entriesOf(asRaw(c.subclass)),comparand:c.level,classSlug:c.entity.slug})}for(const pool of(_b=args.pools)!=null?_b:[]){const c=classes[pool.classIndex];if(!(c==null?void 0:c.entity))continue;for(const m of[...heldPicks(pool),...pool.grants]){if(m.itemBound===true)continue;carriers.push({root:"member",slug:m.slug,edition:editionOf(m.entity),entries:entriesOf(asRaw(m.entity)),comparand:c.level,classSlug:c.entity.slug})}}for(const car of carriers){if(car.entries.length===0)continue;if(car.entries.length>1){if(car.entries.some(e=>entryHasInSliceLeaf(e,car.comparand,ownAbility)))warnOnce(`addspells:siblings:${car.slug}`,`archivist: additional_spells on "${car.slug}" has ${car.entries.length} sibling entries (a choose-one grant); skipped`);continue}const entry=car.entries[0];let ability=readAbility(entry.ability,ownAbility);if(ability==="choose"&&car.root==="race"){const pick=raceChoice("spellcasting-ability");const allowed=entry.ability.choose;ability=typeof pick==="string"&&Array.isArray(allowed)&&allowed.includes(pick)?pick:"choose"}if(ability==="choose")continue;const buckets=["known","prepared"].map(bucket=>{const levels=entry[bucket];return[bucket,!levels||typeof levels!=="object"||Array.isArray(levels)?[]:Object.entries(levels)]});if(car.root==="race")buckets.push(["innate",[["_",innateLeaves(entry.innate,car.comparand)]]]);if(car.root==="member")buckets.push(["at-will",[["_",memberAtWillLeaves(entry.innate,car.comparand,car.slug)]]]);for(const[bucket,levelEntries]of buckets){for(const[k,v]of levelEntries){if(!(k==="_"||Number(k)<=car.comparand))continue;if(!Array.isArray(v)){warnOnce(`addspells:usage:${car.slug}:${bucket}:${k}`,`archivist: additional_spells on "${car.slug}" ${bucket}.${k} is a usage economy (skipped; G8)`);continue}for(const leaf of v){const nameSlug=normalizeSpellRef(leaf);if(!nameSlug)continue;const hit=resolveSpellByName({entities,index:indexOf(),nameSlug,carrierSlug:car.slug,carrierEdition:car.edition,alreadyCollected:[...alreadyCollected,...out]});if(!hit){warnings.push(`additional_spells ref "${String(leaf)}" on ${car.slug} not found in compendium.`);continue}out.push({entity:hit.entity,slug:hit.slug,classSlug:car.classSlug,source:car.root==="race"?"race":car.root==="feat"?"feat":"class",prepared:true,alwaysPrepared:true,...ability?{ability}:{},...bucket==="at-will"?{atWill:true}:{}})}}}}return out}export{prefixOf,normalizeSpellRef,buildSpellNameIndex,resolveSpellByName,raceIsUngated,chosenRaceOptionKeys,collectAdditionalSpells};
1
+ import{RACE_STRUCTURAL_PSEUDO}from"./chunk-UBUKCRZ3.js";import{heldPicks}from"./chunk-7S4VMK3R.js";import{warnOnce}from"./chunk-DZITM5AG.js";import{memoByRevision}from"./chunk-QMEKQTUT.js";import{slugify}from"./chunk-63YJPWTM.js";import{mirrorSpellShapes}from"./chunk-4KVVAENP.js";import{ABILITY_KEYS}from"./chunk-EVT7MGAC.js";var entriesOf=a=>Array.isArray(a)?a:a&&typeof a==="object"?[a]:[];var editionOf=x=>{const e=x==null?void 0:x.edition;return typeof e==="string"?e:void 0};var prefixOf=slug=>{var _a;return(_a=slug.split("_")[0])!=null?_a:slug};function normalizeSpellRef(ref){var _a,_b,_c;if(typeof ref!=="string")return null;let s=ref.trim();const wl=/^\[\[(.+)\]\]$/.exec(s);if(wl){const target=(_a=wl[1].split("|")[0])!=null?_a:"";const tail=(_b=target.split("/").pop())!=null?_b:target;const w=slugify(tail.replace(/#.*$/,"").trim());return w.length>0?w:null}s=s.replace(/#.*$/,"");s=(_c=s.split("|")[0])!=null?_c:"";const out=slugify(s.trim());return out.length>0?out:null}function buildSpellNameIndex(entities){return memoByRevision(SPELL_NAME_INDEX,entities,()=>spellNameIndexOf(entities))}var SPELL_NAME_INDEX=new WeakMap;function spellNameIndexOf(entities){var _a;const byName=new Map;for(const e of entities.search("","spell",Number.POSITIVE_INFINITY)){const raw=e.data.name;const key=slugify(typeof raw==="string"?raw:e.name);const list=(_a=byName.get(key))!=null?_a:[];list.push(e);byName.set(key,list)}return{byName}}function resolveSpellByName(opts){var _a;const{entities,index,nameSlug,carrierSlug,carrierEdition,alreadyCollected}=opts;const own=alreadyCollected.find(s=>{var _a2;return slugify(String((_a2=s.entity.name)!=null?_a2:""))===nameSlug});if(own)return{entity:own.entity,slug:own.slug};const exact=entities.getByTypeAndSlug("spell",`${prefixOf(carrierSlug)}_spell_${nameSlug}`);if(exact)return{entity:mirrorSpellShapes(exact.data),slug:exact.slug};const cands=(_a=index.byName.get(nameSlug))!=null?_a:[];if(cands.length===0){warnOnce(`addspells:miss:${nameSlug}`,`archivist: additional_spells ref "${nameSlug}" matches no spell in the compendium`);return null}const prefix=prefixOf(carrierSlug);let pool=cands.filter(e=>prefixOf(e.slug)===prefix);if(pool.length===0)pool=cands;if(carrierEdition!==void 0){const same=pool.filter(e=>editionOf(e.data)===carrierEdition);if(same.length>0)pool=same}pool=[...pool].sort((a,b)=>a.slug<b.slug?-1:a.slug>b.slug?1:0);if(pool.length>1)warnOnce(`addspells:multi:${nameSlug}`,`archivist: additional_spells ref "${nameSlug}" matches ${cands.length} spells; using "${pool[0].slug}"`);return{entity:mirrorSpellShapes(pool[0].data),slug:pool[0].slug}}var hasContentSelectInline=choices=>Array.isArray(choices)&&choices.some(c=>(c==null?void 0:c.kind)==="select-inline"&&typeof c.id==="string"&&!RACE_STRUCTURAL_PSEUDO.has(c.id)||Array.isArray(c==null?void 0:c.options)&&c.options.some(o=>hasContentSelectInline(o==null?void 0:o.choices)));function raceIsUngated(race){var _a;const r=race;if(hasContentSelectInline(r.choices))return false;return!((_a=r.traits)!=null?_a:[]).some(t=>hasContentSelectInline(t==null?void 0:t.choices))}var readAbility=(v,own)=>{if(v&&typeof v==="object"&&"choose"in v)return"choose";if(typeof v!=="string")return void 0;if(v==="inherit")return own!=null?own:void 0;return ABILITY_KEYS.includes(v)?v:void 0};var entryHasInSliceLeaf=(e,comparand,own)=>readAbility(e.ability,own)!=="choose"&&["known","prepared"].some(b=>{const lv=e[b];return!!lv&&typeof lv==="object"&&!Array.isArray(lv)&&Object.entries(lv).some(([k,v])=>(k==="_"||Number(k)<=comparand)&&Array.isArray(v)&&v.some(x=>typeof x==="string"))});function chosenRaceOptionKeys(race,read){var _a;const out=new Set;const r=race;const lists=[r.choices,...((_a=r.traits)!=null?_a:[]).map(t=>t==null?void 0:t.choices)];for(const list of lists){for(const c of Array.isArray(list)?list:[]){if((c==null?void 0:c.kind)!=="select-inline"||typeof c.id!=="string"||RACE_STRUCTURAL_PSEUDO.has(c.id))continue;const v=read(c.id);for(const value of Array.isArray(v)?v:typeof v==="string"?[v]:[]){if(typeof value!=="string")continue;out.add(slugify(value));const opt=(Array.isArray(c.options)?c.options:[]).find(o=>(o==null?void 0:o.value)===value);if(typeof(opt==null?void 0:opt.label)==="string")out.add(slugify(opt.label))}}}return out}function innateLeaves(innate,comparand){if(!innate||typeof innate!=="object"||Array.isArray(innate))return[];const strings=v=>Array.isArray(v)?v.filter(x=>typeof x==="string"):v&&typeof v==="object"?Object.values(v).flatMap(strings):[];return Object.entries(innate).filter(([k])=>k==="_"||Number(k)<=comparand).flatMap(([,v])=>strings(v))}function memberAtWillLeaves(innate,comparand,slug){if(!innate||typeof innate!=="object"||Array.isArray(innate))return[];const out=[];for(const[k,v]of Object.entries(innate)){if(!(k==="_"||Number(k)<=comparand))continue;if(Array.isArray(v)){out.push(...v);continue}for(const[usage,list]of v&&typeof v==="object"?Object.entries(v):[]){if(usage==="will"&&Array.isArray(list))out.push(...list);else warnOnce(`addspells:usage:${slug}:innate:${k}:${usage}`,`archivist: additional_spells on "${slug}" innate.${k}.${usage} is a usage economy (skipped; G8)`)}}return out}function collectAdditionalSpells(args){var _a,_b;const{race,feats,classes,totalLevel,ownAbility,alreadyCollected,entities,warnings}=args;const raceChoice=(_a=args.raceChoice)!=null?_a:(()=>void 0);let index=null;const indexOf=()=>index!=null?index:index=buildSpellNameIndex(entities);const out=[];const carriers=[];const asRaw=x=>x==null?void 0:x.additional_spells;if(race&&raceIsUngated(race))carriers.push({root:"race",slug:race.slug,edition:editionOf(race),entries:entriesOf(asRaw(race)),comparand:totalLevel,classSlug:null});else if(race){const chosen=chosenRaceOptionKeys(race,raceChoice);for(const e of entriesOf(asRaw(race))){if(typeof e.name==="string"&&chosen.has(slugify(e.name))){carriers.push({root:"race",slug:race.slug,edition:editionOf(race),entries:[e],comparand:totalLevel,classSlug:null})}}}for(const f of feats)carriers.push({root:"feat",slug:f.slug,edition:editionOf(f),entries:entriesOf(asRaw(f)),comparand:totalLevel,classSlug:null});for(const c of classes){if(!c.entity)continue;carriers.push({root:"class",slug:c.entity.slug,edition:editionOf(c.entity),entries:entriesOf(asRaw(c.entity)),comparand:c.level,classSlug:c.entity.slug});if(c.subclass)carriers.push({root:"subclass",slug:c.subclass.slug,edition:editionOf(c.subclass),entries:entriesOf(asRaw(c.subclass)),comparand:c.level,classSlug:c.entity.slug})}for(const pool of(_b=args.pools)!=null?_b:[]){const c=classes[pool.classIndex];if(!(c==null?void 0:c.entity))continue;for(const m of[...heldPicks(pool),...pool.grants]){if(m.itemBound===true)continue;carriers.push({root:"member",slug:m.slug,edition:editionOf(m.entity),entries:entriesOf(asRaw(m.entity)),comparand:c.level,classSlug:c.entity.slug})}}for(const car of carriers){if(car.entries.length===0)continue;if(car.entries.length>1){if(car.entries.some(e=>entryHasInSliceLeaf(e,car.comparand,ownAbility)))warnOnce(`addspells:siblings:${car.slug}`,`archivist: additional_spells on "${car.slug}" has ${car.entries.length} sibling entries (a choose-one grant); skipped`);continue}const entry=car.entries[0];let ability=readAbility(entry.ability,ownAbility);if(ability==="choose"&&car.root==="race"){const pick=raceChoice("spellcasting-ability");const allowed=entry.ability.choose;ability=typeof pick==="string"&&Array.isArray(allowed)&&allowed.includes(pick)?pick:"choose"}if(ability==="choose")continue;const buckets=["known","prepared"].map(bucket=>{const levels=entry[bucket];return[bucket,!levels||typeof levels!=="object"||Array.isArray(levels)?[]:Object.entries(levels)]});if(car.root==="race")buckets.push(["innate",[["_",innateLeaves(entry.innate,car.comparand)]]]);if(car.root==="member")buckets.push(["at-will",[["_",memberAtWillLeaves(entry.innate,car.comparand,car.slug)]]]);for(const[bucket,levelEntries]of buckets){for(const[k,v]of levelEntries){if(!(k==="_"||Number(k)<=car.comparand))continue;if(!Array.isArray(v)){warnOnce(`addspells:usage:${car.slug}:${bucket}:${k}`,`archivist: additional_spells on "${car.slug}" ${bucket}.${k} is a usage economy (skipped; G8)`);continue}for(const leaf of v){const nameSlug=normalizeSpellRef(leaf);if(!nameSlug)continue;const hit=resolveSpellByName({entities,index:indexOf(),nameSlug,carrierSlug:car.slug,carrierEdition:car.edition,alreadyCollected:[...alreadyCollected,...out]});if(!hit){warnings.push(`additional_spells ref "${String(leaf)}" on ${car.slug} not found in compendium.`);continue}out.push({entity:hit.entity,slug:hit.slug,classSlug:car.classSlug,source:car.root==="race"?"race":car.root==="feat"?"feat":"class",prepared:true,alwaysPrepared:true,...ability?{ability}:{},...bucket==="at-will"?{atWill:true}:{}})}}}}return out}export{prefixOf,normalizeSpellRef,buildSpellNameIndex,resolveSpellByName,raceIsUngated,chosenRaceOptionKeys,collectAdditionalSpells};
@@ -1 +1 @@
1
- import{subclassEntitySchema}from"./chunk-NU6WP4P5.js";import{aliasFeaturesByLevelActionCost}from"./chunk-S5UCI27C.js";import{parseYaml}from"@archivist-gg/core";function parseSubclass(source){const raw=parseYaml(source,["name","slug","parent_class"]);if(!raw.success)return raw;aliasFeaturesByLevelActionCost(raw.data.features_by_level);const result=subclassEntitySchema.safeParse({edition:"2014",...raw.data});if(!result.success){return{success:false,error:`subclass schema validation failed: ${result.error.message}`}}return{success:true,data:result.data}}export{parseSubclass};
1
+ import{subclassEntitySchema}from"./chunk-KGRRQ4US.js";import{aliasFeaturesByLevelActionCost}from"./chunk-S5UCI27C.js";import{parseYaml}from"@archivist-gg/core";function parseSubclass(source){const raw=parseYaml(source,["name","slug","parent_class"]);if(!raw.success)return raw;aliasFeaturesByLevelActionCost(raw.data.features_by_level);const result=subclassEntitySchema.safeParse({edition:"2014",...raw.data});if(!result.success){return{success:false,error:`subclass schema validation failed: ${result.error.message}`}}return{success:true,data:result.data}}export{parseSubclass};
@@ -1 +1 @@
1
- import{parseSubclass}from"./chunk-J6FIBUI4.js";import yaml from"js-yaml";var subclassCodec={parse(doc){return parseSubclass(doc.body)},serialize(entity){return yaml.dump(entity,{lineWidth:-1,sortKeys:false})}};export{subclassCodec};
1
+ import{parseSubclass}from"./chunk-HPBEMAM6.js";import yaml from"js-yaml";var subclassCodec={parse(doc){return parseSubclass(doc.body)},serialize(entity){return yaml.dump(entity,{lineWidth:-1,sortKeys:false})}};export{subclassCodec};
@@ -1 +1 @@
1
- import{parseFeat}from"./chunk-EBFLUJIW.js";import yaml from"js-yaml";var featCodec={parse(doc){return parseFeat(doc.body)},serialize(entity){return yaml.dump(entity,{lineWidth:-1,sortKeys:false})}};export{featCodec};
1
+ import{parseFeat}from"./chunk-A25HLCQ7.js";import yaml from"js-yaml";var featCodec={parse(doc){return parseFeat(doc.body)},serialize(entity){return yaml.dump(entity,{lineWidth:-1,sortKeys:false})}};export{featCodec};
@@ -1 +1 @@
1
- import{startingEquipmentEntrySchema}from"./chunk-TKIEPC6F.js";import{choiceSchema}from"./chunk-VHIE2KYQ.js";import{additionalSpellsEntrySchema,imageField}from"./chunk-I26FHSI6.js";import{z}from"zod";var abilityEnum=z.enum(["str","dex","con","int","wis","cha"]);var editionEnum=z.enum(["2014","2024"]);var skillEnum=z.enum(["acrobatics","animal-handling","arcana","athletics","deception","history","insight","intimidation","investigation","medicine","nature","perception","performance","persuasion","religion","sleight-of-hand","stealth","survival"]);var wikilinkRegex=/^\[\[[^[\]]+\]\]$/;var toolProfSchema=z.discriminatedUnion("kind",[z.object({kind:z.literal("fixed"),items:z.array(z.string()).nonempty()}),z.object({kind:z.literal("choice"),count:z.number().int().positive(),from:z.array(z.string()).nonempty()})]);var langProfSchema=z.discriminatedUnion("kind",[z.object({kind:z.literal("fixed"),languages:z.array(z.string()).nonempty()}),z.object({kind:z.literal("choice"),count:z.number().int().positive(),from:z.union([z.string(),z.array(z.string())])})]);var suggestedCharSchema=z.object({personality_traits:z.record(z.string(),z.string()).optional(),ideals:z.record(z.string(),z.object({name:z.string().optional(),desc:z.string(),alignment:z.string().optional()})).optional(),bonds:z.record(z.string(),z.string()).optional(),flaws:z.record(z.string(),z.string()).optional()});var backgroundEntitySchema=z.object({slug:z.string().min(1),name:z.string().min(1),edition:editionEnum,source:z.string().min(1),description:z.string(),skill_proficiencies:z.array(skillEnum),tool_proficiencies:z.array(toolProfSchema),language_proficiencies:z.array(langProfSchema),equipment:z.array(startingEquipmentEntrySchema),feature:z.object({name:z.string().min(1),description:z.string().min(1)}),ability_score_increases:z.object({pool:z.array(abilityEnum).length(3)}).nullable(),origin_feat:z.string().regex(wikilinkRegex).nullable(),suggested_characteristics:suggestedCharSchema.nullable(),choices:z.array(choiceSchema).optional(),rendering_hint:z.string().optional(),has_fluff_images:z.boolean().optional(),tables:z.array(z.object({name:z.string().min(1),dice:z.string().min(1),rows:z.array(z.object({roll:z.string(),text:z.string()}))})).optional(),additional_spells:z.array(additionalSpellsEntrySchema).optional(),prerequisites:z.array(z.object({kind:z.literal("campaign"),slug:z.string().min(1)})).optional(),image:imageField});export{langProfSchema,backgroundEntitySchema};
1
+ import{startingEquipmentEntrySchema}from"./chunk-TKIEPC6F.js";import{choiceSchema}from"./chunk-ZK3P4RSE.js";import{additionalSpellsEntrySchema,imageField}from"./chunk-I26FHSI6.js";import{z}from"zod";var abilityEnum=z.enum(["str","dex","con","int","wis","cha"]);var editionEnum=z.enum(["2014","2024"]);var skillEnum=z.enum(["acrobatics","animal-handling","arcana","athletics","deception","history","insight","intimidation","investigation","medicine","nature","perception","performance","persuasion","religion","sleight-of-hand","stealth","survival"]);var wikilinkRegex=/^\[\[[^[\]]+\]\]$/;var toolProfSchema=z.discriminatedUnion("kind",[z.object({kind:z.literal("fixed"),items:z.array(z.string()).nonempty()}),z.object({kind:z.literal("choice"),count:z.number().int().positive(),from:z.array(z.string()).nonempty()})]);var langProfSchema=z.discriminatedUnion("kind",[z.object({kind:z.literal("fixed"),languages:z.array(z.string()).nonempty()}),z.object({kind:z.literal("choice"),count:z.number().int().positive(),from:z.union([z.string(),z.array(z.string())])})]);var suggestedCharSchema=z.object({personality_traits:z.record(z.string(),z.string()).optional(),ideals:z.record(z.string(),z.object({name:z.string().optional(),desc:z.string(),alignment:z.string().optional()})).optional(),bonds:z.record(z.string(),z.string()).optional(),flaws:z.record(z.string(),z.string()).optional()});var backgroundEntitySchema=z.object({slug:z.string().min(1),name:z.string().min(1),edition:editionEnum,source:z.string().min(1),description:z.string(),skill_proficiencies:z.array(skillEnum),tool_proficiencies:z.array(toolProfSchema),language_proficiencies:z.array(langProfSchema),equipment:z.array(startingEquipmentEntrySchema),feature:z.object({name:z.string().min(1),description:z.string().min(1)}),ability_score_increases:z.object({pool:z.array(abilityEnum).length(3)}).nullable(),origin_feat:z.string().regex(wikilinkRegex).nullable(),suggested_characteristics:suggestedCharSchema.nullable(),choices:z.array(choiceSchema).optional(),rendering_hint:z.string().optional(),has_fluff_images:z.boolean().optional(),tables:z.array(z.object({name:z.string().min(1),dice:z.string().min(1),rows:z.array(z.object({roll:z.string(),text:z.string()}))})).optional(),additional_spells:z.array(additionalSpellsEntrySchema).optional(),prerequisites:z.array(z.object({kind:z.literal("campaign"),slug:z.string().min(1)})).optional(),image:imageField});export{langProfSchema,backgroundEntitySchema};