@opencharacter/swn-revised 0.0.0-stage → 0.2.0

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 (321) hide show
  1. package/LICENSE +147 -0
  2. package/README.md +182 -2
  3. package/content/armor/armored-undersuit.yaml +8 -0
  4. package/content/armor/armored-vacc-suit.yaml +8 -0
  5. package/content/armor/assault-suit.yaml +8 -0
  6. package/content/armor/combat-field-uniform.yaml +8 -0
  7. package/content/armor/deflector-array.yaml +8 -0
  8. package/content/armor/field-emitter-panoply.yaml +9 -0
  9. package/content/armor/force-pavis.yaml +9 -0
  10. package/content/armor/heavy-primitive-armor.yaml +8 -0
  11. package/content/armor/icarus-harness.yaml +8 -0
  12. package/content/armor/light-primitive-armor.yaml +8 -0
  13. package/content/armor/medium-primitive-armor.yaml +8 -0
  14. package/content/armor/secure-clothing.yaml +8 -0
  15. package/content/armor/security-armor.yaml +8 -0
  16. package/content/armor/shield.yaml +9 -0
  17. package/content/armor/storm-armor.yaml +9 -0
  18. package/content/armor/vestimentum.yaml +8 -0
  19. package/content/armor/warpaint.yaml +8 -0
  20. package/content/armor/woven-body-armor.yaml +8 -0
  21. package/content/backgrounds/barbarian.yaml +20 -0
  22. package/content/backgrounds/clergy.yaml +20 -0
  23. package/content/backgrounds/courtesan.yaml +20 -0
  24. package/content/backgrounds/criminal.yaml +20 -0
  25. package/content/backgrounds/dilettante.yaml +20 -0
  26. package/content/backgrounds/entertainer.yaml +20 -0
  27. package/content/backgrounds/merchant.yaml +20 -0
  28. package/content/backgrounds/noble.yaml +20 -0
  29. package/content/backgrounds/official.yaml +20 -0
  30. package/content/backgrounds/peasant.yaml +20 -0
  31. package/content/backgrounds/physician.yaml +20 -0
  32. package/content/backgrounds/pilot.yaml +20 -0
  33. package/content/backgrounds/politician.yaml +20 -0
  34. package/content/backgrounds/scholar.yaml +20 -0
  35. package/content/backgrounds/soldier.yaml +20 -0
  36. package/content/backgrounds/spacer.yaml +20 -0
  37. package/content/backgrounds/technician.yaml +20 -0
  38. package/content/backgrounds/thug.yaml +20 -0
  39. package/content/backgrounds/vagabond.yaml +20 -0
  40. package/content/backgrounds/worker.yaml +20 -0
  41. package/content/classes/adventurer.yaml +9 -0
  42. package/content/classes/expert.yaml +16 -0
  43. package/content/classes/psychic.yaml +11 -0
  44. package/content/classes/warrior.yaml +29 -0
  45. package/content/cyberware/adrenal-suppression-pump.yaml +17 -0
  46. package/content/cyberware/bioadaptation-augments.yaml +6 -0
  47. package/content/cyberware/body-arsenal-array.yaml +6 -0
  48. package/content/cyberware/body-sculpting.yaml +6 -0
  49. package/content/cyberware/dermal-armor.yaml +8 -0
  50. package/content/cyberware/drone-control-link.yaml +6 -0
  51. package/content/cyberware/eelskin-capacitor-mesh.yaml +7 -0
  52. package/content/cyberware/gecko-anchors.yaml +6 -0
  53. package/content/cyberware/ghost-talker-transceiver.yaml +6 -0
  54. package/content/cyberware/holdout-cavity.yaml +6 -0
  55. package/content/cyberware/holoskin-emitters.yaml +6 -0
  56. package/content/cyberware/identity-submersion-trigger.yaml +6 -0
  57. package/content/cyberware/immunofiltration-system.yaml +6 -0
  58. package/content/cyberware/induced-coma-trigger.yaml +6 -0
  59. package/content/cyberware/neurointruder-alert.yaml +11 -0
  60. package/content/cyberware/panspectral-optics.yaml +6 -0
  61. package/content/cyberware/pressure-sheathing.yaml +6 -0
  62. package/content/cyberware/prosthetic-limb.yaml +6 -0
  63. package/content/cyberware/revenant-wiring.yaml +6 -0
  64. package/content/cyberware/slowtime-window.yaml +7 -0
  65. package/content/cyberware/stabilization-overrides.yaml +8 -0
  66. package/content/cyberware/tagger-nanites.yaml +7 -0
  67. package/content/cyberware/toxin-injector.yaml +7 -0
  68. package/content/cyberware/twitchlock-actuators.yaml +7 -0
  69. package/content/foci/alert.yaml +9 -0
  70. package/content/foci/armsman.yaml +9 -0
  71. package/content/foci/assassin.yaml +5 -0
  72. package/content/foci/authority.yaml +5 -0
  73. package/content/foci/close-combatant.yaml +7 -0
  74. package/content/foci/connected.yaml +5 -0
  75. package/content/foci/die-hard.yaml +7 -0
  76. package/content/foci/diplomat.yaml +10 -0
  77. package/content/foci/gunslinger.yaml +8 -0
  78. package/content/foci/hacker.yaml +10 -0
  79. package/content/foci/healer.yaml +7 -0
  80. package/content/foci/henchkeeper.yaml +7 -0
  81. package/content/foci/ironhide.yaml +7 -0
  82. package/content/foci/psychic-training.yaml +19 -0
  83. package/content/foci/savage-fray.yaml +5 -0
  84. package/content/foci/shocking-assault.yaml +8 -0
  85. package/content/foci/sniper.yaml +10 -0
  86. package/content/foci/specialist.yaml +36 -0
  87. package/content/foci/star-captain.yaml +5 -0
  88. package/content/foci/starfarer.yaml +5 -0
  89. package/content/foci/tinker.yaml +5 -0
  90. package/content/foci/unarmed-combatant.yaml +11 -0
  91. package/content/foci/unique-gift.yaml +6 -0
  92. package/content/foci/wanderer.yaml +5 -0
  93. package/content/foci/wild-psychic-talent.yaml +21 -0
  94. package/content/gear/ammo-20-rounds.yaml +9 -0
  95. package/content/gear/ammo-missile.yaml +8 -0
  96. package/content/gear/atmofilter.yaml +7 -0
  97. package/content/gear/backpack-tl0.yaml +7 -0
  98. package/content/gear/backpack-tl4.yaml +7 -0
  99. package/content/gear/bezoar.yaml +9 -0
  100. package/content/gear/binoculars-tl3.yaml +7 -0
  101. package/content/gear/binoculars-tl4.yaml +7 -0
  102. package/content/gear/bioscanner.yaml +7 -0
  103. package/content/gear/black-slab.yaml +7 -0
  104. package/content/gear/brainwave.yaml +8 -0
  105. package/content/gear/climbing-harness.yaml +7 -0
  106. package/content/gear/comm-server.yaml +7 -0
  107. package/content/gear/compad.yaml +7 -0
  108. package/content/gear/data-phase-tap.yaml +7 -0
  109. package/content/gear/data-protocol.yaml +7 -0
  110. package/content/gear/dataslab.yaml +7 -0
  111. package/content/gear/field-radio.yaml +7 -0
  112. package/content/gear/glowbug.yaml +7 -0
  113. package/content/gear/grapnel-launcher.yaml +7 -0
  114. package/content/gear/grav-chute-tl4.yaml +7 -0
  115. package/content/gear/grav-chute-tl5.yaml +7 -0
  116. package/content/gear/grav-harness.yaml +7 -0
  117. package/content/gear/hush.yaml +8 -0
  118. package/content/gear/instapanel.yaml +8 -0
  119. package/content/gear/lazarus-patch.yaml +8 -0
  120. package/content/gear/lift.yaml +11 -0
  121. package/content/gear/line-shunt.yaml +7 -0
  122. package/content/gear/low-light-goggles.yaml +7 -0
  123. package/content/gear/medkit.yaml +7 -0
  124. package/content/gear/metatool.yaml +7 -0
  125. package/content/gear/navcomp.yaml +7 -0
  126. package/content/gear/portabox.yaml +7 -0
  127. package/content/gear/postech-toolkit.yaml +7 -0
  128. package/content/gear/power-cell-a.yaml +9 -0
  129. package/content/gear/power-cell-b.yaml +8 -0
  130. package/content/gear/pressure-tent.yaml +7 -0
  131. package/content/gear/pretech-cosmetic.yaml +9 -0
  132. package/content/gear/pretech-toolkit.yaml +7 -0
  133. package/content/gear/psych.yaml +8 -0
  134. package/content/gear/rations-1-day.yaml +8 -0
  135. package/content/gear/remote-link-unit.yaml +7 -0
  136. package/content/gear/reverie.yaml +9 -0
  137. package/content/gear/rope-tl0.yaml +7 -0
  138. package/content/gear/rope-tl4.yaml +7 -0
  139. package/content/gear/scout-report.yaml +7 -0
  140. package/content/gear/solar-recharger.yaml +7 -0
  141. package/content/gear/spare-parts.yaml +8 -0
  142. package/content/gear/squeal.yaml +8 -0
  143. package/content/gear/stiletto-charge.yaml +6 -0
  144. package/content/gear/storage-unit.yaml +7 -0
  145. package/content/gear/survey-scanner.yaml +7 -0
  146. package/content/gear/survival-kit.yaml +7 -0
  147. package/content/gear/tailored-antiallergens.yaml +7 -0
  148. package/content/gear/telekinetic-generator.yaml +7 -0
  149. package/content/gear/telescoping-pole.yaml +7 -0
  150. package/content/gear/thermal-flare.yaml +7 -0
  151. package/content/gear/tightbeam-link-unit.yaml +7 -0
  152. package/content/gear/trade-goods.yaml +8 -0
  153. package/content/gear/trade-metals.yaml +8 -0
  154. package/content/gear/translator-torc.yaml +7 -0
  155. package/content/gear/tsunami.yaml +9 -0
  156. package/content/gear/vacc-fresher.yaml +7 -0
  157. package/content/gear/vacc-skin.yaml +7 -0
  158. package/content/gear/vacc-suit.yaml +7 -0
  159. package/content/kits/barbarian.yaml +17 -0
  160. package/content/kits/blade.yaml +17 -0
  161. package/content/kits/civilian.yaml +12 -0
  162. package/content/kits/credits.yaml +11 -0
  163. package/content/kits/gunslinger.yaml +16 -0
  164. package/content/kits/hacker.yaml +18 -0
  165. package/content/kits/medic.yaml +18 -0
  166. package/content/kits/scout.yaml +19 -0
  167. package/content/kits/soldier.yaml +16 -0
  168. package/content/kits/technician.yaml +19 -0
  169. package/content/kits/thief.yaml +19 -0
  170. package/content/partial-classes/expert.yaml +5 -0
  171. package/content/partial-classes/psychic.yaml +16 -0
  172. package/content/partial-classes/warrior.yaml +7 -0
  173. package/content/styles/expert-nimble.yaml +11 -0
  174. package/content/styles/expert-smart.yaml +11 -0
  175. package/content/styles/expert-smooth.yaml +11 -0
  176. package/content/styles/psychic-adept.yaml +11 -0
  177. package/content/styles/psychic-seer.yaml +11 -0
  178. package/content/styles/warrior-leader.yaml +11 -0
  179. package/content/styles/warrior-melee.yaml +11 -0
  180. package/content/styles/warrior-ranged.yaml +11 -0
  181. package/content/techniques/accelerated-succor.yaml +10 -0
  182. package/content/techniques/alternate-outcome.yaml +10 -0
  183. package/content/techniques/anguished-vision.yaml +10 -0
  184. package/content/techniques/burdened-apportation.yaml +10 -0
  185. package/content/techniques/cloak-powers.yaml +10 -0
  186. package/content/techniques/concert-of-minds.yaml +10 -0
  187. package/content/techniques/cursed-luck.yaml +59 -0
  188. package/content/techniques/deep-intrusion.yaml +10 -0
  189. package/content/techniques/destinys-shield.yaml +10 -0
  190. package/content/techniques/effortless-apportation.yaml +10 -0
  191. package/content/techniques/facile-mind.yaml +10 -0
  192. package/content/techniques/far-thought.yaml +10 -0
  193. package/content/techniques/flawless-mastery.yaml +10 -0
  194. package/content/techniques/force-puppetry.yaml +10 -0
  195. package/content/techniques/forced-outcome.yaml +10 -0
  196. package/content/techniques/holistic-optimization-patterning.yaml +10 -0
  197. package/content/techniques/impact-sump.yaml +10 -0
  198. package/content/techniques/impervious-pavis-of-will.yaml +10 -0
  199. package/content/techniques/intuitive-response.yaml +10 -0
  200. package/content/techniques/invincible-stand.yaml +10 -0
  201. package/content/techniques/kinetic-transversal.yaml +10 -0
  202. package/content/techniques/major-organ-restoration.yaml +10 -0
  203. package/content/techniques/mastered-succor.yaml +10 -0
  204. package/content/techniques/memory-editing.yaml +10 -0
  205. package/content/techniques/metadimensional-friction.yaml +10 -0
  206. package/content/techniques/metamorph.yaml +10 -0
  207. package/content/techniques/mindtracing.yaml +10 -0
  208. package/content/techniques/neural-trap.yaml +10 -0
  209. package/content/techniques/not-my-time.yaml +10 -0
  210. package/content/techniques/offensive-apportation.yaml +10 -0
  211. package/content/techniques/oracle.yaml +6 -0
  212. package/content/techniques/organic-purification-protocols.yaml +10 -0
  213. package/content/techniques/perceptive-dislocation.yaml +10 -0
  214. package/content/techniques/personal-apportation.yaml +6 -0
  215. package/content/techniques/pressure-field.yaml +10 -0
  216. package/content/techniques/proficient-apportation.yaml +10 -0
  217. package/content/techniques/prophecy.yaml +10 -0
  218. package/content/techniques/psychic-refinement.yaml +11 -0
  219. package/content/techniques/psychic-static.yaml +10 -0
  220. package/content/techniques/psychic-succor.yaml +52 -0
  221. package/content/techniques/psychic-tutelage.yaml +10 -0
  222. package/content/techniques/quintessential-reconstruction.yaml +10 -0
  223. package/content/techniques/reactive-telekinesis.yaml +10 -0
  224. package/content/techniques/reflex-response.yaml +10 -0
  225. package/content/techniques/remote-repair.yaml +10 -0
  226. package/content/techniques/rift-reduplication.yaml +10 -0
  227. package/content/techniques/sense-the-need.yaml +10 -0
  228. package/content/techniques/slip-field.yaml +10 -0
  229. package/content/techniques/spatial-awareness.yaml +10 -0
  230. package/content/techniques/spatial-synchrony-mandala.yaml +10 -0
  231. package/content/techniques/stutterjump.yaml +10 -0
  232. package/content/techniques/suppress-cognition.yaml +10 -0
  233. package/content/techniques/surge-momentum.yaml +10 -0
  234. package/content/techniques/suspended-manifestation.yaml +10 -0
  235. package/content/techniques/synthetic-adaptation.yaml +10 -0
  236. package/content/techniques/tangible-force-construct.yaml +10 -0
  237. package/content/techniques/telekinetic-armory.yaml +10 -0
  238. package/content/techniques/telekinetic-expertise.yaml +10 -0
  239. package/content/techniques/telekinetic-flight.yaml +10 -0
  240. package/content/techniques/telekinetic-manipulation.yaml +6 -0
  241. package/content/techniques/telekinetic-ram.yaml +10 -0
  242. package/content/techniques/telepathic-assault.yaml +10 -0
  243. package/content/techniques/telepathic-contact.yaml +6 -0
  244. package/content/techniques/teratic-overload.yaml +10 -0
  245. package/content/techniques/terminal-reflection.yaml +10 -0
  246. package/content/techniques/thermokinesis.yaml +10 -0
  247. package/content/techniques/tissue-integrity-field.yaml +10 -0
  248. package/content/techniques/transmit-thought.yaml +10 -0
  249. package/content/techniques/unity-of-thought.yaml +10 -0
  250. package/content/templates/trained-unarmed.yaml +9 -0
  251. package/content/weapons/advanced-bow.yaml +13 -0
  252. package/content/weapons/anti-vehicle-laser.yaml +16 -0
  253. package/content/weapons/combat-rifle.yaml +16 -0
  254. package/content/weapons/combat-shotgun.yaml +16 -0
  255. package/content/weapons/conversion-bow.yaml +13 -0
  256. package/content/weapons/crude-pistol.yaml +16 -0
  257. package/content/weapons/demo-charge.yaml +13 -0
  258. package/content/weapons/distortion-cannon.yaml +16 -0
  259. package/content/weapons/grenade.yaml +14 -0
  260. package/content/weapons/heavy-machine-gun.yaml +17 -0
  261. package/content/weapons/hydra-array.yaml +16 -0
  262. package/content/weapons/knife.yaml +7 -0
  263. package/content/weapons/large-advanced-weapon.yaml +13 -0
  264. package/content/weapons/large-primitive-weapon.yaml +12 -0
  265. package/content/weapons/laser-pistol.yaml +16 -0
  266. package/content/weapons/laser-rifle.yaml +17 -0
  267. package/content/weapons/mag-pistol.yaml +15 -0
  268. package/content/weapons/mag-rifle.yaml +15 -0
  269. package/content/weapons/medium-advanced-weapon.yaml +13 -0
  270. package/content/weapons/medium-primitive-weapon.yaml +12 -0
  271. package/content/weapons/monoblade-knife.yaml +7 -0
  272. package/content/weapons/monoblade-sword.yaml +4 -0
  273. package/content/weapons/musket.yaml +16 -0
  274. package/content/weapons/plasma-projector.yaml +16 -0
  275. package/content/weapons/primitive-bow.yaml +13 -0
  276. package/content/weapons/railgun.yaml +16 -0
  277. package/content/weapons/revolver.yaml +15 -0
  278. package/content/weapons/rifle.yaml +15 -0
  279. package/content/weapons/rocket-launcher.yaml +16 -0
  280. package/content/weapons/semi-auto-pistol.yaml +15 -0
  281. package/content/weapons/shear-rifle.yaml +17 -0
  282. package/content/weapons/shotgun.yaml +15 -0
  283. package/content/weapons/small-advanced-weapon.yaml +14 -0
  284. package/content/weapons/small-primitive-weapon.yaml +13 -0
  285. package/content/weapons/sniper-rifle.yaml +15 -0
  286. package/content/weapons/spear.yaml +8 -0
  287. package/content/weapons/spike-thrower.yaml +16 -0
  288. package/content/weapons/stun-baton.yaml +14 -0
  289. package/content/weapons/submachine-gun.yaml +16 -0
  290. package/content/weapons/suit-ripper.yaml +11 -0
  291. package/content/weapons/thermal-knife.yaml +7 -0
  292. package/content/weapons/thermal-pistol.yaml +16 -0
  293. package/content/weapons/thunder-gun.yaml +16 -0
  294. package/content/weapons/unarmed.yaml +8 -0
  295. package/content/weapons/void-carbine.yaml +15 -0
  296. package/content/weapons/vortex-cannon.yaml +14 -0
  297. package/content/weapons/wheatcutter-belt.yaml +14 -0
  298. package/dist/i18n/en.d.ts +3 -0
  299. package/dist/i18n/en.js +2 -0
  300. package/dist/i18n/en.json +1411 -0
  301. package/dist/index.d.ts +3 -0
  302. package/dist/index.js +2 -0
  303. package/dist/release.json +31795 -0
  304. package/i18n/en/content.yaml +436 -0
  305. package/i18n/en/foci.yaml +199 -0
  306. package/i18n/en/rules.yaml +772 -0
  307. package/i18n/en/text.yaml +249 -0
  308. package/i18n/en.yaml +1 -0
  309. package/pack.yaml +15 -0
  310. package/package.json +58 -3
  311. package/rules/advancement.yaml +482 -0
  312. package/rules/character.yaml +139 -0
  313. package/rules/checks.yaml +166 -0
  314. package/rules/combat.yaml +321 -0
  315. package/rules/core.yaml +111 -0
  316. package/rules/creation.yaml +431 -0
  317. package/rules/gear.yaml +188 -0
  318. package/rules/layout.yaml +197 -0
  319. package/rules/psionics.yaml +165 -0
  320. package/rules/start.yaml +417 -0
  321. package/rules/tags.yaml +71 -0
