@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,166 @@
1
+ fields:
2
+ henchmen.max: { type: integer, formula: 0 }
3
+ # The discipline Psychic Training's skill points go to.
4
+ psionics.training: { type: string, formula: "''" }
5
+
6
+ situational:
7
+ - id: burst
8
+ type: boolean
9
+ default: false
10
+ rolls: [attack]
11
+ - id: hacking
12
+ type: boolean
13
+ default: false
14
+ rolls: [check.program]
15
+ - id: negotiation
16
+ type: boolean
17
+ default: false
18
+ rolls: [check]
19
+ - id: executionShot
20
+ type: boolean
21
+ default: false
22
+ rolls: [check.shoot]
23
+ - id: telepathy
24
+ type: boolean
25
+ default: false
26
+ rolls: [save.mental]
27
+
28
+ resultBands:
29
+ check:
30
+ - {
31
+ id: success,
32
+ when: 'flags.difficulty >= 0 && roll.total >= flags.difficulty',
33
+ success: true,
34
+ }
35
+ - { id: failure, when: 'flags.difficulty >= 0' }
36
+ - { id: rolled, when: true }
37
+ # A natural 1 always fails and a natural 20 always succeeds.
38
+ save:
39
+ - {
40
+ id: success,
41
+ when: 'roll.faces[0] == 20 || (roll.faces[0] != 1 && roll.total >= flags.target)',
42
+ success: true,
43
+ }
44
+ - { id: failure, when: true }
45
+ attack:
46
+ - { id: hit, when: 'flags.ac >= 0 && roll.total >= flags.ac', success: true }
47
+ - { id: miss, when: 'flags.ac >= 0' }
48
+ - { id: rolled, when: true }
49
+
50
+ actions:
51
+ # 2d6 + skill + attribute modifier; unskilled is -1. Some foci roll more dice and keep two.
52
+ - id: skill-check
53
+ tags: [check]
54
+ params:
55
+ skill:
56
+ type: enum
57
+ open: true
58
+ required: true
59
+ values:
60
+ &skills [
61
+ administer,
62
+ connect,
63
+ exert,
64
+ fix,
65
+ heal,
66
+ know,
67
+ lead,
68
+ notice,
69
+ perform,
70
+ pilot,
71
+ program,
72
+ punch,
73
+ shoot,
74
+ sneak,
75
+ stab,
76
+ survive,
77
+ talk,
78
+ trade,
79
+ work,
80
+ biopsionics,
81
+ metapsionics,
82
+ precognition,
83
+ telekinesis,
84
+ telepathy,
85
+ teleportation,
86
+ ]
87
+ attribute: { type: enum, required: true, values: [str, dex, con, int, wis, cha] }
88
+ difficulty: { type: integer, optional: true, min: 0 }
89
+ results: { bands: check }
90
+ steps:
91
+ - id: start
92
+ kind: branch
93
+ cases:
94
+ - when: true
95
+ flags:
96
+ difficulty: 'has(params.difficulty) ? params.difficulty : -1'
97
+ reroll: false
98
+ - id: check
99
+ kind: roll
100
+ tags: &checkTags
101
+ - check
102
+ - formula: >-
103
+ ['check.' + params.skill]
104
+ + (params.skill in ['connect', 'lead', 'perform', 'talk'] ? ['check.social'] : [])
105
+ bands: check
106
+ parts: &checkParts
107
+ - dice: "(fieldOf('skills.{skill}.dice', params.skill))d6kh2"
108
+ - value: "fieldOf('skills.{skill}.level', params.skill)"
109
+ - value: "fieldOf('attributes.{attr}.mod', params.attribute)"
110
+ - id: retry
111
+ kind: choice
112
+ tags: [failed-check]
113
+ when: "steps.check.band == 'failure'"
114
+ options: [{ id: accept }]
115
+ recommend: "'accept'"
116
+ - id: reroll
117
+ kind: roll
118
+ when: flags.reroll
119
+ tags: *checkTags
120
+ bands: check
121
+ parts: *checkParts
122
+ - id: result
123
+ kind: outcome
124
+ result: >-
125
+ has(steps.reroll) && steps.reroll.band == 'success' ? 'success' : steps.check.band
126
+ data:
127
+ total: 'has(steps.reroll) ? max(steps.check.total, steps.reroll.total) : steps.check.total'
128
+
129
+ - id: saving-throw
130
+ tags: [save]
131
+ params:
132
+ save: { type: enum, required: true, values: [physical, evasion, mental] }
133
+ modifier: { type: integer, default: 0 }
134
+ results: { bands: save }
135
+ steps:
136
+ - id: start
137
+ kind: branch
138
+ cases:
139
+ - when: true
140
+ flags:
141
+ target: >-
142
+ params.save == 'physical' ? saves.physical
143
+ : params.save == 'evasion' ? saves.evasion : saves.mental
144
+ - id: save
145
+ kind: roll
146
+ tags: [save, { formula: "'save.' + params.save" }]
147
+ bands: save
148
+ parts:
149
+ - dice: 1d20
150
+ - value: params.modifier
151
+ - { id: result, kind: outcome, result: steps.save.band }
152
+
153
+ - id: initiative
154
+ tags: [initiative]
155
+ results: [rolled]
156
+ steps:
157
+ - id: roll
158
+ kind: roll
159
+ tags: [initiative]
160
+ parts:
161
+ - dice: 1d8
162
+ - value: attributes.dex.mod
163
+ - id: result
164
+ kind: outcome
165
+ result: "'rolled'"
166
+ data: { total: steps.roll.total }
@@ -0,0 +1,321 @@
1
+ actions:
2
+ # d20 + attack bonus + combat skill (unskilled -2) + the weapon's attribute modifier, against
3
+ # the target's AC. A miss still does the weapon's Shock if the target's AC is low enough, and a
4
+ # hit never does less than the Shock would.
5
+ - id: attack
6
+ tags: [attack]
7
+ available: >-
8
+ (self.equipped || 'unarmed' in item.tags) && (!has(item.magazine) || self.loaded > 0)
9
+ params:
10
+ targetAc: { type: integer, optional: true }
11
+ modifier: { type: integer, default: 0 }
12
+ participants:
13
+ target:
14
+ max: 1
15
+ fields:
16
+ ac.value: { type: integer, default: 10 }
17
+ ac.advanced: { type: integer }
18
+ psionics.cursedLuck: { type: boolean, default: false }
19
+ results: [hit, miss, rolled]
20
+ steps:
21
+ - id: start
22
+ kind: branch
23
+ cases:
24
+ - when: true
25
+ flags:
26
+ skill: "fieldOf('skills.{skill}.level', item.skill)"
27
+ attr: >-
28
+ !has(item.attribute) ? 0
29
+ : item.attribute == 'str-dex' ? max(attributes.str.mod, attributes.dex.mod)
30
+ : fieldOf('attributes.{attr}.mod', item.attribute)
31
+ advanced: >-
32
+ item.advanced || (item.skill == 'stab' && combat.meleeAdvanced)
33
+ || (item.skill == 'punch' && combat.punchAdvanced)
34
+ bonus: >-
35
+ item.skill == 'punch' ? max(0, skills.punch.level)
36
+ : item.skill == 'stab' ? damage.melee : damage.ranged
37
+ burst: situational.burst && item.burst && self.loaded >= 3
38
+ hit: false
39
+ - id: target
40
+ kind: branch
41
+ cases:
42
+ - when: true
43
+ flags:
44
+ ac: >-
45
+ has(item.fixedAc) ? item.fixedAc : has(params.targetAc) ? params.targetAc
46
+ : size(participants.target) == 0 ? -1
47
+ : flags.advanced && has(participants.target[0].ac.advanced)
48
+ ? participants.target[0].ac.advanced : participants.target[0].ac.value
49
+ - id: roll
50
+ kind: roll
51
+ tags: [attack, { formula: "'attack.' + item.skill" }]
52
+ bands: attack
53
+ parts:
54
+ - dice: 1d20
55
+ - value: combat.attackBonus
56
+ - value: 'flags.skill < 0 ? -2 : flags.skill'
57
+ - value: flags.attr
58
+ - value: 'item.energy ? 1 : 0'
59
+ - value: 'flags.burst ? 2 : 0'
60
+ - value: params.modifier
61
+ - id: luck
62
+ kind: choice
63
+ tags: [missed-attack]
64
+ when: "steps.roll.band == 'miss'"
65
+ options: [{ id: accept }]
66
+ recommend: "'accept'"
67
+ - id: outcome
68
+ kind: branch
69
+ cases:
70
+ - when: true
71
+ flags:
72
+ landed: "steps.roll.band == 'hit' || flags.hit"
73
+ shock: >-
74
+ has(item.shock) && item.shock > 0 && flags.ac >= 0
75
+ && ((shock.anyAc && item.skill != 'shoot') || flags.ac <= item.shockAc)
76
+ ? max(0, item.shock + flags.attr + shock.bonus
77
+ + (item.skill == 'stab' ? damage.melee : 0))
78
+ : 0
79
+ - id: damage
80
+ kind: roll
81
+ when: flags.landed
82
+ tags: [damage]
83
+ parts:
84
+ - dice: item.damage
85
+ - value: flags.attr
86
+ - value: flags.bonus
87
+ - value: 'flags.burst ? 2 : 0'
88
+ - id: missDamage
89
+ kind: roll
90
+ when: "!flags.landed && steps.roll.band == 'miss'"
91
+ tags: [damage]
92
+ parts:
93
+ - dice: "item.skill == 'punch' ? miss.punch : item.skill == 'stab' ? miss.melee : miss.ranged"
94
+ - id: total
95
+ kind: branch
96
+ cases:
97
+ - when: true
98
+ flags:
99
+ damage: >-
100
+ flags.landed ? max(0, steps.damage.total, flags.shock)
101
+ : has(steps.missDamage) ? flags.shock + steps.missDamage.total : 0
102
+ - id: deal
103
+ kind: changes
104
+ when: flags.damage > 0
105
+ to: target
106
+ changes:
107
+ - type: adjust
108
+ field: hp.current
109
+ by: -flags.damage
110
+ tags: [{ formula: "item.nonlethal ? 'damage.nonlethal' : 'damage'" }]
111
+ - id: spend
112
+ kind: changes
113
+ changes:
114
+ - type: adjustState
115
+ when: has(item.magazine)
116
+ entry: self
117
+ key: loaded
118
+ by: '-(flags.burst ? 3 : 1)'
119
+ - type: adjustQuantity
120
+ when: has(item.fixedAc)
121
+ entry: self
122
+ by: -1
123
+ - id: result
124
+ kind: outcome
125
+ result: "flags.landed ? 'hit' : steps.roll.band"
126
+ data:
127
+ total: steps.roll.total
128
+ damage: flags.damage
129
+
130
+ # Refills the magazine from a power cell or a load of ammunition carried, when there is one.
131
+ - id: reload
132
+ tags: [attack]
133
+ available: has(item.magazine) && self.loaded < item.magazine
134
+ results: [reloaded]
135
+ steps:
136
+ - id: load
137
+ kind: changes
138
+ changes:
139
+ - { type: setState, entry: self, key: loaded, value: item.magazine }
140
+ - type: adjustQuantity
141
+ when: has(item.ammo)
142
+ copies:
143
+ {
144
+ type: gear,
145
+ where: 'has(item.kind) && item.kind == action.item.ammo && self.quantity > 0',
146
+ }
147
+ limit: 1
148
+ by: -1
149
+ - { id: result, kind: outcome, result: "'reloaded'" }
150
+
151
+ - id: take-damage
152
+ tags: [health]
153
+ params:
154
+ amount: { type: integer, min: 0 }
155
+ results: [taken]
156
+ steps:
157
+ - id: deal
158
+ kind: changes
159
+ changes:
160
+ - { type: adjust, field: hp.current, by: -params.amount, tags: [damage] }
161
+ - { id: result, kind: outcome, result: "'taken'" }
162
+
163
+ - id: heal
164
+ tags: [health]
165
+ params:
166
+ amount: { type: integer, min: 0 }
167
+ results: [healed]
168
+ steps:
169
+ - id: restore
170
+ kind: changes
171
+ changes:
172
+ - { type: adjust, field: hp.current, by: params.amount, tags: [healing] }
173
+ - { id: result, kind: outcome, result: "'healed'" }
174
+
175
+ # A night's rest: hit points back by the character level (unless mortally wounded), one point
176
+ # of System Strain gone, and every Effort and once-a-scene ability back.
177
+ - id: rest
178
+ tags: [health]
179
+ results: [rested]
180
+ steps:
181
+ - id: rest
182
+ tags: [rest.night]
183
+ kind: changes
184
+ changes:
185
+ - { type: adjust, field: hp.current, by: level, when: hp.current > 0, tags: [healing] }
186
+ - { type: adjust, field: strain.current, by: -1, when: strain.current > 0 }
187
+ - { type: set, field: effort.day, value: 0 }
188
+ - { type: set, field: effort.scene, value: 0 }
189
+ - { type: set, field: effort.torched, value: 0 }
190
+ - { type: set, field: scene.expertReroll, value: false }
191
+ - { type: set, field: scene.warriorLuck, value: false }
192
+ - { id: result, kind: outcome, result: "'rested'" }
193
+
194
+ - id: end-scene
195
+ tags: [health]
196
+ results: [ended]
197
+ steps:
198
+ - id: reset
199
+ tags: [rest.scene]
200
+ kind: changes
201
+ changes:
202
+ - { type: set, field: effort.scene, value: 0 }
203
+ - { type: set, field: effort.torched, value: 0 }
204
+ - { type: set, field: scene.expertReroll, value: false }
205
+ - { type: set, field: scene.warriorLuck, value: false }
206
+ - { id: result, kind: outcome, result: "'ended'" }
207
+
208
+ # A stim or drug on yourself: it fails if its System Strain would pass Constitution.
209
+ - id: use-drug
210
+ tags: [health]
211
+ available: "item.category == 'pharmaceutical' && self.quantity > 0"
212
+ results: [applied, failed]
213
+ steps:
214
+ - id: start
215
+ kind: branch
216
+ cases:
217
+ - when: true
218
+ flags:
219
+ fits: strain.total + item.strain <= strain.max
220
+ - id: heal
221
+ kind: roll
222
+ when: flags.fits && has(item.heal)
223
+ tags: [healing]
224
+ parts:
225
+ - dice: item.heal
226
+ - value: 'item.healAddsSkill ? max(0, skills.heal.level) : 0'
227
+ - id: apply
228
+ kind: changes
229
+ changes:
230
+ - { type: adjustQuantity, entry: self, by: -1 }
231
+ - {
232
+ type: adjust,
233
+ field: strain.current,
234
+ by: item.strain,
235
+ when: flags.fits && item.strain > 0,
236
+ }
237
+ - type: adjust
238
+ when: has(steps.heal)
239
+ field: hp.current
240
+ by: steps.heal.total
241
+ tags: [healing]
242
+ - { id: result, kind: outcome, result: "flags.fits ? 'applied' : 'failed'" }
243
+
244
+ - id: trigger-cyberware
245
+ tags: [strain]
246
+ available: item.activationStrain > 0
247
+ results: [triggered, failed]
248
+ steps:
249
+ - id: start
250
+ kind: branch
251
+ cases:
252
+ - when: true
253
+ flags:
254
+ fits: strain.total + item.activationStrain <= strain.max
255
+ - id: strain
256
+ kind: changes
257
+ when: flags.fits
258
+ changes:
259
+ - { type: adjust, field: strain.current, by: item.activationStrain }
260
+ - { id: result, kind: outcome, result: "flags.fits ? 'triggered' : 'failed'" }
261
+
262
+ # Commit a point of Effort for the scene or for the day.
263
+ - id: commit-effort
264
+ tags: [psionics]
265
+ available: effort.available > 0
266
+ params:
267
+ until: { type: enum, values: [scene, day], default: scene }
268
+ results: [committed]
269
+ steps:
270
+ # Torched Effort lasts only for the scene, whatever it is committed for.
271
+ - id: source
272
+ kind: branch
273
+ cases:
274
+ - when: true
275
+ flags:
276
+ day: "params.until == 'day' && effort.max - effort.scene - effort.day - effort.active > 0"
277
+ - id: commit
278
+ kind: changes
279
+ changes:
280
+ - { type: adjust, field: effort.scene, by: 1, when: '!flags.day' }
281
+ - { type: adjust, field: effort.day, by: 1, when: flags.day }
282
+ - { id: result, kind: outcome, result: "'committed'" }
283
+
284
+ # Torching: a free point of Effort for the scene, at a risk to Wisdom or Constitution.
285
+ - id: torch
286
+ tags: [psionics]
287
+ available: "psionics.access != 'none'"
288
+ results: [harmless, wisdom, constitution, chosen]
289
+ steps:
290
+ - id: roll
291
+ kind: roll
292
+ tags: [torch]
293
+ parts: [{ dice: 1d6 }]
294
+ - id: attribute
295
+ kind: choice
296
+ when: steps.roll.total == 5
297
+ options: { values: { formula: "keysOf('attr')" } }
298
+ recommend: >-
299
+ ['str', 'dex', 'con', 'int', 'wis', 'cha'][indexOf([attributes.str.score,
300
+ attributes.dex.score, attributes.con.score, attributes.int.score,
301
+ attributes.wis.score, attributes.cha.score], maxList([attributes.str.score,
302
+ attributes.dex.score, attributes.con.score, attributes.int.score,
303
+ attributes.wis.score, attributes.cha.score], x))]
304
+ - id: apply
305
+ kind: changes
306
+ changes:
307
+ - { type: adjust, field: effort.torched, by: 1 }
308
+ - { type: adjust, field: attributes.wis.score, by: -1, when: steps.roll.total <= 2 }
309
+ - type: adjust
310
+ when: steps.roll.total == 3 || steps.roll.total == 4
311
+ field: attributes.con.score
312
+ by: -1
313
+ - type: adjust
314
+ when: has(steps.attribute)
315
+ field: { formula: "'attributes.' + steps.attribute.picked + '.score'" }
316
+ by: -1
317
+ - id: result
318
+ kind: outcome
319
+ result: >-
320
+ steps.roll.total <= 2 ? 'wisdom' : steps.roll.total <= 4 ? 'constitution'
321
+ : steps.roll.total == 5 ? 'chosen' : 'harmless'
@@ -0,0 +1,111 @@
1
+ settings:
2
+ rounding: floor
3
+ rollModifiers:
4
+ advantage: cancel
5
+
6
+ families:
7
+ attr: [str, dex, con, int, wis, cha]
8
+ # Every skill, for fieldOf; the fields are declared by the three families below.
9
+ skill:
10
+ [
11
+ administer,
12
+ connect,
13
+ exert,
14
+ fix,
15
+ heal,
16
+ know,
17
+ lead,
18
+ notice,
19
+ perform,
20
+ pilot,
21
+ program,
22
+ punch,
23
+ shoot,
24
+ sneak,
25
+ stab,
26
+ survive,
27
+ talk,
28
+ trade,
29
+ work,
30
+ biopsionics,
31
+ metapsionics,
32
+ precognition,
33
+ telekinesis,
34
+ telepathy,
35
+ teleportation,
36
+ ]
37
+ general:
38
+ [
39
+ administer,
40
+ connect,
41
+ exert,
42
+ fix,
43
+ heal,
44
+ know,
45
+ lead,
46
+ notice,
47
+ perform,
48
+ pilot,
49
+ program,
50
+ sneak,
51
+ survive,
52
+ talk,
53
+ trade,
54
+ work,
55
+ ]
56
+ combat: [punch, shoot, stab]
57
+ psychic: [biopsionics, metapsionics, precognition, telekinesis, telepathy, teleportation]
58
+
59
+ fields:
60
+ 'attributes.{attr}.score':
61
+ { type: integer, input: true, default: 10, min: 0, max: 18, tags: [attribute] }
62
+ 'attributes.{attr}.mod':
63
+ type: integer
64
+ tags: [attr-mod]
65
+ formula: >-
66
+ attributes.{attr}.score <= 3 ? -2 : attributes.{attr}.score <= 7 ? -1
67
+ : attributes.{attr}.score <= 13 ? 0 : attributes.{attr}.score <= 17 ? 1 : 2
68
+
69
+ level: { type: integer, input: true, default: 1, min: 1, max: 20 }
70
+ xp.current: { type: integer, input: true, default: 0, min: 0 }
71
+ # The total the next level needs: the table to 10th level, then 24 more for each level.
72
+ xp.next:
73
+ type: integer
74
+ formula: 'level >= 10 ? 93 + 24 * (level - 9) : [0, 3, 6, 12, 18, 27, 39, 54, 72, 93][level]'
75
+
76
+ # Unskilled is -1: a skill check adds it as the penalty, an attack swaps it for -2.
77
+ 'skills.{general}.level':
78
+ { type: integer, input: true, default: -1, min: -1, max: 4, tags: [skill, skill.general] }
79
+ 'skills.{combat}.level':
80
+ { type: integer, input: true, default: -1, min: -1, max: 4, tags: [skill, skill.combat] }
81
+ 'skills.{psychic}.level':
82
+ { type: integer, input: true, default: -1, min: -1, max: 4, tags: [skill, skill.psychic] }
83
+ # How many d6 a check in the skill rolls, keeping the best two.
84
+ 'skills.{general}.dice': { type: integer, formula: 2, min: 2 }
85
+ 'skills.{combat}.dice': { type: integer, formula: 2, min: 2 }
86
+ 'skills.{psychic}.dice': { type: integer, formula: 2, min: 2 }
87
+
88
+ saves.physical:
89
+ type: integer
90
+ tags: [save]
91
+ formula: 16 - level - max(attributes.str.mod, attributes.con.mod)
92
+ saves.evasion:
93
+ type: integer
94
+ tags: [save]
95
+ formula: 16 - level - max(attributes.dex.mod, attributes.int.mod)
96
+ saves.mental:
97
+ type: integer
98
+ tags: [save]
99
+ formula: 16 - level - max(attributes.wis.mod, attributes.cha.mod)
100
+
101
+ # The rolled part of maximum hit points, Constitution included; the per-level bonuses
102
+ # (Warrior, Partial Warrior, Die Hard) are added on top, so a bonus taken later counts for
103
+ # every level.
104
+ hp.rolled: { type: integer, input: true, default: 1, min: 1 }
105
+ hp.perLevel: { type: integer, formula: 0 }
106
+ hp.max: { type: integer, formula: hp.rolled + hp.perLevel * level, min: 1 }
107
+ hp.current: { type: integer, input: true, default: 1, min: 0, max: hp.max }
108
+
109
+ combat.attackBonus: { type: integer, formula: floor(level / 2) }
110
+
111
+ credits.current: { type: integer, input: true, default: 0, min: 0 }