@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,431 @@
1
+ # Two ways to start: the full procedure (attributes rolled or from the array, a background with
2
+ # its skills picked, taken as quick skills or rolled, a class, foci and a hobby skill) and the
3
+ # quick tables (class and style, background, psychic disciplines, foci and bonus skill, each
4
+ # rolled or picked). The quick tables are the book's random creation.
5
+ creation:
6
+ - { id: standard, action: create-character }
7
+ - { id: quick, action: quick-character }
8
+ - { id: random, action: quick-character, params: { random: true }, random: true }
9
+
10
+ actions:
11
+ # One skill pick at creation: a skill's first pick is level-0, the second level-1, and a third
12
+ # is any other non-psychic skill below level-1. Also the attribute picks of the Growth table.
13
+ - id: gain-skill
14
+ available: character.creating
15
+ tags: [creation]
16
+ params:
17
+ entry:
18
+ {
19
+ type: enum,
20
+ open: true,
21
+ required: true,
22
+ values:
23
+ [
24
+ administer,
25
+ connect,
26
+ exert,
27
+ fix,
28
+ heal,
29
+ know,
30
+ lead,
31
+ notice,
32
+ perform,
33
+ pilot,
34
+ program,
35
+ punch,
36
+ shoot,
37
+ sneak,
38
+ stab,
39
+ survive,
40
+ talk,
41
+ trade,
42
+ work,
43
+ biopsionics,
44
+ metapsionics,
45
+ precognition,
46
+ telekinesis,
47
+ telepathy,
48
+ teleportation,
49
+ any-combat,
50
+ any-skill,
51
+ stab-or-shoot,
52
+ shoot-or-trade,
53
+ punch-or-stab,
54
+ any-psychic,
55
+ raise-zero,
56
+ any-stat,
57
+ physical,
58
+ mental,
59
+ none,
60
+ ],
61
+ }
62
+ random: { type: boolean, default: false }
63
+ results: [gained]
64
+ steps:
65
+ - id: start
66
+ kind: branch
67
+ sheet: proposed
68
+ cases:
69
+ - when: true
70
+ flags:
71
+ stat: "params.entry in ['any-stat', 'physical', 'mental']"
72
+ pool: >-
73
+ params.entry == 'any-combat' ? ['punch', 'shoot', 'stab']
74
+ : params.entry == 'stab-or-shoot' ? ['stab', 'shoot']
75
+ : params.entry == 'shoot-or-trade' ? ['shoot', 'trade']
76
+ : params.entry == 'punch-or-stab' ? ['punch', 'stab']
77
+ : params.entry == 'any-psychic' ? keysOf('psychic')
78
+ : params.entry == 'any-skill' ? keysOf('general') + keysOf('combat')
79
+ : params.entry == 'raise-zero'
80
+ ? filterList(keysOf('general') + keysOf('combat'),
81
+ fieldOf('skills.{skill}.level', x) == 0)
82
+ : params.entry in keysOf('skill') ? [params.entry] : []
83
+ str: 0
84
+ dex: 0
85
+ con: 0
86
+ int: 0
87
+ wis: 0
88
+ cha: 0
89
+ - id: candidates
90
+ kind: branch
91
+ sheet: proposed
92
+ cases:
93
+ - when: true
94
+ flags:
95
+ open: >-
96
+ flags.stat || params.entry == 'none' ? []
97
+ : countList(flags.pool, fieldOf('skills.{skill}.level', x) < 1) > 0
98
+ ? filterList(flags.pool, fieldOf('skills.{skill}.level', x) < 1)
99
+ : filterList(keysOf('general') + keysOf('combat'),
100
+ fieldOf('skills.{skill}.level', x) < 1)
101
+ - id: choose
102
+ kind: choice
103
+ when: size(flags.open) > 1
104
+ random: params.random
105
+ recommend: flags.open[0]
106
+ options: { values: { formula: flags.open } }
107
+ - id: picked
108
+ kind: branch
109
+ cases:
110
+ - when: true
111
+ flags:
112
+ skill: "size(flags.open) == 1 ? flags.open[0] : has(steps.choose) ? steps.choose.picked : ''"
113
+ - id: gain
114
+ kind: changes
115
+ when: flags.skill != ''
116
+ changes:
117
+ - {
118
+ type: adjust,
119
+ field: { formula: "fieldId('skills.{skill}.level', flags.skill)" },
120
+ by: 1,
121
+ }
122
+ # A psychic skill raised to level-1 brings a level-1 technique of its discipline.
123
+ - id: technique
124
+ kind: choice
125
+ sheet: proposed
126
+ when: "flags.skill in keysOf('psychic') && fieldOf('skills.{psychic}.level', flags.skill) >= 1"
127
+ random: params.random
128
+ recommend: options[0]
129
+ options:
130
+ content:
131
+ type: technique
132
+ where: >-
133
+ item.discipline == flags.skill && !item.core
134
+ && item.level <= fieldOf('skills.{psychic}.level', flags.skill)
135
+ && countCopies(copy.item == item.id) == 0
136
+ changes:
137
+ - { type: addItem, entry: { item: picked.id } }
138
+ # +1 to any attribute below 18, or one of the +2 pairs of the physical or mental ones.
139
+ - id: attribute
140
+ kind: choice
141
+ sheet: proposed
142
+ when: "params.entry == 'any-stat'"
143
+ random: params.random
144
+ recommend: options[0]
145
+ options:
146
+ values:
147
+ { formula: "filterList(keysOf('attr'), fieldOf('attributes.{attr}.score', x) < 18)" }
148
+ changes:
149
+ - type: set
150
+ field: { formula: "'attributes.' + picked.value + '.score'" }
151
+ value: "fieldOf('attributes.{attr}.score', picked.value) + 1"
152
+ - id: pair
153
+ kind: choice
154
+ sheet: proposed
155
+ when: "params.entry in ['physical', 'mental']"
156
+ random: params.random
157
+ recommend: options[0]
158
+ options:
159
+ - { id: str2, when: "params.entry == 'physical'", flags: { str: 2 } }
160
+ - { id: dex2, when: "params.entry == 'physical'", flags: { dex: 2 } }
161
+ - { id: con2, when: "params.entry == 'physical'", flags: { con: 2 } }
162
+ - { id: str-dex, when: "params.entry == 'physical'", flags: { str: 1, dex: 1 } }
163
+ - { id: str-con, when: "params.entry == 'physical'", flags: { str: 1, con: 1 } }
164
+ - { id: dex-con, when: "params.entry == 'physical'", flags: { dex: 1, con: 1 } }
165
+ - { id: int2, when: "params.entry == 'mental'", flags: { int: 2 } }
166
+ - { id: wis2, when: "params.entry == 'mental'", flags: { wis: 2 } }
167
+ - { id: cha2, when: "params.entry == 'mental'", flags: { cha: 2 } }
168
+ - { id: int-wis, when: "params.entry == 'mental'", flags: { int: 1, wis: 1 } }
169
+ - { id: int-cha, when: "params.entry == 'mental'", flags: { int: 1, cha: 1 } }
170
+ - { id: wis-cha, when: "params.entry == 'mental'", flags: { wis: 1, cha: 1 } }
171
+ - id: raise
172
+ kind: changes
173
+ sheet: proposed
174
+ when: has(steps.pair)
175
+ changes:
176
+ - type: set
177
+ when: flags.str > 0
178
+ field: attributes.str.score
179
+ value: 'min(18, attributes.str.score + flags.str)'
180
+ - type: set
181
+ when: flags.dex > 0
182
+ field: attributes.dex.score
183
+ value: 'min(18, attributes.dex.score + flags.dex)'
184
+ - type: set
185
+ when: flags.con > 0
186
+ field: attributes.con.score
187
+ value: 'min(18, attributes.con.score + flags.con)'
188
+ - type: set
189
+ when: flags.int > 0
190
+ field: attributes.int.score
191
+ value: 'min(18, attributes.int.score + flags.int)'
192
+ - type: set
193
+ when: flags.wis > 0
194
+ field: attributes.wis.score
195
+ value: 'min(18, attributes.wis.score + flags.wis)'
196
+ - type: set
197
+ when: flags.cha > 0
198
+ field: attributes.cha.score
199
+ value: 'min(18, attributes.cha.score + flags.cha)'
200
+ - id: result
201
+ kind: outcome
202
+ result: "'gained'"
203
+ data: { skill: flags.skill }
204
+
205
+ # A focus level: a new focus, or the next level of one already held. A new focus's bonus skill
206
+ # is a skill pick at creation and three skill points on advancement.
207
+ - id: gain-focus
208
+ listed: false
209
+ tags: [creation, level-up]
210
+ params:
211
+ kind: { type: enum, values: [any, combat, noncombat], default: any }
212
+ advancement: { type: boolean, default: false }
213
+ random: { type: boolean, default: false }
214
+ results: [gained]
215
+ steps:
216
+ - id: focus
217
+ kind: choice
218
+ tags: [{ formula: "params.advancement ? 'level-up.focus' : 'creation.focus'" }]
219
+ sheet: proposed
220
+ random: params.random
221
+ recommend: options[0]
222
+ options:
223
+ content:
224
+ type: focus
225
+ where: >-
226
+ (params.kind == 'any' || item.kind == params.kind)
227
+ && !('needs-psionics' in item.tags && psionics.access == 'none')
228
+ && !('no-psionics' in item.tags && psionics.access != 'none')
229
+ && (item.repeatable || countCopies(copy.item == item.id
230
+ && copy.state.level >= item.maxLevel) == 0)
231
+ changes:
232
+ - type: adjustState
233
+ when: >-
234
+ has(picked.item) && !picked.item.repeatable
235
+ && countCopies(copy.item == picked.id) > 0
236
+ copies: { type: focus, where: item.id == steps.focus.picked }
237
+ limit: 1
238
+ key: level
239
+ by: 1
240
+ - type: addItem
241
+ when: >-
242
+ has(picked.item)
243
+ && (picked.item.repeatable || countCopies(copy.item == picked.id) == 0)
244
+ entry: { item: picked.id }
245
+ - id: picks
246
+ kind: choice
247
+ sheet: proposed
248
+ when: size(steps.focus.added) > 0
249
+ random: params.random
250
+ options: { pending: { entry: 'steps.focus.added[0]' } }
251
+ - id: bonus
252
+ kind: branch
253
+ sheet: proposed
254
+ cases:
255
+ - when: true
256
+ flags:
257
+ entry: >-
258
+ size(steps.focus.added) == 0 ? 'none'
259
+ : steps.focus.item.skill != 'chosen' ? steps.focus.item.skill
260
+ : size(steps.picks.picked) > 0 ? steps.picks.picked[0] : 'any-skill'
261
+ - id: skill
262
+ kind: action
263
+ when: "!params.advancement && flags.entry != 'none'"
264
+ use: gain-skill
265
+ params: { entry: flags.entry, random: params.random }
266
+ - id: points
267
+ kind: action
268
+ when: "params.advancement && flags.entry != 'none'"
269
+ use: focus-skill-points
270
+ params: { entry: flags.entry, random: params.random }
271
+ - { id: result, kind: outcome, result: "'gained'" }
272
+
273
+ - id: starting-gear
274
+ available: character.creating
275
+ tags: [creation]
276
+ params:
277
+ random: { type: boolean, default: false }
278
+ results: [equipped]
279
+ steps:
280
+ # A package (an add-on pack's too), or credits instead: the class's own package is
281
+ # recommended. The package's own action adds its gear and credits.
282
+ - id: kit
283
+ tags: [creation.kit]
284
+ kind: choice
285
+ sheet: proposed
286
+ random: params.random
287
+ options: { content: { type: kit } }
288
+ prefer: "countCopies(copy.type == 'class' && copy.fields.kit == item.id)"
289
+ changes:
290
+ - type: addItem
291
+ when: has(picked.item)
292
+ entry: { id: kit, item: picked.id }
293
+ - id: unpack
294
+ kind: action
295
+ when: has(steps.kit.item)
296
+ sheet: proposed
297
+ entry: "'kit'"
298
+ use: unpack
299
+ - id: unpacked
300
+ kind: changes
301
+ when: has(steps.kit.item)
302
+ changes:
303
+ - { type: removeItem, entry: kit }
304
+ # A kit may ready more than half Strength. Readied gear, then all but one weapon (the
305
+ # weakest first), are stowed while they fit within Strength. Past that, readied gear, a
306
+ # shield, the last weapon and then armor are stowed anyway, and Stowed gear, weapons and
307
+ # armor past Strength are left behind (the heaviest first), so play starts unencumbered.
308
+ - id: stowGear
309
+ kind: choice
310
+ sheet: proposed
311
+ repeat: { max: 20, min: 20 }
312
+ options:
313
+ copies:
314
+ type: gear
315
+ where: >-
316
+ self.equipped && has(item.enc) && item.enc > 0
317
+ && encumbrance.readied > encumbrance.readiedLimit
318
+ && encumbrance.stowed + item.enc * ceil(self.quantity / item.bundle)
319
+ <= encumbrance.stowedLimit
320
+ prefer: item.enc
321
+ changes:
322
+ - { type: equip, entry: picked, equipped: false }
323
+ - id: stowWeapon
324
+ kind: choice
325
+ sheet: proposed
326
+ repeat: { max: 20, min: 20 }
327
+ options:
328
+ copies:
329
+ type: weapon
330
+ where: >-
331
+ self.equipped && has(item.enc) && item.enc > 0
332
+ && countCopies(copy.type == 'weapon' && copy.equipped && has(copy.fields.enc)
333
+ && copy.fields.enc > 0) > 1
334
+ && encumbrance.readied > encumbrance.readiedLimit
335
+ && encumbrance.stowed + item.enc * ceil(self.quantity / item.bundle)
336
+ <= encumbrance.stowedLimit
337
+ prefer: -maxOf(item.damage)
338
+ changes:
339
+ - { type: equip, entry: picked, equipped: false }
340
+ - id: stowGearOver
341
+ kind: choice
342
+ sheet: proposed
343
+ repeat: { max: 20, min: 20 }
344
+ options:
345
+ copies:
346
+ type: gear
347
+ where: >-
348
+ self.equipped && has(item.enc) && item.enc > 0
349
+ && encumbrance.readied > encumbrance.readiedLimit
350
+ prefer: item.enc
351
+ changes:
352
+ - { type: equip, entry: picked, equipped: false }
353
+ - id: stowShield
354
+ kind: choice
355
+ sheet: proposed
356
+ repeat: { max: 20, min: 20 }
357
+ options:
358
+ copies:
359
+ type: armor
360
+ where: >-
361
+ self.equipped && has(item.enc) && item.enc > 0 && item.shield
362
+ && encumbrance.readied > encumbrance.readiedLimit
363
+ prefer: item.enc
364
+ changes:
365
+ - { type: equip, entry: picked, equipped: false }
366
+ - id: stowLastWeapon
367
+ kind: choice
368
+ sheet: proposed
369
+ repeat: { max: 20, min: 20 }
370
+ options:
371
+ copies:
372
+ type: weapon
373
+ where: >-
374
+ self.equipped && has(item.enc) && item.enc > 0
375
+ && encumbrance.readied > encumbrance.readiedLimit
376
+ prefer: -maxOf(item.damage)
377
+ changes:
378
+ - { type: equip, entry: picked, equipped: false }
379
+ - id: stowArmor
380
+ kind: choice
381
+ sheet: proposed
382
+ repeat: { max: 20, min: 20 }
383
+ options:
384
+ copies:
385
+ type: armor
386
+ where: >-
387
+ self.equipped && has(item.enc) && item.enc > 0
388
+ && encumbrance.readied > encumbrance.readiedLimit
389
+ prefer: item.enc
390
+ changes:
391
+ - { type: equip, entry: picked, equipped: false }
392
+ - id: dropGear
393
+ kind: choice
394
+ sheet: proposed
395
+ repeat: { max: 20, min: 20 }
396
+ options:
397
+ copies:
398
+ type: gear
399
+ where: >-
400
+ !self.equipped && !self.stored && has(item.enc) && item.enc > 0
401
+ && encumbrance.stowed > encumbrance.stowedLimit
402
+ prefer: 'item.enc * ceil(self.quantity / item.bundle)'
403
+ changes:
404
+ - { type: removeItem, entry: picked }
405
+ - id: dropWeapon
406
+ kind: choice
407
+ sheet: proposed
408
+ repeat: { max: 20, min: 20 }
409
+ options:
410
+ copies:
411
+ type: weapon
412
+ where: >-
413
+ !self.equipped && !self.stored && has(item.enc) && item.enc > 0
414
+ && encumbrance.stowed > encumbrance.stowedLimit
415
+ prefer: 'item.enc * ceil(self.quantity / item.bundle)'
416
+ changes:
417
+ - { type: removeItem, entry: picked }
418
+ - id: dropArmor
419
+ kind: choice
420
+ sheet: proposed
421
+ repeat: { max: 20, min: 20 }
422
+ options:
423
+ copies:
424
+ type: armor
425
+ where: >-
426
+ !self.equipped && !self.stored && has(item.enc) && item.enc > 0
427
+ && encumbrance.stowed > encumbrance.stowedLimit
428
+ prefer: 'item.enc * ceil(self.quantity / item.bundle)'
429
+ changes:
430
+ - { type: removeItem, entry: picked }
431
+ - { id: result, kind: outcome, result: "'equipped'" }
@@ -0,0 +1,188 @@
1
+ fields:
2
+ # Armor Class: the best armor worn (or an innate AC), a shield, and Dexterity.
3
+ ac.innate: { type: integer, formula: 0 }
4
+ ac.armor:
5
+ type: integer
6
+ formula: >-
7
+ max(10, ac.innate, maxCopies(copy.fields.ac, copy.type == 'armor' && copy.equipped
8
+ && !copy.fields.shield))
9
+ ac.shield:
10
+ type: integer
11
+ formula: "maxCopies(copy.fields.ac, copy.type == 'armor' && copy.equipped && copy.fields.shield)"
12
+ ac.value:
13
+ type: integer
14
+ tags: [ac]
15
+ formula: >-
16
+ (ac.shield > 0 ? (ac.armor >= ac.shield ? ac.armor + 1 : ac.shield) : ac.armor)
17
+ + attributes.dex.mod
18
+ # Against firearms and advanced melee weapons, primitive armor and shields count as AC 10.
19
+ ac.advanced:
20
+ type: integer
21
+ tags: [ac]
22
+ formula: >-
23
+ max(10, ac.innate, maxCopies(copy.fields.ac, copy.type == 'armor' && copy.equipped
24
+ && !copy.fields.shield && copy.fields.category != 'primitive'))
25
+ + (maxCopies(copy.fields.ac, copy.type == 'armor' && copy.equipped && copy.fields.shield
26
+ && copy.fields.category != 'primitive') > 0 ? 1 : 0)
27
+ + attributes.dex.mod
28
+
29
+ # Damage bonuses from foci: the Stab skill to melee and thrown weapons (Armsman), the Shoot skill
30
+ # to ranged ones (Gunslinger).
31
+ damage.melee: { type: integer, formula: 0 }
32
+ damage.ranged: { type: integer, formula: 0 }
33
+ shock.bonus: { type: integer, formula: 0 }
34
+ # Melee Shock that treats every target as AC 10 (Shocking Assault, Close Combatant).
35
+ shock.anyAc: { type: boolean, formula: false }
36
+ # Unmodified damage on a miss (Armsman, Gunslinger, Unarmed Combatant).
37
+ miss.melee: { type: dice, formula: 0 }
38
+ miss.ranged: { type: dice, formula: 0 }
39
+ miss.punch: { type: dice, formula: 0 }
40
+ # Primitive melee weapons and fists that count as advanced (Armsman, Unarmed Combatant).
41
+ combat.meleeAdvanced: { type: boolean, formula: false }
42
+ combat.punchAdvanced: { type: boolean, formula: false }
43
+
44
+ # Encumbrance: Readied (equipped) items up to half Strength, Stowed items up to Strength.
45
+ encumbrance.strength: { type: integer, formula: attributes.str.score }
46
+ encumbrance.readied:
47
+ type: integer
48
+ formula: >-
49
+ sumCopies(copy.fields.enc * ceil(copy.quantity / copy.fields.bundle), has(copy.fields.enc)
50
+ && copy.equipped && !copy.state.stored)
51
+ encumbrance.stowed:
52
+ type: integer
53
+ formula: >-
54
+ sumCopies(copy.fields.enc * ceil(copy.quantity / copy.fields.bundle), has(copy.fields.enc)
55
+ && !copy.equipped && !copy.state.stored)
56
+ encumbrance.readiedLimit: { type: integer, formula: floor(encumbrance.strength / 2) }
57
+ encumbrance.stowedLimit: { type: integer, formula: encumbrance.strength }
58
+ # 0 unencumbered, 1 lightly (2 more Readied or 4 more Stowed), 2 heavily (as much again),
59
+ # 3 more than that.
60
+ encumbrance.level:
61
+ type: integer
62
+ limits: { max: 2 }
63
+ formula: >-
64
+ max(encumbrance.readied <= encumbrance.readiedLimit ? 0
65
+ : encumbrance.readied <= encumbrance.readiedLimit + 2 ? 1
66
+ : encumbrance.readied <= encumbrance.readiedLimit + 4 ? 2 : 3,
67
+ encumbrance.stowed <= encumbrance.stowedLimit ? 0
68
+ : encumbrance.stowed <= encumbrance.stowedLimit + 4 ? 1
69
+ : encumbrance.stowed <= encumbrance.stowedLimit + 8 ? 2 : 3)
70
+ movement: { type: integer, formula: '[10, 7, 5, 0][encumbrance.level]' }
71
+
72
+ # System Strain: permanent from cyberware, the rest temporary. It may not pass Constitution.
73
+ strain.permanent:
74
+ type: integer
75
+ formula: "sumCopies(copy.fields.strain, copy.type == 'cyberware' && has(copy.fields.strain))"
76
+ strain.current: { type: integer, input: true, default: 0, min: 0 }
77
+ strain.total:
78
+ type: integer
79
+ formula: strain.permanent + strain.current
80
+ limits: { max: strain.max }
81
+ strain.max: { type: integer, formula: attributes.con.score }
82
+
83
+ standardCopies:
84
+ - { type: weapon, where: "'unarmed' in item.tags" }
85
+
86
+ contentTypes:
87
+ # A starting package: its own `unpack` action adds its gear and sets the credits.
88
+ kit:
89
+ carried: false
90
+
91
+ weapon:
92
+ carried: true
93
+ equippable: true
94
+ fields:
95
+ damage: { type: dice, required: true }
96
+ skill: { type: enum, values: [punch, shoot, stab], required: true, open: true }
97
+ attribute: { type: enum, values: [str, dex, str-dex] }
98
+ range: { type: integer, min: 0 }
99
+ maxRange: { type: integer, min: 0 }
100
+ magazine: { type: integer, min: 1 }
101
+ ammo: { type: enum, values: [rounds, cell-a, cell-b, missile], open: true }
102
+ shock: { type: integer, min: 0 }
103
+ shockAc: { type: integer, min: 0 }
104
+ burst: { type: boolean, default: false }
105
+ suppress: { type: boolean, default: false }
106
+ # Energy weapons: +1 to hit.
107
+ energy: { type: boolean, default: false }
108
+ # Firearms and TL4 melee weapons ignore primitive armor.
109
+ advanced: { type: boolean, default: false }
110
+ heavy: { type: boolean, default: false }
111
+ thrown: { type: boolean, default: false }
112
+ nonlethal: { type: boolean, default: false }
113
+ # Always rolls against this AC (a grenade).
114
+ fixedAc: { type: integer }
115
+ reloadActions: { type: integer, default: 1, min: 1 }
116
+ cost: { type: integer, min: 0 }
117
+ enc: { type: integer, min: 0 }
118
+ bundle: { type: integer, default: 1, min: 1 }
119
+ techLevel: { type: integer, min: 0, max: 6 }
120
+ state:
121
+ stored: { type: boolean, default: false }
122
+ # Rounds in the magazine of a weapon that has one.
123
+ loaded:
124
+ type: integer
125
+ min: 0
126
+ max: 'has(item.magazine) ? item.magazine : 0'
127
+ default: 'has(item.magazine) ? item.magazine : 0'
128
+ actions:
129
+ - use: attack
130
+ - use: reload
131
+
132
+ armor:
133
+ carried: true
134
+ equippable: true
135
+ fields:
136
+ ac: { type: integer, required: true, min: 10 }
137
+ category:
138
+ { type: enum, values: [primitive, street, combat, powered], required: true, open: true }
139
+ shield: { type: boolean, default: false }
140
+ # Strength counted higher for encumbrance while worn.
141
+ strength: { type: integer, default: 0, min: 0 }
142
+ cost: { type: integer, min: 0 }
143
+ enc: { type: integer, min: 0 }
144
+ bundle: { type: integer, default: 1, min: 1 }
145
+ techLevel: { type: integer, min: 0, max: 6 }
146
+ state:
147
+ stored: { type: boolean, default: false }
148
+ effects:
149
+ - target: encumbrance.strength
150
+ op: add
151
+ value: item.strength
152
+ when: self.equipped && item.strength > 0
153
+
154
+ gear:
155
+ carried: true
156
+ equippable: true
157
+ fields:
158
+ category:
159
+ type: enum
160
+ required: true
161
+ open: true
162
+ values: [ammo-power, communications, computing, field, pharmaceutical, tools-medical]
163
+ # What a weapon reloads with.
164
+ kind: { type: enum, values: [rounds, cell-a, cell-b, missile], open: true }
165
+ # A drug: the Heal skill needed to apply it, the System Strain it adds and what it heals.
166
+ healSkill: { type: integer, min: 0 }
167
+ strain: { type: integer, default: 0, min: 0 }
168
+ heal: { type: dice }
169
+ healAddsSkill: { type: boolean, default: false }
170
+ cost: { type: integer, min: 0 }
171
+ enc: { type: integer, min: 0 }
172
+ # How many make one item of encumbrance when packed together.
173
+ bundle: { type: integer, default: 1, min: 1 }
174
+ techLevel: { type: integer, min: 0, max: 6 }
175
+ state:
176
+ stored: { type: boolean, default: false }
177
+ actions:
178
+ - use: use-drug
179
+
180
+ cyberware:
181
+ fields:
182
+ strain: { type: integer, required: true, min: 0 }
183
+ # System Strain each time it is triggered.
184
+ activationStrain: { type: integer, default: 0, min: 0 }
185
+ cost: { type: integer, min: 0 }
186
+ techLevel: { type: integer, min: 0, max: 6 }
187
+ actions:
188
+ - use: trigger-cyberware