@@ -0,0 +1,482 @@
1
+ fields:
2
+ # Unspent skill points: any skill; non-combat, non-psychic skills only (Expert); psychic skills
3
+ # and techniques only (a psychic's point each level); the Psychic Training discipline only.
4
+ skillPoints.general: { type: integer, input: true, default: 0, min: 0 }
5
+ skillPoints.expert: { type: integer, input: true, default: 0, min: 0 }
6
+ skillPoints.psychic: { type: integer, input: true, default: 0, min: 0 }
7
+ skillPoints.training: { type: integer, input: true, default: 0, min: 0 }
8
+ # A focus's bonus skill points that didn't buy a level, saved toward that skill only.
9
+ 'skills.{skill}.credit': { type: integer, input: true, default: 0, min: 0, max: 4 }
10
+ # Attribute boosts bought with skill points, at most five.
11
+ attributes.boosts: { type: integer, input: true, default: 0, min: 0, max: 5 }
12
+
13
+ followUps:
14
+ - id: level-up
15
+ while: '!character.creating && level < 10 && xp.current >= xp.next'
16
+ action: level-up
17
+
18
+ actions:
19
+ # A new level: hit points rolled again, three skill points (one of them psychic for a psychic,
20
+ # plus the Expert's bonus point), and a focus level at 2nd, 5th, 7th and 10th level. Saving
21
+ # throws and the attack bonus follow the level.
22
+ - id: level-up
23
+ tags: [level-up]
24
+ available: '!character.creating && level < 20 && xp.current >= xp.next'
25
+ results: [advanced]
26
+ steps:
27
+ - id: start
28
+ kind: branch
29
+ cases:
30
+ - when: true
31
+ flags:
32
+ before: hp.max
33
+ next: level + 1
34
+ trained: countCopies(copy.item == @foci.psychic-training && copy.state.level >= 2) > 0
35
+ - id: level
36
+ kind: changes
37
+ changes:
38
+ - { type: set, field: level, value: flags.next }
39
+ # The new level's d6, Constitution added to each (none below 1). The new maximum is the
40
+ # total with the per-level bonuses if that is more, else one more than before.
41
+ - id: hp
42
+ kind: roll
43
+ tags: [level-up]
44
+ parts: [{ dice: (flags.next)d6 }]
45
+ - id: maximum
46
+ kind: branch
47
+ sheet: proposed
48
+ cases:
49
+ - when: true
50
+ flags:
51
+ total: >-
52
+ sumList(steps.hp.faces, max(1, x + attributes.con.mod)) + hp.perLevel * level
53
+ - id: hitPoints
54
+ kind: changes
55
+ sheet: proposed
56
+ changes:
57
+ - type: set
58
+ field: hp.rolled
59
+ value: '(flags.total > flags.before ? flags.total : flags.before + 1) - hp.perLevel * level'
60
+ - type: adjust
61
+ field: hp.current
62
+ by: '(flags.total > flags.before ? flags.total : flags.before + 1) - flags.before'
63
+ tags: [healing]
64
+ - id: focus
65
+ kind: action
66
+ when: flags.next in [2, 5, 7, 10]
67
+ use: gain-focus
68
+ params: { advancement: true }
69
+ # Psychic Training's second level: a point each level, and the levels before it when it is
70
+ # taken late.
71
+ - id: points
72
+ tags: [level-up.level]
73
+ kind: changes
74
+ sheet: proposed
75
+ changes:
76
+ - { type: adjust, field: skillPoints.general, by: "psionics.access == 'none' ? 3 : 2" }
77
+ - { type: adjust, field: skillPoints.psychic, by: 1, when: "psionics.access != 'none'" }
78
+ - {
79
+ type: adjust,
80
+ field: skillPoints.expert,
81
+ by: class.expertPoints,
82
+ when: class.expertPoints > 0,
83
+ }
84
+ - type: adjust
85
+ when: >-
86
+ countCopies(copy.item == @foci.psychic-training && copy.state.level >= 2) > 0
87
+ field: skillPoints.training
88
+ by: 'flags.trained ? 1 : flags.next - 1'
89
+ - { id: result, kind: outcome, result: "'advanced'" }
90
+
91
+ # A focus's bonus skill taken on advancement: three skill points toward it, with any credit
92
+ # already saved toward it, buying levels in order (level-0 costs 1, level-1 2 and so on). What
93
+ # doesn't buy a level is saved as credit toward the skill; on a skill at level-4 it goes to the
94
+ # general pool.
95
+ - id: focus-skill-points
96
+ listed: false
97
+ tags: [level-up]
98
+ params:
99
+ entry:
100
+ type: enum
101
+ open: true
102
+ required: true
103
+ values:
104
+ [
105
+ administer,
106
+ connect,
107
+ exert,
108
+ fix,
109
+ heal,
110
+ know,
111
+ lead,
112
+ notice,
113
+ perform,
114
+ pilot,
115
+ program,
116
+ punch,
117
+ shoot,
118
+ sneak,
119
+ stab,
120
+ survive,
121
+ talk,
122
+ trade,
123
+ work,
124
+ biopsionics,
125
+ metapsionics,
126
+ precognition,
127
+ telekinesis,
128
+ telepathy,
129
+ teleportation,
130
+ any-combat,
131
+ punch-or-stab,
132
+ any-psychic,
133
+ any-skill,
134
+ ]
135
+ random: { type: boolean, default: false }
136
+ results: [spent, none]
137
+ steps:
138
+ - id: start
139
+ kind: branch
140
+ sheet: proposed
141
+ cases:
142
+ - when: true
143
+ flags:
144
+ open: >-
145
+ params.entry == 'any-combat' ? ['punch', 'shoot', 'stab']
146
+ : params.entry == 'punch-or-stab' ? ['punch', 'stab']
147
+ : params.entry == 'any-psychic'
148
+ ? filterList(keysOf('psychic'), psionics.access == 'unrestricted'
149
+ || x == psionics.discipline)
150
+ : params.entry == 'any-skill' ? keysOf('general') + keysOf('combat')
151
+ : params.entry in keysOf('psychic') && psionics.access != 'unrestricted'
152
+ && params.entry != psionics.discipline ? []
153
+ : [params.entry]
154
+ # A psychic skill the character can't learn: nothing to raise.
155
+ - { id: none, kind: outcome, when: size(flags.open) == 0, result: "'none'" }
156
+ - id: choose
157
+ kind: choice
158
+ when: size(flags.open) > 1
159
+ random: params.random
160
+ recommend: flags.open[0]
161
+ options: { values: { formula: flags.open } }
162
+ - id: picked
163
+ kind: branch
164
+ sheet: proposed
165
+ cases:
166
+ - when: true
167
+ flags:
168
+ skill: 'size(flags.open) == 1 ? flags.open[0] : steps.choose.picked'
169
+ from: "fieldOf('skills.{skill}.level', size(flags.open) == 1 ? flags.open[0] : steps.choose.picked)"
170
+ pool: >-
171
+ 3 + fieldOf('skills.{skill}.credit',
172
+ size(flags.open) == 1 ? flags.open[0] : steps.choose.picked)
173
+ - id: level
174
+ kind: branch
175
+ cases:
176
+ - when: true
177
+ flags: { level: flags.from, had: flags.pool - 3 }
178
+ - id: buy1
179
+ kind: branch
180
+ when: flags.level < 4 && flags.pool >= flags.level + 2
181
+ cases:
182
+ - when: true
183
+ flags: { pool: flags.pool - flags.level - 2, level: flags.level + 1 }
184
+ - id: buy2
185
+ kind: branch
186
+ when: flags.level < 4 && flags.pool >= flags.level + 2
187
+ cases:
188
+ - when: true
189
+ flags: { pool: flags.pool - flags.level - 2, level: flags.level + 1 }
190
+ - id: buy3
191
+ kind: branch
192
+ when: flags.level < 4 && flags.pool >= flags.level + 2
193
+ cases:
194
+ - when: true
195
+ flags: { pool: flags.pool - flags.level - 2, level: flags.level + 1 }
196
+ - id: spend
197
+ kind: changes
198
+ changes:
199
+ - type: set
200
+ when: flags.level != flags.from
201
+ field: { formula: "fieldId('skills.{skill}.level', flags.skill)" }
202
+ value: flags.level
203
+ - type: set
204
+ when: '(flags.level >= 4 ? 0 : flags.pool) != flags.had'
205
+ field: { formula: "fieldId('skills.{skill}.credit', flags.skill)" }
206
+ value: 'flags.level >= 4 ? 0 : flags.pool'
207
+ - type: adjust
208
+ when: flags.level >= 4 && flags.pool > 0
209
+ field: skillPoints.general
210
+ by: flags.pool
211
+ # A free technique for each new psychic skill level from level-1 up.
212
+ - id: technique
213
+ kind: action
214
+ when: flags.skill in keysOf('psychic') && flags.level >= 1 && flags.level > flags.from
215
+ use: pick-technique
216
+ params: { discipline: flags.skill, random: params.random }
217
+ - id: technique2
218
+ kind: action
219
+ when: flags.skill in keysOf('psychic') && flags.level >= 2 && flags.level - flags.from >= 2
220
+ use: pick-technique
221
+ params: { discipline: flags.skill, random: params.random }
222
+ - { id: result, kind: outcome, result: "'spent'", data: { skill: flags.skill } }
223
+
224
+ # A technique of the discipline at or below its skill level, free with a new skill level.
225
+ - id: pick-technique
226
+ listed: false
227
+ tags: [level-up]
228
+ params:
229
+ discipline:
230
+ type: enum
231
+ open: true
232
+ required: true
233
+ values: [biopsionics, metapsionics, precognition, telekinesis, telepathy, teleportation]
234
+ random: { type: boolean, default: false }
235
+ results: [picked]
236
+ steps:
237
+ - id: technique
238
+ kind: choice
239
+ sheet: proposed
240
+ random: params.random
241
+ recommend: options[0]
242
+ options:
243
+ content:
244
+ type: technique
245
+ where: >-
246
+ item.discipline == params.discipline && !item.core
247
+ && item.level <= fieldOf('skills.{psychic}.level', params.discipline)
248
+ && countCopies(copy.item == item.id) == 0
249
+ changes:
250
+ - { type: addItem, entry: { item: picked.id } }
251
+ - { id: result, kind: outcome, result: "'picked'" }
252
+
253
+ # Spend skill points on a skill's next level. Each level costs its number plus one, and the
254
+ # higher levels need a character level: level-2 at 3rd, level-3 at 6th, level-4 at 9th.
255
+ - id: raise-skill
256
+ tags: [level-up]
257
+ available: >-
258
+ !character.creating
259
+ && (skillPoints.general + skillPoints.expert + skillPoints.psychic + skillPoints.training > 0
260
+ || maxList(keysOf('skill'), fieldOf('skills.{skill}.credit', x)) > 0)
261
+ params:
262
+ skill:
263
+ type: enum
264
+ open: true
265
+ required: true
266
+ values:
267
+ [
268
+ administer,
269
+ connect,
270
+ exert,
271
+ fix,
272
+ heal,
273
+ know,
274
+ lead,
275
+ notice,
276
+ perform,
277
+ pilot,
278
+ program,
279
+ punch,
280
+ shoot,
281
+ sneak,
282
+ stab,
283
+ survive,
284
+ talk,
285
+ trade,
286
+ work,
287
+ biopsionics,
288
+ metapsionics,
289
+ precognition,
290
+ telekinesis,
291
+ telepathy,
292
+ teleportation,
293
+ ]
294
+ results: [raised, refused]
295
+ steps:
296
+ - id: start
297
+ kind: branch
298
+ cases:
299
+ - when: true
300
+ flags:
301
+ from: "fieldOf('skills.{skill}.level', params.skill)"
302
+ credit: "fieldOf('skills.{skill}.credit', params.skill)"
303
+ psychic: params.skill in keysOf('psychic')
304
+ general: params.skill in keysOf('general')
305
+ # Credit saved toward the skill pays first.
306
+ - id: cost
307
+ kind: branch
308
+ cases:
309
+ - when: true
310
+ flags:
311
+ fromCredit: min(flags.from + 2, flags.credit)
312
+ cost: flags.from + 2 - min(flags.from + 2, flags.credit)
313
+ - id: training
314
+ kind: branch
315
+ cases:
316
+ - when: true
317
+ flags:
318
+ training: >-
319
+ params.skill == psionics.training ? min(flags.cost, skillPoints.training) : 0
320
+ - id: pools
321
+ kind: branch
322
+ cases:
323
+ - when: true
324
+ flags:
325
+ fromPsychic: 'flags.psychic ? min(flags.cost - flags.training, skillPoints.psychic) : 0'
326
+ fromExpert: 'flags.general ? min(flags.cost - flags.training, skillPoints.expert) : 0'
327
+ - id: check
328
+ kind: branch
329
+ cases:
330
+ - when: true
331
+ flags:
332
+ fromGeneral: flags.cost - flags.training - flags.fromPsychic - flags.fromExpert
333
+ allowed: >-
334
+ flags.from < 4 && level >= [1, 1, 3, 6, 9][flags.from + 1]
335
+ && (!flags.psychic || psionics.access == 'unrestricted'
336
+ || (psionics.access == 'restricted' && params.skill == psionics.discipline))
337
+ - id: pay
338
+ kind: changes
339
+ when: flags.allowed && flags.fromGeneral <= skillPoints.general
340
+ changes:
341
+ - type: adjust
342
+ when: flags.fromCredit > 0
343
+ field: { formula: "fieldId('skills.{skill}.credit', params.skill)" }
344
+ by: -flags.fromCredit
345
+ - {
346
+ type: adjust,
347
+ field: skillPoints.training,
348
+ by: -flags.training,
349
+ when: flags.training > 0,
350
+ }
351
+ - {
352
+ type: adjust,
353
+ field: skillPoints.psychic,
354
+ by: -flags.fromPsychic,
355
+ when: flags.fromPsychic > 0,
356
+ }
357
+ - {
358
+ type: adjust,
359
+ field: skillPoints.expert,
360
+ by: -flags.fromExpert,
361
+ when: flags.fromExpert > 0,
362
+ }
363
+ - {
364
+ type: adjust,
365
+ field: skillPoints.general,
366
+ by: -flags.fromGeneral,
367
+ when: flags.fromGeneral > 0,
368
+ }
369
+ - {
370
+ type: adjust,
371
+ field: { formula: "fieldId('skills.{skill}.level', params.skill)" },
372
+ by: 1,
373
+ }
374
+ - id: technique
375
+ kind: action
376
+ when: >-
377
+ flags.psychic && flags.allowed && flags.fromGeneral <= skillPoints.general
378
+ && flags.from >= 0
379
+ use: pick-technique
380
+ params: { discipline: params.skill }
381
+ - id: result
382
+ kind: outcome
383
+ result: "flags.allowed && flags.fromGeneral <= skillPoints.general ? 'raised' : 'refused'"
384
+
385
+ # Spend skill points on a technique: as many as its level.
386
+ - id: learn-technique
387
+ tags: [level-up]
388
+ available: >-
389
+ !character.creating && psionics.access != 'none'
390
+ && skillPoints.general + skillPoints.psychic + skillPoints.training > 0
391
+ params:
392
+ technique: { type: id, of: technique, required: true, where: '!item.core' }
393
+ results: [learned, refused]
394
+ steps:
395
+ - id: start
396
+ kind: choice
397
+ options: { content: { type: technique, where: item.id == params.technique } }
398
+ recommend: options[0]
399
+ - id: cost
400
+ kind: branch
401
+ cases:
402
+ - when: true
403
+ flags:
404
+ cost: steps.start.item.level
405
+ training: >-
406
+ steps.start.item.discipline == psionics.training
407
+ ? min(steps.start.item.level, skillPoints.training) : 0
408
+ - id: pools
409
+ kind: branch
410
+ cases:
411
+ - when: true
412
+ flags:
413
+ fromPsychic: min(flags.cost - flags.training, skillPoints.psychic)
414
+ - id: check
415
+ kind: branch
416
+ cases:
417
+ - when: true
418
+ flags:
419
+ fromGeneral: flags.cost - flags.training - flags.fromPsychic
420
+ allowed: >-
421
+ countCopies(copy.item == params.technique) == 0
422
+ && fieldOf('skills.{psychic}.level', steps.start.item.discipline)
423
+ >= steps.start.item.level
424
+ - id: pay
425
+ kind: changes
426
+ when: flags.allowed && flags.fromGeneral <= skillPoints.general
427
+ changes:
428
+ - {
429
+ type: adjust,
430
+ field: skillPoints.training,
431
+ by: -flags.training,
432
+ when: flags.training > 0,
433
+ }
434
+ - {
435
+ type: adjust,
436
+ field: skillPoints.psychic,
437
+ by: -flags.fromPsychic,
438
+ when: flags.fromPsychic > 0,
439
+ }
440
+ - {
441
+ type: adjust,
442
+ field: skillPoints.general,
443
+ by: -flags.fromGeneral,
444
+ when: flags.fromGeneral > 0,
445
+ }
446
+ - { type: addItem, entry: { item: params.technique } }
447
+ - id: result
448
+ kind: outcome
449
+ result: "flags.allowed && flags.fromGeneral <= skillPoints.general ? 'learned' : 'refused'"
450
+
451
+ # Spend skill points on +1 to an attribute: the first boost costs 1, the second 2 and so on,
452
+ # the third needs 3rd level, the fourth 6th and the fifth 9th.
453
+ - id: boost-attribute
454
+ tags: [level-up]
455
+ available: >-
456
+ !character.creating && attributes.boosts < 5 && skillPoints.general > attributes.boosts
457
+ && level >= [1, 1, 3, 6, 9][attributes.boosts]
458
+ params:
459
+ attribute: { type: enum, required: true, values: [str, dex, con, int, wis, cha] }
460
+ results: [boosted, refused]
461
+ steps:
462
+ - id: start
463
+ kind: branch
464
+ cases:
465
+ - when: true
466
+ flags:
467
+ allowed: >-
468
+ skillPoints.general >= attributes.boosts + 1
469
+ && level >= [1, 1, 3, 6, 9][attributes.boosts]
470
+ && fieldOf('attributes.{attr}.score', params.attribute) < 18
471
+ - id: pay
472
+ kind: changes
473
+ when: flags.allowed
474
+ changes:
475
+ - { type: adjust, field: skillPoints.general, by: -(attributes.boosts + 1) }
476
+ - { type: adjust, field: attributes.boosts, by: 1 }
477
+ - {
478
+ type: adjust,
479
+ field: { formula: "'attributes.' + params.attribute + '.score'" },
480
+ by: 1,
481
+ }
482
+ - { id: result, kind: outcome, result: "flags.allowed ? 'boosted' : 'refused'" }
@@ -0,0 +1,139 @@
1
+ families:
2
+ growthRow: [1, 2, 3, 4, 5, 6]
3
+ learningRow: [1, 2, 3, 4, 5, 6, 7, 8]
4
+
5
+ fields:
6
+ # Set by the class and its partial classes.
7
+ psionics.access: { type: enum, values: [none, restricted, unrestricted], formula: "'none'" }
8
+ # A restricted psychic's one discipline, picked with the Partial Psychic option.
9
+ psionics.discipline:
10
+ type: enum
11
+ open: true
12
+ values: [none, biopsionics, metapsionics, precognition, telekinesis, telepathy, teleportation]
13
+ formula: "'none'"
14
+ # Extra focus levels a new character picks: non-combat (Expert) and combat (Warrior).
15
+ class.focus.noncombat: { type: integer, formula: 0 }
16
+ class.focus.combat: { type: integer, formula: 0 }
17
+ # Extra skill points each level for non-combat, non-psychic skills (Expert).
18
+ class.expertPoints: { type: integer, formula: 0 }
19
+ # Spent for the scene: the Expert's reroll and the Warrior's luck.
20
+ scene.expertReroll: { type: boolean, input: true, default: false }
21
+ scene.warriorLuck: { type: boolean, input: true, default: false }
22
+
23
+ contentTypes:
24
+ class:
25
+ copies: { max: 1 }
26
+ fields:
27
+ # The starting package recommended for the class.
28
+ kit: { type: id, of: kit }
29
+ # Picked, two of them, by the Adventurer.
30
+ partialClass:
31
+ grantOnly: true
32
+ copies: { max: 0 }
33
+ # A quick character's class and style: the class, the attribute scores and, for the book's
34
+ # styles, the style's column of the quick foci table (0-7).
35
+ style:
36
+ grantOnly: true
37
+ carried: false
38
+ copies: { max: 0 }
39
+ fields:
40
+ class: { type: id, of: class, required: true }
41
+ str: { type: integer, required: true }
42
+ dex: { type: integer, required: true }
43
+ con: { type: integer, required: true }
44
+ int: { type: integer, required: true }
45
+ wis: { type: integer, required: true }
46
+ cha: { type: integer, required: true }
47
+ table: { type: integer, min: 0, max: 7 }
48
+ background:
49
+ copies: { max: 1 }
50
+ fields:
51
+ freeSkill:
52
+ type: enum
53
+ open: true
54
+ required: true
55
+ values:
56
+ &entries [
57
+ administer,
58
+ connect,
59
+ exert,
60
+ fix,
61
+ heal,
62
+ know,
63
+ lead,
64
+ notice,
65
+ perform,
66
+ pilot,
67
+ program,
68
+ punch,
69
+ shoot,
70
+ sneak,
71
+ stab,
72
+ survive,
73
+ talk,
74
+ trade,
75
+ work,
76
+ any-combat,
77
+ any-skill,
78
+ stab-or-shoot,
79
+ shoot-or-trade,
80
+ any-stat,
81
+ physical,
82
+ mental,
83
+ ]
84
+ # The quick skills besides the free one.
85
+ quick1: { type: enum, required: true, values: *entries, open: true }
86
+ quick2: { type: enum, required: true, values: *entries, open: true }
87
+ 'growth{growthRow}': { type: enum, required: true, values: *entries, open: true }
88
+ 'learning{learningRow}': { type: enum, required: true, values: *entries, open: true }
89
+ focus:
90
+ fields:
91
+ kind: { type: enum, values: [combat, noncombat, psychic, special], required: true }
92
+ # The bonus skill its first level gives; `chosen` is the skill the focus's own choice names.
93
+ skill:
94
+ type: enum
95
+ open: true
96
+ default: none
97
+ values:
98
+ [
99
+ administer,
100
+ connect,
101
+ exert,
102
+ fix,
103
+ heal,
104
+ know,
105
+ lead,
106
+ notice,
107
+ perform,
108
+ pilot,
109
+ program,
110
+ punch,
111
+ shoot,
112
+ sneak,
113
+ stab,
114
+ survive,
115
+ talk,
116
+ trade,
117
+ work,
118
+ any-combat,
119
+ punch-or-stab,
120
+ chosen,
121
+ none,
122
+ ]
123
+ maxLevel: { type: integer, default: 2, min: 1 }
124
+ # Taken more than once, each time for something else.
125
+ repeatable: { type: boolean, default: false }
126
+ state:
127
+ level: { type: integer, default: 1, min: 1, max: item.maxLevel }
128
+
129
+ constraints:
130
+ - id: creation-class-background
131
+ check: >-
132
+ !character.creating || (countCopies(copy.type == 'class') > 0
133
+ && countCopies(copy.type == 'background') > 0)
134
+ - id: creation-skill-cap
135
+ check: "!character.creating || maxFields(f.value, 'skill' in f.tags) <= 1"
136
+ data: { limit: 1 }
137
+ - id: focus-once
138
+ copies: { type: focus, where: '!item.repeatable' }
139
+ check: countCopies(copy.item == item.id) <= 1